diff --git a/src/Makefile b/src/Makefile index 9c6bb0be4..fee849d6c 100644 --- a/src/Makefile +++ b/src/Makefile @@ -60,6 +60,7 @@ # Compile with GCC 4.6x version, add 'GCC46=1' # Compile a profile version, add 'PROFILEMODE=1' # Compile a debug version, add 'DEBUGMODE=1' +# Compile for the testers group (they don't get to play unless we're watching *wink*), add 'TESTERS=1' # Compile with extra warnings, add 'WARNINGMODE=1' # Compile without NASM's tmap.nas, add 'NOASM=1' # Compile without 3D hardware support, add 'NOHW=1' @@ -434,6 +435,10 @@ else endif CFLAGS+=-g $(OPTS) $(ARCHOPTS) $(WINDRESFLAGS) +ifdef TESTERS + OPTS+=-DTESTERS +endif + ifdef YASM ifdef STABS NASMOPTS?= -g stabs diff --git a/src/d_clisrv.c b/src/d_clisrv.c index ffc5b5772..523c92778 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -3651,6 +3651,11 @@ boolean Playing(void) boolean SV_SpawnServer(void) { +#ifdef TESTERS + /* Just don't let the testers play. Easy. */ + I_Error("What do you think you're doing?"); + return false; +#else if (demo.playback) G_StopDemo(); // reset engine parameter if (metalplayback) @@ -3677,6 +3682,7 @@ boolean SV_SpawnServer(void) } return SV_AddWaitingPlayers(); +#endif } void SV_StopServer(void) diff --git a/src/d_main.c b/src/d_main.c index 5c8e34bde..05a9fa603 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -308,13 +308,6 @@ static void D_Display(void) wipedefindex = gamestate; // wipe_xxx_toblack if (gamestate == GS_TITLESCREEN && wipegamestate != GS_INTRO) wipedefindex = wipe_timeattack_toblack; - else if (gamestate == GS_INTERMISSION) - { - if (intertype == int_spec) // Special Stage - wipedefindex = wipe_specinter_toblack; - else //if (intertype != int_coop) // Multiplayer - wipedefindex = wipe_multinter_toblack; - } if (rendermode != render_none) { @@ -325,7 +318,7 @@ static void D_Display(void) F_WipeStartScreen(); V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31); F_WipeEndScreen(); - F_RunWipe(wipedefs[wipedefindex], gamestate != GS_TIMEATTACK); + F_RunWipe(wipedefs[wipedefindex], gamestate != GS_TIMEATTACK, "FADEMAP0", false, false); } if (gamestate != GS_LEVEL && rendermode != render_none) @@ -447,7 +440,7 @@ static void D_Display(void) { if (i > 0) // Splitscreen-specific { - switch (i) + switch (i) { case 1: if (splitscreen > 1) @@ -556,7 +549,7 @@ static void D_Display(void) if (rendermode != render_none) { F_WipeEndScreen(); - F_RunWipe(wipedefs[wipedefindex], gamestate != GS_TIMEATTACK); + F_RunWipe(wipedefs[wipedefindex], gamestate != GS_TIMEATTACK, "FADEMAP0", true, false); } } @@ -1190,12 +1183,12 @@ void D_SRB2Main(void) M_InitCharacterTables(); // load wad, including the main wad file - CONS_Printf("W_InitMultipleFiles(): Adding IWAD and main PWADs.\n"); + CONS_Printf("W_InitMultipleFiles(): Adding main IWAD and PWADs.\n"); if (!W_InitMultipleFiles(startupwadfiles, false)) #ifdef _DEBUG - CONS_Error("A WAD file was not found or not valid.\nCheck the log to see which ones.\n"); + CONS_Error("A main WAD file was not found or not valid.\nCheck the log to see which ones.\n"); #else - I_Error("A WAD file was not found or not valid.\nCheck the log to see which ones.\n"); + I_Error("A main WAD file was not found or not valid.\nCheck the log to see which ones.\n"); #endif D_CleanFile(startupwadfiles); @@ -1249,8 +1242,9 @@ void D_SRB2Main(void) } } + CONS_Printf("W_InitMultipleFiles(): Adding external PWADs.\n"); if (!W_InitMultipleFiles(startuppwads, true)) - CONS_Error("A PWAD file was not found or not valid.\nCheck the log to see which ones.\n"); + M_StartMessage(M_GetText("A PWAD file was not found or not valid.\nCheck log.txt to see which ones.\n\nPress ESC\n"), NULL, MM_NOTHING); D_CleanFile(startuppwads); // diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 752e4b919..a5085864e 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -415,7 +415,8 @@ consvar_t cv_itemfinder = {"itemfinder", "Off", CV_CALL|CV_NOSHOWHELP, CV_OnOff, // Scoring type options consvar_t cv_match_scoring = {"matchscoring", "Normal", CV_NETVAR|CV_CHEAT|CV_NOSHOWHELP, match_scoring_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; -consvar_t cv_overtime = {"overtime", "Yes", CV_NETVAR, CV_YesNo, NULL, 0, NULL, NULL, 0, 0, NULL}; +static CV_PossibleValue_t overtime_cons_t[] = {{0, "No"}, {1, "Yes"}, {2, "Super"}, {0, NULL}}; +consvar_t cv_overtime = {"overtime", "Yes", CV_NETVAR|CV_CHEAT, overtime_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_rollingdemos = {"rollingdemos", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; @@ -4790,8 +4791,8 @@ static void TimeLimit_OnChange(void) if (cv_timelimit.value != 0) { - CONS_Printf(M_GetText("Levels will end after %d minute%s.\n"),cv_timelimit.value,cv_timelimit.value == 1 ? "" : "s"); // Graue 11-17-2003 - timelimitintics = cv_timelimit.value * 60 * TICRATE; + CONS_Printf(M_GetText("Levels will end after %d second%s.\n"),cv_timelimit.value,cv_timelimit.value == 1 ? "" : "s"); // Graue 11-17-2003 + timelimitintics = cv_timelimit.value * TICRATE; //add hidetime for tag too! if (G_TagGametype()) @@ -4841,9 +4842,9 @@ void D_GameTypeChanged(INT32 lastgametype) case GT_TEAMMATCH: if (!cv_timelimit.changed && !cv_pointlimit.changed) // user hasn't changed limits { - // default settings for match: no timelimit, no pointlimit - CV_SetValue(&cv_pointlimit, 0); - CV_SetValue(&cv_timelimit, 0); + // default settings for match: 2 mins, no pointlimit + CV_SetValue(&cv_pointlimit, 0); + CV_SetValue(&cv_timelimit, 120); } if (!cv_itemrespawntime.changed) CV_Set(&cv_itemrespawntime, cv_itemrespawntime.defaultvalue); // respawn normally @@ -5149,7 +5150,7 @@ static void Hidetime_OnChange(void) //uh oh, gotta change timelimitintics now too if (G_TagGametype()) - timelimitintics = (cv_timelimit.value * 60 * TICRATE) + (hidetime * TICRATE); + timelimitintics = (cv_timelimit.value * TICRATE) + (hidetime * TICRATE); } static void Command_Showmap_f(void) diff --git a/src/d_player.h b/src/d_player.h index d2ed296ce..697c0356c 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -327,6 +327,10 @@ typedef enum k_jawztargetdelay, // Delay for Jawz target switching, to make it less twitchy k_spectatewait, // How long have you been waiting as a spectator k_growcancel, // Hold the item button down to cancel Grow + k_tiregrease, // Reduced friction timer after hitting a horizontal spring + k_springstars, // Spawn stars around a player when they hit a spring + k_springcolor, // Color of spring stars + k_killfield, // How long have you been in the kill field, stay in too long and lose a bumper NUMKARTSTUFF } kartstufftype_t; diff --git a/src/dehacked.c b/src/dehacked.c index b8f292a69..5f9249d89 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -1230,8 +1230,9 @@ static void readlevelheader(MYFILE *f, INT32 num) } else if (fastcmp(word, "WEATHER")) mapheaderinfo[num-1]->weather = (UINT8)get_number(word2); - else if (fastcmp(word, "SKYNUM")) - mapheaderinfo[num-1]->skynum = (INT16)i; + else if (fastcmp(word, "SKYTEXTURE")) + deh_strlcpy(mapheaderinfo[num-1]->skytexture, word2, + sizeof(mapheaderinfo[num-1]->skytexture), va("Level header %d: sky texture", num)); else if (fastcmp(word, "INTERSCREEN")) strncpy(mapheaderinfo[num-1]->interscreen, word2, 8); else if (fastcmp(word, "PRECUTSCENENUM")) @@ -3269,29 +3270,13 @@ static void readwipes(MYFILE *f) else if (fastcmp(pword, "FINAL")) wipeoffset = wipe_intermission_final; } - else if (fastncmp(word, "SPECINTER_", 10)) - { - pword = word + 10; - if (fastcmp(pword, "TOBLACK")) - wipeoffset = wipe_specinter_toblack; - else if (fastcmp(pword, "FINAL")) - wipeoffset = wipe_specinter_final; - } else if (fastncmp(word, "VOTING_", 7)) { pword = word + 7; if (fastcmp(pword, "TOBLACK")) - wipeoffset = wipe_specinter_toblack; + wipeoffset = wipe_voting_toblack; else if (fastcmp(pword, "FINAL")) - wipeoffset = wipe_specinter_final; - } - else if (fastncmp(word, "MULTINTER_", 10)) - { - pword = word + 10; - if (fastcmp(pword, "TOBLACK")) - wipeoffset = wipe_multinter_toblack; - else if (fastcmp(pword, "FINAL")) - wipeoffset = wipe_multinter_final; + wipeoffset = wipe_voting_final; } else if (fastncmp(word, "CONTINUING_", 11)) { @@ -3343,11 +3328,13 @@ static void readwipes(MYFILE *f) else if (fastcmp(pword, "FINAL")) wipeoffset = wipe_gameend_final; } - else if (fastncmp(word, "SPECLEVEL_", 10)) + else if (fastncmp(word, "ENCORE_", 7)) { - pword = word + 10; - if (fastcmp(pword, "TOWHITE")) - wipeoffset = wipe_speclevel_towhite; + pword = word + 7; + if (fastcmp(pword, "TOINVERT")) + wipeoffset = wipe_encore_toinvert; + else if (fastcmp(pword, "TOWHITE")) + wipeoffset = wipe_encore_towhite; } if (wipeoffset < 0) @@ -3357,10 +3344,10 @@ static void readwipes(MYFILE *f) } if (value == UINT8_MAX - && (wipeoffset <= wipe_level_toblack || wipeoffset >= wipe_speclevel_towhite)) + && (wipeoffset <= wipe_level_toblack || wipeoffset >= wipe_encore_toinvert)) { // Cannot disable non-toblack wipes - // (or the level toblack wipe, or the special towhite wipe) + // (or the level toblack wipe, or the special encore wipe) deh_warning("Wipes: can't disable wipe of type '%s'", word); continue; } @@ -5622,44 +5609,77 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_RBIRD2", "S_RBIRD3", - "S_YELLOWSPRING", + // Yellow Spring + "S_YELLOWSPRING1", "S_YELLOWSPRING2", "S_YELLOWSPRING3", "S_YELLOWSPRING4", - "S_YELLOWSPRING5", - "S_REDSPRING", + // Red Spring + "S_REDSPRING1", "S_REDSPRING2", "S_REDSPRING3", "S_REDSPRING4", - "S_REDSPRING5", - // Blue Springs - "S_BLUESPRING", + // Blue Spring + "S_BLUESPRING1", "S_BLUESPRING2", "S_BLUESPRING3", "S_BLUESPRING4", - "S_BLUESPRING5", + + // Grey Spring + "S_GREYSPRING1", + "S_GREYSPRING2", + "S_GREYSPRING3", + "S_GREYSPRING4", // Yellow Diagonal Spring "S_YDIAG1", "S_YDIAG2", "S_YDIAG3", "S_YDIAG4", - "S_YDIAG5", - "S_YDIAG6", - "S_YDIAG7", - "S_YDIAG8", // Red Diagonal Spring "S_RDIAG1", "S_RDIAG2", "S_RDIAG3", "S_RDIAG4", - "S_RDIAG5", - "S_RDIAG6", - "S_RDIAG7", - "S_RDIAG8", + + // Blue Diagonal Spring + "S_BDIAG1", + "S_BDIAG2", + "S_BDIAG3", + "S_BDIAG4", + + // Grey Diagonal Spring + "S_GDIAG1", + "S_GDIAG2", + "S_GDIAG3", + "S_GDIAG4", + + // Yellow Horizontal Spring + "S_YHORIZ1", + "S_YHORIZ2", + "S_YHORIZ3", + "S_YHORIZ4", + + // Red Horizontal Spring + "S_RHORIZ1", + "S_RHORIZ2", + "S_RHORIZ3", + "S_RHORIZ4", + + // Blue Horizontal Spring + "S_BHORIZ1", + "S_BHORIZ2", + "S_BHORIZ3", + "S_BHORIZ4", + + // Grey Horizontal Spring + "S_GHORIZ1", + "S_GHORIZ2", + "S_GHORIZ3", + "S_GHORIZ4", // Rain "S_RAIN1", @@ -6284,26 +6304,6 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_SRB1_GENREX1", "S_SRB1_GENREX2", - // Gray Springs - "S_GRAYSPRING", - "S_GRAYSPRING2", - "S_GRAYSPRING3", - "S_GRAYSPRING4", - "S_GRAYSPRING5", - - // Invis-spring - this is used just for the sproing sound. - "S_INVISSPRING", - - // Blue Diagonal Spring - "S_BDIAG1", - "S_BDIAG2", - "S_BDIAG3", - "S_BDIAG4", - "S_BDIAG5", - "S_BDIAG6", - "S_BDIAG7", - "S_BDIAG8", - //{ Random Item Box "S_RANDOMITEM1", "S_RANDOMITEM2", @@ -7212,6 +7212,12 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_DRAFTDUST4", "S_DRAFTDUST5", + "S_TIREGREASE", + + "S_OVERTIMEFOG", + "S_OVERTIMEORB", + "S_OVERTIMEBEAM", + #ifdef SEENAMES "S_NAMECHECK", #endif @@ -7341,11 +7347,18 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s // Springs and others "MT_FAN", "MT_STEAM", // Steam riser - "MT_BLUESPRING", "MT_YELLOWSPRING", "MT_REDSPRING", + "MT_BLUESPRING", + "MT_GREYSPRING", "MT_YELLOWDIAG", // Yellow Diagonal Spring "MT_REDDIAG", // Red Diagonal Spring + "MT_BLUEDIAG", // Blue Diagonal Spring + "MT_GREYDIAG", // Grey Diagonal Spring + "MT_YELLOWHORIZ", // Yellow Horizontal Spring + "MT_REDHORIZ", // Red Horizontal Spring + "MT_BLUEHORIZ", // Blue Horizontal Spring + "MT_GREYHORIZ", // Grey Horizontal Spring // Interactive Objects "MT_BUBBLES", // Bubble source @@ -7727,9 +7740,6 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s "MT_SRB1_GENREX", // SRB2kart - "MT_GRAYSPRING", - "MT_INVISSPRING", - "MT_BLUEDIAG", "MT_RANDOMITEM", "MT_RANDOMITEMPOP", "MT_FLOATINGITEM", @@ -8000,6 +8010,11 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s "MT_KARMAFIREWORK", "MT_RINGSPARKS", "MT_DRAFTDUST", + "MT_TIREGREASE", + + "MT_OVERTIMEFOG", + "MT_OVERTIMEORB", + "MT_OVERTIMEBEAM", #ifdef SEENAMES "MT_NAMECHECK", @@ -8486,7 +8501,11 @@ static const char *const KARTSTUFF_LIST[] = { "GETSPARKS", "JAWZTARGETDELAY", "SPECTATEWAIT", - "GROWCANCEL" + "GROWCANCEL", + "TIREGREASE", + "SPRINGSTARS", + "SPRINGCOLOR", + "KILLFIELD" }; #endif @@ -9916,11 +9935,11 @@ static inline int lib_getenum(lua_State *L) } else if (fastcmp(word,"globalweather")) { lua_pushinteger(L, globalweather); return 1; - } else if (fastcmp(word,"levelskynum")) { - lua_pushinteger(L, levelskynum); + } else if (fastcmp(word,"levelskytexture")) { + lua_pushstring(L, levelskytexture); return 1; - } else if (fastcmp(word,"globallevelskynum")) { - lua_pushinteger(L, globallevelskynum); + } else if (fastcmp(word,"globallevelskytexture")) { + lua_pushstring(L, globallevelskytexture); return 1; } else if (fastcmp(word,"mapmusname")) { lua_pushstring(L, mapmusname); diff --git a/src/doomstat.h b/src/doomstat.h index 4f410aa53..59e2bd5c4 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -227,7 +227,7 @@ typedef struct UINT32 muspos; ///< Music position to jump to. char forcecharacter[17]; ///< (SKINNAMESIZE+1) Skin to switch to or "" to disable. UINT8 weather; ///< 0 = sunny day, 1 = storm, 2 = snow, 3 = rain, 4 = blank, 5 = thunder w/o rain, 6 = rain w/o lightning, 7 = heat wave. - INT16 skynum; ///< Sky number to use. + char skytexture[9]; ///< Sky texture to use. INT16 skybox_scalex; ///< Skybox X axis scale. (0 = no movement, 1 = 1:1 movement, 16 = 16:1 slow movement, -4 = 1:4 fast movement, etc.) INT16 skybox_scaley; ///< Skybox Y axis scale. INT16 skybox_scalez; ///< Skybox Z axis scale. @@ -435,6 +435,7 @@ extern INT32 sneakertime; extern INT32 itemtime; extern INT32 comebacktime; extern INT32 bumptime; +extern INT32 greasetics; extern INT32 wipeoutslowtime; extern INT32 wantedreduce; extern INT32 wantedfrequency; @@ -485,6 +486,15 @@ extern INT16 votelevels[5][2]; extern SINT8 votes[MAXPLAYERS]; extern SINT8 pickedvote; +/** Battle overtime information + */ +extern struct battleovertime +{ + UINT16 enabled; ///< Has this been initalized yet? + fixed_t radius, minradius; ///< Radius of kill field + fixed_t x, y, z; ///< Position to center on +} battleovertime; + extern tic_t hidetime; extern UINT32 timesBeaten; // # of times the game has been beaten. diff --git a/src/f_finale.c b/src/f_finale.c index 9a4be070c..c620c3ffd 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -220,7 +220,7 @@ void F_StartIntro(void) F_WipeStartScreen(); V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31); F_WipeEndScreen(); - F_RunWipe(wipedefs[wipe_level_final], false); + F_RunWipe(wipedefs[wipe_intro_toblack], false, "FADEMAP0", false, false); } if (introtoplay) @@ -306,7 +306,7 @@ void F_IntroDrawer(void) F_WipeStartScreen(); V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31); F_WipeEndScreen(); - F_RunWipe(99,true); + F_RunWipe(99, true, "FADEMAP0", false, false); } // Stay on black for a bit. =) @@ -1420,7 +1420,7 @@ void F_CutsceneDrawer(void) V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, cutscenes[cutnum]->scene[scenenum].fadecolor); F_WipeEndScreen(); - F_RunWipe(cutscenes[cutnum]->scene[scenenum].fadeinid, true); + F_RunWipe(cutscenes[cutnum]->scene[scenenum].fadeinid, true, NULL, false, false); F_WipeStartScreen(); } @@ -1440,7 +1440,7 @@ void F_CutsceneDrawer(void) if (dofadenow && rendermode != render_none) { F_WipeEndScreen(); - F_RunWipe(cutscenes[cutnum]->scene[scenenum].fadeoutid, true); + F_RunWipe(cutscenes[cutnum]->scene[scenenum].fadeoutid, true, NULL, false, false); } V_DrawString(textxpos, textypos, 0, cutscene_disptext); diff --git a/src/f_finale.h b/src/f_finale.h index 45166e03d..d1efa6ce2 100644 --- a/src/f_finale.h +++ b/src/f_finale.h @@ -74,12 +74,13 @@ extern INT32 lastwipetic; void F_WipeStartScreen(void); void F_WipeEndScreen(void); -void F_RunWipe(UINT8 wipetype, boolean drawMenu); +void F_RunWipe(UINT8 wipetype, boolean drawMenu, const char *colormap, boolean reverse, boolean encorewiggle); enum { wipe_credits_intermediate, // makes a good 0 I guess. + // Gamestate wipes wipe_level_toblack, wipe_intermission_toblack, wipe_voting_toblack, @@ -92,11 +93,11 @@ enum wipe_intro_toblack, wipe_cutscene_toblack, - // custom intermissions - wipe_specinter_toblack, - wipe_multinter_toblack, - wipe_speclevel_towhite, + // Specialized wipes + wipe_encore_toinvert, + wipe_encore_towhite, + // "From black" wipes wipe_level_final, wipe_intermission_final, wipe_voting_final, @@ -109,10 +110,6 @@ enum wipe_intro_final, wipe_cutscene_final, - // custom intermissions - wipe_specinter_final, - wipe_multinter_final, - NUMWIPEDEFS, WIPEFINALSHIFT = wipe_level_final - wipe_level_toblack }; diff --git a/src/f_wipe.c b/src/f_wipe.c index 3c8713d18..12887acf5 100644 --- a/src/f_wipe.c +++ b/src/f_wipe.c @@ -16,8 +16,10 @@ #include "i_video.h" #include "v_video.h" +#include "r_data.h" // NearestColor #include "r_draw.h" // transtable #include "p_pspr.h" // tr_transxxx + #include "w_wad.h" #include "z_zone.h" @@ -47,35 +49,31 @@ UINT8 wipedefs[NUMWIPEDEFS] = { 99, // wipe_credits_intermediate (0) 0, // wipe_level_toblack - UINT8_MAX, // wipe_intermission_toblack + 0, // wipe_intermission_toblack 0, // wipe_voting_toblack, - UINT8_MAX, // wipe_continuing_toblack - 3, // wipe_titlescreen_toblack + 0, // wipe_continuing_toblack + 0, // wipe_titlescreen_toblack 0, // wipe_timeattack_toblack 99, // wipe_credits_toblack 0, // wipe_evaluation_toblack 0, // wipe_gameend_toblack UINT8_MAX, // wipe_intro_toblack (hardcoded) - UINT8_MAX, // wipe_cutscene_toblack (hardcoded) + 99, // wipe_cutscene_toblack (hardcoded) - UINT8_MAX, // wipe_specinter_toblack - UINT8_MAX, // wipe_multinter_toblack - 99, // wipe_speclevel_towhite + 72, // wipe_encore_toinvert + 99, // wipe_encore_towhite - 3, // wipe_level_final + UINT8_MAX, // wipe_level_final 0, // wipe_intermission_final 0, // wipe_voting_final 0, // wipe_continuing_final - 3, // wipe_titlescreen_final + 0, // wipe_titlescreen_final 0, // wipe_timeattack_final 99, // wipe_credits_final 0, // wipe_evaluation_final 0, // wipe_gameend_final 99, // wipe_intro_final (hardcoded) - 99, // wipe_cutscene_final (hardcoded) - - 0, // wipe_specinter_final - 0 // wipe_multinter_final + 99 // wipe_cutscene_final (hardcoded) }; //-------------------------------------------------------------------------- @@ -86,9 +84,13 @@ boolean WipeInAction = false; INT32 lastwipetic = 0; #ifndef NOWIPE + +#define GENLEN 31 + static UINT8 *wipe_scr_start; //screen 3 static UINT8 *wipe_scr_end; //screen 4 static UINT8 *wipe_scr; //screen 0 (main drawing) +static UINT8 pallen; static fixed_t paldiv; /** Create fademask_t from lump @@ -181,7 +183,7 @@ static fademask_t *F_GetFadeMask(UINT8 masknum, UINT8 scrnnum) { * * \param fademask pixels to change */ -static void F_DoWipe(fademask_t *fademask) +static void F_DoWipe(fademask_t *fademask, lighttable_t *fadecolormap, boolean reverse) { // Software mask wipe -- optimized; though it might not look like it! // Okay, to save you wondering *how* this is more optimized than the simpler @@ -199,6 +201,10 @@ static void F_DoWipe(fademask_t *fademask) // look a little messy; sorry!) but it simultaneously runs at twice the speed. // In addition, we precalculate all the X and Y positions that we need to draw // from and to, so it uses a little extra memory, but again, helps it run faster. + // --- + // Sal: I kinda destroyed some of this code by introducing Genesis-style fades. + // A colormap can be provided in F_RunWipe, which the white/black values will be + // remapped to the appropriate entry in the fade colormap. { // wipe screen, start, end UINT8 *w = wipe_scr; @@ -242,6 +248,8 @@ static void F_DoWipe(fademask_t *fademask) maskx = masky = 0; do { + UINT8 m = *mask; + draw_rowstart = scrxpos[maskx]; draw_rowend = scrxpos[maskx + 1]; draw_linestart = scrypos[masky]; @@ -250,28 +258,31 @@ static void F_DoWipe(fademask_t *fademask) relativepos = (draw_linestart * vid.width) + draw_rowstart; draw_linestogo = draw_lineend - draw_linestart; - if (*mask == 0) + if (reverse) + m = ((pallen-1) - m); + + if (m == 0) { // shortcut - memcpy source to work while (draw_linestogo--) { - M_Memcpy(w_base+relativepos, s_base+relativepos, draw_rowend-draw_rowstart); + M_Memcpy(w_base+relativepos, (reverse ? e_base : s_base)+relativepos, draw_rowend-draw_rowstart); relativepos += vid.width; } } - else if (*mask == 10) + else if (m >= (pallen-1)) { // shortcut - memcpy target to work while (draw_linestogo--) { - M_Memcpy(w_base+relativepos, e_base+relativepos, draw_rowend-draw_rowstart); + M_Memcpy(w_base+relativepos, (reverse ? s_base : e_base)+relativepos, draw_rowend-draw_rowstart); relativepos += vid.width; } } else { // pointer to transtable that this mask would use - transtbl = transtables + ((9 - *mask)<>FRACBITS; + scanline = y / vid.dupy; + if (scanline & 1) + sine = -sine; + newpix = abs(sine); + + if (sine < 0) + { + M_Memcpy(&tmpscr[(y*vid.width)+newpix], &srcscr[(y*vid.width)], vid.width-newpix); + + // Cleanup edge + while (newpix) + { + tmpscr[(y*vid.width)+newpix] = srcscr[(y*vid.width)]; + newpix--; + } + } + else + { + M_Memcpy(&tmpscr[(y*vid.width)], &srcscr[(y*vid.width) + sine], vid.width-newpix); + + // Cleanup edge + while (newpix) + { + tmpscr[(y*vid.width) + vid.width - newpix] = srcscr[(y*vid.width) + (vid.width-1)]; + newpix--; + } + } + + disStart += (time*8); //the offset into the displacement map, increment each game loop + disStart &= FINEMASK; //clip it to FINEMASK + } +} + /** After setting up the screens you want to wipe, * calling this will do a 'typical' wipe. */ -void F_RunWipe(UINT8 wipetype, boolean drawMenu) +void F_RunWipe(UINT8 wipetype, boolean drawMenu, const char *colormap, boolean reverse, boolean encorewiggle) { #ifdef NOWIPE (void)wipetype; (void)drawMenu; + (void)colormap; + (void)reverse; + (void)encorewiggle; #else tic_t nowtime; UINT8 wipeframe = 0; fademask_t *fmask; - paldiv = FixedDiv(257< 0; bufx--) diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index 0d024dc65..659af386d 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -5922,13 +5922,15 @@ static void HWR_ProjectPrecipitationSprite(precipmobj_t *thing) static void HWR_DrawSkyBackground(void) { FOutVector v[4]; + texture_t *tex; angle_t angle; float dimensionmultiply; float aspectratio; float angleturn; + tex = textures[texturetranslation[skytexture]]; HWR_GetTexture(texturetranslation[skytexture]); - aspectratio = (float)vid.width/(float)vid.height; + aspectratio = (float)vid.width / (float)vid.height; //Hurdler: the sky is the only texture who need 4.0f instead of 1.0 // because it's called just after clearing the screen @@ -5952,22 +5954,22 @@ static void HWR_DrawSkyBackground(void) // software doesn't draw any further than 1024 for skies anyway, but this doesn't overlap properly // The only time this will probably be an issue is when a sky wider than 1024 is used as a sky AND a regular wall texture - angle = (dup_viewangle + gr_xtoviewangle[0]); - dimensionmultiply = ((float)textures[texturetranslation[skytexture]]->width/256.0f); + angle = -(dup_viewangle + gr_xtoviewangle[0]); + dimensionmultiply = ((float)tex->width/256.0f); if (atransform.mirror) { angle = InvAngle(angle); - dimensionmultiply *= -1; + dimensionmultiply = -dimensionmultiply; } v[0].sow = v[3].sow = ((float) angle / ((ANGLE_90-1)*dimensionmultiply)); - v[2].sow = v[1].sow = (-1.0f/dimensionmultiply)+((float) angle / ((ANGLE_90-1)*dimensionmultiply)); + v[2].sow = v[1].sow = (1.0f/dimensionmultiply)+((float) angle / ((ANGLE_90-1)*dimensionmultiply)); // Y angle = aimingangle; - dimensionmultiply = ((float)textures[texturetranslation[skytexture]]->height/(128.0f*aspectratio)); + dimensionmultiply = ((float)tex->height/(128.0f*aspectratio)); if (splitscreen == 1) { diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c index d217f4094..21deed84b 100644 --- a/src/hardware/hw_md2.c +++ b/src/hardware/hw_md2.c @@ -653,13 +653,12 @@ spritemd2found: // 0.2126 to red // 0.7152 to green // 0.0722 to blue -// (See this same define in k_kart.c!) +// (See this same define in hw_md2.c!) #define SETBRIGHTNESS(brightness,r,g,b) \ - brightness = (UINT8)(((1063*((UINT16)r)/5000) + (3576*((UINT16)g)/5000) + (361*((UINT16)b)/5000)) / 3) + brightness = (UINT8)(((1063*(UINT16)(r))/5000) + ((3576*(UINT16)(g))/5000) + ((361*(UINT16)(b))/5000)) static void HWR_CreateBlendedTexture(GLPatch_t *gpatch, GLPatch_t *blendgpatch, GLMipmap_t *grmip, INT32 skinnum, skincolors_t color) { - UINT8 i; UINT16 w = gpatch->width, h = gpatch->height; UINT32 size = w*h; RGBA_t *image, *blendimage, *cur, blendcolor; @@ -684,102 +683,188 @@ static void HWR_CreateBlendedTexture(GLPatch_t *gpatch, GLPatch_t *blendgpatch, image = gpatch->mipmap.grInfo.data; blendimage = blendgpatch->mipmap.grInfo.data; + blendcolor = V_GetColor(0); // initialize - // Average all of the translation's colors + while (size--) { - const UINT8 div = 6; - const UINT8 start = 4; - UINT32 r, g, b; + UINT16 brightness; - blendcolor = V_GetColor(colortranslations[color][start]); - r = (UINT32)(blendcolor.s.red*blendcolor.s.red); - g = (UINT32)(blendcolor.s.green*blendcolor.s.green); - b = (UINT32)(blendcolor.s.blue*blendcolor.s.blue); - - for (i = 1; i < div; i++) - { - RGBA_t nextcolor = V_GetColor(colortranslations[color][start+i]); - r += (UINT32)(nextcolor.s.red*nextcolor.s.red); - g += (UINT32)(nextcolor.s.green*nextcolor.s.green); - b += (UINT32)(nextcolor.s.blue*nextcolor.s.blue); - } - - blendcolor.s.red = (UINT8)(FixedSqrt((r/div)<>FRACBITS); - blendcolor.s.green = (UINT8)(FixedSqrt((g/div)<>FRACBITS); - blendcolor.s.blue = (UINT8)(FixedSqrt((b/div)<>FRACBITS); - } - - // rainbow support, could theoretically support boss ones too - if (skinnum == TC_RAINBOW) - { - while (size--) + // Don't bother with blending the pixel if the alpha of the blend pixel is 0 + if (skinnum == TC_RAINBOW) { if (image->s.alpha == 0 && blendimage->s.alpha == 0) { - // Don't bother with blending the pixel if the alpha of the blend pixel is 0 cur->rgba = image->rgba; + cur++; image++; blendimage++; + continue; } else { - UINT32 tempcolor; - UINT16 imagebright, blendbright, finalbright, colorbright; + UINT16 imagebright, blendbright; SETBRIGHTNESS(imagebright,image->s.red,image->s.green,image->s.blue); SETBRIGHTNESS(blendbright,blendimage->s.red,blendimage->s.green,blendimage->s.blue); // slightly dumb average between the blend image color and base image colour, usually one or the other will be fully opaque anyway - finalbright = (imagebright*(255-blendimage->s.alpha))/255 + (blendbright*blendimage->s.alpha)/255; - SETBRIGHTNESS(colorbright,blendcolor.s.red,blendcolor.s.green,blendcolor.s.blue); - - tempcolor = (finalbright*blendcolor.s.red)/colorbright; - tempcolor = min(255, tempcolor); - cur->s.red = (UINT8)tempcolor; - tempcolor = (finalbright*blendcolor.s.green)/colorbright; - tempcolor = min(255, tempcolor); - cur->s.green = (UINT8)tempcolor; - tempcolor = (finalbright*blendcolor.s.blue)/colorbright; - tempcolor = min(255, tempcolor); - cur->s.blue = (UINT8)tempcolor; - cur->s.alpha = image->s.alpha; + brightness = (imagebright*(255-blendimage->s.alpha))/255 + (blendbright*blendimage->s.alpha)/255; } - - cur++; image++; blendimage++; } - } - else - { - while (size--) + else { if (blendimage->s.alpha == 0) { - // Don't bother with blending the pixel if the alpha of the blend pixel is 0 cur->rgba = image->rgba; + cur++; image++; blendimage++; + continue; } else { - INT32 tempcolor; - INT16 tempmult, tempalpha; - tempalpha = -(abs(blendimage->s.red-127)-127)*2; - if (tempalpha > 255) - tempalpha = 255; - else if (tempalpha < 0) - tempalpha = 0; + SETBRIGHTNESS(brightness,blendimage->s.red,blendimage->s.green,blendimage->s.blue); + } + } - tempmult = (blendimage->s.red-127)*2; - if (tempmult > 255) - tempmult = 255; - else if (tempmult < 0) - tempmult = 0; + // Calculate a sort of "gradient" for the skincolor + // (Me splitting this into a function didn't work, so I had to ruin this entire function's groove...) + { + RGBA_t nextcolor; + UINT8 firsti, secondi, mul; + UINT32 r, g, b; - tempcolor = (image->s.red*(255-blendimage->s.alpha))/255 + ((tempmult + ((tempalpha*blendcolor.s.red)/255)) * blendimage->s.alpha)/255; - cur->s.red = (UINT8)tempcolor; - tempcolor = (image->s.green*(255-blendimage->s.alpha))/255 + ((tempmult + ((tempalpha*blendcolor.s.green)/255)) * blendimage->s.alpha)/255; - cur->s.green = (UINT8)tempcolor; - tempcolor = (image->s.blue*(255-blendimage->s.alpha))/255 + ((tempmult + ((tempalpha*blendcolor.s.blue)/255)) * blendimage->s.alpha)/255; - cur->s.blue = (UINT8)tempcolor; - cur->s.alpha = image->s.alpha; + // Rainbow needs to find the closest match to the textures themselves, instead of matching brightnesses to other colors. + // Ensue horrible mess. + if (skinnum == TC_RAINBOW) + { + UINT16 brightdif = 256; + UINT8 colorbrightnesses[16]; + INT32 compare, m, d; + UINT8 i; + + // Ignore pure white & pitch black + if (brightness > 253 || brightness < 2) + { + cur->rgba = image->rgba; + cur++; image++; blendimage++; + continue; + } + + firsti = 0; + mul = 0; + + for (i = 0; i < 16; i++) + { + RGBA_t tempc = V_GetColor(colortranslations[color][i]); + SETBRIGHTNESS(colorbrightnesses[i], tempc.s.red, tempc.s.green, tempc.s.blue); // store brightnesses for comparison + } + + for (i = 0; i < 16; i++) + { + if (brightness > colorbrightnesses[i]) // don't allow greater matches (because calculating a makeshift gradient for this is already a huge mess as is) + continue; + compare = abs((INT16)(colorbrightnesses[i]) - (INT16)(brightness)); + if (compare < brightdif) + { + brightdif = (UINT16)compare; + firsti = i; // best matching color that's equal brightness or darker + } + } + + secondi = firsti+1; // next color in line + if (secondi == 16) + { + m = (INT16)brightness; // - 0; + d = (INT16)colorbrightnesses[firsti]; // - 0; + } + else + { + m = (INT16)brightness - (INT16)colorbrightnesses[secondi]; + d = (INT16)colorbrightnesses[firsti] - (INT16)colorbrightnesses[secondi]; + } + + if (m >= d) + m = d-1; + + // calculate the "gradient" multiplier based on how close this color is to the one next in line + if (m <= 0 || d <= 0) + mul = 0; + else + mul = 15 - ((m * 16) / d); + } + else + { + // Thankfully, it's normally way more simple. + // Just convert brightness to a skincolor value, use remainder to find the gradient multipler + firsti = ((UINT8)(255-brightness) / 16); + secondi = firsti+1; + mul = ((UINT8)(255-brightness) % 16); } - cur++; image++; blendimage++; + blendcolor = V_GetColor(colortranslations[color][firsti]); + + if (mul > 0 // If it's 0, then we only need the first color. + && colortranslations[color][firsti] != colortranslations[color][secondi]) // Some colors have duplicate colors in a row, so let's just save the process + { + if (secondi == 16) // blend to black + nextcolor = V_GetColor(31); + else + nextcolor = V_GetColor(colortranslations[color][secondi]); + + // Find difference between points + r = (UINT32)(nextcolor.s.red - blendcolor.s.red); + g = (UINT32)(nextcolor.s.green - blendcolor.s.green); + b = (UINT32)(nextcolor.s.blue - blendcolor.s.blue); + + // Find the gradient of the two points + r = ((mul * r) / 16); + g = ((mul * g) / 16); + b = ((mul * b) / 16); + + // Add gradient value to color + blendcolor.s.red += r; + blendcolor.s.green += g; + blendcolor.s.blue += b; + } } + + if (skinnum == TC_RAINBOW) + { + UINT32 tempcolor; + UINT16 colorbright; + + SETBRIGHTNESS(colorbright,blendcolor.s.red,blendcolor.s.green,blendcolor.s.blue); + if (colorbright == 0) + colorbright = 1; // no dividing by 0 please + + tempcolor = (brightness * blendcolor.s.red) / colorbright; + tempcolor = min(255, tempcolor); + cur->s.red = (UINT8)tempcolor; + + tempcolor = (brightness * blendcolor.s.green) / colorbright; + tempcolor = min(255, tempcolor); + cur->s.green = (UINT8)tempcolor; + + tempcolor = (brightness * blendcolor.s.blue) / colorbright; + tempcolor = min(255, tempcolor); + cur->s.blue = (UINT8)tempcolor; + cur->s.alpha = image->s.alpha; + } + else + { + // Color strength depends on image alpha + INT32 tempcolor; + + tempcolor = ((image->s.red * (255-blendimage->s.alpha)) / 255) + ((blendcolor.s.red * blendimage->s.alpha) / 255); + tempcolor = min(255, tempcolor); + cur->s.red = (UINT8)tempcolor; + + tempcolor = ((image->s.green * (255-blendimage->s.alpha)) / 255) + ((blendcolor.s.green * blendimage->s.alpha) / 255); + tempcolor = min(255, tempcolor); + cur->s.green = (UINT8)tempcolor; + + tempcolor = ((image->s.blue * (255-blendimage->s.alpha)) / 255) + ((blendcolor.s.blue * blendimage->s.alpha) / 255); + tempcolor = min(255, tempcolor); + cur->s.blue = (UINT8)tempcolor; + cur->s.alpha = image->s.alpha; + } + + cur++; image++; blendimage++; } return; @@ -1091,11 +1176,11 @@ void HWR_DrawMD2(gr_vissprite_t *spr) #ifdef USE_FTRANSFORM_ANGLEZ // Slope rotation from Kart p.anglez = 0.0f; - if (spr->mobj->standingslope) + if (spr->mobj->modeltilt) { - fixed_t tempz = spr->mobj->standingslope->normal.z; - fixed_t tempy = spr->mobj->standingslope->normal.y; - fixed_t tempx = spr->mobj->standingslope->normal.x; + fixed_t tempz = spr->mobj->modeltilt->normal.z; + fixed_t tempy = spr->mobj->modeltilt->normal.y; + fixed_t tempx = spr->mobj->modeltilt->normal.x; fixed_t tempangle = AngleFixed(R_PointToAngle2(0, 0, FixedSqrt(FixedMul(tempy, tempy) + FixedMul(tempz, tempz)), tempx)); p.anglez = FIXED_TO_FLOAT(tempangle); tempangle = -AngleFixed(R_PointToAngle2(0, 0, tempz, tempy)); diff --git a/src/info.c b/src/info.c index 31f2f8348..c960ebff6 100644 --- a/src/info.c +++ b/src/info.c @@ -43,33 +43,34 @@ char sprnames[NUMSPRITES + 1][5] = "DFLM","XMS1","XMS2","XMS3","BSZ1","BSZ2","BSZ3","BSZ4","BSZ5","BSZ6", "BSZ7","BSZ8","STLG","DBAL","RCRY","ARMA","ARMF","ARMB","WIND","MAGN", "ELEM","FORC","PITY","IVSP","SSPK","GOAL","BIRD","BUNY","MOUS","CHIC", - "COWZ","RBRD","SPRY","SPRR","SPRB","YSPR","RSPR","RAIN","SNO1","SPLH", - "SPLA","SMOK","BUBP","BUBO","BUBN","BUBM","POPP","TFOG","SEED","PRTL", - "SCOR","DRWN","TTAG","GFLG","RRNG","RNGB","RNGR","RNGI","RNGA","RNGE", - "RNGS","RNGG","PIKB","PIKR","PIKA","PIKE","PIKS","PIKG","TAUT","TGRE", - "TSCR","COIN","CPRK","GOOM","BGOM","FFWR","FBLL","SHLL","PUMA","HAMM", - "KOOP","BFLM","MAXE","MUS1","MUS2","TOAD","NDRN","SUPE","SUPZ","NDRL", - "NSPK","NBMP","HOOP","NSCR","NPRU","CAPS","SUPT","SPRK","BOM1","BOM2", - "BOM3","BOM4","ROIA","ROIB","ROIC","ROID","ROIE","ROIF","ROIG","ROIH", - "ROII","ROIJ","ROIK","ROIL","ROIM","ROIN","ROIO","ROIP","BBAL","GWLG", - "GWLR","SRBA","SRBB","SRBC","SRBD","SRBE","SRBF","SRBG","SRBH","SRBI", - "SRBJ","SRBK","SRBL","SRBM","SRBN","SRBO", + "COWZ","RBRD","SPVY","SPVR","SPVB","SPVG","SPDY","SPDR","SPDB","SPDG", + "SPHY","SPHR","SPHB","SPHG","RAIN","SNO1","SPLH","SPLA","SMOK","BUBP", + "BUBO","BUBN","BUBM","POPP","TFOG","SEED","PRTL","SCOR","DRWN","TTAG", + "GFLG","RRNG","RNGB","RNGR","RNGI","RNGA","RNGE","RNGS","RNGG","PIKB", + "PIKR","PIKA","PIKE","PIKS","PIKG","TAUT","TGRE","TSCR","COIN","CPRK", + "GOOM","BGOM","FFWR","FBLL","SHLL","PUMA","HAMM","KOOP","BFLM","MAXE", + "MUS1","MUS2","TOAD","NDRN","SUPE","SUPZ","NDRL","NSPK","NBMP","HOOP", + "NSCR","NPRU","CAPS","SUPT","SPRK","BOM1","BOM2","BOM3","BOM4","ROIA", + "ROIB","ROIC","ROID","ROIE","ROIF","ROIG","ROIH","ROII","ROIJ","ROIK", + "ROIL","ROIM","ROIN","ROIO","ROIP","BBAL","GWLG","GWLR","SRBA","SRBB", + "SRBC","SRBD","SRBE","SRBF","SRBG","SRBH","SRBI","SRBJ","SRBK","SRBL", + "SRBM","SRBN","SRBO", //SRB2kart Sprites - "SPRG","BSPR","RNDM","RPOP","SGNS","FAST","DSHR","BOST","BOSM","KFRE", - "KINV","KINF","WIPD","DRIF","BDRF","DUST","RSHE","FITM","BANA","ORBN", - "JAWZ","SSMN","KRBM","BHOG","BHBM","SPBM","THNS","SINK","SITR","KBLN", - "DEZL","POKE","AUDI","DECO","DOOD","SNES","GBAS","SPRS","BUZB","CHOM", - "SACO","CRAB","SHAD","BRNG","BUMP","FLEN","CLAS","PSHW","ISTA","ISTB", - "ARRO","ITEM","ITMO","ITMI","ITMN","WANT","PBOM","HIT1","HIT2","HIT3", - "RETI","AIDU","KSPK","LZI1","LZI2","KLIT","FZSM","FZBM","FPRT","SBUS", - "MARB","FUFO","RUST","BLON","VAPE","HTZA","HTZB","SGVA","SGVB","SGVC", - "PGTR","PGF1","PGF2","PGF3","PGBH","DPLR","SPTL","ENM1","GARU","MARR", - "REAP","JITB","CDMO","CDBU","PINE","PPLR","DPPT","AATR","COCO","BDST", - "FROG","CBRA","HOLE","BBRA","EGFG","SMKP","MTYM","THWP","SNOB","ICEB", - "CNDL","DOCH","DUCK","GTRE","CHES","CHIM","DRGN","LZMN","PGSS","ZTCH", - "MKMA","MKMP","RTCH","BOWL","BOWH","BRRL","BRRR","HRSE","TOAH","BFRT", - "OFRT","RFRT","PFRT","ASPK","HBST","HBSO","HBSF","WBLZ","WBLN","FWRK", - "MXCL","RGSP","DRAF","XMS4","XMS5","VIEW" + "RNDM","RPOP","SGNS","FAST","DSHR","BOST","BOSM","KFRE","KINV","KINF", + "WIPD","DRIF","BDRF","DUST","RSHE","FITM","BANA","ORBN","JAWZ","SSMN", + "KRBM","BHOG","BHBM","SPBM","THNS","SINK","SITR","KBLN","DEZL","POKE", + "AUDI","DECO","DOOD","SNES","GBAS","SPRS","BUZB","CHOM","SACO","CRAB", + "SHAD","BRNG","BUMP","FLEN","CLAS","PSHW","ISTA","ISTB","ARRO","ITEM", + "ITMO","ITMI","ITMN","WANT","PBOM","HIT1","HIT2","HIT3","RETI","AIDU", + "KSPK","LZI1","LZI2","KLIT","FZSM","FZBM","FPRT","SBUS","MARB","FUFO", + "RUST","BLON","VAPE","HTZA","HTZB","SGVA","SGVB","SGVC","PGTR","PGF1", + "PGF2","PGF3","PGBH","DPLR","SPTL","ENM1","GARU","MARR","REAP","JITB", + "CDMO","CDBU","PINE","PPLR","DPPT","AATR","COCO","BDST","FROG","CBRA", + "HOLE","BBRA","EGFG","SMKP","MTYM","THWP","SNOB","ICEB","CNDL","DOCH", + "DUCK","GTRE","CHES","CHIM","DRGN","LZMN","PGSS","ZTCH","MKMA","MKMP", + "RTCH","BOWL","BOWH","BRRL","BRRR","HRSE","TOAH","BFRT","OFRT","RFRT", + "PFRT","ASPK","HBST","HBSO","HBSF","WBLZ","WBLN","FWRK","MXCL","RGSP", + "DRAF","GRES","OTFG","XMS4","XMS5","VIEW" }; // Doesn't work with g++, needs actionf_p1 (don't modify this comment) @@ -1795,45 +1796,76 @@ state_t states[NUMSTATES] = {SPR_RBRD, 1, 4, {A_Chase}, 0, 0, S_RBIRD2}, // S_RBIRD3 // Yellow Spring - {SPR_SPRY, 0, -1, {NULL}, 0, 0, S_NULL}, // S_YELLOWSPRING - {SPR_SPRY, 4, 4, {A_Pain}, 0, 0, S_YELLOWSPRING3}, // S_YELLOWSPRING2 - {SPR_SPRY, 3, 1, {NULL}, 0, 0, S_YELLOWSPRING4}, // S_YELLOWSPRING3 - {SPR_SPRY, 2, 1, {NULL}, 0, 0, S_YELLOWSPRING5}, // S_YELLOWSPRING4 - {SPR_SPRY, 1, 1, {NULL}, 0, 0, S_YELLOWSPRING}, // S_YELLOWSPRING5 + {SPR_SPVY, 0, -1, {NULL}, 0, 0, S_NULL}, // S_YELLOWSPRING1 + {SPR_SPVY, 1, 1, {A_Pain}, 0, 0, S_YELLOWSPRING3}, // S_YELLOWSPRING2 + {SPR_SPVY, 0, 1, {NULL}, 0, 0, S_YELLOWSPRING4}, // S_YELLOWSPRING3 + {SPR_SPVY, 2, 4, {NULL}, 0, 0, S_YELLOWSPRING1}, // S_YELLOWSPRING4 // Red Spring - {SPR_SPRR, 0, -1, {NULL}, 0, 0, S_NULL}, // S_REDSPRING - {SPR_SPRR, 4, 4, {A_Pain}, 0, 0, S_REDSPRING3}, // S_REDSPRING2 - {SPR_SPRR, 3, 1, {NULL}, 0, 0, S_REDSPRING4}, // S_REDSPRING3 - {SPR_SPRR, 2, 1, {NULL}, 0, 0, S_REDSPRING5}, // S_REDSPRING4 - {SPR_SPRR, 1, 1, {NULL}, 0, 0, S_REDSPRING}, // S_REDSPRING5 + {SPR_SPVR, 0, -1, {NULL}, 0, 0, S_NULL}, // S_REDSPRING1 + {SPR_SPVR, 1, 1, {A_Pain}, 0, 0, S_REDSPRING3}, // S_REDSPRING2 + {SPR_SPVR, 0, 1, {NULL}, 0, 0, S_REDSPRING4}, // S_REDSPRING3 + {SPR_SPVR, 2, 4, {NULL}, 0, 0, S_REDSPRING1}, // S_REDSPRING4 // Blue Spring - {SPR_SPRB, 0, -1, {NULL}, 0, 0, S_NULL}, // S_BLUESPRING - {SPR_SPRB, 4, 4, {A_Pain}, 0, 0, S_BLUESPRING3}, // S_BLUESPRING2 - {SPR_SPRB, 3, 1, {NULL}, 0, 0, S_BLUESPRING4}, // S_BLUESPRING3 - {SPR_SPRB, 2, 1, {NULL}, 0, 0, S_BLUESPRING5}, // S_BLUESPRING4 - {SPR_SPRB, 1, 1, {NULL}, 0, 0, S_BLUESPRING}, // S_BLUESPRING5 + {SPR_SPVB, 0, -1, {NULL}, 0, 0, S_NULL}, // S_BLUESPRING1 + {SPR_SPVB, 1, 1, {A_Pain}, 0, 0, S_BLUESPRING3}, // S_BLUESPRING2 + {SPR_SPVB, 0, 1, {NULL}, 0, 0, S_BLUESPRING4}, // S_BLUESPRING3 + {SPR_SPVB, 2, 4, {NULL}, 0, 0, S_BLUESPRING1}, // S_BLUESPRING4 + + // Grey Spring + {SPR_SPVG, 0, -1, {NULL}, 0, 0, S_NULL}, // S_GREYSPRING1 + {SPR_SPVG, 1, 1, {A_Pain}, 0, 0, S_GREYSPRING3}, // S_GREYSPRING2 + {SPR_SPVG, 0, 1, {NULL}, 0, 0, S_GREYSPRING4}, // S_GREYSPRING3 + {SPR_SPVG, 2, 4, {NULL}, 0, 0, S_GREYSPRING1}, // S_GREYSPRING4 // Yellow Diagonal Spring - {SPR_YSPR, 0, -1, {NULL}, 0, 0, S_NULL}, // S_YDIAG1 - {SPR_YSPR, 1, 1, {A_Pain}, 0, 0, S_YDIAG3}, // S_YDIAG2 - {SPR_YSPR, 2, 1, {NULL}, 0, 0, S_YDIAG4}, // S_YDIAG3 - {SPR_YSPR, 3, 1, {NULL}, 0, 0, S_YDIAG5}, // S_YDIAG4 - {SPR_YSPR, 4, 1, {NULL}, 0, 0, S_YDIAG6}, // S_YDIAG5 - {SPR_YSPR, 3, 1, {NULL}, 0, 0, S_YDIAG7}, // S_YDIAG6 - {SPR_YSPR, 2, 1, {NULL}, 0, 0, S_YDIAG8}, // S_YDIAG7 - {SPR_YSPR, 1, 1, {NULL}, 0, 0, S_YDIAG1}, // S_YDIAG8 + {SPR_SPDY, 0, -1, {NULL}, 0, 0, S_NULL}, // S_YDIAG1 + {SPR_SPDY, 1, 1, {A_Pain}, 0, 0, S_YDIAG3}, // S_YDIAG2 + {SPR_SPDY, 0, 1, {NULL}, 0, 0, S_YDIAG4}, // S_YDIAG3 + {SPR_SPDY, 2, 4, {NULL}, 0, 0, S_YDIAG1}, // S_YDIAG4 // Red Diagonal Spring - {SPR_RSPR, 0, -1, {NULL}, 0, 0, S_NULL}, // S_RDIAG1 - {SPR_RSPR, 1, 1, {A_Pain}, 0, 0, S_RDIAG3}, // S_RDIAG2 - {SPR_RSPR, 2, 1, {NULL}, 0, 0, S_RDIAG4}, // S_RDIAG3 - {SPR_RSPR, 3, 1, {NULL}, 0, 0, S_RDIAG5}, // S_RDIAG4 - {SPR_RSPR, 4, 1, {NULL}, 0, 0, S_RDIAG6}, // S_RDIAG5 - {SPR_RSPR, 3, 1, {NULL}, 0, 0, S_RDIAG7}, // S_RDIAG6 - {SPR_RSPR, 2, 1, {NULL}, 0, 0, S_RDIAG8}, // S_RDIAG7 - {SPR_RSPR, 1, 1, {NULL}, 0, 0, S_RDIAG1}, // S_RDIAG8 + {SPR_SPDR, 0, -1, {NULL}, 0, 0, S_NULL}, // S_RDIAG1 + {SPR_SPDR, 1, 1, {A_Pain}, 0, 0, S_RDIAG3}, // S_RDIAG2 + {SPR_SPDR, 0, 1, {NULL}, 0, 0, S_RDIAG4}, // S_RDIAG3 + {SPR_SPDR, 2, 4, {NULL}, 0, 0, S_RDIAG1}, // S_RDIAG4 + + // Blue Diagonal Spring + {SPR_SPDB, 0, -1, {NULL}, 0, 0, S_NULL}, // S_BDIAG1 + {SPR_SPDB, 1, 1, {A_Pain}, 0, 0, S_BDIAG3}, // S_BDIAG2 + {SPR_SPDB, 0, 1, {NULL}, 0, 0, S_BDIAG4}, // S_BDIAG3 + {SPR_SPDB, 2, 4, {NULL}, 0, 0, S_BDIAG1}, // S_BDIAG4 + + // Grey Diagonal Spring + {SPR_SPDG, 0, -1, {NULL}, 0, 0, S_NULL}, // S_GDIAG1 + {SPR_SPDG, 1, 1, {A_Pain}, 0, 0, S_GDIAG3}, // S_GDIAG2 + {SPR_SPDG, 0, 1, {NULL}, 0, 0, S_GDIAG4}, // S_GDIAG3 + {SPR_SPDG, 2, 4, {NULL}, 0, 0, S_GDIAG1}, // S_GDIAG4 + + // Yellow Horizontal Spring + {SPR_SPHY, 0, -1, {NULL}, 0, 0, S_NULL}, // S_YHORIZ1 + {SPR_SPHY, 1, 1, {A_Pain}, 0, 0, S_YHORIZ3}, // S_YHORIZ2 + {SPR_SPHY, 0, 1, {NULL}, 0, 0, S_YHORIZ4}, // S_YHORIZ3 + {SPR_SPHY, 2, 4, {NULL}, 0, 0, S_YHORIZ1}, // S_YHORIZ4 + + // Red Horizontal Spring + {SPR_SPHR, 0, -1, {NULL}, 0, 0, S_NULL}, // S_RHORIZ1 + {SPR_SPHR, 1, 1, {A_Pain}, 0, 0, S_RHORIZ3}, // S_RHORIZ2 + {SPR_SPHR, 0, 1, {NULL}, 0, 0, S_RHORIZ4}, // S_RHORIZ3 + {SPR_SPHR, 2, 4, {NULL}, 0, 0, S_RHORIZ1}, // S_RHORIZ4 + + // Blue Horizontal Spring + {SPR_SPHB, 0, -1, {NULL}, 0, 0, S_NULL}, // S_BHORIZ1 + {SPR_SPHB, 1, 1, {A_Pain}, 0, 0, S_BHORIZ3}, // S_BHORIZ2 + {SPR_SPHB, 0, 1, {NULL}, 0, 0, S_BHORIZ4}, // S_BHORIZ3 + {SPR_SPHB, 2, 4, {NULL}, 0, 0, S_BHORIZ1}, // S_BHORIZ4 + + // Grey Horizontal Spring + {SPR_SPHG, 0, -1, {NULL}, 0, 0, S_NULL}, // S_GHORIZ1 + {SPR_SPHG, 1, 1, {A_Pain}, 0, 0, S_GHORIZ3}, // S_GHORIZ2 + {SPR_SPHG, 0, 1, {NULL}, 0, 0, S_GHORIZ4}, // S_GHORIZ3 + {SPR_SPHG, 2, 4, {NULL}, 0, 0, S_GHORIZ1}, // S_GHORIZ4 // Rain {SPR_RAIN, FF_TRANS50, -1, {NULL}, 0, 0, S_NULL}, // S_RAIN1 @@ -2512,23 +2544,6 @@ state_t states[NUMSTATES] = {SPR_SRBO, 0, 2, {A_BuzzFly}, 0, 0, S_SRB1_GENREX2}, // S_SRB1_GENREX2 // SRB2kart - {SPR_SPRG, 0, -1, {NULL}, 0, 0, S_NULL}, // S_GRAYSPRING - {SPR_SPRG, 4, 4, {A_Pain}, 0, 0, S_GRAYSPRING3}, // S_GRAYSPRING2 - {SPR_SPRG, 3, 1, {NULL}, 0, 0, S_GRAYSPRING4}, // S_GRAYSPRING3 - {SPR_SPRG, 2, 1, {NULL}, 0, 0, S_GRAYSPRING5}, // S_GRAYSPRING4 - {SPR_SPRG, 1, 1, {NULL}, 0, 0, S_GRAYSPRING}, // S_GRAYSPRING5 - - {SPR_NULL, 0, 1, {A_Pain}, 0, 0, S_INVISIBLE}, // S_INVISSPRING - - {SPR_BSPR, 0, -1, {NULL}, 0, 0, S_NULL}, // S_BDIAG1 - {SPR_BSPR, 1, 1, {A_Pain}, 0, 0, S_BDIAG3}, // S_BDIAG2 - {SPR_BSPR, 2, 1, {NULL}, 0, 0, S_BDIAG4}, // S_BDIAG3 - {SPR_BSPR, 3, 1, {NULL}, 0, 0, S_BDIAG5}, // S_BDIAG4 - {SPR_BSPR, 4, 1, {NULL}, 0, 0, S_BDIAG6}, // S_BDIAG5 - {SPR_BSPR, 3, 1, {NULL}, 0, 0, S_BDIAG7}, // S_BDIAG6 - {SPR_BSPR, 2, 1, {NULL}, 0, 0, S_BDIAG8}, // S_BDIAG7 - {SPR_BSPR, 1, 1, {NULL}, 0, 0, S_BDIAG1}, // S_BDIAG8 - {SPR_RNDM, 0|FF_FULLBRIGHT, 3, {NULL}, 0, 0, S_RANDOMITEM2}, // S_RANDOMITEM1 {SPR_RNDM, 1|FF_FULLBRIGHT, 3, {NULL}, 0, 0, S_RANDOMITEM3}, // S_RANDOMITEM2 {SPR_RNDM, 2|FF_FULLBRIGHT, 3, {NULL}, 0, 0, S_RANDOMITEM4}, // S_RANDOMITEM3 @@ -3437,6 +3452,12 @@ state_t states[NUMSTATES] = {SPR_DRAF, 3, 1, {NULL}, 0, 0, S_DRAFTDUST5}, // S_DRAFTDUST4 {SPR_DRAF, 4, 1, {NULL}, 0, 0, S_NULL}, // S_DRAFTDUST5 + {SPR_GRES, FF_ANIMATE|FF_PAPERSPRITE, -1, {NULL}, 2, 4, S_NULL}, // S_TIREGREASE + + {SPR_OTFG, FF_FULLBRIGHT|FF_TRANS50, TICRATE, {NULL}, 0, 0, S_NULL}, // S_OVERTIMEFOG + {SPR_OTFG, 2|FF_FULLBRIGHT|FF_PAPERSPRITE, 1, {NULL}, 0, 0, S_NULL}, // S_OVERTIMEORB + {SPR_OTFG, 1|FF_FULLBRIGHT, 1, {NULL}, 0, 0, S_NULL}, // S_OVERTIMEBEAM + #ifdef SEENAMES {SPR_NULL, 0, 1, {NULL}, 0, 0, S_NULL}, // S_NAMECHECK #endif @@ -4236,8 +4257,8 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 32, // reactiontime sfx_None, // attacksound S_NULL, // painstate - 0, // painchance - sfx_spring, // painsound + SKINCOLOR_TEA, // painchance + sfx_s3kb1, // painsound S_NULL, // meleestate S_NULL, // missilestate S_XPLD1, // deathstate @@ -4247,7 +4268,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 24*FRACUNIT, // radius 40*FRACUNIT, // height 0, // display offset - 13*FRACUNIT, // mass + 15*FRACUNIT, // mass 0, // damage sfx_None, // activesound MF_ENEMY|MF_SPECIAL|MF_SHOOTABLE, // flags @@ -4263,8 +4284,8 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 32, // reactiontime sfx_None, // attacksound S_NULL, // painstate - 0, // painchance - sfx_spring, // painsound + SKINCOLOR_YELLOW, // painchance + sfx_s3kb1, // painsound S_NULL, // meleestate S_NULL, // missilestate S_XPLD1, // deathstate @@ -4274,7 +4295,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 24*FRACUNIT, // radius 40*FRACUNIT, // height 0, // display offset - 26*FRACUNIT, // mass + 25*FRACUNIT, // mass 0, // damage sfx_None, // activesound MF_ENEMY|MF_SPECIAL|MF_SHOOTABLE, // flags @@ -4681,7 +4702,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 0, // display offset 0, // mass 0, // damage - sfx_spring, // activesound + sfx_s3kb1, // activesound MF_SPECIAL|MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOCLIPTHING, // flags S_EGGMOBILE2_POGO5 // raisestate }, @@ -6058,54 +6079,27 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, - { // MT_BLUESPRING - 552, // doomednum - S_BLUESPRING, // spawnstate - 1000, // spawnhealth - S_BLUESPRING2, // seestate - sfx_None, // seesound - 8, // reactiontime - sfx_None, // attacksound - S_NULL, // painstate - 0, // painchance - sfx_spring, // painsound - S_NULL, // meleestate - S_NULL, // missilestate - S_NULL, // deathstate - S_NULL, // xdeathstate - sfx_None, // deathsound - 0, // speed - 20*FRACUNIT, // radius - 16*FRACUNIT, // height - 0, // display offset - 14*FRACUNIT, // mass - 0, // damage - sfx_None, // activesound - MF_SOLID|MF_SPRING|MF_DONTENCOREMAP, // flags - S_BLUESPRING2 // raisestate - }, - { // MT_YELLOWSPRING 550, // doomednum - S_YELLOWSPRING, // spawnstate + S_YELLOWSPRING1,// spawnstate 1000, // spawnhealth S_YELLOWSPRING2,// seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate - 0, // painchance - sfx_spring, // painsound + SKINCOLOR_YELLOW, // painchance + sfx_s3kb1, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed - 20*FRACUNIT, // radius - 16*FRACUNIT, // height + 48*FRACUNIT, // radius + 32*FRACUNIT, // height 0, // display offset - 26*FRACUNIT, // mass + 25*FRACUNIT, // mass 0, // damage sfx_None, // activesound MF_SOLID|MF_SPRING|MF_DONTENCOREMAP, // flags @@ -6114,23 +6108,23 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = { // MT_REDSPRING 551, // doomednum - S_REDSPRING, // spawnstate + S_REDSPRING1, // spawnstate 1000, // spawnhealth S_REDSPRING2, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate - 0, // painchance - sfx_spring, // painsound + SKINCOLOR_SALMON, // painchance + sfx_s3kb1, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed - 20*FRACUNIT, // radius - 16*FRACUNIT, // height + 48*FRACUNIT, // radius + 32*FRACUNIT, // height 0, // display offset 40*FRACUNIT, // mass 0, // damage @@ -6139,8 +6133,62 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_REDSPRING2 // raisestate }, + { // MT_BLUESPRING + 552, // doomednum + S_BLUESPRING1, // spawnstate + 1000, // spawnhealth + S_BLUESPRING2, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + SKINCOLOR_PASTEL, // painchance + sfx_s3kb1, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 48*FRACUNIT, // radius + 32*FRACUNIT, // height + 0, // display offset + 64*FRACUNIT, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID|MF_SPRING|MF_DONTENCOREMAP, // flags + S_BLUESPRING2 // raisestate + }, + + { // MT_GREYSPRING + 553, // doomednum + S_GREYSPRING1, // spawnstate + 1000, // spawnhealth + S_GREYSPRING2, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + SKINCOLOR_POPCORN, // painchance + sfx_s3kb1, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 48*FRACUNIT, // radius + 32*FRACUNIT, // height + 0, // display offset + 15*FRACUNIT, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID|MF_SPRING|MF_DONTENCOREMAP, // flags + S_GREYSPRING2 // raisestate + }, + { // MT_YELLOWDIAG - 555, // doomednum + 554, // doomednum S_YDIAG1, // spawnstate 1, // spawnhealth S_YDIAG2, // seestate @@ -6148,26 +6196,26 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate - 0, // painchance - sfx_spring, // painsound + SKINCOLOR_YELLOW, // painchance + sfx_s3kb1, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed - 16*FRACUNIT, // radius - 16*FRACUNIT, // height + 48*FRACUNIT, // radius + 56*FRACUNIT, // height 0, // display offset - 26*FRACUNIT, // mass - 26*FRACUNIT, // damage + 25*FRACUNIT, // mass + 25*FRACUNIT, // damage sfx_None, // activesound MF_SOLID|MF_SPRING|MF_DONTENCOREMAP, // flags S_YDIAG2 // raisestate }, { // MT_REDDIAG - 556, // doomednum + 555, // doomednum S_RDIAG1, // spawnstate 1, // spawnhealth S_RDIAG2, // seestate @@ -6175,16 +6223,16 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate - 0, // painchance - sfx_spring, // painsound + SKINCOLOR_SALMON, // painchance + sfx_s3kb1, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed - 16*FRACUNIT, // radius - 16*FRACUNIT, // height + 48*FRACUNIT, // radius + 56*FRACUNIT, // height 0, // display offset 40*FRACUNIT, // mass 40*FRACUNIT, // damage @@ -6193,6 +6241,168 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_RDIAG2 // raisestate }, + { // MT_BLUEDIAG + 556, // doomednum + S_BDIAG1, // spawnstate + 1, // spawnhealth + S_BDIAG2, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + SKINCOLOR_PASTEL, // painchance + sfx_s3kb1, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 48*FRACUNIT, // radius + 56*FRACUNIT, // height + 0, // display offset + 64*FRACUNIT, // mass + 64*FRACUNIT, // damage + sfx_None, // activesound + MF_SOLID|MF_SPRING|MF_DONTENCOREMAP, // flags + S_BDIAG2 // raisestate + }, + + { // MT_GREYDIAG + 557, // doomednum + S_GDIAG1, // spawnstate + 1, // spawnhealth + S_GDIAG2, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + SKINCOLOR_POPCORN, // painchance + sfx_s3kb1, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 48*FRACUNIT, // radius + 56*FRACUNIT, // height + 0, // display offset + 15*FRACUNIT, // mass + 15*FRACUNIT, // damage + sfx_None, // activesound + MF_SOLID|MF_SPRING|MF_DONTENCOREMAP, // flags + S_GDIAG2 // raisestate + }, + + { // MT_YELLOWHORIZ + 558, // doomednum + S_YHORIZ1, // spawnstate + 1, // spawnhealth + S_YHORIZ2, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + SKINCOLOR_YELLOW, // painchance + sfx_s3kb1, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 48*FRACUNIT, // radius + 56*FRACUNIT, // height + 0, // display offset + 0, // mass + 45*FRACUNIT, // damage + sfx_None, // activesound + MF_SOLID|MF_SPRING|MF_NOGRAVITY|MF_DONTENCOREMAP, // flags + S_YHORIZ2 // raisestate + }, + + { // MT_REDHORIZ + 559, // doomednum + S_RHORIZ1, // spawnstate + 1, // spawnhealth + S_RHORIZ2, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + SKINCOLOR_SALMON, // painchance + sfx_s3kb1, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 48*FRACUNIT, // radius + 56*FRACUNIT, // height + 0, // display offset + 0, // mass + 72*FRACUNIT, // damage + sfx_None, // activesound + MF_SOLID|MF_SPRING|MF_NOGRAVITY|MF_DONTENCOREMAP, // flags + S_RHORIZ2 // raisestate + }, + + { // MT_BLUEHORIZ + 560, // doomednum + S_BHORIZ1, // spawnstate + 1, // spawnhealth + S_BHORIZ2, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + SKINCOLOR_PASTEL, // painchance + sfx_s3kb1, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 48*FRACUNIT, // radius + 56*FRACUNIT, // height + 0, // display offset + 0, // mass + 115*FRACUNIT, // damage + sfx_None, // activesound + MF_SOLID|MF_SPRING|MF_NOGRAVITY|MF_DONTENCOREMAP, // flags + S_BHORIZ2 // raisestate + }, + + { // MT_GREYHORIZ + 561, // doomednum + S_GHORIZ1, // spawnstate + 1, // spawnhealth + S_GHORIZ2, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + SKINCOLOR_POPCORN, // painchance + sfx_s3kb1, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 48*FRACUNIT, // radius + 56*FRACUNIT, // height + 0, // display offset + 0, // mass + 27*FRACUNIT, // damage + sfx_None, // activesound + MF_SOLID|MF_SPRING|MF_NOGRAVITY|MF_DONTENCOREMAP, // flags + S_GHORIZ2 // raisestate + }, + { // MT_BUBBLES 500, // doomednum S_BUBBLES1, // spawnstate @@ -14800,88 +15010,6 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = }, // SRB2kart MT's - - { // MT_GRAYSPRING - 553, // doomednum - S_GRAYSPRING, // spawnstate - 100, // spawnhealth - S_GRAYSPRING2, // seestate - sfx_None, // seesound - 8, // reactiontime - sfx_None, // attacksound - S_NULL, // painstate - 0, // painchance - sfx_spring, // painsound - S_NULL, // meleestate - S_NULL, // missilestate - S_NULL, // deathstate - S_NULL, // xdeathstate - sfx_None, // deathsound - 0, // speed - 20*FRACUNIT, // radius - 16*FRACUNIT, // height - 0, // display offset - 6*FRACUNIT, // mass - 0, // damage - sfx_None, // activesound - MF_SOLID|MF_SPRING|MF_DONTENCOREMAP, // flags - S_GRAYSPRING2 // raisestate - }, - - { // MT_INVISSPRING - 554, // doomednum - S_INVISIBLE, // spawnstate - 100, // spawnhealth - S_INVISSPRING, // seestate - sfx_None, // seesound - 8, // reactiontime - sfx_None, // attacksound - S_NULL, // painstate - 0, // painchance - sfx_spring, // painsound - S_NULL, // meleestate - S_NULL, // missilestate - S_NULL, // deathstate - S_NULL, // xdeathstate - sfx_None, // deathsound - 0, // speed - 20*FRACUNIT, // radius - 16*FRACUNIT, // height - 0, // display offset - 6*FRACUNIT, // mass - 0, // damage - sfx_None, // activesound - MF_SOLID|MF_SPRING, // flags - S_INVISSPRING // raisestate - }, - - { // MT_BLUEDIAG - 557, // doomednum - S_BDIAG1, // spawnstate - 1, // spawnhealth - S_BDIAG2, // seestate - sfx_None, // seesound - 8, // reactiontime - sfx_None, // attacksound - S_NULL, // painstate - 0, // painchance - sfx_spring, // painsound - S_NULL, // meleestate - S_NULL, // missilestate - S_NULL, // deathstate - S_NULL, // xdeathstate - sfx_None, // deathsound - 0, // speed - 16*FRACUNIT, // radius - 16*FRACUNIT, // height - 0, // display offset - 14*FRACUNIT, // mass - 14*FRACUNIT, // damage - sfx_None, // activesound - MF_SOLID|MF_SPRING|MF_DONTENCOREMAP, // flags - S_BDIAG2 // raisestate - }, - { // MT_RANDOMITEM 2000, // doomednum S_RANDOMITEM1, // spawnstate @@ -20149,6 +20277,121 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, + { // MT_TIREGREASE + -1, // doomednum + S_TIREGREASE, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 8<destscale = (3*player->mo->scale)/2)); band->color = colors[c]; band->colorized = true; @@ -4531,6 +4531,15 @@ static void K_MoveHeldObjects(player_t *player) if (R_PointToDist2(cur->x, cur->y, targx, targy) > 768*FRACUNIT) P_TeleportMove(cur, targx, targy, cur->z); +#ifdef ESLOPE + if (P_IsObjectOnGround(cur)) + { + // Slope values are set in the function, but we DON'T want to use its return value. + P_CalculateShadowFloor(cur, cur->x, cur->y, cur->z, + cur->radius, cur->height, (cur->eflags & MFE_VERTICALFLIP), false); + } +#endif + cur = cur->hnext; } } @@ -4620,6 +4629,9 @@ static void K_MoveHeldObjects(player_t *player) P_TeleportMove(cur, targx, targy, targz); K_FlipFromObject(cur, player->mo); // Update graviflip in real time thanks. +#ifdef HWRENDER + cur->modeltilt = player->mo->modeltilt; +#endif num = (num+1) % 2; cur = cur->hnext; } @@ -5063,6 +5075,29 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) if (P_IsDisplayPlayer(player)) debtflag->flags2 |= MF2_DONTDRAW; } + + if (player->kartstuff[k_springstars] && (leveltime & 1)) + { + fixed_t randx = P_RandomRange(-40, 40) * player->mo->scale; + fixed_t randy = P_RandomRange(-40, 40) * player->mo->scale; + fixed_t randz = P_RandomRange(0, player->mo->height >> FRACBITS) << FRACBITS; + mobj_t *star = P_SpawnMobj( + player->mo->x + randx, + player->mo->y + randy, + player->mo->z + randz, + MT_KARMAFIREWORK); + + star->color = player->kartstuff[k_springcolor]; + star->flags |= MF_NOGRAVITY; + star->momx = player->mo->momx / 2; + star->momy = player->mo->momy / 2; + star->momz = player->mo->momz / 2; + star->fuse = 12; + star->scale = player->mo->scale; + star->destscale = star->scale / 2; + + player->kartstuff[k_springstars]--; + } } if (player->playerstate == PST_DEAD || player->kartstuff[k_respawn] > 1) // Ensure these are set correctly here @@ -5105,6 +5140,25 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) player->mo->colorized = false; player->mo->color = player->skincolor; } + } + else if (player->kartstuff[k_killfield]) // You're gonna REALLY diiiiie + { + const INT32 flashtime = 4<<(4-(player->kartstuff[k_killfield]/TICRATE)); + if (player->kartstuff[k_killfield] == 1 || (player->kartstuff[k_killfield] % (flashtime/2) != 0)) + { + player->mo->colorized = false; + player->mo->color = player->skincolor; + } + else if (player->kartstuff[k_killfield] % flashtime == 0) + { + player->mo->colorized = true; + player->mo->color = SKINCOLOR_BYZANTIUM; + } + else + { + player->mo->colorized = true; + player->mo->color = SKINCOLOR_RUBY; + } } else if (player->kartstuff[k_ringboost] && (leveltime & 1)) // ring boosting { @@ -5265,6 +5319,9 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) if (player->kartstuff[k_justbumped]) player->kartstuff[k_justbumped]--; + if (player->kartstuff[k_tiregrease]) + player->kartstuff[k_tiregrease]--; + // This doesn't go in HUD update because it has potential gameplay ramifications if (player->karthud[khud_itemblink] && player->karthud[khud_itemblink]-- <= 0) { @@ -5274,8 +5331,28 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) K_KartPlayerHUDUpdate(player); - if (G_BattleGametype() && player->kartstuff[k_bumper] > 0) - player->kartstuff[k_wanted]++; + if (G_BattleGametype() && player->kartstuff[k_bumper] > 0 + && !player->kartstuff[k_spinouttimer] && !player->kartstuff[k_squishedtimer] + && !player->kartstuff[k_respawn] && !player->powers[pw_flashing]) + { + player->kartstuff[k_wanted]++; + if (battleovertime.enabled >= 10*TICRATE) + { + if (P_AproxDistance(player->mo->x - battleovertime.x, player->mo->y - battleovertime.y) > battleovertime.radius) + { + player->kartstuff[k_killfield]++; + if (player->kartstuff[k_killfield] > 4*TICRATE) + { + K_SpinPlayer(player, NULL, 0, NULL, false); + //player->kartstuff[k_killfield] = 1; + } + } + else if (player->kartstuff[k_killfield] > 0) + player->kartstuff[k_killfield]--; + } + } + else if (player->kartstuff[k_killfield] > 0) + player->kartstuff[k_killfield]--; if (P_IsObjectOnGround(player->mo)) player->kartstuff[k_waterskip] = 0; @@ -5305,17 +5382,6 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) } } - // ??? - /* - if (player->kartstuff[k_jmp] > 1 && onground) - { - S_StartSound(player->mo, sfx_spring); - P_DoJump(player, false); - player->mo->momz *= player->kartstuff[k_jmp]; - player->kartstuff[k_jmp] = 0; - } - */ - if (player->kartstuff[k_comebacktimer]) player->kartstuff[k_comebackmode] = 0; @@ -5445,15 +5511,16 @@ static INT16 K_GetKartDriftValue(player_t *player, fixed_t countersteer) return 0; if (player->kartstuff[k_driftend] != 0) - { return -266*player->kartstuff[k_drift]; // Drift has ended and we are tweaking their angle back a bit - } //basedrift = 90*player->kartstuff[k_drift]; // 450 //basedrift = 93*player->kartstuff[k_drift] - driftweight*3*player->kartstuff[k_drift]/10; // 447 - 303 basedrift = 83*player->kartstuff[k_drift] - (driftweight - 14)*player->kartstuff[k_drift]/5; // 415 - 303 driftangle = abs((252 - driftweight)*player->kartstuff[k_drift]/5); + if (player->kartstuff[k_tiregrease] > 0) // Buff drift-steering while in greasemode + basedrift += (basedrift / greasetics) * player->kartstuff[k_tiregrease]; + return basedrift + FixedMul(driftangle, countersteer); } @@ -5927,7 +5994,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground) && 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_growshrinktimer] > 0 || player->kartstuff[k_rocketsneakertimer] || player->kartstuff[k_eggmanexplode])) player->kartstuff[k_userings] = 1; @@ -6495,6 +6562,12 @@ void K_MoveKartPlayer(player_t *player, boolean onground) if (onground) { + fixed_t prevfriction = player->mo->friction; + + // Reduce friction after hitting a horizontal spring + if (player->kartstuff[k_tiregrease]) + player->mo->friction += ((FRACUNIT - prevfriction) / greasetics) * player->kartstuff[k_tiregrease]; + // Friction if (!player->kartstuff[k_offroad]) { @@ -6507,9 +6580,20 @@ void K_MoveKartPlayer(player_t *player, boolean onground) // Karma ice physics if (G_BattleGametype() && player->kartstuff[k_bumper] <= 0) - { player->mo->friction += 1228; + // Wipeout slowdown + if (player->kartstuff[k_spinouttimer] && player->kartstuff[k_wipeoutslow]) + { + if (player->kartstuff[k_offroad]) + player->mo->friction -= 4912; + if (player->kartstuff[k_wipeoutslow] == 1) + player->mo->friction -= 9824; + } + + // Friction was changed, so we must recalculate a bunch of stuff + if (player->mo->friction != prevfriction) + { if (player->mo->friction > FRACUNIT) player->mo->friction = FRACUNIT; if (player->mo->friction < 0) @@ -6520,20 +6604,11 @@ void K_MoveKartPlayer(player_t *player, boolean onground) if (player->mo->movefactor < FRACUNIT) player->mo->movefactor = 19*player->mo->movefactor - 18*FRACUNIT; else - player->mo->movefactor = FRACUNIT; //player->mo->movefactor = ((player->mo->friction - 0xDB34)*(0xA))/0x80; + player->mo->movefactor = FRACUNIT; if (player->mo->movefactor < 32) player->mo->movefactor = 32; } - - // Wipeout slowdown - if (player->kartstuff[k_spinouttimer] && player->kartstuff[k_wipeoutslow]) - { - if (player->kartstuff[k_offroad]) - player->mo->friction -= 4912; - if (player->kartstuff[k_wipeoutslow] == 1) - player->mo->friction -= 9824; - } } K_KartDrift(player, onground); @@ -7009,7 +7084,8 @@ static patch_t *kp_lapanim_number[10][3]; static patch_t *kp_lapanim_emblem[2]; static patch_t *kp_lapanim_hand[3]; -static patch_t *kp_yougotem; +static patch_t *kp_yougotem; +static patch_t *kp_itemminimap; void K_LoadKartHUDGraphics(void) { @@ -7309,7 +7385,8 @@ void K_LoadKartHUDGraphics(void) kp_lapanim_hand[i] = (patch_t *) W_CachePatchName(buffer, PU_HUDGFX); } - kp_yougotem = (patch_t *) W_CachePatchName("YOUGOTEM", PU_HUDGFX); + kp_yougotem = (patch_t *) W_CachePatchName("YOUGOTEM", PU_HUDGFX); + kp_itemminimap = (patch_t *) W_CachePatchName("MMAPITEM", PU_HUDGFX); } // For the item toggle menu @@ -8833,229 +8910,279 @@ static void K_drawKartPlayerCheck(void) V_DrawMappedPatch(x, CHEK_Y, V_HUDTRANS|splitflags, kp_check[pnum], colormap); } } -} +} -static void K_drawKartMinimapHead(mobj_t *mo, INT32 x, INT32 y, INT32 flags, patch_t *AutomapPic) -{ - // amnum xpos & ypos are the icon's speed around the HUD. - // The number being divided by is for how fast it moves. - // The higher the number, the slower it moves. +static void K_drawKartMinimapIcon(fixed_t objx, fixed_t objy, INT32 hudx, INT32 hudy, INT32 flags, patch_t *icon, UINT8 *colormap, patch_t *AutomapPic) +{ + // amnum xpos & ypos are the icon's speed around the HUD. + // The number being divided by is for how fast it moves. + // The higher the number, the slower it moves. + + // am xpos & ypos are the icon's starting position. Withouht + // it, they wouldn't 'spawn' on the top-right side of the HUD. + + fixed_t amnumxpos, amnumypos; + INT32 amxpos, amypos; + + node_t *bsp = &nodes[numnodes-1]; + fixed_t maxx, minx, maxy, miny; + + fixed_t mapwidth, mapheight; + fixed_t xoffset, yoffset; + fixed_t xscale, yscale, zoom; + + maxx = maxy = INT32_MAX; + minx = miny = INT32_MIN; + minx = bsp->bbox[0][BOXLEFT]; + maxx = bsp->bbox[0][BOXRIGHT]; + miny = bsp->bbox[0][BOXBOTTOM]; + maxy = bsp->bbox[0][BOXTOP]; + + if (bsp->bbox[1][BOXLEFT] < minx) + minx = bsp->bbox[1][BOXLEFT]; + if (bsp->bbox[1][BOXRIGHT] > maxx) + maxx = bsp->bbox[1][BOXRIGHT]; + if (bsp->bbox[1][BOXBOTTOM] < miny) + miny = bsp->bbox[1][BOXBOTTOM]; + if (bsp->bbox[1][BOXTOP] > maxy) + maxy = bsp->bbox[1][BOXTOP]; + + // You might be wondering why these are being bitshift here + // it's because mapwidth and height would otherwise overflow for maps larger than half the size possible... + // map boundaries and sizes will ALWAYS be whole numbers thankfully + // later calculations take into consideration that these are actually not in terms of FRACUNIT though + minx >>= FRACBITS; + maxx >>= FRACBITS; + miny >>= FRACBITS; + maxy >>= FRACBITS; + + mapwidth = maxx - minx; + mapheight = maxy - miny; + + // These should always be small enough to be bitshift back right now + xoffset = (minx + mapwidth/2)<width, mapwidth); + yscale = FixedDiv(AutomapPic->height, mapheight); + zoom = FixedMul(min(xscale, yscale), FRACUNIT-FRACUNIT/20); + + amnumxpos = (FixedMul(objx, zoom) - FixedMul(xoffset, zoom)); + amnumypos = -(FixedMul(objy, zoom) - FixedMul(yoffset, zoom)); + + if (encoremode) + amnumxpos = -amnumxpos; + + amxpos = amnumxpos + ((hudx + AutomapPic->width/2 - (icon->width/2))<height/2 - (icon->height/2))<width/2 + (icon->width/2))<width/2); + y = MINI_Y - (AutomapPic->height/2); + + if (timeinmap > 105) + { + minimaptrans = cv_kartminimap.value; + if (timeinmap <= 113) + minimaptrans = ((((INT32)timeinmap) - 105)*minimaptrans)/(113-105); + if (!minimaptrans) + return; + } + else + return; + + minimaptrans = ((10-minimaptrans)<width), y, splitflags|V_FLIP, AutomapPic); + else + V_DrawScaledPatch(x, y, splitflags, AutomapPic); + + if (!(splitscreen == 2)) + { + splitflags &= ~minimaptrans; + splitflags |= V_HUDTRANSHALF; + } + + // let offsets transfer to the heads, too! + if (encoremode) + x += SHORT(AutomapPic->leftoffset); + else + x -= SHORT(AutomapPic->leftoffset); + y -= SHORT(AutomapPic->topoffset); + + // Draw the super item in Battle + if (G_BattleGametype() && battleovertime.enabled) + { + if (battleovertime.enabled >= 10*TICRATE || (battleovertime.enabled & 1)) + { + const INT32 prevsplitflags = splitflags; + splitflags &= ~V_HUDTRANSHALF; + splitflags |= V_HUDTRANS; + colormap = R_GetTranslationColormap(TC_RAINBOW, (UINT8)(1 + (leveltime % (MAXSKINCOLORS-1))), GTC_CACHE); + K_drawKartMinimapIcon(battleovertime.x, battleovertime.y, x, y, splitflags, kp_itemminimap, colormap, AutomapPic); + splitflags = prevsplitflags; + } + } + + // initialize + for (i = 0; i < 4; i++) + localplayers[i] = -1; + + // Player's tiny icons on the Automap. (drawn opposite direction so player 1 is drawn last in splitscreen) + if (ghosts) + { + demoghost *g = ghosts; + while (g) + { + if (g->mo->skin) + skin = ((skin_t*)g->mo->skin)-skins; + else + skin = 0; + if (g->mo->color) + { + if (g->mo->colorized) + colormap = R_GetTranslationColormap(TC_RAINBOW, g->mo->color, GTC_CACHE); + else + colormap = R_GetTranslationColormap(skin, g->mo->color, GTC_CACHE); + } + else + colormap = NULL; + K_drawKartMinimapIcon(g->mo->x, g->mo->y, x, y, splitflags, facemmapprefix[skin], colormap, AutomapPic); + g = g->next; + } + + if (!stplyr->mo || stplyr->spectator) // do we need the latter..? + return; + + localplayers[numlocalplayers] = stplyr-players; + numlocalplayers++; + } + else + { + for (i = MAXPLAYERS-1; i >= 0; i--) + { + if (!playeringame[i]) + continue; + if (!players[i].mo || players[i].spectator) + continue; + + if (i != displayplayers[0] || splitscreen) + { + if (G_BattleGametype() && players[i].kartstuff[k_bumper] <= 0) + continue; + + if (players[i].kartstuff[k_hyudorotimer] > 0) + { + if (!((players[i].kartstuff[k_hyudorotimer] < 1*TICRATE/2 + || players[i].kartstuff[k_hyudorotimer] > hyudorotime-(1*TICRATE/2)) + && !(leveltime & 1))) + continue; + } + } + + if (i == displayplayers[0] || i == displayplayers[1] || i == displayplayers[2] || i == displayplayers[3]) + { + // Draw display players on top of everything else + localplayers[numlocalplayers] = i; + numlocalplayers++; + continue; + } + + if (players[i].mo->skin) + skin = ((skin_t*)players[i].mo->skin)-skins; + else + skin = 0; + + if (players[i].mo->color) + { + if (players[i].mo->colorized) + colormap = R_GetTranslationColormap(TC_RAINBOW, players[i].mo->color, GTC_CACHE); + else + colormap = R_GetTranslationColormap(skin, players[i].mo->color, GTC_CACHE); + } + else + colormap = NULL; + + K_drawKartMinimapIcon(players[i].mo->x, players[i].mo->y, x, y, splitflags, facemmapprefix[skin], colormap, AutomapPic); + // Target reticule + if ((G_RaceGametype() && players[i].kartstuff[k_position] == spbplace) + || (G_BattleGametype() && K_IsPlayerWanted(&players[i]))) + K_drawKartMinimapIcon(players[i].mo->x, players[i].mo->y, x, y, splitflags, kp_wantedreticle, NULL, AutomapPic); + } + } + + // draw our local players here, opaque. + splitflags &= ~V_HUDTRANSHALF; + splitflags |= V_HUDTRANS; + + for (i = 0; i < numlocalplayers; i++) + { + if (i == -1) + continue; // this doesn't interest us + + if (players[localplayers[i]].mo->skin) + skin = ((skin_t*)players[localplayers[i]].mo->skin)-skins; + else + skin = 0; + + if (players[localplayers[i]].mo->color) + { + if (players[localplayers[i]].mo->colorized) + colormap = R_GetTranslationColormap(TC_RAINBOW, players[localplayers[i]].mo->color, GTC_CACHE); + else + colormap = R_GetTranslationColormap(skin, players[localplayers[i]].mo->color, GTC_CACHE); + } + else + colormap = NULL; + + K_drawKartMinimapIcon(players[localplayers[i]].mo->x, players[localplayers[i]].mo->y, x, y, splitflags, facemmapprefix[skin], colormap, AutomapPic); - UINT8 skin = 0; - - fixed_t amnumxpos, amnumypos; - INT32 amxpos, amypos; - - node_t *bsp = &nodes[numnodes-1]; - fixed_t maxx, minx, maxy, miny; - - fixed_t mapwidth, mapheight; - fixed_t xoffset, yoffset; - fixed_t xscale, yscale, zoom; - - if (mo->skin) - skin = ((skin_t*)mo->skin)-skins; - - maxx = maxy = INT32_MAX; - minx = miny = INT32_MIN; - minx = bsp->bbox[0][BOXLEFT]; - maxx = bsp->bbox[0][BOXRIGHT]; - miny = bsp->bbox[0][BOXBOTTOM]; - maxy = bsp->bbox[0][BOXTOP]; - - if (bsp->bbox[1][BOXLEFT] < minx) - minx = bsp->bbox[1][BOXLEFT]; - if (bsp->bbox[1][BOXRIGHT] > maxx) - maxx = bsp->bbox[1][BOXRIGHT]; - if (bsp->bbox[1][BOXBOTTOM] < miny) - miny = bsp->bbox[1][BOXBOTTOM]; - if (bsp->bbox[1][BOXTOP] > maxy) - maxy = bsp->bbox[1][BOXTOP]; - - // You might be wondering why these are being bitshift here - // it's because mapwidth and height would otherwise overflow for maps larger than half the size possible... - // map boundaries and sizes will ALWAYS be whole numbers thankfully - // later calculations take into consideration that these are actually not in terms of FRACUNIT though - minx >>= FRACBITS; - maxx >>= FRACBITS; - miny >>= FRACBITS; - maxy >>= FRACBITS; - - mapwidth = maxx - minx; - mapheight = maxy - miny; - - // These should always be small enough to be bitshift back right now - xoffset = (minx + mapwidth/2)<width, mapwidth); - yscale = FixedDiv(AutomapPic->height, mapheight); - zoom = FixedMul(min(xscale, yscale), FRACUNIT-FRACUNIT/20); - - amnumxpos = (FixedMul(mo->x, zoom) - FixedMul(xoffset, zoom)); - amnumypos = -(FixedMul(mo->y, zoom) - FixedMul(yoffset, zoom)); - - if (encoremode) - amnumxpos = -amnumxpos; - - amxpos = amnumxpos + ((x + AutomapPic->width/2 - (facemmapprefix[skin]->width/2))<height/2 - (facemmapprefix[skin]->height/2))<width/2 + (facemmapprefix[skin]->width/2))<color) // 'default' color - V_DrawSciencePatch(amxpos, amypos, flags, facemmapprefix[skin], FRACUNIT); - else - { - UINT8 *colormap; - if (mo->colorized) - colormap = R_GetTranslationColormap(TC_RAINBOW, mo->color, GTC_CACHE); - else - colormap = R_GetTranslationColormap(skin, mo->color, GTC_CACHE); - V_DrawFixedPatch(amxpos, amypos, FRACUNIT, flags, facemmapprefix[skin], colormap); - if (mo->player - && ((G_RaceGametype() && mo->player->kartstuff[k_position] == spbplace) - || (G_BattleGametype() && K_IsPlayerWanted(mo->player)))) - { - V_DrawFixedPatch(amxpos - (4<width/2); - y = MINI_Y - (AutomapPic->height/2); - - if (timeinmap > 105) - { - minimaptrans = cv_kartminimap.value; - if (timeinmap <= 113) - minimaptrans = ((((INT32)timeinmap) - 105)*minimaptrans)/(113-105); - if (!minimaptrans) - return; - } - else - return; - - minimaptrans = ((10-minimaptrans)<width), y, splitflags|V_FLIP, AutomapPic); - else - V_DrawScaledPatch(x, y, splitflags, AutomapPic); - - if (!(splitscreen == 2)) - { - splitflags &= ~minimaptrans; - splitflags |= V_HUDTRANSHALF; - } - - // let offsets transfer to the heads, too! - if (encoremode) - x += SHORT(AutomapPic->leftoffset); - else - x -= SHORT(AutomapPic->leftoffset); - y -= SHORT(AutomapPic->topoffset); - - // initialize - for (i = 0; i < 4; i++) - localplayers[i] = -1; - - // Player's tiny icons on the Automap. (drawn opposite direction so player 1 is drawn last in splitscreen) - if (ghosts) - { - demoghost *g = ghosts; - while (g) - { - K_drawKartMinimapHead(g->mo, x, y, splitflags, AutomapPic); - g = g->next; - } - - if (!stplyr->mo || stplyr->spectator) // do we need the latter..? - return; - - localplayers[numlocalplayers] = stplyr-players; - numlocalplayers++; - } - else - { - for (i = MAXPLAYERS-1; i >= 0; i--) - { - if (!playeringame[i]) - continue; - if (!players[i].mo || players[i].spectator) - continue; - - if (i != displayplayers[0] || splitscreen) - { - if (G_BattleGametype() && players[i].kartstuff[k_bumper] <= 0) - continue; - - if (players[i].kartstuff[k_hyudorotimer] > 0) - { - if (!((players[i].kartstuff[k_hyudorotimer] < 1*TICRATE/2 - || players[i].kartstuff[k_hyudorotimer] > hyudorotime-(1*TICRATE/2)) - && !(leveltime & 1))) - continue; - } - } - - if (P_IsDisplayPlayer(&players[i])) - { - // Draw display players on top of everything else - localplayers[numlocalplayers] = i; - numlocalplayers++; - continue; - } - - K_drawKartMinimapHead(players[i].mo, x, y, splitflags, AutomapPic); - } - } - - // draw our local players here, opaque. - splitflags &= ~V_HUDTRANSHALF; - splitflags |= V_HUDTRANS; - - for (i = 0; i < numlocalplayers; i++) - { - if (i == -1) - continue; // this doesn't interest us - K_drawKartMinimapHead(players[localplayers[i]].mo, x, y, splitflags, AutomapPic); - } -} + // Target reticule + if ((G_RaceGametype() && players[localplayers[i]].kartstuff[k_position] == spbplace) + || (G_BattleGametype() && K_IsPlayerWanted(&players[localplayers[i]]))) + K_drawKartMinimapIcon(players[localplayers[i]].mo->x, players[localplayers[i]].mo->y, x, y, splitflags, kp_wantedreticle, NULL, AutomapPic); + } +} static void K_drawKartStartCountdown(void) { diff --git a/src/lua_baselib.c b/src/lua_baselib.c index 38af4d2e9..7464743c3 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -1405,15 +1405,15 @@ static int lib_pIsFlagAtBase(lua_State *L) static int lib_pSetupLevelSky(lua_State *L) { - INT32 skynum = (INT32)luaL_checkinteger(L, 1); + const char *skytexname = luaL_checkstring(L, 1); player_t *user = NULL; NOHUD if (!lua_isnone(L, 2) && lua_isuserdata(L, 2)) // if a player, setup sky for only the player, otherwise setup sky for all players user = *((player_t **)luaL_checkudata(L, 2, META_PLAYER)); if (!user) // global - P_SetupLevelSky(skynum, true); + P_SetupLevelSky(skytexname, true); else if (P_IsLocalPlayer(user)) - P_SetupLevelSky(skynum, false); + P_SetupLevelSky(skytexname, false); return 0; } diff --git a/src/lua_maplib.c b/src/lua_maplib.c index 19292b3d6..0522cb737 100644 --- a/src/lua_maplib.c +++ b/src/lua_maplib.c @@ -1487,8 +1487,8 @@ static int mapheaderinfo_get(lua_State *L) lua_pushstring(L, header->forcecharacter); else if (fastcmp(field,"weather")) lua_pushinteger(L, header->weather); - else if (fastcmp(field,"skynum")) - lua_pushinteger(L, header->skynum); + else if (fastcmp(field,"skytexture")) + lua_pushstring(L, header->skytexture); else if (fastcmp(field,"skybox_scalex")) lua_pushinteger(L, header->skybox_scalex); else if (fastcmp(field,"skybox_scaley")) diff --git a/src/m_anigif.c b/src/m_anigif.c index 4e68819bc..4dfc77cb3 100644 --- a/src/m_anigif.c +++ b/src/m_anigif.c @@ -422,7 +422,7 @@ static void GIF_headwrite(void) WRITEUINT16(p, rheight); // colors, aspect, etc - WRITEUINT8(p, 0xF7); + WRITEUINT8(p, 0xFF); // TRANSPARENTPIXEL WRITEUINT8(p, 0x00); WRITEUINT8(p, 0x00); diff --git a/src/m_cheat.c b/src/m_cheat.c index e7e877ada..c24a8014b 100644 --- a/src/m_cheat.c +++ b/src/m_cheat.c @@ -577,14 +577,14 @@ void Command_Skynum_f(void) if (COM_Argc() != 2) { - CONS_Printf(M_GetText("skynum : change the sky\n")); - CONS_Printf(M_GetText("Current sky is %d\n"), levelskynum); + CONS_Printf(M_GetText("skynum : change the sky\n")); + CONS_Printf(M_GetText("Current sky is %s\n"), levelskytexture); return; } CONS_Printf(M_GetText("Previewing sky %s...\n"), COM_Argv(1)); - P_SetupLevelSky(atoi(COM_Argv(1)), false); + P_SetupLevelSky(COM_Argv(1), false); } void Command_Weather_f(void) diff --git a/src/m_menu.c b/src/m_menu.c index 9f4c3cda5..4a3102925 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -90,6 +90,10 @@ int snprintf(char *str, size_t n, const char *fmt, ...); #define SLIDER_WIDTH (8*SLIDER_RANGE+6) #define SERVERS_PER_PAGE 11 +#if defined (NONET) || defined (TESTERS) +#define NOMENUHOST +#endif + typedef enum { QUITMSG = 0, @@ -242,14 +246,18 @@ static menu_t SP_TimeAttackDef, SP_ReplayDef, SP_GuestReplayDef, SP_GhostDef; // Multiplayer #ifndef NONET +#ifndef TESTERS static void M_StartServerMenu(INT32 choice); +#endif static void M_ConnectMenu(INT32 choice); static void M_ConnectMenuModChecks(INT32 choice); static void M_Refresh(INT32 choice); static void M_Connect(INT32 choice); static void M_ChooseRoom(INT32 choice); #endif +#ifndef TESTERS static void M_StartOfflineServerMenu(INT32 choice); +#endif static void M_StartServer(INT32 choice); static void M_SetupMultiPlayer(INT32 choice); static void M_SetupMultiPlayer2(INT32 choice); @@ -475,9 +483,14 @@ static menuitem_t MainMenu[] = { {IT_SUBMENU|IT_STRING, NULL, "Extras", &SR_MainDef, 76}, //{IT_CALL |IT_STRING, NULL, "1 Player", M_SinglePlayerMenu, 84}, +#ifdef TESTERS + {IT_GRAYEDOUT, NULL, "Time Attack", NULL, 84}, +#else {IT_CALL |IT_STRING, NULL, "Time Attack", M_TimeAttack, 84}, +#endif {IT_SUBMENU|IT_STRING, NULL, "Multiplayer", &MP_MainDef, 92}, {IT_CALL |IT_STRING, NULL, "Options", M_Options, 100}, + /* I don't think is useful at all... */ {IT_CALL |IT_STRING, NULL, "Addons", M_Addons, 108}, {IT_CALL |IT_STRING, NULL, "Quit Game", M_QuitSRB2, 116}, }; @@ -728,7 +741,9 @@ static menuitem_t SR_PandorasBox[] = // Sky Room Custom Unlocks static menuitem_t SR_MainMenu[] = { +#ifndef TESTERS {IT_STRING|IT_SUBMENU, NULL, "Unlockables", &SR_UnlockChecklistDef, 100}, +#endif {IT_CALL|IT_STRING|IT_CALL_NOTMODIFIED, NULL, "Statistics", M_Statistics, 108}, {IT_CALL|IT_STRING, NULL, "Replay Hut", M_ReplayHut, 116}, {IT_DISABLED, NULL, "", NULL, 0}, // Custom1 @@ -962,12 +977,16 @@ static menuitem_t MP_MainMenu[] = {IT_STRING|IT_KEYHANDLER,NULL, "Player setup...", M_SetupMultiHandler,18}, {IT_HEADER, NULL, "Host a game", NULL, 100-24}, -#ifndef NONET +#ifndef NOMENUHOST {IT_STRING|IT_CALL, NULL, "Internet/LAN...", M_StartServerMenu, 110-24}, #else {IT_GRAYEDOUT, NULL, "Internet/LAN...", NULL, 110-24}, #endif +#ifdef TESTERS + {IT_GRAYEDOUT, NULL, "Offline...", NULL, 118-24}, +#else {IT_STRING|IT_CALL, NULL, "Offline...", M_StartOfflineServerMenu, 118-24}, +#endif {IT_HEADER, NULL, "Join a game", NULL, 132-24}, #ifndef NONET @@ -3029,7 +3048,11 @@ void M_StartControlPanel(void) //MainMenu[secrets].status = (M_AnySecretUnlocked()) ? (IT_STRING | IT_CALL) : (IT_DISABLED); currentMenu = &MainDef; +#ifdef TESTERS + itemOn = multiplr; +#else itemOn = singleplr; +#endif } else if (modeattacking) { @@ -4092,6 +4115,14 @@ static void M_DrawCenteredMenu(void) W_CachePatchName(currentMenu->menuitems[i].patch,PU_CACHE), graymap); y += LINEHEIGHT; break; + case IT_TRANSTEXT: + if (currentMenu->menuitems[i].alphaKey) + y = currentMenu->y+currentMenu->menuitems[i].alphaKey; + /* FALLTHRU */ + case IT_TRANSTEXT2: + V_DrawCenteredString(x, y, V_TRANSLUCENT, currentMenu->menuitems[i].text); + y += SMALLLINEHEIGHT; + break; } } @@ -8787,6 +8818,7 @@ static void M_MapChange(INT32 choice) M_SetupNextMenu(&MISC_ChangeLevelDef); } +#ifndef TESTERS static void M_StartOfflineServerMenu(INT32 choice) { (void)choice; @@ -8794,8 +8826,10 @@ static void M_StartOfflineServerMenu(INT32 choice) M_PrepareLevelSelect(); M_SetupNextMenu(&MP_OfflineServerDef); } +#endif #ifndef NONET +#ifndef TESTERS static void M_StartServerMenu(INT32 choice) { (void)choice; @@ -8805,6 +8839,7 @@ static void M_StartServerMenu(INT32 choice) M_SetupNextMenu(&MP_ServerDef); } +#endif // ============== // CONNECT VIA IP @@ -8824,7 +8859,7 @@ static void M_DrawMPMainMenu(void) // use generic drawer for cursor, items and title M_DrawGenericMenu(); -#ifndef NONET +#ifndef NOMENUHOST #if MAXPLAYERS != 16 Update the maxplayers label... #endif @@ -8832,10 +8867,12 @@ Update the maxplayers label... ((itemOn == 4) ? highlightflags : 0), "(2-16 players)"); #endif +#ifndef TESTERS V_DrawRightAlignedString(BASEVIDWIDTH-x, y+MP_MainMenu[5].alphaKey, ((itemOn == 5) ? highlightflags : 0), "(2-4 players)" ); +#endif #ifndef NONET y += MP_MainMenu[8].alphaKey; diff --git a/src/p_enemy.c b/src/p_enemy.c index 9569b2c4c..3c59c40f5 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -8299,7 +8299,7 @@ void A_ItemPop(mobj_t *actor) remains->flags = actor->flags; // Transfer flags remains->flags2 = actor->flags2; // Transfer flags2 remains->fuse = actor->fuse; // Transfer respawn timer - remains->threshold = (actor->threshold == 69 ? 69 : 68); + remains->threshold = (actor->threshold == 70 ? 70 : (actor->threshold == 69 ? 69 : 68)); remains->skin = NULL; remains->spawnpoint = actor->spawnpoint; @@ -8313,7 +8313,7 @@ void A_ItemPop(mobj_t *actor) remains->flags2 &= ~MF2_AMBUSH; - if (G_BattleGametype() && actor->threshold != 69) + if (G_BattleGametype() && (actor->threshold != 69 && actor->threshold != 70)) numgotboxes++; P_RemoveMobj(actor); diff --git a/src/p_inter.c b/src/p_inter.c index 64bd573f1..7a975951c 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -1776,6 +1776,9 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) } } +// Easily make it so that overtime works offline +//#define TESTOVERTIMEINFREEPLAY + /** Checks if the level timer is over the timelimit and the round should end, * unless you are in overtime. In which case leveltime may stretch out beyond * timelimitintics and overtime's status will be checked here each tick. @@ -1786,7 +1789,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) */ void P_CheckTimeLimit(void) { - INT32 i, k; + INT32 i; if (!cv_timelimit.value) return; @@ -1820,71 +1823,76 @@ void P_CheckTimeLimit(void) } } } + else*/ //Optional tie-breaker for Match/CTF - else*/ if (cv_overtime.value) + if (cv_overtime.value) { - INT32 playerarray[MAXPLAYERS]; - INT32 tempplayer = 0; - INT32 spectators = 0; - INT32 playercount = 0; - - //Figure out if we have enough participating players to care. +#ifndef TESTOVERTIMEINFREEPLAY + boolean foundone = false; // Overtime is used for closing off down to a specific item. for (i = 0; i < MAXPLAYERS; i++) { - if (players[i].exiting) - return; - if (playeringame[i] && players[i].spectator) - spectators++; - } - - if ((D_NumPlayers() - spectators) > 1) - { - // Play the starpost sfx after the first second of overtime. - if (gamestate == GS_LEVEL && (leveltime == (timelimitintics + TICRATE))) - S_StartSound(NULL, sfx_strpst); - - // Normal Match - if (!G_GametypeHasTeams()) + if (!playeringame[i] || players[i].spectator) + continue; + if (foundone) { - //Store the nodes of participating players in an array. - for (i = 0; i < MAXPLAYERS; i++) +#endif + // Initiate the kill zone + if (!battleovertime.enabled) { - if (playeringame[i] && !players[i].spectator) + INT32 b = 0; + thinker_t *th; + mobj_t *item = NULL; + + P_RespawnBattleBoxes(); // FORCE THESE TO BE RESPAWNED FOR THIS!!!!!!! + + // Find us an item box to center on. + for (th = thinkercap.next; th != &thinkercap; th = th->next) { - playerarray[playercount] = i; - playercount++; + mobj_t *thismo; + if (th->function.acp1 != (actionf_p1)P_MobjThinker) + continue; + thismo = (mobj_t *)th; + + if (thismo->type != MT_RANDOMITEM) + continue; + if (thismo->threshold == 69) // Disappears + continue; + + b++; + + // Only select items that are on the ground, ignore ones in the air. Ambush flag inverts this rule. + if ((!P_IsObjectOnGround(thismo)) != (thismo->flags2 & MF2_AMBUSH)) + continue; + + if (item == NULL || (b < nummapboxes && P_RandomChance(((nummapboxes-b)*FRACUNIT)/nummapboxes))) // This is to throw off the RNG some + item = thismo; + if (b >= nummapboxes) // end early if we've found them all already + break; } - } - if (playercount > MAXPLAYERS) - playercount = MAXPLAYERS; - - //Sort 'em. - for (i = 1; i < playercount; i++) - { - for (k = i; k < playercount; k++) + if (item == NULL) // no item found, could happen if every item is in the air or has ambush flag, or the map has none { - if (players[playerarray[i-1]].marescore < players[playerarray[k]].marescore) - { - tempplayer = playerarray[i-1]; - playerarray[i-1] = playerarray[k]; - playerarray[k] = tempplayer; - } + CONS_Alert(CONS_WARNING, "No usuable items for Battle overtime!\n"); + return; } - } - //End the round if the top players aren't tied. - if (players[playerarray[0]].marescore == players[playerarray[1]].marescore) - return; + item->threshold = 70; // Set constant respawn + battleovertime.x = item->x; + battleovertime.y = item->y; + battleovertime.z = item->z; + battleovertime.radius = 4096*mapobjectscale; + battleovertime.minradius = (cv_overtime.value == 2 ? 40 : 512) * mapobjectscale; + battleovertime.enabled = 1; + S_StartSound(NULL, sfx_kc47); + } + return; +#ifndef TESTOVERTIMEINFREEPLAY } else - { - //In team match and CTF, determining a tie is much simpler. =P - if (redscore == bluescore) - return; - } + foundone = true; } +#endif } for (i = 0; i < MAXPLAYERS; i++) @@ -1895,9 +1903,6 @@ void P_CheckTimeLimit(void) return; P_DoPlayerExit(&players[i]); } - - /*if (server) - SendNetXCmd(XD_EXITLEVEL, NULL, 0);*/ } /** Checks if a player's score is over the pointlimit and the round should end. @@ -3304,12 +3309,12 @@ void P_PlayerRingBurst(player_t *player, INT32 num_rings) // 20 is the ring cap in kart if (num_rings > 20) - num_rings = 20; + num_rings = 20; else if (num_rings <= 0) return; // Cap the maximum loss automatically to 2 in ring debt - if (player->kartstuff[k_rings] <= 0 && num_rings > 2) + if (player->kartstuff[k_rings] <= 0 && num_rings > 2) num_rings = 2; P_GivePlayerRings(player, -num_rings); diff --git a/src/p_local.h b/src/p_local.h index bc25affd4..33f0026da 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -211,6 +211,7 @@ extern tic_t itemrespawntime[ITEMQUESIZE]; extern size_t iquehead, iquetail; extern consvar_t cv_gravity/*, cv_viewheight*/; +void P_RespawnBattleBoxes(void); void P_RespawnSpecials(void); mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type); @@ -227,7 +228,9 @@ boolean P_SetPlayerMobjState(mobj_t *mobj, statenum_t state); boolean P_SetMobjState(mobj_t *mobj, statenum_t state); //void P_RunShields(void); void P_RunOverlays(void); +fixed_t P_CalculateShadowFloor(mobj_t *mobj, fixed_t x, fixed_t y, fixed_t z, fixed_t radius, fixed_t height, boolean flip, boolean player); void P_RunShadows(void); +void P_RunBattleOvertime(void); void P_MobjThinker(mobj_t *mobj); boolean P_RailThinker(mobj_t *mobj); void P_PushableThinker(mobj_t *mobj); diff --git a/src/p_map.c b/src/p_map.c index d99105005..d4f2a94fa 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -113,14 +113,18 @@ boolean P_TeleportMove(mobj_t *thing, fixed_t x, fixed_t y, fixed_t z) // MOVEMENT ITERATOR FUNCTIONS // ========================================================================= +//#define TELEPORTJANK + boolean P_DoSpring(mobj_t *spring, mobj_t *object) { //INT32 pflags; const fixed_t hscale = mapobjectscale + (mapobjectscale - object->scale); const fixed_t vscale = mapobjectscale + (object->scale - mapobjectscale); - fixed_t offx, offy; fixed_t vertispeed = spring->info->mass; fixed_t horizspeed = spring->info->damage; + UINT8 starcolor = (spring->info->painchance % MAXTRANSLATIONS); + fixed_t savemomx = 0; + fixed_t savemomy = 0; if (object->eflags & MFE_SPRUNG) // Object was already sprung this tic return false; @@ -142,29 +146,36 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object) object->eflags |= MFE_SPRUNG; // apply this flag asap! spring->flags &= ~(MF_SOLID|MF_SPECIAL); // De-solidify +#ifdef TELEPORTJANK if (horizspeed && vertispeed) // Mimic SA { object->momx = object->momy = 0; P_TryMove(object, spring->x, spring->y, true); } +#endif if (spring->eflags & MFE_VERTICALFLIP) vertispeed *= -1; + // Vertical springs teleport you on TOP of them. if (vertispeed > 0) object->z = spring->z + spring->height + 1; else if (vertispeed < 0) object->z = spring->z - object->height - 1; else { + fixed_t offx, offy; + // Horizontal springs teleport you in FRONT of them. + savemomx = object->momx; + savemomy = object->momy; object->momx = object->momy = 0; // Overestimate the distance to position you at offx = P_ReturnThrustX(spring, spring->angle, (spring->radius + object->radius + 1) * 2); offy = P_ReturnThrustY(spring, spring->angle, (spring->radius + object->radius + 1) * 2); - // Make it square by clipping + // Then clip it down to a square, so it matches the hitbox size. if (offx > (spring->radius + object->radius + 1)) offx = spring->radius + object->radius + 1; else if (offx < -(spring->radius + object->radius + 1)) @@ -175,27 +186,94 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object) else if (offy < -(spring->radius + object->radius + 1)) offy = -(spring->radius + object->radius + 1); - // Set position! P_TryMove(object, spring->x + offx, spring->y + offy, true); } if (vertispeed) - object->momz = FixedMul(vertispeed,FixedSqrt(FixedMul(vscale, spring->scale))); + object->momz = FixedMul(vertispeed, FixedSqrt(FixedMul(vscale, spring->scale))); if (horizspeed) { - if (!object->player) - P_InstaThrustEvenIn2D(object, spring->angle, FixedMul(horizspeed,FixedSqrt(FixedMul(hscale, spring->scale)))); + angle_t finalAngle = spring->angle; + fixed_t finalSpeed = horizspeed; + fixed_t objectSpeed; + + if (object->player) + objectSpeed = object->player->speed; else + objectSpeed = R_PointToDist2(0, 0, savemomx, savemomy); + + if (!vertispeed) { - fixed_t finalSpeed = FixedDiv(horizspeed, hscale); - fixed_t pSpeed = object->player->speed; + // Scale to gamespeed + finalSpeed = FixedMul(finalSpeed, K_GetKartGameSpeedScalar(gamespeed)); - if (pSpeed > finalSpeed) - finalSpeed = pSpeed; + // Reflect your momentum angle against the surface of horizontal springs. + // This makes it a bit more interesting & unique than just being a speed boost in a pre-defined direction + if (savemomx || savemomy) + { + angle_t momang; + INT32 angoffset; + boolean subtract = false; - P_InstaThrustEvenIn2D(object, spring->angle, FixedMul(finalSpeed,FixedSqrt(FixedMul(hscale, spring->scale)))); + momang = R_PointToAngle2(0, 0, savemomx, savemomy); + + angoffset = momang; + angoffset -= spring->angle; // Subtract + + // Flip on wrong side + if ((angle_t)angoffset > ANGLE_180) + { + angoffset = InvAngle((angle_t)angoffset); + subtract = !subtract; + } + + // Fix going directly against the spring's angle sending you the wrong way + if ((spring->angle - momang) > ANGLE_90) + angoffset = ANGLE_180 - angoffset; + + // Offset is reduced to cap it (90 / 2 = max of 45 degrees) + angoffset /= 2; + + // Reduce further based on how slow your speed is compared to the spring's speed + if (finalSpeed > objectSpeed) + angoffset = FixedDiv(angoffset, FixedDiv(finalSpeed, objectSpeed)); + + if (subtract) + angoffset = (signed)(spring->angle) - angoffset; + else + angoffset = (signed)(spring->angle) + angoffset; + + finalAngle = angoffset; + } } + + if (object->player) + { + // Less friction when hitting horizontal springs + if (!vertispeed) + { + if (!object->player->kartstuff[k_tiregrease]) + { + UINT8 i; + for (i = 0; i < 2; i++) + { + mobj_t *grease; + grease = P_SpawnMobj(object->x, object->y, object->z, MT_TIREGREASE); + P_SetTarget(&grease->target, object); + grease->angle = R_PointToAngle2(0, 0, object->momx, object->momy); + grease->extravalue1 = i; + } + } + + object->player->kartstuff[k_tiregrease] = greasetics; //FixedMul(greasetics << FRACBITS, finalSpeed/72) >> FRACBITS + } + } + + // Horizontal speed is used as a minimum thrust, not a direct replacement + finalSpeed = max(objectSpeed, finalSpeed); + + P_InstaThrustEvenIn2D(object, finalAngle, FixedMul(finalSpeed, FixedSqrt(FixedMul(hscale, spring->scale)))); } // Re-solidify @@ -208,46 +286,12 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object) if (spring->flags & MF_ENEMY) // Spring shells P_SetTarget(&spring->target, object); - if (horizspeed && object->player->cmd.forwardmove == 0 && object->player->cmd.sidemove == 0) - { - object->angle = spring->angle; - - if (!demo.playback || P_AnalogMove(object->player)) - { - if (object->player == &players[consoleplayer]) - localangle[0] = spring->angle; - else if (object->player == &players[displayplayers[1]]) - localangle[1] = spring->angle; - else if (object->player == &players[displayplayers[2]]) - localangle[2] = spring->angle; - else if (object->player == &players[displayplayers[3]]) - localangle[3] = spring->angle; - } - } - - //pflags = object->player->pflags & (PF_JUMPED|PF_SPINNING|PF_THOKKED); // I still need these. P_ResetPlayer(object->player); - /* // SRB2kart - Springs don't need to change player state in kart. - if (P_MobjFlip(object)*vertispeed > 0) - P_SetPlayerMobjState(object, S_PLAY_SPRING); - else if (P_MobjFlip(object)*vertispeed < 0) - P_SetPlayerMobjState(object, S_PLAY_FALL1); - else // horizontal spring - { - if (pflags & (PF_JUMPED|PF_SPINNING) && object->player->panim == PA_ROLL) - object->player->pflags = pflags; - else - P_SetPlayerMobjState(object, S_PLAY_RUN1); - } - - if (spring->info->painchance) - { - object->player->pflags |= PF_JUMPED; - P_SetPlayerMobjState(object, S_PLAY_ATK1); - } - */ + object->player->kartstuff[k_springstars] = max(vertispeed, horizspeed) / FRACUNIT / 2; + object->player->kartstuff[k_springcolor] = starcolor; } + return true; } @@ -1163,6 +1207,7 @@ static boolean PIT_CheckThing(mobj_t *thing) //else if (tmz > thzh - sprarea && tmz < thzh) // Don't damage people springing up / down return true; } + // missiles can hit other things if (tmthing->flags & MF_MISSILE || tmthing->type == MT_SHELL) { @@ -2892,14 +2937,24 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff) P_HandleSlopeLanding(thing, tmfloorslope); if (thing->momz <= 0) + { thing->standingslope = tmfloorslope; +#ifdef HWRENDER + thing->modeltilt = thing->standingslope; +#endif + } } else if (thing->z+thing->height >= tmceilingz && (thing->eflags & MFE_VERTICALFLIP)) { if (!startingonground && tmceilingslope) P_HandleSlopeLanding(thing, tmceilingslope); if (thing->momz >= 0) + { thing->standingslope = tmceilingslope; +#ifdef HWRENDER + thing->modeltilt = thing->standingslope; +#endif + } } } else // don't set standingslope if you're not going to clip against it @@ -4702,7 +4757,7 @@ fixed_t P_FloorzAtPos(fixed_t x, fixed_t y, fixed_t z, fixed_t height) if (!(rover->flags & FF_EXISTS)) continue; - if ((!(rover->flags & FF_SOLID || rover->flags & FF_QUICKSAND) || (rover->flags & FF_SWIMMABLE))) + if (!((rover->flags & FF_SOLID) || (rover->flags & FF_QUICKSAND)) || (rover->flags & FF_SWIMMABLE)) continue; topheight = *rover->topheight; diff --git a/src/p_mobj.c b/src/p_mobj.c index e8880f07b..b1d862718 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -1848,6 +1848,9 @@ void P_XYMovement(mobj_t *mo) // Now compare the Zs of the different quantizations if (oldangle-newangle > ANG30 && oldangle-newangle < ANGLE_180) { // Allow for a bit of sticking - this value can be adjusted later mo->standingslope = oldslope; +#ifdef HWRENDER + mo->modeltilt = mo->standingslope; +#endif P_SlopeLaunch(mo); //CONS_Printf("launched off of slope - "); @@ -2421,6 +2424,9 @@ static boolean P_ZMovement(mobj_t *mo) if (((mo->eflags & MFE_VERTICALFLIP) ? tmceilingslope : tmfloorslope) && (mo->type != MT_STEAM)) { mo->standingslope = (mo->eflags & MFE_VERTICALFLIP) ? tmceilingslope : tmfloorslope; +#ifdef HWRENDER + mo->modeltilt = mo->standingslope; +#endif P_ReverseQuantizeMomentumToSlope(&mom, mo->standingslope); } #endif @@ -6199,13 +6205,178 @@ static void P_RemoveOverlay(mobj_t *thing) } } +// Simplified version of a code bit in P_MobjFloorZ +static fixed_t P_ShadowSlopeZ(pslope_t *slope, fixed_t x, fixed_t y, fixed_t radius, boolean ceiling) +{ + fixed_t testx, testy; + + if (slope->d.x < 0) + testx = radius; + else + testx = -radius; + + if (slope->d.y < 0) + testy = radius; + else + testy = -radius; + + if ((slope->zdelta > 0) ^ !!(ceiling)) + { + testx = -testx; + testy = -testy; + } + + testx += x; + testy += y; + + return P_GetZAt(slope, testx, testy); +} + +// Sets standingslope/modeltilt, returns z position for shadows; used also for stuff like bananas +// (I would've preferred to be able to return both the slope & z, but I'll take what I can get...) +fixed_t P_CalculateShadowFloor(mobj_t *mobj, fixed_t x, fixed_t y, fixed_t z, fixed_t radius, fixed_t height, boolean flip, boolean player) +{ + fixed_t newz; + sector_t *sec; +#ifdef ESLOPE + pslope_t *slope = NULL; +#endif + + sec = R_PointInSubsector(x, y)->sector; + + if (flip) + { +#ifdef ESLOPE + if (sec->c_slope) + { + slope = sec->c_slope; + newz = P_ShadowSlopeZ(slope, x, y, radius, true); + } + else +#endif + newz = sec->ceilingheight; + } + else + { +#ifdef ESLOPE + if (sec->f_slope) + { + slope = sec->f_slope; + newz = P_ShadowSlopeZ(slope, x, y, radius, false); + } + else +#endif + newz = sec->floorheight; + } + + // Check FOFs for a better suited slope + if (sec->ffloors) + { + ffloor_t *rover; + + for (rover = sec->ffloors; rover; rover = rover->next) + { + fixed_t top, bottom; + fixed_t d1, d2; + + if (!(rover->flags & FF_EXISTS)) + continue; + + if ((!(((rover->flags & FF_BLOCKPLAYER && player) + || (rover->flags & FF_BLOCKOTHERS && !player)) + || (rover->flags & FF_QUICKSAND)) + || (rover->flags & FF_SWIMMABLE))) + continue; + +#ifdef ESLOPE + if (*rover->t_slope) + top = P_ShadowSlopeZ(*rover->t_slope, x, y, radius, false); + else +#endif + top = *rover->topheight; + +#ifdef ESLOPE + if (*rover->b_slope) + bottom = P_ShadowSlopeZ(*rover->b_slope, x, y, radius, true); + else +#endif + bottom = *rover->bottomheight; + + if (flip) + { + if (rover->flags & FF_QUICKSAND) + { + if (z < top && (z + height) > bottom) + { + if (newz > (z + height)) + { + newz = (z + height); + slope = NULL; + } + } + continue; + } + + d1 = (z + height) - (top + ((bottom - top)/2)); + d2 = z - (top + ((bottom - top)/2)); + + if (bottom < newz && abs(d1) < abs(d2)) + { + newz = bottom; +#ifdef ESLOPE + if (*rover->b_slope) + slope = *rover->b_slope; +#endif + } + } + else + { + if (rover->flags & FF_QUICKSAND) + { + if (z < top && (z + height) > bottom) + { + if (newz < z) + { + newz = z; + slope = NULL; + } + } + continue; + } + + d1 = z - (bottom + ((top - bottom)/2)); + d2 = (z + height) - (bottom + ((top - bottom)/2)); + + if (top > newz && abs(d1) < abs(d2)) + { + newz = top; +#ifdef ESLOPE + if (*rover->t_slope) + slope = *rover->t_slope; +#endif + } + } + } + } + +#if 0 + mobj->standingslope = slope; +#endif +#ifdef HWRENDER + mobj->modeltilt = slope; +#endif + + return newz; +} + void P_RunShadows(void) { mobj_t *mobj, *next, *dest; for (mobj = shadowcap; mobj; mobj = next) { - fixed_t floorz; + boolean flip; + fixed_t newz; next = mobj->hnext; P_SetTarget(&mobj->hnext, NULL); @@ -6216,16 +6387,22 @@ void P_RunShadows(void) continue; // shouldn't you already be dead? } - if (mobj->target->player) - floorz = mobj->target->floorz; - else // FOR SOME REASON, plain floorz is not reliable for normal objects, only players?! - floorz = P_FloorzAtPos(mobj->target->x, mobj->target->y, mobj->target->z, mobj->target->height); - K_MatchGenericExtraFlags(mobj, mobj->target); + flip = (mobj->eflags & MFE_VERTICALFLIP); - if (((mobj->target->eflags & MFE_VERTICALFLIP) && mobj->target->z+mobj->target->height > mobj->target->ceilingz) - || (!(mobj->target->eflags & MFE_VERTICALFLIP) && mobj->target->z < floorz)) - mobj->flags2 |= MF2_DONTDRAW; + newz = P_CalculateShadowFloor(mobj, mobj->target->x, mobj->target->y, mobj->target->z, + mobj->target->radius, mobj->target->height, flip, (mobj->target->player != NULL)); + + if (flip) + { + if ((mobj->target->z + mobj->target->height) > newz) + mobj->flags2 |= MF2_DONTDRAW; + } + else + { + if (mobj->target->z < newz) + mobj->flags2 |= MF2_DONTDRAW; + } // First scale to the same radius P_SetScale(mobj, FixedDiv(mobj->target->radius, mobj->info->radius)); @@ -6237,13 +6414,12 @@ void P_RunShadows(void) P_TeleportMove(mobj, dest->x, dest->y, mobj->target->z); - if (((mobj->eflags & MFE_VERTICALFLIP) && (mobj->ceilingz > mobj->z+mobj->height)) - || (!(mobj->eflags & MFE_VERTICALFLIP) && (floorz < mobj->z))) + if ((flip && newz > (mobj->z + mobj->height)) || (!flip && newz < mobj->z)) { INT32 i; fixed_t prevz; - mobj->z = (mobj->eflags & MFE_VERTICALFLIP ? mobj->ceilingz : floorz); + mobj->z = newz; for (i = 0; i < MAXFFLOORS; i++) { @@ -6255,7 +6431,7 @@ void P_RunShadows(void) // Check new position to see if you should still be on that ledge P_TeleportMove(mobj, dest->x, dest->y, mobj->z); - mobj->z = (mobj->eflags & MFE_VERTICALFLIP ? mobj->ceilingz : floorz); + mobj->z = newz; if (mobj->z == prevz) break; @@ -6310,6 +6486,216 @@ static void P_RemoveShadow(mobj_t *thing) } } +// SAL'S KART BATTLE MODE OVERTIME HANDLER +#define MAXPLANESPERSECTOR (MAXFFLOORS+1)*2 +static void P_SpawnOvertimeParticles(fixed_t x, fixed_t y, fixed_t scale, mobjtype_t type, boolean ceiling) +{ + UINT8 i; + fixed_t flatz[MAXPLANESPERSECTOR]; + boolean flip[MAXPLANESPERSECTOR]; + UINT8 numflats = 0; + mobj_t *mo; + subsector_t *ss = R_IsPointInSubsector(x, y); + sector_t *sec; + + if (!ss) + return; + sec = ss->sector; + + // convoluted stuff JUST to get all of the planes we need to draw orbs on :V + + for (i = 0; i < MAXPLANESPERSECTOR; i++) + flip[i] = false; + + if (sec->floorpic != skyflatnum) + { +#ifdef ESLOPE + flatz[numflats] = (sec->f_slope ? P_GetZAt(sec->f_slope, x, y) : sec->floorheight); +#else + flatz[numflats] = (sec->floorheight); +#endif + numflats++; + } + if (sec->ceilingpic != skyflatnum && ceiling) + { +#ifdef ESLOPE + flatz[numflats] = (sec->c_slope ? P_GetZAt(sec->c_slope, x, y) : sec->ceilingheight) - FixedMul(mobjinfo[type].height, scale); +#else + flatz[numflats] = (sec->ceilingheight) - FixedMul(mobjinfo[type].height, scale); +#endif + flip[numflats] = true; + numflats++; + } + + if (sec->ffloors) + { + ffloor_t *rover; + for (rover = sec->ffloors; rover; rover = rover->next) + { + if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_BLOCKPLAYER)) + continue; + if (*rover->toppic != skyflatnum) + { +#ifdef ESLOPE + flatz[numflats] = (*rover->t_slope ? P_GetZAt(*rover->t_slope, x, y) : *rover->topheight); +#else + flatz[numflats] = (*rover->topheight); +#endif + numflats++; + } + if (*rover->bottompic != skyflatnum && ceiling) + { +#ifdef ESLOPE + flatz[numflats] = (*rover->b_slope ? P_GetZAt(*rover->b_slope, x, y) : *rover->bottomheight) - FixedMul(mobjinfo[type].height, scale); +#else + flatz[numflats] = (*rover->bottomheight) - FixedMul(mobjinfo[type].height, scale); +#endif + flip[numflats] = true; + numflats++; + } + } + } + + if (numflats <= 0) // no flats + return; + + for (i = 0; i < numflats; i++) + { + mo = P_SpawnMobj(x, y, flatz[i], type); + + // Lastly, if this can see the skybox mobj, then... we just wasted our time :V + if (skyboxmo[0] && !P_MobjWasRemoved(skyboxmo[0])) + { + const fixed_t sbz = skyboxmo[0]->z; + fixed_t checkz = sec->floorheight; + + while (checkz < sec->ceilingheight) + { + P_TeleportMove(skyboxmo[0], skyboxmo[0]->x, skyboxmo[0]->y, checkz); + if (P_CheckSight(skyboxmo[0], mo)) + { + P_RemoveMobj(mo); + break; + } + else + checkz += 32*mapobjectscale; + } + + P_TeleportMove(skyboxmo[0], skyboxmo[0]->x, skyboxmo[0]->y, sbz); + + if (P_MobjWasRemoved(mo)) + continue; + } + + P_SetScale(mo, scale); + + if (flip[i]) + { + mo->flags2 |= MF2_OBJECTFLIP; + mo->eflags |= MFE_VERTICALFLIP; + } + + switch(type) + { + case MT_OVERTIMEFOG: + mo->destscale = 8*mo->scale; + mo->momz = P_RandomRange(1,8)*mo->scale; + break; + case MT_OVERTIMEORB: + //mo->destscale = mo->scale/4; + mo->frame += ((leveltime/4) % 8); + /*if (battleovertime.enabled < 10*TICRATE) + mo->flags2 |= MF2_SHADOW;*/ + mo->angle = R_PointToAngle2(mo->x, mo->y, battleovertime.x, battleovertime.y) + ANGLE_90; + mo->z += P_RandomRange(0,48) * mo->scale; + break; + default: + break; + } + } +} +#undef MAXPLANESPERSECTOR + +void P_RunBattleOvertime(void) +{ + UINT16 i, j; + + if (battleovertime.enabled < 10*TICRATE) + { + battleovertime.enabled++; + if (battleovertime.enabled == TICRATE) + S_StartSound(NULL, sfx_bhurry); + if (battleovertime.enabled == 10*TICRATE) + S_StartSound(NULL, sfx_kc40); + } + else + { + if (battleovertime.radius > battleovertime.minradius) + battleovertime.radius -= mapobjectscale; + else + battleovertime.radius = battleovertime.minradius; + } + + if (leveltime & 1) + { + UINT8 transparency = tr_trans50; + + if (!splitscreen && players[displayplayers[0]].mo) + { + INT32 dist = P_AproxDistance(battleovertime.x-players[displayplayers[0]].mo->x, battleovertime.y-players[displayplayers[0]].mo->y); + transparency = max(0, NUMTRANSMAPS - ((256 + (dist>>FRACBITS)) / 256)); + } + + if (transparency < NUMTRANSMAPS) + { + mobj_t *beam = P_SpawnMobj(battleovertime.x, battleovertime.y, battleovertime.z + (mobjinfo[MT_RANDOMITEM].height/2), MT_OVERTIMEBEAM); + P_SetScale(beam, beam->scale*2); + if (transparency > 0) + beam->frame |= transparency<>FRACBITS / 2));*/ + + for (i = 0; i < 16; i++) + { + j = 0; + while (j < 32) // max attempts + { + fixed_t x = battleovertime.x + ((P_RandomRange(-64,64) * 128)<x = mobj->target->x; mobj->y = mobj->target->y; - if (!splitscreen) + if (!splitscreen && players[displayplayers[0]].mo) { scale = mobj->target->scale + FixedMul(FixedDiv(abs(P_AproxDistance(players[displayplayers[0]].mo->x-mobj->target->x, players[displayplayers[0]].mo->y-mobj->target->y)), RING_DIST), mobj->target->scale); @@ -8216,6 +8602,9 @@ void P_MobjThinker(mobj_t *mobj) P_TeleportMove(mobj, mobj->target->x + P_ReturnThrustX(mobj, mobj->angle+ANGLE_180, mobj->target->radius), mobj->target->y + P_ReturnThrustY(mobj, mobj->angle+ANGLE_180, mobj->target->radius), mobj->target->z); P_SetScale(mobj, mobj->target->scale); +#ifdef HWRENDER + mobj->modeltilt = mobj->target->modeltilt; +#endif { player_t *p = NULL; @@ -8368,6 +8757,56 @@ void P_MobjThinker(mobj_t *mobj) z); } break; + case MT_TIREGREASE: + if (!mobj->target || P_MobjWasRemoved(mobj->target) || !mobj->target->player + || !mobj->target->player->kartstuff[k_tiregrease]) + { + P_RemoveMobj(mobj); + return; + } + + K_MatchGenericExtraFlags(mobj, mobj->target); + + { + const angle_t off = FixedAngle(40*FRACUNIT); + angle_t ang = mobj->target->angle; + fixed_t z; + UINT8 trans = (mobj->target->player->kartstuff[k_tiregrease] * (NUMTRANSMAPS+1)) / greasetics; + + if (trans > NUMTRANSMAPS) + trans = NUMTRANSMAPS; + + trans = NUMTRANSMAPS - trans; + + z = mobj->target->z; + if (mobj->eflags & MFE_VERTICALFLIP) + z += mobj->target->height; + + if (mobj->target->momx || mobj->target->momy) + ang = R_PointToAngle2(0, 0, mobj->target->momx, mobj->target->momy); + + if (mobj->extravalue1) + ang = (signed)(ang - off); + else + ang = (signed)(ang + off); + + P_TeleportMove(mobj, + mobj->target->x - FixedMul(mobj->target->radius, FINECOSINE(ang >> ANGLETOFINESHIFT)), + mobj->target->y - FixedMul(mobj->target->radius, FINESINE(ang >> ANGLETOFINESHIFT)), + z); + mobj->angle = ang; + + if (leveltime & 1) + mobj->flags2 |= MF2_DONTDRAW; + + if (trans >= NUMTRANSMAPS) + mobj->flags2 |= MF2_DONTDRAW; + else if (trans == 0) + mobj->frame = (mobj->frame & ~FF_TRANSMASK); + else + mobj->frame = (mobj->frame & ~FF_TRANSMASK)|(trans << FF_TRANSSHIFT); + } + break; case MT_THUNDERSHIELD: { fixed_t destx, desty; @@ -9070,6 +9509,9 @@ void P_MobjThinker(mobj_t *mobj) } break; case MT_KARMAFIREWORK: + if (mobj->flags & MF_NOGRAVITY) + break; + if (mobj->momz == 0) { P_RemoveMobj(mobj); @@ -9085,6 +9527,40 @@ void P_MobjThinker(mobj_t *mobj) trail->color = mobj->color; } break; + case MT_RANDOMITEM: + if (G_BattleGametype() && mobj->threshold == 70) + { + mobj->color = (UINT8)(1 + (leveltime % (MAXSKINCOLORS-1))); + mobj->colorized = true; + + if (battleovertime.enabled) + { + angle_t ang = FixedAngle((leveltime % 360) << FRACBITS); + fixed_t z = battleovertime.z; + fixed_t dist; + mobj_t *ghost; + + /*if (z < mobj->subsector->sector->floorheight) + z = mobj->subsector->sector->floorheight;*/ + + if (mobj->extravalue1 < 512) + mobj->extravalue1++; + dist = mobj->extravalue1 * mapobjectscale; + + P_TeleportMove(mobj, battleovertime.x + P_ReturnThrustX(NULL, ang, dist), + battleovertime.y + P_ReturnThrustY(NULL, ang, dist), z); + + ghost = P_SpawnGhostMobj(mobj); + ghost->fuse = 4; + ghost->frame |= FF_FULLBRIGHT; + } + } + else + { + mobj->color = SKINCOLOR_NONE; + mobj->colorized = false; + } + break; //} case MT_TURRET: P_MobjCheckWater(mobj); @@ -9349,7 +9825,7 @@ for (i = ((mobj->flags2 & MF2_STRONGBOX) ? strongboxamt : weakboxamt); i; --i) s P_RemoveMobj(mobj); // make sure they disappear return; case MT_RANDOMITEM: - if (G_BattleGametype()) + if (G_BattleGametype() && (mobj->threshold != 70)) { if (mobj->threshold != 69) break; @@ -9365,8 +9841,11 @@ for (i = ((mobj->flags2 & MF2_STRONGBOX) ? strongboxamt : weakboxamt); i; --i) s else newmobj = P_SpawnMobj(mobj->x, mobj->y, mobj->z, mobj->type); + P_SpawnMobj(newmobj->x, newmobj->y, newmobj->z, MT_EXPLODE); // poof into existance // Transfer flags2 (strongbox, objectflip) newmobj->flags2 = mobj->flags2 & ~MF2_DONTDRAW; + if (mobj->threshold == 70) + newmobj->threshold = 70; } P_RemoveMobj(mobj); // make sure they disappear return; @@ -10726,6 +11205,50 @@ void P_PrecipitationEffects(void) } } +void P_RespawnBattleBoxes(void) +{ + thinker_t *th; + + if (!G_BattleGametype()) + return; + + for (th = thinkercap.next; th != &thinkercap; th = th->next) + { + mobj_t *box; + mobj_t *newmobj; + + if (th->function.acp1 != (actionf_p1)P_MobjThinker) // not a mobj + continue; + + box = (mobj_t *)th; + + if (box->type != MT_RANDOMITEM || box->threshold != 68 || box->fuse) // only popped items + continue; + + // Respawn from mapthing if you have one! + if (box->spawnpoint) + { + P_SpawnMapThing(box->spawnpoint); + newmobj = box->spawnpoint->mobj; // this is set to the new mobj in P_SpawnMapThing + P_SpawnMobj(box->spawnpoint->mobj->x, box->spawnpoint->mobj->y, box->spawnpoint->mobj->z, MT_EXPLODE); // poof into existance + } + else + { + newmobj = P_SpawnMobj(box->x, box->y, box->z, box->type); + P_SpawnMobj(newmobj->x, newmobj->y, newmobj->z, MT_EXPLODE); // poof into existance + } + + // Transfer flags2 (strongbox, objectflip) + newmobj->flags2 = box->flags2; + P_RemoveMobj(box); // make sure they disappear + numgotboxes--; // you've restored a box, remove it from the count + //continue; -- irrelevant? + } + + if (numgotboxes < 0) + numgotboxes = 0; +} + // // P_RespawnSpecials // @@ -10739,45 +11262,7 @@ void P_RespawnSpecials(void) mapthing_t *mthing = NULL; if (G_BattleGametype() && numgotboxes >= (4*nummapboxes/5)) // Battle Mode respawns all boxes in a different way - { - thinker_t *th; - - for (th = thinkercap.next; th != &thinkercap; th = th->next) - { - mobj_t *box; - mobj_t *newmobj; - - if (th->function.acp1 != (actionf_p1)P_MobjThinker) // not a mobj - continue; - - box = (mobj_t *)th; - - if (box->type != MT_RANDOMITEM || box->threshold != 68 || box->fuse) // only popped items - continue; - - // Respawn from mapthing if you have one! - if (box->spawnpoint) - { - P_SpawnMapThing(box->spawnpoint); - newmobj = box->spawnpoint->mobj; // this is set to the new mobj in P_SpawnMapThing - P_SpawnMobj(box->spawnpoint->mobj->x, box->spawnpoint->mobj->y, box->spawnpoint->mobj->z, MT_EXPLODE); // poof into existance - } - else - { - newmobj = P_SpawnMobj(box->x, box->y, box->z, box->type); - P_SpawnMobj(newmobj->x, newmobj->y, newmobj->z, MT_EXPLODE); // poof into existance - } - - // Transfer flags2 (strongbox, objectflip) - newmobj->flags2 = box->flags2; - P_RemoveMobj(box); // make sure they disappear - numgotboxes--; // you've restored a box, remove it from the count - //continue; -- irrelevant? - } - - if (numgotboxes < 0) - numgotboxes = 0; - } + P_RespawnBattleBoxes(); // wait time depends on player count for (p = 0; p < MAXPLAYERS; p++) @@ -10789,8 +11274,16 @@ void P_RespawnSpecials(void) if (pcount == 1) // No respawn when alone return; else if (pcount > 1) + { time = (180 - (pcount * 10))*TICRATE; + // If the map is longer or shorter than 3 laps, then adjust ring respawn to account for this. + // 5 lap courses would have more retreaded ground, while 2 lap courses would have less. + if ((mapheaderinfo[gamemap-1]->numlaps != 3) + && !(mapheaderinfo[gamemap-1]->levelflags & LF_SECTIONRACE)) + time = (time * 3) / max(1, mapheaderinfo[gamemap-1]->numlaps); + } + // only respawn items when cv_itemrespawn is on //if (!cv_itemrespawn.value) // TODO: remove this cvar //return; @@ -12011,7 +12504,7 @@ ML_NOCLIMB : Direction not controllable { if (mthing->options & MTF_AMBUSH) { - if (i == MT_YELLOWDIAG || i == MT_REDDIAG) + if (mobj->flags & MF_SPRING && mobj->info->damage) mobj->angle += ANGLE_22h; if (mobj->flags & MF_NIGHTSITEM) diff --git a/src/p_mobj.h b/src/p_mobj.h index dfc8fc738..aec2ed951 100644 --- a/src/p_mobj.h +++ b/src/p_mobj.h @@ -370,6 +370,9 @@ typedef struct mobj_s #ifdef ESLOPE struct pslope_s *standingslope; // The slope that the object is standing on (shouldn't need synced in savegames, right?) +#ifdef HWRENDER + struct pslope_s *modeltilt; // Slope used for model tilting. Also is not synched, this is totally visual. +#endif #endif boolean colorized; // Whether the mobj uses the rainbow colormap diff --git a/src/p_saveg.c b/src/p_saveg.c index c86758058..eb7d2900e 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -950,8 +950,8 @@ typedef enum MD2_EXTVAL2 = 1<<6, MD2_HNEXT = 1<<7, MD2_HPREV = 1<<8, - MD2_COLORIZED = 1<<9, - MD2_WAYPOINTCAP = 1<<10 + MD2_COLORIZED = 1<<9, + MD2_WAYPOINTCAP = 1<<10 #ifdef ESLOPE , MD2_SLOPE = 1<<11 #endif @@ -2147,7 +2147,12 @@ static void LoadMobjThinker(actionf_p1 thinker) mobj->hprev = (mobj_t *)(size_t)READUINT32(save_p); #ifdef ESLOPE if (diff2 & MD2_SLOPE) + { mobj->standingslope = P_SlopeById(READUINT16(save_p)); +#ifdef HWRENDER + mobj->modeltilt = mobj->standingslope; +#endif + } #endif if (diff2 & MD2_COLORIZED) mobj->colorized = READUINT8(save_p); @@ -3094,7 +3099,7 @@ static inline void P_NetArchiveSpecials(void) WRITEUINT32(save_p, 0xffffffff); // Sky number - WRITEINT32(save_p, globallevelskynum); + WRITESTRINGN(save_p, globallevelskytexture, 9); // Current global weather type WRITEUINT8(save_p, globalweather); @@ -3113,8 +3118,8 @@ static inline void P_NetArchiveSpecials(void) // static void P_NetUnArchiveSpecials(void) { + char skytex[9]; size_t i; - INT32 j; if (READUINT32(save_p) != ARCHIVEBLOCK_SPECIALS) I_Error("Bad $$$.sav at archive block Specials"); @@ -3127,9 +3132,9 @@ static void P_NetUnArchiveSpecials(void) itemrespawntime[iquehead++] = READINT32(save_p); } - j = READINT32(save_p); - if (j != globallevelskynum) - P_SetupLevelSky(j, true); + READSTRINGN(save_p, skytex, sizeof(skytex)); + if (strcmp(skytex, globallevelskytexture)) + P_SetupLevelSky(skytex, true); globalweather = READUINT8(save_p); @@ -3288,6 +3293,14 @@ static void P_NetArchiveMisc(void) for (i = 0; i < 4; i++) WRITESINT8(save_p, battlewanted[i]); + // battleovertime_t + WRITEUINT16(save_p, battleovertime.enabled); + WRITEFIXED(save_p, battleovertime.radius); + WRITEFIXED(save_p, battleovertime.minradius); + WRITEFIXED(save_p, battleovertime.x); + WRITEFIXED(save_p, battleovertime.y); + WRITEFIXED(save_p, battleovertime.z); + WRITEUINT32(save_p, wantedcalcdelay); WRITEUINT32(save_p, indirectitemcooldown); WRITEUINT32(save_p, hyubgone); @@ -3400,6 +3413,14 @@ static inline boolean P_NetUnArchiveMisc(void) for (i = 0; i < 4; i++) battlewanted[i] = READSINT8(save_p); + // battleovertime_t + battleovertime.enabled = READUINT16(save_p); + battleovertime.radius = READFIXED(save_p); + battleovertime.minradius = READFIXED(save_p); + battleovertime.x = READFIXED(save_p); + battleovertime.y = READFIXED(save_p); + battleovertime.z = READFIXED(save_p); + wantedcalcdelay = READUINT32(save_p); indirectitemcooldown = READUINT32(save_p); hyubgone = READUINT32(save_p); diff --git a/src/p_setup.c b/src/p_setup.c index b19093d9a..3498c443b 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -208,8 +208,9 @@ static void P_ClearSingleMapHeaderInfo(INT16 i) mapheaderinfo[num]->forcecharacter[0] = '\0'; DEH_WriteUndoline("WEATHER", va("%d", mapheaderinfo[num]->weather), UNDO_NONE); mapheaderinfo[num]->weather = 0; - DEH_WriteUndoline("SKYNUM", va("%d", mapheaderinfo[num]->skynum), UNDO_NONE); - mapheaderinfo[num]->skynum = 1; + DEH_WriteUndoline("SKYTEXTURE", va("%d", mapheaderinfo[num]->skytexture), UNDO_NONE); + snprintf(mapheaderinfo[num]->skytexture, 9, "SKY1"); + mapheaderinfo[num]->skytexture[8] = 0; DEH_WriteUndoline("SKYBOXSCALEX", va("%d", mapheaderinfo[num]->skybox_scalex), UNDO_NONE); mapheaderinfo[num]->skybox_scalex = 16; DEH_WriteUndoline("SKYBOXSCALEY", va("%d", mapheaderinfo[num]->skybox_scaley), UNDO_NONE); @@ -2256,17 +2257,18 @@ static inline boolean P_CheckLevel(lumpnum_t lumpnum) /** Sets up a sky texture to use for the level. * The sky texture is used instead of F_SKY1. */ -void P_SetupLevelSky(INT32 skynum, boolean global) +void P_SetupLevelSky(const char *skytexname, boolean global) { - char skytexname[12]; + char tex[9]; + strncpy(tex, skytexname, 9); + tex[8] = 0; - sprintf(skytexname, "SKY%d", skynum); - skytexture = R_TextureNumForName(skytexname); - levelskynum = skynum; + skytexture = R_TextureNumForName(tex); + strncpy(levelskytexture, tex, 9); // Global change if (global) - globallevelskynum = levelskynum; + strncpy(globallevelskytexture, tex, 9); // Don't go beyond for dedicated servers if (dedicated) @@ -2408,6 +2410,7 @@ static void P_LevelInitStuff(void) for (i = 0; i < 4; i++) battlewanted[i] = -1; + memset(&battleovertime, 0, sizeof(struct battleovertime)); speedscramble = encorescramble = -1; } @@ -2786,7 +2789,7 @@ boolean P_SetupLevel(boolean skipprecip) // use gamemap to get map number. // 99% of the things already did, so. // Map header should always be in place at this point - INT32 i, loadprecip = 1, ranspecialwipe = 0; + INT32 i, loadprecip = 1; INT32 loademblems = 1; INT32 fromnetsave = 0; boolean loadedbm = false; @@ -2865,36 +2868,50 @@ boolean P_SetupLevel(boolean skipprecip) S_StartSound(NULL, sfx_ruby1); + // Fade to an inverted screen, with a circle fade... F_WipeStartScreen(); - V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 209); + V_EncoreInvertScreen(); F_WipeEndScreen(); - F_RunWipe(wipedefs[wipe_speclevel_towhite], false); + F_RunWipe(wipedefs[wipe_encore_toinvert], false, NULL, false, false); + + // Hold on invert for extra effect. + // (This define might be useful for other areas of code? Not sure) +#define WAIT(timetowait) \ + locstarttime = nowtime = lastwipetic; \ + endtime = locstarttime + timetowait; \ + while (nowtime < endtime) \ + { \ + while (!((nowtime = I_GetTime()) - lastwipetic)) \ + I_Sleep(); \ + lastwipetic = nowtime; \ + if (moviemode) \ + M_SaveFrame(); \ + NetKeepAlive(); \ + } \ + + WAIT((3*TICRATE)/2); + S_StartSound(NULL, sfx_ruby2); + + // Then fade to a white screen F_WipeStartScreen(); + V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 0); - F_WipeEndScreen(); - F_RunWipe(wipedefs[wipe_level_final], false); - locstarttime = nowtime = lastwipetic; - endtime = locstarttime + (3*TICRATE)/2; + F_RunWipe(wipedefs[wipe_encore_towhite], false, "FADEMAP1", false, true); // wiggle the screen during this! - // Hold on white for extra effect. - while (nowtime < endtime) - { - // wait loop - while (!((nowtime = I_GetTime()) - lastwipetic)) - I_Sleep(); - lastwipetic = nowtime; - if (moviemode) // make sure we save frames for the white hold too - M_SaveFrame(); + // THEN fade to a black screen. + F_WipeStartScreen(); - // Keep the network alive - NetKeepAlive(); - } + V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31); + F_WipeEndScreen(); - ranspecialwipe = 1; + F_RunWipe(wipedefs[wipe_level_toblack], false, "FADEMAP0", false, false); + + // Wait a bit longer. + WAIT((3*TICRATE)/4); } // Make sure all sounds are stopped before Z_FreeTags. @@ -2905,17 +2922,18 @@ boolean P_SetupLevel(boolean skipprecip) // We should be fine starting it here. S_Start(); - levelfadecol = (encoremode && !ranspecialwipe ? 209 : 0); + levelfadecol = (encoremode ? 0 : 31); // Let's fade to white here // But only if we didn't do the encore startup wipe - if (rendermode != render_none && !ranspecialwipe && !demo.rewinding) + if (rendermode != render_none && !demo.rewinding) { F_WipeStartScreen(); - V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, levelfadecol); + V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, levelfadecol); F_WipeEndScreen(); - F_RunWipe(wipedefs[(encoremode ? wipe_level_final : wipe_level_toblack)], false); + + F_RunWipe(wipedefs[wipe_level_toblack], false, ((levelfadecol == 0) ? "FADEMAP1" : "FADEMAP0"), false, false); } // Reset the palette now all fades have been done @@ -2981,7 +2999,7 @@ boolean P_SetupLevel(boolean skipprecip) CON_SetupBackColormap(); // SRB2 determines the sky texture to be used depending on the map header. - P_SetupLevelSky(mapheaderinfo[gamemap-1]->skynum, true); + P_SetupLevelSky(mapheaderinfo[gamemap-1]->skytexture, true); P_MakeMapMD5(lastloadedmaplumpnum, &mapmd5); diff --git a/src/p_setup.h b/src/p_setup.h index c4a3aab9a..9abcfe5f6 100644 --- a/src/p_setup.h +++ b/src/p_setup.h @@ -54,7 +54,7 @@ INT32 P_CheckLevelFlat(const char *flatname); extern size_t nummapthings; extern mapthing_t *mapthings; -void P_SetupLevelSky(INT32 skynum, boolean global); +void P_SetupLevelSky(const char *skytexname, boolean global); #ifdef SCANTHINGS void P_ScanThings(INT16 mapnum, INT16 wadnum, INT16 lumpnum); #endif diff --git a/src/p_slopes.c b/src/p_slopes.c index 06bc74c76..e623b6f19 100644 --- a/src/p_slopes.c +++ b/src/p_slopes.c @@ -836,6 +836,9 @@ void P_HandleSlopeLanding(mobj_t *thing, pslope_t *slope) if (P_MobjFlip(thing)*(thing->momz) < 0) { // falling, land on slope thing->momz = -P_MobjFlip(thing); thing->standingslope = slope; +#ifdef HWRENDER + thing->modeltilt = thing->standingslope; +#endif } return; } @@ -852,6 +855,9 @@ void P_HandleSlopeLanding(mobj_t *thing, pslope_t *slope) thing->momz = -P_MobjFlip(thing); thing->standingslope = slope; +#ifdef HWRENDER + thing->modeltilt = thing->standingslope; +#endif } } diff --git a/src/p_spec.c b/src/p_spec.c index 3e654036f..aa43583a4 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -2802,7 +2802,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) case 423: // Change Sky if ((mo && mo->player && P_IsLocalPlayer(mo->player)) || (line->flags & ML_NOCLIMB)) - P_SetupLevelSky(sides[line->sidenum[0]].textureoffset>>FRACBITS, (line->flags & ML_NOCLIMB)); + P_SetupLevelSky(sides[line->sidenum[0]].text, (line->flags & ML_NOCLIMB)); break; case 424: // Change Weather diff --git a/src/p_tick.c b/src/p_tick.c index 02a532bc1..b285c35d0 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -641,6 +641,8 @@ void P_Ticker(boolean run) if (run) { P_RunThinkers(); + if (G_BattleGametype() && battleovertime.enabled) + P_RunBattleOvertime(); // Run any "after all the other thinkers" stuff for (i = 0; i < MAXPLAYERS; i++) @@ -793,6 +795,8 @@ void P_PreTicker(INT32 frames) } P_RunThinkers(); + if (G_BattleGametype() && battleovertime.enabled) + P_RunBattleOvertime(); // Run any "after all the other thinkers" stuff for (i = 0; i < MAXPLAYERS; i++) diff --git a/src/p_user.c b/src/p_user.c index d5d7dc6fd..8185667a0 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -1645,12 +1645,16 @@ mobj_t *P_SpawnGhostMobj(mobj_t *mobj) ghost->frame |= tr_trans50<fuse = ghost->info->damage; ghost->skin = mobj->skin; + ghost->standingslope = mobj->standingslope; +#ifdef HWRENDER + ghost->modeltilt = mobj->modeltilt; +#endif if (mobj->flags2 & MF2_OBJECTFLIP) ghost->flags |= MF2_OBJECTFLIP; if (!(mobj->flags & MF_DONTENCOREMAP)) - mobj->flags &= ~MF_DONTENCOREMAP; + ghost->flags &= ~MF_DONTENCOREMAP; return ghost; } diff --git a/src/r_data.c b/src/r_data.c index 7fb11855f..922e907e2 100644 --- a/src/r_data.c +++ b/src/r_data.c @@ -267,7 +267,7 @@ static UINT8 *R_GenerateTexture(size_t texnum) texturememory += blocksize; block = Z_Malloc(blocksize+1, PU_STATIC, &texturecache[texnum]); - memset(block, 0xF7, blocksize+1); // Transparency hack + memset(block, 0xFF, blocksize+1); // TRANSPARENTPIXEL // columns lookup table colofs = (UINT32 *)(void *)block; @@ -1177,7 +1177,6 @@ void R_ClearColormaps(void) // static double deltas[256][3], map[256][3]; -static UINT8 NearestColor(UINT8 r, UINT8 g, UINT8 b); static int RoundUp(double number); #ifdef HASINVERT @@ -1403,7 +1402,7 @@ INT32 R_CreateColormap(char *p1, char *p2, char *p3) // Thanks to quake2 source! // utils3/qdata/images.c -static UINT8 NearestColor(UINT8 r, UINT8 g, UINT8 b) +UINT8 NearestColor(UINT8 r, UINT8 g, UINT8 b) { int dr, dg, db; int distortion, bestdistortion = 256 * 256 * 4, bestcolor = 0, i; @@ -1631,7 +1630,7 @@ void R_PrecacheLevel(void) // Sky texture is always present. // Note that F_SKY1 is the name used to indicate a sky floor/ceiling as a flat, - // while the sky texture is stored like a wall texture, with a skynum dependent name. + // while the sky texture is stored like a wall texture, with a texture name set by the map. texturepresent[skytexture] = 1; texturememory = 0; diff --git a/src/r_data.h b/src/r_data.h index 640b30309..cd61bbaac 100644 --- a/src/r_data.h +++ b/src/r_data.h @@ -93,6 +93,7 @@ void R_ReInitColormaps(UINT16 num, lumpnum_t newencoremap); void R_ClearColormaps(void); INT32 R_ColormapNumForName(char *name); INT32 R_CreateColormap(char *p1, char *p2, char *p3); +UINT8 NearestColor(UINT8 r, UINT8 g, UINT8 b); #ifdef HASINVERT void R_MakeInvertmap(void); #endif diff --git a/src/r_plane.c b/src/r_plane.c index db5bfbda2..ec105bf75 100644 --- a/src/r_plane.c +++ b/src/r_plane.c @@ -734,7 +734,7 @@ void R_DrawPlanes(void) dc_x = x; dc_source = R_GetColumn(texturetranslation[skytexture], - angle); + -angle); // Negative because skies were being drawn horizontally flipped wallcolfunc(); } } diff --git a/src/r_sky.c b/src/r_sky.c index fe1630e90..1fe0fe0e6 100644 --- a/src/r_sky.c +++ b/src/r_sky.c @@ -47,8 +47,8 @@ fixed_t skyscale; /** \brief used for keeping track of the current sky */ -INT32 levelskynum; -INT32 globallevelskynum; +char levelskytexture[9]; +char globallevelskytexture[9]; /** \brief The R_SetupSkyDraw function diff --git a/src/r_sky.h b/src/r_sky.h index 86b615595..a41b24463 100644 --- a/src/r_sky.h +++ b/src/r_sky.h @@ -30,8 +30,8 @@ extern INT32 skytexture, skytexturemid; extern fixed_t skyscale; extern INT32 skyflatnum; -extern INT32 levelskynum; -extern INT32 globallevelskynum; +extern char levelskytexture[9]; +extern char globallevelskytexture[9]; // call after skytexture is set to adapt for old/new skies void R_SetupSkyDraw(void); diff --git a/src/sdl/i_system.c b/src/sdl/i_system.c index 8695bd1fc..f75a42117 100644 --- a/src/sdl/i_system.c +++ b/src/sdl/i_system.c @@ -3183,11 +3183,14 @@ void I_Error(const char *error, ...) #endif G_SaveGameData(false); // Tails 12-08-2002 + /* Prevent segmentation fault if testers go to Record Attack... */ +#ifndef TESTERS // Shutdown. Here might be other errors. if (demo.recording) G_CheckDemoStatus(); if (metalrecording) G_StopMetalRecording(); +#endif D_QuitNetGame(); I_ShutdownMusic(); diff --git a/src/sounds.c b/src/sounds.c index 61fddb76f..ef150d7a5 100644 --- a/src/sounds.c +++ b/src/sounds.c @@ -815,6 +815,7 @@ sfxinfo_t S_sfx[NUMSFX] = {"chain", false, 255, 8, -1, NULL, 0, -1, -1, LUMPERROR}, // Mementos Reaper {"mkuma", false, 96, 8, -1, NULL, 0, -1, -1, LUMPERROR}, // Trigger Happy Havoc Monokuma {"toada", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR}, // Arid Sands Toad scream + {"bhurry", false, 255, 0, -1, NULL, 0, -1, -1, LUMPERROR}, // v1.0.2 Battle overtime {"bsnipe", false, 96, 8, -1, NULL, 0, -1, -1, LUMPERROR}, // Banana sniping {"itfree", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR}, // :shitsfree: {"dbgsal", false, 255, 8, -1, NULL, 0, -1, -1, LUMPERROR}, // Debug notification diff --git a/src/sounds.h b/src/sounds.h index bb46ea9d8..8b9ca609e 100644 --- a/src/sounds.h +++ b/src/sounds.h @@ -890,6 +890,7 @@ typedef enum sfx_chain, sfx_mkuma, sfx_toada, + sfx_bhurry, sfx_bsnipe, sfx_itfree, sfx_dbgsal, diff --git a/src/st_stuff.c b/src/st_stuff.c index e59846aed..caed81f3e 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -2134,12 +2134,7 @@ void ST_Drawer(void) ST_MayonakaStatic(); } - // Draw a white fade on level opening - if (timeinmap < 15) - { - if (timeinmap <= 5) - V_DrawFill(0,0,BASEVIDWIDTH,BASEVIDHEIGHT,0); // Pure white on first few frames, to hide SRB2's awful level load artifacts - else - V_DrawFadeScreen(0, 15-timeinmap); // Then gradually fade out from there - } + // Draw a fade on level opening + if (timeinmap < 16) + V_DrawCustomFadeScreen(((levelfadecol == 0) ? "FADEMAP1" : "FADEMAP0"), 32-(timeinmap*2)); // Then gradually fade out from there } diff --git a/src/v_video.c b/src/v_video.c index 1b1d03baa..297eae9c4 100644 --- a/src/v_video.c +++ b/src/v_video.c @@ -1287,28 +1287,75 @@ void V_DrawVhsEffect(boolean rewind) void V_DrawFadeScreen(UINT16 color, UINT8 strength) { #ifdef HWRENDER - if (rendermode != render_soft && rendermode != render_none) - { - HWR_FadeScreenMenuBack(color, strength); - return; - } + if (rendermode != render_soft && rendermode != render_none) + { + HWR_FadeScreenMenuBack(color, strength); + return; + } #endif - { - const UINT8 *fadetable = + { + const UINT8 *fadetable = (color > 0xFFF0) // Grab a specific colormap palette? ? R_GetTranslationColormap(color | 0xFFFF0000, strength, GTC_CACHE) : ((color & 0xFF00) // Color is not palette index? ? ((UINT8 *)colormaps + strength*256) // Do COLORMAP fade. : ((UINT8 *)transtables + ((9-strength)<