diff --git a/CMakeLists.txt b/CMakeLists.txt index 7995034d3..13a6bbaca 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.0) # DO NOT CHANGE THIS SRB2 STRING! Some variable names depend on this string. # Version change is fine. project(SRB2 - VERSION 1.1.0 + VERSION 2.0.0 LANGUAGES C) if(${PROJECT_SOURCE_DIR} MATCHES ${PROJECT_BINARY_DIR}) diff --git a/appveyor.yml b/appveyor.yml index 3d46cf6de..cc5a01741 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,4 +1,4 @@ -version: 1.1.0.{branch}-{build} +version: 2.0.0.{branch}-{build} os: MinGW environment: @@ -29,7 +29,7 @@ environment: ############################## DPL_ENABLED: 0 DPL_TAG_ENABLED: 0 - DPL_INSTALLER_NAME: srb2kart-v110 + DPL_INSTALLER_NAME: srb2kart-v200 # Asset handling is barebones vs. Travis Deployer. We operate on 7z only. # Include the README files and the OpenGL batch in the main and patch archives. # The x86/x64 archives contain the DLL binaries. diff --git a/assets/CMakeLists.txt b/assets/CMakeLists.txt index 1eab62cc9..89be796ad 100644 --- a/assets/CMakeLists.txt +++ b/assets/CMakeLists.txt @@ -13,12 +13,12 @@ set(SRB2_ASSET_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/installer" CACHE STRING "Path to directory that contains all asset files for the installer.") set(SRB2_ASSET_HASHED -"srb2.srb;\ -patch.kart;\ -gfx.kart;\ -textures.kart;\ -chars.kart;\ -maps.kart" +"main.kart;\ +gfx.pk3;\ +textures.pk3;\ +chars.pk3;\ +maps.wad;\ +patch.pk3" CACHE STRING "Asset filenames to apply MD5 checks. No spaces between entries!" ) diff --git a/src/Makefile b/src/Makefile index 214c2bf7a..f4a77aedd 100644 --- a/src/Makefile +++ b/src/Makefile @@ -83,16 +83,14 @@ # SRB2 data files D_DIR?=../bin/Resources -D_FILES=$(D_DIR)/srb2.srb \ - $(D_DIR)/patch.dta \ - #$(D_DIR)/music.dta \ - $(D_DIR)/gfx.kart \ - $(D_DIR)/textures.kart \ - $(D_DIR)/chars.kart \ - $(D_DIR)/maps.kart \ - $(D_DIR)/sounds.kart \ - $(D_DIR)/patch.kart \ - $(D_DIR)/music.kart \ +D_FILES=$(D_DIR)/main.kart \ + $(D_DIR)/gfx.pk3 \ + $(D_DIR)/textures.pk3 \ + $(D_DIR)/chars.pk3 \ + $(D_DIR)/maps.wad \ + $(D_DIR)/patch.pk3 \ + $(D_DIR)/sounds.wad \ + $(D_DIR)/music.wad \ PKG_CONFIG?=pkg-config diff --git a/src/config.h.in b/src/config.h.in index f3f8339f8..4bf84ff1d 100644 --- a/src/config.h.in +++ b/src/config.h.in @@ -11,19 +11,13 @@ #ifdef CMAKECONFIG -// Base SRB2 hashes -#define ASSET_HASH_SRB2_SRB "${SRB2_ASSET_srb2.srb_HASH}" -#ifdef USE_PATCH_DTA -#define ASSET_HASH_PATCH_DTA "${SRB2_ASSET_patch.dta_HASH}" -#endif - -// SRB2Kart-specific hashes -#define ASSET_HASH_GFX_KART "${SRB2_ASSET_gfx.kart_HASH}" -#define ASSET_HASH_TEXTURES_KART "${SRB2_ASSET_textures.kart_HASH}" -#define ASSET_HASH_CHARS_KART "${SRB2_ASSET_chars.kart_HASH}" -#define ASSET_HASH_MAPS_KART "${SRB2_ASSET_maps.kart_HASH}" -#ifdef USE_PATCH_KART -#define ASSET_HASH_PATCH_KART "${SRB2_ASSET_patch.kart_HASH}" +#define ASSET_HASH_MAIN_KART "${SRB2_ASSET_main.kart_HASH}" +#define ASSET_HASH_GFX_PK3 "${SRB2_ASSET_gfx.pk3_HASH}" +#define ASSET_HASH_TEXTURES_PK3 "${SRB2_ASSET_textures.pk3_HASH}" +#define ASSET_HASH_CHARS_PK3 "${SRB2_ASSET_chars.pk3_HASH}" +#define ASSET_HASH_MAPS_WAD "${SRB2_ASSET_maps.wad_HASH}" +#ifdef USE_PATCH_FILE +#define ASSET_HASH_PATCH_PK3 "${SRB2_ASSET_patch.pk3_HASH}" #endif #define SRB2_COMP_REVISION "${SRB2_COMP_REVISION}" @@ -34,25 +28,17 @@ #else /* Manually defined asset hashes for non-CMake builds - * Last updated 2015 / 05 / 03 - SRB2 v2.1.15 - srb2.srb - * Last updated 2018 / 12 / 23 - SRB2 v2.1.22 - patch.dta * Last updated 2019 / 01 / 18 - Kart v1.0.2 - Main assets * Last updated 2019 / 05 / 06 - Kart v1.1.0 - patch.kart */ -// Base SRB2 hashes -#define ASSET_HASH_SRB2_SRB "c1b9577687f8a795104aef4600720ea7" -#ifdef USE_PATCH_DTA -#define ASSET_HASH_PATCH_DTA "b04fd9624bfd94dc96dcf4f400f7deb4" -#endif - -// SRB2Kart-specific hashes -#define ASSET_HASH_GFX_KART "99c39f223d84ebc78e67ab68f3bead95" -#define ASSET_HASH_TEXTURES_KART "ec8e9b7535cf585afe72ef277b08f490" -#define ASSET_HASH_CHARS_KART "e2c428347dde52858a3dacd29fc5b964" -#define ASSET_HASH_MAPS_KART "1335cd064656aedca359cfbb5233ac4a" -#ifdef USE_PATCH_KART -#define ASSET_HASH_PATCH_KART "7093231f2c3c1cca1a909a708be85d9a" +#define ASSET_HASH_MAIN_KART "00000000000000000000000000000000" +#define ASSET_HASH_GFX_PK3 "00000000000000000000000000000000" +#define ASSET_HASH_TEXTURES_PK3 "00000000000000000000000000000000" +#define ASSET_HASH_CHARS_PK3 "00000000000000000000000000000000" +#define ASSET_HASH_MAPS_WAD "00000000000000000000000000000000" +#ifdef USE_PATCH_FILE +#define ASSET_HASH_PATCH_PK3 "00000000000000000000000000000000" #endif #endif diff --git a/src/console.c b/src/console.c index 28958089b..1defa7e82 100644 --- a/src/console.c +++ b/src/console.c @@ -131,12 +131,12 @@ static CV_PossibleValue_t backpic_cons_t[] = {{0, "translucent"}, {1, "picture"} static consvar_t cons_backpic = {"con_backpic", "translucent", CV_SAVE, backpic_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; static CV_PossibleValue_t backcolor_cons_t[] = {{0, "White"}, {1, "Black"}, {2, "Sepia"}, - {3, "Brown"}, {4, "Pink"}, {5, "Raspberry"}, - {6, "Red"}, {7, "Creamsicle"}, {8, "Orange"}, - {9, "Gold"}, {10,"Yellow"}, {11,"Emerald"}, - {12,"Green"}, {13,"Cyan"}, {14,"Steel"}, - {15,"Periwinkle"}, {16,"Blue"}, {17,"Purple"}, - {18,"Lavender"}, + {3, "Brown"}, {4, "Pink"}, {5, "Red"}, + {6, "Orange"}, {7, "Gold"}, {8, "Yellow"}, + {9, "Peridot"}, {10,"Green"}, {11,"Aquamarine"}, + {12,"Cyan"}, {13,"Steel"}, {14,"Blue"}, + {15,"Purple"}, {16,"Magenta"}, {17,"Lavender"}, + {18,"Rose"}, {0, NULL}}; consvar_t cons_backcolor = {"con_backcolor", "Black", CV_CALL|CV_SAVE, backcolor_cons_t, CONS_backcolor_Change, 0, NULL, NULL, 0, 0, NULL}; @@ -153,11 +153,11 @@ static CV_PossibleValue_t menuhighlight_cons_t[] = {V_SKYMAP, "Always sky-blue"}, {V_GOLDMAP, "Always gold"}, {V_LAVENDERMAP, "Always lavender"}, - {V_TEAMAP, "Always tea-green"}, - {V_STEELMAP, "Always steel-blue"}, + {V_AQUAMAP, "Always aqua-green"}, + {V_MAGENTAMAP, "Always magenta"}, {V_PINKMAP, "Always pink"}, {V_BROWNMAP, "Always brown"}, - {V_PEACHMAP, "Always peach"}, + {V_TANMAP, "Always tan"}, {0, NULL} }; consvar_t cons_menuhighlight = {"menuhighlight", "Game type", CV_SAVE, menuhighlight_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; @@ -262,27 +262,27 @@ void CON_SetupBackColormap(void) switch (cons_backcolor.value) { - case 0: palindex = 15; break; // White - case 1: palindex = 31; break; // Gray - case 2: palindex = 47; break; // Sepia - case 3: palindex = 63; break; // Brown - case 4: palindex = 150; shift = 7; break; // Pink - case 5: palindex = 127; shift = 7; break; // Raspberry - case 6: palindex = 143; break; // Red - case 7: palindex = 86; shift = 7; break; // Creamsicle - case 8: palindex = 95; break; // Orange - case 9: palindex = 119; shift = 7; break; // Gold - case 10: palindex = 111; break; // Yellow - case 11: palindex = 191; shift = 7; break; // Emerald - case 12: palindex = 175; break; // Green - case 13: palindex = 219; break; // Cyan - case 14: palindex = 207; shift = 7; break; // Steel - case 15: palindex = 230; shift = 7; break; // Periwinkle - case 16: palindex = 239; break; // Blue - case 17: palindex = 199; shift = 7; break; // Purple - case 18: palindex = 255; shift = 7; break; // Lavender - // Default green - default: palindex = 175; break; + case 0: palindex = 15; break; // White + case 1: palindex = 31; break; // Black + case 2: palindex = 251; break; // Sepia + case 3: palindex = 239; break; // Brown + case 4: palindex = 214; shift = 7; break; // Pink + case 5: palindex = 47; break; // Red + case 6: palindex = 63; break; // Orange + case 7: palindex = 71; shift = 7; break; // Gold + case 8: palindex = 79; shift = 7; break; // Yellow + case 9: palindex = 191; shift = 8; break; // Peridot + case 10: palindex = 111; break; // Green + case 11: palindex = 127; shift = 7; break; // Aquamarine + case 12: palindex = 139; break; // Cyan + case 13: palindex = 175; shift = 7; break; // Steel + case 14: palindex = 159; break; // Blue + case 15: palindex = 169; break; // Purple + case 16: palindex = 187; break; // Magenta + case 17: palindex = 199; shift = 7; break; // Lavender + case 18: palindex = 207; shift = 7; break; // Rose + // Default black + default: palindex = 31; break; } @@ -303,7 +303,7 @@ static void CONS_backcolor_Change(void) // TODO: This could probably be improved somehow... // These colormaps are 99% identical, with just a few changed bytes UINT8 *yellowmap, *purplemap, *greenmap, *bluemap, *graymap, *redmap, *orangemap,\ - *skymap, *goldmap, *lavendermap, *teamap, *steelmap, *pinkmap, *brownmap, *peachmap; + *skymap, *goldmap, *lavendermap, *aquamap, *magentamap, *pinkmap, *brownmap, *tanmap; static void CON_SetupColormaps(void) { @@ -320,11 +320,11 @@ static void CON_SetupColormaps(void) skymap = (orangemap+256); lavendermap = (skymap+256); goldmap = (lavendermap+256); - teamap = (goldmap+256); - steelmap = (teamap+256); - pinkmap = (steelmap+256); + aquamap = (goldmap+256); + magentamap = (aquamap+256); + pinkmap = (magentamap+256); brownmap = (pinkmap+256); - peachmap = (brownmap+256); + tanmap = (brownmap+256); // setup the other colormaps, for console text @@ -335,21 +335,21 @@ static void CON_SetupColormaps(void) *memorysrc = (UINT8)(i & 0xFF); // remap each color to itself... // SRB2Kart: Different console font, new colors - purplemap[120] = (UINT8)194; - yellowmap[120] = (UINT8)103; - greenmap[120] = (UINT8)162; - bluemap[120] = (UINT8)228; - redmap[120] = (UINT8)126; // battle - graymap[120] = (UINT8)10; - orangemap[120] = (UINT8)85; // record attack - skymap[120] = (UINT8)214; // race - lavendermap[120] = (UINT8)248; - goldmap[120] = (UINT8)114; - teamap[120] = (UINT8)177; - steelmap[120] = (UINT8)201; - pinkmap[120] = (UINT8)145; - brownmap[120] = (UINT8)48; - peachmap[120] = (UINT8)69; // nice + purplemap[0] = (UINT8)163; + yellowmap[0] = (UINT8)73; + greenmap[0] = (UINT8)98; + bluemap[0] = (UINT8)148; + redmap[0] = (UINT8)34; // battle + graymap[0] = (UINT8)10; + orangemap[0] = (UINT8)52; // record attack + skymap[0] = (UINT8)132; // race + lavendermap[0] = (UINT8)192; + goldmap[0] = (UINT8)65; + aquamap[0] = (UINT8)121; + magentamap[0] = (UINT8)182; + pinkmap[0] = (UINT8)210; + brownmap[0] = (UINT8)224; + tanmap[0] = (UINT8)217; // no longer nice :( // Init back colormap CON_SetupBackColormap(); @@ -1472,7 +1472,7 @@ static void CON_DrawInput(void) { x -= charwidth*3; if (input_sel < c) - V_DrawFill(x, y, charwidth*3, (10 * con_scalefactor), 107 | V_NOSCALESTART); + V_DrawFill(x, y, charwidth*3, (10 * con_scalefactor), 77 | V_NOSCALESTART); for (i = 0; i < 3; ++i, x += charwidth) V_DrawCharacter(x, y, '.' | cv_constextsize.value | V_GRAYMAP | V_NOSCALESTART, !cv_allcaps.value); } @@ -1483,7 +1483,7 @@ static void CON_DrawInput(void) { if ((input_sel > c && input_cur <= c) || (input_sel <= c && input_cur > c)) { - V_DrawFill(x, y, charwidth, (10 * con_scalefactor), 107 | V_NOSCALESTART); + V_DrawFill(x, y, charwidth, (10 * con_scalefactor), 77 | V_NOSCALESTART); V_DrawCharacter(x, y, p[c] | cv_constextsize.value | V_YELLOWMAP | V_NOSCALESTART, !cv_allcaps.value); } else @@ -1497,7 +1497,7 @@ static void CON_DrawInput(void) if (rellip) { if (input_sel > cend) - V_DrawFill(x, y, charwidth*3, (10 * con_scalefactor), 107 | V_NOSCALESTART); + V_DrawFill(x, y, charwidth*3, (10 * con_scalefactor), 77 | V_NOSCALESTART); for (i = 0; i < 3; ++i, x += charwidth) V_DrawCharacter(x, y, '.' | cv_constextsize.value | V_GRAYMAP | V_NOSCALESTART, !cv_allcaps.value); } diff --git a/src/console.h b/src/console.h index 11621746c..7ed585177 100644 --- a/src/console.h +++ b/src/console.h @@ -39,7 +39,7 @@ extern UINT32 con_scalefactor; // console text scale factor extern consvar_t cons_backcolor, cons_menuhighlight; extern UINT8 *yellowmap, *purplemap, *greenmap, *bluemap, *graymap, *redmap, *orangemap,\ - *skymap, *goldmap, *lavendermap, *teamap, *steelmap, *pinkmap, *brownmap, *peachmap; + *skymap, *goldmap, *lavendermap, *aquamap, *magentamap, *pinkmap, *brownmap, *tanmap; // Console bg color (auto updated to match) extern UINT8 *consolebgmap; diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 1dc2c1420..fa228df06 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -1175,7 +1175,7 @@ static inline void CL_DrawConnectionStatus(void) if (cl_mode != CL_DOWNLOADFILES) { INT32 i, animtime = ((ccstime / 4) & 15) + 16; - UINT8 palstart = (cl_mode == CL_SEARCHING) ? 128 : 160; + UINT8 palstart = (cl_mode == CL_SEARCHING) ? 32 : 96; // 15 pal entries total. const char *cltext; @@ -1259,8 +1259,8 @@ static inline void CL_DrawConnectionStatus(void) dldlength = (INT32)((file->currentsize/(double)file->totalsize) * 256); if (dldlength > 256) dldlength = 256; - V_DrawFill(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-24, 256, 8, 175); - V_DrawFill(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-24, dldlength, 8, 160); + V_DrawFill(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-24, 256, 8, 111); + V_DrawFill(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-24, dldlength, 8, 96); memset(tempname, 0, sizeof(tempname)); // offset filename to just the name only part diff --git a/src/d_main.c b/src/d_main.c index 467976c17..1404a5e61 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -836,11 +836,11 @@ static inline void D_CleanFile(char **filearray) static void IdentifyVersion(void) { - char *srb2wad1, *srb2wad2; + char *mainresource; const char *srb2waddir = NULL; #if (defined (__unix__) && !defined (MSDOS)) || defined (UNIXCOMMON) || defined (HAVE_SDL) - // change to the directory where 'srb2.srb' is found + // change to the directory where 'main.kart' is found srb2waddir = I_LocateWad(); #endif @@ -871,46 +871,34 @@ static void IdentifyVersion(void) srb2waddir = I_GetWadDir(); #endif // Commercial. - srb2wad1 = malloc(strlen(srb2waddir)+1+8+1); - srb2wad2 = malloc(strlen(srb2waddir)+1+8+1); - if (srb2wad1 == NULL && srb2wad2 == NULL) + mainresource = malloc(strlen(srb2waddir)+1+9+1); + if (mainresource == NULL) I_Error("No more free memory to look in %s", srb2waddir); - if (srb2wad1 != NULL) - sprintf(srb2wad1, pandf, srb2waddir, "srb2.srb"); - if (srb2wad2 != NULL) - sprintf(srb2wad2, pandf, srb2waddir, "srb2.wad"); + if (mainresource != NULL) + sprintf(mainresource, pandf, srb2waddir, "main.kart"); // will be overwritten in case of -cdrom or unix/win home snprintf(configfile, sizeof configfile, "%s" PATHSEP CONFIGFILENAME, srb2waddir); configfile[sizeof configfile - 1] = '\0'; // Load the IWAD - if (srb2wad2 != NULL && FIL_ReadFileOK(srb2wad2)) - D_AddFile(srb2wad2, startupwadfiles); - else if (srb2wad1 != NULL && FIL_ReadFileOK(srb2wad1)) - D_AddFile(srb2wad1, startupwadfiles); + if (mainresource != NULL && FIL_ReadFileOK(mainresource)) + D_AddFile(mainresource, startupwadfiles); else - I_Error("SRB2.SRB/SRB2.WAD not found! Expected in %s, ss files: %s or %s\n", srb2waddir, srb2wad1, srb2wad2); + I_Error("MAIN.KART not found! Expected in %s, ss file: %s \n", srb2waddir, mainresource); - if (srb2wad1) - free(srb2wad1); - if (srb2wad2) - free(srb2wad2); + if (mainresource) + free(mainresource); // if you change the ordering of this or add/remove a file, be sure to update the md5 // checking in D_SRB2Main -#ifdef USE_PATCH_DTA - // Add our crappy patches to fix our bugs - D_AddFile(va(pandf,srb2waddir,"patch.dta")); -#endif - - D_AddFile(va(pandf,srb2waddir,"gfx.kart"), startupwadfiles); - D_AddFile(va(pandf,srb2waddir,"textures.kart"), startupwadfiles); - D_AddFile(va(pandf,srb2waddir,"chars.kart"), startupwadfiles); - D_AddFile(va(pandf,srb2waddir,"maps.kart"), startupwadfiles); -#ifdef USE_PATCH_KART - D_AddFile(va(pandf,srb2waddir,"patch.kart"), startupwadfiles); + D_AddFile(va(pandf,srb2waddir,"gfx.pk3"), startupwadfiles); + D_AddFile(va(pandf,srb2waddir,"textures.pk3"), startupwadfiles); + D_AddFile(va(pandf,srb2waddir,"chars.pk3"), startupwadfiles); + D_AddFile(va(pandf,srb2waddir,"maps.wad"), startupwadfiles); // TODO: make this a pk3 too! +#ifdef USE_PATCH_FILE + D_AddFile(va(pandf,srb2waddir,"patch.pk3"), startupwadfiles); #endif #if !defined (HAVE_SDL) || defined (HAVE_MIXER) @@ -923,8 +911,8 @@ static void IdentifyVersion(void) else if (ms == 0) \ I_Error("File "str" has been modified with non-music/sound lumps"); \ } - MUSICTEST("sounds.kart") - MUSICTEST("music.kart") + MUSICTEST("sounds.wad") + MUSICTEST("music.wad") #undef MUSICTEST #endif } @@ -1208,27 +1196,21 @@ void D_SRB2Main(void) #ifndef DEVELOP // Check MD5s of autoloaded files // Note: Do not add any files that ignore MD5! - W_VerifyFileMD5(mainwads, ASSET_HASH_SRB2_SRB); // srb2.srb/srb2.wad -#ifdef USE_PATCH_DTA - mainwads++; W_VerifyFileMD5(mainwads, ASSET_HASH_PATCH_DTA); // patch.dta -#endif - mainwads++; W_VerifyFileMD5(mainwads, ASSET_HASH_GFX_KART); // gfx.kart - mainwads++; W_VerifyFileMD5(mainwads, ASSET_HASH_TEXTURES_KART); // textures.kart - mainwads++; W_VerifyFileMD5(mainwads, ASSET_HASH_CHARS_KART); // chars.kart - mainwads++; W_VerifyFileMD5(mainwads, ASSET_HASH_MAPS_KART); // maps.kart -- 4 - If you touch this, make sure to touch up the majormods stuff below. -#ifdef USE_PATCH_KART - mainwads++; W_VerifyFileMD5(mainwads, ASSET_HASH_PATCH_KART); // patch.kart + W_VerifyFileMD5(mainwads, ASSET_HASH_MAIN_KART); // main.kart + mainwads++; W_VerifyFileMD5(mainwads, ASSET_HASH_GFX_PK3); // gfx.pk3 + mainwads++; W_VerifyFileMD5(mainwads, ASSET_HASH_TEXTURES_PK3); // textures.pk3 + mainwads++; W_VerifyFileMD5(mainwads, ASSET_HASH_CHARS_PK3); // chars.pk3 + mainwads++; W_VerifyFileMD5(mainwads, ASSET_HASH_MAPS_WAD); // maps.wad -- 4 - If you touch this, make sure to touch up the majormods stuff below. +#ifdef USE_PATCH_FILE + mainwads++; W_VerifyFileMD5(mainwads, ASSET_HASH_PATCH_PK3); // patch.pk3 #endif #else -#ifdef USE_PATCH_DTA - mainwads++; // patch.dta -#endif - mainwads++; // gfx.kart - mainwads++; // textures.kart - mainwads++; // chars.kart - mainwads++; // maps.kart -#ifdef USE_PATCH_KART - mainwads++; // patch.kart + mainwads++; // gfx.pk3 + mainwads++; // textures.pk3 + mainwads++; // chars.pk3 + mainwads++; // maps.wad +#ifdef USE_PATCH_FILE + mainwads++; // patch.pk3 #endif #endif //ifndef DEVELOP diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 0bb87556d..c4d99e840 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -328,6 +328,7 @@ consvar_t cv_1up = {"tv_1up", "5", CV_NETVAR|CV_CHEAT, chanc consvar_t cv_eggmanbox = {"tv_eggman", "5", CV_NETVAR|CV_CHEAT, chances_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};*/ // SRB2kart +consvar_t cv_superring = {"superring", "On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_sneaker = {"sneaker", "On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_rocketsneaker = {"rocketsneaker", "On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_invincibility = {"invincibility", "On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; @@ -365,7 +366,7 @@ consvar_t cv_kartcomeback = {"kartcomeback", "On", CV_NETVAR|CV_CHEAT|CV_CALL|CV consvar_t cv_kartencore = {"kartencore", "Off", CV_NETVAR|CV_CALL|CV_NOINIT, CV_OnOff, KartEncore_OnChange, 0, NULL, NULL, 0, 0, NULL}; static CV_PossibleValue_t kartvoterulechanges_cons_t[] = {{0, "Never"}, {1, "Sometimes"}, {2, "Frequent"}, {3, "Always"}, {0, NULL}}; consvar_t cv_kartvoterulechanges = {"kartvoterulechanges", "Frequent", CV_NETVAR, kartvoterulechanges_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; -static CV_PossibleValue_t kartspeedometer_cons_t[] = {{0, "Off"}, {1, "Kilometers"}, {2, "Miles"}, {3, "Fracunits"}, {0, NULL}}; +static CV_PossibleValue_t kartspeedometer_cons_t[] = {{0, "Off"}, {1, "Percentage"}, {2, "Kilometers"}, {3, "Miles"}, {4, "Fracunits"}, {0, NULL}}; consvar_t cv_kartspeedometer = {"kartdisplayspeed", "Off", CV_SAVE, kartspeedometer_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; // use tics in display static CV_PossibleValue_t kartvoices_cons_t[] = {{0, "Never"}, {1, "Tasteful"}, {2, "Meme"}, {0, NULL}}; consvar_t cv_kartvoices = {"kartvoices", "Tasteful", CV_SAVE, kartvoices_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; diff --git a/src/d_netcmd.h b/src/d_netcmd.h index e6c327abf..73930c172 100644 --- a/src/d_netcmd.h +++ b/src/d_netcmd.h @@ -101,7 +101,7 @@ extern consvar_t cv_1up, cv_eggmanbox; extern consvar_t cv_recycler;*/ // SRB2kart items -extern consvar_t cv_sneaker, cv_rocketsneaker, cv_invincibility, cv_banana; +extern consvar_t cv_superring, cv_sneaker, cv_rocketsneaker, cv_invincibility, cv_banana; extern consvar_t cv_eggmanmonitor, cv_orbinaut, cv_jawz, cv_mine; extern consvar_t cv_ballhog, cv_selfpropelledbomb, cv_grow, cv_shrink; extern consvar_t cv_thundershield, cv_hyudoro, cv_pogospring, cv_kitchensink; diff --git a/src/d_netfil.c b/src/d_netfil.c index 4dcd3da4a..0b9dc9126 100644 --- a/src/d_netfil.c +++ b/src/d_netfil.c @@ -358,7 +358,6 @@ INT32 CL_CheckFiles(void) // return 1; // the first is the iwad (the main wad file) - // we don't care if it's called srb2.srb or srb2.wad. // Never download the IWAD, just assume it's there and identical // ...No! Why were we sending the base wads to begin with?? //fileneeded[0].status = FS_OPEN; @@ -774,17 +773,14 @@ void Got_Filetxpak(void) char *filename = file->filename; static INT32 filetime = 0; - if (!(strcmp(filename, "srb2.srb") - && strcmp(filename, "srb2.wad") - && strcmp(filename, "patch.dta") - //&& strcmp(filename, "music.dta") - && strcmp(filename, "gfx.kart") - && strcmp(filename, "textures.kart") - && strcmp(filename, "chars.kart") - && strcmp(filename, "maps.kart") - && strcmp(filename, "sounds.kart") - && strcmp(filename, "music.kart") - && strcmp(filename, "patch.kart") + if (!(strcmp(filename, "main.kart") + && strcmp(filename, "gfx.pk3") + && strcmp(filename, "textures.pk3") + && strcmp(filename, "chars.pk3") + && strcmp(filename, "maps.wad") + && strcmp(filename, "patch.pk3") + && strcmp(filename, "sounds.wad") + && strcmp(filename, "music.wad") )) I_Error("Tried to download \"%s\"", filename); diff --git a/src/d_player.h b/src/d_player.h index 114674ff5..d2ed296ce 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -216,6 +216,7 @@ typedef enum KITEM_THUNDERSHIELD, KITEM_HYUDORO, KITEM_POGOSPRING, + KITEM_SUPERRING, KITEM_KITCHENSINK, NUMKARTITEMS, @@ -234,6 +235,7 @@ typedef enum //{ SRB2kart - kartstuff typedef enum { + // TODO: Kill this giant array. Add them as actual player_t variables, or condense related timers into their own, smaller arrays. // Basic gameplay things k_position, // Used for Kart positions, mostly for deterministic stuff k_oldposition, // Used for taunting when you pass someone @@ -247,16 +249,10 @@ typedef enum k_dropdash, // Charge up for respawn Drop Dash k_throwdir, // Held dir of controls; 1 = forward, 0 = none, -1 = backward (was "player->heldDir") - k_lapanimation, // Used to show the lap start wing logo animation - k_laphand, // Lap hand gfx to use; 0 = none, 1 = :ok_hand:, 2 = :thumbs_up:, 3 = :thumps_down: - k_cardanimation, // Used to determine the position of some full-screen Battle Mode graphics - k_voices, // Used to stop the player saying more voices than it should - k_tauntvoices, // Used to specifically stop taunt voice spam k_instashield, // Instashield no-damage animation timer - k_enginesnd, // Engine sound number you're on. k_floorboost, // Prevents Sneaker sounds for a breif duration when triggered by a floor panel - k_spinouttype, // Determines whether to thrust forward or not while spinning out; 0 = move forwards, 1 = stay still + k_spinouttype, // Determines whether to thrust forward or not while spinning out; 0 = move forwards, 1 = stay still, 2 = stay still & no flashing tics k_drift, // Drifting Left or Right, plus a bigger counter = sharper turn k_driftend, // Drift has ended, used to adjust character angle after drift @@ -264,19 +260,27 @@ typedef enum k_driftboost, // Boost you get from drifting k_boostcharge, // Charge-up for boosting at the start of the race k_startboost, // Boost you get from start of race or respawn drop dash + k_rings, // Number of held rings + k_pickuprings, // Number of rings being picked up before added to the counter (prevents rings from being deleted forever over 20) + k_userings, // Have to be not holding the item button to change from using rings to using items (or vice versa), to prevent some weirdness with the button + k_ringdelay, // 3 tic delay between every ring usage + k_ringboost, // Ring boost timer + k_ringlock, // Prevent picking up rings while SPB is locked on + k_sparkleanim, // Angle offset for ring sparkle animation k_jmp, // In Mario Kart, letting go of the jump button stops the drift k_offroad, // In Super Mario Kart, going offroad has lee-way of about 1 second before you start losing speed k_pogospring, // Pogo spring bounce effect k_brakestop, // Wait until you've made a complete stop for a few tics before letting brake go in reverse. k_waterskip, // Water skipping counter k_dashpadcooldown, // Separate the vanilla SA-style dash pads from using pw_flashing + k_numboosts, // Count of how many boosts are being stacked, for after image spawning k_boostpower, // Base boost value, for offroad k_speedboost, // Boost value smoothing for max speed k_accelboost, // Boost value smoothing for acceleration + k_draftpower, // Drafting power (from 0 to FRACUNIT), doubles your top speed & acceleration at max + k_draftleeway, // Leniency timer before removing draft power + k_lastdraft, // Last player being drafted k_boostangle, // angle set when not spun out OR boosted to determine what direction you should keep going at if you're spun out and boosted. - k_boostcam, // Camera push forward on boost - k_destboostcam, // Ditto - k_timeovercam, // Camera timer for leaving behind or not k_aizdriftstrat, // Let go of your drift while boosting? Helper for the SICK STRATZ you have just unlocked k_brakedrift, // Helper for brake-drift spark spawning @@ -294,7 +298,9 @@ typedef enum k_hyudorotimer, // Duration of the Hyudoro offroad effect itself k_stealingtimer, // You are stealing an item, this is your timer k_stolentimer, // You are being stolen from, this is your timer + k_superring, // Spawn rings on top of you every tic! k_sneakertimer, // Duration of the Sneaker Boost itself + k_levelbooster, // Duration of a level booster's boost (same as sneaker, but separated for ) k_growshrinktimer, // > 0 = Big, < 0 = small k_squishedtimer, // Squished frame timer k_rocketsneakertimer, // Rocket Sneaker duration timer @@ -315,11 +321,8 @@ typedef enum k_comebackpoints, // Number of times you've bombed or gave an item to someone; once it's 3 it gets set back to 0 and you're given a bumper k_comebackmode, // 0 = bomb, 1 = item k_wanted, // Timer for determining WANTED status, lowers when hitting people, prevents the game turning into Camp Lazlo - k_yougotem, // "You Got Em" gfx when hitting someone as a karma player via a method that gets you back in the game instantly // v1.0.2+ vars - k_itemblink, // Item flashing after roulette, prevents Hyudoro stealing AND serves as a mashing indicator - k_itemblinkmode, // Type of flashing: 0 = white (normal), 1 = red (mashing), 2 = rainbow (enhanced items) k_getsparks, // Disable drift sparks at low speed, JUST enough to give acceleration the actual headstart above speed k_jawztargetdelay, // Delay for Jawz target switching, to make it less twitchy k_spectatewait, // How long have you been waiting as a spectator @@ -327,6 +330,44 @@ typedef enum NUMKARTSTUFF } kartstufftype_t; + +typedef enum +{ + // Unsynced, HUD or clientsided effects + // Item box + khud_itemblink, // Item flashing after roulette, prevents Hyudoro stealing AND serves as a mashing indicator + khud_itemblinkmode, // Type of flashing: 0 = white (normal), 1 = red (mashing), 2 = rainbow (enhanced items) + + // Rings + khud_ringframe, // Ring spin frame + khud_ringtics, // Tics left until next ring frame + khud_ringdelay, // Next frame's tics + khud_ringspblock, // Which frame of the SPB ring lock animation to use + + // Lap finish + khud_lapanimation, // Used to show the lap start wing logo animation + khud_laphand, // Lap hand gfx to use; 0 = none, 1 = :ok_hand:, 2 = :thumbs_up:, 3 = :thumps_down: + + // Camera + khud_boostcam, // Camera push forward on boost + khud_destboostcam, // Ditto + khud_timeovercam, // Camera timer for leaving behind or not + + // Sounds + khud_enginesnd, // Engine sound offset this player is using. + khud_voices, // Used to stop the player saying more voices than it should + khud_tauntvoices, // Used to specifically stop taunt voice spam + + // Battle + khud_cardanimation, // Used to determine the position of some full-screen Battle Mode graphics + khud_yougotem, // "You Got Em" gfx when hitting someone as a karma player via a method that gets you back in the game instantly + + NUMKARTHUD +} karthudtype_t; + +// QUICKLY GET EITHER SNEAKER OR LEVEL BOOSTER SINCE THEY ARE FUNCTIONALLY IDENTICAL +#define EITHERSNEAKER(p) (p->kartstuff[k_sneakertimer] || p->kartstuff[k_levelbooster]) + //} #define WEP_AUTO 1 @@ -387,6 +428,7 @@ typedef struct player_s // SRB2kart stuff INT32 kartstuff[NUMKARTSTUFF]; + INT32 karthud[NUMKARTHUD]; angle_t frameangle; // for the player add the ability to have the sprite only face other angles INT16 lturn_max[MAXPREDICTTICS]; // What's the expected turn value for full-left for a number of frames back (to account for netgame latency)? INT16 rturn_max[MAXPREDICTTICS]; // Ditto but for full-right diff --git a/src/dehacked.c b/src/dehacked.c index b311a860c..be45f3f0f 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -3749,8 +3749,7 @@ static void DEH_LoadDehackedFile(MYFILE *f, UINT16 wad) } else if (fastcmp(word, "SRB2")) { - if (mainwads) // srb2.srb triggers this warning otherwise - deh_warning("Patch is only compatible with base SRB2."); + deh_warning("Patch is only compatible with base SRB2."); } // Clear all data in certain locations (mostly for unlocks) // Unless you REALLY want to piss people off, @@ -4797,6 +4796,18 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit // Ring "S_RING", + "S_FASTRING1", + "S_FASTRING2", + "S_FASTRING3", + "S_FASTRING4", + "S_FASTRING5", + "S_FASTRING6", + "S_FASTRING7", + "S_FASTRING8", + "S_FASTRING9", + "S_FASTRING10", + "S_FASTRING11", + "S_FASTRING12", // Blue Sphere for special stages "S_BLUEBALL", @@ -7165,6 +7176,29 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_OPAQUESMOKE4", "S_OPAQUESMOKE5", + "S_RINGDEBT", + "S_RINGSPARKS1", + "S_RINGSPARKS2", + "S_RINGSPARKS3", + "S_RINGSPARKS4", + "S_RINGSPARKS5", + "S_RINGSPARKS6", + "S_RINGSPARKS7", + "S_RINGSPARKS8", + "S_RINGSPARKS9", + "S_RINGSPARKS10", + "S_RINGSPARKS11", + "S_RINGSPARKS12", + "S_RINGSPARKS13", + "S_RINGSPARKS14", + "S_RINGSPARKS15", + + "S_DRAFTDUST1", + "S_DRAFTDUST2", + "S_DRAFTDUST3", + "S_DRAFTDUST4", + "S_DRAFTDUST5", + #ifdef SEENAMES "S_NAMECHECK", #endif @@ -7951,6 +7985,8 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s "MT_LIONMAN", "MT_KARMAFIREWORK", + "MT_RINGSPARKS", + "MT_DRAFTDUST", #ifdef SEENAMES "MT_NAMECHECK", @@ -8155,51 +8191,46 @@ static const char *COLOR_ENUMS[] = { // Rejigged for Kart. "GREY", // SKINCOLOR_GREY "NICKEL", // SKINCOLOR_NICKEL "BLACK", // SKINCOLOR_BLACK - "SKUNK", // SKINCOLOR_SKUNK "FAIRY", // SKINCOLOR_FAIRY "POPCORN", // SKINCOLOR_POPCORN "ARTICHOKE", // SKINCOLOR_ARTICHOKE "PIGEON", // SKINCOLOR_PIGEON "SEPIA", // SKINCOLOR_SEPIA "BEIGE", // SKINCOLOR_BEIGE - "WALNUT", // SKINCOLOR_WALNUT + "CARAMEL", // SKINCOLOR_CARAMEL + "PEACH", // SKINCOLOR_PEACH "BROWN", // SKINCOLOR_BROWN "LEATHER", // SKINCOLOR_LEATHER "SALMON", // SKINCOLOR_SALMON "PINK", // SKINCOLOR_PINK "ROSE", // SKINCOLOR_ROSE - "BRICK", // SKINCOLOR_BRICK "CINNAMON", // SKINCOLOR_CINNAMON "RUBY", // SKINCOLOR_RUBY "RASPBERRY", // SKINCOLOR_RASPBERRY - "CHERRY", // SKINCOLOR_CHERRY "RED", // SKINCOLOR_RED "CRIMSON", // SKINCOLOR_CRIMSON "MAROON", // SKINCOLOR_MAROON "LEMONADE", // SKINCOLOR_LEMONADE - "FLAME", // SKINCOLOR_FLAME "SCARLET", // SKINCOLOR_SCARLET "KETCHUP", // SKINCOLOR_KETCHUP "DAWN", // SKINCOLOR_DAWN "SUNSET", // SKINCOLOR_SUNSET "CREAMSICLE", // SKINCOLOR_CREAMSICLE "ORANGE", // SKINCOLOR_ORANGE - "PUMPKIN", // SKINCOLOR_PUMPKIN "ROSEWOOD", // SKINCOLOR_ROSEWOOD - "BURGUNDY", // SKINCOLOR_BURGUNDY "TANGERINE", // SKINCOLOR_TANGERINE - "PEACH", // SKINCOLOR_PEACH - "CARAMEL", // SKINCOLOR_CARAMEL + "TAN", // SKINCOLOR_TAN "CREAM", // SKINCOLOR_CREAM "GOLD", // SKINCOLOR_GOLD "ROYAL", // SKINCOLOR_ROYAL "BRONZE", // SKINCOLOR_BRONZE "COPPER", // SKINCOLOR_COPPER - "QUARRY", // SKINCOLOR_QUARRY "YELLOW", // SKINCOLOR_YELLOW "MUSTARD", // SKINCOLOR_MUSTARD - "CROCODILE", // SKINCOLOR_CROCODILE + "BANANA", // SKINCOLOR_BANANA "OLIVE", // SKINCOLOR_OLIVE + "CROCODILE", // SKINCOLOR_CROCODILE + "PERIDOT", // SKINCOLOR_PERIDOT "VOMIT", // SKINCOLOR_VOMIT "GARDEN", // SKINCOLOR_GARDEN "LIME", // SKINCOLOR_LIME @@ -8212,14 +8243,16 @@ static const char *COLOR_ENUMS[] = { // Rejigged for Kart. "MINT", // SKINCOLOR_MINT "GREEN", // SKINCOLOR_GREEN "PINETREE", // SKINCOLOR_PINETREE - "EMERALD", // SKINCOLOR_EMERALD + "TURTLE", // SKINCOLOR_TURTLE "SWAMP", // SKINCOLOR_SWAMP "DREAM", // SKINCOLOR_DREAM "PLAGUE", // SKINCOLOR_PLAGUE + "EMERALD", // SKINCOLOR_EMERALD "ALGAE", // SKINCOLOR_ALGAE "CARIBBEAN", // SKINCOLOR_CARIBBEAN "AZURE", // SKINCOLOR_AZURE - "AQUA", // SKINCOLOR_AQUA + "AQUAMARINE", // SKINCOLOR_AQUAMARINE + "TURQUOISE", // SKINCOLOR_TURQUOISE "TEAL", // SKINCOLOR_TEAL "CYAN", // SKINCOLOR_CYAN "JAWZ", // SKINCOLOR_JAWZ @@ -8229,20 +8262,22 @@ static const char *COLOR_ENUMS[] = { // Rejigged for Kart. "SLATE", // SKINCOLOR_SLATE "STEEL", // SKINCOLOR_STEEL "THUNDER", // SKINCOLOR_THUNDER + "NOVA", // SKINCOLOR_NOVA "RUST", // SKINCOLOR_RUST "WRISTWATCH", // SKINCOLOR_WRISTWATCH "JET", // SKINCOLOR_JET "SAPPHIRE", // SKINCOLOR_SAPPHIRE + "ULTRAMARINE", // SKINCOLOR_ULTRAMARINE "PERIWINKLE", // SKINCOLOR_PERIWINKLE "BLUE", // SKINCOLOR_BLUE "BLUEBERRY", // SKINCOLOR_BLUEBERRY - "NOVA", // SKINCOLOR_NOVA + "THISTLE", // SKINCOLOR_THISTLE + "PURPLE", // SKINCOLOR_PURPLE "PASTEL", // SKINCOLOR_PASTEL "MOONSLAM", // SKINCOLOR_MOONSLAM - "ULTRAVIOLET", // SKINCOLOR_ULTRAVIOLET "DUSK", // SKINCOLOR_DUSK "BUBBLEGUM", // SKINCOLOR_BUBBLEGUM - "PURPLE", // SKINCOLOR_PURPLE + "MAGENTA", // SKINCOLOR_MAGENTA "FUCHSIA", // SKINCOLOR_FUCHSIA "TOXIC", // SKINCOLOR_TOXIC "MAUVE", // SKINCOLOR_MAUVE @@ -8250,6 +8285,7 @@ static const char *COLOR_ENUMS[] = { // Rejigged for Kart. "BYZANTIUM", // SKINCOLOR_BYZANTIUM "POMEGRANATE", // SKINCOLOR_POMEGRANATE "LILAC", // SKINCOLOR_LILAC + "TAFFY", // SKINCOLOR_TAFFY // Special super colors // Super Sonic Yellow @@ -8365,13 +8401,7 @@ static const char *const KARTSTUFF_LIST[] = { "DROPDASH", "THROWDIR", - "LAPANIMATION", - "LAPHAND", - "CARDANIMATION", - "VOICES", - "TAUNTVOICES", "INSTASHIELD", - "ENGINESND", "FLOORBOOST", "SPINOUTTYPE", @@ -8382,19 +8412,27 @@ static const char *const KARTSTUFF_LIST[] = { "DRIFTBOOST", "BOOSTCHARGE", "STARTBOOST", + "RINGS", + "PICKUPRINGS", + "USERINGS", + "RINGDELAY", + "RINGBOOST", + "RINGLOCK", + "SPARKLEANIM", "JMP", "OFFROAD", "POGOSPRING", "BRAKESTOP", "WATERSKIP", "DASHPADCOOLDOWN", + "NUMBOOSTS", "BOOSTPOWER", "SPEEDBOOST", "ACCELBOOST", + "DRAFTPOWER", + "DRAFTLEEWAY", + "LASTDRAFT", "BOOSTANGLE", - "BOOSTCAM", - "DESTBOOSTCAM", - "TIMEOVERCAM", "AIZDRIFTSTRAT", "BRAKEDRIFT", @@ -8409,7 +8447,9 @@ static const char *const KARTSTUFF_LIST[] = { "HYUDOROTIMER", "STEALINGTIMER", "STOLENTIMER", + "SUPERRING", "SNEAKERTIMER", + "LEVELBOOSTER", "GROWSHRINKTIMER", "SQUISHEDTIMER", "ROCKETSNEAKERTIMER", @@ -8429,10 +8469,7 @@ static const char *const KARTSTUFF_LIST[] = { "COMEBACKPOINTS", "COMEBACKMODE", "WANTED", - "YOUGOTEM", - "ITEMBLINK", - "ITEMBLINKMODE", "GETSPARKS", "JAWZTARGETDELAY", "SPECTATEWAIT", @@ -8530,9 +8567,13 @@ struct { // Frame settings {"FF_FRAMEMASK",FF_FRAMEMASK}, - {"FF_PAPERSPRITE",FF_PAPERSPRITE}, {"FF_ANIMATE",FF_ANIMATE}, + {"FF_RANDOMANIM",FF_RANDOMANIM}, + {"FF_GLOBALANIM",FF_GLOBALANIM}, {"FF_FULLBRIGHT",FF_FULLBRIGHT}, + {"FF_SEMIBRIGHT",FF_SEMIBRIGHT}, + {"FF_PAPERSPRITE",FF_PAPERSPRITE}, + {"FF_VERTICALFLIP",FF_VERTICALFLIP}, {"FF_TRANSMASK",FF_TRANSMASK}, {"FF_TRANSSHIFT",FF_TRANSSHIFT}, // new preshifted translucency (used in source) @@ -8889,11 +8930,11 @@ struct { {"V_SKYMAP",V_SKYMAP}, {"V_LAVENDERMAP",V_LAVENDERMAP}, {"V_GOLDMAP",V_GOLDMAP}, - {"V_TEAMAP",V_TEAMAP}, - {"V_STEELMAP",V_STEELMAP}, + {"V_AQUAMAP",V_AQUAMAP}, + {"V_MAGENTAMAP",V_MAGENTAMAP}, {"V_PINKMAP",V_PINKMAP}, {"V_BROWNMAP",V_BROWNMAP}, - {"V_PEACHMAP",V_PEACHMAP}, + {"V_TANMAP",V_TANMAP}, {"V_TRANSLUCENT",V_TRANSLUCENT}, {"V_10TRANS",V_10TRANS}, {"V_20TRANS",V_20TRANS}, @@ -8957,6 +8998,7 @@ struct { {"KITEM_THUNDERSHIELD",KITEM_THUNDERSHIELD}, {"KITEM_HYUDORO",KITEM_HYUDORO}, {"KITEM_POGOSPRING",KITEM_POGOSPRING}, + {"KITEM_SUPERRING",KITEM_SUPERRING}, {"KITEM_KITCHENSINK",KITEM_KITCHENSINK}, {"NUMKARTITEMS",NUMKARTITEMS}, {"KRITEM_TRIPLESNEAKER",KRITEM_TRIPLESNEAKER}, // Additional roulette IDs (not usable for much in Lua besides K_GetItemPatch) @@ -9350,7 +9392,7 @@ fixed_t get_number(const char *word) void DEH_Check(void) { -#if defined(_DEBUG) || defined(PARANOIA) +//#if defined(_DEBUG) || defined(PARANOIA) const size_t dehstates = sizeof(STATE_LIST)/sizeof(const char*); const size_t dehmobjs = sizeof(MOBJTYPE_LIST)/sizeof(const char*); const size_t dehpowers = sizeof(POWERS_LIST)/sizeof(const char*); @@ -9371,7 +9413,7 @@ void DEH_Check(void) if (dehcolors != MAXTRANSLATIONS) I_Error("You forgot to update the Dehacked colors list, you dolt!\n(%d colors defined, versus %s in the Dehacked list)\n", MAXTRANSLATIONS, sizeu1(dehcolors)); -#endif +//#endif } #ifdef HAVE_BLUA diff --git a/src/doomdef.h b/src/doomdef.h index 4ab40853a..728dc3ab9 100644 --- a/src/doomdef.h +++ b/src/doomdef.h @@ -149,24 +149,21 @@ extern FILE *logstream; // most interface strings are ignored in development mode. // we use comprevision and compbranch instead. #else -#define VERSION 110 // Game version +#define VERSION 200 // Game version #define SUBVERSION 0 // more precise version number -#define VERSIONSTRING "v1.1" -#define VERSIONSTRINGW L"v1.1" +#define VERSIONSTRING "v2.0" +#define VERSIONSTRINGW L"v2.0" // Hey! If you change this, add 1 to the MODVERSION below! Otherwise we can't force updates! // And change CMakeLists.txt, for CMake users! // AND appveyor.yml, for the build bots! #endif // Maintain compatibility with 1.0.x record attack replays? -#define DEMO_COMPAT_100 +//#define DEMO_COMPAT_100 // Does this version require an added patch file? // Comment or uncomment this as necessary. -//#define USE_PATCH_DTA - -// Kart has it's own, as well. -#define USE_PATCH_KART +#define USE_PATCH_FILE // Use .kart extension addons #define USE_KART @@ -225,7 +222,7 @@ extern FILE *logstream; // it's only for detection of the version the player is using so the MS can alert them of an update. // Only set it higher, not lower, obviously. // Note that we use this to help keep internal testing in check; this is why v2.1.0 is not version "1". -#define MODVERSION 5 +#define MODVERSION 6 // Filter consvars by version // To version config.cfg, MAJOREXECVERSION is set equal to MODVERSION automatically. @@ -260,51 +257,46 @@ typedef enum SKINCOLOR_GREY, SKINCOLOR_NICKEL, SKINCOLOR_BLACK, - SKINCOLOR_SKUNK, SKINCOLOR_FAIRY, SKINCOLOR_POPCORN, SKINCOLOR_ARTICHOKE, SKINCOLOR_PIGEON, SKINCOLOR_SEPIA, SKINCOLOR_BEIGE, - SKINCOLOR_WALNUT, + SKINCOLOR_CARAMEL, + SKINCOLOR_PEACH, SKINCOLOR_BROWN, SKINCOLOR_LEATHER, SKINCOLOR_SALMON, SKINCOLOR_PINK, SKINCOLOR_ROSE, - SKINCOLOR_BRICK, SKINCOLOR_CINNAMON, SKINCOLOR_RUBY, SKINCOLOR_RASPBERRY, - SKINCOLOR_CHERRY, SKINCOLOR_RED, SKINCOLOR_CRIMSON, SKINCOLOR_MAROON, SKINCOLOR_LEMONADE, - SKINCOLOR_FLAME, SKINCOLOR_SCARLET, SKINCOLOR_KETCHUP, SKINCOLOR_DAWN, SKINCOLOR_SUNSET, SKINCOLOR_CREAMSICLE, SKINCOLOR_ORANGE, - SKINCOLOR_PUMPKIN, SKINCOLOR_ROSEWOOD, - SKINCOLOR_BURGUNDY, SKINCOLOR_TANGERINE, - SKINCOLOR_PEACH, - SKINCOLOR_CARAMEL, + SKINCOLOR_TAN, SKINCOLOR_CREAM, SKINCOLOR_GOLD, SKINCOLOR_ROYAL, SKINCOLOR_BRONZE, SKINCOLOR_COPPER, - SKINCOLOR_QUARRY, SKINCOLOR_YELLOW, SKINCOLOR_MUSTARD, - SKINCOLOR_CROCODILE, + SKINCOLOR_BANANA, SKINCOLOR_OLIVE, + SKINCOLOR_CROCODILE, + SKINCOLOR_PERIDOT, SKINCOLOR_VOMIT, SKINCOLOR_GARDEN, SKINCOLOR_LIME, @@ -317,14 +309,16 @@ typedef enum SKINCOLOR_MINT, SKINCOLOR_GREEN, SKINCOLOR_PINETREE, - SKINCOLOR_EMERALD, + SKINCOLOR_TURTLE, SKINCOLOR_SWAMP, SKINCOLOR_DREAM, SKINCOLOR_PLAGUE, + SKINCOLOR_EMERALD, SKINCOLOR_ALGAE, SKINCOLOR_CARIBBEAN, SKINCOLOR_AZURE, - SKINCOLOR_AQUA, + SKINCOLOR_AQUAMARINE, + SKINCOLOR_TURQUOISE, SKINCOLOR_TEAL, SKINCOLOR_CYAN, SKINCOLOR_JAWZ, // Oni's torment @@ -334,20 +328,22 @@ typedef enum SKINCOLOR_SLATE, SKINCOLOR_STEEL, SKINCOLOR_THUNDER, + SKINCOLOR_NOVA, SKINCOLOR_RUST, SKINCOLOR_WRISTWATCH, SKINCOLOR_JET, SKINCOLOR_SAPPHIRE, // sweet mother, i cannot weave - slender aphrodite has overcome me with longing for a girl + SKINCOLOR_ULTRAMARINE, SKINCOLOR_PERIWINKLE, SKINCOLOR_BLUE, SKINCOLOR_BLUEBERRY, - SKINCOLOR_NOVA, + SKINCOLOR_THISTLE, + SKINCOLOR_PURPLE, SKINCOLOR_PASTEL, SKINCOLOR_MOONSLAM, - SKINCOLOR_ULTRAVIOLET, SKINCOLOR_DUSK, SKINCOLOR_BUBBLEGUM, - SKINCOLOR_PURPLE, + SKINCOLOR_MAGENTA, SKINCOLOR_FUCHSIA, SKINCOLOR_TOXIC, SKINCOLOR_MAUVE, @@ -355,6 +351,7 @@ typedef enum SKINCOLOR_BYZANTIUM, SKINCOLOR_POMEGRANATE, SKINCOLOR_LILAC, + SKINCOLOR_TAFFY, // "Careful! MAXSKINCOLORS cannot be greater than 0x40 -- Which it is now." // (This comment is a dirty liar! This is only limited by the integer type, so 255 for UINT8.) diff --git a/src/f_finale.c b/src/f_finale.c index 2bf5c7438..9a4be070c 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -173,7 +173,7 @@ static void F_SkyScroll(INT32 scrollspeed) // SRB2Kart: F_DrawPatchCol is over-engineered; recoded to be less shitty and error-prone if (rendermode != render_none) { - V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 120); + V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 0); x = -((INT32)animtimer); y = 0; @@ -274,7 +274,7 @@ static void F_IntroDrawScene(void) highres = true; } - V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 120); + V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 0); if (background) { @@ -976,7 +976,7 @@ void F_TitleScreenDrawer(void) } else if (finalecount < 52) { - V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 120); + V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 0); V_DrawSmallScaledPatch(84, 36, 0, ttkflash); } else @@ -992,7 +992,7 @@ void F_TitleScreenDrawer(void) V_DrawSciencePatch(280< 0) || player->kartstuff[k_sneakertimer]) + if (InputDown(gc_accelerate, ssplayer) || (gamepadjoystickmove && axis > 0) || EITHERSNEAKER(player)) { cmd->buttons |= BT_ACCELERATE; forward = forwardmove[1]; // 50 @@ -1555,10 +1555,10 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer) cmd->angleturn *= realtics; // SRB2kart - no additional angle if not moving - if (((player->mo && player->speed > 0) // Moving + if ((player->mo && player->speed > 0) // Moving || (leveltime > starttime && (cmd->buttons & BT_ACCELERATE && cmd->buttons & BT_BRAKE)) // Rubber-burn turn || (player->kartstuff[k_respawn]) // Respawning - || (player->spectator || objectplacing))) // Not a physical player + || (player->spectator || objectplacing)) // Not a physical player lang += (cmd->angleturn<<16); cmd->angleturn = (INT16)(lang >> 16); @@ -2580,6 +2580,7 @@ void G_PlayerReborn(INT32 player) INT32 bumper; INT32 comebackpoints; INT32 wanted; + INT32 rings; INT32 respawnflip; boolean songcredit = false; @@ -2631,6 +2632,7 @@ void G_PlayerReborn(INT32 player) itemamount = 0; growshrinktimer = 0; bumper = (G_BattleGametype() ? cv_kartbumpers.value : 0); + rings = (G_BattleGametype() ? 0 : 5); comebackpoints = 0; wanted = 0; starpostwp = 0; @@ -2660,6 +2662,7 @@ void G_PlayerReborn(INT32 player) growshrinktimer = 0; bumper = players[player].kartstuff[k_bumper]; + rings = players[player].kartstuff[k_rings]; comebackpoints = players[player].kartstuff[k_comebackpoints]; wanted = players[player].kartstuff[k_wanted]; } @@ -2704,17 +2707,19 @@ void G_PlayerReborn(INT32 player) p->pity = pity; // SRB2kart - p->kartstuff[k_starpostwp] = starpostwp; // TODO: get these out of kartstuff, it causes desync + p->kartstuff[k_starpostwp] = starpostwp; // TODO: get these out of kartstuff, it causes desync (Does it...?) p->kartstuff[k_itemroulette] = itemroulette; p->kartstuff[k_roulettetype] = roulettetype; p->kartstuff[k_itemtype] = itemtype; p->kartstuff[k_itemamount] = itemamount; p->kartstuff[k_growshrinktimer] = growshrinktimer; p->kartstuff[k_bumper] = bumper; + p->kartstuff[k_rings] = rings; p->kartstuff[k_comebackpoints] = comebackpoints; p->kartstuff[k_comebacktimer] = comebacktime; p->kartstuff[k_wanted] = wanted; p->kartstuff[k_eggmanblame] = -1; + p->kartstuff[k_lastdraft] = -1; p->kartstuff[k_starpostflip] = respawnflip; // Don't do anything immediately @@ -3439,12 +3444,12 @@ UINT8 G_GetGametypeColor(INT16 gt) { if (modeattacking // == ATTACKING_RECORD || gamestate == GS_TIMEATTACK) - return orangemap[120]; + return orangemap[0]; if (gt == GT_MATCH) - return redmap[120]; + return redmap[0]; if (gt == GT_RACE) - return skymap[120]; - return 247; // FALLBACK + return skymap[0]; + return 255; // FALLBACK } // @@ -5103,7 +5108,8 @@ void G_ReadDemoTiccmd(ticcmd_t *cmd, INT32 playernum) || (leveltime > starttime && (cmd->buttons & BT_ACCELERATE && cmd->buttons & BT_BRAKE)) // Rubber-burn turn || (players[displayplayers[0]].kartstuff[k_respawn]) // Respawning || (players[displayplayers[0]].spectator || objectplacing)) // Not a physical player - && !(players[displayplayers[0]].kartstuff[k_spinouttimer] && players[displayplayers[0]].kartstuff[k_sneakertimer])) // Spinning and boosting cancels out spinout + && !(players[displayplayers[0]].kartstuff[k_spinouttimer] + && (players[displayplayers[0]].kartstuff[k_sneakertimer] || players[displayplayers[0]].kartstuff[k_levelbooster]))) // Spinning and boosting cancels out spinout localangle[0] += (cmd->angleturn<<16); if (!(demoflags & DF_GHOST) && *demo_p == DEMOMARKER) @@ -5351,7 +5357,7 @@ void G_WriteGhostTic(mobj_t *ghost, INT32 playernum) } // Store the sprite frame. - frame = ghost->frame & 0xFF; + frame = ghost->frame & FF_FRAMEMASK; if (frame != oldghost[playernum].frame) { oldghost[playernum].frame = frame; diff --git a/src/hardware/hw_defs.h b/src/hardware/hw_defs.h index b37850bb7..9ecb16a56 100644 --- a/src/hardware/hw_defs.h +++ b/src/hardware/hw_defs.h @@ -46,8 +46,8 @@ typedef unsigned char FBOOLEAN; #define HWR_PATCHES_CHROMAKEY_COLORINDEX 0 #define HWR_CHROMAKEY_EQUIVALENTCOLORINDEX 1 #else -#define HWR_PATCHES_CHROMAKEY_COLORINDEX 247 -#define HWR_CHROMAKEY_EQUIVALENTCOLORINDEX 220 +#define HWR_PATCHES_CHROMAKEY_COLORINDEX 255 +#define HWR_CHROMAKEY_EQUIVALENTCOLORINDEX 130 #endif // the chroma key color shows on border sprites, set it to black diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index 63cde0ca0..3fe1e18be 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -4220,7 +4220,11 @@ static void HWR_DrawSpriteShadow(gr_vissprite_t *spr, GLPatch_t *gpatch, float t INT32 light = R_GetPlaneLight(sector, spr->mobj->floorz, false); if (!(spr->mobj->frame & FF_FULLBRIGHT)) + { lightlevel = *sector->lightlist[light].lightlevel; + if (spr->mobj->frame & FF_SEMIBRIGHT) + lightlevel = 128 + (lightlevel>>1); + } if (sector->lightlist[light].extra_colormap) colormap = sector->lightlist[light].extra_colormap; @@ -4441,16 +4445,20 @@ static void HWR_SplitSprite(gr_vissprite_t *spr) alpha = Surf.FlatColor.s.alpha; - // Start with the lightlevel and colormap from the top of the sprite - lightlevel = *list[sector->numlights - 1].lightlevel; - colormap = list[sector->numlights - 1].extra_colormap; - i = 0; temp = FLOAT_TO_FIXED(realtop); - if (spr->mobj->frame & FF_FULLBRIGHT) - lightlevel = 255; - #ifdef ESLOPE + // Start with the lightlevel and colormap from the top of the sprite + lightlevel = 255; + colormap = list[sector->numlights - 1].extra_colormap; + + if (!(spr->mobj->frame & FF_FULLBRIGHT)) + { + lightlevel = *list[sector->numlights - 1].lightlevel; + if (spr->mobj->frame & FF_SEMIBRIGHT) + lightlevel = 128 + (lightlevel>>1); + } + for (i = 1; i < sector->numlights; i++) { fixed_t h = sector->lightlist[i].slope ? P_GetZAt(sector->lightlist[i].slope, spr->mobj->x, spr->mobj->y) @@ -4458,7 +4466,11 @@ static void HWR_SplitSprite(gr_vissprite_t *spr) if (h <= temp) { if (!(spr->mobj->frame & FF_FULLBRIGHT)) + { lightlevel = *list[i-1].lightlevel; + if (spr->mobj->frame & FF_SEMIBRIGHT) + lightlevel = 128 + (lightlevel>>1); + } colormap = list[i-1].extra_colormap; break; } @@ -4466,7 +4478,11 @@ static void HWR_SplitSprite(gr_vissprite_t *spr) #else i = R_GetPlaneLight(sector, temp, false); if (!(spr->mobj->frame & FF_FULLBRIGHT)) + { lightlevel = *list[i].lightlevel; + if (spr->mobj->frame & FF_SEMIBRIGHT) + lightlevel = 128 + (lightlevel>>1); + } colormap = list[i].extra_colormap; #endif @@ -4482,7 +4498,11 @@ static void HWR_SplitSprite(gr_vissprite_t *spr) if (!(list[i].flags & FF_NOSHADE) && (list[i].flags & FF_CUTSPRITES)) { if (!(spr->mobj->frame & FF_FULLBRIGHT)) + { lightlevel = *list[i].lightlevel; + if (spr->mobj->frame & FF_SEMIBRIGHT) + lightlevel = 128 + (lightlevel>>1); + } colormap = list[i].extra_colormap; } @@ -4775,7 +4795,11 @@ static void HWR_DrawSprite(gr_vissprite_t *spr) extracolormap_t *colormap = sector->extra_colormap; if (!(spr->mobj->frame & FF_FULLBRIGHT)) + { lightlevel = sector->lightlevel; + if (spr->mobj->frame & FF_SEMIBRIGHT) + lightlevel = 128 + (lightlevel>>1); + } if (colormap) Surf.FlatColor.rgba = HWR_Lighting(lightlevel, colormap->rgba, colormap->fadergba, false, false); @@ -4886,6 +4910,9 @@ static inline void HWR_DrawPrecipitationSprite(gr_vissprite_t *spr) colormap = sector->extra_colormap; } + if (spr->mobj->frame & FF_SEMIBRIGHT) + lightlevel = 128 + (lightlevel>>1); + if (colormap) Surf.FlatColor.rgba = HWR_Lighting(lightlevel, colormap->rgba, colormap->fadergba, false, false); else @@ -5515,6 +5542,7 @@ static void HWR_ProjectSprite(mobj_t *thing) size_t lumpoff; unsigned rot; UINT8 flip; + boolean vflip = (!(thing->eflags & MFE_VERTICALFLIP) != !(thing->frame & FF_VERTICALFLIP)); angle_t ang; INT32 heightsec, phs; const boolean papersprite = (thing->frame & FF_PAPERSPRITE); @@ -5646,7 +5674,7 @@ static void HWR_ProjectSprite(mobj_t *thing) x1 = tr_x + x1 * rightcos; x2 = tr_x - x2 * rightcos; - if (thing->eflags & MFE_VERTICALFLIP) + if (vflip) { gz = FIXED_TO_FLOAT(thing->z+thing->height) - FIXED_TO_FLOAT(spritecachedinfo[lumpoff].topoffset) * this_scale; gzt = gz + FIXED_TO_FLOAT(spritecachedinfo[lumpoff].height) * this_scale; @@ -5733,10 +5761,7 @@ static void HWR_ProjectSprite(mobj_t *thing) //CONS_Debug(DBG_RENDER, "------------------\nH: sprite : %d\nH: frame : %x\nH: type : %d\nH: sname : %s\n\n", // thing->sprite, thing->frame, thing->type, sprnames[thing->sprite]); - if (thing->eflags & MFE_VERTICALFLIP) - vis->vflip = true; - else - vis->vflip = false; + vis->vflip = vflip; vis->precip = false; } diff --git a/src/hu_stuff.c b/src/hu_stuff.c index f343f12b7..7a912e010 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -793,13 +793,14 @@ static void Got_Saycmd(UINT8 **p, INT32 playernum) case SKINCOLOR_GREY: case SKINCOLOR_NICKEL: case SKINCOLOR_BLACK: - case SKINCOLOR_SKUNK: + case SKINCOLOR_PLATINUM: case SKINCOLOR_JET: cstart = "\x86"; // V_GRAYMAP break; case SKINCOLOR_SEPIA: case SKINCOLOR_BEIGE: - case SKINCOLOR_WALNUT: + case SKINCOLOR_CARAMEL: + case SKINCOLOR_PEACH: case SKINCOLOR_BROWN: case SKINCOLOR_LEATHER: case SKINCOLOR_RUST: @@ -810,20 +811,18 @@ static void Got_Saycmd(UINT8 **p, INT32 playernum) case SKINCOLOR_SALMON: case SKINCOLOR_PINK: case SKINCOLOR_ROSE: - case SKINCOLOR_BRICK: case SKINCOLOR_LEMONADE: case SKINCOLOR_BUBBLEGUM: case SKINCOLOR_LILAC: + case SKINCOLOR_TAFFY: cstart = "\x8d"; // V_PINKMAP break; case SKINCOLOR_CINNAMON: case SKINCOLOR_RUBY: case SKINCOLOR_RASPBERRY: - case SKINCOLOR_CHERRY: case SKINCOLOR_RED: case SKINCOLOR_CRIMSON: case SKINCOLOR_MAROON: - case SKINCOLOR_FLAME: case SKINCOLOR_SCARLET: case SKINCOLOR_KETCHUP: cstart = "\x85"; // V_REDMAP @@ -832,16 +831,13 @@ static void Got_Saycmd(UINT8 **p, INT32 playernum) case SKINCOLOR_SUNSET: case SKINCOLOR_CREAMSICLE: case SKINCOLOR_ORANGE: - case SKINCOLOR_PUMPKIN: case SKINCOLOR_ROSEWOOD: - case SKINCOLOR_BURGUNDY: case SKINCOLOR_TANGERINE: cstart = "\x87"; // V_ORANGEMAP break; - case SKINCOLOR_PEACH: - case SKINCOLOR_CARAMEL: + case SKINCOLOR_TAN: case SKINCOLOR_CREAM: - cstart = "\x8f"; // V_PEACHMAP + cstart = "\x8f"; // V_TANMAP break; case SKINCOLOR_GOLD: case SKINCOLOR_ROYAL: @@ -851,39 +847,43 @@ static void Got_Saycmd(UINT8 **p, INT32 playernum) cstart = "\x8A"; // V_GOLDMAP break; case SKINCOLOR_POPCORN: - case SKINCOLOR_QUARRY: case SKINCOLOR_YELLOW: case SKINCOLOR_MUSTARD: - case SKINCOLOR_CROCODILE: + case SKINCOLOR_BANANA: case SKINCOLOR_OLIVE: + case SKINCOLOR_CROCODILE: cstart = "\x82"; // V_YELLOWMAP break; case SKINCOLOR_ARTICHOKE: + case SKINCOLOR_PERIDOT: case SKINCOLOR_VOMIT: case SKINCOLOR_GARDEN: - case SKINCOLOR_TEA: - case SKINCOLOR_PISTACHIO: - cstart = "\x8b"; // V_TEAMAP - break; case SKINCOLOR_LIME: case SKINCOLOR_HANDHELD: + case SKINCOLOR_TEA: + case SKINCOLOR_PISTACHIO: case SKINCOLOR_MOSS: case SKINCOLOR_CAMOUFLAGE: case SKINCOLOR_ROBOHOOD: case SKINCOLOR_MINT: case SKINCOLOR_GREEN: case SKINCOLOR_PINETREE: - case SKINCOLOR_EMERALD: + case SKINCOLOR_TURTLE: case SKINCOLOR_SWAMP: case SKINCOLOR_DREAM: case SKINCOLOR_PLAGUE: + case SKINCOLOR_EMERALD: case SKINCOLOR_ALGAE: cstart = "\x83"; // V_GREENMAP break; case SKINCOLOR_CARIBBEAN: case SKINCOLOR_AZURE: - case SKINCOLOR_AQUA: + case SKINCOLOR_AQUAMARINE: + case SKINCOLOR_TURQUOISE: case SKINCOLOR_TEAL: + cstart = "\x8b"; // V_AQUAMAP + break; + case SKINCOLOR_PIGEON: case SKINCOLOR_CYAN: case SKINCOLOR_JAWZ: case SKINCOLOR_CERULEAN: @@ -891,24 +891,24 @@ static void Got_Saycmd(UINT8 **p, INT32 playernum) case SKINCOLOR_SAPPHIRE: cstart = "\x88"; // V_SKYMAP break; - case SKINCOLOR_PIGEON: - case SKINCOLOR_PLATINUM: case SKINCOLOR_STEEL: - cstart = "\x8c"; // V_STEELMAP - break; + case SKINCOLOR_ULTRAMARINE: case SKINCOLOR_PERIWINKLE: case SKINCOLOR_BLUE: case SKINCOLOR_BLUEBERRY: case SKINCOLOR_NOVA: cstart = "\x84"; // V_BLUEMAP break; - case SKINCOLOR_ULTRAVIOLET: + case SKINCOLOR_THISTLE: case SKINCOLOR_PURPLE: - case SKINCOLOR_FUCHSIA: + case SKINCOLOR_PASTEL: cstart = "\x81"; // V_PURPLEMAP break; - case SKINCOLOR_PASTEL: + case SKINCOLOR_MAGENTA: + case SKINCOLOR_FUCHSIA: case SKINCOLOR_MOONSLAM: + cstart = "\x8c"; // V_MAGENTAMAP + break; case SKINCOLOR_DUSK: case SKINCOLOR_TOXIC: case SKINCOLOR_MAUVE: @@ -1581,7 +1581,7 @@ static void HU_drawMiniChat(void) else { if (cv_chatbacktint.value) // on request of wolfy - V_DrawFillConsoleMap(x + dx + 2, y+dy, charwidth, charheight, 239|V_SNAPTOBOTTOM|V_SNAPTOLEFT); + V_DrawFillConsoleMap(x + dx + 2, y+dy, charwidth, charheight, 159|V_SNAPTOBOTTOM|V_SNAPTOLEFT); V_DrawChatCharacter(x + dx + 2, y+dy, msg[j++] |V_SNAPTOBOTTOM|V_SNAPTOLEFT|transflag, !cv_allcaps.value, colormap); } @@ -1645,7 +1645,7 @@ static void HU_drawChatLog(INT32 offset) chat_topy = y + chat_scroll*charheight; chat_bottomy = chat_topy + boxh*charheight; - V_DrawFillConsoleMap(chatx, chat_topy, boxw, boxh*charheight +2, 239|V_SNAPTOBOTTOM|V_SNAPTOLEFT); // log box + V_DrawFillConsoleMap(chatx, chat_topy, boxw, boxh*charheight +2, 159|V_SNAPTOBOTTOM|V_SNAPTOLEFT); // log box for (i=0; i 0) || (pexiting > 0) || (secondist/distvar < 3)) - && (pos != 9)) // Force SPB + if ((indirectitemcooldown > 0) || (pexiting > 0) || (secondist/DISTVAR < 3)) newodds = 0; else - newodds *= min((secondist/distvar)-4, 3); // POWERITEMODDS(newodds); + newodds *= min((secondist/DISTVAR)-4, 3); // POWERITEMODDS(newodds); break; case KITEM_SHRINK: if ((indirectitemcooldown > 0) || (pingame-1 <= pexiting) || COOLDOWNONSTART) @@ -894,7 +908,7 @@ static INT32 K_KartGetItemOdds(UINT8 pos, SINT8 item, fixed_t mashed, boolean sp POWERITEMODDS(newodds); break; case KITEM_THUNDERSHIELD: - if (thunderisout) + if (thunderisout || spbplace != -1) newodds = 0; else POWERITEMODDS(newodds); @@ -913,16 +927,17 @@ static INT32 K_KartGetItemOdds(UINT8 pos, SINT8 item, fixed_t mashed, boolean sp //{ SRB2kart Roulette Code - Distance Based, no waypoints -static INT32 K_FindUseodds(player_t *player, fixed_t mashed, INT32 pingame, INT32 bestbumper, boolean spbrush, boolean dontforcespb) +static INT32 K_FindUseodds(player_t *player, fixed_t mashed, INT32 pdis, INT32 bestbumper, boolean spbrush) { - const INT32 distvar = (64*14); INT32 i; - INT32 pdis = 0, useodds = 0; + INT32 n = 0; + INT32 useodds = 0; UINT8 disttable[14]; + UINT8 totallen = 0; UINT8 distlen = 0; - boolean oddsvalid[10]; + boolean oddsvalid[8]; - for (i = 0; i < 10; i++) + for (i = 0; i < 8; i++) { INT32 j; boolean available = false; @@ -945,27 +960,19 @@ static INT32 K_FindUseodds(player_t *player, fixed_t mashed, INT32 pingame, INT3 oddsvalid[i] = available; } - for (i = 0; i < MAXPLAYERS; i++) - { - if (playeringame[i] && !players[i].spectator && players[i].mo - && players[i].kartstuff[k_position] < player->kartstuff[k_position]) - pdis += P_AproxDistance(P_AproxDistance(players[i].mo->x - player->mo->x, - players[i].mo->y - player->mo->y), - players[i].mo->z - player->mo->z) / mapobjectscale - * (pingame - players[i].kartstuff[k_position]) - / max(1, ((pingame - 1) * (pingame + 1) / 3)); - } - #define SETUPDISTTABLE(odds, num) \ - for (i = num; i; --i) disttable[distlen++] = odds + if (oddsvalid[odds]) \ + for (i = num; i; --i) \ + disttable[distlen++] = odds; \ + totallen += num; if (G_BattleGametype()) // Battle Mode { - if (oddsvalid[0]) SETUPDISTTABLE(0,1); - if (oddsvalid[1]) SETUPDISTTABLE(1,1); - if (oddsvalid[2]) SETUPDISTTABLE(2,1); - if (oddsvalid[3]) SETUPDISTTABLE(3,1); - if (oddsvalid[4]) SETUPDISTTABLE(4,1); + SETUPDISTTABLE(0,1); + SETUPDISTTABLE(1,1); + SETUPDISTTABLE(2,1); + SETUPDISTTABLE(3,1); + SETUPDISTTABLE(4,1); if (player->kartstuff[k_roulettetype] == 1 && oddsvalid[5]) // 5 is the extreme odds of player-controlled "Karma" items useodds = 5; @@ -978,43 +985,30 @@ static INT32 K_FindUseodds(player_t *player, fixed_t mashed, INT32 pingame, INT3 wantedpos = 4; if (wantedpos < 0) // Don't go below somehow wantedpos = 0; - useodds = disttable[(wantedpos * distlen) / 5]; + n = (wantedpos * distlen) / totallen; + useodds = disttable[n]; } } else { - if (oddsvalid[1]) SETUPDISTTABLE(1,1); - if (oddsvalid[2]) SETUPDISTTABLE(2,1); - if (oddsvalid[3]) SETUPDISTTABLE(3,1); - if (oddsvalid[4]) SETUPDISTTABLE(4,2); - if (oddsvalid[5]) SETUPDISTTABLE(5,2); - if (oddsvalid[6]) SETUPDISTTABLE(6,3); - if (oddsvalid[7]) SETUPDISTTABLE(7,3); - if (oddsvalid[8]) SETUPDISTTABLE(8,1); + SETUPDISTTABLE(0,1); + SETUPDISTTABLE(1,1); + SETUPDISTTABLE(2,1); + SETUPDISTTABLE(3,2); + SETUPDISTTABLE(4,2); + SETUPDISTTABLE(5,3); + SETUPDISTTABLE(6,3); + SETUPDISTTABLE(7,1); - if (franticitems) // Frantic items make the distances between everyone artifically higher, for crazier items - pdis = (15 * pdis) / 14; - - if (spbrush) // SPB Rush Mode: It's 2nd place's job to catch-up items and make 1st place's job hell - pdis = (3 * pdis) / 2; - - pdis = ((28 + (8-pingame)) * pdis) / 28; - - if (pingame == 1 && oddsvalid[0]) // Record Attack, or just alone - useodds = 0; - else if (pdis <= 0) // (64*14) * 0 = 0 + if (pdis <= 0) // (64*14) * 0 = 0 useodds = disttable[0]; - else if (player->kartstuff[k_position] == 2 && pdis > (distvar*6) - && spbplace == -1 && !indirectitemcooldown && !dontforcespb - && oddsvalid[9]) // Force SPB in 2nd - useodds = 9; - else if (pdis > distvar * ((12 * distlen) / 14)) // (64*14) * 12 = 10752 + else if (pdis > DISTVAR * ((12 * distlen) / 14)) // (64*14) * 12 = 10752 useodds = disttable[distlen-1]; else { for (i = 1; i < 13; i++) { - if (pdis <= distvar * ((i * distlen) / 14)) + if (pdis <= DISTVAR * ((i * distlen) / 14)) { useodds = disttable[((i * distlen) / 14)]; break; @@ -1025,8 +1019,6 @@ static INT32 K_FindUseodds(player_t *player, fixed_t mashed, INT32 pingame, INT3 #undef SETUPDISTTABLE - //CONS_Printf("Got useodds %d. (position: %d, distance: %d)\n", useodds, player->kartstuff[k_position], pdis); - return useodds; } @@ -1035,6 +1027,7 @@ static void K_KartItemRoulette(player_t *player, ticcmd_t *cmd) INT32 i; UINT8 pingame = 0; UINT8 roulettestop; + INT32 pdis = 0; INT32 useodds = 0; INT32 spawnchance[NUMKARTRESULTS]; INT32 totalspawnchance = 0; @@ -1078,7 +1071,8 @@ static void K_KartItemRoulette(player_t *player, ticcmd_t *cmd) // If the roulette finishes or the player presses BT_ATTACK, stop the roulette and calculate the item. // I'm returning via the exact opposite, however, to forgo having another bracket embed. Same result either way, I think. // Finally, if you get past this check, now you can actually start calculating what item you get. - if ((cmd->buttons & BT_ATTACK) && !(player->kartstuff[k_eggmanheld] || player->kartstuff[k_itemheld]) && player->kartstuff[k_itemroulette] >= roulettestop && !modeattacking) + if ((cmd->buttons & BT_ATTACK) && (player->kartstuff[k_itemroulette] >= roulettestop) + && !(player->kartstuff[k_eggmanheld] || player->kartstuff[k_itemheld] || player->kartstuff[k_userings])) { // Mashing reduces your chances for the good items mashed = FixedDiv((player->kartstuff[k_itemroulette])*FRACUNIT, ((TICRATE*3)+roulettestop)*FRACUNIT) - FRACUNIT; @@ -1089,11 +1083,35 @@ static void K_KartItemRoulette(player_t *player, ticcmd_t *cmd) if (cmd->buttons & BT_ATTACK) player->pflags |= PF_ATTACKDOWN; - if (player->kartstuff[k_roulettetype] == 2) // Fake items + for (i = 0; i < MAXPLAYERS; i++) + { + if (playeringame[i] && !players[i].spectator && players[i].mo + && players[i].kartstuff[k_position] < player->kartstuff[k_position]) + pdis += P_AproxDistance(P_AproxDistance(players[i].mo->x - player->mo->x, + players[i].mo->y - player->mo->y), + players[i].mo->z - player->mo->z) / mapobjectscale + * (pingame - players[i].kartstuff[k_position]) + / max(1, ((pingame - 1) * (pingame + 1) / 3)); + } + + if (franticitems) // Frantic items make the distances between everyone artifically higher, for crazier items + pdis = (15 * pdis) / 14; + + if (spbplace != -1 && player->kartstuff[k_position] == spbplace+1) // SPB Rush Mode: It's 2nd place's job to catch-up items and make 1st place's job hell + { + pdis = (3 * pdis) / 2; + spbrush = true; + } + + pdis = ((28 + (8-pingame)) * pdis) / 28; // scale with player count + + // SPECIAL CASE No. 1: + // Fake Eggman items + if (player->kartstuff[k_roulettetype] == 2) { player->kartstuff[k_eggmanexplode] = 4*TICRATE; - //player->kartstuff[k_itemblink] = TICRATE; - //player->kartstuff[k_itemblinkmode] = 1; + //player->karthud[khud_itemblink] = TICRATE; + //player->karthud[khud_itemblinkmode] = 1; player->kartstuff[k_itemroulette] = 0; player->kartstuff[k_roulettetype] = 0; if (P_IsDisplayPlayer(player)) @@ -1101,12 +1119,14 @@ static void K_KartItemRoulette(player_t *player, ticcmd_t *cmd) return; } + // SPECIAL CASE No. 2: + // Give a debug item instead if specified if (cv_kartdebugitem.value != 0 && !modeattacking) { K_KartGetItemResult(player, cv_kartdebugitem.value); player->kartstuff[k_itemamount] = cv_kartdebugamount.value; - player->kartstuff[k_itemblink] = TICRATE; - player->kartstuff[k_itemblinkmode] = 2; + player->karthud[khud_itemblink] = TICRATE; + player->karthud[khud_itemblinkmode] = 2; player->kartstuff[k_itemroulette] = 0; player->kartstuff[k_roulettetype] = 0; if (P_IsDisplayPlayer(player)) @@ -1114,15 +1134,98 @@ static void K_KartItemRoulette(player_t *player, ticcmd_t *cmd) return; } - if (G_RaceGametype()) - spbrush = (spbplace != -1 && player->kartstuff[k_position] == spbplace+1); + // SPECIAL CASE No. 3: + // Record Attack / alone mashing behavior + if (modeattacking || pingame == 1) + { + if (G_RaceGametype()) + { + if (mashed && (modeattacking || cv_superring.value)) // ANY mashed value? You get rings. + { + K_KartGetItemResult(player, KITEM_SUPERRING); + player->karthud[khud_itemblinkmode] = 1; + if (P_IsDisplayPlayer(player)) + S_StartSound(NULL, sfx_itrolm); + } + else + { + if (modeattacking || cv_sneaker.value) // Waited patiently? You get a sneaker! + K_KartGetItemResult(player, KITEM_SNEAKER); + else // Default to sad if nothing's enabled... + K_KartGetItemResult(player, KITEM_SAD); + player->karthud[khud_itemblinkmode] = 0; + if (P_IsDisplayPlayer(player)) + S_StartSound(NULL, sfx_itrolf); + } + } + else if (G_BattleGametype()) + { + if (mashed && (modeattacking || cv_banana.value)) // ANY mashed value? You get a banana. + { + K_KartGetItemResult(player, KITEM_BANANA); + player->karthud[khud_itemblinkmode] = 1; + if (P_IsDisplayPlayer(player)) + S_StartSound(NULL, sfx_itrolm); + } + else + { + if (modeattacking || cv_orbinaut.value) // Waited patiently? You get an orbinaut! + K_KartGetItemResult(player, KITEM_ORBINAUT); + else // Default to sad if nothing's enabled... + K_KartGetItemResult(player, KITEM_SAD); + player->karthud[khud_itemblinkmode] = 0; + if (P_IsDisplayPlayer(player)) + S_StartSound(NULL, sfx_itrolf); + } + } + player->karthud[khud_itemblink] = TICRATE; + player->kartstuff[k_itemroulette] = 0; + player->kartstuff[k_roulettetype] = 0; + return; + } + + // SPECIAL CASE No. 4: + // Being in ring debt occasionally forces Super Ring on you if you mashed + if (mashed && player->kartstuff[k_rings] < 0 && cv_superring.value) + { + INT32 debtamount = min(20, abs(player->kartstuff[k_rings])); + if (P_RandomChance((debtamount*FRACUNIT)/20)) + { + K_KartGetItemResult(player, KITEM_SUPERRING); + player->karthud[khud_itemblink] = TICRATE; + player->karthud[khud_itemblinkmode] = 1; + player->kartstuff[k_itemroulette] = 0; + player->kartstuff[k_roulettetype] = 0; + if (P_IsDisplayPlayer(player)) + S_StartSound(NULL, (mashed ? sfx_itrolm : sfx_itrolf)); + return; + } + } + + // SPECIAL CASE No. 5: + // Force SPB onto 2nd if they get too far behind + if (player->kartstuff[k_position] == 2 && pdis > (DISTVAR*6) + && spbplace == -1 && !indirectitemcooldown && !dontforcespb + && cv_selfpropelledbomb.value) + { + K_KartGetItemResult(player, KITEM_SPB); + player->karthud[khud_itemblink] = TICRATE; + player->karthud[khud_itemblinkmode] = (mashed ? 1 : 0); + player->kartstuff[k_itemroulette] = 0; + player->kartstuff[k_roulettetype] = 0; + if (P_IsDisplayPlayer(player)) + S_StartSound(NULL, (mashed ? sfx_itrolm : sfx_itrolf)); + return; + } + + // NOW that we're done with all of those specialized cases, we can move onto the REAL item roulette tables. // Initializes existing spawnchance values for (i = 0; i < NUMKARTRESULTS; i++) spawnchance[i] = 0; // Split into another function for a debug function below - useodds = K_FindUseodds(player, mashed, pingame, bestbumper, spbrush, dontforcespb); + useodds = K_FindUseodds(player, mashed, pdis, bestbumper, spbrush); for (i = 1; i < NUMKARTRESULTS; i++) spawnchance[i] = (totalspawnchance += K_KartGetItemOdds(useodds, i, mashed, spbrush)); @@ -1144,8 +1247,8 @@ static void K_KartItemRoulette(player_t *player, ticcmd_t *cmd) if (P_IsDisplayPlayer(player)) S_StartSound(NULL, ((player->kartstuff[k_roulettetype] == 1) ? sfx_itrolk : (mashed ? sfx_itrolm : sfx_itrolf))); - player->kartstuff[k_itemblink] = TICRATE; - player->kartstuff[k_itemblinkmode] = ((player->kartstuff[k_roulettetype] == 1) ? 2 : (mashed ? 1 : 0)); + player->karthud[khud_itemblink] = TICRATE; + player->karthud[khud_itemblinkmode] = ((player->kartstuff[k_roulettetype] == 1) ? 2 : (mashed ? 1 : 0)); player->kartstuff[k_itemroulette] = 0; // Since we're done, clear the roulette number player->kartstuff[k_roulettetype] = 0; // This too @@ -1203,6 +1306,34 @@ static fixed_t K_GetMobjWeight(mobj_t *mobj, mobj_t *against) return weight; } +// This kind of wipeout happens with no rings -- doesn't remove a bumper, has no invulnerability, and is much shorter. +static void K_DebtStingPlayer(player_t *player, INT32 length) +{ + if (player->health <= 0) + return; + + if (player->powers[pw_flashing] > 0 || player->kartstuff[k_squishedtimer] > 0 || player->kartstuff[k_spinouttimer] > 0 + || player->kartstuff[k_invincibilitytimer] > 0 || player->kartstuff[k_growshrinktimer] > 0 || player->kartstuff[k_hyudorotimer] > 0 + || (G_BattleGametype() && ((player->kartstuff[k_bumper] <= 0 && player->kartstuff[k_comebacktimer]) || player->kartstuff[k_comebackmode] == 1))) + return; + + player->kartstuff[k_ringboost] = 0; + player->kartstuff[k_driftboost] = 0; + player->kartstuff[k_drift] = 0; + player->kartstuff[k_driftcharge] = 0; + player->kartstuff[k_pogospring] = 0; + + player->kartstuff[k_spinouttype] = 2; + player->kartstuff[k_spinouttimer] = length; + player->kartstuff[k_wipeoutslow] = min(length-1, wipeoutslowtime+1); + + if (player->mo->state != &states[S_KART_SPIN]) + P_SetPlayerMobjState(player->mo, S_KART_SPIN); + + K_DropHnextList(player); + return; +} + void K_KartBouncing(mobj_t *mobj1, mobj_t *mobj2, boolean bounce, boolean solid) { mobj_t *fx; @@ -1352,10 +1483,22 @@ void K_KartBouncing(mobj_t *mobj1, mobj_t *mobj2, boolean bounce, boolean solid) mobj1->player->rmomx = mobj1->momx - mobj1->player->cmomx; mobj1->player->rmomy = mobj1->momy - mobj1->player->cmomy; mobj1->player->kartstuff[k_justbumped] = bumptime; + if (mobj1->player->kartstuff[k_spinouttimer]) { mobj1->player->kartstuff[k_wipeoutslow] = wipeoutslowtime+1; mobj1->player->kartstuff[k_spinouttimer] = max(wipeoutslowtime+1, mobj1->player->kartstuff[k_spinouttimer]); + //mobj1->player->kartstuff[k_spinouttype] = 1; // Enforce type + } + else if (mobj2->player) // Player VS player bumping only + { + if (mobj1->player->kartstuff[k_rings] <= 0) + { + K_DebtStingPlayer(mobj1->player, TICRATE + (4 * (mobj2->player->kartweight - mobj1->player->kartweight))); + K_KartPainEnergyFling(mobj1->player); + P_PlayRinglossSound(mobj1); + } + P_PlayerRingBurst(mobj1->player, 1); } } @@ -1364,10 +1507,22 @@ void K_KartBouncing(mobj_t *mobj1, mobj_t *mobj2, boolean bounce, boolean solid) mobj2->player->rmomx = mobj2->momx - mobj2->player->cmomx; mobj2->player->rmomy = mobj2->momy - mobj2->player->cmomy; mobj2->player->kartstuff[k_justbumped] = bumptime; + if (mobj2->player->kartstuff[k_spinouttimer]) { mobj2->player->kartstuff[k_wipeoutslow] = wipeoutslowtime+1; mobj2->player->kartstuff[k_spinouttimer] = max(wipeoutslowtime+1, mobj2->player->kartstuff[k_spinouttimer]); + //mobj2->player->kartstuff[k_spinouttype] = 1; // Enforce type + } + else if (mobj1->player) // Player VS player bumping only + { + if (mobj2->player->kartstuff[k_rings] <= 0) + { + K_DebtStingPlayer(mobj2->player, TICRATE + (4 * (mobj1->player->kartweight - mobj2->player->kartweight))); + K_KartPainEnergyFling(mobj2->player); + P_PlayRinglossSound(mobj2); + } + P_PlayerRingBurst(mobj2->player, 1); } } } @@ -1415,15 +1570,11 @@ static void K_UpdateOffroad(player_t *player) if (offroadstrength) { if (K_CheckOffroadCollide(player->mo, player->mo->subsector->sector) && player->kartstuff[k_offroad] == 0) - player->kartstuff[k_offroad] = (TICRATE/2); + player->kartstuff[k_offroad] = TICRATE; if (player->kartstuff[k_offroad] > 0) { - offroad = (offroadstrength << FRACBITS) / (TICRATE/2); - - //if (player->kartstuff[k_growshrinktimer] > 1) // grow slows down half as fast - // offroad /= 2; - + offroad = (offroadstrength << FRACBITS) / TICRATE; player->kartstuff[k_offroad] += offroad; } @@ -1434,6 +1585,255 @@ static void K_UpdateOffroad(player_t *player) player->kartstuff[k_offroad] = 0; } +static void K_DrawDraftCombiring(player_t *player, player_t *victim, fixed_t curdist, fixed_t maxdist, boolean transparent) +{ +#define CHAOTIXBANDLEN 15 +#define CHAOTIXBANDCOLORS 9 + static const UINT8 colors[CHAOTIXBANDCOLORS] = { + SKINCOLOR_SAPPHIRE, + SKINCOLOR_PLATINUM, + SKINCOLOR_TEA, + SKINCOLOR_GARDEN, + SKINCOLOR_BANANA, + SKINCOLOR_GOLD, + SKINCOLOR_ORANGE, + SKINCOLOR_SCARLET, + SKINCOLOR_TAFFY + }; + fixed_t minimumdist = FixedMul(RING_DIST>>1, player->mo->scale); + UINT8 c = FixedMul(CHAOTIXBANDCOLORS<> FRACBITS; + UINT8 n = CHAOTIXBANDLEN; + UINT8 offset = ((leveltime / 3) % 3); + fixed_t stepx, stepy, stepz; + fixed_t curx, cury, curz; + + stepx = (victim->mo->x - player->mo->x) / CHAOTIXBANDLEN; + stepy = (victim->mo->y - player->mo->y) / CHAOTIXBANDLEN; + stepz = ((victim->mo->z + (victim->mo->height / 2)) - (player->mo->z + (player->mo->height / 2))) / CHAOTIXBANDLEN; + + curx = player->mo->x + stepx; + cury = player->mo->y + stepy; + curz = player->mo->z + stepz; + + while (n) + { + if (offset == 0) + { + mobj_t *band = P_SpawnMobj(curx + (P_RandomRange(-12,12)*mapobjectscale), + cury + (P_RandomRange(-12,12)*mapobjectscale), + curz + (P_RandomRange(24,48)*mapobjectscale), + MT_SIGNSPARKLE); + P_SetMobjState(band, S_SIGNSPARK1 + (abs(leveltime+offset) % 11)); + P_SetScale(band, (band->destscale = (3*player->mo->scale)/2)); + band->color = colors[c]; + band->colorized = true; + band->fuse = 2; + if (transparent) + band->flags2 |= MF2_SHADOW; + if (!P_IsDisplayPlayer(player) && !P_IsDisplayPlayer(victim)) + band->flags2 |= MF2_DONTDRAW; + } + + curx += stepx; + cury += stepy; + curz += stepz; + + offset = abs(offset-1) % 3; + n--; + } +#undef CHAOTIXBANDLEN +} + +/** \brief Updates the player's drafting values once per frame + + \param player player object passed from K_KartPlayerThink + + \return void +*/ +static void K_UpdateDraft(player_t *player) +{ + fixed_t topspd = K_GetKartSpeed(player, false); + fixed_t draftdistance; + UINT8 leniency; + UINT8 i; + + // Distance you have to be to draft. If you're still accelerating, then this distance is lessened. + // This distance biases toward low weight! (min weight gets 4096 units, max weight gets 3072 units) + // This distance is also scaled based on game speed. + draftdistance = (3072 + (128 * (9 - player->kartweight))) * player->mo->scale; + if (player->speed < topspd) + draftdistance = FixedMul(draftdistance, FixedDiv(player->speed, topspd)); + draftdistance = FixedMul(draftdistance, K_GetKartGameSpeedScalar(gamespeed)); + + // On the contrary, the leniency period biases toward high weight. + // (See also: the leniency variable in K_SpawnDraftDust) + leniency = (3*TICRATE)/4 + ((player->kartweight-1) * (TICRATE/4)); + + // Not enough speed to draft. + if (player->speed >= 20*player->mo->scale) + { +//#define EASYDRAFTTEST + // Let's hunt for players to draft off of! + for (i = 0; i < MAXPLAYERS; i++) + { + fixed_t dist, olddraft; +#ifndef EASYDRAFTTEST + angle_t yourangle, theirangle, diff; +#endif + + if (!playeringame[i] || players[i].spectator || !players[i].mo) + continue; + +#ifndef EASYDRAFTTEST + // Don't draft on yourself :V + if (&players[i] == player) + continue; +#endif + + // Not enough speed to draft off of. + if (players[i].speed < 20*players[i].mo->scale) + continue; + +#ifndef EASYDRAFTTEST + yourangle = R_PointToAngle2(0, 0, player->mo->momx, player->mo->momy); + theirangle = R_PointToAngle2(0, 0, players[i].mo->momx, players[i].mo->momy); + + diff = R_PointToAngle2(player->mo->x, player->mo->y, players[i].mo->x, players[i].mo->y) - yourangle; + if (diff > ANGLE_180) + diff = InvAngle(diff); + + // Not in front of this player. + if (diff > ANG10) + continue; + + diff = yourangle - theirangle; + if (diff > ANGLE_180) + diff = InvAngle(diff); + + // Not moving in the same direction. + if (diff > ANGLE_90) + continue; +#endif + + dist = P_AproxDistance(P_AproxDistance(players[i].mo->x - player->mo->x, players[i].mo->y - player->mo->y), players[i].mo->z - player->mo->z); + +#ifndef EASYDRAFTTEST + // TOO close to draft. + if (dist < FixedMul(RING_DIST>>1, player->mo->scale)) + continue; + + // Not close enough to draft. + if (dist > draftdistance) + continue; +#endif + + olddraft = player->kartstuff[k_draftpower]; + + player->kartstuff[k_draftleeway] = leniency; + player->kartstuff[k_lastdraft] = i; + + // Draft power is used later in K_GetKartBoostPower, ranging from 0 for normal speed and FRACUNIT for max draft speed. + // How much this increments every tic biases toward acceleration! (min speed gets 1.5% per tic, max speed gets 0.5% per tic) + if (player->kartstuff[k_draftpower] < FRACUNIT) + player->kartstuff[k_draftpower] += (FRACUNIT/200) + ((9 - player->kartspeed) * ((3*FRACUNIT)/1600)); + + if (player->kartstuff[k_draftpower] > FRACUNIT) + player->kartstuff[k_draftpower] = FRACUNIT; + + // Play draft finish noise + if (olddraft < FRACUNIT && player->kartstuff[k_draftpower] >= FRACUNIT) + S_StartSound(player->mo, sfx_cdfm62); + + // Spawn in the visual! + K_DrawDraftCombiring(player, &players[i], dist, draftdistance, false); + + return; // Finished doing our draft. + } + } + + // No one to draft off of? Then you can knock that off. + if (player->kartstuff[k_draftleeway]) // Prevent small disruptions from stopping your draft. + { + player->kartstuff[k_draftleeway]--; + if (player->kartstuff[k_lastdraft] >= 0 + && player->kartstuff[k_lastdraft] < MAXPLAYERS + && playeringame[player->kartstuff[k_lastdraft]] + && !players[player->kartstuff[k_lastdraft]].spectator + && players[player->kartstuff[k_lastdraft]].mo) + { + player_t *victim = &players[player->kartstuff[k_lastdraft]]; + fixed_t dist = P_AproxDistance(P_AproxDistance(victim->mo->x - player->mo->x, victim->mo->y - player->mo->y), victim->mo->z - player->mo->z); + K_DrawDraftCombiring(player, victim, dist, draftdistance, true); + } + } + else // Remove draft speed boost. + { + player->kartstuff[k_draftpower] = 0; + player->kartstuff[k_lastdraft] = -1; + } +} + +void K_KartPainEnergyFling(player_t *player) +{ + static const UINT8 numfling = 5; + INT32 i; + mobj_t *mo; + angle_t fa; + fixed_t ns; + fixed_t z; + + // Better safe than sorry. + if (!player) + return; + + // P_PlayerRingBurst: "There's no ring spilling in kart, so I'm hijacking this for the same thing as TD" + // :oh: + + for (i = 0; i < numfling; i++) + { + INT32 objType = mobjinfo[MT_FLINGENERGY].reactiontime; + fixed_t momxy, momz; // base horizonal/vertical thrusts + + z = player->mo->z; + if (player->mo->eflags & MFE_VERTICALFLIP) + z += player->mo->height - mobjinfo[objType].height; + + mo = P_SpawnMobj(player->mo->x, player->mo->y, z, objType); + + mo->fuse = 8*TICRATE; + P_SetTarget(&mo->target, player->mo); + + mo->destscale = player->mo->scale; + P_SetScale(mo, player->mo->scale); + + // Angle offset by player angle, then slightly offset by amount of fling + fa = ((i*FINEANGLES/16) + (player->mo->angle>>ANGLETOFINESHIFT) - ((numfling-1)*FINEANGLES/32)) & FINEMASK; + + if (i > 15) + { + momxy = 3*FRACUNIT; + momz = 4*FRACUNIT; + } + else + { + momxy = 28*FRACUNIT; + momz = 3*FRACUNIT; + } + + ns = FixedMul(momxy, mo->scale); + mo->momx = FixedMul(FINECOSINE(fa),ns); + + ns = momz; + P_SetObjectMomZ(mo, ns, false); + + if (i & 1) + P_SetObjectMomZ(mo, ns, true); + + if (player->mo->eflags & MFE_VERTICALFLIP) + mo->momz *= -1; + } +} + // Adds gravity flipping to an object relative to its master and shifts the z coordinate accordingly. void K_FlipFromObject(mobj_t *mo, mobj_t *master) { @@ -1612,6 +2012,8 @@ void K_RespawnChecker(player_t *player) player->mo->colorized = false; player->kartstuff[k_dropdash] = 0; player->kartstuff[k_respawn] = 0; + //P_PlayRinglossSound(player->mo); + P_PlayerRingBurst(player, 3); } } } @@ -1674,8 +2076,8 @@ static void K_TauntVoiceTimers(player_t *player) if (!player) return; - player->kartstuff[k_tauntvoices] = 6*TICRATE; - player->kartstuff[k_voices] = 4*TICRATE; + player->karthud[khud_tauntvoices] = 6*TICRATE; + player->karthud[khud_voices] = 4*TICRATE; } static void K_RegularVoiceTimers(player_t *player) @@ -1683,16 +2085,16 @@ static void K_RegularVoiceTimers(player_t *player) if (!player) return; - player->kartstuff[k_voices] = 4*TICRATE; + player->karthud[khud_voices] = 4*TICRATE; - if (player->kartstuff[k_tauntvoices] < 4*TICRATE) - player->kartstuff[k_tauntvoices] = 4*TICRATE; + if (player->karthud[khud_tauntvoices] < 4*TICRATE) + player->karthud[khud_tauntvoices] = 4*TICRATE; } void K_PlayAttackTaunt(mobj_t *source) { sfxenum_t pick = P_RandomKey(2); // Gotta roll the RNG every time this is called for sync reasons - boolean tasteful = (!source->player || !source->player->kartstuff[k_tauntvoices]); + boolean tasteful = (!source->player || !source->player->karthud[khud_tauntvoices]); if (cv_kartvoices.value && (tasteful || cv_kartvoices.value == 2)) S_StartSound(source, sfx_kattk1+pick); @@ -1706,7 +2108,7 @@ void K_PlayAttackTaunt(mobj_t *source) void K_PlayBoostTaunt(mobj_t *source) { sfxenum_t pick = P_RandomKey(2); // Gotta roll the RNG every time this is called for sync reasons - boolean tasteful = (!source->player || !source->player->kartstuff[k_tauntvoices]); + boolean tasteful = (!source->player || !source->player->karthud[khud_tauntvoices]); if (cv_kartvoices.value && (tasteful || cv_kartvoices.value == 2)) S_StartSound(source, sfx_kbost1+pick); @@ -1719,7 +2121,7 @@ void K_PlayBoostTaunt(mobj_t *source) void K_PlayOvertakeSound(mobj_t *source) { - boolean tasteful = (!source->player || !source->player->kartstuff[k_voices]); + boolean tasteful = (!source->player || !source->player->karthud[khud_voices]); if (!G_RaceGametype()) // Only in race return; @@ -1737,6 +2139,16 @@ void K_PlayOvertakeSound(mobj_t *source) K_RegularVoiceTimers(source->player); } +void K_PlayPainSound(mobj_t *source) +{ + sfxenum_t pick = P_RandomKey(2); // Gotta roll the RNG every time this is called for sync reasons + + if (cv_kartvoices.value) + S_StartSound(source, sfx_khurt1 + pick); + + K_RegularVoiceTimers(source->player); +} + void K_PlayHitEmSound(mobj_t *source) { if (cv_kartvoices.value) @@ -1778,6 +2190,7 @@ static void K_GetKartBoostPower(player_t *player) { fixed_t boostpower = FRACUNIT; fixed_t speedboost = 0, accelboost = 0; + UINT8 numboosts = 0; if (player->kartstuff[k_spinouttimer] && player->kartstuff[k_wipeoutslow] == 1) // Slow down after you've been bumped { @@ -1786,108 +2199,81 @@ static void K_GetKartBoostPower(player_t *player) } // Offroad is separate, it's difficult to factor it in with a variable value anyway. - if (!(player->kartstuff[k_invincibilitytimer] || player->kartstuff[k_hyudorotimer] || player->kartstuff[k_sneakertimer]) + if (!(player->kartstuff[k_invincibilitytimer] || player->kartstuff[k_hyudorotimer] || EITHERSNEAKER(player)) && player->kartstuff[k_offroad] >= 0) - boostpower = FixedDiv(boostpower, player->kartstuff[k_offroad] + FRACUNIT); + boostpower = FixedDiv(boostpower, FixedMul(player->kartstuff[k_offroad], K_GetKartGameSpeedScalar(gamespeed)) + FRACUNIT); if (player->kartstuff[k_bananadrag] > TICRATE) boostpower = (4*boostpower)/5; - // Banana drag/offroad dust - if (boostpower < FRACUNIT - && player->mo && P_IsObjectOnGround(player->mo) - && player->speed > 0 - && !player->spectator) - { - K_SpawnWipeoutTrail(player->mo, true); - if (leveltime % 6 == 0) - S_StartSound(player->mo, sfx_cdfm70); - } +#define ADDBOOST(s,a) { \ + numboosts++; \ + speedboost += (s) / numboosts; \ + accelboost += (a) / numboosts; \ +} + + if (player->kartstuff[k_levelbooster]) // Level boosters + ADDBOOST(FRACUNIT/2, 8*FRACUNIT); // + 50% top speed, + 800% acceleration if (player->kartstuff[k_sneakertimer]) // Sneaker - { - switch (gamespeed) - { - case 0: - speedboost = max(speedboost, 53740+768); - break; - case 2: - speedboost = max(speedboost, 17294+768); - break; - default: - speedboost = max(speedboost, 32768); - break; - } - accelboost = max(accelboost, 8*FRACUNIT); // + 800% - } + ADDBOOST(FRACUNIT/2, 8*FRACUNIT); // + 50% top speed, + 800% acceleration if (player->kartstuff[k_invincibilitytimer]) // Invincibility - { - speedboost = max(speedboost, 3*FRACUNIT/8); // + 37.5% - accelboost = max(accelboost, 3*FRACUNIT); // + 300% - } + ADDBOOST((3*FRACUNIT)/8, 3*FRACUNIT); // + 37.5% top speed, + 300% acceleration + + if (player->kartstuff[k_startboost]) // Startup Boost + ADDBOOST(FRACUNIT/4, 6*FRACUNIT); // + 25% top speed, + 600% acceleration + + if (player->kartstuff[k_driftboost]) // Drift Boost + ADDBOOST(FRACUNIT/4, 4*FRACUNIT); // + 25% top speed, + 400% acceleration + + if (player->kartstuff[k_ringboost]) // Ring Boost + ADDBOOST(FRACUNIT/5, 4*FRACUNIT); // + 20% top speed, + 400% acceleration if (player->kartstuff[k_growshrinktimer] > 0) // Grow { - speedboost = max(speedboost, FRACUNIT/5); // + 20% + // Grow's design is weird with booster stacking. + // We'll see how to replace its design BEFORE v2 gets released. + speedboost += (FRACUNIT/5); // + 20% + //numboosts++; // Don't add any boost afterimages to Grow } - if (player->kartstuff[k_driftboost]) // Drift Boost + if (player->kartstuff[k_draftpower] > 0) // Drafting { - speedboost = max(speedboost, FRACUNIT/4); // + 25% - accelboost = max(accelboost, 4*FRACUNIT); // + 400% + fixed_t draftspeed = ((3*FRACUNIT)/10) + ((player->kartspeed-1) * (FRACUNIT/50)); // min is 30%, max is 46% + speedboost += FixedMul(draftspeed, player->kartstuff[k_draftpower]); // (Drafting suffers no boost stack penalty.) + numboosts++; } - if (player->kartstuff[k_startboost]) // Startup Boost - { - speedboost = max(speedboost, FRACUNIT/4); // + 25% - accelboost = max(accelboost, 6*FRACUNIT); // + 300% - } - - // don't average them anymore, this would make a small boost and a high boost less useful - // just take the highest we want instead - player->kartstuff[k_boostpower] = boostpower; // value smoothing if (speedboost > player->kartstuff[k_speedboost]) player->kartstuff[k_speedboost] = speedboost; else - player->kartstuff[k_speedboost] += (speedboost - player->kartstuff[k_speedboost])/(TICRATE/2); + player->kartstuff[k_speedboost] += (speedboost - player->kartstuff[k_speedboost]) / (TICRATE/2); player->kartstuff[k_accelboost] = accelboost; + player->kartstuff[k_numboosts] = numboosts; } fixed_t K_GetKartSpeed(player_t *player, boolean doboostpower) { + const fixed_t xspd = (3*FRACUNIT)/64; + fixed_t g_cc = K_GetKartGameSpeedScalar(gamespeed) + xspd; fixed_t k_speed = 150; - fixed_t g_cc = FRACUNIT; - fixed_t xspd = 3072; // 4.6875 aka 3/64 UINT8 kartspeed = player->kartspeed; fixed_t finalspeed; - if (doboostpower && !player->kartstuff[k_pogospring] && !P_IsObjectOnGround(player->mo)) - return (75*mapobjectscale); // air speed cap - - switch (gamespeed) - { - case 0: - g_cc = 53248 + xspd; // 50cc = 81.25 + 4.69 = 85.94% - break; - case 2: - g_cc = 77824 + xspd; // 150cc = 118.75 + 4.69 = 123.44% - break; - default: - g_cc = 65536 + xspd; // 100cc = 100.00 + 4.69 = 104.69% - break; - } - if (G_BattleGametype() && player->kartstuff[k_bumper] <= 0) kartspeed = 1; k_speed += kartspeed*3; // 153 - 177 - finalspeed = FixedMul(FixedMul(k_speed<<14, g_cc), player->mo->scale); + finalspeed = FixedMul(k_speed<<14, g_cc); + + if (player->mo && !P_MobjWasRemoved(player->mo)) + finalspeed = FixedMul(finalspeed, player->mo->scale); if (doboostpower) return FixedMul(finalspeed, player->kartstuff[k_boostpower]+player->kartstuff[k_speedboost]); @@ -1959,10 +2345,10 @@ fixed_t K_3dKartMovement(player_t *player, boolean onground, fixed_t forwardmove finalspeed *= forwardmove/25; finalspeed /= 2; - if (forwardmove < 0 && finalspeed > FRACUNIT*2) + if (forwardmove < 0 && finalspeed > mapobjectscale*2) return finalspeed/2; else if (forwardmove < 0) - return -FRACUNIT/2; + return -mapobjectscale/2; if (finalspeed < 0) finalspeed = 0; @@ -2032,7 +2418,6 @@ void K_SpinPlayer(player_t *player, mobj_t *source, INT32 type, mobj_t *inflicto (void)inflictor; // in case some weirdo doesn't want Lua. #endif - if (!trapitem && G_BattleGametype()) { if (K_IsPlayerWanted(player)) @@ -2044,7 +2429,7 @@ void K_SpinPlayer(player_t *player, mobj_t *source, INT32 type, mobj_t *inflicto if (player->health <= 0) return; - if (player->powers[pw_flashing] > 0 || player->kartstuff[k_squishedtimer] > 0 || player->kartstuff[k_spinouttimer] > 0 + if (player->powers[pw_flashing] > 0 || player->kartstuff[k_squishedtimer] > 0 || (player->kartstuff[k_spinouttimer] > 0 && player->kartstuff[k_spinouttype] != 2) || player->kartstuff[k_invincibilitytimer] > 0 || player->kartstuff[k_growshrinktimer] > 0 || player->kartstuff[k_hyudorotimer] > 0 || (G_BattleGametype() && ((player->kartstuff[k_bumper] <= 0 && player->kartstuff[k_comebacktimer]) || player->kartstuff[k_comebackmode] == 1))) { @@ -2063,8 +2448,10 @@ void K_SpinPlayer(player_t *player, mobj_t *source, INT32 type, mobj_t *inflicto if (source && source != player->mo && source->player) K_PlayHitEmSound(source); - //player->kartstuff[k_sneakertimer] = 0; + player->kartstuff[k_sneakertimer] = 0; + //player->kartstuff[k_levelbooster] = 0; player->kartstuff[k_driftboost] = 0; + player->kartstuff[k_ringboost] = 0; player->kartstuff[k_drift] = 0; player->kartstuff[k_driftcharge] = 0; @@ -2114,7 +2501,7 @@ void K_SpinPlayer(player_t *player, mobj_t *source, INT32 type, mobj_t *inflicto player->kartstuff[k_spinouttype] = type; - if (player->kartstuff[k_spinouttype] <= 0) // type 0 is spinout, type 1 is wipeout + if (player->kartstuff[k_spinouttype] <= 0) // type 0 is spinout, type 1 is wipeout, type 2 is no-invuln wipeout { // At spinout, player speed is increased to 1/4 their regular speed, moving them forward if (player->speed < K_GetKartSpeed(player, true)/4) @@ -2125,6 +2512,10 @@ void K_SpinPlayer(player_t *player, mobj_t *source, INT32 type, mobj_t *inflicto player->kartstuff[k_spinouttimer] = (3*TICRATE/2)+2; player->powers[pw_flashing] = K_GetKartFlashing(player); + P_PlayRinglossSound(player->mo); + P_PlayerRingBurst(player, 5); + K_PlayPainSound(player->mo); + if (player->mo->state != &states[S_KART_SPIN]) P_SetPlayerMobjState(player->mo, S_KART_SPIN); @@ -2206,7 +2597,9 @@ void K_SquishPlayer(player_t *player, mobj_t *source, mobj_t *inflictor) #endif player->kartstuff[k_sneakertimer] = 0; + player->kartstuff[k_levelbooster] = 0; player->kartstuff[k_driftboost] = 0; + player->kartstuff[k_ringboost] = 0; player->kartstuff[k_drift] = 0; player->kartstuff[k_driftcharge] = 0; @@ -2269,6 +2662,8 @@ void K_SquishPlayer(player_t *player, mobj_t *source, mobj_t *inflictor) P_SetPlayerMobjState(player->mo, S_KART_SQUISH); P_PlayRinglossSound(player->mo); + P_PlayerRingBurst(player, 5); + K_PlayPainSound(player->mo); player->kartstuff[k_instashield] = 15; if (cv_kartdebughuddrop.value && !modeattacking) @@ -2307,8 +2702,7 @@ void K_ExplodePlayer(player_t *player, mobj_t *source, mobj_t *inflictor) // A b if (player->health <= 0) return; - if (/*player->powers[pw_flashing] > 0 || player->kartstuff[k_squishedtimer] > 0 || player->kartstuff[k_spinouttimer] > 0 // Explosions should combo, because of SPB and Eggman - ||*/player->kartstuff[k_invincibilitytimer] > 0 || player->kartstuff[k_growshrinktimer] > 0 || player->kartstuff[k_hyudorotimer] > 0 + if (player->kartstuff[k_invincibilitytimer] > 0 || player->kartstuff[k_growshrinktimer] > 0 || player->kartstuff[k_hyudorotimer] > 0 // Do not check spinout, because SPB and Eggman should combo || (G_BattleGametype() && ((player->kartstuff[k_bumper] <= 0 && player->kartstuff[k_comebacktimer]) || player->kartstuff[k_comebackmode] == 1))) { if (!force) // ShouldDamage can bypass that, again. @@ -2330,14 +2724,16 @@ void K_ExplodePlayer(player_t *player, mobj_t *source, mobj_t *inflictor) // A b player->mo->momx = player->mo->momy = 0; player->kartstuff[k_sneakertimer] = 0; + player->kartstuff[k_levelbooster] = 0; player->kartstuff[k_driftboost] = 0; + player->kartstuff[k_ringboost] = 0; player->kartstuff[k_drift] = 0; player->kartstuff[k_driftcharge] = 0; player->kartstuff[k_pogospring] = 0; // This is the only part that SHOULDN'T combo :VVVVV - if (G_BattleGametype() && !(player->powers[pw_flashing] > 0 || player->kartstuff[k_squishedtimer] > 0 || player->kartstuff[k_spinouttimer] > 0)) + if (G_BattleGametype() && !(player->powers[pw_flashing] > 0 || player->kartstuff[k_squishedtimer] > 0 || (player->kartstuff[k_spinouttimer] > 0 && player->kartstuff[k_spinouttype] != 2))) { if (source && source->player && player != source->player) { @@ -2394,8 +2790,10 @@ void K_ExplodePlayer(player_t *player, mobj_t *source, mobj_t *inflictor) // A b P_SetPlayerMobjState(player->mo, S_KART_SPIN); P_PlayRinglossSound(player->mo); + P_PlayerRingBurst(player, 5); + K_PlayPainSound(player->mo); - if (P_IsLocalPlayer(player)) + if (P_IsDisplayPlayer(player)) { quake.intensity = 64*FRACUNIT; quake.time = 5; @@ -2428,7 +2826,7 @@ void K_StealBumper(player_t *player, player_t *victim, boolean force) if (player->kartstuff[k_squishedtimer] > 0 || player->kartstuff[k_spinouttimer] > 0) return; - if (victim->powers[pw_flashing] > 0 || victim->kartstuff[k_squishedtimer] > 0 || victim->kartstuff[k_spinouttimer] > 0 + if (victim->powers[pw_flashing] > 0 || victim->kartstuff[k_squishedtimer] > 0 || (victim->kartstuff[k_spinouttimer] > 0 && victim->kartstuff[k_spinouttype] != 2) || victim->kartstuff[k_invincibilitytimer] > 0 || victim->kartstuff[k_growshrinktimer] > 0 || victim->kartstuff[k_hyudorotimer] > 0) { K_DoInstashield(victim); @@ -2566,14 +2964,13 @@ void K_SpawnKartExplosion(fixed_t x, fixed_t y, fixed_t z, fixed_t radius, INT32 // Spawns the purely visual explosion void K_SpawnMineExplosion(mobj_t *source, UINT8 color) { + INT32 i, radius, height; + mobj_t *smoldering = P_SpawnMobj(source->x, source->y, source->z, MT_SMOLDERING); mobj_t *dust; mobj_t *truc; INT32 speed, speed2; - INT32 i, radius, height; - mobj_t *smoldering = P_SpawnMobj(source->x, source->y, source->z, MT_SMOLDERING); K_MatchGenericExtraFlags(smoldering, source); - smoldering->tics = TICRATE*3; radius = source->radius>>FRACBITS; height = source->height>>FRACBITS; @@ -2996,6 +3393,82 @@ void K_SpawnWipeoutTrail(mobj_t *mo, boolean translucent) dust->flags2 |= MF2_SHADOW; } +void K_SpawnDraftDust(mobj_t *mo) +{ + UINT8 i; + + I_Assert(mo != NULL); + I_Assert(!P_MobjWasRemoved(mo)); + + for (i = 0; i < 2; i++) + { + angle_t ang, aoff; + SINT8 sign = 1; + UINT8 foff = 0; + mobj_t *dust; + boolean drifting = false; + + if (mo->player) + { + UINT8 leniency = (3*TICRATE)/4 + ((mo->player->kartweight-1) * (TICRATE/4)); + + ang = mo->player->frameangle; + + if (mo->player->kartstuff[k_drift] != 0) + { + drifting = true; + ang += (mo->player->kartstuff[k_drift] * ((ANGLE_270 + ANGLE_22h) / 5)); // -112.5 doesn't work. I fucking HATE SRB2 angles + if (mo->player->kartstuff[k_drift] < 0) + sign = 1; + else + sign = -1; + } + + foff = 5 - ((mo->player->kartstuff[k_draftleeway] * 5) / leniency); + + // this shouldn't happen + if (foff > 4) + foff = 4; + } + else + ang = mo->angle; + + if (!drifting) + { + if (i & 1) + sign = -1; + else + sign = 1; + } + + aoff = (ang + ANGLE_180) + (ANGLE_45 * sign); + + dust = P_SpawnMobj(mo->x + FixedMul(24*mo->scale, FINECOSINE(aoff>>ANGLETOFINESHIFT)), + mo->y + FixedMul(24*mo->scale, FINESINE(aoff>>ANGLETOFINESHIFT)), + mo->z, MT_DRAFTDUST); + + P_SetMobjState(dust, S_DRAFTDUST1 + foff); + + P_SetTarget(&dust->target, mo); + dust->angle = ang - (ANGLE_90 * sign); // point completely perpendicular from the player + dust->destscale = mo->scale; + P_SetScale(dust, mo->scale); + K_FlipFromObject(dust, mo); + + if (leveltime & 1) + dust->tics++; // "randomize" animation + + dust->momx = (4*mo->momx)/5; + dust->momy = (4*mo->momy)/5; + //dust->momz = (4*mo->momz)/5; + + P_Thrust(dust, dust->angle, 4*mo->scale); + + if (drifting) // only 1 trail while drifting + break; + } +} + // K_DriftDustHandling // Parameters: // spawner: The map object that is spawning the drift dust @@ -3092,29 +3565,10 @@ static mobj_t *K_ThrowKartItem(player_t *player, boolean missile, mobjtype_t map // Figure out projectile speed by game speed if (missile && mapthing != MT_BALLHOG) // Trying to keep compatability... - { - PROJSPEED = mobjinfo[mapthing].speed; - if (gamespeed == 0) - PROJSPEED = FixedMul(PROJSPEED, FRACUNIT-FRACUNIT/4); - else if (gamespeed == 2) - PROJSPEED = FixedMul(PROJSPEED, FRACUNIT+FRACUNIT/4); - PROJSPEED = FixedMul(PROJSPEED, mapobjectscale); - } + PROJSPEED = FixedMul(mobjinfo[mapthing].speed, FRACUNIT + ((gamespeed-1) * (FRACUNIT/4))); else - { - switch (gamespeed) - { - case 0: - PROJSPEED = 68*mapobjectscale; // Avg Speed is 34 - break; - case 2: - PROJSPEED = 96*mapobjectscale; // Avg Speed is 48 - break; - default: - PROJSPEED = 82*mapobjectscale; // Avg Speed is 41 - break; - } - } + PROJSPEED = (82 + ((gamespeed-1) * 14)) * FRACUNIT; // Avg Speed is 41 in Normal + PROJSPEED = FixedMul(PROJSPEED, mapobjectscale); if (altthrow) { @@ -3328,18 +3782,7 @@ void K_PuntMine(mobj_t *thismine, mobj_t *punter) if (!mine || P_MobjWasRemoved(mine)) return; - switch (gamespeed) - { - case 0: - spd = 68*mapobjectscale; // Avg Speed is 34 - break; - case 2: - spd = 96*mapobjectscale; // Avg Speed is 48 - break; - default: - spd = 82*mapobjectscale; // Avg Speed is 41 - break; - } + spd = (82 + ((gamespeed-1) * 14))*mapobjectscale; // Avg Speed is 41 in Normal mine->flags |= MF_NOCLIPTHING; @@ -3430,7 +3873,7 @@ static void K_DoHyudoroSteal(player_t *player) && (players[i].kartstuff[k_itemtype] && players[i].kartstuff[k_itemamount] && !players[i].kartstuff[k_itemheld] - && !players[i].kartstuff[k_itemblink])) + && !players[i].karthud[khud_itemblink])) { playerswappable[numplayers] = i; numplayers++; @@ -3479,37 +3922,24 @@ static void K_DoHyudoroSteal(player_t *player) players[stealplayer].kartstuff[k_itemamount] = 0; players[stealplayer].kartstuff[k_itemheld] = 0; - if (P_IsLocalPlayer(&players[stealplayer]) && !splitscreen) + if (P_IsDisplayPlayer(&players[stealplayer]) && !splitscreen) S_StartSound(NULL, sfx_s3k92); } } void K_DoSneaker(player_t *player, INT32 type) { - fixed_t intendedboost; - - switch (gamespeed) - { - case 0: - intendedboost = 53740+768; - break; - case 2: - intendedboost = 17294+768; - break; - default: - intendedboost = 32768; - break; - } + const fixed_t intendedboost = FRACUNIT/2; if (!player->kartstuff[k_floorboost] || player->kartstuff[k_floorboost] == 3) { S_StartSound(player->mo, sfx_cdfm01); K_SpawnDashDustRelease(player); if (intendedboost > player->kartstuff[k_speedboost]) - player->kartstuff[k_destboostcam] = FixedMul(FRACUNIT, FixedDiv((intendedboost - player->kartstuff[k_speedboost]), intendedboost)); + player->karthud[khud_destboostcam] = FixedMul(FRACUNIT, FixedDiv((intendedboost - player->kartstuff[k_speedboost]), intendedboost)); } - if (!player->kartstuff[k_sneakertimer]) + if (!EITHERSNEAKER(player)) { if (type == 2) { @@ -3539,16 +3969,17 @@ void K_DoSneaker(player_t *player, INT32 type) } } - player->kartstuff[k_sneakertimer] = sneakertime; - - // set angle for spun out players: - player->kartstuff[k_boostangle] = (INT32)player->mo->angle; - if (type != 0) { player->pflags |= PF_ATTACKDOWN; K_PlayBoostTaunt(player->mo); + player->kartstuff[k_sneakertimer] = sneakertime; } + else + player->kartstuff[k_levelbooster] = sneakertime; + + // set angle for spun out players: + player->kartstuff[k_boostangle] = (INT32)player->mo->angle; } static void K_DoShrink(player_t *user) @@ -3578,7 +4009,7 @@ static void K_DoShrink(player_t *user) { // Start shrinking! K_DropItems(&players[i]); - players[i].kartstuff[k_growshrinktimer] = -(20*TICRATE); + players[i].kartstuff[k_growshrinktimer] = -(15*TICRATE); if (players[i].mo && !P_MobjWasRemoved(players[i].mo)) { @@ -3626,10 +4057,10 @@ void K_DoPogoSpring(mobj_t *mo, fixed_t vertispeed, UINT8 sound) thrust = 72<player->kartstuff[k_pogospring] != 2) { - if (mo->player->kartstuff[k_sneakertimer]) - thrust = FixedMul(thrust, 5*FRACUNIT/4); + if (EITHERSNEAKER(mo->player)) + thrust = FixedMul(thrust, (5*FRACUNIT)/4); else if (mo->player->kartstuff[k_invincibilitytimer]) - thrust = FixedMul(thrust, 9*FRACUNIT/8); + thrust = FixedMul(thrust, (9*FRACUNIT)/8); } } else @@ -4313,7 +4744,7 @@ static void K_UpdateEngineSounds(player_t *player, ticcmd_t *cmd) // Silence the engines if (leveltime < 8 || player->spectator || player->exiting) { - player->kartstuff[k_enginesnd] = 0; // Reset sound number + player->karthud[khud_enginesnd] = 0; // Reset sound number return; } @@ -4334,15 +4765,15 @@ static void K_UpdateEngineSounds(player_t *player, ticcmd_t *cmd) if (targetsnd > 12) targetsnd = 12; - if (player->kartstuff[k_enginesnd] < targetsnd) - player->kartstuff[k_enginesnd]++; - if (player->kartstuff[k_enginesnd] > targetsnd) - player->kartstuff[k_enginesnd]--; + if (player->karthud[khud_enginesnd] < targetsnd) + player->karthud[khud_enginesnd]++; + if (player->karthud[khud_enginesnd] > targetsnd) + player->karthud[khud_enginesnd]--; - if (player->kartstuff[k_enginesnd] < 0) - player->kartstuff[k_enginesnd] = 0; - if (player->kartstuff[k_enginesnd] > 12) - player->kartstuff[k_enginesnd] = 12; + if (player->karthud[khud_enginesnd] < 0) + player->karthud[khud_enginesnd] = 0; + if (player->karthud[khud_enginesnd] > 12) + player->karthud[khud_enginesnd] = 12; for (i = 0; i < MAXPLAYERS; i++) { @@ -4382,14 +4813,14 @@ static void K_UpdateEngineSounds(player_t *player, ticcmd_t *cmd) if (volume <= 0) // Might as well return; - S_StartSoundAtVolume(player->mo, (sfx_krta00 + player->kartstuff[k_enginesnd]) + (class*numsnds), volume); + S_StartSoundAtVolume(player->mo, (sfx_krta00 + player->karthud[khud_enginesnd]) + (class*numsnds), volume); } static void K_UpdateInvincibilitySounds(player_t *player) { INT32 sfxnum = sfx_None; - if (player->mo->health > 0 && !P_IsLocalPlayer(player)) + if (player->mo->health > 0 && !P_IsDisplayPlayer(player)) { if (cv_kartinvinsfx.value) { @@ -4420,47 +4851,111 @@ static void K_UpdateInvincibilitySounds(player_t *player) #undef STOPTHIS } +#define RINGANIM_NUMFRAMES 10 +#define RINGANIM_DELAYMAX 5 + void K_KartPlayerHUDUpdate(player_t *player) { - if (player->kartstuff[k_lapanimation]) - player->kartstuff[k_lapanimation]--; + if (player->karthud[khud_lapanimation]) + player->karthud[khud_lapanimation]--; - if (player->kartstuff[k_yougotem]) - player->kartstuff[k_yougotem]--; + if (player->karthud[khud_yougotem]) + player->karthud[khud_yougotem]--; + + if (player->karthud[khud_voices]) + player->karthud[khud_voices]--; + + if (player->karthud[khud_tauntvoices]) + player->karthud[khud_tauntvoices]--; + + if (G_RaceGametype()) + { + // 0 is the fast spin animation, set at 30 tics of ring boost or higher! + if (player->kartstuff[k_ringboost] >= 30) + player->karthud[khud_ringdelay] = 0; + else + player->karthud[khud_ringdelay] = ((RINGANIM_DELAYMAX+1) * (30 - player->kartstuff[k_ringboost])) / 30; + + if (player->karthud[khud_ringframe] == 0 && player->karthud[khud_ringdelay] > RINGANIM_DELAYMAX) + { + player->karthud[khud_ringframe] = 0; + player->karthud[khud_ringtics] = 0; + } + else if ((player->karthud[khud_ringtics]--) <= 0) + { + if (player->karthud[khud_ringdelay] == 0) // fast spin animation + { + player->karthud[khud_ringframe] = ((player->karthud[khud_ringframe]+2) % RINGANIM_NUMFRAMES); + player->karthud[khud_ringtics] = 0; + } + else + { + player->karthud[khud_ringframe] = ((player->karthud[khud_ringframe]+1) % RINGANIM_NUMFRAMES); + player->karthud[khud_ringtics] = min(RINGANIM_DELAYMAX, player->karthud[khud_ringdelay])-1; + } + } + + if (player->kartstuff[k_ringlock]) + { + UINT8 normalanim = (leveltime % 14); + UINT8 debtanim = 14 + (leveltime % 2); + + if (player->karthud[khud_ringspblock] >= 14) // debt animation + { + if ((player->kartstuff[k_rings] > 0) // Get out of 0 ring animation + && (normalanim == 3 || normalanim == 10)) // on these transition frames. + player->karthud[khud_ringspblock] = normalanim; + else + player->karthud[khud_ringspblock] = debtanim; + } + else // normal animation + { + if ((player->kartstuff[k_rings] <= 0) // Go into 0 ring animation + && (player->karthud[khud_ringspblock] == 1 || player->karthud[khud_ringspblock] == 8)) // on these transition frames. + player->karthud[khud_ringspblock] = debtanim; + else + player->karthud[khud_ringspblock] = normalanim; + } + } + else + player->karthud[khud_ringspblock] = (leveltime % 14); // reset to normal anim next time + } if (G_BattleGametype() && (player->exiting || player->kartstuff[k_comebacktimer])) { if (player->exiting) { if (player->exiting < 6*TICRATE) - player->kartstuff[k_cardanimation] += ((164-player->kartstuff[k_cardanimation])/8)+1; + player->karthud[khud_cardanimation] += ((164-player->karthud[khud_cardanimation])/8)+1; else if (player->exiting == 6*TICRATE) - player->kartstuff[k_cardanimation] = 0; - else if (player->kartstuff[k_cardanimation] < 2*TICRATE) - player->kartstuff[k_cardanimation]++; + player->karthud[khud_cardanimation] = 0; + else if (player->karthud[khud_cardanimation] < 2*TICRATE) + player->karthud[khud_cardanimation]++; } else { if (player->kartstuff[k_comebacktimer] < 6*TICRATE) - player->kartstuff[k_cardanimation] -= ((164-player->kartstuff[k_cardanimation])/8)+1; + player->karthud[khud_cardanimation] -= ((164-player->karthud[khud_cardanimation])/8)+1; else if (player->kartstuff[k_comebacktimer] < 9*TICRATE) - player->kartstuff[k_cardanimation] += ((164-player->kartstuff[k_cardanimation])/8)+1; + player->karthud[khud_cardanimation] += ((164-player->karthud[khud_cardanimation])/8)+1; } - if (player->kartstuff[k_cardanimation] > 164) - player->kartstuff[k_cardanimation] = 164; - if (player->kartstuff[k_cardanimation] < 0) - player->kartstuff[k_cardanimation] = 0; + if (player->karthud[khud_cardanimation] > 164) + player->karthud[khud_cardanimation] = 164; + if (player->karthud[khud_cardanimation] < 0) + player->karthud[khud_cardanimation] = 0; } else if (G_RaceGametype() && player->exiting) { - if (player->kartstuff[k_cardanimation] < 2*TICRATE) - player->kartstuff[k_cardanimation]++; + if (player->karthud[khud_cardanimation] < 2*TICRATE) + player->karthud[khud_cardanimation]++; } else - player->kartstuff[k_cardanimation] = 0; + player->karthud[khud_cardanimation] = 0; } +#undef RINGANIM_DELAYMAX + /** \brief Decreases various kart timers and powers per frame. Called in P_PlayerThink in p_user.c \param player player object passed from P_PlayerThink @@ -4471,6 +4966,7 @@ void K_KartPlayerHUDUpdate(player_t *player) void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) { K_UpdateOffroad(player); + K_UpdateDraft(player); K_UpdateEngineSounds(player, cmd); // Thanks, VAda! // update boost angle if not spun out @@ -4479,18 +4975,89 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) K_GetKartBoostPower(player); - // Speed lines - if ((player->kartstuff[k_sneakertimer] || player->kartstuff[k_driftboost] || player->kartstuff[k_startboost]) && player->speed > 0) + // Special effect objects! + if (player->mo && !player->spectator) { - mobj_t *fast = P_SpawnMobj(player->mo->x + (P_RandomRange(-36,36) * player->mo->scale), - player->mo->y + (P_RandomRange(-36,36) * player->mo->scale), - player->mo->z + (player->mo->height/2) + (P_RandomRange(-20,20) * player->mo->scale), - MT_FASTLINE); - fast->angle = R_PointToAngle2(0, 0, player->mo->momx, player->mo->momy); - fast->momx = 3*player->mo->momx/4; - fast->momy = 3*player->mo->momy/4; - fast->momz = 3*player->mo->momz/4; - K_MatchGenericExtraFlags(fast, player->mo); + if (player->kartstuff[k_dashpadcooldown]) // Twinkle Circuit afterimages + { + mobj_t *ghost; + ghost = P_SpawnGhostMobj(player->mo); + ghost->fuse = player->kartstuff[k_dashpadcooldown]+1; + ghost->momx = player->mo->momx / (player->kartstuff[k_dashpadcooldown]+1); + ghost->momy = player->mo->momy / (player->kartstuff[k_dashpadcooldown]+1); + ghost->momz = player->mo->momz / (player->kartstuff[k_dashpadcooldown]+1); + player->kartstuff[k_dashpadcooldown]--; + } + + if (player->speed > 0) + { + // Speed lines + if (EITHERSNEAKER(player) || player->kartstuff[k_ringboost] + || player->kartstuff[k_driftboost] || player->kartstuff[k_startboost]) + { + mobj_t *fast = P_SpawnMobj(player->mo->x + (P_RandomRange(-36,36) * player->mo->scale), + player->mo->y + (P_RandomRange(-36,36) * player->mo->scale), + player->mo->z + (player->mo->height/2) + (P_RandomRange(-20,20) * player->mo->scale), + MT_FASTLINE); + fast->angle = R_PointToAngle2(0, 0, player->mo->momx, player->mo->momy); + fast->momx = 3*player->mo->momx/4; + fast->momy = 3*player->mo->momy/4; + fast->momz = 3*player->mo->momz/4; + K_MatchGenericExtraFlags(fast, player->mo); + } + + if (player->kartstuff[k_numboosts] > 0) // Boosting after images + { + mobj_t *ghost; + ghost = P_SpawnGhostMobj(player->mo); + ghost->extravalue1 = player->kartstuff[k_numboosts]+1; + ghost->extravalue2 = (leveltime % ghost->extravalue1); + ghost->fuse = ghost->extravalue1; + ghost->frame |= FF_FULLBRIGHT; + ghost->colorized = true; + //ghost->color = player->skincolor; + //ghost->momx = (3*player->mo->momx)/4; + //ghost->momy = (3*player->mo->momy)/4; + //ghost->momz = (3*player->mo->momz)/4; + if (leveltime & 1) + ghost->flags2 |= MF2_DONTDRAW; + } + + if (P_IsObjectOnGround(player->mo)) + { + // Offroad dust + if (player->kartstuff[k_boostpower] < FRACUNIT) + { + K_SpawnWipeoutTrail(player->mo, true); + if (leveltime % 6 == 0) + S_StartSound(player->mo, sfx_cdfm70); + } + + // Draft dust + if (player->kartstuff[k_draftpower] >= FRACUNIT) + { + K_SpawnDraftDust(player->mo); + /*if (leveltime % 23 == 0 || !S_SoundPlaying(player->mo, sfx_s265)) + S_StartSound(player->mo, sfx_s265);*/ + } + } + } + + if (G_RaceGametype() && player->kartstuff[k_rings] <= 0) // spawn ring debt indicator + { + mobj_t *debtflag = P_SpawnMobj(player->mo->x + player->mo->momx, player->mo->y + player->mo->momy, + player->mo->z + player->mo->momz + player->mo->height + (24*player->mo->scale), MT_THOK); + P_SetMobjState(debtflag, S_RINGDEBT); + P_SetScale(debtflag, (debtflag->destscale = player->mo->scale)); + K_MatchGenericExtraFlags(debtflag, player->mo); + debtflag->frame += (leveltime % 4); + if ((leveltime/12) & 1) + debtflag->frame += 4; + debtflag->color = player->skincolor; + debtflag->fuse = 2; + if (P_IsDisplayPlayer(player)) + debtflag->flags2 |= MF2_DONTDRAW; + } } if (player->playerstate == PST_DEAD || player->kartstuff[k_respawn] > 1) // Ensure these are set correctly here @@ -4519,11 +5086,7 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) } else if (player->kartstuff[k_invincibilitytimer]) // setting players to use the star colormap and spawning afterimages { - mobj_t *ghost; player->mo->colorized = true; - ghost = P_SpawnGhostMobj(player->mo); - ghost->fuse = 4; - ghost->frame |= FF_FULLBRIGHT; } else if (player->kartstuff[k_growshrinktimer]) // Ditto, for grow/shrink { @@ -4538,45 +5101,43 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) player->mo->color = player->skincolor; } } + else if (player->kartstuff[k_ringboost] && (leveltime & 1)) // ring boosting + { + player->mo->colorized = true; + } else { player->mo->colorized = false; } - if (player->kartstuff[k_dashpadcooldown]) // Twinkle Circuit inspired afterimages - { - mobj_t *ghost; - ghost = P_SpawnGhostMobj(player->mo); - ghost->fuse = player->kartstuff[k_dashpadcooldown]+1; - ghost->momx = player->mo->momx / (player->kartstuff[k_dashpadcooldown]+1); - ghost->momy = player->mo->momy / (player->kartstuff[k_dashpadcooldown]+1); - ghost->momz = player->mo->momz / (player->kartstuff[k_dashpadcooldown]+1); - player->kartstuff[k_dashpadcooldown]--; - } - // DKR style camera for boosting - if (player->kartstuff[k_boostcam] != 0 || player->kartstuff[k_destboostcam] != 0) + if (player->karthud[khud_boostcam] != 0 || player->karthud[khud_destboostcam] != 0) { - if (player->kartstuff[k_boostcam] < player->kartstuff[k_destboostcam] - && player->kartstuff[k_destboostcam] != 0) + if (player->karthud[khud_boostcam] < player->karthud[khud_destboostcam] + && player->karthud[khud_destboostcam] != 0) { - player->kartstuff[k_boostcam] += FRACUNIT/(TICRATE/4); - if (player->kartstuff[k_boostcam] >= player->kartstuff[k_destboostcam]) - player->kartstuff[k_destboostcam] = 0; + player->karthud[khud_boostcam] += FRACUNIT/(TICRATE/4); + if (player->karthud[khud_boostcam] >= player->karthud[khud_destboostcam]) + player->karthud[khud_destboostcam] = 0; } else { - player->kartstuff[k_boostcam] -= FRACUNIT/TICRATE; - if (player->kartstuff[k_boostcam] < player->kartstuff[k_destboostcam]) - player->kartstuff[k_boostcam] = player->kartstuff[k_destboostcam] = 0; + player->karthud[khud_boostcam] -= FRACUNIT/TICRATE; + if (player->karthud[khud_boostcam] < player->karthud[khud_destboostcam]) + player->karthud[khud_boostcam] = player->karthud[khud_destboostcam] = 0; } - //CONS_Printf("cam: %d, dest: %d\n", player->kartstuff[k_boostcam], player->kartstuff[k_destboostcam]); + //CONS_Printf("cam: %d, dest: %d\n", player->karthud[khud_boostcam], player->karthud[khud_destboostcam]); } - player->kartstuff[k_timeovercam] = 0; + player->karthud[khud_timeovercam] = 0; + // Specific hack because it insists on setting flashing tics during this anyway... + if (player->kartstuff[k_spinouttype] == 2) + { + player->powers[pw_flashing] = 0; + } // Make ABSOLUTELY SURE that your flashing tics don't get set WHILE you're still in hit animations. - if (player->kartstuff[k_spinouttimer] != 0 + else if (player->kartstuff[k_spinouttimer] != 0 || player->kartstuff[k_wipeoutslow] != 0 || player->kartstuff[k_squishedtimer] != 0) { @@ -4589,19 +5150,21 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) if (player->kartstuff[k_spinouttimer]) { - if ((P_IsObjectOnGround(player->mo) || player->kartstuff[k_spinouttype] == 1) - && (player->kartstuff[k_sneakertimer] == 0)) + if ((P_IsObjectOnGround(player->mo) + || (player->kartstuff[k_spinouttype] != 0)) + && (!EITHERSNEAKER(player))) { player->kartstuff[k_spinouttimer]--; if (player->kartstuff[k_wipeoutslow] > 1) player->kartstuff[k_wipeoutslow]--; - if (player->kartstuff[k_spinouttimer] == 0) - player->kartstuff[k_spinouttype] = 0; // Reset type + // Actually, this caused more problems than it solved. Just make sure you set type before you spinout. Which K_SpinPlayer always does. + /*if (player->kartstuff[k_spinouttimer] == 0) + player->kartstuff[k_spinouttype] = 0;*/ // Reset type } } else { - if (player->kartstuff[k_wipeoutslow] == 1) + if (player->kartstuff[k_wipeoutslow] >= 1) player->mo->friction = ORIG_FRICTION; player->kartstuff[k_wipeoutslow] = 0; if (!comeback) @@ -4609,20 +5172,32 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) else if (player->kartstuff[k_comebacktimer]) { player->kartstuff[k_comebacktimer]--; - if (P_IsLocalPlayer(player) && player->kartstuff[k_bumper] <= 0 && player->kartstuff[k_comebacktimer] <= 0) + if (P_IsDisplayPlayer(player) && player->kartstuff[k_bumper] <= 0 && player->kartstuff[k_comebacktimer] <= 0) comebackshowninfo = true; // client has already seen the message } } - /*if (player->kartstuff[k_thunderanim]) - player->kartstuff[k_thunderanim]--;*/ + if (player->kartstuff[k_rings] > 20) + player->kartstuff[k_rings] = 20; + else if (player->kartstuff[k_rings] < -20) + player->kartstuff[k_rings] = -20; + + if (player->kartstuff[k_ringdelay]) + player->kartstuff[k_ringdelay]--; + + if (player->kartstuff[k_spinouttimer] || player->kartstuff[k_squishedtimer]) + player->kartstuff[k_ringboost] = 0; + else if (player->kartstuff[k_ringboost]) + player->kartstuff[k_ringboost]--; if (player->kartstuff[k_sneakertimer]) - { player->kartstuff[k_sneakertimer]--; - if (player->kartstuff[k_wipeoutslow] > 0 && player->kartstuff[k_wipeoutslow] < wipeoutslowtime+1) - player->kartstuff[k_wipeoutslow] = wipeoutslowtime+1; - } + + if (player->kartstuff[k_levelbooster]) + player->kartstuff[k_levelbooster]--; + + if (EITHERSNEAKER(player) && player->kartstuff[k_wipeoutslow] > 0 && player->kartstuff[k_wipeoutslow] < wipeoutslowtime+1) + player->kartstuff[k_wipeoutslow] = wipeoutslowtime+1; if (player->kartstuff[k_floorboost]) player->kartstuff[k_floorboost]--; @@ -4648,6 +5223,21 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) K_RemoveGrowShrink(player); } + if (player->kartstuff[k_superring]) + { + if (player->kartstuff[k_superring] % 3 == 0) + { + mobj_t *ring = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_RING); + ring->extravalue1 = 1; // Ring collect animation timer + ring->angle = player->mo->angle; // animation angle + P_SetTarget(&ring->target, player->mo); // toucher for thinker + player->kartstuff[k_pickuprings]++; + if (player->kartstuff[k_superring] <= 3) + ring->cvmem = 1; // play caching when collected + } + player->kartstuff[k_superring]--; + } + if (player->kartstuff[k_stealingtimer] == 0 && player->kartstuff[k_stolentimer] == 0 && player->kartstuff[k_rocketsneakertimer]) player->kartstuff[k_rocketsneakertimer]--; @@ -4671,20 +5261,14 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) player->kartstuff[k_justbumped]--; // This doesn't go in HUD update because it has potential gameplay ramifications - if (player->kartstuff[k_itemblink] && player->kartstuff[k_itemblink]-- <= 0) + if (player->karthud[khud_itemblink] && player->karthud[khud_itemblink]-- <= 0) { - player->kartstuff[k_itemblinkmode] = 0; - player->kartstuff[k_itemblink] = 0; + player->karthud[khud_itemblinkmode] = 0; + player->karthud[khud_itemblink] = 0; } K_KartPlayerHUDUpdate(player); - if (player->kartstuff[k_voices]) - player->kartstuff[k_voices]--; - - if (player->kartstuff[k_tauntvoices]) - player->kartstuff[k_tauntvoices]--; - if (G_BattleGametype() && player->kartstuff[k_bumper] > 0) player->kartstuff[k_wanted]++; @@ -4806,7 +5390,7 @@ void K_KartPlayerAfterThink(player_t *player) if (targ-players != lasttarg) { - if (P_IsLocalPlayer(player) || P_IsLocalPlayer(targ)) + if (P_IsDisplayPlayer(player) || P_IsDisplayPlayer(targ)) S_StartSound(NULL, sfx_s3k89); else S_StartSound(targ->mo, sfx_s3k89); @@ -4893,7 +5477,7 @@ INT16 K_GetKartTurnValue(player_t *player, INT16 turnvalue) turnvalue = FixedMul(turnvalue, adjustangle); // Weight has a small effect on turning - if (player->kartstuff[k_invincibilitytimer] || player->kartstuff[k_sneakertimer] || player->kartstuff[k_growshrinktimer] > 0) + if (EITHERSNEAKER(player) || player->kartstuff[k_invincibilitytimer] || player->kartstuff[k_growshrinktimer] > 0) turnvalue = FixedMul(turnvalue, FixedDiv(5*FRACUNIT, 4*FRACUNIT)); return turnvalue; @@ -5021,7 +5605,11 @@ static void K_KartDrift(player_t *player, boolean onground) } // Disable drift-sparks until you're going fast enough - if (player->kartstuff[k_getsparks] == 0 || (player->kartstuff[k_offroad] && !player->kartstuff[k_invincibilitytimer] && !player->kartstuff[k_hyudorotimer] && !player->kartstuff[k_sneakertimer])) + if (player->kartstuff[k_getsparks] == 0 + || (player->kartstuff[k_offroad] + && !player->kartstuff[k_invincibilitytimer] + && !player->kartstuff[k_hyudorotimer] + && !EITHERSNEAKER(player))) driftadditive = 0; if (player->speed > minspeed*2) player->kartstuff[k_getsparks] = 1; @@ -5031,7 +5619,7 @@ static void K_KartDrift(player_t *player, boolean onground) K_SpawnDriftSparks(player); // Sound whenever you get a different tier of sparks - if (P_IsLocalPlayer(player) // UGHGHGH... + if (P_IsDisplayPlayer(player) // UGHGHGH... && ((player->kartstuff[k_driftcharge] < dsone && player->kartstuff[k_driftcharge]+driftadditive >= dsone) || (player->kartstuff[k_driftcharge] < dstwo && player->kartstuff[k_driftcharge]+driftadditive >= dstwo) || (player->kartstuff[k_driftcharge] < dsthree && player->kartstuff[k_driftcharge]+driftadditive >= dsthree))) @@ -5052,7 +5640,7 @@ static void K_KartDrift(player_t *player, boolean onground) player->kartstuff[k_getsparks] = 0; } - if ((!player->kartstuff[k_sneakertimer]) + if ((!EITHERSNEAKER(player)) || (!player->cmd.driftturn) || (!player->kartstuff[k_aizdriftstrat]) || (player->cmd.driftturn > 0) != (player->kartstuff[k_aizdriftstrat] > 0)) @@ -5236,6 +5824,68 @@ void K_StripOther(player_t *player) } } +// SRB2Kart: blockmap iterate for attraction shield users +static mobj_t *attractmo; +static fixed_t attractdist; +static inline boolean PIT_AttractingRings(mobj_t *thing) +{ + if (!attractmo || P_MobjWasRemoved(attractmo)) + return false; + + if (!attractmo->player) + return false; // not a player + + if (thing->health <= 0 || !thing) + return true; // dead + + if (thing->type != MT_RING && thing->type != MT_FLINGRING) + return true; // not a ring + + if (thing->extravalue1) + return true; // in special ring animation + + if (thing->cusval) + return true; // already attracted + + // see if it went over / under + if (attractmo->z - (attractdist>>2) > thing->z + thing->height) + return true; // overhead + if (attractmo->z + attractmo->height + (attractdist>>2) < thing->z) + return true; // underneath + + if (P_AproxDistance(attractmo->x - thing->x, attractmo->y - thing->y) < attractdist) + return true; // Too far away + + // set target + P_SetTarget(&thing->tracer, attractmo); + // flag to show it's been attracted once before + thing->cusval = 1; + return true; // find other rings +} + +/** Looks for rings near a player in the blockmap. + * + * \param pmo Player object looking for rings to attract + * \sa A_AttractChase + */ +static void K_LookForRings(mobj_t *pmo) +{ + INT32 bx, by, xl, xh, yl, yh; + attractdist = FixedMul(RING_DIST, pmo->scale)>>2; + + // Use blockmap to check for nearby rings + yh = (unsigned)(pmo->y + attractdist - bmaporgy)>>MAPBLOCKSHIFT; + yl = (unsigned)(pmo->y - attractdist - bmaporgy)>>MAPBLOCKSHIFT; + xh = (unsigned)(pmo->x + attractdist - bmaporgx)>>MAPBLOCKSHIFT; + xl = (unsigned)(pmo->x - attractdist - bmaporgx)>>MAPBLOCKSHIFT; + + attractmo = pmo; + + for (by = yl; by <= yh; by++) + for (bx = xl; bx <= xh; bx++) + P_BlockThingsIterator(bx, by, PIT_AttractingRings); +} + // // K_MoveKartPlayer // @@ -5265,439 +5915,490 @@ void K_MoveKartPlayer(player_t *player, boolean onground) if (player->kartstuff[k_positiondelay]) player->kartstuff[k_positiondelay]--; + // Prevent ring misfire + if (!(cmd->buttons & BT_ATTACK)) + { + if (player->kartstuff[k_itemtype] == KITEM_NONE + && NO_HYUDORO && !(HOLDING_ITEM + || player->kartstuff[k_itemamount] + || player->kartstuff[k_itemroulette] + || player->kartstuff[k_growshrinktimer] // Being disabled during Shrink was unintended but people seemed to be okay with it sooo... + || player->kartstuff[k_rocketsneakertimer] + || player->kartstuff[k_eggmanexplode])) + player->kartstuff[k_userings] = 1; + else + player->kartstuff[k_userings] = 0; + } + if ((player->pflags & PF_ATTACKDOWN) && !(cmd->buttons & BT_ATTACK)) player->pflags &= ~PF_ATTACKDOWN; else if (cmd->buttons & BT_ATTACK) player->pflags |= PF_ATTACKDOWN; - if (player && player->mo && player->mo->health > 0 && !player->spectator && !(player->exiting || mapreset) + if (player && player->mo && player->mo->health > 0 && !player->spectator && !(player->exiting || mapreset) && leveltime > starttime && player->kartstuff[k_spinouttimer] == 0 && player->kartstuff[k_squishedtimer] == 0 && player->kartstuff[k_respawn] == 0) { // First, the really specific, finicky items that function without the item being directly in your item slot. // Karma item dropping - if (ATTACK_IS_DOWN && player->kartstuff[k_comebackmode] && !player->kartstuff[k_comebacktimer]) + if (player->kartstuff[k_comebackmode] && !player->kartstuff[k_comebacktimer]) { - mobj_t *newitem; - - if (player->kartstuff[k_comebackmode] == 1) + if (ATTACK_IS_DOWN) { - newitem = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_RANDOMITEM); - newitem->threshold = 69; // selected "randomly". - } - else - { - newitem = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_EGGMANITEM); - if (player->kartstuff[k_eggmanblame] >= 0 - && player->kartstuff[k_eggmanblame] < MAXPLAYERS - && playeringame[player->kartstuff[k_eggmanblame]] - && !players[player->kartstuff[k_eggmanblame]].spectator - && players[player->kartstuff[k_eggmanblame]].mo) - P_SetTarget(&newitem->target, players[player->kartstuff[k_eggmanblame]].mo); - player->kartstuff[k_eggmanblame] = -1; - } + mobj_t *newitem; - newitem->flags2 = (player->mo->flags2 & MF2_OBJECTFLIP); - newitem->fuse = 15*TICRATE; // selected randomly. - - player->kartstuff[k_comebackmode] = 0; - player->kartstuff[k_comebacktimer] = comebacktime; - S_StartSound(player->mo, sfx_s254); - } - // Eggman Monitor exploding - else if (player->kartstuff[k_eggmanexplode]) - { - if (ATTACK_IS_DOWN && player->kartstuff[k_eggmanexplode] <= 3*TICRATE && player->kartstuff[k_eggmanexplode] > 1) - player->kartstuff[k_eggmanexplode] = 1; - } - // Eggman Monitor throwing - else if (ATTACK_IS_DOWN && player->kartstuff[k_eggmanheld]) - { - K_ThrowKartItem(player, false, MT_EGGMANITEM, -1, 0); - K_PlayAttackTaunt(player->mo); - player->kartstuff[k_eggmanheld] = 0; - K_UpdateHnextList(player, true); - } - // Rocket Sneaker - else if (ATTACK_IS_DOWN && !HOLDING_ITEM && onground && NO_HYUDORO - && player->kartstuff[k_rocketsneakertimer] > 1) - { - K_DoSneaker(player, 2); - K_PlayBoostTaunt(player->mo); - player->kartstuff[k_rocketsneakertimer] -= 2*TICRATE; - if (player->kartstuff[k_rocketsneakertimer] < 1) - player->kartstuff[k_rocketsneakertimer] = 1; - } - // Grow Canceling - else if (player->kartstuff[k_growshrinktimer] > 0) - { - if (player->kartstuff[k_growcancel] >= 0) - { - if (cmd->buttons & BT_ATTACK) + if (player->kartstuff[k_comebackmode] == 1) { - player->kartstuff[k_growcancel]++; - if (player->kartstuff[k_growcancel] > 26) - K_RemoveGrowShrink(player); + newitem = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_RANDOMITEM); + newitem->threshold = 69; // selected "randomly". } else - player->kartstuff[k_growcancel] = 0; + { + newitem = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_EGGMANITEM); + if (player->kartstuff[k_eggmanblame] >= 0 + && player->kartstuff[k_eggmanblame] < MAXPLAYERS + && playeringame[player->kartstuff[k_eggmanblame]] + && !players[player->kartstuff[k_eggmanblame]].spectator + && players[player->kartstuff[k_eggmanblame]].mo) + P_SetTarget(&newitem->target, players[player->kartstuff[k_eggmanblame]].mo); + player->kartstuff[k_eggmanblame] = -1; + } + + newitem->flags2 = (player->mo->flags2 & MF2_OBJECTFLIP); + newitem->fuse = 15*TICRATE; // selected randomly. + + player->kartstuff[k_comebackmode] = 0; + player->kartstuff[k_comebacktimer] = comebacktime; + S_StartSound(player->mo, sfx_s254); } - else - { - if ((cmd->buttons & BT_ATTACK) || (player->pflags & PF_ATTACKDOWN)) - player->kartstuff[k_growcancel] = -1; - else - player->kartstuff[k_growcancel] = 0; - } - } - else if (player->kartstuff[k_itemamount] <= 0) - { - player->kartstuff[k_itemamount] = player->kartstuff[k_itemheld] = 0; } else { - switch (player->kartstuff[k_itemtype]) + // Ring boosting + if (player->kartstuff[k_userings]) { - case KITEM_SNEAKER: + if ((player->pflags & PF_ATTACKDOWN) && !player->kartstuff[k_ringdelay] && player->kartstuff[k_rings] > 0) + { + mobj_t *ring = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_RING); + P_SetMobjState(ring, S_FASTRING1); + ring->extravalue1 = 1; // Ring use animation timer + ring->extravalue2 = 1; // Ring use animation flag + P_SetTarget(&ring->target, player->mo); // user + player->kartstuff[k_rings]--; + player->kartstuff[k_ringdelay] = 3; + } + } + // Other items + else + { + // Eggman Monitor exploding + if (player->kartstuff[k_eggmanexplode]) + { + if (ATTACK_IS_DOWN && player->kartstuff[k_eggmanexplode] <= 3*TICRATE && player->kartstuff[k_eggmanexplode] > 1) + player->kartstuff[k_eggmanexplode] = 1; + } + // Eggman Monitor throwing + else if (player->kartstuff[k_eggmanheld]) + { + if (ATTACK_IS_DOWN) + { + K_ThrowKartItem(player, false, MT_EGGMANITEM, -1, 0); + K_PlayAttackTaunt(player->mo); + player->kartstuff[k_eggmanheld] = 0; + K_UpdateHnextList(player, true); + } + } + // Rocket Sneaker usage + else if (player->kartstuff[k_rocketsneakertimer] > 1) + { if (ATTACK_IS_DOWN && !HOLDING_ITEM && onground && NO_HYUDORO) { - K_DoSneaker(player, 1); + K_DoSneaker(player, 2); K_PlayBoostTaunt(player->mo); - player->kartstuff[k_itemamount]--; + player->kartstuff[k_rocketsneakertimer] -= 2*TICRATE; + if (player->kartstuff[k_rocketsneakertimer] < 1) + player->kartstuff[k_rocketsneakertimer] = 1; } - break; - case KITEM_ROCKETSNEAKER: - if (ATTACK_IS_DOWN && !HOLDING_ITEM && onground && NO_HYUDORO - && player->kartstuff[k_rocketsneakertimer] == 0) + } + // Grow Canceling + else if (player->kartstuff[k_growshrinktimer] > 0) + { + if (player->kartstuff[k_growcancel] >= 0) { - INT32 moloop; - mobj_t *mo = NULL; - mobj_t *prev = player->mo; - - K_PlayBoostTaunt(player->mo); - //player->kartstuff[k_itemheld] = 1; - S_StartSound(player->mo, sfx_s3k3a); - - //K_DoSneaker(player, 2); - - player->kartstuff[k_rocketsneakertimer] = (itemtime*3); - player->kartstuff[k_itemamount]--; - K_UpdateHnextList(player, true); - - for (moloop = 0; moloop < 2; moloop++) + if (cmd->buttons & BT_ATTACK) { - mo = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_ROCKETSNEAKER); - K_MatchGenericExtraFlags(mo, player->mo); - mo->flags |= MF_NOCLIPTHING; - mo->angle = player->mo->angle; - mo->threshold = 10; - mo->movecount = moloop%2; - mo->movedir = mo->lastlook = moloop+1; - P_SetTarget(&mo->target, player->mo); - P_SetTarget(&mo->hprev, prev); - P_SetTarget(&prev->hnext, mo); - prev = mo; + player->kartstuff[k_growcancel]++; + if (player->kartstuff[k_growcancel] > 26) + K_RemoveGrowShrink(player); } - } - break; - case KITEM_INVINCIBILITY: - if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO) // Doesn't hold your item slot hostage normally, so you're free to waste it if you have multiple - { - if (!player->kartstuff[k_invincibilitytimer]) - { - mobj_t *overlay = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_INVULNFLASH); - P_SetTarget(&overlay->target, player->mo); - overlay->destscale = player->mo->scale; - P_SetScale(overlay, player->mo->scale); - } - player->kartstuff[k_invincibilitytimer] = itemtime+(2*TICRATE); // 10 seconds - P_RestoreMusic(player); - if (!P_IsLocalPlayer(player)) - S_StartSound(player->mo, (cv_kartinvinsfx.value ? sfx_alarmi : sfx_kinvnc)); - K_PlayPowerGloatSound(player->mo); - player->kartstuff[k_itemamount]--; - } - break; - case KITEM_BANANA: - if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO) - { - INT32 moloop; - mobj_t *mo; - mobj_t *prev = player->mo; - - //K_PlayAttackTaunt(player->mo); - player->kartstuff[k_itemheld] = 1; - S_StartSound(player->mo, sfx_s254); - - for (moloop = 0; moloop < player->kartstuff[k_itemamount]; moloop++) - { - mo = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_BANANA_SHIELD); - if (!mo) - { - player->kartstuff[k_itemamount] = moloop; - break; - } - mo->flags |= MF_NOCLIPTHING; - mo->threshold = 10; - mo->movecount = player->kartstuff[k_itemamount]; - mo->movedir = moloop+1; - P_SetTarget(&mo->target, player->mo); - P_SetTarget(&mo->hprev, prev); - P_SetTarget(&prev->hnext, mo); - prev = mo; - } - } - else if (ATTACK_IS_DOWN && player->kartstuff[k_itemheld]) // Banana x3 thrown - { - K_ThrowKartItem(player, false, MT_BANANA, -1, 0); - K_PlayAttackTaunt(player->mo); - player->kartstuff[k_itemamount]--; - K_UpdateHnextList(player, false); - } - break; - case KITEM_EGGMAN: - if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO) - { - mobj_t *mo; - player->kartstuff[k_itemamount]--; - player->kartstuff[k_eggmanheld] = 1; - S_StartSound(player->mo, sfx_s254); - mo = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_EGGMANITEM_SHIELD); - if (mo) - { - mo->flags |= MF_NOCLIPTHING; - mo->threshold = 10; - mo->movecount = 1; - mo->movedir = 1; - P_SetTarget(&mo->target, player->mo); - P_SetTarget(&player->mo->hnext, mo); - } - } - break; - case KITEM_ORBINAUT: - if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO) - { - angle_t newangle; - INT32 moloop; - mobj_t *mo = NULL; - mobj_t *prev = player->mo; - - //K_PlayAttackTaunt(player->mo); - player->kartstuff[k_itemheld] = 1; - S_StartSound(player->mo, sfx_s3k3a); - - for (moloop = 0; moloop < player->kartstuff[k_itemamount]; moloop++) - { - newangle = (player->mo->angle + ANGLE_157h) + FixedAngle(((360 / player->kartstuff[k_itemamount]) * moloop) << FRACBITS) + ANGLE_90; - mo = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_ORBINAUT_SHIELD); - if (!mo) - { - player->kartstuff[k_itemamount] = moloop; - break; - } - mo->flags |= MF_NOCLIPTHING; - mo->angle = newangle; - mo->threshold = 10; - mo->movecount = player->kartstuff[k_itemamount]; - mo->movedir = mo->lastlook = moloop+1; - mo->color = player->skincolor; - P_SetTarget(&mo->target, player->mo); - P_SetTarget(&mo->hprev, prev); - P_SetTarget(&prev->hnext, mo); - prev = mo; - } - } - else if (ATTACK_IS_DOWN && player->kartstuff[k_itemheld]) // Orbinaut x3 thrown - { - K_ThrowKartItem(player, true, MT_ORBINAUT, 1, 0); - K_PlayAttackTaunt(player->mo); - player->kartstuff[k_itemamount]--; - K_UpdateHnextList(player, false); - } - break; - case KITEM_JAWZ: - if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO) - { - angle_t newangle; - INT32 moloop; - mobj_t *mo = NULL; - mobj_t *prev = player->mo; - - //K_PlayAttackTaunt(player->mo); - player->kartstuff[k_itemheld] = 1; - S_StartSound(player->mo, sfx_s3k3a); - - for (moloop = 0; moloop < player->kartstuff[k_itemamount]; moloop++) - { - newangle = (player->mo->angle + ANGLE_157h) + FixedAngle(((360 / player->kartstuff[k_itemamount]) * moloop) << FRACBITS) + ANGLE_90; - mo = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_JAWZ_SHIELD); - if (!mo) - { - player->kartstuff[k_itemamount] = moloop; - break; - } - mo->flags |= MF_NOCLIPTHING; - mo->angle = newangle; - mo->threshold = 10; - mo->movecount = player->kartstuff[k_itemamount]; - mo->movedir = mo->lastlook = moloop+1; - P_SetTarget(&mo->target, player->mo); - P_SetTarget(&mo->hprev, prev); - P_SetTarget(&prev->hnext, mo); - prev = mo; - } - } - else if (ATTACK_IS_DOWN && HOLDING_ITEM && player->kartstuff[k_itemheld]) // Jawz thrown - { - if (player->kartstuff[k_throwdir] == 1 || player->kartstuff[k_throwdir] == 0) - K_ThrowKartItem(player, true, MT_JAWZ, 1, 0); - else if (player->kartstuff[k_throwdir] == -1) // Throwing backward gives you a dud that doesn't home in - K_ThrowKartItem(player, true, MT_JAWZ_DUD, -1, 0); - K_PlayAttackTaunt(player->mo); - player->kartstuff[k_itemamount]--; - K_UpdateHnextList(player, false); - } - break; - case KITEM_MINE: - if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO) - { - mobj_t *mo; - player->kartstuff[k_itemheld] = 1; - S_StartSound(player->mo, sfx_s254); - mo = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_SSMINE_SHIELD); - if (mo) - { - mo->flags |= MF_NOCLIPTHING; - mo->threshold = 10; - mo->movecount = 1; - mo->movedir = 1; - P_SetTarget(&mo->target, player->mo); - P_SetTarget(&player->mo->hnext, mo); - } - } - else if (ATTACK_IS_DOWN && player->kartstuff[k_itemheld]) - { - K_ThrowKartItem(player, false, MT_SSMINE, 1, 1); - K_PlayAttackTaunt(player->mo); - player->kartstuff[k_itemamount]--; - player->kartstuff[k_itemheld] = 0; - K_UpdateHnextList(player, true); - } - break; - case KITEM_BALLHOG: - if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO) - { - player->kartstuff[k_itemamount]--; - K_ThrowKartItem(player, true, MT_BALLHOG, 1, 0); - K_PlayAttackTaunt(player->mo); - } - break; - case KITEM_SPB: - if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO) - { - player->kartstuff[k_itemamount]--; - K_ThrowKartItem(player, true, MT_SPB, 1, 0); - K_PlayAttackTaunt(player->mo); - } - break; - case KITEM_GROW: - if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO - && player->kartstuff[k_growshrinktimer] <= 0) // Grow holds the item box hostage - { - if (player->kartstuff[k_growshrinktimer] < 0) // If you're shrunk, then "grow" will just make you normal again. - K_RemoveGrowShrink(player); else - { - K_PlayPowerGloatSound(player->mo); - player->mo->scalespeed = mapobjectscale/TICRATE; - player->mo->destscale = (3*mapobjectscale)/2; - if (cv_kartdebugshrink.value && !modeattacking && !player->bot) - player->mo->destscale = (6*player->mo->destscale)/8; - player->kartstuff[k_growshrinktimer] = itemtime+(4*TICRATE); // 12 seconds - P_RestoreMusic(player); - if (!P_IsLocalPlayer(player)) - S_StartSound(player->mo, (cv_kartinvinsfx.value ? sfx_alarmg : sfx_kgrow)); - S_StartSound(player->mo, sfx_kc5a); - } - player->kartstuff[k_itemamount]--; + player->kartstuff[k_growcancel] = 0; } - break; - case KITEM_SHRINK: - if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO) + else { - K_DoShrink(player); - player->kartstuff[k_itemamount]--; - K_PlayPowerGloatSound(player->mo); + if ((cmd->buttons & BT_ATTACK) || (player->pflags & PF_ATTACKDOWN)) + player->kartstuff[k_growcancel] = -1; + else + player->kartstuff[k_growcancel] = 0; } - break; - case KITEM_THUNDERSHIELD: - if (player->kartstuff[k_curshield] != 1) + } + else if (player->kartstuff[k_itemamount] <= 0) + { + player->kartstuff[k_itemamount] = player->kartstuff[k_itemheld] = 0; + } + else + { + switch (player->kartstuff[k_itemtype]) { - mobj_t *shield = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_THUNDERSHIELD); - P_SetScale(shield, (shield->destscale = (5*shield->destscale)>>2)); - P_SetTarget(&shield->target, player->mo); - S_StartSound(shield, sfx_s3k41); - player->kartstuff[k_curshield] = 1; + case KITEM_SNEAKER: + if (ATTACK_IS_DOWN && !HOLDING_ITEM && onground && NO_HYUDORO) + { + K_DoSneaker(player, 1); + K_PlayBoostTaunt(player->mo); + player->kartstuff[k_itemamount]--; + } + break; + case KITEM_ROCKETSNEAKER: + if (ATTACK_IS_DOWN && !HOLDING_ITEM && onground && NO_HYUDORO + && player->kartstuff[k_rocketsneakertimer] == 0) + { + INT32 moloop; + mobj_t *mo = NULL; + mobj_t *prev = player->mo; + + K_PlayBoostTaunt(player->mo); + //player->kartstuff[k_itemheld] = 1; + S_StartSound(player->mo, sfx_s3k3a); + + //K_DoSneaker(player, 2); + + player->kartstuff[k_rocketsneakertimer] = (itemtime*3); + player->kartstuff[k_itemamount]--; + K_UpdateHnextList(player, true); + + for (moloop = 0; moloop < 2; moloop++) + { + mo = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_ROCKETSNEAKER); + K_MatchGenericExtraFlags(mo, player->mo); + mo->flags |= MF_NOCLIPTHING; + mo->angle = player->mo->angle; + mo->threshold = 10; + mo->movecount = moloop%2; + mo->movedir = mo->lastlook = moloop+1; + P_SetTarget(&mo->target, player->mo); + P_SetTarget(&mo->hprev, prev); + P_SetTarget(&prev->hnext, mo); + prev = mo; + } + } + break; + case KITEM_INVINCIBILITY: + if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO) // Doesn't hold your item slot hostage normally, so you're free to waste it if you have multiple + { + if (!player->kartstuff[k_invincibilitytimer]) + { + mobj_t *overlay = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_INVULNFLASH); + P_SetTarget(&overlay->target, player->mo); + overlay->destscale = player->mo->scale; + P_SetScale(overlay, player->mo->scale); + } + player->kartstuff[k_invincibilitytimer] = itemtime+(2*TICRATE); // 10 seconds + P_RestoreMusic(player); + if (!P_IsDisplayPlayer(player)) + S_StartSound(player->mo, (cv_kartinvinsfx.value ? sfx_alarmi : sfx_kinvnc)); + K_PlayPowerGloatSound(player->mo); + player->kartstuff[k_itemamount]--; + } + break; + case KITEM_BANANA: + if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO) + { + INT32 moloop; + mobj_t *mo; + mobj_t *prev = player->mo; + + //K_PlayAttackTaunt(player->mo); + player->kartstuff[k_itemheld] = 1; + S_StartSound(player->mo, sfx_s254); + + for (moloop = 0; moloop < player->kartstuff[k_itemamount]; moloop++) + { + mo = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_BANANA_SHIELD); + if (!mo) + { + player->kartstuff[k_itemamount] = moloop; + break; + } + mo->flags |= MF_NOCLIPTHING; + mo->threshold = 10; + mo->movecount = player->kartstuff[k_itemamount]; + mo->movedir = moloop+1; + P_SetTarget(&mo->target, player->mo); + P_SetTarget(&mo->hprev, prev); + P_SetTarget(&prev->hnext, mo); + prev = mo; + } + } + else if (ATTACK_IS_DOWN && player->kartstuff[k_itemheld]) // Banana x3 thrown + { + K_ThrowKartItem(player, false, MT_BANANA, -1, 0); + K_PlayAttackTaunt(player->mo); + player->kartstuff[k_itemamount]--; + K_UpdateHnextList(player, false); + } + break; + case KITEM_EGGMAN: + if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO) + { + mobj_t *mo; + player->kartstuff[k_itemamount]--; + player->kartstuff[k_eggmanheld] = 1; + S_StartSound(player->mo, sfx_s254); + mo = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_EGGMANITEM_SHIELD); + if (mo) + { + mo->flags |= MF_NOCLIPTHING; + mo->threshold = 10; + mo->movecount = 1; + mo->movedir = 1; + P_SetTarget(&mo->target, player->mo); + P_SetTarget(&player->mo->hnext, mo); + } + } + break; + case KITEM_ORBINAUT: + if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO) + { + angle_t newangle; + INT32 moloop; + mobj_t *mo = NULL; + mobj_t *prev = player->mo; + + //K_PlayAttackTaunt(player->mo); + player->kartstuff[k_itemheld] = 1; + S_StartSound(player->mo, sfx_s3k3a); + + for (moloop = 0; moloop < player->kartstuff[k_itemamount]; moloop++) + { + newangle = (player->mo->angle + ANGLE_157h) + FixedAngle(((360 / player->kartstuff[k_itemamount]) * moloop) << FRACBITS) + ANGLE_90; + mo = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_ORBINAUT_SHIELD); + if (!mo) + { + player->kartstuff[k_itemamount] = moloop; + break; + } + mo->flags |= MF_NOCLIPTHING; + mo->angle = newangle; + mo->threshold = 10; + mo->movecount = player->kartstuff[k_itemamount]; + mo->movedir = mo->lastlook = moloop+1; + mo->color = player->skincolor; + P_SetTarget(&mo->target, player->mo); + P_SetTarget(&mo->hprev, prev); + P_SetTarget(&prev->hnext, mo); + prev = mo; + } + } + else if (ATTACK_IS_DOWN && player->kartstuff[k_itemheld]) // Orbinaut x3 thrown + { + K_ThrowKartItem(player, true, MT_ORBINAUT, 1, 0); + K_PlayAttackTaunt(player->mo); + player->kartstuff[k_itemamount]--; + K_UpdateHnextList(player, false); + } + break; + case KITEM_JAWZ: + if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO) + { + angle_t newangle; + INT32 moloop; + mobj_t *mo = NULL; + mobj_t *prev = player->mo; + + //K_PlayAttackTaunt(player->mo); + player->kartstuff[k_itemheld] = 1; + S_StartSound(player->mo, sfx_s3k3a); + + for (moloop = 0; moloop < player->kartstuff[k_itemamount]; moloop++) + { + newangle = (player->mo->angle + ANGLE_157h) + FixedAngle(((360 / player->kartstuff[k_itemamount]) * moloop) << FRACBITS) + ANGLE_90; + mo = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_JAWZ_SHIELD); + if (!mo) + { + player->kartstuff[k_itemamount] = moloop; + break; + } + mo->flags |= MF_NOCLIPTHING; + mo->angle = newangle; + mo->threshold = 10; + mo->movecount = player->kartstuff[k_itemamount]; + mo->movedir = mo->lastlook = moloop+1; + P_SetTarget(&mo->target, player->mo); + P_SetTarget(&mo->hprev, prev); + P_SetTarget(&prev->hnext, mo); + prev = mo; + } + } + else if (ATTACK_IS_DOWN && HOLDING_ITEM && player->kartstuff[k_itemheld]) // Jawz thrown + { + if (player->kartstuff[k_throwdir] == 1 || player->kartstuff[k_throwdir] == 0) + K_ThrowKartItem(player, true, MT_JAWZ, 1, 0); + else if (player->kartstuff[k_throwdir] == -1) // Throwing backward gives you a dud that doesn't home in + K_ThrowKartItem(player, true, MT_JAWZ_DUD, -1, 0); + K_PlayAttackTaunt(player->mo); + player->kartstuff[k_itemamount]--; + K_UpdateHnextList(player, false); + } + break; + case KITEM_MINE: + if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO) + { + mobj_t *mo; + player->kartstuff[k_itemheld] = 1; + S_StartSound(player->mo, sfx_s254); + mo = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_SSMINE_SHIELD); + if (mo) + { + mo->flags |= MF_NOCLIPTHING; + mo->threshold = 10; + mo->movecount = 1; + mo->movedir = 1; + P_SetTarget(&mo->target, player->mo); + P_SetTarget(&player->mo->hnext, mo); + } + } + else if (ATTACK_IS_DOWN && player->kartstuff[k_itemheld]) + { + K_ThrowKartItem(player, false, MT_SSMINE, 1, 1); + K_PlayAttackTaunt(player->mo); + player->kartstuff[k_itemamount]--; + player->kartstuff[k_itemheld] = 0; + K_UpdateHnextList(player, true); + } + break; + case KITEM_BALLHOG: + if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO) + { + player->kartstuff[k_itemamount]--; + K_ThrowKartItem(player, true, MT_BALLHOG, 1, 0); + K_PlayAttackTaunt(player->mo); + } + break; + case KITEM_SPB: + if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO) + { + player->kartstuff[k_itemamount]--; + K_ThrowKartItem(player, true, MT_SPB, 1, 0); + K_PlayAttackTaunt(player->mo); + } + break; + case KITEM_GROW: + if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO + && player->kartstuff[k_growshrinktimer] <= 0) // Grow holds the item box hostage + { + if (player->kartstuff[k_growshrinktimer] < 0) // If you're shrunk, then "grow" will just make you normal again. + K_RemoveGrowShrink(player); + else + { + K_PlayPowerGloatSound(player->mo); + player->mo->scalespeed = mapobjectscale/TICRATE; + player->mo->destscale = (3*mapobjectscale)/2; + if (cv_kartdebugshrink.value && !modeattacking && !player->bot) + player->mo->destscale = (6*player->mo->destscale)/8; + player->kartstuff[k_growshrinktimer] = itemtime+(4*TICRATE); // 12 seconds + P_RestoreMusic(player); + if (!P_IsDisplayPlayer(player)) + S_StartSound(player->mo, (cv_kartinvinsfx.value ? sfx_alarmg : sfx_kgrow)); + S_StartSound(player->mo, sfx_kc5a); + } + player->kartstuff[k_itemamount]--; + } + break; + case KITEM_SHRINK: + if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO) + { + K_DoShrink(player); + player->kartstuff[k_itemamount]--; + K_PlayPowerGloatSound(player->mo); + } + break; + case KITEM_THUNDERSHIELD: + if (player->kartstuff[k_curshield] != 1) + { + mobj_t *shield = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_THUNDERSHIELD); + P_SetScale(shield, (shield->destscale = (5*shield->destscale)>>2)); + P_SetTarget(&shield->target, player->mo); + S_StartSound(shield, sfx_s3k41); + player->kartstuff[k_curshield] = 1; + } + if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO) + { + K_DoThunderShield(player); + player->kartstuff[k_itemamount]--; + K_PlayAttackTaunt(player->mo); + } + break; + case KITEM_HYUDORO: + if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO) + { + player->kartstuff[k_itemamount]--; + K_DoHyudoroSteal(player); // yes. yes they do. + } + break; + case KITEM_POGOSPRING: + if (ATTACK_IS_DOWN && !HOLDING_ITEM && onground && NO_HYUDORO + && !player->kartstuff[k_pogospring]) + { + K_PlayBoostTaunt(player->mo); + K_DoPogoSpring(player->mo, 32<kartstuff[k_pogospring] = 1; + player->kartstuff[k_itemamount]--; + } + break; + case KITEM_SUPERRING: + if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO) + { + player->kartstuff[k_superring] += (10*3); + player->kartstuff[k_itemamount]--; + } + break; + case KITEM_KITCHENSINK: + if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO) + { + mobj_t *mo; + player->kartstuff[k_itemheld] = 1; + S_StartSound(player->mo, sfx_s254); + mo = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_SINK_SHIELD); + if (mo) + { + mo->flags |= MF_NOCLIPTHING; + mo->threshold = 10; + mo->movecount = 1; + mo->movedir = 1; + P_SetTarget(&mo->target, player->mo); + P_SetTarget(&player->mo->hnext, mo); + } + } + else if (ATTACK_IS_DOWN && HOLDING_ITEM && player->kartstuff[k_itemheld]) // Sink thrown + { + K_ThrowKartItem(player, false, MT_SINK, 1, 2); + K_PlayAttackTaunt(player->mo); + player->kartstuff[k_itemamount]--; + player->kartstuff[k_itemheld] = 0; + K_UpdateHnextList(player, true); + } + break; + case KITEM_SAD: + if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO + && !player->kartstuff[k_sadtimer]) + { + player->kartstuff[k_sadtimer] = stealtime; + player->kartstuff[k_itemamount]--; + } + break; + default: + break; } - if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO) - { - K_DoThunderShield(player); - player->kartstuff[k_itemamount]--; - K_PlayAttackTaunt(player->mo); - } - break; - case KITEM_HYUDORO: - if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO) - { - player->kartstuff[k_itemamount]--; - K_DoHyudoroSteal(player); // yes. yes they do. - } - break; - case KITEM_POGOSPRING: - if (ATTACK_IS_DOWN && !HOLDING_ITEM && onground && NO_HYUDORO - && !player->kartstuff[k_pogospring]) - { - K_PlayBoostTaunt(player->mo); - K_DoPogoSpring(player->mo, 32<kartstuff[k_pogospring] = 1; - player->kartstuff[k_itemamount]--; - } - break; - case KITEM_KITCHENSINK: - if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO) - { - mobj_t *mo; - player->kartstuff[k_itemheld] = 1; - S_StartSound(player->mo, sfx_s254); - mo = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_SINK_SHIELD); - if (mo) - { - mo->flags |= MF_NOCLIPTHING; - mo->threshold = 10; - mo->movecount = 1; - mo->movedir = 1; - P_SetTarget(&mo->target, player->mo); - P_SetTarget(&player->mo->hnext, mo); - } - } - else if (ATTACK_IS_DOWN && HOLDING_ITEM && player->kartstuff[k_itemheld]) // Sink thrown - { - K_ThrowKartItem(player, false, MT_SINK, 1, 2); - K_PlayAttackTaunt(player->mo); - player->kartstuff[k_itemamount]--; - player->kartstuff[k_itemheld] = 0; - K_UpdateHnextList(player, true); - } - break; - case KITEM_SAD: - if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO - && !player->kartstuff[k_sadtimer]) - { - player->kartstuff[k_sadtimer] = stealtime; - player->kartstuff[k_itemamount]--; - } - break; - default: - break; + } } } @@ -5708,7 +6409,15 @@ void K_MoveKartPlayer(player_t *player, boolean onground) player->kartstuff[k_itemtype] = KITEM_NONE; } - if (player->kartstuff[k_itemtype] != KITEM_THUNDERSHIELD) + if (spbplace == -1 || player->kartstuff[k_position] != spbplace) + player->kartstuff[k_ringlock] = 0; // reset ring lock + + if (player->kartstuff[k_itemtype] == KITEM_THUNDERSHIELD) + { + if ((player->kartstuff[k_rings]+player->kartstuff[k_pickuprings]) < 20 && !player->kartstuff[k_ringlock]) + K_LookForRings(player->mo); + } + else player->kartstuff[k_curshield] = 0; if (player->kartstuff[k_growshrinktimer] <= 0) @@ -5908,7 +6617,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground) else { K_SpawnDashDustRelease(player); // already handled for perfect boosts by K_DoSneaker - if ((!player->kartstuff[k_floorboost] || player->kartstuff[k_floorboost] == 3) && P_IsLocalPlayer(player)) + if ((!player->kartstuff[k_floorboost] || player->kartstuff[k_floorboost] == 3) && P_IsDisplayPlayer(player)) { if (player->kartstuff[k_boostcharge] <= 40) S_StartSound(player->mo, sfx_cdfm01); // You were almost there! @@ -6231,6 +6940,18 @@ static patch_t *kp_winnernum[NUMPOSFRAMES]; static patch_t *kp_facenum[MAXPLAYERS+1]; static patch_t *kp_facehighlight[8]; +static patch_t *kp_ringsticker[2]; +static patch_t *kp_ringstickersplit[4]; +static patch_t *kp_ring[6]; +static patch_t *kp_smallring[6]; +static patch_t *kp_ringdebtminus; +static patch_t *kp_ringdebtminussmall; +static patch_t *kp_ringspblock[16]; +static patch_t *kp_ringspblocksmall[16]; + +static patch_t *kp_speedometersticker; +static patch_t *kp_speedometerlabel[4]; + static patch_t *kp_rankbumper; static patch_t *kp_tinybumper[2]; static patch_t *kp_ranknobumpers; @@ -6249,6 +6970,7 @@ static patch_t *kp_itemtimer[2]; static patch_t *kp_itemmulsticker[2]; static patch_t *kp_itemx; +static patch_t *kp_superring[2]; static patch_t *kp_sneaker[2]; static patch_t *kp_rocketsneaker[2]; static patch_t *kp_invincibility[13]; @@ -6369,6 +7091,57 @@ void K_LoadKartHUDGraphics(void) kp_facehighlight[i] = (patch_t *) W_CachePatchName(buffer, PU_HUDGFX); } + // Rings & Lives + kp_ringsticker[0] = W_CachePatchName("RNGBACKA", PU_HUDGFX); + kp_ringsticker[1] = W_CachePatchName("RNGBACKB", PU_HUDGFX); + + sprintf(buffer, "K_RINGx"); + for (i = 0; i < 6; i++) + { + buffer[6] = '0'+(i+1); + kp_ring[i] = (patch_t *) W_CachePatchName(buffer, PU_HUDGFX); + } + + kp_ringdebtminus = W_CachePatchName("RDEBTMIN", PU_HUDGFX); + + sprintf(buffer, "SPBRNGxx"); + for (i = 0; i < 16; i++) + { + buffer[6] = '0'+((i+1) / 10); + buffer[7] = '0'+((i+1) % 10); + kp_ringspblock[i] = (patch_t *) W_CachePatchName(buffer, PU_HUDGFX); + } + + kp_ringstickersplit[0] = W_CachePatchName("SMRNGBGA", PU_HUDGFX); + kp_ringstickersplit[1] = W_CachePatchName("SMRNGBGB", PU_HUDGFX); + + sprintf(buffer, "K_SRINGx"); + for (i = 0; i < 6; i++) + { + buffer[7] = '0'+(i+1); + kp_smallring[i] = (patch_t *) W_CachePatchName(buffer, PU_HUDGFX); + } + + kp_ringdebtminussmall = W_CachePatchName("SRDEBTMN", PU_HUDGFX); + + sprintf(buffer, "SPBRGSxx"); + for (i = 0; i < 16; i++) + { + buffer[6] = '0'+((i+1) / 10); + buffer[7] = '0'+((i+1) % 10); + kp_ringspblocksmall[i] = (patch_t *) W_CachePatchName(buffer, PU_HUDGFX); + } + + // Speedometer + kp_speedometersticker = W_CachePatchName("K_SPDMBG", PU_HUDGFX); + + sprintf(buffer, "K_SPDMLx"); + for (i = 0; i < 4; i++) + { + buffer[7] = '0'+(i+1); + kp_speedometerlabel[i] = (patch_t *) W_CachePatchName(buffer, PU_HUDGFX); + } + // Extra ranking icons kp_rankbumper = W_CachePatchName("K_BLNICO", PU_HUDGFX); kp_tinybumper[0] = W_CachePatchName("K_BLNA", PU_HUDGFX); @@ -6392,6 +7165,7 @@ void K_LoadKartHUDGraphics(void) kp_itemmulsticker[0] = W_CachePatchName("K_ITMUL", PU_HUDGFX); kp_itemx = W_CachePatchName("K_ITX", PU_HUDGFX); + kp_superring[0] = W_CachePatchName("K_ITRING", PU_HUDGFX); kp_sneaker[0] = W_CachePatchName("K_ITSHOE", PU_HUDGFX); kp_rocketsneaker[0] = W_CachePatchName("K_ITRSHE", PU_HUDGFX); @@ -6427,6 +7201,7 @@ void K_LoadKartHUDGraphics(void) kp_itemtimer[1] = W_CachePatchName("K_ISIMER", PU_HUDGFX); kp_itemmulsticker[1] = W_CachePatchName("K_ISMUL", PU_HUDGFX); + kp_superring[1] = W_CachePatchName("K_ISRING", PU_HUDGFX); kp_sneaker[1] = W_CachePatchName("K_ISSHOE", PU_HUDGFX); kp_rocketsneaker[1] = W_CachePatchName("K_ISRSHE", PU_HUDGFX); sprintf(buffer, "K_ISINVx"); @@ -6571,6 +7346,8 @@ const char *K_GetItemPatch(UINT8 item, boolean tiny) return (tiny ? "K_ISHYUD" : "K_ITHYUD"); case KITEM_POGOSPRING: return (tiny ? "K_ISPOGO" : "K_ITPOGO"); + case KITEM_SUPERRING: + return (tiny ? "K_ISRING" : "K_ITRING"); case KITEM_KITCHENSINK: return (tiny ? "K_ISSINK" : "K_ITSINK"); case KRITEM_TRIPLEORBINAUT: @@ -6587,7 +7364,6 @@ const char *K_GetItemPatch(UINT8 item, boolean tiny) INT32 ITEM_X, ITEM_Y; // Item Window INT32 TIME_X, TIME_Y; // Time Sticker INT32 LAPS_X, LAPS_Y; // Lap Sticker -INT32 SPDM_X, SPDM_Y; // Speedometer INT32 POSI_X, POSI_Y; // Position Number INT32 FACE_X, FACE_Y; // Top-four Faces INT32 STCD_X, STCD_Y; // Starting countdown @@ -6647,9 +7423,6 @@ static void K_initKartHUD(void) // Level Laps LAPS_X = 9; // 9 LAPS_Y = BASEVIDHEIGHT - 29; // 171 - // Speedometer - SPDM_X = 9; // 9 - SPDM_Y = BASEVIDHEIGHT - 45; // 155 // Position Number POSI_X = BASEVIDWIDTH - 9; // 268 POSI_Y = BASEVIDHEIGHT - 9; // 138 @@ -6688,20 +7461,20 @@ static void K_initKartHUD(void) ITEM_Y = -8; LAPS_X = 3; - LAPS_Y = (BASEVIDHEIGHT/2)-13; + LAPS_Y = (BASEVIDHEIGHT/2)-12; POSI_X = 24; - POSI_Y = (BASEVIDHEIGHT/2)- 16; + POSI_Y = (BASEVIDHEIGHT/2)-26; // 2P (top right) ITEM2_X = BASEVIDWIDTH-39; ITEM2_Y = -8; - LAPS2_X = BASEVIDWIDTH-40; - LAPS2_Y = (BASEVIDHEIGHT/2)-13; + LAPS2_X = BASEVIDWIDTH-43; + LAPS2_Y = (BASEVIDHEIGHT/2)-12; POSI2_X = BASEVIDWIDTH -4; - POSI2_Y = (BASEVIDHEIGHT/2)- 16; + POSI2_Y = (BASEVIDHEIGHT/2)-26; // Reminder that 3P and 4P are just 1P and 2P splitscreen'd to the bottom. @@ -6791,7 +7564,7 @@ static void K_drawKartItem(void) if (stplyr->skincolor) localcolor = stplyr->skincolor; - switch((stplyr->kartstuff[k_itemroulette] % (14*3)) / 3) + switch((stplyr->kartstuff[k_itemroulette] % (15*3)) / 3) { // Each case is handled in threes, to give three frames of in-game time to see the item on the roulette case 0: // Sneaker @@ -6850,11 +7623,15 @@ static void K_drawKartItem(void) localpatch = kp_thundershield[offset]; //localcolor = SKINCOLOR_CYAN; break; - /*case 14: // Pogo Spring + case 14: // Super Ring + localpatch = kp_superring[offset]; + //localcolor = SKINCOLOR_GOLD; + break; + /*case 15: // Pogo Spring localpatch = kp_pogospring[offset]; localcolor = SKINCOLOR_TANGERINE; break; - case 15: // Kitchen Sink + case 16: // Kitchen Sink localpatch = kp_kitchensink[offset]; localcolor = SKINCOLOR_STEEL; break;*/ @@ -6971,6 +7748,9 @@ static void K_drawKartItem(void) case KITEM_POGOSPRING: localpatch = kp_pogospring[offset]; break; + case KITEM_SUPERRING: + localpatch = kp_superring[offset]; + break; case KITEM_KITCHENSINK: localpatch = kp_kitchensink[offset]; break; @@ -6985,11 +7765,11 @@ static void K_drawKartItem(void) localpatch = kp_nodraw; } - if (stplyr->kartstuff[k_itemblink] && (leveltime & 1)) + if (stplyr->karthud[khud_itemblink] && (leveltime & 1)) { colormode = TC_BLINK; - switch (stplyr->kartstuff[k_itemblinkmode]) + switch (stplyr->karthud[khud_itemblinkmode]) { case 2: localcolor = (UINT8)(1 + (leveltime % (MAXSKINCOLORS-1))); @@ -7069,14 +7849,13 @@ static void K_drawKartItem(void) V_DrawFill(fx+x+length, fy+y+1, 1, height, 12|fflags); // the right one if (height == 2) V_DrawFill(fx+x+2, fy+y+2, length-2, 1, 8|fflags); // the dulled underside - V_DrawFill(fx+x+2, fy+y+1, length-2, 1, 120|fflags); // the shine + V_DrawFill(fx+x+2, fy+y+1, length-2, 1, 0|fflags); // the shine } } // Quick Eggman numbers if (stplyr->kartstuff[k_eggmanexplode] > 1 /*&& stplyr->kartstuff[k_eggmanexplode] <= 3*TICRATE*/) V_DrawScaledPatch(fx+17, fy+13-offset, V_HUDTRANS|fflags, kp_eggnum[min(3, G_TicsToSeconds(stplyr->kartstuff[k_eggmanexplode]))]); - } void K_drawKartTimestamp(tic_t drawtime, INT32 TX, INT32 TY, INT16 emblemmap, UINT8 mode) @@ -7601,22 +8380,46 @@ void HU_DrawTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scorelines, I } } -static void K_drawKartLaps(void) +#define RINGANIM_FLIPFRAME (RINGANIM_NUMFRAMES/2) + +static void K_drawKartLapsAndRings(void) { + SINT8 ringanim_realframe = stplyr->karthud[khud_ringframe]; INT32 splitflags = K_calcSplitFlags(V_SNAPTOBOTTOM|V_SNAPTOLEFT); - INT32 fx = 0, fy = 0, fflags = 0; // stuff for 3p / 4p splitscreen. - boolean flipstring = false; // used for 3p or 4p - INT32 stringw = 0; // used with the above + UINT8 rn[2]; + INT32 ringflip = 0; + UINT8 *ringmap = NULL; + boolean colorring = false; + INT32 ringx = 0; + + rn[0] = ((abs(stplyr->kartstuff[k_rings]) / 10) % 10); + rn[1] = (abs(stplyr->kartstuff[k_rings]) % 10); + + if (stplyr->kartstuff[k_rings] <= 0 && (leveltime/5 & 1)) // In debt + { + ringmap = R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_CRIMSON, GTC_CACHE); + colorring = true; + } + else if (stplyr->kartstuff[k_rings] >= 20) // Maxed out + ringmap = R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_YELLOW, GTC_CACHE); + + if (stplyr->karthud[khud_ringframe] > RINGANIM_FLIPFRAME) + { + ringflip = V_FLIP; + ringanim_realframe = RINGANIM_NUMFRAMES-stplyr->karthud[khud_ringframe]; + ringx += SHORT((splitscreen > 1) ? kp_smallring[ringanim_realframe]->width : kp_ring[ringanim_realframe]->width); + } if (splitscreen > 1) { + INT32 fx = 0, fy = 0, fr = 0; + INT32 flipflag = 0; // pain and suffering defined below if (splitscreen < 2) // don't change shit for THIS splitscreen. { fx = LAPS_X; fy = LAPS_Y; - fflags = splitflags; } else { @@ -7624,116 +8427,238 @@ static void K_drawKartLaps(void) { fx = LAPS_X; fy = LAPS_Y; - fflags = V_SNAPTOLEFT|((stplyr == &players[displayplayers[2]]) ? V_SPLITSCREEN|V_SNAPTOBOTTOM : 0); // flip P3 to the bottom. + splitflags = V_SNAPTOLEFT|((stplyr == &players[displayplayers[2]]) ? V_SPLITSCREEN|V_SNAPTOBOTTOM : 0); // flip P3 to the bottom. } else // else, that means we're P2 or P4. { fx = LAPS2_X; fy = LAPS2_Y; - fflags = V_SNAPTORIGHT|((stplyr == &players[displayplayers[3]]) ? V_SPLITSCREEN|V_SNAPTOBOTTOM : 0); // flip P4 to the bottom - flipstring = true; // make the string right aligned and other shit + splitflags = V_SNAPTORIGHT|((stplyr == &players[displayplayers[3]]) ? V_SPLITSCREEN|V_SNAPTOBOTTOM : 0); // flip P4 to the bottom + flipflag = V_FLIP; // make the string right aligned and other shit } } + fr = fx; + // Laps + V_DrawScaledPatch(fx-2 + (flipflag ? (SHORT(kp_ringstickersplit[1]->width) - 3) : 0), fy, V_HUDTRANS|splitflags|flipflag, kp_ringstickersplit[0]); - if (stplyr->exiting) // draw stuff as god intended. + V_DrawScaledPatch(fx, fy, V_HUDTRANS|splitflags, kp_splitlapflag); + V_DrawScaledPatch(fx+22, fy, V_HUDTRANS|splitflags, frameslash); + + if (cv_numlaps.value >= 10) { - V_DrawScaledPatch(fx, fy, V_HUDTRANS|fflags, kp_splitlapflag); - V_DrawString(fx+13, fy+1, V_HUDTRANS|fflags, "FIN"); - } - else // take flipstring into account here since we may have more laps than just 10 - if (flipstring) - { - stringw = V_StringWidth(va("%d/%d", stplyr->laps+1, cv_numlaps.value), 0); + UINT8 ln[2]; + ln[0] = ((abs(stplyr->laps+1) / 10) % 10); + ln[1] = (abs(stplyr->laps+1) % 10); - V_DrawScaledPatch(BASEVIDWIDTH-stringw-16, fy, V_HUDTRANS|fflags, kp_splitlapflag); - V_DrawRightAlignedString(BASEVIDWIDTH-3, fy+1, V_HUDTRANS|fflags, va("%d/%d", stplyr->laps+1, cv_numlaps.value)); - } - else // draw stuff NORMALLY. - { - V_DrawScaledPatch(fx, fy, V_HUDTRANS|fflags, kp_splitlapflag); - V_DrawString(fx+13, fy+1, V_HUDTRANS|fflags, va("%d/%d", stplyr->laps+1, cv_numlaps.value)); - } + V_DrawScaledPatch(fx+13, fy, V_HUDTRANS|splitflags, pingnum[ln[0]]); + V_DrawScaledPatch(fx+17, fy, V_HUDTRANS|splitflags, pingnum[ln[1]]); + + ln[0] = ((abs(cv_numlaps.value) / 10) % 10); + ln[1] = (abs(cv_numlaps.value) % 10); + + V_DrawScaledPatch(fx+27, fy, V_HUDTRANS|splitflags, pingnum[ln[0]]); + V_DrawScaledPatch(fx+31, fy, V_HUDTRANS|splitflags, pingnum[ln[1]]); + } + else + { + V_DrawScaledPatch(fx+13, fy, V_HUDTRANS|splitflags, kp_facenum[(stplyr->laps+1) % 10]); + V_DrawScaledPatch(fx+27, fy, V_HUDTRANS|splitflags, kp_facenum[(cv_numlaps.value) % 10]); + } + + // Rings + if (netgame) + { + V_DrawScaledPatch(fx-2 + (flipflag ? (SHORT(kp_ringstickersplit[1]->width) - 3) : 0), fy-10, V_HUDTRANS|splitflags|flipflag, kp_ringstickersplit[1]); + if (flipflag) + fr += 15; + } + else + V_DrawScaledPatch(fx-2 + (flipflag ? (SHORT(kp_ringstickersplit[0]->width) - 3) : 0), fy-10, V_HUDTRANS|splitflags|flipflag, kp_ringstickersplit[0]); + + V_DrawMappedPatch(fr+ringx, fy-13, V_HUDTRANS|splitflags|ringflip, kp_smallring[ringanim_realframe], (colorring ? ringmap : NULL)); + + if (stplyr->kartstuff[k_rings] < 0) // Draw the minus for ring debt + V_DrawMappedPatch(fr+7, fy-10, V_HUDTRANS|splitflags, kp_ringdebtminussmall, ringmap); + + V_DrawMappedPatch(fr+11, fy-10, V_HUDTRANS|splitflags, pingnum[rn[0]], ringmap); + V_DrawMappedPatch(fr+15, fy-10, V_HUDTRANS|splitflags, pingnum[rn[1]], ringmap); + + // SPB ring lock + if (stplyr->kartstuff[k_ringlock]) + V_DrawScaledPatch(fr-12, fy-23, V_HUDTRANS|splitflags, kp_ringspblocksmall[stplyr->karthud[khud_ringspblock]]); + + // Lives + if (!netgame) + { + UINT8 *colormap = R_GetTranslationColormap(stplyr->skin, stplyr->skincolor, GTC_CACHE); + V_DrawMappedPatch(fr+21, fy-13, V_HUDTRANS|splitflags, facemmapprefix[stplyr->skin], colormap); + V_DrawScaledPatch(fr+34, fy-10, V_HUDTRANS|splitflags, pingnum[(stplyr->lives % 10)]); // make sure this doesn't overflow + } } else { + // Laps V_DrawScaledPatch(LAPS_X, LAPS_Y, V_HUDTRANS|splitflags, kp_lapsticker); if (stplyr->exiting) V_DrawKartString(LAPS_X+33, LAPS_Y+3, V_HUDTRANS|splitflags, "FIN"); else V_DrawKartString(LAPS_X+33, LAPS_Y+3, V_HUDTRANS|splitflags, va("%d/%d", stplyr->laps+1, cv_numlaps.value)); + + // Rings + if (netgame) + V_DrawScaledPatch(LAPS_X, LAPS_Y-11, V_HUDTRANS|splitflags, kp_ringsticker[1]); + else + V_DrawScaledPatch(LAPS_X, LAPS_Y-11, V_HUDTRANS|splitflags, kp_ringsticker[0]); + + V_DrawMappedPatch(LAPS_X+ringx+7, LAPS_Y-16, V_HUDTRANS|splitflags|ringflip, kp_ring[ringanim_realframe], (colorring ? ringmap : NULL)); + + if (stplyr->kartstuff[k_rings] < 0) // Draw the minus for ring debt + { + V_DrawMappedPatch(LAPS_X+23, LAPS_Y-11, V_HUDTRANS|splitflags, kp_ringdebtminus, ringmap); + V_DrawMappedPatch(LAPS_X+29, LAPS_Y-11, V_HUDTRANS|splitflags, kp_facenum[rn[0]], ringmap); + V_DrawMappedPatch(LAPS_X+35, LAPS_Y-11, V_HUDTRANS|splitflags, kp_facenum[rn[1]], ringmap); + } + else + { + V_DrawMappedPatch(LAPS_X+23, LAPS_Y-11, V_HUDTRANS|splitflags, kp_facenum[rn[0]], ringmap); + V_DrawMappedPatch(LAPS_X+29, LAPS_Y-11, V_HUDTRANS|splitflags, kp_facenum[rn[1]], ringmap); + } + + // SPB ring lock + if (stplyr->kartstuff[k_ringlock]) + V_DrawScaledPatch(LAPS_X-5, LAPS_Y-28, V_HUDTRANS|splitflags, kp_ringspblock[stplyr->karthud[khud_ringspblock]]); + + // Lives + if (!netgame) + { + UINT8 *colormap = R_GetTranslationColormap(stplyr->skin, stplyr->skincolor, GTC_CACHE); + V_DrawMappedPatch(LAPS_X+46, LAPS_Y-16, V_HUDTRANS|splitflags, facerankprefix[stplyr->skin], colormap); + V_DrawScaledPatch(LAPS_X+63, LAPS_Y-11, V_HUDTRANS|splitflags, kp_facenum[(stplyr->lives % 10)]); // make sure this doesn't overflow + } } } +#undef RINGANIM_NUMFRAMES +#undef RINGANIM_FLIPFRAME + static void K_drawKartSpeedometer(void) { - fixed_t convSpeed; + static fixed_t convSpeed; + UINT8 labeln = 0; + UINT8 numbers[3]; INT32 splitflags = K_calcSplitFlags(V_SNAPTOBOTTOM|V_SNAPTOLEFT); + UINT8 battleoffset = 0; - if (cv_kartspeedometer.value == 1) // Kilometers + if (!stplyr->exiting) // Keep the same speed value as when you crossed the finish line! { - convSpeed = FixedDiv(FixedMul(stplyr->speed, 142371), mapobjectscale)/FRACUNIT; // 2.172409058 - V_DrawKartString(SPDM_X, SPDM_Y, V_HUDTRANS|splitflags, va("%3d km/h", convSpeed)); - } - else if (cv_kartspeedometer.value == 2) // Miles - { - convSpeed = FixedDiv(FixedMul(stplyr->speed, 88465), mapobjectscale)/FRACUNIT; // 1.349868774 - V_DrawKartString(SPDM_X, SPDM_Y, V_HUDTRANS|splitflags, va("%3d mph", convSpeed)); - } - else if (cv_kartspeedometer.value == 3) // Fracunits - { - convSpeed = FixedDiv(stplyr->speed, mapobjectscale)/FRACUNIT; - V_DrawKartString(SPDM_X, SPDM_Y, V_HUDTRANS|splitflags, va("%3d fu/t", convSpeed)); + switch (cv_kartspeedometer.value) + { + case 1: // Sonic Drift 2 style percentage + default: + convSpeed = (((25*stplyr->speed)/24) * 100) / K_GetKartSpeed(stplyr, false); // Based on top speed! (cheats with the numbers due to some weird discrepancy) + labeln = 0; + break; + case 2: // Kilometers + convSpeed = FixedDiv(FixedMul(stplyr->speed, 142371), mapobjectscale)/FRACUNIT; // 2.172409058 + labeln = 1; + break; + case 3: // Miles + convSpeed = FixedDiv(FixedMul(stplyr->speed, 88465), mapobjectscale)/FRACUNIT; // 1.349868774 + labeln = 2; + break; + case 4: // Fracunits + convSpeed = FixedDiv(stplyr->speed, mapobjectscale)/FRACUNIT; // 1.0. duh. + labeln = 3; + break; + } } + + // Don't overflow + if (convSpeed > 999) + convSpeed = 999; + + numbers[0] = ((convSpeed / 100) % 10); + numbers[1] = ((convSpeed / 10) % 10); + numbers[2] = (convSpeed % 10); + + if (G_BattleGametype()) + battleoffset = 8; + + V_DrawScaledPatch(LAPS_X, LAPS_Y-25 + battleoffset, V_HUDTRANS|splitflags, kp_speedometersticker); + V_DrawScaledPatch(LAPS_X+7, LAPS_Y-25 + battleoffset, V_HUDTRANS|splitflags, kp_facenum[numbers[0]]); + V_DrawScaledPatch(LAPS_X+13, LAPS_Y-25 + battleoffset, V_HUDTRANS|splitflags, kp_facenum[numbers[1]]); + V_DrawScaledPatch(LAPS_X+19, LAPS_Y-25 + battleoffset, V_HUDTRANS|splitflags, kp_facenum[numbers[2]]); + V_DrawScaledPatch(LAPS_X+29, LAPS_Y-25 + battleoffset, V_HUDTRANS|splitflags, kp_speedometerlabel[labeln]); } static void K_drawKartBumpersOrKarma(void) { UINT8 *colormap = R_GetTranslationColormap(TC_DEFAULT, stplyr->skincolor, GTC_CACHE); INT32 splitflags = K_calcSplitFlags(V_SNAPTOBOTTOM|V_SNAPTOLEFT); - INT32 fx = 0, fy = 0, fflags = 0; - boolean flipstring = false; // same as laps, used for splitscreen - INT32 stringw = 0; // used with the above if (splitscreen > 1) { + INT32 fx = 0, fy = 0; + INT32 flipflag = 0; - // we will reuse lap coords here since it's essentially the same shit. - - if (stplyr == &players[displayplayers[0]] || stplyr == &players[displayplayers[2]]) // If we are P1 or P3... + // pain and suffering defined below + if (splitscreen < 2) // don't change shit for THIS splitscreen. { fx = LAPS_X; fy = LAPS_Y; - fflags = V_SNAPTOLEFT|((stplyr == &players[displayplayers[2]]) ? V_SPLITSCREEN|V_SNAPTOBOTTOM : 0); // flip P3 to the bottom. } - else // else, that means we're P2 or P4. + else { - fx = LAPS2_X; - fy = LAPS2_Y; - fflags = V_SNAPTORIGHT|((stplyr == &players[displayplayers[3]]) ? V_SPLITSCREEN|V_SNAPTOBOTTOM : 0); // flip P4 to the bottom - flipstring = true; + if (stplyr == &players[displayplayers[0]] || stplyr == &players[displayplayers[2]]) // If we are P1 or P3... + { + fx = LAPS_X; + fy = LAPS_Y; + splitflags = V_SNAPTOLEFT|((stplyr == &players[displayplayers[2]]) ? V_SPLITSCREEN|V_SNAPTOBOTTOM : 0); // flip P3 to the bottom. + } + else // else, that means we're P2 or P4. + { + fx = LAPS2_X; + fy = LAPS2_Y; + splitflags = V_SNAPTORIGHT|((stplyr == &players[displayplayers[3]]) ? V_SPLITSCREEN|V_SNAPTOBOTTOM : 0); // flip P4 to the bottom + flipflag = V_FLIP; // make the string right aligned and other shit + } } + V_DrawScaledPatch(fx-2 + (flipflag ? (SHORT(kp_ringstickersplit[1]->width) - 3) : 0), fy, V_HUDTRANS|splitflags|flipflag, kp_ringstickersplit[0]); + V_DrawScaledPatch(fx+22, fy, V_HUDTRANS|splitflags, frameslash); + if (stplyr->kartstuff[k_bumper] <= 0) { - V_DrawMappedPatch(fx, fy-1, V_HUDTRANS|fflags, kp_splitkarmabomb, colormap); - V_DrawString(fx+13, fy+1, V_HUDTRANS|fflags, va("%d/2", stplyr->kartstuff[k_comebackpoints])); + V_DrawMappedPatch(fx+1, fy-2, V_HUDTRANS|splitflags, kp_splitkarmabomb, colormap); + V_DrawScaledPatch(fx+13, fy, V_HUDTRANS|splitflags, kp_facenum[(stplyr->kartstuff[k_comebackpoints]) % 10]); + V_DrawScaledPatch(fx+27, fy, V_HUDTRANS|splitflags, kp_facenum[2]); } - else // the above doesn't need to account for weird stuff since the max amount of karma necessary is always 2 ^^^^ + else { - if (flipstring) // for p2 and p4, assume we can have more than 10 bumpers. It's retarded but who knows. - { - stringw = V_StringWidth(va("%d/%d", stplyr->kartstuff[k_bumper], cv_kartbumpers.value), 0); + V_DrawMappedPatch(fx+1, fy-2, V_HUDTRANS|splitflags, kp_rankbumper, colormap); - V_DrawMappedPatch(BASEVIDWIDTH-stringw-16, fy-1, V_HUDTRANS|fflags, kp_rankbumper, colormap); - V_DrawRightAlignedString(BASEVIDWIDTH-3, fy+1, V_HUDTRANS|fflags, va("%d/%d", stplyr->kartstuff[k_bumper], cv_kartbumpers.value)); - } - else // draw bumpers normally. + if (stplyr->kartstuff[k_bumper] > 9 || cv_kartbumpers.value > 9) { - V_DrawMappedPatch(fx, fy-1, V_HUDTRANS|fflags, kp_rankbumper, colormap); - V_DrawString(fx+13, fy+1, V_HUDTRANS|fflags, va("%d/%d", stplyr->kartstuff[k_bumper], cv_kartbumpers.value)); + UINT8 ln[2]; + ln[0] = ((abs(stplyr->kartstuff[k_bumper]) / 10) % 10); + ln[1] = (abs(stplyr->kartstuff[k_bumper]) % 10); + + V_DrawScaledPatch(fx+13, fy, V_HUDTRANS|splitflags, pingnum[ln[0]]); + V_DrawScaledPatch(fx+17, fy, V_HUDTRANS|splitflags, pingnum[ln[1]]); + + ln[0] = ((abs(cv_kartbumpers.value) / 10) % 10); + ln[1] = (abs(cv_kartbumpers.value) % 10); + + V_DrawScaledPatch(fx+27, fy, V_HUDTRANS|splitflags, pingnum[ln[0]]); + V_DrawScaledPatch(fx+31, fy, V_HUDTRANS|splitflags, pingnum[ln[1]]); + } + else + { + V_DrawScaledPatch(fx+13, fy, V_HUDTRANS|splitflags, kp_facenum[(stplyr->kartstuff[k_bumper]) % 10]); + V_DrawScaledPatch(fx+27, fy, V_HUDTRANS|splitflags, kp_facenum[(cv_kartbumpers.value) % 10]); } } } @@ -8149,10 +9074,10 @@ static void K_drawKartFinish(void) { INT32 pnum = 0, splitflags = K_calcSplitFlags(0); - if (!stplyr->kartstuff[k_cardanimation] || stplyr->kartstuff[k_cardanimation] >= 2*TICRATE) + if (!stplyr->karthud[khud_cardanimation] || stplyr->karthud[khud_cardanimation] >= 2*TICRATE) return; - if ((stplyr->kartstuff[k_cardanimation] % (2*5)) / 5) // blink + if ((stplyr->karthud[khud_cardanimation] % (2*5)) / 5) // blink pnum = 1; if (splitscreen > 1) // 3/4p, stationary FIN @@ -8171,7 +9096,7 @@ static void K_drawKartFinish(void) x = ((vid.width<width)<kartstuff[k_cardanimation])*(xval > x ? xval : x))/TICRATE; + x = ((TICRATE - stplyr->karthud[khud_cardanimation])*(xval > x ? xval : x))/TICRATE; if (splitscreen && stplyr == &players[displayplayers[1]]) x = -x; @@ -8186,7 +9111,7 @@ static void K_drawKartFinish(void) static void K_drawBattleFullscreen(void) { INT32 x = BASEVIDWIDTH/2; - INT32 y = -64+(stplyr->kartstuff[k_cardanimation]); // card animation goes from 0 to 164, 164 is the middle of the screen + INT32 y = -64+(stplyr->karthud[khud_cardanimation]); // card animation goes from 0 to 164, 164 is the middle of the screen INT32 splitflags = V_SNAPTOTOP; // I don't feel like properly supporting non-green resolutions, so you can have a misuse of SNAPTO instead fixed_t scale = FRACUNIT; boolean drawcomebacktimer = true; // lazy hack because it's cleaner in the long run. @@ -8201,11 +9126,11 @@ static void K_drawBattleFullscreen(void) || (splitscreen > 1 && (stplyr == &players[displayplayers[2]] || (stplyr == &players[displayplayers[3]] && splitscreen > 2)))) { - y = 232-(stplyr->kartstuff[k_cardanimation]/2); + y = 232-(stplyr->karthud[khud_cardanimation]/2); splitflags = V_SNAPTOBOTTOM; } else - y = -32+(stplyr->kartstuff[k_cardanimation]/2); + y = -32+(stplyr->karthud[khud_cardanimation]/2); if (splitscreen > 1) { @@ -8569,21 +9494,21 @@ static void K_drawChallengerScreen(void) static void K_drawLapStartAnim(void) { // This is an EVEN MORE insanely complicated animation. - const UINT8 progress = 80-stplyr->kartstuff[k_lapanimation]; + const UINT8 progress = 80-stplyr->karthud[khud_lapanimation]; UINT8 *colormap = R_GetTranslationColormap(TC_DEFAULT, stplyr->skincolor, GTC_CACHE); - V_DrawFixedPatch((BASEVIDWIDTH/2 + (32*max(0, stplyr->kartstuff[k_lapanimation]-76)))*FRACUNIT, + V_DrawFixedPatch((BASEVIDWIDTH/2 + (32*max(0, stplyr->karthud[khud_lapanimation]-76)))*FRACUNIT, (48 - (32*max(0, progress-76)))*FRACUNIT, FRACUNIT, V_SNAPTOTOP|V_HUDTRANS, (modeattacking ? kp_lapanim_emblem[1] : kp_lapanim_emblem[0]), colormap); - if (stplyr->kartstuff[k_laphand] >= 1 && stplyr->kartstuff[k_laphand] <= 3) + if (stplyr->karthud[khud_laphand] >= 1 && stplyr->karthud[khud_laphand] <= 3) { - V_DrawFixedPatch((BASEVIDWIDTH/2 + (32*max(0, stplyr->kartstuff[k_lapanimation]-76)))*FRACUNIT, + V_DrawFixedPatch((BASEVIDWIDTH/2 + (32*max(0, stplyr->karthud[khud_lapanimation]-76)))*FRACUNIT, (48 - (32*max(0, progress-76)) + 4 - abs((signed)((leveltime % 8) - 4)))*FRACUNIT, FRACUNIT, V_SNAPTOTOP|V_HUDTRANS, - kp_lapanim_hand[stplyr->kartstuff[k_laphand]-1], NULL); + kp_lapanim_hand[stplyr->karthud[khud_laphand]-1], NULL); } if (stplyr->laps == (UINT8)(cv_numlaps.value - 1)) @@ -8629,6 +9554,7 @@ static void K_drawLapStartAnim(void) void K_drawKartFreePlay(UINT32 flashtime) { // no splitscreen support because it's not FREE PLAY if you have more than one player in-game + // (you fool, you can take splitscreen online. :V) if ((flashtime % TICRATE) < TICRATE/2) return; @@ -8656,6 +9582,7 @@ static void K_drawDistributionDebugger(void) kp_thundershield[1], kp_hyudoro[1], kp_pogospring[1], + kp_superring[1], kp_kitchensink[1], kp_sneaker[1], @@ -8667,9 +9594,9 @@ static void K_drawDistributionDebugger(void) }; INT32 useodds = 0; INT32 pingame = 0, bestbumper = 0; + INT32 pdis = 0; INT32 i; INT32 x = -9, y = -9; - boolean dontforcespb = false; boolean spbrush = false; if (stplyr != &players[displayplayers[0]]) // only for p1 @@ -8681,16 +9608,34 @@ static void K_drawDistributionDebugger(void) if (!playeringame[i] || players[i].spectator) continue; pingame++; - if (players[i].exiting) - dontforcespb = true; if (players[i].kartstuff[k_bumper] > bestbumper) bestbumper = players[i].kartstuff[k_bumper]; } - if (G_RaceGametype()) - spbrush = (spbplace != -1 && stplyr->kartstuff[k_position] == spbplace+1); + // lovely double loop...... + for (i = 0; i < MAXPLAYERS; i++) + { + if (playeringame[i] && !players[i].spectator && players[i].mo + && players[i].kartstuff[k_position] < stplyr->kartstuff[k_position]) + pdis += P_AproxDistance(P_AproxDistance(players[i].mo->x - stplyr->mo->x, + players[i].mo->y - stplyr->mo->y), + players[i].mo->z - stplyr->mo->z) / mapobjectscale + * (pingame - players[i].kartstuff[k_position]) + / max(1, ((pingame - 1) * (pingame + 1) / 3)); + } - useodds = K_FindUseodds(stplyr, 0, pingame, bestbumper, spbrush, dontforcespb); + if (franticitems) // Frantic items make the distances between everyone artifically higher, for crazier items + pdis = (15 * pdis) / 14; + + if (spbplace != -1 && stplyr->kartstuff[k_position] == spbplace+1) // SPB Rush Mode: It's 2nd place's job to catch-up items and make 1st place's job hell + { + pdis = (3 * pdis) / 2; + spbrush = true; + } + + pdis = ((28 + (8-pingame)) * pdis) / 28; // scale with player count + + useodds = K_FindUseodds(stplyr, 0, pdis, bestbumper, spbrush); for (i = 1; i < NUMKARTRESULTS; i++) { @@ -8837,6 +9782,15 @@ void K_drawKartHUD(void) if (!stplyr->spectator) // Bottom of the screen elements, don't need in spectate mode { + // Draw the speedometer + if (cv_kartspeedometer.value && !splitscreen) + { +#ifdef HAVE_BLUA + if (LUA_HudEnabled(hud_speedometer)) +#endif + K_drawKartSpeedometer(); + } + if (demo.title) // Draw title logo instead in demo.titles { INT32 x = BASEVIDWIDTH - 32, y = 128, offs; @@ -8865,17 +9819,7 @@ void K_drawKartHUD(void) #ifdef HAVE_BLUA if (LUA_HudEnabled(hud_gametypeinfo)) #endif - K_drawKartLaps(); - - if (!splitscreen) - { - // Draw the speedometer - // TODO: Make a better speedometer. -#ifdef HAVE_BLUA - if (LUA_HudEnabled(hud_speedometer)) -#endif - K_drawKartSpeedometer(); - } + K_drawKartLapsAndRings(); if (isfreeplay) ; @@ -8928,14 +9872,14 @@ void K_drawKartHUD(void) { if (stplyr->exiting) K_drawKartFinish(); - else if (stplyr->kartstuff[k_lapanimation] && !splitscreen) + else if (stplyr->karthud[khud_lapanimation] && !splitscreen) K_drawLapStartAnim(); } if (modeattacking) // everything after here is MP and debug only return; - if (G_BattleGametype() && !splitscreen && (stplyr->kartstuff[k_yougotem] % 2)) // * YOU GOT EM * + if (G_BattleGametype() && !splitscreen && (stplyr->karthud[khud_yougotem] % 2)) // * YOU GOT EM * V_DrawScaledPatch(BASEVIDWIDTH/2 - (SHORT(kp_yougotem->width)/2), 32, V_HUDTRANS, kp_yougotem); // Draw FREE PLAY. diff --git a/src/k_kart.h b/src/k_kart.h index 2ba5d1bdc..b91e8c8a1 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -22,7 +22,9 @@ void K_RegisterKartStuff(void); boolean K_IsPlayerLosing(player_t *player); boolean K_IsPlayerWanted(player_t *player); +fixed_t K_GetKartGameSpeedScalar(SINT8 value); void K_KartBouncing(mobj_t *mobj1, mobj_t *mobj2, boolean bounce, boolean solid); +void K_KartPainEnergyFling(player_t *player); void K_FlipFromObject(mobj_t *mo, mobj_t *master); void K_MatchGenericExtraFlags(mobj_t *mo, mobj_t *master); void K_RespawnChecker(player_t *player); @@ -41,6 +43,7 @@ void K_SpawnMineExplosion(mobj_t *source, UINT8 color); void K_SpawnBoostTrail(player_t *player); void K_SpawnSparkleTrail(mobj_t *mo); void K_SpawnWipeoutTrail(mobj_t *mo, boolean translucent); +void K_SpawnDraftDust(mobj_t *mo); void K_DriftDustHandling(mobj_t *spawner); void K_PuntMine(mobj_t *mine, mobj_t *punter); void K_DoSneaker(player_t *player, INT32 type); @@ -71,6 +74,7 @@ void K_CheckSpectateStatus(void); void K_PlayAttackTaunt(mobj_t *source); void K_PlayBoostTaunt(mobj_t *source); void K_PlayOvertakeSound(mobj_t *source); +void K_PlayPainSound(mobj_t *source); void K_PlayHitEmSound(mobj_t *source); void K_PlayPowerGloatSound(mobj_t *source); diff --git a/src/lua_baselib.c b/src/lua_baselib.c index 6700d5af8..38af4d2e9 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -1166,37 +1166,6 @@ static int lib_pPlayerRingBurst(lua_State *L) return 0; } -static int lib_pPlayerWeaponPanelBurst(lua_State *L) -{ - player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER)); - NOHUD - if (!player) - return LUA_ErrInvalid(L, "player_t"); - P_PlayerWeaponPanelBurst(player); - return 0; -} - -static int lib_pPlayerWeaponAmmoBurst(lua_State *L) -{ - player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER)); - NOHUD - if (!player) - return LUA_ErrInvalid(L, "player_t"); - P_PlayerWeaponAmmoBurst(player); - return 0; -} - -static int lib_pPlayerEmeraldBurst(lua_State *L) -{ - player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER)); - boolean toss = lua_optboolean(L, 2); - NOHUD - if (!player) - return LUA_ErrInvalid(L, "player_t"); - P_PlayerEmeraldBurst(player, toss); - return 0; -} - static int lib_pPlayerFlagBurst(lua_State *L) { player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER)); @@ -2229,6 +2198,16 @@ static int lib_kOvertakeSound(lua_State *L) return 0; } +static int lib_kPainSound(lua_State *L) +{ + mobj_t *mobj = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)); + NOHUD + if (!mobj->player) + return luaL_error(L, "K_PlayPainSound: mobj_t isn't a player object."); //Nothing bad would happen if we let it run the func, but telling why it ain't doing anything is helpful. + K_PlayPainSound(mobj); + return 0; +} + static int lib_kHitEmSound(lua_State *L) { mobj_t *mobj = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)); @@ -2744,9 +2723,6 @@ static luaL_Reg lib[] = { {"P_DamageMobj",lib_pDamageMobj}, {"P_KillMobj",lib_pKillMobj}, {"P_PlayerRingBurst",lib_pPlayerRingBurst}, - {"P_PlayerWeaponPanelBurst",lib_pPlayerWeaponPanelBurst}, - {"P_PlayerWeaponAmmoBurst",lib_pPlayerWeaponAmmoBurst}, - {"P_PlayerEmeraldBurst",lib_pPlayerEmeraldBurst}, {"P_PlayerFlagBurst",lib_pPlayerFlagBurst}, {"P_PlayRinglossSound",lib_pPlayRinglossSound}, {"P_PlayDeathSound",lib_pPlayDeathSound}, @@ -2835,6 +2811,7 @@ static luaL_Reg lib[] = { {"K_PlayPowerGloatSound", lib_kGloatSound}, {"K_PlayOvertakeSound", lib_kOvertakeSound}, {"K_PlayLossSound", lib_kLossSound}, + {"K_PlayPainSound", lib_kPainSound}, {"K_PlayHitEmSound", lib_kHitEmSound}, {"K_GetKartColorByName",lib_kGetKartColorByName}, {"K_IsPlayerLosing",lib_kIsPlayerLosing}, diff --git a/src/lua_hudlib.c b/src/lua_hudlib.c index 22c89a234..ec76552d1 100644 --- a/src/lua_hudlib.c +++ b/src/lua_hudlib.c @@ -618,26 +618,26 @@ static int libd_drawFill(lua_State *L) static int libd_fadeScreen(lua_State *L) { - UINT16 color = luaL_checkinteger(L, 1); - UINT8 strength = luaL_checkinteger(L, 2); - const UINT8 maxstrength = ((color & 0xFF00) ? 32 : 10); + UINT16 color = luaL_checkinteger(L, 1); + UINT8 strength = luaL_checkinteger(L, 2); + const UINT8 maxstrength = ((color & 0xFF00) ? 32 : 10); - HUDONLY + HUDONLY - if (!strength) - return 0; + if (!strength) + return 0; - if (strength > maxstrength) - return luaL_error(L, "%s fade strength %d out of range (0 - %d)", ((color & 0xFF00) ? "COLORMAP" : "TRANSMAP"), strength, maxstrength); + if (strength > maxstrength) + return luaL_error(L, "%s fade strength %d out of range (0 - %d)", ((color & 0xFF00) ? "COLORMAP" : "TRANSMAP"), strength, maxstrength); - if (strength == maxstrength) // Allow as a shortcut for drawfill... - { - V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, ((color & 0xFF00) ? 31 : color)); - return 0; - } + if (strength == maxstrength) // Allow as a shortcut for drawfill... + { + V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, ((color & 0xFF00) ? 31 : color)); + return 0; + } - V_DrawFadeScreen(color, strength); - return 0; + V_DrawFadeScreen(color, strength); + return 0; } static int libd_drawString(lua_State *L) diff --git a/src/m_menu.c b/src/m_menu.c index 9b5e98e44..01cfabac6 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -1562,7 +1562,7 @@ static menuitem_t OP_AdvServerOptionsMenu[] = {IT_STRING | IT_CVAR, NULL, "Karma Comeback", &cv_kartcomeback, 66}, };*/ -#define ITEMTOGGLEBOTTOMRIGHT +//#define ITEMTOGGLEBOTTOMRIGHT static menuitem_t OP_MonitorToggleMenu[] = { @@ -1590,6 +1590,7 @@ static menuitem_t OP_MonitorToggleMenu[] = {IT_KEYHANDLER | IT_NOTHING, NULL, "Thunder Shields", M_HandleMonitorToggles, KITEM_THUNDERSHIELD}, {IT_KEYHANDLER | IT_NOTHING, NULL, "Hyudoros", M_HandleMonitorToggles, KITEM_HYUDORO}, {IT_KEYHANDLER | IT_NOTHING, NULL, "Pogo Springs", M_HandleMonitorToggles, KITEM_POGOSPRING}, + {IT_KEYHANDLER | IT_NOTHING, NULL, "Super Rings", M_HandleMonitorToggles, KITEM_SUPERRING}, {IT_KEYHANDLER | IT_NOTHING, NULL, "Kitchen Sinks", M_HandleMonitorToggles, KITEM_KITCHENSINK}, #ifdef ITEMTOGGLEBOTTOMRIGHT {IT_KEYHANDLER | IT_NOTHING, NULL, "---", M_HandleMonitorToggles, 255}, @@ -3516,7 +3517,7 @@ static void M_DrawSlider(INT32 x, INT32 y, const consvar_t *cv, boolean ontop) void M_DrawTextBox(INT32 x, INT32 y, INT32 width, INT32 boxlines) { // Solid color textbox. - V_DrawFill(x+5, y+5, width*8+6, boxlines*8+6, 239); + V_DrawFill(x+5, y+5, width*8+6, boxlines*8+6, 159); //V_DrawFill(x+8, y+8, width*8, boxlines*8, 31); /* patch_t *p; @@ -4675,10 +4676,10 @@ static void M_DrawTemperature(INT32 x, fixed_t t) t = (FixedMul(h<>FRACBITS); // border - V_DrawFill(x - 1, vpadding, 1, h, 120); - V_DrawFill(x + width, vpadding, 1, h, 120); - V_DrawFill(x - 1, vpadding-1, width+2, 1, 120); - V_DrawFill(x - 1, vpadding+h, width+2, 1, 120); + V_DrawFill(x - 1, vpadding, 1, h, 0); + V_DrawFill(x + width, vpadding, 1, h, 0); + V_DrawFill(x - 1, vpadding-1, width+2, 1, 0); + V_DrawFill(x - 1, vpadding+h, width+2, 1, 0); // bar itself y = h; @@ -4829,14 +4830,14 @@ static void M_DrawAddons(void) x = currentMenu->x; y = currentMenu->y + 1; - hilicol = V_GetStringColormap(highlightflags)[120]; + hilicol = V_GetStringColormap(highlightflags)[0]; V_DrawString(x-21, (y - 16) + (lsheadingheight - 12), highlightflags|V_ALLOWLOWERCASE, M_AddonsHeaderPath()); V_DrawFill(x-21, (y - 16) + (lsheadingheight - 3), MAXSTRINGLENGTH*8+6, 1, hilicol); V_DrawFill(x-21, (y - 16) + (lsheadingheight - 2), MAXSTRINGLENGTH*8+6, 1, 30); m = (BASEVIDHEIGHT - currentMenu->y + 2) - (y - 1); - V_DrawFill(x - 21, y - 1, MAXSTRINGLENGTH*8+6, m, 239); + V_DrawFill(x - 21, y - 1, MAXSTRINGLENGTH*8+6, m, 159); // scrollbar! if (sizedirmenu <= (2*numaddonsshown + 1)) @@ -5562,8 +5563,8 @@ static void M_DrawReplayHut(void) y = sizedirmenu*10 + currentMenu->menuitems[replaylistitem].alphaKey + 30; if (y > SCALEDVIEWHEIGHT-80) { - V_DrawFill(BASEVIDWIDTH-4, 75, 4, SCALEDVIEWHEIGHT-80, V_SNAPTOTOP|V_SNAPTORIGHT|239); - V_DrawFill(BASEVIDWIDTH-3, 76 + (SCALEDVIEWHEIGHT-80) * replayhutmenuy / y, 2, (((SCALEDVIEWHEIGHT-80) * (SCALEDVIEWHEIGHT-80))-1) / y - 1, V_SNAPTOTOP|V_SNAPTORIGHT|229); + V_DrawFill(BASEVIDWIDTH-4, 75, 4, SCALEDVIEWHEIGHT-80, V_SNAPTOTOP|V_SNAPTORIGHT|159); + V_DrawFill(BASEVIDWIDTH-3, 76 + (SCALEDVIEWHEIGHT-80) * replayhutmenuy / y, 2, (((SCALEDVIEWHEIGHT-80) * (SCALEDVIEWHEIGHT-80))-1) / y - 1, V_SNAPTOTOP|V_SNAPTORIGHT|149); } // Draw the cursor @@ -5572,7 +5573,7 @@ static void M_DrawReplayHut(void) V_DrawString(currentMenu->x, cursory, V_SNAPTOTOP|V_SNAPTOLEFT|highlightflags, currentMenu->menuitems[itemOn].text); // Now draw some replay info! - V_DrawFill(10, 10, 300, 60, V_SNAPTOTOP|239); + V_DrawFill(10, 10, 300, 60, V_SNAPTOTOP|159); if (itemOn == replaylistitem) { @@ -5654,7 +5655,7 @@ static void M_DrawReplayStartMenu(void) } } - V_DrawFill(10, 10, 300, 60, V_SNAPTOTOP|239); + V_DrawFill(10, 10, 300, 60, V_SNAPTOTOP|159); DrawReplayHutReplayInfo(); V_DrawString(10, 72, V_SNAPTOTOP|highlightflags|V_ALLOWLOWERCASE, demolist[dir_on[menudepthleft]].title); @@ -7583,7 +7584,7 @@ void M_DrawTimeAttackMenu(void) time = mainrecords[cv_nextmap.value-1]->time; } - V_DrawFill((BASEVIDWIDTH - dupadjust)>>1, 78, dupadjust, 36, 239); + V_DrawFill((BASEVIDWIDTH - dupadjust)>>1, 78, dupadjust, 36, 159); V_DrawRightAlignedString(149, 80, highlightflags, "BEST LAP:"); K_drawKartTimestamp(lap, 19, 86, 0, 2); @@ -8630,7 +8631,7 @@ static void M_DrawLevelSelectOnly(boolean leftfade, boolean rightfade) y = currentMenu->y + 130 + 8 - i; if (currentMenu->menuitems[itemOn].itemaction == &cv_nextmap && skullAnimCounter < 4) - trans = 120; + trans = 0; else trans = G_GetGametypeColor(cv_newgametype.value); @@ -8822,7 +8823,7 @@ Update the maxplayers label... #ifndef NONET y += MP_MainMenu[8].alphaKey; - V_DrawFill(x+5, y+4+5, /*16*8 + 6,*/ BASEVIDWIDTH - 2*(x+5), 8+6, 239); + V_DrawFill(x+5, y+4+5, /*16*8 + 6,*/ BASEVIDWIDTH - 2*(x+5), 8+6, 159); // draw name string V_DrawString(x+8,y+12, V_ALLOWLOWERCASE, setupm_ip); @@ -9296,7 +9297,7 @@ static void M_DrawSetupMultiPlayerMenu(void) flags |= V_FLIP; // This sprite is left/right flipped! // draw box around guy - V_DrawFill(mx + 43 - (charw/2), my+65, charw, 84, 239); + V_DrawFill(mx + 43 - (charw/2), my+65, charw, 84, 159); // draw player sprite if (setupm_fakecolor) // inverse should never happen @@ -10627,6 +10628,7 @@ static consvar_t *kartitemcvs[NUMKARTRESULTS-1] = { &cv_thundershield, &cv_hyudoro, &cv_pogospring, + &cv_superring, &cv_kitchensink, &cv_triplesneaker, &cv_triplebanana, diff --git a/src/p_enemy.c b/src/p_enemy.c index 1795a304b..7baca2adc 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -710,59 +710,6 @@ boolean P_LookForPlayers(mobj_t *actor, boolean allaround, boolean tracer, fixed //return false; } -/** Looks for a player with a ring shield. - * Used by rings. - * - * \param actor Ring looking for a shield to be attracted to. - * \return True if a player with ring shield is found, otherwise false. - * \sa A_AttractChase - */ -static boolean P_LookForShield(mobj_t *actor) -{ - INT32 c = 0, stop; - player_t *player; - - // BP: first time init, this allow minimum lastlook changes - if (actor->lastlook < 0) - actor->lastlook = P_RandomByte(); - - actor->lastlook %= MAXPLAYERS; - - stop = (actor->lastlook - 1) & PLAYERSMASK; - - for (; ; actor->lastlook = ((actor->lastlook + 1) & PLAYERSMASK)) - { - // done looking - if (actor->lastlook == stop) - return false; - - if (!playeringame[actor->lastlook]) - continue; - - if (c++ == 2) - return false; - - player = &players[actor->lastlook]; - - if (player->health <= 0 || !player->mo) - continue; // dead - - //When in CTF, don't pull rings that you cannot pick up. - if ((actor->type == MT_REDTEAMRING && player->ctfteam != 1) || - (actor->type == MT_BLUETEAMRING && player->ctfteam != 2)) - continue; - - if ((player->powers[pw_shield] & SH_NOSTACK) == SH_ATTRACT - && (P_AproxDistance(P_AproxDistance(actor->x-player->mo->x, actor->y-player->mo->y), actor->z-player->mo->z) < FixedMul(RING_DIST/4, player->mo->scale))) - { - P_SetTarget(&actor->tracer, player->mo); - return true; - } - } - - //return false; -} - #ifdef WEIGHTEDRECYCLER // Compares players to see who currently has the "best" items, etc. static int P_RecycleCompare(const void *p1, const void *p2) @@ -3615,57 +3562,163 @@ void A_AttractChase(mobj_t *actor) if (LUA_CallAction("A_AttractChase", actor)) return; #endif + if (actor->flags2 & MF2_NIGHTSPULL || !actor->health) return; - // spilled rings flicker before disappearing - if (leveltime & 1 && actor->type == (mobjtype_t)actor->info->reactiontime && actor->fuse && actor->fuse < 2*TICRATE) - actor->flags2 |= MF2_DONTDRAW; + if (actor->extravalue1) // SRB2Kart + { +#define RINGBOOSTPWR (((9 - actor->target->player->kartspeed) + (9 - actor->target->player->kartweight)) / 2) + if (!actor->target || P_MobjWasRemoved(actor->target) || !actor->target->player) + { + P_RemoveMobj(actor); + return; + } + + if (actor->extravalue2) // Using for ring boost + { + // Always fullbright + actor->frame |= FF_FULLBRIGHT; + + if (actor->extravalue1 >= 21) + { + mobj_t *sparkle; + angle_t offset = FixedAngle(18<target->player->kartstuff[k_ringboost] += RINGBOOSTPWR+3; + S_StartSound(actor->target, sfx_s1b5); + + sparkle = P_SpawnMobj(actor->target->x, actor->target->y, actor->target->z, MT_RINGSPARKS); + P_SetTarget(&sparkle->target, actor->target); + sparkle->angle = (actor->target->angle + (offset>>1)) + (offset * actor->target->player->kartstuff[k_sparkleanim]); + actor->target->player->kartstuff[k_sparkleanim] = (actor->target->player->kartstuff[k_sparkleanim]+1) % 20; + + P_KillMobj(actor, actor->target, actor->target); + return; + } + else + { + fixed_t offz = FixedMul(80*actor->target->scale, FINESINE(FixedAngle((90 - (9 * abs(10 - actor->extravalue1))) << FRACBITS) >> ANGLETOFINESHIFT)); + //P_SetScale(actor, (actor->destscale = actor->target->scale)); + P_TeleportMove(actor, actor->target->x, actor->target->y, actor->target->z + actor->target->height + offz); + actor->extravalue1++; + } + } + else // Collecting + { + if (actor->extravalue1 >= 16) + { + if (actor->target->player->kartstuff[k_rings] >= 20) + actor->target->player->kartstuff[k_ringboost] += RINGBOOSTPWR+3; + else + P_GivePlayerRings(actor->target->player, 1); + + if (actor->cvmem) // caching + S_StartSound(actor->target, sfx_s1c5); + else + S_StartSound(actor->target, sfx_s227); + + actor->target->player->kartstuff[k_pickuprings]--; + P_RemoveMobj(actor); + return; + } + else + { + fixed_t dist = (actor->target->radius/4) * (16 - actor->extravalue1); + + P_SetScale(actor, (actor->destscale = actor->target->scale - ((actor->target->scale/14) * actor->extravalue1))); + P_TeleportMove(actor, + actor->target->x + FixedMul(dist, FINECOSINE(actor->angle >> ANGLETOFINESHIFT)), + actor->target->y + FixedMul(dist, FINESINE(actor->angle >> ANGLETOFINESHIFT)), + actor->target->z + (24 * actor->target->scale)); + + actor->angle += ANG30; + actor->extravalue1++; + } + } +#undef RINGBOOSTPWR + } else - actor->flags2 &= ~MF2_DONTDRAW; - - // Turn flingrings back into regular rings if attracted. - if (actor->tracer && actor->tracer->player - && (actor->tracer->player->powers[pw_shield] & SH_NOSTACK) != SH_ATTRACT - && actor->info->reactiontime && actor->type != (mobjtype_t)actor->info->reactiontime) { - mobj_t *newring; - newring = P_SpawnMobj(actor->x, actor->y, actor->z, actor->info->reactiontime); - newring->momx = actor->momx; - newring->momy = actor->momy; - newring->momz = actor->momz; - P_RemoveMobj(actor); - return; + // Don't immediately pick up spilled rings + if (actor->threshold > 0) + actor->threshold--; + + // Rings flicker before disappearing + if (actor->fuse && actor->fuse < 5*TICRATE && (leveltime & 1)) + actor->flags2 |= MF2_DONTDRAW; + else + actor->flags2 &= ~MF2_DONTDRAW; + + // spilled rings have ghost trails and get capped to a certain speed + if (actor->type == (mobjtype_t)actor->info->reactiontime) + { + const fixed_t maxspeed = 4<momx, actor->momy); + + if (oldspeed > maxspeed) + { + fixed_t newspeed = max(maxspeed, oldspeed-FRACUNIT); + actor->momx = FixedMul(FixedDiv(actor->momx, oldspeed), newspeed); + actor->momy = FixedMul(FixedDiv(actor->momy, oldspeed), newspeed); + } + + if (!P_IsObjectOnGround(actor)) + P_SpawnGhostMobj(actor)->tics = 3; + } + + if (actor->tracer && actor->tracer->player && actor->tracer->health + //&& P_CheckSight(actor, actor->tracer) + && actor->tracer->player->kartstuff[k_itemtype] == KITEM_THUNDERSHIELD + && (actor->tracer->player->kartstuff[k_rings]+actor->tracer->player->kartstuff[k_pickuprings]) < 20 + && !actor->tracer->player->kartstuff[k_ringlock]) + { + fixed_t dist; + angle_t hang, vang; + + // If a flung ring gets attracted by a shield, change it into a normal ring. + if (actor->type == (mobjtype_t)actor->info->reactiontime) + { + P_SpawnMobj(actor->x, actor->y, actor->z, actor->info->painchance); + P_RemoveMobj(actor); + return; + } + + // Keep stuff from going down inside floors and junk + actor->flags &= ~MF_NOCLIPHEIGHT; + + // Let attracted rings move through walls and such. + actor->flags |= MF_NOCLIP; + + // P_Attract is too "smart" for Kart; keep it simple, stupid! + dist = P_AproxDistance(P_AproxDistance(actor->x - actor->tracer->x, actor->y - actor->tracer->y), actor->z - actor->tracer->z); + hang = R_PointToAngle2(actor->x, actor->y, actor->tracer->x, actor->tracer->y); + vang = R_PointToAngle2(actor->z , 0, actor->tracer->z, dist); + + actor->momx -= actor->momx>>4, actor->momy -= actor->momy>>4, actor->momz -= actor->momz>>4; + actor->momx += FixedMul(FINESINE(vang>>ANGLETOFINESHIFT), FixedMul(FINECOSINE(hang>>ANGLETOFINESHIFT), 4*actor->scale)); + actor->momy += FixedMul(FINESINE(vang>>ANGLETOFINESHIFT), FixedMul(FINESINE(hang>>ANGLETOFINESHIFT), 4*actor->scale)); + actor->momz += FixedMul(FINECOSINE(vang>>ANGLETOFINESHIFT), 4*actor->scale); + } + else + { + // Turn rings back into flung rings if lost + if (actor->cusval && actor->info->reactiontime && actor->type != (mobjtype_t)actor->info->reactiontime) + { + mobj_t *newring; + newring = P_SpawnMobj(actor->x, actor->y, actor->z, actor->info->reactiontime); + P_InstaThrust(newring, P_RandomRange(0,7) * ANGLE_45, 2<momz = 8<fuse = 120*TICRATE; + P_RemoveMobj(actor); + return; + } + /*else + P_LookForShield(actor);*/ + // SRB2Kart: now it's the PLAYER'S job to use the blockmap to find rings, not the ring's. + } } - - P_LookForShield(actor); // Go find 'em, boy! - - if (!actor->tracer - || !actor->tracer->player - || !actor->tracer->health - || !P_CheckSight(actor, actor->tracer)) // You have to be able to SEE it...sorta - { - // Lost attracted rings don't through walls anymore. - actor->flags &= ~MF_NOCLIP; - P_SetTarget(&actor->tracer, NULL); - return; - } - - // If a FlingRing gets attracted by a shield, change it into a normal ring. - if (actor->type == (mobjtype_t)actor->info->reactiontime) - { - P_SpawnMobj(actor->x, actor->y, actor->z, actor->info->painchance); - P_RemoveMobj(actor); - return; - } - - // Keep stuff from going down inside floors and junk - actor->flags &= ~MF_NOCLIPHEIGHT; - - // Let attracted rings move through walls and such. - actor->flags |= MF_NOCLIP; - - P_Attract(actor, actor->tracer, false); } // Function: A_DropMine @@ -8405,6 +8458,7 @@ void A_SPBChase(mobj_t *actor) fixed_t easiness = ((actor->tracer->player->kartspeed + (10-spark)) << FRACBITS) / 2; actor->lastlook = actor->tracer->player-players; // Save the player num for death scumming... + actor->tracer->player->kartstuff[k_ringlock] = 1; // set ring lock if (!P_IsObjectOnGround(actor->tracer) /*&& !actor->tracer->player->kartstuff[k_pogospring]*/) { @@ -8488,6 +8542,15 @@ void A_SPBChase(mobj_t *actor) actor->momy = cy + FixedMul(FixedMul(xyspeed, FINESINE(actor->angle>>ANGLETOFINESHIFT)), FINECOSINE(actor->movedir>>ANGLETOFINESHIFT)); actor->momz = FixedMul(zspeed, FINESINE(actor->movedir>>ANGLETOFINESHIFT)); + // Spawn a trail of rings behind the SPB! + if (leveltime % 6 == 0) + { + mobj_t *ring = P_SpawnMobj(actor->x - actor->momx, actor->y - actor->momx, + actor->z - actor->momz + (24*mapobjectscale), MT_RING); + ring->threshold = 10; + ring->fuse = 120*TICRATE; + } + // Red speed lines for when it's gaining on its target. A tell for when you're starting to lose too much speed! if (R_PointToDist2(0, 0, actor->momx, actor->momy) > (actor->tracer->player ? (16*actor->tracer->player->speed)/15 : (16*R_PointToDist2(0, 0, actor->tracer->momx, actor->tracer->momy))/15) // Going faster than the target @@ -8529,6 +8592,7 @@ void A_SPBChase(mobj_t *actor) && !players[actor->lastlook].exiting) { spbplace = players[actor->lastlook].kartstuff[k_position]; + players[actor->lastlook].kartstuff[k_ringlock] = 1; if (actor->extravalue2-- <= 0 && players[actor->lastlook].mo) { P_SetTarget(&actor->tracer, players[actor->lastlook].mo); diff --git a/src/p_inter.c b/src/p_inter.c index a910445da..de14b3db9 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -116,7 +116,7 @@ boolean P_CanPickupItem(player_t *player, UINT8 weapon) { // Invulnerable if (player->powers[pw_flashing] > 0 - || player->kartstuff[k_spinouttimer] > 0 + || (player->kartstuff[k_spinouttimer] > 0 && player->kartstuff[k_spinouttype] != 2) || player->kartstuff[k_squishedtimer] > 0 || player->kartstuff[k_invincibilitytimer] > 0 || player->kartstuff[k_growshrinktimer] > 0 @@ -494,7 +494,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) special->target->player->kartstuff[k_comebackpoints] += ptadd; if (ptadd > 1) - special->target->player->kartstuff[k_yougotem] = 2*TICRATE; + special->target->player->karthud[khud_yougotem] = 2*TICRATE; if (special->target->player->kartstuff[k_comebackpoints] >= 2) K_StealBumper(special->target->player, player, true); @@ -557,7 +557,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) special->target->player->kartstuff[k_comebackpoints] += ptadd; if (ptadd > 1) - special->target->player->kartstuff[k_yougotem] = 2*TICRATE; + special->target->player->karthud[khud_yougotem] = 2*TICRATE; if (special->target->player->kartstuff[k_comebackpoints] >= 2) K_StealBumper(special->target->player, player, true); @@ -687,15 +687,34 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) /* FALLTHRU */ case MT_RING: case MT_FLINGRING: + if (special->extravalue1) + return; + + // No picking up rings while SPB is targetting you + if (player->kartstuff[k_ringlock]) + return; + + // Don't immediately pick up spilled rings + if (special->threshold > 0 + || player->kartstuff[k_squishedtimer] + || player->kartstuff[k_spinouttimer]) + return; + if (!(P_CanPickupItem(player, 0))) return; - special->momx = special->momy = special->momz = 0; - P_GivePlayerRings(player, 1); + // Reached the cap, don't waste 'em! + if ((player->kartstuff[k_rings] + player->kartstuff[k_pickuprings]) >= 20) + return; - if ((maptol & TOL_NIGHTS) && special->type != MT_FLINGRING) - P_DoNightsScore(player); - break; + special->momx = special->momy = special->momz = 0; + + special->extravalue1 = 1; // Ring collect animation timer + special->angle = R_PointToAngle2(toucher->x, toucher->y, special->x, special->y); // animation angle + P_SetTarget(&special->target, toucher); // toucher for thinker + player->kartstuff[k_pickuprings]++; + + return; case MT_COIN: case MT_FLINGCOIN: @@ -2819,16 +2838,8 @@ static inline boolean P_TagDamage(mobj_t *target, mobj_t *inflictor, mobj_t *sou return true; } - if (target->health <= 1) // Death - { - P_PlayDeathSound(target); - P_PlayVictorySound(source); // Killer laughs at you! LAUGHS! BWAHAHAHHAHAA!! - } - else if (target->health > 1) // Ring loss - { - P_PlayRinglossSound(target); - P_PlayerRingBurst(player, player->mo->health - 1); - } + P_PlayRinglossSound(target); + P_PlayerRingBurst(player, 5); if (inflictor && ((inflictor->flags & MF_MISSILE) || inflictor->player) && player->powers[pw_super] && ALL7EMERALDS(player->powers[pw_emeralds])) { @@ -2884,14 +2895,9 @@ static inline boolean P_PlayerHitsPlayer(mobj_t *target, mobj_t *inflictor, mobj static void P_KillPlayer(player_t *player, mobj_t *source, INT32 damage) { - player->pflags &= ~(PF_CARRIED|PF_SLIDING|PF_ITEMHANG|PF_MACESPIN|PF_ROPEHANG|PF_NIGHTSMODE); + (void)source; - // Burst weapons and emeralds in Match/CTF only - if (source && (G_BattleGametype())) - { - P_PlayerRingBurst(player, player->health - 1); - P_PlayerEmeraldBurst(player, false); - } + player->pflags &= ~(PF_CARRIED|PF_SLIDING|PF_ITEMHANG|PF_MACESPIN|PF_ROPEHANG|PF_NIGHTSMODE); // Get rid of shield player->powers[pw_shield] = SH_NONE; @@ -2907,32 +2913,6 @@ static void P_KillPlayer(player_t *player, mobj_t *source, INT32 damage) P_SetPlayerMobjState(player->mo, player->mo->info->deathstate); - /*if (gametype == GT_CTF && (player->gotflag & (GF_REDFLAG|GF_BLUEFLAG))) - { - P_PlayerFlagBurst(player, false); - if (source && source->player) - { - // Award no points when players shoot each other when cv_friendlyfire is on. - if (!G_GametypeHasTeams() || !(source->player->ctfteam == player->ctfteam && source != player->mo)) - P_AddPlayerScore(source->player, 1); - } - } - if (source && source->player && !player->powers[pw_super]) //don't score points against super players - { - // Award no points when players shoot each other when cv_friendlyfire is on. - if (!G_GametypeHasTeams() || !(source->player->ctfteam == player->ctfteam && source != player->mo)) - P_AddPlayerScore(source->player, 1); - } - - // If the player was super, tell them he/she ain't so super nomore. - if (gametype != GT_COOP && player->powers[pw_super]) - { - S_StartSound(NULL, sfx_s3k66); //let all players hear it. - HU_SetCEchoFlags(0); - HU_SetCEchoDuration(5); - HU_DoCEcho(va("%s\\is no longer super.\\\\\\\\", player_names[player-players])); - }*/ - if (player->pflags & PF_TIMEOVER) { mobj_t *boom; @@ -2993,75 +2973,6 @@ void P_RemoveShield(player_t *player) player->powers[pw_shield] = player->powers[pw_shield] & SH_STACK; } -/* -static void P_ShieldDamage(player_t *player, mobj_t *inflictor, mobj_t *source, INT32 damage) // SRB2kart - unused. -{ - // Must do pain first to set flashing -- P_RemoveShield can cause damage - P_DoPlayerPain(player, source, inflictor); - - P_RemoveShield(player); - - P_ForceFeed(player, 40, 10, TICRATE, 40 + min(damage, 100)*2); - - if (source && (source->type == MT_SPIKE || (source->type == MT_NULL && source->threshold == 43))) // spikes - S_StartSound(player->mo, sfx_spkdth); - else - S_StartSound (player->mo, sfx_shldls); // Ba-Dum! Shield loss. - - if (gametype == GT_CTF && (player->gotflag & (GF_REDFLAG|GF_BLUEFLAG))) - { - P_PlayerFlagBurst(player, false); - if (source && source->player) - { - // Award no points when players shoot each other when cv_friendlyfire is on. - if (!G_GametypeHasTeams() || !(source->player->ctfteam == player->ctfteam && source != player->mo)) - P_AddPlayerScore(source->player, 25); - } - } - if (source && source->player && !player->powers[pw_super]) //don't score points against super players - { - // Award no points when players shoot each other when cv_friendlyfire is on. - if (!G_GametypeHasTeams() || !(source->player->ctfteam == player->ctfteam && source != player->mo)) - P_AddPlayerScore(source->player, cv_match_scoring.value == 1 ? 25 : 50); - } -} -*/ - -static void P_RingDamage(player_t *player, mobj_t *inflictor, mobj_t *source, INT32 damage) -{ - //const UINT8 scoremultiply = ((K_IsWantedPlayer(player) && !trapitem) : 2 ? 1); - - if (!(inflictor && ((inflictor->flags & MF_MISSILE) || inflictor->player) && player->powers[pw_super] && ALL7EMERALDS(player->powers[pw_emeralds]))) - { - P_DoPlayerPain(player, source, inflictor); - - P_ForceFeed(player, 40, 10, TICRATE, 40 + min(damage, 100)*2); - - if (source && (source->type == MT_SPIKE || (source->type == MT_NULL && source->threshold == 43))) // spikes - S_StartSound(player->mo, sfx_spkdth); - } - - /*if (source && source->player && !player->powers[pw_super]) //don't score points against super players - { - // Award no points when players shoot each other when cv_friendlyfire is on. - if (!G_GametypeHasTeams() || !(source->player->ctfteam == player->ctfteam && source != player->mo)) - P_AddPlayerScore(source->player, scoremultiply); - } - - if (gametype == GT_CTF && (player->gotflag & (GF_REDFLAG|GF_BLUEFLAG))) - { - P_PlayerFlagBurst(player, false); - if (source && source->player) - { - // Award no points when players shoot each other when cv_friendlyfire is on. - if (!G_GametypeHasTeams() || !(source->player->ctfteam == player->ctfteam && source != player->mo)) - P_AddPlayerScore(source->player, scoremultiply); - } - }*/ - - // Ring loss sound plays despite hitting spikes - P_PlayRinglossSound(player->mo); // Ringledingle! -} /** Damages an object, which may or may not be a player. * For melee attacks, source and inflictor are the same. @@ -3279,121 +3190,21 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da || inflictor->type == MT_SMK_THWOMP || inflictor->player)) { player->kartstuff[k_sneakertimer] = 0; + K_SpinPlayer(player, source, 1, inflictor, false); - damage = player->mo->health - 1; - P_RingDamage(player, inflictor, source, damage); - P_PlayerRingBurst(player, 5); - if (P_IsLocalPlayer(player)) + K_KartPainEnergyFling(player); + + if (P_IsDisplayPlayer(player)) { quake.intensity = 32*FRACUNIT; quake.time = 5; } } else - { K_SpinPlayer(player, source, 0, inflictor, false); - } + return true; } - /* // SRB2kart - don't need these - else if (metalrecording) - { - if (!inflictor) - inflictor = source; - if (inflictor && inflictor->flags & MF_ENEMY) - { // Metal Sonic destroy enemy !! - P_KillMobj(inflictor, NULL, target); - return false; - } - else if (inflictor && inflictor->flags & MF_MISSILE) - return false; // Metal Sonic walk through flame !! - else - { // Oh no! Metal Sonic is hit !! - P_ShieldDamage(player, inflictor, source, damage); - return true; - } - } - else if (player->powers[pw_invulnerability] || player->powers[pw_flashing] // ignore bouncing & such in invulnerability - || (player->powers[pw_super] && !(ALL7EMERALDS(player->powers[pw_emeralds]) && inflictor && ((inflictor->flags & MF_MISSILE) || inflictor->player)))) - { - if (force || (inflictor && (inflictor->flags & MF_MISSILE) - && (inflictor->flags2 & MF2_SUPERFIRE) - && player->powers[pw_super])) - { -#ifdef HAVE_BLUA - if (!LUAh_MobjDamage(target, inflictor, source, damage)) -#endif - P_SuperDamage(player, inflictor, source, damage); - return true; - } - else - return false; - } -#ifdef HAVE_BLUA - else if (LUAh_MobjDamage(target, inflictor, source, damage)) - return true; -#endif - else if (!player->powers[pw_super] && (player->powers[pw_shield] || player->bot)) //If One-Hit Shield - { - P_ShieldDamage(player, inflictor, source, damage); - damage = 0; - } - else if (player->mo->health > 1) // No shield but have rings. - { - damage = player->mo->health - 1; - P_RingDamage(player, inflictor, source, damage); - } - else // No shield, no rings, no invincibility. - { - // To reduce griefing potential, don't allow players to be killed - // by friendly fire. Spilling their rings and other items is enough. - if (force || !(G_GametypeHasTeams() - && source && source->player && (source->player->ctfteam == player->ctfteam) - && cv_friendlyfire.value)) - { - damage = 1; - P_KillPlayer(player, source, damage); - } - else - { - damage = 0; - P_ShieldDamage(player, inflictor, source, damage); - } - } - */ - - if (inflictor && ((inflictor->flags & MF_MISSILE) || inflictor->player) && player->powers[pw_super] && ALL7EMERALDS(player->powers[pw_emeralds])) - { - if (player->powers[pw_shield]) - { - P_RemoveShield(player); - return true; - } - else - { - player->health -= (10 * (1 << (INT32)(player->powers[pw_super] / 10500))); - if (player->health < 2) - player->health = 2; - } - - if (gametype == GT_CTF && (player->gotflag & (GF_REDFLAG|GF_BLUEFLAG))) - P_PlayerFlagBurst(player, false); - } - else - { - player->health -= damage; // mirror mobj health here - if (damage < 10000) - { - target->player->powers[pw_flashing] = K_GetKartFlashing(target->player); - if (damage > 0) // don't spill emeralds/ammo/panels for shield damage - P_PlayerRingBurst(player, damage); - } - } - - if (player->health < 0) - player->health = 0; - - P_ForceFeed(player, 40, 10, TICRATE, 40 + min(damage, 100)*2); } // Killing dead. Just for kicks. @@ -3468,7 +3279,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da /** Spills an injured player's rings. * * \param player The player who is losing rings. - * \param num_rings Number of rings lost. A maximum of 32 rings will be + * \param num_rings Number of rings lost. A maximum of 20 rings will be * spawned. * \sa P_PlayerFlagBurst */ @@ -3479,32 +3290,38 @@ void P_PlayerRingBurst(player_t *player, INT32 num_rings) angle_t fa; fixed_t ns; fixed_t z; + fixed_t momxy = 5<mo->health <= 1) - num_rings = 5; + // Has a shield? Don't lose your rings! + if (player->kartstuff[k_itemtype] == KITEM_THUNDERSHIELD) + return; - if (num_rings > 32 && !(player->pflags & PF_NIGHTSFALL)) - num_rings = 32; + // 20 is the ring cap in kart + if (num_rings > 20) + num_rings = 20; + else if (num_rings <= 0) + return; - if (player->powers[pw_emeralds]) - P_PlayerEmeraldBurst(player, false); + // Cap the maximum loss automatically to 2 in ring debt + if (player->kartstuff[k_rings] <= 0 && num_rings > 2) + num_rings = 2; - // Spill weapons first - if (player->ringweapons) - P_PlayerWeaponPanelBurst(player); + P_GivePlayerRings(player, -num_rings); - // Spill the ammo - P_PlayerWeaponAmmoBurst(player); + // determine first angle + fa = player->mo->angle + ((P_RandomByte() & 1) ? -ANGLE_90 : ANGLE_90); - // There's no ring spilling in kart, so I'm hijacking this for the same thing as TD for (i = 0; i < num_rings; i++) { - INT32 objType = mobjinfo[MT_FLINGENERGY].reactiontime; + INT32 objType = mobjinfo[MT_RING].reactiontime; z = player->mo->z; if (player->mo->eflags & MFE_VERTICALFLIP) @@ -3512,379 +3329,34 @@ void P_PlayerRingBurst(player_t *player, INT32 num_rings) mo = P_SpawnMobj(player->mo->x, player->mo->y, z, objType); - mo->fuse = 8*TICRATE; + mo->threshold = 10; + mo->fuse = 120*TICRATE; P_SetTarget(&mo->target, player->mo); mo->destscale = player->mo->scale; P_SetScale(mo, player->mo->scale); - // Angle offset by player angle, then slightly offset by amount of rings - fa = ((i*FINEANGLES/16) + (player->mo->angle>>ANGLETOFINESHIFT) - ((num_rings-1)*FINEANGLES/32)) & FINEMASK; - - // Make rings spill out around the player in 16 directions like SA, but spill like Sonic 2. - // Technically a non-SA way of spilling rings. They just so happen to be a little similar. - if (player->pflags & PF_NIGHTSFALL) + // Angle / height offset changes every other ring + if (i != 0) { - ns = FixedMul(((i*FRACUNIT)/16)+2*FRACUNIT, mo->scale); - mo->momx = FixedMul(FINECOSINE(fa),ns); - - if (!(twodlevel || (player->mo->flags2 & MF2_TWOD))) - mo->momy = FixedMul(FINESINE(fa),ns); - - P_SetObjectMomZ(mo, 8*FRACUNIT, false); - mo->fuse = 20*TICRATE; // Adjust fuse for NiGHTS - } - else - { - fixed_t momxy, momz; // base horizonal/vertical thrusts - - if (i > 15) - { - momxy = 3*FRACUNIT; - momz = 4*FRACUNIT; - } - else - { - momxy = 28*FRACUNIT; - momz = 3*FRACUNIT; - } - - ns = FixedMul(momxy, mo->scale); - mo->momx = FixedMul(FINECOSINE(fa),ns); - - if (!(twodlevel || (player->mo->flags2 & MF2_TWOD))) - mo->momy = FixedMul(FINESINE(fa),ns); - - ns = momz; - P_SetObjectMomZ(mo, ns, false); - if (i & 1) - P_SetObjectMomZ(mo, ns, true); + { + momxy -= FRACUNIT; + momz += 2<scale); + mo->momx = (mo->target->momx/2) + FixedMul(FINECOSINE(fa>>ANGLETOFINESHIFT), ns); + mo->momy = (mo->target->momy/2) + FixedMul(FINESINE(fa>>ANGLETOFINESHIFT), ns); + + ns = FixedMul(momz, mo->scale); + P_SetObjectMomZ(mo, (mo->target->momz/2) + ns, false); + if (player->mo->eflags & MFE_VERTICALFLIP) mo->momz *= -1; } - - player->losstime += 10*TICRATE; - - if (P_IsObjectOnGround(player->mo)) - player->pflags &= ~PF_NIGHTSFALL; - - return; -} - -void P_PlayerWeaponPanelBurst(player_t *player) -{ - mobj_t *mo; - angle_t fa; - fixed_t ns; - INT32 i; - fixed_t z; - - INT32 num_weapons = M_CountBits((UINT32)player->ringweapons, NUM_WEAPONS-1); - UINT16 ammoamt = 0; - - for (i = 0; i < num_weapons; i++) - { - mobjtype_t weptype = 0; - powertype_t power = 0; - - if (player->ringweapons & RW_BOUNCE) // Bounce - { - weptype = MT_BOUNCEPICKUP; - player->ringweapons &= ~RW_BOUNCE; - power = pw_bouncering; - } - else if (player->ringweapons & RW_RAIL) // Rail - { - weptype = MT_RAILPICKUP; - player->ringweapons &= ~RW_RAIL; - power = pw_railring; - } - else if (player->ringweapons & RW_AUTO) // Auto - { - weptype = MT_AUTOPICKUP; - player->ringweapons &= ~RW_AUTO; - power = pw_automaticring; - } - else if (player->ringweapons & RW_EXPLODE) // Explode - { - weptype = MT_EXPLODEPICKUP; - player->ringweapons &= ~RW_EXPLODE; - power = pw_explosionring; - } - else if (player->ringweapons & RW_SCATTER) // Scatter - { - weptype = MT_SCATTERPICKUP; - player->ringweapons &= ~RW_SCATTER; - power = pw_scatterring; - } - else if (player->ringweapons & RW_GRENADE) // Grenade - { - weptype = MT_GRENADEPICKUP; - player->ringweapons &= ~RW_GRENADE; - power = pw_grenadering; - } - - if (!weptype) // ??? - continue; - - if (player->powers[power] >= mobjinfo[weptype].reactiontime) - ammoamt = (UINT16)mobjinfo[weptype].reactiontime; - else - ammoamt = player->powers[power]; - - player->powers[power] -= ammoamt; - - z = player->mo->z; - if (player->mo->eflags & MFE_VERTICALFLIP) - z += player->mo->height - mobjinfo[weptype].height; - - mo = P_SpawnMobj(player->mo->x, player->mo->y, z, weptype); - mo->reactiontime = ammoamt; - mo->flags2 |= MF2_DONTRESPAWN; - mo->flags &= ~(MF_NOGRAVITY|MF_NOCLIPHEIGHT); - P_SetTarget(&mo->target, player->mo); - mo->fuse = 12*TICRATE; - mo->destscale = player->mo->scale; - P_SetScale(mo, player->mo->scale); - - // Angle offset by player angle - fa = ((i*FINEANGLES/16) + (player->mo->angle>>ANGLETOFINESHIFT)) & FINEMASK; - - // Make rings spill out around the player in 16 directions like SA, but spill like Sonic 2. - // Technically a non-SA way of spilling rings. They just so happen to be a little similar. - - // >16 ring type spillout - ns = FixedMul(3*FRACUNIT, mo->scale); - mo->momx = FixedMul(FINECOSINE(fa),ns); - - if (!(twodlevel || (player->mo->flags2 & MF2_TWOD))) - mo->momy = FixedMul(FINESINE(fa),ns); - - P_SetObjectMomZ(mo, 4*FRACUNIT, false); - - if (i & 1) - P_SetObjectMomZ(mo, 4*FRACUNIT, true); - } -} - -void P_PlayerWeaponAmmoBurst(player_t *player) -{ - mobj_t *mo; - angle_t fa; - fixed_t ns; - INT32 i = 0; - fixed_t z; - - mobjtype_t weptype = 0; - powertype_t power = 0; - - while (true) - { - if (player->powers[pw_bouncering]) - { - weptype = MT_BOUNCERING; - power = pw_bouncering; - } - else if (player->powers[pw_railring]) - { - weptype = MT_RAILRING; - power = pw_railring; - } - else if (player->powers[pw_infinityring]) - { - weptype = MT_INFINITYRING; - power = pw_infinityring; - } - else if (player->powers[pw_automaticring]) - { - weptype = MT_AUTOMATICRING; - power = pw_automaticring; - } - else if (player->powers[pw_explosionring]) - { - weptype = MT_EXPLOSIONRING; - power = pw_explosionring; - } - else if (player->powers[pw_scatterring]) - { - weptype = MT_SCATTERRING; - power = pw_scatterring; - } - else if (player->powers[pw_grenadering]) - { - weptype = MT_GRENADERING; - power = pw_grenadering; - } - else - break; // All done! - - z = player->mo->z; - if (player->mo->eflags & MFE_VERTICALFLIP) - z += player->mo->height - mobjinfo[weptype].height; - - mo = P_SpawnMobj(player->mo->x, player->mo->y, z, weptype); - mo->health = player->powers[power]; - mo->flags2 |= MF2_DONTRESPAWN; - mo->flags &= ~(MF_NOGRAVITY|MF_NOCLIPHEIGHT); - P_SetTarget(&mo->target, player->mo); - - player->powers[power] = 0; - mo->fuse = 12*TICRATE; - - mo->destscale = player->mo->scale; - P_SetScale(mo, player->mo->scale); - - // Angle offset by player angle - fa = ((i*FINEANGLES/16) + (player->mo->angle>>ANGLETOFINESHIFT)) & FINEMASK; - - // Spill them! - ns = FixedMul(2*FRACUNIT, mo->scale); - mo->momx = FixedMul(FINECOSINE(fa), ns); - - if (!(twodlevel || (player->mo->flags2 & MF2_TWOD))) - mo->momy = FixedMul(FINESINE(fa),ns); - - P_SetObjectMomZ(mo, 3*FRACUNIT, false); - - if (i & 1) - P_SetObjectMomZ(mo, 3*FRACUNIT, true); - - i++; - } -} - -// -// P_PlayerEmeraldBurst -// -// Spills ONLY emeralds. -// -void P_PlayerEmeraldBurst(player_t *player, boolean toss) -{ - INT32 i; - angle_t fa; - fixed_t ns; - fixed_t z = 0, momx = 0, momy = 0; - - // Better safe than sorry. - if (!player) - return; - - // Spill power stones - if (player->powers[pw_emeralds]) - { - INT32 num_stones = 0; - - if (player->powers[pw_emeralds] & EMERALD1) - num_stones++; - if (player->powers[pw_emeralds] & EMERALD2) - num_stones++; - if (player->powers[pw_emeralds] & EMERALD3) - num_stones++; - if (player->powers[pw_emeralds] & EMERALD4) - num_stones++; - if (player->powers[pw_emeralds] & EMERALD5) - num_stones++; - if (player->powers[pw_emeralds] & EMERALD6) - num_stones++; - if (player->powers[pw_emeralds] & EMERALD7) - num_stones++; - - for (i = 0; i < num_stones; i++) - { - INT32 stoneflag = 0; - statenum_t statenum = S_CEMG1; - mobj_t *mo; - - if (player->powers[pw_emeralds] & EMERALD1) - { - stoneflag = EMERALD1; - statenum = S_CEMG1; - } - else if (player->powers[pw_emeralds] & EMERALD2) - { - stoneflag = EMERALD2; - statenum = S_CEMG2; - } - else if (player->powers[pw_emeralds] & EMERALD3) - { - stoneflag = EMERALD3; - statenum = S_CEMG3; - } - else if (player->powers[pw_emeralds] & EMERALD4) - { - stoneflag = EMERALD4; - statenum = S_CEMG4; - } - else if (player->powers[pw_emeralds] & EMERALD5) - { - stoneflag = EMERALD5; - statenum = S_CEMG5; - } - else if (player->powers[pw_emeralds] & EMERALD6) - { - stoneflag = EMERALD6; - statenum = S_CEMG6; - } - else if (player->powers[pw_emeralds] & EMERALD7) - { - stoneflag = EMERALD7; - statenum = S_CEMG7; - } - - if (!stoneflag) // ??? - continue; - - player->powers[pw_emeralds] &= ~stoneflag; - - if (toss) - { - fa = player->mo->angle>>ANGLETOFINESHIFT; - - z = player->mo->z + player->mo->height; - if (player->mo->eflags & MFE_VERTICALFLIP) - z -= mobjinfo[MT_FLINGEMERALD].height + player->mo->height; - ns = FixedMul(8*FRACUNIT, player->mo->scale); - } - else - { - fa = ((255 / num_stones) * i) * FINEANGLES/256; - - z = player->mo->z + (player->mo->height / 2); - if (player->mo->eflags & MFE_VERTICALFLIP) - z -= mobjinfo[MT_FLINGEMERALD].height; - ns = FixedMul(4*FRACUNIT, player->mo->scale); - } - - momx = FixedMul(FINECOSINE(fa), ns); - - if (!(twodlevel || (player->mo->flags2 & MF2_TWOD))) - momy = FixedMul(FINESINE(fa),ns); - else - momy = 0; - - mo = P_SpawnMobj(player->mo->x, player->mo->y, z, MT_FLINGEMERALD); - mo->health = 1; - mo->threshold = stoneflag; - mo->flags2 |= (MF2_DONTRESPAWN|MF2_SLIDEPUSH); - mo->flags &= ~(MF_NOGRAVITY|MF_NOCLIPHEIGHT); - P_SetTarget(&mo->target, player->mo); - mo->fuse = 12*TICRATE; - P_SetMobjState(mo, statenum); - - mo->momx = momx; - mo->momy = momy; - - P_SetObjectMomZ(mo, 3*FRACUNIT, false); - - if (player->mo->eflags & MFE_VERTICALFLIP) - mo->momz = -mo->momz; - - if (toss) - player->tossdelay = 2*TICRATE; - } - } } /** Makes an injured or dead player lose possession of the flag. diff --git a/src/p_local.h b/src/p_local.h index 0d0ddc89b..bc25affd4 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -390,9 +390,6 @@ void P_RemoveShield(player_t *player); boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 damage); void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source); void P_PlayerRingBurst(player_t *player, INT32 num_rings); /// \todo better fit in p_user.c -void P_PlayerWeaponPanelBurst(player_t *player); -void P_PlayerWeaponAmmoBurst(player_t *player); -void P_PlayerEmeraldBurst(player_t *player, boolean toss); void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck); void P_PlayerFlagBurst(player_t *player, boolean toss); diff --git a/src/p_map.c b/src/p_map.c index d9b723650..d99105005 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -1557,39 +1557,50 @@ static boolean PIT_CheckThing(mobj_t *thing) return true; } - if (P_IsObjectOnGround(thing) && tmthing->momz < 0) { - K_KartBouncing(tmthing, thing, true, false); - if (G_BattleGametype() && tmthing->player->kartstuff[k_pogospring]) - { - K_StealBumper(tmthing->player, thing->player, false); - K_SpinPlayer(thing->player, tmthing, 0, tmthing, false); - } - } - else if (P_IsObjectOnGround(tmthing) && thing->momz < 0) - { - K_KartBouncing(thing, tmthing, true, false); - if (G_BattleGametype() && thing->player->kartstuff[k_pogospring]) - { - K_StealBumper(thing->player, tmthing->player, false); - K_SpinPlayer(tmthing->player, thing, 0, thing, false); - } - } - else - K_KartBouncing(tmthing, thing, false, false); + // The bump has to happen last + mobj_t *mo1 = tmthing; + mobj_t *mo2 = thing; + boolean zbounce = false; - if (G_BattleGametype()) - { - if (thing->player->kartstuff[k_sneakertimer] && !(tmthing->player->kartstuff[k_sneakertimer]) && !(thing->player->powers[pw_flashing])) // Don't steal bumpers while intangible + if (P_IsObjectOnGround(thing) && tmthing->momz < 0) { - K_StealBumper(thing->player, tmthing->player, false); - K_SpinPlayer(tmthing->player, thing, 0, tmthing, false); + zbounce = true; + mo1 = thing; + mo2 = tmthing; + + if (G_BattleGametype() && tmthing->player->kartstuff[k_pogospring]) + { + K_StealBumper(tmthing->player, thing->player, false); + K_SpinPlayer(thing->player, tmthing, 0, tmthing, false); + } } - else if (tmthing->player->kartstuff[k_sneakertimer] && !(thing->player->kartstuff[k_sneakertimer]) && !(tmthing->player->powers[pw_flashing])) + else if (P_IsObjectOnGround(tmthing) && thing->momz < 0) { - K_StealBumper(tmthing->player, thing->player, false); - K_SpinPlayer(thing->player, tmthing, 0, thing, false); + zbounce = true; + + if (G_BattleGametype() && thing->player->kartstuff[k_pogospring]) + { + K_StealBumper(thing->player, tmthing->player, false); + K_SpinPlayer(tmthing->player, thing, 0, thing, false); + } } + + if (G_BattleGametype()) + { + if (thing->player->kartstuff[k_sneakertimer] && !(tmthing->player->kartstuff[k_sneakertimer]) && !(thing->player->powers[pw_flashing])) // Don't steal bumpers while intangible + { + K_StealBumper(thing->player, tmthing->player, false); + K_SpinPlayer(tmthing->player, thing, 0, tmthing, false); + } + else if (tmthing->player->kartstuff[k_sneakertimer] && !(thing->player->kartstuff[k_sneakertimer]) && !(tmthing->player->powers[pw_flashing])) + { + K_StealBumper(tmthing->player, thing->player, false); + K_SpinPlayer(thing->player, tmthing, 0, thing, false); + } + } + + K_KartBouncing(mo1, mo2, zbounce, false); } return true; diff --git a/src/p_mobj.c b/src/p_mobj.c index f7f2afe34..9919b2266 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -85,6 +85,37 @@ void P_AddCachedAction(mobj_t *mobj, INT32 statenum) actioncachehead.prev = newaction; } +// +// P_SetupStateAnimation +// +FUNCINLINE static ATTRINLINE void P_SetupStateAnimation(mobj_t *mobj, state_t *st) +{ + if (!(st->frame & FF_ANIMATE)) + return; + + if (st->var1 <= 0 || st->var2 == 0) + { + mobj->frame &= ~FF_ANIMATE; + return; // Crash/stupidity prevention + } + + mobj->anim_duration = (UINT16)st->var2; + + if (st->frame & FF_GLOBALANIM) + { + // Attempt to account for the pre-ticker for objects spawned on load + if (!leveltime) return; + + mobj->anim_duration -= (leveltime + 2) % st->var2; // Duration synced to timer + mobj->frame += ((leveltime + 2) / st->var2) % (st->var1 + 1); // Frame synced to timer (duration taken into account) + } + else if (st->frame & FF_RANDOMANIM) + { + mobj->frame += P_RandomKey(st->var1 + 1); // Random starting frame + mobj->anim_duration -= P_RandomKey(st->var2); // Random duration for first frame + } +} + // // P_CycleStateAnimation // @@ -93,6 +124,7 @@ FUNCINLINE static ATTRINLINE void P_CycleStateAnimation(mobj_t *mobj) // var2 determines delay between animation frames if (!(mobj->frame & FF_ANIMATE) || --mobj->anim_duration != 0) return; + mobj->anim_duration = (UINT16)mobj->state->var2; // compare the current sprite frame to the one we started from @@ -212,7 +244,7 @@ boolean P_SetPlayerMobjState(mobj_t *mobj, statenum_t state) mobj->tics = st->tics; mobj->sprite = st->sprite; mobj->frame = st->frame; - mobj->anim_duration = (UINT16)st->var2; // only used if FF_ANIMATE is set + P_SetupStateAnimation(mobj, st); // Modified handling. // Call action functions when the state is set @@ -280,7 +312,7 @@ boolean P_SetMobjState(mobj_t *mobj, statenum_t state) mobj->tics = st->tics; mobj->sprite = st->sprite; mobj->frame = st->frame; - mobj->anim_duration = (UINT16)st->var2; // only used if FF_ANIMATE is set + P_SetupStateAnimation(mobj, st); // Modified handling. // Call action functions when the state is set @@ -334,7 +366,7 @@ boolean P_SetMobjStateNF(mobj_t *mobj, statenum_t state) mobj->tics = st->tics; mobj->sprite = st->sprite; mobj->frame = st->frame; - mobj->anim_duration = (UINT16)st->var2; // only used if FF_ANIMATE is set + P_SetupStateAnimation(mobj, st); return true; } @@ -353,7 +385,7 @@ static boolean P_SetPrecipMobjState(precipmobj_t *mobj, statenum_t state) mobj->tics = st->tics; mobj->sprite = st->sprite; mobj->frame = st->frame; - mobj->anim_duration = (UINT16)st->var2; // only used if FF_ANIMATE is set + P_SetupStateAnimation((mobj_t*)mobj, st); return true; } @@ -1905,7 +1937,7 @@ void P_XYMovement(mobj_t *mo) #endif //{ SRB2kart stuff - if (mo->type == MT_ORBINAUT || mo->type == MT_JAWZ_DUD || mo->type == MT_JAWZ || mo->type == MT_BALLHOG) //(mo->type == MT_JAWZ && !mo->tracer)) + if (mo->type == MT_ORBINAUT || mo->type == MT_JAWZ_DUD || mo->type == MT_JAWZ || mo->type == MT_BALLHOG || mo->type == MT_FLINGRING) //(mo->type == MT_JAWZ && !mo->tracer)) return; if (mo->player && (mo->player->kartstuff[k_spinouttimer] && !mo->player->kartstuff[k_wipeoutslow]) && mo->player->speed <= K_GetKartSpeed(mo->player, false)/2) @@ -2456,11 +2488,11 @@ static boolean P_ZMovement(mobj_t *mo) mom.z = -mom.z; else // Flingrings bounce - if (mo->type == MT_FLINGRING + if (/*mo->type == MT_FLINGRING || mo->type == MT_FLINGCOIN || P_WeaponOrPanel(mo->type) || mo->type == MT_FLINGEMERALD - || mo->type == MT_BIGTUMBLEWEED + ||*/ mo->type == MT_BIGTUMBLEWEED || mo->type == MT_LITTLETUMBLEWEED || mo->type == MT_CANNONBALLDECOR || mo->type == MT_FALLINGROCK) @@ -3592,7 +3624,7 @@ boolean P_CameraThinker(player_t *player, camera_t *thiscam, boolean resetcalled dummy.z = thiscam->z; dummy.height = thiscam->height; if (player->pflags & PF_TIMEOVER) - player->kartstuff[k_timeovercam] = (2*TICRATE)+1; + player->karthud[khud_timeovercam] = (2*TICRATE)+1; if (!resetcalled && !(player->pflags & PF_NOCLIP || leveltime < introtime) && !P_CheckSight(&dummy, player->mo)) // TODO: "P_CheckCameraSight" instead. P_ResetCamera(player, thiscam); else @@ -6670,7 +6702,7 @@ void P_MobjThinker(mobj_t *mobj) if ((G_RaceGametype() || mobj->target->player->kartstuff[k_bumper] <= 0) #if 1 // Set to 0 to test without needing to host - || ((mobj->target->player == &players[displayplayers[0]]) || P_IsLocalPlayer(mobj->target->player)) + || (P_IsDisplayPlayer(mobj->target->player)) #endif ) mobj->flags2 |= MF2_DONTDRAW; @@ -7903,8 +7935,8 @@ void P_MobjThinker(mobj_t *mobj) else { fixed_t finalspeed = mobj->movefactor; - - P_SpawnGhostMobj(mobj); + mobj_t *ghost = P_SpawnGhostMobj(mobj); + ghost->colorized = true; // already has color! mobj->angle = R_PointToAngle2(0, 0, mobj->momx, mobj->momy); if (mobj->health <= 5) @@ -7939,18 +7971,20 @@ void P_MobjThinker(mobj_t *mobj) fixed_t topspeed = mobj->movefactor; fixed_t distbarrier = 512*mapobjectscale; fixed_t distaway; + mobj_t *ghost = P_SpawnGhostMobj(mobj); - P_SpawnGhostMobj(mobj); + if (mobj->target && !P_MobjWasRemoved(mobj->target) && mobj->target->player) + { + ghost->color = mobj->target->player->skincolor; + ghost->colorized = true; + } if (mobj->threshold > 0) mobj->threshold--; if (leveltime % TICRATE == 0) S_StartSound(mobj, mobj->info->activesound); - if (gamespeed == 0) - distbarrier = FixedMul(distbarrier, FRACUNIT-FRACUNIT/4); - else if (gamespeed == 2) - distbarrier = FixedMul(distbarrier, FRACUNIT+FRACUNIT/4); + distbarrier = FixedMul(distbarrier, FRACUNIT + ((gamespeed-1) * (FRACUNIT/4))); if (G_RaceGametype() && mobj->tracer) { @@ -8007,7 +8041,14 @@ void P_MobjThinker(mobj_t *mobj) } else { - P_SpawnGhostMobj(mobj); + mobj_t *ghost = P_SpawnGhostMobj(mobj); + + if (mobj->target && !P_MobjWasRemoved(mobj->target) && mobj->target->player) + { + ghost->color = mobj->target->player->skincolor; + ghost->colorized = true; + } + mobj->angle = R_PointToAngle2(0, 0, mobj->momx, mobj->momy); P_InstaThrust(mobj, mobj->angle, mobj->movefactor); @@ -8032,14 +8073,25 @@ void P_MobjThinker(mobj_t *mobj) case MT_BANANA: case MT_EGGMANITEM: mobj->friction = ORIG_FRICTION/4; + if (mobj->momx || mobj->momy) - P_SpawnGhostMobj(mobj); + { + mobj_t *ghost = P_SpawnGhostMobj(mobj); + + if (mobj->target && !P_MobjWasRemoved(mobj->target) && mobj->target->player) + { + ghost->color = mobj->target->player->skincolor; + ghost->colorized = true; + } + } + if (P_IsObjectOnGround(mobj) && mobj->health > 1) { S_StartSound(mobj, mobj->info->activesound); mobj->momx = mobj->momy = 0; mobj->health = 1; } + if (mobj->threshold > 0) mobj->threshold--; break; @@ -8047,18 +8099,38 @@ void P_MobjThinker(mobj_t *mobj) indirectitemcooldown = 20*TICRATE; /* FALLTHRU */ case MT_BALLHOG: - P_SpawnGhostMobj(mobj)->fuse = 3; - if (mobj->threshold > 0) - mobj->threshold--; + { + mobj_t *ghost = P_SpawnGhostMobj(mobj); + ghost->fuse = 3; + + if (mobj->target && !P_MobjWasRemoved(mobj->target) && mobj->target->player) + { + ghost->color = mobj->target->player->skincolor; + ghost->colorized = true; + } + + if (mobj->threshold > 0) + mobj->threshold--; + } break; case MT_SINK: if (mobj->momx || mobj->momy) - P_SpawnGhostMobj(mobj); + { + mobj_t *ghost = P_SpawnGhostMobj(mobj); + + if (mobj->target && !P_MobjWasRemoved(mobj->target) && mobj->target->player) + { + ghost->color = mobj->target->player->skincolor; + ghost->colorized = true; + } + } + if (P_IsObjectOnGround(mobj)) { S_StartSound(mobj, mobj->info->deathsound); P_SetMobjState(mobj, S_NULL); } + if (mobj->threshold > 0) mobj->threshold--; break; @@ -8069,7 +8141,10 @@ void P_MobjThinker(mobj_t *mobj) mobj->color = SKINCOLOR_KETCHUP; if (mobj->momx || mobj->momy) - P_SpawnGhostMobj(mobj); + { + mobj_t *ghost = P_SpawnGhostMobj(mobj); + ghost->colorized = true; // already has color! + } if (P_IsObjectOnGround(mobj) && (mobj->state == &states[S_SSMINE_AIR1] || mobj->state == &states[S_SSMINE_AIR2])) { @@ -8142,9 +8217,10 @@ void P_MobjThinker(mobj_t *mobj) if (p) { - if (p->kartstuff[k_sneakertimer] > mobj->movecount) + if (p->kartstuff[k_sneakertimer] > mobj->movecount + || p->kartstuff[k_levelbooster] > mobj->movecount) P_SetMobjState(mobj, S_BOOSTFLAME); - mobj->movecount = p->kartstuff[k_sneakertimer]; + mobj->movecount = max(p->kartstuff[k_sneakertimer], p->kartstuff[k_levelbooster]); } } @@ -8263,6 +8339,18 @@ void P_MobjThinker(mobj_t *mobj) K_MatchGenericExtraFlags(mobj, mobj->target); P_TeleportMove(mobj, mobj->target->x, mobj->target->y, mobj->target->z + (mobj->target->height/2) + mobj->movefactor); break; + case MT_RINGSPARKS: + if (!mobj->target || P_MobjWasRemoved(mobj->target)) + { + P_RemoveMobj(mobj); + return; + } + + K_MatchGenericExtraFlags(mobj, mobj->target); + P_TeleportMove(mobj, mobj->target->x + FINECOSINE(mobj->angle >> ANGLETOFINESHIFT), + mobj->target->y + FINESINE(mobj->angle >> ANGLETOFINESHIFT), + mobj->target->z + mobj->target->height); + break; case MT_THUNDERSHIELD: { fixed_t destx, desty; @@ -9528,6 +9616,21 @@ void P_SceneryThinker(mobj_t *mobj) } } + // Sonic Advance 2 flashing afterimages + if (mobj->type == MT_GHOST && mobj->fuse > 0 + && mobj->extravalue1 > 0 && mobj->extravalue2 >= 2) + { + if (mobj->extravalue2 == 2) // I don't know why the normal logic doesn't work for this. + mobj->flags2 ^= MF2_DONTDRAW; + else + { + if (mobj->fuse == mobj->extravalue2) + mobj->flags2 &= ~MF2_DONTDRAW; + else + mobj->flags2 |= MF2_DONTDRAW; + } + } + // momentum movement if (mobj->momx || mobj->momy) { @@ -9635,7 +9738,7 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) mobj->tics = st->tics; mobj->sprite = st->sprite; mobj->frame = st->frame; // FF_FRAMEMASK for frame, and other bits.. - mobj->anim_duration = (UINT16)st->var2; // only used if FF_ANIMATE is set + P_SetupStateAnimation(mobj, st); mobj->friction = ORIG_FRICTION; @@ -9879,7 +9982,7 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) break; } - mobj->color = SKINCOLOR_AQUA; + mobj->color = SKINCOLOR_CYAN; break; } case MT_MARBLETORCH: @@ -10086,6 +10189,7 @@ mobj_t *P_SpawnShadowMobj(mobj_t * caster) mobj->tics = st->tics; mobj->sprite = st->sprite; mobj->frame = st->frame; // FF_FRAMEMASK for frame, and other bits.. + P_SetupStateAnimation(mobj, st); mobj->friction = ORIG_FRICTION; @@ -10178,7 +10282,7 @@ static precipmobj_t *P_SpawnPrecipMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype mobj->tics = st->tics; mobj->sprite = st->sprite; mobj->frame = st->frame; // FF_FRAMEMASK for frame, and other bits.. - mobj->anim_duration = (UINT16)st->var2; // only used if FF_ANIMATE is set + P_SetupStateAnimation((mobj_t*)mobj, st); // set subsector and/or block links P_SetPrecipitationThingPosition(mobj); @@ -10608,6 +10712,8 @@ void P_PrecipitationEffects(void) // void P_RespawnSpecials(void) { + UINT8 p, pcount = 0; + tic_t time = 30*TICRATE; // Respawn things in empty dedicated servers fixed_t x, y, z; subsector_t *ss; mobj_t *mo = NULL; @@ -10654,21 +10760,28 @@ void P_RespawnSpecials(void) numgotboxes = 0; } - // only respawn items when cv_itemrespawn is on - if (!cv_itemrespawn.value) - return; + // wait time depends on player count + for (p = 0; p < MAXPLAYERS; p++) + { + if (playeringame[p] && !players[p].spectator) + pcount++; + } - // Don't respawn in special stages! - if (G_IsSpecialStage(gamemap)) + if (pcount == 1) // No respawn when alone return; + else if (pcount > 1) + time = (180 - (pcount * 10))*TICRATE; + + // only respawn items when cv_itemrespawn is on + //if (!cv_itemrespawn.value) // TODO: remove this cvar + //return; // nothing left to respawn? if (iquehead == iquetail) return; // the first item in the queue is the first to respawn - // wait at least 30 seconds - if (leveltime - itemrespawntime[iquetail] < (tic_t)cv_itemrespawntime.value*TICRATE) + if (leveltime - itemrespawntime[iquetail] < time) return; mthing = itemrespawnque[iquetail]; @@ -11508,20 +11621,16 @@ void P_SpawnMapThing(mapthing_t *mthing) mobjtype_t macetype = MT_SMALLMACE; boolean firsttime; mobj_t *spawnee; - size_t line; + INT32 line; const size_t mthingi = (size_t)(mthing - mapthings); - // Why does P_FindSpecialLineFromTag not work here?!? - // Monster Iestyn: tag lists haven't been initialised yet for the map, that's why - for (line = 0; line < numlines; line++) - { - if (lines[line].special == 9 && lines[line].tag == mthing->angle) - break; - } + // Find the corresponding linedef special, using angle as tag + // P_FindSpecialLineFromTag works here now =D + line = P_FindSpecialLineFromTag(9, mthing->angle, -1); - if (line == numlines) + if (line == -1) { - CONS_Debug(DBG_GAMELOGIC, "Mace chain (mapthing #%s) needs tagged to a #9 parameter line (trying to find tag %d).\n", sizeu1(mthingi), mthing->angle); + CONS_Debug(DBG_GAMELOGIC, "Mace chain (mapthing #%s) needs to be tagged to a #9 parameter line (trying to find tag %d).\n", sizeu1(mthingi), mthing->angle); return; } /* @@ -11957,7 +12066,7 @@ ML_NOCLIMB : Direction not controllable void P_SpawnHoopsAndRings(mapthing_t *mthing) { mobj_t *mobj = NULL; - INT32 /*r,*/ i; + INT32 r, i; fixed_t x, y, z, finalx, finaly, finalz; sector_t *sec; TVector v, *res; @@ -12244,8 +12353,6 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing) return; } - else return; // srb2kart - no rings or ring-like objects in R1 - /* // Wing logo item. else if (mthing->type == mobjinfo[MT_NIGHTSWING].doomednum) { @@ -12539,7 +12646,8 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing) } } return; - }*/ + } + else return; } // diff --git a/src/p_pspr.h b/src/p_pspr.h index e74266002..b42692462 100644 --- a/src/p_pspr.h +++ b/src/p_pspr.h @@ -35,14 +35,9 @@ #pragma interface #endif -/// \brief Frame flags: only the frame number -#define FF_FRAMEMASK 0x1ff -/// \brief Frame flags: Thin, paper-like sprite (for collision equivalent, see MF_PAPERCOLLISION) -#define FF_PAPERSPRITE 0x800 -/// \brief Frame flags: Simple stateless animation -#define FF_ANIMATE 0x4000 -/// \brief Frame flags: frame always appears full bright -#define FF_FULLBRIGHT 0x8000 +/// \brief Frame flags: only the frame number (frames from 0 to 63, but a bit of headroom for 2.2 compat) +#define FF_FRAMEMASK 0xff + /// \brief Frame flags: 0 = no trans(opaque), 1-15 = transl. table #define FF_TRANSMASK 0xf0000 /// \brief shift for FF_TRANSMASK @@ -58,6 +53,23 @@ #define FF_TRANS80 (tr_trans80<forcecharacter[0] != '\0' - && atoi(mapheaderinfo[gamemap-1]->forcecharacter) != 255) + if (mapheaderinfo[gamemap-1]->forcecharacter[0] != '\0') P_ForceCharacter(mapheaderinfo[gamemap-1]->forcecharacter); // chasecam on in chaos, race, coop @@ -2859,13 +2858,13 @@ boolean P_SetupLevel(boolean skipprecip) S_StartSound(NULL, sfx_ruby1); F_WipeStartScreen(); - V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 122); + V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 209); F_WipeEndScreen(); F_RunWipe(wipedefs[wipe_speclevel_towhite], false); F_WipeStartScreen(); - V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 120); + V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 0); F_WipeEndScreen(); F_RunWipe(wipedefs[wipe_level_final], false); @@ -2898,7 +2897,7 @@ boolean P_SetupLevel(boolean skipprecip) // We should be fine starting it here. S_Start(); - levelfadecol = (encoremode && !ranspecialwipe ? 122 : 120); + levelfadecol = (encoremode && !ranspecialwipe ? 209 : 0); // Let's fade to white here // But only if we didn't do the encore startup wipe @@ -3066,6 +3065,10 @@ boolean P_SetupLevel(boolean skipprecip) P_PrepareThings(lastloadedmaplumpnum + ML_THINGS); } + // init gravity, tag lists, + // anything that P_ResetDynamicSlopes/P_LoadThings needs to know + P_InitSpecials(); + #ifdef ESLOPE P_ResetDynamicSlopes(); #endif @@ -3084,8 +3087,6 @@ boolean P_SetupLevel(boolean skipprecip) if (loadprecip) // ugly hack for P_NetUnArchiveMisc (and P_LoadNetGame) P_SpawnPrecipitation(); - globalweather = mapheaderinfo[gamemap-1]->weather; - #ifdef HWRENDER // not win32 only 19990829 by Kin if (rendermode != render_soft && rendermode != render_none) { diff --git a/src/p_spec.c b/src/p_spec.c index a08bdbc34..e0c1a7465 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -4247,19 +4247,19 @@ DoneSection2: if (nump > 1) { if (K_IsPlayerLosing(player)) - player->kartstuff[k_laphand] = 3; + player->karthud[khud_laphand] = 3; else { if (nump > 2 && player->kartstuff[k_position] == 1) // 1st place in 1v1 uses thumbs up - player->kartstuff[k_laphand] = 1; + player->karthud[khud_laphand] = 1; else - player->kartstuff[k_laphand] = 2; + player->karthud[khud_laphand] = 2; } } else - player->kartstuff[k_laphand] = 0; // No hands in FREE PLAY + player->karthud[khud_laphand] = 0; // No hands in FREE PLAY - player->kartstuff[k_lapanimation] = 80; + player->karthud[khud_lapanimation] = 80; if (player->pflags & PF_NIGHTSMODE) player->drillmeter += 48*20; @@ -4295,7 +4295,7 @@ DoneSection2: player->starpostangle = player->starpostx = player->starposty = player->starpostz = player->kartstuff[k_starpostflip] = 0; } - if (P_IsLocalPlayer(player)) + if (P_IsDisplayPlayer(player)) { if (player->laps == (UINT8)(cv_numlaps.value - 1)) S_StartSound(NULL, sfx_s3k68); @@ -4325,7 +4325,7 @@ DoneSection2: if (player->laps >= (unsigned)cv_numlaps.value) { - if (P_IsLocalPlayer(player)) + if (P_IsDisplayPlayer(player)) S_StartSound(NULL, sfx_s3k6a); else if (player->kartstuff[k_position] == 1) S_StartSound(NULL, sfx_s253); @@ -5659,6 +5659,45 @@ static void P_RunLevelLoadExecutors(void) } } +/** Before things are loaded, initialises certain stuff in case they're needed + * by P_ResetDynamicSlopes or P_LoadThings. This was split off from + * P_SpawnSpecials, in case you couldn't tell. + * + * \sa P_SpawnSpecials, P_InitTagLists + * \author Monster Iestyn + */ +void P_InitSpecials(void) +{ + // Set the default gravity. Custom gravity overrides this setting. + gravity = (FRACUNIT*8)/10; + + // Defaults in case levels don't have them set. + sstimer = 90*TICRATE + 6; + totalrings = 1; + + CheckForBustableBlocks = CheckForBouncySector = CheckForQuicksand = CheckForMarioBlocks = CheckForFloatBob = CheckForReverseGravity = false; + + // Set curWeather + switch (mapheaderinfo[gamemap-1]->weather) + { + case PRECIP_SNOW: // snow + case PRECIP_RAIN: // rain + case PRECIP_STORM: // storm + case PRECIP_STORM_NORAIN: // storm w/o rain + case PRECIP_STORM_NOSTRIKES: // storm w/o lightning + curWeather = mapheaderinfo[gamemap-1]->weather; + break; + default: // blank/none + curWeather = PRECIP_NONE; + break; + } + + // Set globalweather + globalweather = mapheaderinfo[gamemap-1]->weather; + + P_InitTagLists(); // Create xref tables for tags +} + /** After the map has loaded, scans for specials that spawn 3Dfloors and * thinkers. * @@ -5680,15 +5719,6 @@ void P_SpawnSpecials(INT32 fromnetsave) // but currently isn't. (void)fromnetsave; - // Set the default gravity. Custom gravity overrides this setting. - gravity = (FRACUNIT*8)/10; - - // Defaults in case levels don't have them set. - sstimer = 90*TICRATE + 6; - totalrings = 1; - - CheckForBustableBlocks = CheckForBouncySector = CheckForQuicksand = CheckForMarioBlocks = CheckForFloatBob = CheckForReverseGravity = false; - // Init special SECTORs. sector = sectors; for (i = 0; i < numsectors; i++, sector++) @@ -5737,20 +5767,6 @@ void P_SpawnSpecials(INT32 fromnetsave) } } - if (mapheaderinfo[gamemap-1]->weather == 2) // snow - curWeather = PRECIP_SNOW; - else if (mapheaderinfo[gamemap-1]->weather == 3) // rain - curWeather = PRECIP_RAIN; - else if (mapheaderinfo[gamemap-1]->weather == 1) // storm - curWeather = PRECIP_STORM; - else if (mapheaderinfo[gamemap-1]->weather == 5) // storm w/o rain - curWeather = PRECIP_STORM_NORAIN; - else if (mapheaderinfo[gamemap-1]->weather == 6) // storm w/o lightning - curWeather = PRECIP_STORM_NOSTRIKES; - else - curWeather = PRECIP_NONE; - - P_InitTagLists(); // Create xref tables for tags P_SearchForDisableLinedefs(); // Disable linedefs are now allowed to disable *any* line P_SpawnScrollers(); // Add generalized scrollers @@ -7340,9 +7356,7 @@ void T_Friction(friction_t *f) // apparently, all I had to do was comment out part of the next line and // friction works for all mobj's // (or at least MF_PUSHABLEs, which is all I care about anyway) - if ((!(thing->flags & (MF_NOGRAVITY | MF_NOCLIP)) && thing->z == thing->floorz) && (thing->player - && (thing->player->kartstuff[k_invincibilitytimer] == 0 && thing->player->kartstuff[k_hyudorotimer] == 0 - && thing->player->kartstuff[k_sneakertimer] == 0 && thing->player->kartstuff[k_growshrinktimer] <= 0))) + if (!(thing->flags & (MF_NOGRAVITY | MF_NOCLIP)) && thing->z == thing->floorz) { if (f->roverfriction) { diff --git a/src/p_spec.h b/src/p_spec.h index 1231aeda8..b604ac951 100644 --- a/src/p_spec.h +++ b/src/p_spec.h @@ -32,6 +32,7 @@ void P_InitPicAnims(void); void P_SetupLevelFlatAnims(void); // at map load +void P_InitSpecials(void); void P_SpawnSpecials(INT32 fromnetsave); // every tic diff --git a/src/p_user.c b/src/p_user.c index ced8b2da0..afa0966cf 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -946,50 +946,19 @@ void P_ResetPlayer(player_t *player) // void P_GivePlayerRings(player_t *player, INT32 num_rings) { - if (player->bot) - player = &players[consoleplayer]; - if (!player->mo) return; - player->mo->health += num_rings; - player->health += num_rings; + if (G_BattleGametype()) // No rings in Battle Mode + return; - if (!G_IsSpecialStage(gamemap) || !useNightsSS) - player->totalring += num_rings; + player->kartstuff[k_rings] += num_rings; + //player->totalring += num_rings; // Used for GP lives later - //{ SRB2kart - rings don't really do anything, but we don't want the player spilling them later. - /* - // Can only get up to 9999 rings, sorry! - if (player->mo->health > 10000) - { - player->mo->health = 10000; - player->health = 10000; - } - else if (player->mo->health < 1)*/ - { - player->mo->health = 1; - player->health = 1; - } - //} - - // Now extra life bonuses are handled here instead of in P_MovePlayer, since why not? - if (!ultimatemode && !modeattacking && !G_IsSpecialStage(gamemap) && G_GametypeUsesLives()) - { - INT32 gainlives = 0; - - while (player->xtralife < maxXtraLife && player->health > 100 * (player->xtralife+1)) - { - ++gainlives; - ++player->xtralife; - } - - if (gainlives) - { - P_GivePlayerLives(player, gainlives); - P_PlayLivesJingle(player); - } - } + if (player->kartstuff[k_rings] > 20) + player->kartstuff[k_rings] = 20; // Caps at 20 rings, sorry! + else if (player->kartstuff[k_rings] < -20) + player->kartstuff[k_rings] = -20; // Chaotix ring debt! } // @@ -1114,11 +1083,12 @@ void P_PlayLivesJingle(player_t *player) void P_PlayRinglossSound(mobj_t *source) { - sfxenum_t key = P_RandomKey(2); - if (cv_kartvoices.value) - S_StartSound(source, (mariomode) ? sfx_mario8 : sfx_khurt1 + key); + if (source->player && source->player->kartstuff[k_itemtype] == KITEM_THUNDERSHIELD) + S_StartSound(source, sfx_s1a3); // Shield hit (no ring loss) + else if (source->player && source->player->kartstuff[k_rings] <= 0) + S_StartSound(source, sfx_s1a6); // Ring debt (lessened ring loss) else - S_StartSound(source, sfx_slip); + S_StartSound(source, sfx_s1c6); // Normal ring loss sound } void P_PlayDeathSound(mobj_t *source) @@ -1704,7 +1674,7 @@ void P_DoPlayerExit(player_t *player) if (cv_kartvoices.value) { - if (P_IsLocalPlayer(player)) + if (P_IsDisplayPlayer(player)) { sfxenum_t sfx_id; if (K_IsPlayerLosing(player)) @@ -1751,7 +1721,7 @@ void P_DoPlayerExit(player_t *player) */ player->powers[pw_underwater] = 0; player->powers[pw_spacetime] = 0; - player->kartstuff[k_cardanimation] = 0; // srb2kart: reset battle animation + player->karthud[khud_cardanimation] = 0; // srb2kart: reset battle animation if (player == &players[consoleplayer]) demo.savebutton = leveltime; @@ -4039,7 +4009,7 @@ static void P_3dMovement(player_t *player) if ((player->exiting || mapreset) || player->pflags & PF_STASIS || player->kartstuff[k_spinouttimer]) // pw_introcam? { cmd->forwardmove = cmd->sidemove = 0; - if (player->kartstuff[k_sneakertimer]) + if (EITHERSNEAKER(player)) cmd->forwardmove = 50; } @@ -4129,13 +4099,6 @@ static void P_3dMovement(player_t *player) //movepushforward = cmd->forwardmove * (thrustfactor * acceleration); movepushforward = K_3dKartMovement(player, onground, cmd->forwardmove); - // allow very small movement while in air for gameplay - if (!onground) - movepushforward >>= 2; // proper air movement - - // don't need to account for scale here with kart accel code - //movepushforward = FixedMul(movepushforward, player->mo->scale); - if (player->mo->movefactor != FRACUNIT) // Friction-scaled acceleration... movepushforward = FixedMul(movepushforward, player->mo->movefactor); @@ -4199,6 +4162,18 @@ static void P_3dMovement(player_t *player) player->mo->momx += totalthrust.x; player->mo->momy += totalthrust.y; + + if (!onground) + { + fixed_t airspeedcap = (50*mapobjectscale); + fixed_t speed = R_PointToDist2(0, 0, player->mo->momx, player->mo->momy); + if (speed > airspeedcap) + { + fixed_t newspeed = speed - ((speed - airspeedcap) / 32); + player->mo->momx = FixedMul(FixedDiv(player->mo->momx, speed), newspeed); + player->mo->momy = FixedMul(FixedDiv(player->mo->momy, speed), newspeed); + } + } #endif // Time to ask three questions: @@ -4215,7 +4190,7 @@ static void P_3dMovement(player_t *player) if (newMagnitude > K_GetKartSpeed(player, true)) //topspeed) { fixed_t tempmomx, tempmomy; - if (oldMagnitude > K_GetKartSpeed(player, true) && onground) // SRB2Kart: onground check for air speed cap + if (oldMagnitude > K_GetKartSpeed(player, true)) { if (newMagnitude > oldMagnitude) { @@ -5778,11 +5753,10 @@ static void P_MovePlayer(player_t *player) boolean add_delta = true; // Kart: store the current turn range for later use - if (((player->mo && player->speed > 0) // Moving + if ((player->mo && player->speed > 0) // Moving || (leveltime > starttime && (cmd->buttons & BT_ACCELERATE && cmd->buttons & BT_BRAKE)) // Rubber-burn turn || (player->kartstuff[k_respawn]) // Respawning || (player->spectator || objectplacing)) // Not a physical player - ) // ~~Spinning and boosting cancels out turning~~ Not anymore given spinout is more slippery and more prone to get you killed because of boosters. { player->lturn_max[leveltime%MAXPREDICTTICS] = K_GetKartTurnValue(player, KART_FULLTURN)+1; player->rturn_max[leveltime%MAXPREDICTTICS] = K_GetKartTurnValue(player, -KART_FULLTURN)-1; @@ -6172,7 +6146,7 @@ static void P_MovePlayer(player_t *player) //////////////////////////// // SRB2kart - Drifting smoke and fire - if (player->kartstuff[k_sneakertimer] > 0 && onground && (leveltime & 1)) + if (EITHERSNEAKER(player) && onground && (leveltime & 1)) K_SpawnBoostTrail(player); if (player->kartstuff[k_invincibilitytimer] > 0) @@ -7064,7 +7038,7 @@ static void P_DeathThink(player_t *player) if (player->pflags & PF_TIMEOVER) { - player->kartstuff[k_timeovercam]++; + player->karthud[khud_timeovercam]++; if (player->mo) { player->mo->flags |= (MF_NOGRAVITY|MF_NOCLIP); @@ -7072,7 +7046,7 @@ static void P_DeathThink(player_t *player) } } else - player->kartstuff[k_timeovercam] = 0; + player->karthud[khud_timeovercam] = 0; K_KartPlayerHUDUpdate(player); @@ -7280,7 +7254,7 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall #endif if (player->pflags & PF_TIMEOVER) // 1 for momentum keep, 2 for turnaround - timeover = (player->kartstuff[k_timeovercam] > 2*TICRATE ? 2 : 1); + timeover = (player->karthud[khud_timeovercam] > 2*TICRATE ? 2 : 1); else timeover = 0; @@ -7423,7 +7397,7 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall if (timeover) { - const INT32 timeovercam = max(0, min(180, (player->kartstuff[k_timeovercam] - 2*TICRATE)*15)); + const INT32 timeovercam = max(0, min(180, (player->karthud[khud_timeovercam] - 2*TICRATE)*15)); camrotate += timeovercam; } else if (leveltime < introtime) // Whoooshy camera! @@ -7497,10 +7471,10 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall dist += 4*(player->speed - K_GetKartSpeed(player, false)); dist += abs(thiscam->momz)/4; - if (player->kartstuff[k_boostcam]) + if (player->karthud[khud_boostcam]) { - dist -= FixedMul(11*dist/16, player->kartstuff[k_boostcam]); - height -= FixedMul(height, player->kartstuff[k_boostcam]); + dist -= FixedMul(11*dist/16, player->karthud[khud_boostcam]); + height -= FixedMul(height, player->karthud[khud_boostcam]); } x = mo->x - FixedMul(FINECOSINE((angle>>ANGLETOFINESHIFT) & FINEMASK), dist); @@ -8437,8 +8411,7 @@ void P_PlayerThink(player_t *player) #if 1 // "Blur" a bit when you have speed shoes and are going fast enough - if ((player->powers[pw_super] || player->powers[pw_sneakers] - || player->kartstuff[k_driftboost] || player->kartstuff[k_sneakertimer] || player->kartstuff[k_startboost]) && !player->kartstuff[k_invincibilitytimer] // SRB2kart + if ((player->powers[pw_super] || player->powers[pw_sneakers]) && (player->speed + abs(player->mo->momz)) > FixedMul(20*FRACUNIT,player->mo->scale)) { UINT8 i; diff --git a/src/r_draw.c b/src/r_draw.c index 02a912155..1931ce6ee 100644 --- a/src/r_draw.c +++ b/src/r_draw.c @@ -139,75 +139,12 @@ UINT32 nflatxshift, nflatyshift, nflatshiftup, nflatmask; #define BLINK_TT_CACHE_INDEX (MAXSKINS + 5) #define TT_CACHE_SIZE (MAXSKINS + 6) #define SKIN_RAMP_LENGTH 16 -#define DEFAULT_STARTTRANSCOLOR 160 +#define DEFAULT_STARTTRANSCOLOR 96 #define NUM_PALETTE_ENTRIES 256 static UINT8** translationtablecache[TT_CACHE_SIZE] = {NULL}; - -// See also the enum skincolors_t -// TODO Callum: Can this be translated? -/* -const char *Color_Names[MAXSKINCOLORS] = -{ - "None", // SKINCOLOR_NONE - "White", // SKINCOLOR_WHITE - "Silver", // SKINCOLOR_SILVER - "Grey", // SKINCOLOR_GREY - "Black", // SKINCOLOR_BLACK - "Cyan", // SKINCOLOR_CYAN - "Teal", // SKINCOLOR_TEAL - "Steel_Blue",// SKINCOLOR_STEEL - "Blue", // SKINCOLOR_BLUE - "Peach", // SKINCOLOR_PEACH - "Tan", // SKINCOLOR_TAN - "Pink", // SKINCOLOR_PINK - "Lavender", // SKINCOLOR_LAVENDER - "Purple", // SKINCOLOR_PURPLE - "Orange", // SKINCOLOR_ORANGE - "Rosewood", // SKINCOLOR_ROSEWOOD - "Beige", // SKINCOLOR_BEIGE - "Brown", // SKINCOLOR_BROWN - "Red", // SKINCOLOR_RED - "Dark_Red", // SKINCOLOR_DARKRED - "Neon_Green",// SKINCOLOR_NEONGREEN - "Green", // SKINCOLOR_GREEN - "Zim", // SKINCOLOR_ZIM - "Olive", // SKINCOLOR_OLIVE - "Yellow", // SKINCOLOR_YELLOW - "Gold" // SKINCOLOR_GOLD -}; - -const UINT8 Color_Opposite[MAXSKINCOLORS*2] = -{ - SKINCOLOR_NONE,8, // SKINCOLOR_NONE - SKINCOLOR_BLACK,10, // SKINCOLOR_WHITE - SKINCOLOR_GREY,4, // SKINCOLOR_SILVER - SKINCOLOR_SILVER,12,// SKINCOLOR_GREY - SKINCOLOR_WHITE,8, // SKINCOLOR_BLACK - SKINCOLOR_NONE,8, // SKINCOLOR_CYAN - SKINCOLOR_NONE,8, // SKINCOLOR_TEAL - SKINCOLOR_NONE,8, // SKINCOLOR_STEEL - SKINCOLOR_ORANGE,9, // SKINCOLOR_BLUE - SKINCOLOR_NONE,8, // SKINCOLOR_PEACH - SKINCOLOR_NONE,8, // SKINCOLOR_TAN - SKINCOLOR_NONE,8, // SKINCOLOR_PINK - SKINCOLOR_NONE,8, // SKINCOLOR_LAVENDER - SKINCOLOR_NONE,8, // SKINCOLOR_PURPLE - SKINCOLOR_BLUE,12, // SKINCOLOR_ORANGE - SKINCOLOR_NONE,8, // SKINCOLOR_ROSEWOOD - SKINCOLOR_NONE,8, // SKINCOLOR_BEIGE - SKINCOLOR_NONE,8, // SKINCOLOR_BROWN - SKINCOLOR_GREEN,5, // SKINCOLOR_RED - SKINCOLOR_NONE,8, // SKINCOLOR_DARKRED - SKINCOLOR_NONE,8, // SKINCOLOR_NEONGREEN - SKINCOLOR_RED,11, // SKINCOLOR_GREEN - SKINCOLOR_PURPLE,3, // SKINCOLOR_ZIM - SKINCOLOR_NONE,8, // SKINCOLOR_OLIVE - SKINCOLOR_NONE,8, // SKINCOLOR_YELLOW - SKINCOLOR_NONE,8 // SKINCOLOR_GOLD -}; -*/ +// SKINCOLOR DEFINITIONS HAVE BEEN MOVED TO K_KART.C CV_PossibleValue_t Color_cons_t[MAXSKINCOLORS+1]; @@ -239,280 +176,6 @@ void R_InitTranslationTables(void) #endif } - -/** \brief Generates a translation colormap. - - \param dest_colormap colormap to populate - \param skinnum number of skin, TC_DEFAULT or TC_BOSS - \param color translation color - - \return void -*/ -/* -static void R_GenerateTranslationColormap(UINT8 *dest_colormap, INT32 skinnum, UINT8 color) -{ - // Table of indices into the palette of the first entries of each translated ramp - const UINT8 skinbasecolors[] = { - 0x00, // SKINCOLOR_WHITE - 0x03, // SKINCOLOR_SILVER - 0x08, // SKINCOLOR_GREY - 0x18, // SKINCOLOR_BLACK - 0xd0, // SKINCOLOR_CYAN - 0xdc, // SKINCOLOR_TEAL - 0xc8, // SKINCOLOR_STEEL - 0xe2, // SKINCOLOR_BLUE - 0x40, // SKINCOLOR_PEACH - 0x48, // SKINCOLOR_TAN - 0x90, // SKINCOLOR_PINK - 0xf8, // SKINCOLOR_LAVENDER - 0xc0, // SKINCOLOR_PURPLE - 0x52, // SKINCOLOR_ORANGE - 0x5c, // SKINCOLOR_ROSEWOOD - 0x20, // SKINCOLOR_BEIGE - 0x30, // SKINCOLOR_BROWN - 0x7d, // SKINCOLOR_RED - 0x85, // SKINCOLOR_DARKRED - 0xb8, // SKINCOLOR_NEONGREEN - 0xa0, // SKINCOLOR_GREEN - 0xb0, // SKINCOLOR_ZIM - 0x69, // SKINCOLOR_OLIVE - 0x67, // SKINCOLOR_YELLOW - 0x70, // SKINCOLOR_GOLD - }; - INT32 i; - INT32 starttranscolor; - - // Handle a couple of simple special cases - if (skinnum == TC_BOSS || skinnum == TC_ALLWHITE || skinnum == TC_METALSONIC || color == SKINCOLOR_NONE) - { - for (i = 0; i < NUM_PALETTE_ENTRIES; i++) - { - if (skinnum == TC_ALLWHITE) dest_colormap[i] = 0; - else dest_colormap[i] = (UINT8)i; - } - - // White! - if (skinnum == TC_BOSS) - dest_colormap[31] = 0; - else if (skinnum == TC_METALSONIC) - dest_colormap[239] = 0; - - return; - } - - starttranscolor = (skinnum != TC_DEFAULT) ? skins[skinnum].starttranscolor : DEFAULT_STARTTRANSCOLOR; - - // Fill in the entries of the palette that are fixed - for (i = 0; i < starttranscolor; i++) - dest_colormap[i] = (UINT8)i; - - for (i = (UINT8)(starttranscolor + 16); i < NUM_PALETTE_ENTRIES; i++) - dest_colormap[i] = (UINT8)i; - - // Build the translated ramp - switch (color) - { - case SKINCOLOR_SILVER: - case SKINCOLOR_GREY: - case SKINCOLOR_PEACH: - case SKINCOLOR_BEIGE: - case SKINCOLOR_BROWN: - case SKINCOLOR_RED: - case SKINCOLOR_GREEN: - case SKINCOLOR_BLUE: - // 16 color ramp - for (i = 0; i < SKIN_RAMP_LENGTH; i++) - dest_colormap[starttranscolor + i] = (UINT8)(skinbasecolors[color - 1] + i); - break; - - case SKINCOLOR_ORANGE: - // 14 colors of orange + brown - for (i = 0; i < SKIN_RAMP_LENGTH-2; i++) - dest_colormap[starttranscolor + i] = (UINT8)(skinbasecolors[color - 1] + i); - for (i = 0; i < 2; i++) - dest_colormap[starttranscolor + (i+SKIN_RAMP_LENGTH-2)] = (UINT8)(152 + i); - break; - - case SKINCOLOR_CYAN: - // 12 color ramp - for (i = 0; i < SKIN_RAMP_LENGTH; i++) - dest_colormap[starttranscolor + i] = (UINT8)(skinbasecolors[color - 1] + (12*i/SKIN_RAMP_LENGTH)); - break; - - case SKINCOLOR_WHITE: - case SKINCOLOR_BLACK: - case SKINCOLOR_STEEL: - case SKINCOLOR_PINK: - case SKINCOLOR_LAVENDER: - case SKINCOLOR_PURPLE: - case SKINCOLOR_DARKRED: - case SKINCOLOR_ZIM: - case SKINCOLOR_YELLOW: - case SKINCOLOR_GOLD: - // 8 color ramp - for (i = 0; i < SKIN_RAMP_LENGTH; i++) - dest_colormap[starttranscolor + i] = (UINT8)(skinbasecolors[color - 1] + (i >> 1)); - break; - - case SKINCOLOR_TEAL: - // 5 color ramp - for (i = 0; i < SKIN_RAMP_LENGTH; i++) - { - if (5*i/16 == 0) - dest_colormap[starttranscolor + i] = 0xf7; - else - dest_colormap[starttranscolor + i] = (UINT8)(skinbasecolors[color - 1] + (5*i/SKIN_RAMP_LENGTH) - 1); - } - break; - - case SKINCOLOR_OLIVE: - // 7 color ramp - for (i = 0; i < SKIN_RAMP_LENGTH; i++) - dest_colormap[starttranscolor + i] = (UINT8)(skinbasecolors[color - 1] + (7*i/SKIN_RAMP_LENGTH)); - break; - - case SKINCOLOR_TAN: - // 16 color ramp, from two color ranges - for (i = 0; i < SKIN_RAMP_LENGTH/2; i++) // Peach half - dest_colormap[starttranscolor + i] = (UINT8)(skinbasecolors[color - 1] + i); - for (i = 0; i < SKIN_RAMP_LENGTH/2; i++) // Brown half - dest_colormap[starttranscolor + (i+8)] = (UINT8)(48 + i); - break; - - case SKINCOLOR_ROSEWOOD: - // 12 color ramp, from two color ranges! - for (i = 0; i < 6; i++) // Orange ...third? - dest_colormap[starttranscolor + i] = (UINT8)(skinbasecolors[color - 1] + (12*i/SKIN_RAMP_LENGTH)); - for (i = 0; i < 10; i++) // Rosewood two-thirds-ish - dest_colormap[starttranscolor + (i+6)] = (UINT8)(152 + (12*i/SKIN_RAMP_LENGTH)); - break; - - case SKINCOLOR_NEONGREEN: - // Multi-color ramp - dest_colormap[starttranscolor] = 0xA0; // Brighter green - for (i = 0; i < SKIN_RAMP_LENGTH-1; i++) // Neon Green - dest_colormap[starttranscolor + (i+1)] = (UINT8)(skinbasecolors[color - 1] + (6*i/(SKIN_RAMP_LENGTH-1))); - break; - - // Super colors, from lightest to darkest! - case SKINCOLOR_SUPER1: - // Super White - for (i = 0; i < 10; i++) - dest_colormap[starttranscolor + i] = 120; // True white - for (; i < SKIN_RAMP_LENGTH; i++) // White-yellow fade - dest_colormap[starttranscolor + i] = (UINT8)(96 + (i-10)); - break; - - case SKINCOLOR_SUPER2: - // Super Bright - for (i = 0; i < 5; i++) // White-yellow fade - dest_colormap[starttranscolor + i] = (UINT8)(96 + i); - dest_colormap[starttranscolor + 5] = 112; // Golden shine - for (i = 0; i < 8; i++) // Yellow - dest_colormap[starttranscolor + (i+6)] = (UINT8)(101 + (i>>1)); - for (i = 0; i < 2; i++) // With a fine golden finish! :3 - dest_colormap[starttranscolor + (i+14)] = (UINT8)(113 + i); - break; - - case SKINCOLOR_SUPER3: - // Super Yellow - for (i = 0; i < 3; i++) // White-yellow fade - dest_colormap[starttranscolor + i] = (UINT8)(98 + i); - dest_colormap[starttranscolor + 3] = 112; // Golden shine - for (i = 0; i < 8; i++) // Yellow - dest_colormap[starttranscolor + (i+4)] = (UINT8)(101 + (i>>1)); - for (i = 0; i < 4; i++) // With a fine golden finish! :3 - dest_colormap[starttranscolor + (i+12)] = (UINT8)(113 + i); - break; - - case SKINCOLOR_SUPER4: - // "The SSNTails" - dest_colormap[starttranscolor] = 112; // Golden shine - for (i = 0; i < 8; i++) // Yellow - dest_colormap[starttranscolor + (i+1)] = (UINT8)(101 + (i>>1)); - for (i = 0; i < 7; i++) // With a fine golden finish! :3 - dest_colormap[starttranscolor + (i+9)] = (UINT8)(113 + i); - break; - - case SKINCOLOR_SUPER5: - // Golden Delicious - for (i = 0; i < 8; i++) // Yellow - dest_colormap[starttranscolor + i] = (UINT8)(101 + (i>>1)); - for (i = 0; i < 7; i++) // With a fine golden finish! :3 - dest_colormap[starttranscolor + (i+8)] = (UINT8)(113 + i); - dest_colormap[starttranscolor + 15] = 155; - break; - - // Super Tails - case SKINCOLOR_TSUPER1: - for (i = 0; i < 10; i++) // white - dest_colormap[starttranscolor + i] = 120; - for (; i < SKIN_RAMP_LENGTH; i++) // orange - dest_colormap[starttranscolor + i] = (UINT8)(80 + (i-10)); - break; - - case SKINCOLOR_TSUPER2: - for (i = 0; i < 4; i++) // white - dest_colormap[starttranscolor + i] = 120; - for (; i < SKIN_RAMP_LENGTH; i++) // orange - dest_colormap[starttranscolor + i] = (UINT8)(80 + ((i-4)>>1)); - break; - - case SKINCOLOR_TSUPER3: - dest_colormap[starttranscolor] = 120; // pure white - dest_colormap[starttranscolor+1] = 120; - for (i = 2; i < SKIN_RAMP_LENGTH; i++) // orange - dest_colormap[starttranscolor + i] = (UINT8)(80 + ((i-2)>>1)); - break; - - case SKINCOLOR_TSUPER4: - dest_colormap[starttranscolor] = 120; // pure white - for (i = 1; i < 9; i++) // orange - dest_colormap[starttranscolor + i] = (UINT8)(80 + (i-1)); - for (; i < SKIN_RAMP_LENGTH; i++) // gold - dest_colormap[starttranscolor + i] = (UINT8)(115 + (5*(i-9)/7)); - break; - - case SKINCOLOR_TSUPER5: - for (i = 0; i < 8; i++) // orange - dest_colormap[starttranscolor + i] = (UINT8)(80 + i); - for (; i < SKIN_RAMP_LENGTH; i++) // gold - dest_colormap[starttranscolor + i] = (UINT8)(115 + (5*(i-8)/8)); - break; - - // Super Knuckles - case SKINCOLOR_KSUPER1: - for (i = 0; i < SKIN_RAMP_LENGTH; i++) - dest_colormap[starttranscolor + i] = (UINT8)(120 + (i >> 2)); - break; - - case SKINCOLOR_KSUPER2: - for (i = 0; i < SKIN_RAMP_LENGTH; i++) - dest_colormap[starttranscolor + i] = (UINT8)(120 + (6*i/SKIN_RAMP_LENGTH)); - break; - - case SKINCOLOR_KSUPER3: - for (i = 0; i < SKIN_RAMP_LENGTH; i++) - dest_colormap[starttranscolor + i] = (UINT8)(120 + (i >> 1)); - break; - - case SKINCOLOR_KSUPER4: - for (i = 0; i < SKIN_RAMP_LENGTH; i++) - dest_colormap[starttranscolor + i] = (UINT8)(121 + (i >> 1)); - break; - - case SKINCOLOR_KSUPER5: - for (i = 0; i < SKIN_RAMP_LENGTH; i++) - dest_colormap[starttranscolor + i] = (UINT8)(122 + (i >> 1)); - break; - - default: - I_Error("Invalid skin color #%hu.", (UINT16)color); - break; - } -} -*/ - /** \brief Retrieves a translation colormap from the cache. \param skinnum number of skin, TC_DEFAULT or TC_BOSS diff --git a/src/r_draw8.c b/src/r_draw8.c index 634ae7075..ef67dbaf7 100644 --- a/src/r_draw8.c +++ b/src/r_draw8.c @@ -105,7 +105,7 @@ void R_DrawColumn_8(void) } } -#define TRANSPARENTPIXEL 247 +#define TRANSPARENTPIXEL 255 void R_Draw2sMultiPatchColumn_8(void) { diff --git a/src/r_main.c b/src/r_main.c index 358a24bb8..0d14bed73 100644 --- a/src/r_main.c +++ b/src/r_main.c @@ -1331,7 +1331,7 @@ void R_RenderPlayerView(player_t *player) if (cv_homremoval.value == 1) V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31); // No HOM effect! else //'development' HOM removal -- makes it blindingly obvious if HOM is spotted. - V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 128+(timeinmap&15)); + V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 32+(timeinmap&15)); } // Draw over the fourth screen so you don't have to stare at a HOM :V else if (splitscreen == 2 && player == &players[displayplayers[2]]) diff --git a/src/r_things.c b/src/r_things.c index b2170924e..1afbb125c 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -42,8 +42,6 @@ int snprintf(char *str, size_t n, const char *fmt, ...); CV_PossibleValue_t Forceskin_cons_t[MAXSKINS+2]; -static void R_InitSkins(void); - #define MINZ (FRACUNIT*4) #define BASEYCENTER (BASEVIDHEIGHT/2) @@ -585,7 +583,17 @@ void R_InitSprites(void) // // it can be is do before loading config for skin cvar possible value - R_InitSkins(); + // (... what the fuck did you just say to me? "it can be is do"?) +#ifdef SKINVALUES + for (i = 0; i <= MAXSKINS; i++) + { + skin_cons_t[i].value = 0; + skin_cons_t[i].strvalue = NULL; + } +#endif + + numskins = 0; + for (i = 0; i < numwadfiles; i++) R_AddSkins((UINT16)i); @@ -820,7 +828,7 @@ static void R_DrawVisSprite(vissprite_t *vis) colfunc = basecolfunc; // hack: this isn't resetting properly somewhere. dc_colormap = vis->colormap; - if ((vis->mobj->flags & MF_BOSS) && (vis->mobj->flags2 & MF2_FRET) && (leveltime & 1)) // Bosses "flash" + if (!(vis->cut & SC_PRECIP) && (vis->mobj->flags & MF_BOSS) && (vis->mobj->flags2 & MF2_FRET) && (leveltime & 1)) // Bosses "flash" { // translate certain pixels to white colfunc = transcolfunc; @@ -891,18 +899,18 @@ static void R_DrawVisSprite(vissprite_t *vis) frac = vis->startfrac; windowtop = windowbottom = sprbotscreen = INT32_MAX; - if (vis->mobj->skin && ((skin_t *)vis->mobj->skin)->flags & SF_HIRES) + if (!(vis->cut & SC_PRECIP) && vis->mobj->skin && ((skin_t *)vis->mobj->skin)->flags & SF_HIRES) this_scale = FixedMul(this_scale, ((skin_t *)vis->mobj->skin)->highresscale); if (this_scale <= 0) this_scale = 1; if (this_scale != FRACUNIT) { - if (!vis->isScaled) + if (!(vis->cut & SC_ISSCALED)) { vis->scale = FixedMul(vis->scale, this_scale); vis->scalestep = FixedMul(vis->scalestep, this_scale); vis->xiscale = FixedDiv(vis->xiscale,this_scale); - vis->isScaled = true; + vis->cut |= SC_ISSCALED; } dc_texturemid = FixedDiv(dc_texturemid,this_scale); } @@ -955,7 +963,7 @@ static void R_DrawVisSprite(vissprite_t *vis) #else column = (column_t *)((UINT8 *)patch + LONG(patch->columnofs[frac>>FRACBITS])); #endif - if (vis->vflip) + if (vis->cut & SC_VFLIP) R_DrawFlippedMaskedColumn(column, patch->height); else R_DrawMaskedColumn(column); @@ -1035,7 +1043,7 @@ static void R_DrawPrecipitationVisSprite(vissprite_t *vis) // // R_SplitSprite // runs through a sector's lightlist and -static void R_SplitSprite(vissprite_t *sprite, mobj_t *thing) +static void R_SplitSprite(vissprite_t *sprite) { INT32 i, lightnum, lindex; INT16 cutfrac; @@ -1071,6 +1079,8 @@ static void R_SplitSprite(vissprite_t *sprite, mobj_t *thing) // adjust the heights. newsprite = M_Memcpy(R_NewVisSprite(), sprite, sizeof (vissprite_t)); + newsprite->cut |= (sprite->cut & SC_FLAGMASK); + sprite->cut |= SC_BOTTOM; sprite->gz = testheight; @@ -1110,13 +1120,17 @@ static void R_SplitSprite(vissprite_t *sprite, mobj_t *thing) ; else */ - if (!((thing->frame & (FF_FULLBRIGHT|FF_TRANSMASK) || thing->flags2 & MF2_SHADOW) + if (!((newsprite->cut & SC_FULLBRIGHT) && (!newsprite->extra_colormap || !(newsprite->extra_colormap->fog & 1)))) { lindex = FixedMul(sprite->xscale, FixedDiv(640, vid.width))>>(LIGHTSCALESHIFT); if (lindex >= MAXLIGHTSCALE) lindex = MAXLIGHTSCALE-1; + + if (newsprite->cut & SC_SEMIBRIGHT) + lindex = (MAXLIGHTSCALE/2) + (lindex >> 1); + newsprite->colormap = spritelights[lindex]; } } @@ -1144,6 +1158,7 @@ static void R_ProjectSprite(mobj_t *thing) size_t rot; UINT8 flip; + boolean vflip = (!(thing->eflags & MFE_VERTICALFLIP) != !(thing->frame & FF_VERTICALFLIP)); INT32 lindex; @@ -1349,7 +1364,7 @@ static void R_ProjectSprite(mobj_t *thing) } //SoM: 3/17/2000: Disregard sprites that are out of view.. - if (thing->eflags & MFE_VERTICALFLIP) + if (vflip) { // When vertical flipped, draw sprites from the top down, at least as far as offsets are concerned. // sprite height - sprite topoffset is the proper inverse of the vertical offset, of course. @@ -1491,7 +1506,12 @@ static void R_ProjectSprite(mobj_t *thing) else if (thing->frame & FF_TRANSMASK) vis->transmap = transtables + (thing->frame & FF_TRANSMASK) - 0x10000; - if (((thing->frame & FF_FULLBRIGHT) || (thing->flags2 & MF2_SHADOW)) + if (thing->frame & FF_FULLBRIGHT || thing->flags2 & MF2_SHADOW) + vis->cut |= SC_FULLBRIGHT; + else if (thing->frame & FF_SEMIBRIGHT) + vis->cut |= SC_SEMIBRIGHT; + + if (vis->cut & SC_FULLBRIGHT && (!vis->extra_colormap || !(vis->extra_colormap->fog & 1))) { // full bright: goggles @@ -1505,20 +1525,17 @@ static void R_ProjectSprite(mobj_t *thing) if (lindex >= MAXLIGHTSCALE) lindex = MAXLIGHTSCALE-1; + if (vis->cut & SC_SEMIBRIGHT) + lindex = (MAXLIGHTSCALE/2) + (lindex >> 1); + vis->colormap = spritelights[lindex]; } - vis->precip = false; - - if (thing->eflags & MFE_VERTICALFLIP) - vis->vflip = true; - else - vis->vflip = false; - - vis->isScaled = false; + if (vflip) + vis->cut |= SC_VFLIP; if (thing->subsector->sector->numlights) - R_SplitSprite(vis, thing); + R_SplitSprite(vis); // Debug ++objectsdrawn; @@ -1690,15 +1707,12 @@ static void R_ProjectPrecipitationSprite(precipmobj_t *thing) vis->transmap = NULL; vis->mobjflags = 0; - vis->cut = SC_NONE; + vis->cut = SC_PRECIP; vis->extra_colormap = thing->subsector->sector->extra_colormap; vis->heightsec = thing->subsector->sector->heightsec; // Fullbright vis->colormap = colormaps; - vis->precip = true; - vis->vflip = false; - vis->isScaled = false; } // R_AddSprites @@ -2484,7 +2498,7 @@ void R_DrawMasked(void) next = r2->prev; // Tails 08-18-2002 - if (r2->sprite->precip == true) + if (r2->sprite->cut & SC_PRECIP) R_DrawPrecipitationSprite(r2->sprite); else R_DrawSprite(r2->sprite); @@ -2531,7 +2545,7 @@ static void Sk_SetDefaultValue(skin_t *skin) strncpy(skin->facewant, "PLAYWANT", 9); strncpy(skin->facemmap, "PLAYMMAP", 9); - skin->starttranscolor = 160; + skin->starttranscolor = 96; skin->prefcolor = SKINCOLOR_GREEN; // SRB2kart @@ -2546,61 +2560,6 @@ static void Sk_SetDefaultValue(skin_t *skin) skin->soundsid[S_sfx[i].skinsound] = i; } -// -// Initialize the basic skins -// -void R_InitSkins(void) -{ - skin_t *skin; -#ifdef SKINVALUES - INT32 i; - - for (i = 0; i <= MAXSKINS; i++) - { - skin_cons_t[i].value = 0; - skin_cons_t[i].strvalue = NULL; - } -#endif - - // skin[0] = Sonic skin - skin = &skins[0]; - numskins = 1; - Sk_SetDefaultValue(skin); - - // Hardcoded S_SKIN customizations for Sonic. - strcpy(skin->name, DEFAULTSKIN); -#ifdef SKINVALUES - skin_cons_t[0].strvalue = skins[0].name; -#endif - skin->flags = 0; - strcpy(skin->realname, "Sonic"); - strcpy(skin->hudname, "SONIC"); - - strncpy(skin->facerank, "PLAYRANK", 9); - strncpy(skin->facewant, "PLAYWANT", 9); - strncpy(skin->facemmap, "PLAYMMAP", 9); - skin->prefcolor = SKINCOLOR_BLUE; - - // SRB2kart - skin->kartspeed = 8; - skin->kartweight = 2; - // - - skin->spritedef.numframes = sprites[SPR_PLAY].numframes; - skin->spritedef.spriteframes = sprites[SPR_PLAY].spriteframes; - ST_LoadFaceGraphics(skin->facerank, skin->facewant, skin->facemmap, 0); - - // Set values for Sonic skin - Forceskin_cons_t[1].value = 0; - Forceskin_cons_t[1].strvalue = skin->name; - - //MD2 for sonic doesn't want to load in Linux. -#ifdef HWRENDER - if (rendermode == render_opengl) - HWR_AddPlayerMD2(0); -#endif -} - // returns true if the skin name is found (loaded from pwad) // warning return -1 if not found INT32 R_SkinAvailable(const char *name) diff --git a/src/r_things.h b/src/r_things.h index 697cde256..4837b4aee 100644 --- a/src/r_things.h +++ b/src/r_things.h @@ -104,9 +104,20 @@ extern CV_PossibleValue_t Forceskin_cons_t[]; // ----------- typedef enum { + // actual cuts SC_NONE = 0, SC_TOP = 1, - SC_BOTTOM = 2 + SC_BOTTOM = 1<<1, + // other flags + SC_PRECIP = 1<<2, + //SC_LINKDRAW = 1<<3, -- 2.2 compat + SC_FULLBRIGHT = 1<<4, + SC_SEMIBRIGHT = 1<<5, + SC_VFLIP = 1<<6, + SC_ISSCALED = 1>>7, + // masks + SC_CUTMASK = SC_TOP|SC_BOTTOM, + SC_FLAGMASK = ~SC_CUTMASK } spritecut_e; // A vissprite_t is a thing that will be drawn during a refresh, @@ -155,9 +166,6 @@ typedef struct vissprite_s INT16 clipbot[MAXVIDWIDTH], cliptop[MAXVIDWIDTH]; - boolean precip; - boolean vflip; // Flip vertically - boolean isScaled; INT32 dispoffset; // copy of info->dispoffset, affects ordering but not drawing } vissprite_t; diff --git a/src/sdl/i_system.c b/src/sdl/i_system.c index c0fca64da..d24bd5ade 100644 --- a/src/sdl/i_system.c +++ b/src/sdl/i_system.c @@ -131,7 +131,7 @@ typedef LPVOID (WINAPI *p_MapViewOfFile) (HANDLE, DWORD, DWORD, DWORD, SIZE_T); #include #endif -// Locations for searching the srb2.srb +// Locations for searching for main.kart #if defined (__unix__) || defined(__APPLE__) || defined (UNIXCOMMON) #define DEFAULTWADLOCATION1 "/usr/local/share/games/SRB2Kart" #define DEFAULTWADLOCATION2 "/usr/local/games/SRB2Kart" @@ -149,8 +149,7 @@ typedef LPVOID (WINAPI *p_MapViewOfFile) (HANDLE, DWORD, DWORD, DWORD, SIZE_T); /** \brief WAD file to look for */ -#define WADKEYWORD1 "srb2.srb" -#define WADKEYWORD2 "srb2.wad" +#define WADKEYWORD "main.kart" /** \brief holds wad path */ static char returnWadPath[256]; @@ -3454,15 +3453,7 @@ static boolean isWadPathOk(const char *path) if (!wad3path) return false; - sprintf(wad3path, pandf, path, WADKEYWORD1); - - if (FIL_ReadFileOK(wad3path)) - { - free(wad3path); - return true; - } - - sprintf(wad3path, pandf, path, WADKEYWORD2); + sprintf(wad3path, pandf, path, WADKEYWORD); if (FIL_ReadFileOK(wad3path)) { @@ -3487,7 +3478,7 @@ static void pathonly(char *s) } } -/** \brief search for srb2.srb in the given path +/** \brief search for main.kart in the given path \param searchDir starting path @@ -3500,7 +3491,7 @@ static const char *searchWad(const char *searchDir) static char tempsw[256] = ""; filestatus_t fstemp; - strcpy(tempsw, WADKEYWORD1); + strcpy(tempsw, WADKEYWORD); fstemp = filesearch(tempsw,searchDir,NULL,true,20); if (fstemp == FS_FOUND) { @@ -3508,19 +3499,12 @@ static const char *searchWad(const char *searchDir) return tempsw; } - strcpy(tempsw, WADKEYWORD2); - fstemp = filesearch(tempsw, searchDir, NULL, true, 20); - if (fstemp == FS_FOUND) - { - pathonly(tempsw); - return tempsw; - } return NULL; } -/** \brief go through all possible paths and look for srb2.srb +/** \brief go through all possible paths and look for main.kart - \return path to srb2.srb if any + \return path to main.kart if any */ static const char *locateWad(void) { @@ -3649,7 +3633,7 @@ const char *I_LocateWad(void) if (waddir) { - // change to the directory where we found srb2.srb + // change to the directory where we found main.kart #if defined (_WIN32) SetCurrentDirectoryA(waddir); #else diff --git a/src/sdl12/i_system.c b/src/sdl12/i_system.c index d055a4ca5..62256f3a5 100644 --- a/src/sdl12/i_system.c +++ b/src/sdl12/i_system.c @@ -145,7 +145,7 @@ void __set_fpscr(long); // in libgcc / kernel's startup.s? #define O_BINARY 0 #endif -// Locations for searching the srb2.srb +// Locations for searching the main.kart #ifdef _arch_dreamcast #define DEFAULTWADLOCATION1 "/cd" #define DEFAULTWADLOCATION2 "/pc" @@ -217,8 +217,7 @@ void __set_fpscr(long); // in libgcc / kernel's startup.s? /** \brief WAD file to look for */ -#define WADKEYWORD1 "srb2.srb" -#define WADKEYWORD2 "srb2.wad" +#define WADKEYWORD "main.kart" /** \brief holds wad path */ static char returnWadPath[256]; @@ -3398,15 +3397,7 @@ static boolean isWadPathOk(const char *path) if (!wad3path) return false; - sprintf(wad3path, pandf, path, WADKEYWORD1); - - if (FIL_ReadFileOK(wad3path)) - { - free(wad3path); - return true; - } - - sprintf(wad3path, pandf, path, WADKEYWORD2); + sprintf(wad3path, pandf, path, WADKEYWORD); if (FIL_ReadFileOK(wad3path)) { @@ -3431,7 +3422,7 @@ static void pathonly(char *s) } } -/** \brief search for srb2.srb in the given path +/** \brief search for main.kart in the given path \param searchDir starting path @@ -3444,7 +3435,7 @@ static const char *searchWad(const char *searchDir) static char tempsw[256] = ""; filestatus_t fstemp; - strcpy(tempsw, WADKEYWORD1); + strcpy(tempsw, WADKEYWORD); fstemp = filesearch(tempsw,searchDir,NULL,true,20); if (fstemp == FS_FOUND) { @@ -3452,19 +3443,12 @@ static const char *searchWad(const char *searchDir) return tempsw; } - strcpy(tempsw, WADKEYWORD2); - fstemp = filesearch(tempsw, searchDir, NULL, true, 20); - if (fstemp == FS_FOUND) - { - pathonly(tempsw); - return tempsw; - } return NULL; } -/** \brief go through all possible paths and look for srb2.srb +/** \brief go through all possible paths and look for main.kart - \return path to srb2.srb if any + \return path to main.kart if any */ static const char *locateWad(void) { @@ -3581,7 +3565,7 @@ const char *I_LocateWad(void) if (waddir) { - // change to the directory where we found srb2.srb + // change to the directory where we found main.kart #if (defined (_WIN32) && !defined (_WIN32_WCE)) && !defined (_XBOX) SetCurrentDirectoryA(waddir); #elif !defined (_WIN32_WCE) && !defined (_PS3) diff --git a/src/st_stuff.c b/src/st_stuff.c index 50bac3eef..e59846aed 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -2138,8 +2138,8 @@ void ST_Drawer(void) if (timeinmap < 15) { if (timeinmap <= 5) - V_DrawFill(0,0,BASEVIDWIDTH,BASEVIDHEIGHT,120); // Pure white on first few frames, to hide SRB2's awful level load artifacts + V_DrawFill(0,0,BASEVIDWIDTH,BASEVIDHEIGHT,0); // Pure white on first few frames, to hide SRB2's awful level load artifacts else - V_DrawFadeScreen(120, 15-timeinmap); // Then gradually fade out from there + V_DrawFadeScreen(0, 15-timeinmap); // Then gradually fade out from there } } diff --git a/src/tmap.nas b/src/tmap.nas index 78840106f..c72c1890a 100644 --- a/src/tmap.nas +++ b/src/tmap.nas @@ -17,7 +17,7 @@ [BITS 32] %define FRACBITS 16 -%define TRANSPARENTPIXEL 247 +%define TRANSPARENTPIXEL 255 %ifdef LINUX %macro cextern 1 diff --git a/src/tmap_mmx.nas b/src/tmap_mmx.nas index 39380a065..c512de8e9 100644 --- a/src/tmap_mmx.nas +++ b/src/tmap_mmx.nas @@ -18,7 +18,7 @@ [BITS 32] %define FRACBITS 16 -%define TRANSPARENTPIXEL 247 +%define TRANSPARENTPIXEL 255 %ifdef LINUX %macro cextern 1 diff --git a/src/v_video.c b/src/v_video.c index 9233eda42..1b1d03baa 100644 --- a/src/v_video.c +++ b/src/v_video.c @@ -1359,16 +1359,16 @@ UINT8 *V_GetStringColormap(INT32 colorflags) return lavendermap; case 10: // 0x8A, gold return goldmap; - case 11: // 0x8B, tea-green - return teamap; - case 12: // 0x8C, steel - return steelmap; + case 11: // 0x8B, aqua-green + return aquamap; + case 12: // 0x8C, magenta + return magentamap; case 13: // 0x8D, pink return pinkmap; case 14: // 0x8E, brown return brownmap; - case 15: // 0x8F, peach - return peachmap; + case 15: // 0x8F, tan + return tanmap; default: // reset return NULL; } diff --git a/src/v_video.h b/src/v_video.h index c8485c179..a48fed4d3 100644 --- a/src/v_video.h +++ b/src/v_video.h @@ -79,11 +79,11 @@ extern UINT8 hudtrans; #define V_SKYMAP 0x00008000 #define V_LAVENDERMAP 0x00009000 #define V_GOLDMAP 0x0000A000 -#define V_TEAMAP 0x0000B000 -#define V_STEELMAP 0x0000C000 +#define V_AQUAMAP 0x0000B000 +#define V_MAGENTAMAP 0x0000C000 #define V_PINKMAP 0x0000D000 #define V_BROWNMAP 0x0000E000 -#define V_PEACHMAP 0x0000F000 +#define V_TANMAP 0x0000F000 // use bits 17-20 for alpha transparency #define V_ALPHASHIFT 16 diff --git a/src/y_inter.c b/src/y_inter.c index 379694a11..c270f04ab 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -1083,7 +1083,7 @@ void Y_VoteDrawer(void) V_DrawMappedPatch(BASEVIDWIDTH-124, handy, V_SNAPTORIGHT, thiscurs, colormap); if (votetic % 10 < 4) - V_DrawFill(BASEVIDWIDTH-100-sizeadd, y-sizeadd, 80+(sizeadd*2), 50+(sizeadd*2), 120|V_SNAPTORIGHT); + V_DrawFill(BASEVIDWIDTH-100-sizeadd, y-sizeadd, 80+(sizeadd*2), 50+(sizeadd*2), 0|V_SNAPTORIGHT); else V_DrawFill(BASEVIDWIDTH-100-sizeadd, y-sizeadd, 80+(sizeadd*2), 50+(sizeadd*2), color|V_SNAPTORIGHT); @@ -1154,7 +1154,7 @@ void Y_VoteDrawer(void) { V_DrawScaledPatch(x-18, y+9, V_SNAPTOLEFT, cursor); if (voteendtic != -1 && !(votetic % 4)) - V_DrawFill(x-1, y-1, 42, 27, 120|V_SNAPTOLEFT); + V_DrawFill(x-1, y-1, 42, 27, 0|V_SNAPTOLEFT); else V_DrawFill(x-1, y-1, 42, 27, levelinfo[votes[i]].gtc|V_SNAPTOLEFT); }