diff --git a/extras/conf/SRB2-22.cfg b/extras/conf/SRB2-22.cfg index f316cd032..7a8f31d5a 100644 --- a/extras/conf/SRB2-22.cfg +++ b/extras/conf/SRB2-22.cfg @@ -3,6 +3,7 @@ For Sonic Robo Blast 2 Version 2.2 Contributors (alphabetical): * Foxboy + * FuriousFox * JJames19119 * Kalaron * Kristos @@ -44,27 +45,32 @@ formatinterface = "SRB2MapSetIO"; //Sky textures for vanilla maps defaultskytextures { - SKY1 = "MAP01,MAP02,MAP03,MAP50,MAPA1,MAPA2,MAPA5,MAPA6,MAPA9,MAPAA,MAPAB,MAPAC,MAPAD,MAPAE,MAPAG,MAPAJ,MAPAK,MAPF0,MAPF1,MAPFA,MAPM0,MAPM8,MAPMA,MAPMB,MAPMC"; - SKY4 = "MAP04,MAP06,MAP51,MAPF8,MAPM1"; - SKY6 = "MAP05"; - SKY7 = "MAP07,MAP08,MAP09,MAP52,MAPM2,MAPM5"; - SKY10 = "MAP12,MAP53,MAPM3"; - SKY11 = "MAP10,MAP11,MAP16,MAP55,MAPF2,MAPF5,MAPF6,MAPF9,MAPM7"; - SKY13 = "MAP13,MAP54,MAPAS"; - SKY21 = "MAPAF,MAPF7,MAPM4"; - SKY22 = "MAP22,MAP23,MAP24,MAP25,MAP56,MAPAN,MAPAO,MAPF4,MAPM6"; - SKY29 = "MAP58,MAPAV"; + SKY1 = "MAP01,MAP02,MAP03,MAP33,MAP50,MAP60,MAPF0,MAPM0"; + SKY2 = "MAPM7,MAPMB"; + SKY4 = "MAP04,MAP06,MAP61,MAPF6,MAPM1"; + SKY6 = "MAP05,MAP51,MAPMA"; + SKY7 = "MAPM2,MAPM5"; + SKY8 = "MAP07,MAP08,MAP09,MAP52,MAP62,MAPF1"; + SKY10 = "MAP10,MAP12,MAP53,MAP63,MAPM3"; + SKY11 = "MAP11,MAPF7"; + SKY13 = "MAP13,MAP64"; + SKY14 = "MAP14"; + SKY15 = "MAP15,MAP54"; + SKY17 = "MAP70"; + SKY20 = "MAP32,MAP55,MAP65,MAPF2,MAPF5"; + SKY21 = "MAPM4"; + SKY22 = "MAP22,MAP23,MAP25,MAP26,MAP27,MAP56,MAP66,MAPF4,MAPM6"; SKY30 = "MAP30"; - SKY35 = "MAP41"; - SKY40 = "MAP40"; - SKY55 = "MAPF3,MAPM9"; - SKY66 = "MAPAT"; - SKY99 = "MAP57"; - SKY103 = "MAPA3,MAPA4,MAPAU"; - SKY107 = "MAPA7,MAPA8"; - SKY117 = "MAPAH,MAPAI"; - SKY127 = "MAPAR"; - SKY132 = "MAPAW"; + SKY31 = "MAP31"; + SKY35 = "MAP42"; + SKY40 = "MAP41,MAP71,MAPM9"; + SKY55 = "MAPF3,MAPM8"; + SKY68 = "MAPF8"; + SKY99 = "MAP57,MAPZ0"; + SKY159 = "MAP16"; + SKY172 = "MAP40"; + SKY300 = "MAP72"; + SKY301 = "MAP73"; } // Default lump name for new map @@ -90,9 +96,9 @@ skins Sonic; Tails; Knuckles; - Metalsonic; - Fang; Amy; + Fang; + Metalsonic; } // Gametypes @@ -3422,7 +3428,7 @@ thingtypes 121 { title = "Minus"; - sprite = "MNUSA1"; + sprite = "MNUSA0"; width = 24; height = 32; } @@ -3457,6 +3463,13 @@ thingtypes height = 34; flags8text = "[8] Start on fire"; } + 137 + { + title = "Dragonbomber"; + sprite = "DRABA1"; + width = 28; + height = 48; + } 105 { title = "Jetty-Syn Bomber"; @@ -5726,6 +5739,24 @@ thingtypes width = 24; height = 32; } + 1505 + { + title = "Green Flame"; + sprite = "CFLMA0E0"; + width = 8; + height = 32; + } + 1506 + { + arrow = 1; + blocking = 2; + title = "Blue Gargoyle"; + sprite = "BGARD1"; + width = 16; + height = 40; + flags4text = "[4] Slides when pushed"; + flags8text = "[8] Not pushable"; + } } dreamhill diff --git a/src/b_bot.c b/src/b_bot.c index 709a280b5..895c8d18d 100644 --- a/src/b_bot.c +++ b/src/b_bot.c @@ -135,7 +135,7 @@ static inline void B_BuildTailsTiccmd(mobj_t *sonic, mobj_t *tails, ticcmd_t *cm // ******** // FLY MODE // spinmode check - if (spinmode) + if (spinmode || player->exiting) thinkfly = false; else { diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 2a89116a1..635bd7ee9 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -1633,7 +1633,7 @@ static void CL_LoadReceivedSavegame(void) { CONS_Printf(": %s", mapheaderinfo[gamemap-1]->lvlttl); if (!(mapheaderinfo[gamemap-1]->levelflags & LF_NOZONE)) - CONS_Printf(M_GetText(" ZONE")); + CONS_Printf(M_GetText(" Zone")); if (actnum > 0) CONS_Printf(" %2d", actnum); } diff --git a/src/d_main.c b/src/d_main.c index 98e16a277..5853fccf0 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -291,8 +291,11 @@ static void D_Display(void) switch (gamestate) { case GS_TITLESCREEN: - F_TitleScreenDrawer(); - break; + if (!titlemapinaction || !curbghide) { + F_TitleScreenDrawer(); + break; + } + /* FALLTHRU */ case GS_LEVEL: if (!gametic) break; @@ -363,11 +366,56 @@ static void D_Display(void) // clean up border stuff // see if the border needs to be initially drawn - if (gamestate == GS_LEVEL) + if (gamestate == GS_LEVEL || (gamestate == GS_TITLESCREEN && titlemapinaction && curbghide && (!hidetitlemap))) { // draw the view directly - D_Render(); + if (!automapactive && !dedicated && cv_renderview.value) + { + if (players[displayplayer].mo || players[displayplayer].playerstate == PST_DEAD) + { + topleft = screens[0] + viewwindowy*vid.width + viewwindowx; + objectsdrawn = 0; + #ifdef HWRENDER + if (rendermode != render_soft) + HWR_RenderPlayerView(0, &players[displayplayer]); + else + #endif + if (rendermode != render_none) + R_RenderPlayerView(&players[displayplayer]); + } + + // render the second screen + if (splitscreen && players[secondarydisplayplayer].mo) + { + #ifdef HWRENDER + if (rendermode != render_soft) + HWR_RenderPlayerView(1, &players[secondarydisplayplayer]); + else + #endif + if (rendermode != render_none) + { + viewwindowy = vid.height / 2; + M_Memcpy(ylookup, ylookup2, viewheight*sizeof (ylookup[0])); + + topleft = screens[0] + viewwindowy*vid.width + viewwindowx; + + R_RenderPlayerView(&players[secondarydisplayplayer]); + + viewwindowy = 0; + M_Memcpy(ylookup, ylookup1, viewheight*sizeof (ylookup[0])); + } + } + + // Image postprocessing effect + if (rendermode == render_soft) + { + if (postimgtype) + V_DoPostProcessor(0, postimgtype, postimgparam); + if (postimgtype2) + V_DoPostProcessor(1, postimgtype2, postimgparam2); + } + } if (lastdraw) { @@ -380,9 +428,14 @@ static void D_Display(void) lastdraw = false; } - ST_Drawer(); - F_TextPromptDrawer(); - HU_Drawer(); + if (gamestate == GS_LEVEL) + { + ST_Drawer(); + F_TextPromptDrawer(); + HU_Drawer(); + } + else + F_TitleScreenDrawer(); } } @@ -494,56 +547,6 @@ static void D_Display(void) } } -void D_Render(void) -{ - if (!automapactive && !dedicated && cv_renderview.value) - { - if (players[displayplayer].mo || players[displayplayer].playerstate == PST_DEAD) - { - topleft = screens[0] + viewwindowy*vid.width + viewwindowx; - objectsdrawn = 0; -#ifdef HWRENDER - if (rendermode != render_soft) - HWR_RenderPlayerView(0, &players[displayplayer]); - else -#endif - if (rendermode != render_none) - R_RenderPlayerView(&players[displayplayer]); - } - - // render the second screen - if (splitscreen && players[secondarydisplayplayer].mo) - { -#ifdef HWRENDER - if (rendermode != render_soft) - HWR_RenderPlayerView(1, &players[secondarydisplayplayer]); - else -#endif - if (rendermode != render_none) - { - viewwindowy = vid.height / 2; - M_Memcpy(ylookup, ylookup2, viewheight*sizeof (ylookup[0])); - - topleft = screens[0] + viewwindowy*vid.width + viewwindowx; - - R_RenderPlayerView(&players[secondarydisplayplayer]); - - viewwindowy = 0; - M_Memcpy(ylookup, ylookup1, viewheight*sizeof (ylookup[0])); - } - } - - // Image postprocessing effect - if (rendermode == render_soft) - { - if (postimgtype) - V_DoPostProcessor(0, postimgtype, postimgparam); - if (postimgtype2) - V_DoPostProcessor(1, postimgtype2, postimgparam2); - } - } -} - // ========================================================================= // D_SRB2Loop // ========================================================================= @@ -664,6 +667,7 @@ void D_SRB2Loop(void) // consoleplayer -> displayplayer (hear sounds from viewpoint) S_UpdateSounds(); // move positional sounds + S_UpdateClosedCaptions(); // check for media change, loop music.. I_UpdateCD(); @@ -729,6 +733,8 @@ void D_StartTitle(void) for (i = 0; i < MAXPLAYERS; i++) CL_ClearPlayer(i); + players[consoleplayer].availabilities = players[1].availabilities = R_GetSkinAvailabilities(); // players[1] is supposed to be for 2p + splitscreen = false; SplitScreen_OnChange(); botingame = false; diff --git a/src/d_main.h b/src/d_main.h index 65c51802a..d67a5bb49 100644 --- a/src/d_main.h +++ b/src/d_main.h @@ -54,7 +54,4 @@ const char *D_Home(void); void D_AdvanceDemo(void); void D_StartTitle(void); -/* Here for title maps */ -void D_Render(void); - #endif //__D_MAIN__ diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 2b6055873..8fa4b2e0b 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -355,7 +355,7 @@ static CV_PossibleValue_t inttime_cons_t[] = {{0, "MIN"}, {3600, "MAX"}, {0, NUL consvar_t cv_inttime = {"inttime", "10", CV_NETVAR, inttime_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; static CV_PossibleValue_t coopstarposts_cons_t[] = {{0, "Per-player"}, {1, "Shared"}, {2, "Teamwork"}, {0, NULL}}; -consvar_t cv_coopstarposts = {"coopstarposts", "Teamwork", CV_NETVAR|CV_CALL|CV_CHEAT, coopstarposts_cons_t, CoopStarposts_OnChange, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_coopstarposts = {"coopstarposts", "Per-player", CV_NETVAR|CV_CALL, coopstarposts_cons_t, CoopStarposts_OnChange, 0, NULL, NULL, 0, 0, NULL}; static CV_PossibleValue_t cooplives_cons_t[] = {{0, "Infinite"}, {1, "Per-player"}, {2, "Avoid Game Over"}, {3, "Single pool"}, {0, NULL}}; consvar_t cv_cooplives = {"cooplives", "Avoid Game Over", CV_NETVAR|CV_CALL|CV_CHEAT, cooplives_cons_t, CoopLives_OnChange, 0, NULL, NULL, 0, 0, NULL}; @@ -1228,16 +1228,16 @@ static void SendNameAndColor(void) } else if ((foundskin = R_SkinAvailable(cv_skin.string)) != -1 && R_SkinUsable(consoleplayer, foundskin)) { - boolean notsame; + //boolean notsame; cv_skin.value = foundskin; - notsame = (cv_skin.value != players[consoleplayer].skin); + //notsame = (cv_skin.value != players[consoleplayer].skin); SetPlayerSkin(consoleplayer, cv_skin.string); CV_StealthSet(&cv_skin, skins[cv_skin.value].name); - if (notsame) + /*if (notsame) { CV_StealthSetValue(&cv_playercolor, skins[cv_skin.value].prefcolor); @@ -1245,7 +1245,7 @@ static void SendNameAndColor(void) if (players[consoleplayer].mo) players[consoleplayer].mo->color = (UINT8)players[consoleplayer].skincolor; - } + }*/ } else { @@ -1356,15 +1356,16 @@ static void SendNameAndColor2(void) } else if ((foundskin = R_SkinAvailable(cv_skin2.string)) != -1 && R_SkinUsable(secondplaya, foundskin)) { - boolean notsame; + //boolean notsame; cv_skin2.value = foundskin; - notsame = (cv_skin2.value != players[secondplaya].skin); + //notsame = (cv_skin2.value != players[secondplaya].skin); SetPlayerSkin(secondplaya, cv_skin2.string); + CV_StealthSet(&cv_skin2, skins[cv_skin2.value].name); - if (notsame) + /*if (notsame) { CV_StealthSetValue(&cv_playercolor2, skins[players[secondplaya].skin].prefcolor); @@ -1372,7 +1373,7 @@ static void SendNameAndColor2(void) if (players[secondplaya].mo) players[secondplaya].mo->color = players[secondplaya].skincolor; - } + }*/ } else { @@ -4289,6 +4290,8 @@ void Command_ExitGame_f(void) for (i = 0; i < MAXPLAYERS; i++) CL_ClearPlayer(i); + players[consoleplayer].availabilities = players[1].availabilities = R_GetSkinAvailabilities(); // players[1] is supposed to be for 2p + splitscreen = false; SplitScreen_OnChange(); botingame = false; diff --git a/src/dehacked.c b/src/dehacked.c index 29992fcd5..40ba0abca 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -3184,7 +3184,6 @@ static void readextraemblemdata(MYFILE *f, INT32 num) // Now get the part after word2 = tmp += 2; - strupr(word2); value = atoi(word2); // used for numerical settings @@ -3196,22 +3195,26 @@ static void readextraemblemdata(MYFILE *f, INT32 num) sizeof (extraemblems[num-1].description), va("Extra emblem %d: objective", num)); else if (fastcmp(word, "CONDITIONSET")) extraemblems[num-1].conditionset = (UINT8)value; - else if (fastcmp(word, "SPRITE")) - { - if (word2[0] >= 'A' && word2[0] <= 'Z') - value = word2[0]; - else - value += 'A'-1; - - if (value < 'A' || value > 'Z') - deh_warning("Emblem %d: sprite must be from A - Z (1 - 26)", num); - else - extraemblems[num-1].sprite = (UINT8)value; - } - else if (fastcmp(word, "COLOR")) - extraemblems[num-1].color = get_number(word2); else - deh_warning("Extra emblem %d: unknown word '%s'", num, word); + { + strupr(word2); + if (fastcmp(word, "SPRITE")) + { + if (word2[0] >= 'A' && word2[0] <= 'Z') + value = word2[0]; + else + value += 'A'-1; + + if (value < 'A' || value > 'Z') + deh_warning("Emblem %d: sprite must be from A - Z (1 - 26)", num); + else + extraemblems[num-1].sprite = (UINT8)value; + } + else if (fastcmp(word, "COLOR")) + extraemblems[num-1].color = get_number(word2); + else + deh_warning("Extra emblem %d: unknown word '%s'", num, word); + } } } while (!myfeof(f)); @@ -3262,7 +3265,6 @@ static void readunlockable(MYFILE *f, INT32 num) // Now get the part after word2 = tmp += 2; - strupr(word2); i = atoi(word2); // used for numerical settings @@ -3272,54 +3274,58 @@ static void readunlockable(MYFILE *f, INT32 num) else if (fastcmp(word, "OBJECTIVE")) deh_strlcpy(unlockables[num].objective, word2, sizeof (unlockables[num].objective), va("Unlockable %d: objective", num)); - else if (fastcmp(word, "HEIGHT")) - unlockables[num].height = (UINT16)i; - else if (fastcmp(word, "CONDITIONSET")) - unlockables[num].conditionset = (UINT8)i; - else if (fastcmp(word, "NOCECHO")) - unlockables[num].nocecho = (UINT8)(i || word2[0] == 'T' || word2[0] == 'Y'); - else if (fastcmp(word, "NOCHECKLIST")) - unlockables[num].nochecklist = (UINT8)(i || word2[0] == 'T' || word2[0] == 'Y'); - else if (fastcmp(word, "TYPE")) - { - if (fastcmp(word2, "NONE")) - unlockables[num].type = SECRET_NONE; - else if (fastcmp(word2, "ITEMFINDER")) - unlockables[num].type = SECRET_ITEMFINDER; - else if (fastcmp(word2, "EMBLEMHINTS")) - unlockables[num].type = SECRET_EMBLEMHINTS; - else if (fastcmp(word2, "PANDORA")) - unlockables[num].type = SECRET_PANDORA; - else if (fastcmp(word2, "CREDITS")) - unlockables[num].type = SECRET_CREDITS; - else if (fastcmp(word2, "RECORDATTACK")) - unlockables[num].type = SECRET_RECORDATTACK; - else if (fastcmp(word2, "NIGHTSMODE")) - unlockables[num].type = SECRET_NIGHTSMODE; - else if (fastcmp(word2, "HEADER")) - unlockables[num].type = SECRET_HEADER; - else if (fastcmp(word2, "LEVELSELECT")) - unlockables[num].type = SECRET_LEVELSELECT; - else if (fastcmp(word2, "WARP")) - unlockables[num].type = SECRET_WARP; - else if (fastcmp(word2, "SOUNDTEST")) - unlockables[num].type = SECRET_SOUNDTEST; - else - unlockables[num].type = (INT16)i; - } - else if (fastcmp(word, "VAR")) - { - // Support using the actual map name, - // i.e., Level AB, Level FZ, etc. - - // Convert to map number - if (word2[0] >= 'A' && word2[0] <= 'Z') - i = M_MapNumber(word2[0], word2[1]); - - unlockables[num].variable = (INT16)i; - } else - deh_warning("Unlockable %d: unknown word '%s'", num+1, word); + { + strupr(word2); + if (fastcmp(word, "HEIGHT")) + unlockables[num].height = (UINT16)i; + else if (fastcmp(word, "CONDITIONSET")) + unlockables[num].conditionset = (UINT8)i; + else if (fastcmp(word, "NOCECHO")) + unlockables[num].nocecho = (UINT8)(i || word2[0] == 'T' || word2[0] == 'Y'); + else if (fastcmp(word, "NOCHECKLIST")) + unlockables[num].nochecklist = (UINT8)(i || word2[0] == 'T' || word2[0] == 'Y'); + else if (fastcmp(word, "TYPE")) + { + if (fastcmp(word2, "NONE")) + unlockables[num].type = SECRET_NONE; + else if (fastcmp(word2, "ITEMFINDER")) + unlockables[num].type = SECRET_ITEMFINDER; + else if (fastcmp(word2, "EMBLEMHINTS")) + unlockables[num].type = SECRET_EMBLEMHINTS; + else if (fastcmp(word2, "PANDORA")) + unlockables[num].type = SECRET_PANDORA; + else if (fastcmp(word2, "CREDITS")) + unlockables[num].type = SECRET_CREDITS; + else if (fastcmp(word2, "RECORDATTACK")) + unlockables[num].type = SECRET_RECORDATTACK; + else if (fastcmp(word2, "NIGHTSMODE")) + unlockables[num].type = SECRET_NIGHTSMODE; + else if (fastcmp(word2, "HEADER")) + unlockables[num].type = SECRET_HEADER; + else if (fastcmp(word2, "LEVELSELECT")) + unlockables[num].type = SECRET_LEVELSELECT; + else if (fastcmp(word2, "WARP")) + unlockables[num].type = SECRET_WARP; + else if (fastcmp(word2, "SOUNDTEST")) + unlockables[num].type = SECRET_SOUNDTEST; + else + unlockables[num].type = (INT16)i; + } + else if (fastcmp(word, "VAR")) + { + // Support using the actual map name, + // i.e., Level AB, Level FZ, etc. + + // Convert to map number + if (word2[0] >= 'A' && word2[0] <= 'Z') + i = M_MapNumber(word2[0], word2[1]); + + unlockables[num].variable = (INT16)i; + } + else + deh_warning("Unlockable %d: unknown word '%s'", num+1, word); + } } } while (!myfeof(f)); // finish when the line is empty @@ -4969,14 +4975,10 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_MINUS_BURST4", "S_MINUS_BURST5", "S_MINUS_POPUP", - "S_MINUS_UPWARD1", - "S_MINUS_UPWARD2", - "S_MINUS_UPWARD3", - "S_MINUS_UPWARD4", - "S_MINUS_DOWNWARD1", - "S_MINUS_DOWNWARD2", - "S_MINUS_DOWNWARD3", - "S_MINUS_DOWNWARD4", + "S_MINUS_AERIAL1", + "S_MINUS_AERIAL2", + "S_MINUS_AERIAL3", + "S_MINUS_AERIAL4", // Minus dirt "S_MINUSDIRT1", diff --git a/src/f_finale.c b/src/f_finale.c index f319c6789..210adaca8 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -1681,6 +1681,7 @@ void F_GameEvaluationTicker(void) // ========== #define INFLECTIONPOINT (6*TICRATE) +#define STOPPINGPOINT (14*TICRATE) #define SPARKLLOOPTIME 15 // must be odd void F_StartEnding(void) @@ -1739,7 +1740,7 @@ void F_StartEnding(void) UINT8 skinnum = players[consoleplayer].skin; spritedef_t *sprdef; spriteframe_t *sprframe; - if (skins[skinnum].sprites[SPR2_XTRA].numframes >= (XTRA_ENDING+2)+1) + if (skins[skinnum].sprites[SPR2_XTRA].numframes > (XTRA_ENDING+2)) { sprdef = &skins[skinnum].sprites[SPR2_XTRA]; // character head, skin specific @@ -1772,7 +1773,7 @@ void F_StartEnding(void) void F_EndingTicker(void) { - if (++finalecount > INFLECTIONPOINT*2) + if (++finalecount > STOPPINGPOINT) { F_StartCredits(); wipetypepre = INT16_MAX; @@ -2168,26 +2169,26 @@ void F_EndingDrawer(void) if (finalecount < 10) trans = (10-finalecount)/2; - else if (finalecount > (2*INFLECTIONPOINT) - 20) + else if (finalecount > STOPPINGPOINT - 20) { - trans = 10 + (finalecount/2) - INFLECTIONPOINT; + trans = 10 + (finalecount - STOPPINGPOINT)/2; donttouch = true; } - if (trans != 10) + if (trans < 10) { //colset(linkmap, 164, 165, 169); -- the ideal purple colour to represent a clicked in-game link, but not worth it just for a soundtest-controlled secret V_DrawCenteredString(BASEVIDWIDTH/2, 8, V_ALLOWLOWERCASE|(trans<'|(trans<= (2*INFLECTIONPOINT)-TICRATE) ? V_PURPLEMAP : V_BLUEMAP)|(trans<"); + V_DrawString(40, ((finalecount == STOPPINGPOINT-(20+TICRATE)) ? 1 : 0)+BASEVIDHEIGHT-16, ((timesBeaten || finalecount >= STOPPINGPOINT-TICRATE) ? V_PURPLEMAP : V_BLUEMAP)|(trans<"); } - if (finalecount > (2*INFLECTIONPOINT)-(20+(2*TICRATE))) + if (finalecount > STOPPINGPOINT-(20+(2*TICRATE))) { INT32 trans2 = abs((5*FINECOSINE((FixedAngle((finalecount*5)<>ANGLETOFINESHIFT & FINEMASK)))>>FRACBITS)+2; if (!donttouch) { - trans = 10 + ((2*INFLECTIONPOINT)-(20+(2*TICRATE))) - finalecount; + trans = 10 + (STOPPINGPOINT-(20+(2*TICRATE))) - finalecount; if (trans > trans2) trans2 = trans; } @@ -2644,9 +2645,7 @@ void F_TitleScreenDrawer(void) // Draw that sky! if (curbgcolor >= 0) V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, curbgcolor); - else if (titlemapinaction && curbghide && ! hidetitlemap) - D_Render(); - else + else if (!curbghide || !titlemapinaction || gamestate == GS_WAITINGPLAYERS) F_SkyScroll(curbgxspeed, curbgyspeed, curbgname); // Don't draw outside of the title screen, or if the patch isn't there. @@ -3406,6 +3405,10 @@ void F_TitleScreenTicker(boolean run) if (run) finalecount++; + // don't trigger if doing anything besides idling on title + if (gameaction != ga_nothing || gamestate != GS_TITLESCREEN) + return; + // Execute the titlemap camera settings if (titlemapinaction) { @@ -3452,10 +3455,6 @@ void F_TitleScreenTicker(boolean run) } } - // don't trigger if doing anything besides idling on title - if (gameaction != ga_nothing || gamestate != GS_TITLESCREEN) - return; - // no demos to play? or, are they disabled? if (!cv_rollingdemos.value || !numDemos) return; @@ -3608,7 +3607,7 @@ void F_ContinueDrawer(void) if (timetonext >= (11*TICRATE)+10) return; - V_DrawLevelTitle(x - (V_LevelNameWidth("CONTINUE")>>1), 16, 0, "CONTINUE"); + V_DrawLevelTitle(x - (V_LevelNameWidth("Continue?")>>1), 16, 0, "Continue?"); // Two stars... patch = W_CachePatchName("CONTSTAR", PU_CACHE); diff --git a/src/g_game.c b/src/g_game.c index faaed13c7..340babb10 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -1019,11 +1019,11 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics) movebkey = PLAYER1INPUTDOWN(gc_backward); mouseaiming = (PLAYER1INPUTDOWN(gc_mouseaiming)) ^ - (cv_chasecam.value ? cv_chasefreelook.value : cv_alwaysfreelook.value); + ((cv_chasecam.value && !player->spectator) ? cv_chasefreelook.value : cv_alwaysfreelook.value); analogjoystickmove = cv_usejoystick.value && !Joystick.bGamepadStyle; gamepadjoystickmove = cv_usejoystick.value && Joystick.bGamepadStyle; - thisjoyaiming = (cv_chasecam.value) ? cv_chasefreelook.value : cv_alwaysfreelook.value; + thisjoyaiming = (cv_chasecam.value && !player->spectator) ? cv_chasefreelook.value : cv_alwaysfreelook.value; // Reset the vertical look if we're no longer joyaiming if (!thisjoyaiming && joyaiming) @@ -1348,11 +1348,11 @@ void G_BuildTiccmd2(ticcmd_t *cmd, INT32 realtics) movebkey = PLAYER2INPUTDOWN(gc_backward); mouseaiming = (PLAYER2INPUTDOWN(gc_mouseaiming)) ^ - (cv_chasecam2.value ? cv_chasefreelook2.value : cv_alwaysfreelook2.value); + ((cv_chasecam2.value && !player->spectator) ? cv_chasefreelook2.value : cv_alwaysfreelook2.value); analogjoystickmove = cv_usejoystick2.value && !Joystick2.bGamepadStyle; gamepadjoystickmove = cv_usejoystick2.value && Joystick2.bGamepadStyle; - thisjoyaiming = (cv_chasecam2.value) ? cv_chasefreelook2.value : cv_alwaysfreelook2.value; + thisjoyaiming = (cv_chasecam2.value && !player->spectator) ? cv_chasefreelook2.value : cv_alwaysfreelook2.value; // Reset the vertical look if we're no longer joyaiming if (!thisjoyaiming && joyaiming) @@ -2323,6 +2323,9 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps) outofcoop = players[player].outofcoop; pflags = (players[player].pflags & (PF_FLIPCAM|PF_ANALOGMODE|PF_DIRECTIONCHAR|PF_AUTOBRAKE|PF_TAGIT|PF_GAMETYPEOVER)); + if (!betweenmaps) + pflags |= (players[player].pflags & PF_FINISHED); + // As long as we're not in multiplayer, carry over cheatcodes from map to map if (!(netgame || multiplayer)) pflags |= (players[player].pflags & (PF_GODMODE|PF_NOCLIP|PF_INVIS)); @@ -2978,7 +2981,7 @@ void G_AddPlayer(INT32 playernum) if (G_GametypeUsesLives() || ((netgame || multiplayer) && gametype == GT_COOP)) p->lives = cv_startinglives.value; - if (countplayers && !notexiting) + if ((countplayers && !notexiting) || G_IsSpecialStage(gamemap)) P_DoPlayerExit(p); } @@ -2997,7 +3000,7 @@ boolean G_EnoughPlayersFinished(void) continue; total++; - if (players[i].pflags & PF_FINISHED) + if ((players[i].pflags & PF_FINISHED) || players[i].exiting) exiting++; } @@ -3099,7 +3102,7 @@ boolean G_GametypeUsesLives(void) // Coop, Competitive if ((gametype == GT_COOP || gametype == GT_COMPETITION) && !(modeattacking || metalrecording) // No lives in Time Attack - //&& !G_IsSpecialStage(gamemap) + && !G_IsSpecialStage(gamemap) && !(maptol & TOL_NIGHTS)) // No lives in NiGHTS return true; return false; diff --git a/src/hardware/hw_cache.c b/src/hardware/hw_cache.c index 6eaafca6d..2d4704b8b 100644 --- a/src/hardware/hw_cache.c +++ b/src/hardware/hw_cache.c @@ -771,18 +771,25 @@ void HWR_InitTextureCache(void) gr_textures2 = NULL; } - // Callback function for HWR_FreeTextureCache. static void FreeMipmapColormap(INT32 patchnum, void *patch) { - GLPatch_t* const grpatch = patch; + GLPatch_t* const pat = patch; (void)patchnum; //unused - while (grpatch->mipmap->nextcolormap) + while (pat->mipmap && pat->mipmap->nextcolormap) // The mipmap must be valid, obviously { - GLMipmap_t *grmip = grpatch->mipmap->nextcolormap; - grpatch->mipmap->nextcolormap = grmip->nextcolormap; - if (grmip->grInfo.data) Z_Free(grmip->grInfo.data); - free(grmip); + // Confusing at first, but pat->mipmap->nextcolormap + // at the beginning of the loop is the first colormap + // from the linked list of colormaps + GLMipmap_t *next = pat->mipmap->nextcolormap; + // Set the first colormap + // to the one that comes after it + pat->mipmap->nextcolormap = next->nextcolormap; + // Free image data from memory + if (next->grInfo.data) + Z_Free(next->grInfo.data); + // Free the old colormap from memory + free(next); } } @@ -799,7 +806,7 @@ void HWR_FreeTextureCache(void) // Alam: free the Z_Blocks before freeing it's users - // free all skin after each level: must be done after pfnClearMipMapCache! + // free all patch colormaps after each level: must be done after ClearMipMapCache! for (i = 0; i < numwadfiles; i++) M_AATreeIterate(wadfiles[i]->hwrcache, FreeMipmapColormap); diff --git a/src/info.c b/src/info.c index e14abd575..45a4c88d9 100644 --- a/src/info.c +++ b/src/info.c @@ -635,7 +635,7 @@ playersprite_t spr2defaults[NUMPLAYERSPRITES] = { 0, // SPR2_TRNS, FF_SPR2SUPER|SPR2_STND, // SPR2_NSTD, - FF_SPR2SUPER|SPR2_FLT , // SPR2_NFLT, + FF_SPR2SUPER|SPR2_FALL, // SPR2_NFLT, 0, // SPR2_NFLY, (will never be referenced unless skin 0 lacks this) SPR2_NFLY, // SPR2_NDRL, FF_SPR2SUPER|SPR2_STUN, // SPR2_NSTN, @@ -1074,15 +1074,11 @@ state_t states[NUMSTATES] = {SPR_MNUD, 2|FF_ANIMATE, 5, {NULL}, 1, 2, S_MINUS_BURST4}, // S_MINUS_BURST3 {SPR_MNUD, 3|FF_ANIMATE, 5, {NULL}, 1, 2, S_MINUS_BURST5}, // S_MINUS_BURST4 {SPR_MNUD, 4|FF_ANIMATE, 5, {NULL}, 1, 2, S_MINUSDIRT2}, // S_MINUS_BURST5 - {SPR_MNUS, 3, 1, {A_MinusPopup}, 0, 0, S_MINUS_UPWARD1}, // S_MINUS_POPUP - {SPR_MNUS, 0, 1, {A_MinusCheck}, 0, 0, S_MINUS_UPWARD2}, // S_MINUS_UPWARD1 - {SPR_MNUS, 1, 1, {A_MinusCheck}, 0, 0, S_MINUS_UPWARD3}, // S_MINUS_UPWARD2 - {SPR_MNUS, 2, 1, {A_MinusCheck}, 0, 0, S_MINUS_UPWARD4}, // S_MINUS_UPWARD3 - {SPR_MNUS, 3, 1, {A_MinusCheck}, 0, 0, S_MINUS_UPWARD1}, // S_MINUS_UPWARD4 - {SPR_MNUS, 4, 1, {A_MinusCheck}, 0, 0, S_MINUS_DOWNWARD2}, // S_MINUS_DOWNWARD1 - {SPR_MNUS, 5, 1, {A_MinusCheck}, 0, 0, S_MINUS_DOWNWARD3}, // S_MINUS_DOWNWARD2 - {SPR_MNUS, 6, 1, {A_MinusCheck}, 0, 0, S_MINUS_DOWNWARD4}, // S_MINUS_DOWNWARD3 - {SPR_MNUS, 7, 1, {A_MinusCheck}, 0, 0, S_MINUS_DOWNWARD1}, // S_MINUS_DOWNWARD4 + {SPR_MNUS, 3, 1, {A_MinusPopup}, 0, 0, S_MINUS_AERIAL1}, // S_MINUS_POPUP + {SPR_MNUS, 0, 1, {A_MinusCheck}, 0, 1, S_MINUS_AERIAL2}, // S_MINUS_AERIAL1 + {SPR_MNUS, 1, 1, {A_MinusCheck}, 0, 1, S_MINUS_AERIAL3}, // S_MINUS_AERIAL2 + {SPR_MNUS, 2, 1, {A_MinusCheck}, 0, 1, S_MINUS_AERIAL4}, // S_MINUS_AERIAL3 + {SPR_MNUS, 3, 1, {A_MinusCheck}, 0, 1, S_MINUS_AERIAL1}, // S_MINUS_AERIAL4 {SPR_MNUD, FF_ANIMATE, 6, {NULL}, 1, 5, S_MINUSDIRT2}, // S_MINUSDIRT1 {SPR_MNUD, 5, 8, {NULL}, 3, 5, S_MINUSDIRT3}, // S_MINUSDIRT2 @@ -13373,7 +13369,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 0, // damage sfx_None, // activesound - MF_SPECIAL|MF_PAIN|MF_NOGRAVITY, // flags + MF_SPECIAL|MF_PAIN|MF_NOGRAVITY|MF_FIRE, // flags S_NULL // raisestate }, diff --git a/src/info.h b/src/info.h index ff346412e..f3f50fab7 100644 --- a/src/info.h +++ b/src/info.h @@ -1270,14 +1270,10 @@ typedef enum state S_MINUS_BURST4, S_MINUS_BURST5, S_MINUS_POPUP, - S_MINUS_UPWARD1, - S_MINUS_UPWARD2, - S_MINUS_UPWARD3, - S_MINUS_UPWARD4, - S_MINUS_DOWNWARD1, - S_MINUS_DOWNWARD2, - S_MINUS_DOWNWARD3, - S_MINUS_DOWNWARD4, + S_MINUS_AERIAL1, + S_MINUS_AERIAL2, + S_MINUS_AERIAL3, + S_MINUS_AERIAL4, // Minus dirt S_MINUSDIRT1, diff --git a/src/m_cond.c b/src/m_cond.c index b7520aba7..8c4e3c0b7 100644 --- a/src/m_cond.c +++ b/src/m_cond.c @@ -284,6 +284,8 @@ void M_SilentUpdateUnlockablesAndEmblems(void) continue; unlockables[i].unlocked = M_Achieved(unlockables[i].conditionset - 1); } + + players[consoleplayer].availabilities = players[1].availabilities = R_GetSkinAvailabilities(); // players[1] is supposed to be for 2p } // Emblem unlocking shit diff --git a/src/m_menu.c b/src/m_menu.c index 7d62514e6..7c635a137 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -6688,7 +6688,7 @@ static void M_DrawChecklist(void) || !unlockables[i].conditionset || unlockables[i].conditionset > MAXCONDITIONSETS) continue; - V_DrawString(currentMenu->x, y, ((unlockables[i].unlocked) ? V_GREENMAP : V_TRANSLUCENT), ((unlockables[i].unlocked || !unlockables[i].nochecklist) ? unlockables[i].name : M_CreateSecretMenuOption(unlockables[i].name))); + V_DrawString(currentMenu->x, y, ((unlockables[i].unlocked) ? V_GREENMAP : V_TRANSLUCENT)|V_ALLOWLOWERCASE, ((unlockables[i].unlocked || !unlockables[i].nochecklist) ? unlockables[i].name : M_CreateSecretMenuOption(unlockables[i].name))); for (j = i+1; j < MAXUNLOCKABLES; j++) { @@ -8334,16 +8334,12 @@ static void M_SetupChoosePlayer(INT32 choice) { INT32 skinnum; UINT8 i; - UINT8 firstvalid = 255; - UINT8 lastvalid = 0; + UINT8 firstvalid = 255, lastvalid = 255; boolean allowed = false; char *and; (void)choice; - if (!(mapheaderinfo[startmap-1] - && (mapheaderinfo[startmap-1]->forcecharacter[0] != '\0' - || (mapheaderinfo[startmap-1]->typeoflevel & TOL_NIGHTS)) // remove this later when everyone gets their own nights sprites, maybe - )) + if (!mapheaderinfo[startmap-1] || mapheaderinfo[startmap-1]->forcecharacter[0] == '\0') { for (i = 0; i < 32; i++) // Handle charsels, availability, and unlocks. { @@ -8353,6 +8349,8 @@ static void M_SetupChoosePlayer(INT32 choice) if (and) { char firstskin[SKINNAMESIZE+1]; + if (mapheaderinfo[startmap-1]->typeoflevel & TOL_NIGHTS) // skip tagteam characters for NiGHTS levels + continue; strncpy(firstskin, description[i].skinname, (and - description[i].skinname)); firstskin[(and - description[i].skinname)] = '\0'; description[i].skinnum[0] = R_SkinAvailable(firstskin); @@ -8381,7 +8379,7 @@ static void M_SetupChoosePlayer(INT32 choice) if (!(description[i].picname[0])) { - if (skins[skinnum].sprites[SPR2_XTRA].numframes >= XTRA_CHARSEL+1) + if (skins[skinnum].sprites[SPR2_XTRA].numframes > XTRA_CHARSEL) { spritedef_t *sprdef = &skins[skinnum].sprites[SPR2_XTRA]; spriteframe_t *sprframe = &sprdef->spriteframes[XTRA_CHARSEL]; @@ -8406,17 +8404,16 @@ static void M_SetupChoosePlayer(INT32 choice) } } - if (firstvalid != 255) - { // One last bit of order we can't do in the iteration above. - description[firstvalid].prev = lastvalid; - description[lastvalid].next = firstvalid; - } - else // We're being forced into a specific character, so might as well just skip it. + if (firstvalid == lastvalid) // We're being forced into a specific character, so might as well just skip it. { - M_ChoosePlayer(-1); + M_ChoosePlayer(firstvalid); return; } + // One last bit of order we can't do in the iteration above. + description[firstvalid].prev = lastvalid; + description[lastvalid].next = firstvalid; + M_ChangeMenuMusic("_chsel", true); /* the menus suck -James */ @@ -8743,7 +8740,7 @@ static void M_ChoosePlayer(INT32 choice) UINT8 skinnum; // skip this if forcecharacter or no characters available - if (choice == -1) + if (choice == 255) { skinnum = botskin = 0; botingame = false; @@ -8855,9 +8852,9 @@ static void M_DrawStatsMaps(int location) M_DrawMapEmblems(mnum+1, 292, y); if (mapheaderinfo[mnum]->actnum != 0) - V_DrawString(20, y, V_YELLOWMAP, va("%s %d", mapheaderinfo[mnum]->lvlttl, mapheaderinfo[mnum]->actnum)); + V_DrawString(20, y, V_YELLOWMAP|V_ALLOWLOWERCASE, va("%s %d", mapheaderinfo[mnum]->lvlttl, mapheaderinfo[mnum]->actnum)); else - V_DrawString(20, y, V_YELLOWMAP, mapheaderinfo[mnum]->lvlttl); + V_DrawString(20, y, V_YELLOWMAP|V_ALLOWLOWERCASE, mapheaderinfo[mnum]->lvlttl); y += 8; @@ -8901,7 +8898,7 @@ static void M_DrawStatsMaps(int location) else V_DrawSmallScaledPatch(292, y, 0, W_CachePatchName("NEEDIT", PU_CACHE)); - V_DrawString(20, y, V_YELLOWMAP, va("%s", exemblem->description)); + V_DrawString(20, y, V_YELLOWMAP|V_ALLOWLOWERCASE, va("%s", exemblem->description)); } y += 8; @@ -9112,7 +9109,7 @@ void M_DrawTimeAttackMenu(void) // Character face! { - if (skins[cv_chooseskin.value-1].sprites[SPR2_XTRA].numframes >= XTRA_CHARSEL+1) + if (skins[cv_chooseskin.value-1].sprites[SPR2_XTRA].numframes > XTRA_CHARSEL) { spritedef_t *sprdef = &skins[cv_chooseskin.value-1].sprites[SPR2_XTRA]; spriteframe_t *sprframe = &sprdef->spriteframes[XTRA_CHARSEL]; @@ -9388,6 +9385,7 @@ void M_DrawNightsAttackMenu(void) { emblem_t *em; INT32 yHeight; + INT32 xpos; patch_t *PictureOfLevel; lumpnum_t lumpnum; char beststr[40]; @@ -9447,17 +9445,23 @@ void M_DrawNightsAttackMenu(void) { switch (em->type) { - case ET_NGRADE: yHeight = 48; break; - case ET_NTIME: yHeight = 68; break; + case ET_NGRADE: + xpos = 104+38; + yHeight = 48; + break; + case ET_NTIME: + xpos = 104+76; + yHeight = 68; + break; default: goto skipThisOne; } if (em->collected) - V_DrawSmallMappedPatch(104+38, yHeight+lsheadingheight/2, 0, W_CachePatchName(M_GetEmblemPatch(em, false), PU_CACHE), + V_DrawSmallMappedPatch(xpos, yHeight+lsheadingheight/2, 0, W_CachePatchName(M_GetEmblemPatch(em, false), PU_CACHE), R_GetTranslationColormap(TC_DEFAULT, M_GetEmblemColor(em), GTC_CACHE)); else - V_DrawSmallScaledPatch(104+38, yHeight+lsheadingheight/2, 0, W_CachePatchName("NEEDIT", PU_CACHE)); + V_DrawSmallScaledPatch(xpos, yHeight+lsheadingheight/2, 0, W_CachePatchName("NEEDIT", PU_CACHE)); skipThisOne: em = M_GetLevelEmblems(-1); diff --git a/src/m_misc.c b/src/m_misc.c index 5cfb20f0f..ca9b3a8e1 100644 --- a/src/m_misc.c +++ b/src/m_misc.c @@ -789,7 +789,7 @@ static void M_PNGText(png_structp png_ptr, png_infop png_info_ptr, PNG_CONST png if (gamestate == GS_LEVEL && mapheaderinfo[gamemap-1]->lvlttl[0] != '\0') snprintf(lvlttltext, 48, "%s%s%s", mapheaderinfo[gamemap-1]->lvlttl, - (mapheaderinfo[gamemap-1]->levelflags & LF_NOZONE) ? "" : " ZONE", + (mapheaderinfo[gamemap-1]->levelflags & LF_NOZONE) ? "" : " Zone", (mapheaderinfo[gamemap-1]->actnum > 0) ? va(" %d",mapheaderinfo[gamemap-1]->actnum) : ""); else snprintf(lvlttltext, 48, "Unknown"); diff --git a/src/p_enemy.c b/src/p_enemy.c index 26d079cb4..785d19fb4 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -2476,12 +2476,8 @@ void A_VultureBlast(mobj_t *actor) void A_VultureFly(mobj_t *actor) { fixed_t speedmax = 18*FRACUNIT; - angle_t angledif = R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y) - actor->angle; - fixed_t dx = actor->target->x - actor->x; - fixed_t dy = actor->target->y - actor->y; - fixed_t dz = actor->target->z - actor->z; - fixed_t dxy = FixedHypot(dx, dy); - fixed_t dm; + angle_t angledif; + fixed_t dx, dy, dz, dxy, dm; mobj_t *dust; fixed_t momm; @@ -2490,6 +2486,18 @@ void A_VultureFly(mobj_t *actor) return; #endif + if (!actor->target || P_MobjWasRemoved(actor->target)) + { + P_SetMobjState(actor, actor->info->spawnstate); + return; + } + + angledif = R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y) - actor->angle; + dx = actor->target->x - actor->x; + dy = actor->target->y - actor->y; + dz = actor->target->z - actor->z; + dxy = FixedHypot(dx, dy); + if (leveltime % 4 == 0) S_StartSound(actor, actor->info->activesound); @@ -5664,10 +5672,10 @@ void A_MinusPopup(mobj_t *actor) S_StartSound(actor, sfx_s3k82); for (i = 1; i <= num; i++) { - mobj_t *rock = P_SpawnMobj(actor->x, actor->y, actor->z + actor->height/4, MT_ROCKCRUMBLE1); + mobj_t *rock = P_SpawnMobjFromMobj(actor, 0, 0, actor->height/4, MT_ROCKCRUMBLE1); P_Thrust(rock, ani*i, FRACUNIT); - rock->momz = 3*FRACUNIT; - P_SetScale(rock, FRACUNIT/3); + P_SetObjectMomZ(rock, 3*FRACUNIT, false); + P_SetScale(rock, rock->scale/3); } P_RadiusAttack(actor, actor, 2*actor->radius, 0); if (actor->tracer) @@ -5681,11 +5689,12 @@ void A_MinusPopup(mobj_t *actor) // Description: If the minus hits the floor, dig back into the ground. // // var1 = State to switch to (if 0, use seestate). -// var2 = unused +// var2 = If not 0, spawn debris when hitting the floor. // void A_MinusCheck(mobj_t *actor) { INT32 locvar1 = var1; + INT32 locvar2 = var2; #ifdef HAVE_BLUA if (LUA_CallAction("A_MinusCheck", actor)) @@ -5696,6 +5705,18 @@ void A_MinusCheck(mobj_t *actor) { P_SetMobjState(actor, locvar1 ? (statenum_t)locvar1 : actor->info->seestate); actor->flags = actor->info->flags; + if (locvar2) + { + INT32 i, num = 6; + angle_t ani = FixedAngle(FRACUNIT*360/num); + for (i = 1; i <= num; i++) + { + mobj_t *rock = P_SpawnMobjFromMobj(actor, 0, 0, actor->height/4, MT_ROCKCRUMBLE1); + P_Thrust(rock, ani*i, FRACUNIT); + P_SetObjectMomZ(rock, 3*FRACUNIT, false); + P_SetScale(rock, rock->scale/3); + } + } } } @@ -14590,6 +14611,9 @@ void A_RolloutRock(mobj_t *actor) actor->frame = actor->reactiontime % maxframes; // set frame + if (!actor->tracer || P_MobjWasRemoved(actor->tracer) || !actor->tracer->health) + actor->flags |= MF_PUSHABLE; + if (!(actor->flags & MF_PUSHABLE)) // if being ridden, don't disappear actor->fuse = 0; else if (!actor->fuse && actor->movecount == 1) // otherwise if rock has moved, set its fuse diff --git a/src/p_inter.c b/src/p_inter.c index a51a4e8e6..469cec33e 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -148,15 +148,19 @@ void P_ResetStarposts(void) // boolean P_CanPickupItem(player_t *player, boolean weapon) { - if (player->bot && weapon) + if (!player->mo || player->mo->health <= 0) return false; + if (player->bot) + { + if (weapon) + return false; + return P_CanPickupItem(&players[consoleplayer], true); // weapon is true to prevent infinite recursion if p1 is bot - doesn't occur in vanilla, but may be relevant for mods + } + if (player->powers[pw_flashing] > (flashingtics/4)*3 && player->powers[pw_flashing] < UINT16_MAX) return false; - if (player->mo && player->mo->health <= 0) - return false; - return true; } @@ -2521,7 +2525,7 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget if ((target->player->lives <= 1) && (netgame || multiplayer) && (gametype == GT_COOP) && (cv_cooplives.value == 0)) ; - else if (!target->player->bot && !target->player->spectator && !G_IsSpecialStage(gamemap) && (target->player->lives != INFLIVES) + else if (!target->player->bot && !target->player->spectator && (target->player->lives != INFLIVES) && G_GametypeUsesLives()) { target->player->lives -= 1; // Lose a life Tails 03-11-2000 @@ -2814,13 +2818,10 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget if (flip) momz *= -1; #define makechunk(angtweak, xmov, ymov) \ - chunk = P_SpawnMobj(target->x, target->y, target->z, MT_SPIKE);\ - chunk->eflags |= flip;\ + chunk = P_SpawnMobjFromMobj(target, 0, 0, 0, MT_SPIKE);\ P_SetMobjState(chunk, target->info->xdeathstate);\ chunk->health = 0;\ chunk->angle = angtweak;\ - chunk->destscale = scale;\ - P_SetScale(chunk, scale);\ P_UnsetThingPosition(chunk);\ chunk->flags = MF_NOCLIP;\ chunk->x += xmov;\ @@ -2839,14 +2840,10 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget if (flip) momz *= -1; - chunk = P_SpawnMobj(target->x, target->y, target->z, MT_SPIKE); - chunk->eflags |= flip; - + chunk = P_SpawnMobjFromMobj(target, 0, 0, 0, MT_SPIKE); P_SetMobjState(chunk, target->info->deathstate); chunk->health = 0; chunk->angle = ang + ANGLE_180; - chunk->destscale = scale; - P_SetScale(chunk, scale); P_UnsetThingPosition(chunk); chunk->flags = MF_NOCLIP; chunk->x -= xoffs; @@ -2889,13 +2886,10 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget sprflip = P_RandomChance(FRACUNIT/2); #define makechunk(angtweak, xmov, ymov) \ - chunk = P_SpawnMobj(target->x, target->y, target->z, MT_WALLSPIKE);\ - chunk->eflags |= flip;\ + chunk = P_SpawnMobjFromMobj(target, 0, 0, 0, MT_WALLSPIKE);\ P_SetMobjState(chunk, target->info->xdeathstate);\ chunk->health = 0;\ chunk->angle = target->angle;\ - chunk->destscale = scale;\ - P_SetScale(chunk, scale);\ P_UnsetThingPosition(chunk);\ chunk->flags = MF_NOCLIP;\ chunk->x += xmov - forwardxoffs;\ @@ -2917,14 +2911,11 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget sprflip = P_RandomChance(FRACUNIT/2); - chunk = P_SpawnMobj(target->x, target->y, target->z, MT_WALLSPIKE); - chunk->eflags |= flip; + chunk = P_SpawnMobjFromMobj(target, 0, 0, 0, MT_WALLSPIKE); P_SetMobjState(chunk, target->info->deathstate); chunk->health = 0; chunk->angle = target->angle; - chunk->destscale = scale; - P_SetScale(chunk, scale); P_UnsetThingPosition(chunk); chunk->flags = MF_NOCLIP; chunk->x += forwardxoffs - xoffs; diff --git a/src/p_local.h b/src/p_local.h index b718c43f1..646fa70f2 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -323,6 +323,7 @@ SINT8 P_MobjFlip(mobj_t *mobj); fixed_t P_GetMobjGravity(mobj_t *mo); FUNCMATH boolean P_WeaponOrPanel(mobjtype_t type); +void P_CalcChasePostImg(player_t *player, camera_t *thiscam); boolean P_CameraThinker(player_t *player, camera_t *thiscam, boolean resetcalled); void P_Attract(mobj_t *source, mobj_t *enemy, boolean nightsgrab); diff --git a/src/p_map.c b/src/p_map.c index 753ce9eb5..8220f3818 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -784,12 +784,12 @@ static boolean PIT_CheckThing(mobj_t *thing) if (thing->type == MT_SPIKE || thing->type == MT_WALLSPIKE) { - mobjtype_t type = thing->type; + mobj_t *iter; if (thing->flags & MF_SOLID) S_StartSound(tmthing, thing->info->deathsound); - for (thing = thing->subsector->sector->thinglist; thing; thing = thing->snext) - if (thing->type == type && thing->health > 0 && thing->flags & MF_SOLID && P_AproxDistance(P_AproxDistance(thing->x - tmthing->x, thing->y - tmthing->y), thing->z - tmthing->z) < 56*thing->scale)//FixedMul(56*FRACUNIT, thing->scale)) - P_KillMobj(thing, tmthing, tmthing, 0); + for (iter = thing->subsector->sector->thinglist; iter; iter = iter->snext) + if (iter->type == thing->type && iter->health > 0 && iter->flags & MF_SOLID && (iter == thing || P_AproxDistance(P_AproxDistance(thing->x - iter->x, thing->y - iter->y), thing->z - iter->z) < 56*thing->scale))//FixedMul(56*FRACUNIT, thing->scale)) + P_KillMobj(iter, tmthing, tmthing, 0); } else { @@ -823,12 +823,12 @@ static boolean PIT_CheckThing(mobj_t *thing) if (thing->type == MT_SPIKE || thing->type == MT_WALLSPIKE) { - mobjtype_t type = thing->type; + mobj_t *iter; if (thing->flags & MF_SOLID) S_StartSound(tmthing, thing->info->deathsound); - for (thing = thing->subsector->sector->thinglist; thing; thing = thing->snext) - if (thing->type == type && thing->health > 0 && thing->flags & MF_SOLID && P_AproxDistance(P_AproxDistance(thing->x - tmthing->x, thing->y - tmthing->y), thing->z - tmthing->z) < 56*thing->scale)//FixedMul(56*FRACUNIT, thing->scale)) - P_KillMobj(thing, tmthing, tmthing, 0); + for (iter = thing->subsector->sector->thinglist; iter; iter = iter->snext) + if (iter->type == thing->type && iter->health > 0 && iter->flags & MF_SOLID && (iter == thing || P_AproxDistance(P_AproxDistance(thing->x - iter->x, thing->y - iter->y), thing->z - iter->z) < 56*thing->scale))//FixedMul(56*FRACUNIT, thing->scale)) + P_KillMobj(iter, tmthing, tmthing, 0); } else { @@ -1303,11 +1303,6 @@ static boolean PIT_CheckThing(mobj_t *thing) return false; } - // Fireball touched an enemy - // Don't bounce though, just despawn right there - if ((tmthing->type == MT_FIREBALL) && (thing->flags & MF_ENEMY)) - P_KillMobj(tmthing, NULL, NULL, 0); - // damage / explode if (tmthing->flags & MF_ENEMY) // An actual ENEMY! (Like the deton, for example) P_DamageMobj(thing, tmthing, tmthing, 1, 0); @@ -1356,6 +1351,11 @@ static boolean PIT_CheckThing(mobj_t *thing) P_DamageMobj(thing, tmthing, tmthing->target, 1, damagetype); } + // Fireball touched an enemy + // Don't bounce though, just despawn right there + if ((tmthing->type == MT_FIREBALL) && (thing->flags & MF_ENEMY)) + P_KillMobj(tmthing, NULL, NULL, 0); + // don't traverse any more if (tmthing->type == MT_SHELL) @@ -1719,8 +1719,8 @@ static boolean PIT_CheckThing(mobj_t *thing) } } - if ((tmthing->flags & MF_SPRING || tmthing->type == MT_STEAM) && (thing->player)) - ; // springs and gas jets should never be able to step up onto a player + if ((tmthing->flags & MF_SPRING || tmthing->type == MT_STEAM || tmthing->type == MT_SPIKE || tmthing->type == MT_WALLSPIKE) && (thing->player)) + ; // springs, gas jets and springs should never be able to step up onto a player // z checking at last // Treat noclip things as non-solid! else if ((thing->flags & (MF_SOLID|MF_NOCLIP)) == MF_SOLID @@ -3758,6 +3758,33 @@ void P_SlideMove(mobj_t *mo) v2.x = tmhitthing->x + cosradius; v2.y = tmhitthing->y + sinradius; + // Can we box collision our way into smooth movement..? + if (sinradius && mo->y + mo->radius <= min(v1.y, v2.y)) + { + mo->momy = 0; + P_TryMove(mo, mo->x + mo->momx, min(v1.y, v2.y) - mo->radius, true); + return; + } + else if (sinradius && mo->y - mo->radius >= max(v1.y, v2.y)) + { + mo->momy = 0; + P_TryMove(mo, mo->x + mo->momx, max(v1.y, v2.y) + mo->radius, true); + return; + } + else if (cosradius && mo->x + mo->radius <= min(v1.x, v2.x)) + { + mo->momx = 0; + P_TryMove(mo, min(v1.x, v2.x) - mo->radius, mo->y + mo->momy, true); + return; + } + else if (cosradius && mo->x - mo->radius >= max(v1.x, v2.x)) + { + mo->momx = 0; + P_TryMove(mo, max(v1.x, v2.x) + mo->radius, mo->y + mo->momy, true); + return; + } + + // nope, gotta fuck around with a fake linedef! junk.v1 = &v1; junk.v2 = &v2; junk.dx = 2*cosradius; // v2.x - v1.x; diff --git a/src/p_mobj.c b/src/p_mobj.c index f2dd1a734..6a250a783 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -255,7 +255,6 @@ boolean P_SetPlayerMobjState(mobj_t *mobj, statenum_t state) case S_PLAY_WALK: case S_PLAY_SKID: case S_PLAY_FLOAT: - case S_PLAY_NIGHTS_FLOAT: player->panim = PA_WALK; break; case S_PLAY_RUN: @@ -281,6 +280,7 @@ boolean P_SetPlayerMobjState(mobj_t *mobj, statenum_t state) player->panim = PA_SPRING; break; case S_PLAY_FALL: + case S_PLAY_NIGHTS_FLOAT: player->panim = PA_FALL; break; case S_PLAY_FLY: @@ -3408,7 +3408,7 @@ void P_MobjCheckWater(mobj_t *mobj) // Drown timer setting if ((p->powers[pw_shield] & SH_PROTECTWATER) // Has water protection - || (p->exiting) // Or exiting + || (p->exiting) || (p->pflags & PF_FINISHED) // Or finished/exiting || (maptol & TOL_NIGHTS) // Or in NiGHTS mode || (mariomode)) // Or in Mario mode... { @@ -3724,17 +3724,10 @@ void P_DestroyRobots(void) } } -// P_CameraThinker -// -// Process the mobj-ish required functions of the camera -boolean P_CameraThinker(player_t *player, camera_t *thiscam, boolean resetcalled) +// the below is chasecam only, if you're curious. check out P_CalcPostImg in p_user.c for first person +void P_CalcChasePostImg(player_t *player, camera_t *thiscam) { - boolean itsatwodlevel = false; postimg_t postimg = postimg_none; - if (twodlevel - || (thiscam == &camera && players[displayplayer].mo && (players[displayplayer].mo->flags2 & MF2_TWOD)) - || (thiscam == &camera2 && players[secondarydisplayplayer].mo && (players[secondarydisplayplayer].mo->flags2 & MF2_TWOD))) - itsatwodlevel = true; if (player->pflags & PF_FLIPCAM && !(player->powers[pw_carry] == CR_NIGHTSMODE) && player->mo->eflags & MFE_VERTICALFLIP) postimg = postimg_flip; @@ -3762,13 +3755,27 @@ boolean P_CameraThinker(player_t *player, camera_t *thiscam, boolean resetcalled postimg = postimg_heat; } - if (postimg != postimg_none) - { - if (splitscreen && player == &players[secondarydisplayplayer]) - postimgtype2 = postimg; - else - postimgtype = postimg; - } + if (postimg == postimg_none) + return; + + if (splitscreen && player == &players[secondarydisplayplayer]) + postimgtype2 = postimg; + else + postimgtype = postimg; +} + +// P_CameraThinker +// +// Process the mobj-ish required functions of the camera +boolean P_CameraThinker(player_t *player, camera_t *thiscam, boolean resetcalled) +{ + boolean itsatwodlevel = false; + if (twodlevel + || (thiscam == &camera && players[displayplayer].mo && (players[displayplayer].mo->flags2 & MF2_TWOD)) + || (thiscam == &camera2 && players[secondarydisplayplayer].mo && (players[secondarydisplayplayer].mo->flags2 & MF2_TWOD))) + itsatwodlevel = true; + + P_CalcChasePostImg(player, thiscam); if (thiscam->momx || thiscam->momy) { @@ -7082,7 +7089,7 @@ static void P_SpawnMinecartSegments(mobj_t *mobj, boolean mode) seg = P_SpawnMobj(x, y, z, MT_MINECARTSEG); P_SetMobjState(seg, (statenum_t)(S_MINECARTSEG_FRONT + i)); if (i >= 2) - seg->extravalue1 = (i == 2) ? -18 : 18; + seg->extravalue1 = (i == 2) ? -20 : 20; else { seg->extravalue2 = (i == 0) ? 24 : -24; @@ -9709,6 +9716,16 @@ void P_MobjThinker(mobj_t *mobj) #undef DRAGONTURNSPEED } break; + case MT_MINUS: +#ifdef ROTSPRITE + { + if (P_IsObjectOnGround(mobj)) + mobj->rollangle = 0; + else + mobj->rollangle = R_PointToAngle2(0, 0, mobj->momz, (mobj->scale << 1) - min(abs(mobj->momz), mobj->scale << 1)); + } +#endif + break; case MT_SPINFIRE: if (mobj->flags & MF_NOGRAVITY) { @@ -11294,7 +11311,7 @@ void P_SpawnPlayer(INT32 playernum) mobj->radius = FixedMul(skins[p->skin].radius, mobj->scale); mobj->height = P_GetPlayerHeight(p); - if (!leveltime && ((maptol & TOL_NIGHTS) == TOL_NIGHTS) != (G_IsSpecialStage(gamemap))) // non-special NiGHTS stage or special non-NiGHTS stage + if (!leveltime && !p->spectator && ((maptol & TOL_NIGHTS) == TOL_NIGHTS) != (G_IsSpecialStage(gamemap))) // non-special NiGHTS stage or special non-NiGHTS stage { if (maptol & TOL_NIGHTS) { diff --git a/src/p_setup.c b/src/p_setup.c index 5c792c73c..2216334e7 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -2812,12 +2812,12 @@ boolean P_SetupLevel(boolean skipprecip) { // Don't include these in the fade! char tx[64]; - V_DrawSmallString(1, 191, V_ALLOWLOWERCASE|V_TRANSLUCENT, M_GetText("Speeding off to...")); + V_DrawSmallString(1, 191, V_ALLOWLOWERCASE|V_TRANSLUCENT|V_SNAPTOLEFT|V_SNAPTOBOTTOM, M_GetText("Speeding off to...")); snprintf(tx, 63, "%s%s%s", mapheaderinfo[gamemap-1]->lvlttl, (mapheaderinfo[gamemap-1]->levelflags & LF_NOZONE) ? "" : " Zone", (mapheaderinfo[gamemap-1]->actnum > 0) ? va(" %d",mapheaderinfo[gamemap-1]->actnum) : ""); - V_DrawSmallString(1, 195, V_ALLOWLOWERCASE|V_TRANSLUCENT, tx); + V_DrawSmallString(1, 195, V_ALLOWLOWERCASE|V_TRANSLUCENT|V_SNAPTOLEFT|V_SNAPTOBOTTOM, tx); I_UpdateNoVsync(); } diff --git a/src/p_spec.c b/src/p_spec.c index f814e89c6..605638bd3 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -2721,6 +2721,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) if (line->tag != 0) // Do special stuff only if a non-zero linedef tag is set { + // Play sounds from tagged sectors' origins. if (line->flags & ML_EFFECT5) // Repeat Midtexture { // Additionally play the sound from tagged sectors' soundorgs @@ -2732,31 +2733,45 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) S_StartSound(&sec->soundorg, sfxnum); } } - else if (mo) // A mobj must have triggered the executor + + // Play the sound without origin for anyone, as long as they're inside tagged areas. + else { - // Only trigger if mobj is touching the tag + UINT8 i = 0; + mobj_t* camobj = players[displayplayer].mo; ffloor_t *rover; boolean foundit = false; - for(rover = mo->subsector->sector->ffloors; rover; rover = rover->next) + for (i = 0; i < 2; camobj = players[secondarydisplayplayer].mo, i++) { - if (rover->master->frontsector->tag != line->tag) + if (!camobj) continue; - if (mo->z > P_GetSpecialTopZ(mo, sectors + rover->secnum, mo->subsector->sector)) - continue; + if (foundit || (camobj->subsector->sector->tag == line->tag)) + { + foundit = true; + break; + } - if (mo->z + mo->height < P_GetSpecialBottomZ(mo, sectors + rover->secnum, mo->subsector->sector)) - continue; + // Only trigger if mobj is touching the tag + for(rover = camobj->subsector->sector->ffloors; rover; rover = rover->next) + { + if (rover->master->frontsector->tag != line->tag) + continue; - foundit = true; + if (camobj->z > P_GetSpecialTopZ(camobj, sectors + rover->secnum, camobj->subsector->sector)) + continue; + + if (camobj->z + camobj->height < P_GetSpecialBottomZ(camobj, sectors + rover->secnum, camobj->subsector->sector)) + continue; + + foundit = true; + break; + } } - if (mo->subsector->sector->tag == line->tag) - foundit = true; - - if (!foundit) - return; + if (foundit) + S_StartSound(NULL, sfxnum); } } else diff --git a/src/p_tick.c b/src/p_tick.c index e02b11f49..237d6b593 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -481,6 +481,9 @@ static inline void P_DoSpecialStageStuff(void) tic_t oldnightstime = players[i].nightstime; countspheres += players[i].spheres; + if (!oldnightstime) + continue; + // If in water, deplete timer 6x as fast. if (players[i].mo->eflags & (MFE_TOUCHWATER|MFE_UNDERWATER) && !(players[i].powers[pw_shield] & SH_PROTECTWATER)) players[i].nightstime -= 5; @@ -506,12 +509,11 @@ static inline void P_DoSpecialStageStuff(void) { // Halt all the players for (i = 0; i < MAXPLAYERS; i++) - if (playeringame[i]) + if (playeringame[i] && !players[i].exiting) { players[i].mo->momx = players[i].mo->momy = 0; players[i].exiting = (14*TICRATE)/5 + 1; } - sstimer = 0; P_GiveEmerald(true); P_RestoreMusic(&players[consoleplayer]); diff --git a/src/p_user.c b/src/p_user.c index 0838ff80e..37f1a5ec5 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -343,13 +343,15 @@ void P_GiveEmerald(boolean spawnObj) continue; emmo = P_SpawnMobjFromMobj(players[i].mo, 0, 0, players[i].mo->height, MT_GOTEMERALD); + if (!emmo) + continue; P_SetTarget(&emmo->target, players[i].mo); P_SetMobjState(emmo, mobjinfo[MT_GOTEMERALD].meleestate + em); P_SetTarget(&players[i].mo->tracer, emmo); if (pnum == 255) { - i = pnum; + pnum = i; continue; } @@ -1223,6 +1225,7 @@ void P_GivePlayerSpheres(player_t *player, INT32 num_spheres) // void P_GivePlayerLives(player_t *player, INT32 numlives) { + UINT8 prevlives = player->lives; if (!player) return; @@ -1239,10 +1242,9 @@ void P_GivePlayerLives(player_t *player, INT32 numlives) if ((netgame || multiplayer) && gametype == GT_COOP && cv_cooplives.value == 0) { - UINT8 prevlives = player->lives; P_GivePlayerRings(player, 100*numlives); if (player->lives - prevlives >= numlives) - return; + goto docooprespawn; numlives = (numlives + prevlives - player->lives); } @@ -1256,6 +1258,15 @@ void P_GivePlayerLives(player_t *player, INT32 numlives) player->lives = 99; else if (player->lives < 1) player->lives = 1; + +docooprespawn: + if (cv_coopstarposts.value) + return; + if (prevlives > 0) + return; + if (!player->spectator) + return; + P_SpectatorJoinGame(player); } void P_GiveCoopLives(player_t *player, INT32 numlives, boolean sound) @@ -2153,6 +2164,10 @@ void P_DoPlayerFinish(player_t *player) if (netgame) CONS_Printf(M_GetText("%s has completed the level.\n"), player_names[player-players]); + + player->powers[pw_underwater] = 0; + player->powers[pw_spacetime] = 0; + P_RestoreMusic(player); } // @@ -2296,7 +2311,7 @@ boolean P_PlayerHitFloor(player_t *player, boolean dorollstuff) else if (!player->skidtime) player->pflags &= ~PF_GLIDING; } - else if (player->charability == CA_GLIDEANDCLIMB && player->pflags & PF_THOKKED && !(player->pflags & PF_SHIELDABILITY) && player->mo->state-states == S_PLAY_FALL) + else if (player->charability == CA_GLIDEANDCLIMB && player->pflags & PF_THOKKED && !(player->pflags & (PF_JUMPED|PF_SHIELDABILITY)) && player->mo->state-states == S_PLAY_FALL) { if (player->mo->state-states != S_PLAY_GLIDE_LANDING) { @@ -2872,7 +2887,7 @@ static void P_CheckUnderwaterAndSpaceTimer(player_t *player) { tic_t timeleft = (player->powers[pw_spacetime]) ? player->powers[pw_spacetime] : player->powers[pw_underwater]; - if (player->exiting) + if (player->exiting || (player->pflags & PF_FINISHED)) player->powers[pw_underwater] = player->powers[pw_spacetime] = 0; timeleft--; // The original code was all n*TICRATE + 1, so let's remove 1 tic for simplicity @@ -3523,7 +3538,7 @@ static void P_DoClimbing(player_t *player) { P_SetObjectMomZ(player->mo, 2*FRACUNIT, true); if (cmd->forwardmove) - P_SetObjectMomZ(player->mo, 2*player->mo->momz/3, false); + player->mo->momz = 2*player->mo->momz/3; } if (thrust) P_Thrust(player->mo, player->mo->angle, FixedMul(4*FRACUNIT, player->mo->scale)); // Lil' boost up. @@ -4613,6 +4628,13 @@ static void P_DoSpinAbility(player_t *player, ticcmd_t *cmd) // Revving else if ((cmd->buttons & BT_USE) && (player->pflags & PF_STARTDASH)) { + if (player->speed > 5*player->mo->scale) + { + player->pflags &= ~PF_STARTDASH; + P_SetPlayerMobjState(player->mo, S_PLAY_ROLL); + S_StartSound(player->mo, sfx_spin); + break; + } if (player->dashspeed < player->maxdash) { #define chargecalculation (6*(player->dashspeed - player->mindash))/(player->maxdash - player->mindash) @@ -4628,7 +4650,6 @@ static void P_DoSpinAbility(player_t *player, ticcmd_t *cmd) G_GhostAddRev(); } } - // If not moving up or down, and travelling faster than a speed of five while not holding // down the spin button and not spinning. // AKA Just go into a spin on the ground, you idiot. ;) @@ -4780,10 +4801,10 @@ static void P_DoSpinAbility(player_t *player, ticcmd_t *cmd) // Rolling normally if (onground && player->pflags & PF_SPINNING && !(player->pflags & PF_STARTDASH) - && player->speed < FixedMul(5*FRACUNIT,player->mo->scale) && canstand) + && player->speed < 5*player->mo->scale && canstand) { if (GETSECSPECIAL(player->mo->subsector->sector->special, 4) == 7 || (player->mo->ceilingz - player->mo->floorz < P_GetPlayerHeight(player))) - P_InstaThrust(player->mo, player->mo->angle, FixedMul(10*FRACUNIT, player->mo->scale)); + P_InstaThrust(player->mo, player->mo->angle, 10*player->mo->scale); else { player->skidtime = 0; @@ -5550,7 +5571,7 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd) else potentialmomz = ((player->speed < 10*player->mo->scale) ? (player->speed - 10*player->mo->scale)/5 - : 0); + : -1); // Should be 0, but made negative to ensure P_PlayerHitFloor runs upon touching ground if (P_MobjFlip(player->mo)*player->mo->momz < potentialmomz) player->mo->momz = P_MobjFlip(player->mo)*potentialmomz; player->pflags &= ~PF_SPINNING; @@ -5945,6 +5966,8 @@ static void P_3dMovement(player_t *player) // When sliding, don't allow forward/back if (player->pflags & PF_SLIDING) cmd->forwardmove = 0; + else if (onground && player->mo->state == states+S_PLAY_PAIN) + P_SetPlayerMobjState(player->mo, S_PLAY_WALK); player->aiming = cmd->aiming<deadtimer >= 8*TICRATE) { - INT32 i, deadtimercheck = INT32_MAX; // In a net/multiplayer game, and out of lives @@ -9652,14 +9674,24 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall mo = player->mo; + if (player->playerstate == PST_REBORN) + { + P_CalcChasePostImg(player, thiscam); + return true; + } + if (player->exiting) { - if (mo->target && mo->target->type == MT_SIGN && mo->target->spawnpoint) + if (mo->target && mo->target->type == MT_SIGN && mo->target->spawnpoint + && !(gametype == GT_COOP && (netgame || multiplayer) && cv_exitmove.value)) sign = mo->target; else if ((player->powers[pw_carry] == CR_NIGHTSMODE) && !(player->mo->state >= &states[S_PLAY_NIGHTS_TRANS1] && player->mo->state <= &states[S_PLAY_NIGHTS_TRANS6])) + { + P_CalcChasePostImg(player, thiscam); return true; + } } cameranoclip = (player->powers[pw_carry] == CR_NIGHTSMODE || player->pflags & PF_NOCLIP) || (mo->flags & (MF_NOCLIP|MF_NOCLIPHEIGHT)); // Noclipping player camera noclips too!! @@ -9740,7 +9772,7 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall camorbit = (!stricmp(cv_cam_orbit.defaultvalue, "off")) ? false : true; camrotate = atoi(cv_cam_rotate.defaultvalue); camdist = FixedMul((INT32)(atof(cv_cam_dist.defaultvalue) * FRACUNIT), mo->scale); - camheight = FixedMul((INT32)(atof(cv_cam_height.defaultvalue) * FRACUNIT), FixedMul(player->camerascale, mo->scale)); + camheight = FixedMul((INT32)(atof(cv_cam_height.defaultvalue) * FRACUNIT), mo->scale); } else if (thiscam == &camera) { @@ -9749,7 +9781,7 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall camorbit = cv_cam_orbit.value; camrotate = cv_cam_rotate.value; camdist = FixedMul(cv_cam_dist.value, mo->scale); - camheight = FixedMul(cv_cam_height.value, FixedMul(player->camerascale, mo->scale)); + camheight = FixedMul(cv_cam_height.value, mo->scale); } else // Camera 2 { @@ -9758,9 +9790,12 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall camorbit = cv_cam2_orbit.value; camrotate = cv_cam2_rotate.value; camdist = FixedMul(cv_cam2_dist.value, mo->scale); - camheight = FixedMul(cv_cam2_height.value, FixedMul(player->camerascale, mo->scale)); + camheight = FixedMul(cv_cam2_height.value, mo->scale); } + if (!(twodlevel || (mo->flags2 & MF2_TWOD)) && !(player->powers[pw_carry] == CR_NIGHTSMODE)) + camheight = FixedMul(camheight, player->camerascale); + #ifdef REDSANALOG if (P_AnalogMove(player) && (player->cmd.buttons & (BT_CAMLEFT|BT_CAMRIGHT)) == (BT_CAMLEFT|BT_CAMRIGHT)) { camstill = true; @@ -9871,9 +9906,10 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall dist <<= 1; } + if (!(twodlevel || (mo->flags2 & MF2_TWOD)) && !(player->powers[pw_carry] == CR_NIGHTSMODE)) + dist = FixedMul(dist, player->camerascale); - - checkdist = (dist = FixedMul(dist, player->camerascale)); + checkdist = dist; if (checkdist < 128*FRACUNIT) checkdist = 128*FRACUNIT; @@ -10396,6 +10432,7 @@ boolean P_SpectatorJoinGame(player_t *player) return false; } +// the below is first person only, if you're curious. check out P_CalcChasePostImg in p_mobj.c for chasecam static void P_CalcPostImg(player_t *player) { sector_t *sector = player->mo->subsector->sector; @@ -11470,7 +11507,7 @@ void P_PlayerThink(player_t *player) if (player->pflags & PF_FINISHED) { - if (cv_exitmove.value && !G_EnoughPlayersFinished()) + if ((gametype == GT_COOP && cv_exitmove.value) && !G_EnoughPlayersFinished()) player->exiting = 0; else P_DoPlayerExit(player); diff --git a/src/r_things.c b/src/r_things.c index c89d87bf4..9763648cd 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -1137,8 +1137,6 @@ static void R_ProjectSprite(mobj_t *thing) UINT32 rollangle = AngleFixed(arollangle)>>FRACBITS; #endif - fixed_t ang_scale = FRACUNIT; - // transform the origin point tr_x = thing->x - viewx; tr_y = thing->y - viewy; @@ -1223,8 +1221,6 @@ static void R_ProjectSprite(mobj_t *thing) if (sprframe->rotate != SRF_SINGLE || papersprite) { ang = R_PointToAngle (thing->x, thing->y) - (thing->player ? thing->player->drawangle : thing->angle); - if (papersprite) - ang_scale = abs(FINESINE(ang>>ANGLETOFINESHIFT)); } if (sprframe->rotate == SRF_SINGLE) @@ -1286,24 +1282,11 @@ static void R_ProjectSprite(mobj_t *thing) else offset = -spr_offset; offset = FixedMul(offset, this_scale); - tx += FixedMul(offset, ang_scale); - x1 = (centerxfrac + FixedMul (tx,xscale)) >>FRACBITS; - - // off the right side? - if (x1 > viewwidth) - return; - offset2 = FixedMul(spr_width, this_scale); - tx += FixedMul(offset2, ang_scale); - x2 = ((centerxfrac + FixedMul (tx,xscale)) >> FRACBITS) - (papersprite ? 2 : 1); - - // off the left side - if (x2 < 0) - return; if (papersprite) { - fixed_t yscale2, cosmul, sinmul, tz2; + fixed_t xscale2, yscale2, cosmul, sinmul, tz2; INT32 range; if (ang >= ANGLE_180) @@ -1323,6 +1306,16 @@ static void R_ProjectSprite(mobj_t *thing) yscale = FixedDiv(projectiony, tz); if (yscale < 64) return; // Fix some funky visuals + gxt = -FixedMul(tr_x, viewsin); + gyt = FixedMul(tr_y, viewcos); + tx = -(gyt + gxt); + xscale = FixedDiv(projection, tz); + x1 = (centerxfrac + FixedMul(tx,xscale))>>FRACBITS; + + // off the right side? + if (x1 > viewwidth) + return; + tr_x += FixedMul(offset2, cosmul); tr_y += FixedMul(offset2, sinmul); gxt = FixedMul(tr_x, viewcos); @@ -1331,15 +1324,25 @@ static void R_ProjectSprite(mobj_t *thing) yscale2 = FixedDiv(projectiony, tz2); if (yscale2 < 64) return; // ditto + gxt = -FixedMul(tr_x, viewsin); + gyt = FixedMul(tr_y, viewcos); + tx = -(gyt + gxt); + xscale2 = FixedDiv(projection, tz2); + x2 = (centerxfrac + FixedMul(tx,xscale2))>>FRACBITS; x2--; + + // off the left side + if (x2 < 0) + return; + if (max(tz, tz2) < FixedMul(MINZ, this_scale)) // non-papersprite clipping is handled earlier return; - if (x2 > x1) - range = (x2 - x1); - else + if ((range = x2 - x1) <= 0) range = 1; - scalestep = (yscale2 - yscale)/range ?: 1; + scalestep = (yscale2 - yscale)/range; + scalestep = scalestep ? scalestep : 1; + xscale = FixedDiv(range<>FRACBITS; - xscale = FixedMul(xscale, ang_scale); + // off the right side? + if (x1 > viewwidth) + return; + + tx += offset2; + x2 = ((centerxfrac + FixedMul(tx,xscale))>>FRACBITS); x2--; + + // off the left side + if (x2 < 0) + return; + } if ((thing->flags2 & MF2_LINKDRAW) && thing->tracer) // toast 16/09/16 (SYMMETRY) { diff --git a/src/s_sound.c b/src/s_sound.c index 8e4e7715d..2f88349f1 100644 --- a/src/s_sound.c +++ b/src/s_sound.c @@ -860,7 +860,6 @@ static INT32 actualmidimusicvolume; void S_UpdateSounds(void) { INT32 audible, cnum, volume, sep, pitch; - UINT8 i; channel_t *c; listener_t listener; @@ -1017,28 +1016,30 @@ void S_UpdateSounds(void) notinlevel: I_UpdateSound(); +} +void S_UpdateClosedCaptions(void) +{ + UINT8 i; + boolean gamestopped = (paused || P_AutoPause()); + for (i = 0; i < NUMCAPTIONS; i++) // update captions { - boolean gamestopped = (paused || P_AutoPause()); - for (i = 0; i < NUMCAPTIONS; i++) // update captions + if (!closedcaptions[i].s) + continue; + + if (i == 0 && (closedcaptions[0].s-S_sfx == sfx_None) && gamestopped) + continue; + + if (!(--closedcaptions[i].t)) { - if (!closedcaptions[i].s) - continue; - - if (i == 0 && (closedcaptions[0].s-S_sfx == sfx_None) && gamestopped) - continue; - - if (!(--closedcaptions[i].t)) - { - closedcaptions[i].c = NULL; - closedcaptions[i].s = NULL; - } - else if (closedcaptions[i].c && !I_SoundIsPlaying(closedcaptions[i].c->handle)) - { - closedcaptions[i].c = NULL; - if (closedcaptions[i].t > CAPTIONFADETICS) - closedcaptions[i].t = CAPTIONFADETICS; - } + closedcaptions[i].c = NULL; + closedcaptions[i].s = NULL; + } + else if (closedcaptions[i].c && !I_SoundIsPlaying(closedcaptions[i].c->handle)) + { + closedcaptions[i].c = NULL; + if (closedcaptions[i].t > CAPTIONFADETICS) + closedcaptions[i].t = CAPTIONFADETICS; } } } diff --git a/src/s_sound.h b/src/s_sound.h index d1551df0b..f9bbf6767 100644 --- a/src/s_sound.h +++ b/src/s_sound.h @@ -303,6 +303,7 @@ boolean S_FadeOutStopMusic(UINT32 ms); // Updates music & sounds // void S_UpdateSounds(void); +void S_UpdateClosedCaptions(void); FUNCMATH fixed_t S_CalculateSoundDistance(fixed_t px1, fixed_t py1, fixed_t pz1, fixed_t px2, fixed_t py2, fixed_t pz2); diff --git a/src/sounds.c b/src/sounds.c index ba2402eb9..596ed74f2 100644 --- a/src/sounds.c +++ b/src/sounds.c @@ -92,7 +92,7 @@ sfxinfo_t S_sfx[NUMSFX] = {"pstop", false, 100, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Crusher stomp"}, {"steam1", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Steam jet"}, // Tails 06-19-2001 {"steam2", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Steam jet"}, // Tails 06-19-2001 - {"wbreak", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Wood breaking"}, + {"wbreak", true, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Wood breaking"}, {"ambmac", false, 60, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Machinery"}, {"spsmsh", false, 60, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Heavy impact"}, @@ -208,7 +208,7 @@ sfxinfo_t S_sfx[NUMSFX] = {"shrpsp", true, 60, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Spincushion"}, {"shrpgo", false, 60, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Launch"}, {"mswarp", false, 60, 16, -1, NULL, 0, -1, -1, LUMPERROR, "Spinning out"}, - {"mspogo", false, 60, 8, -1, NULL, 0, -1, -1, LUMPERROR, "Breaking through"}, + {"mspogo", true, 60, 8, -1, NULL, 0, -1, -1, LUMPERROR, "Breaking through"}, {"boingf", false, 60, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Bouncing"}, {"corkp", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Cork fired"}, {"corkh", false, 32, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Cork hit"}, diff --git a/src/st_stuff.c b/src/st_stuff.c index 6f75a25e7..8b3ceac9d 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -353,12 +353,12 @@ void ST_LoadGraphics(void) // made separate so that skins code can reload custom face graphics void ST_LoadFaceGraphics(INT32 skinnum) { - if (skins[skinnum].sprites[SPR2_XTRA].numframes) + if (skins[skinnum].sprites[SPR2_XTRA].numframes > XTRA_LIFEPIC) { spritedef_t *sprdef = &skins[skinnum].sprites[SPR2_XTRA]; spriteframe_t *sprframe = &sprdef->spriteframes[XTRA_LIFEPIC]; faceprefix[skinnum] = W_CachePatchNum(sprframe->lumppat[0], PU_HUDGFX); - if (skins[skinnum].sprites[(SPR2_XTRA|FF_SPR2SUPER)].numframes) + if (skins[skinnum].sprites[(SPR2_XTRA|FF_SPR2SUPER)].numframes > XTRA_LIFEPIC) { sprdef = &skins[skinnum].sprites[SPR2_XTRA|FF_SPR2SUPER]; sprframe = &sprdef->spriteframes[0]; diff --git a/src/v_video.c b/src/v_video.c index e92375630..5813a451b 100644 --- a/src/v_video.c +++ b/src/v_video.c @@ -1076,7 +1076,7 @@ void V_DrawCroppedPatch(fixed_t x, fixed_t y, fixed_t pscale, INT32 scrn, patch_ // void V_DrawContinueIcon(INT32 x, INT32 y, INT32 flags, INT32 skinnum, UINT8 skincolor) { - if (skinnum >= 0 && skinnum < numskins && skins[skinnum].sprites[SPR2_XTRA].numframes >= 4) + if (skinnum >= 0 && skinnum < numskins && skins[skinnum].sprites[SPR2_XTRA].numframes > XTRA_CONTINUE) { spritedef_t *sprdef = &skins[skinnum].sprites[SPR2_XTRA]; spriteframe_t *sprframe = &sprdef->spriteframes[XTRA_CONTINUE]; @@ -1902,14 +1902,15 @@ void V_DrawPromptBack(INT32 boxheight, INT32 color) { UINT8 *deststop, *buf; - boxheight = ((boxheight * 4) + (boxheight/2)*5); - if (color >= 256 && color < 512) { + boxheight = ((boxheight * 4) + (boxheight/2)*5); V_DrawFill((BASEVIDWIDTH-(vid.width/vid.dupx))/2, BASEVIDHEIGHT-boxheight, (vid.width/vid.dupx),boxheight, (color-256)|V_SNAPTOBOTTOM); return; } + boxheight *= vid.dupy; + if (color == INT32_MAX) color = cons_backcolor.value; @@ -1951,7 +1952,7 @@ void V_DrawPromptBack(INT32 boxheight, INT32 color) // heavily simplified -- we don't need to know x or y position, // just the start and stop positions deststop = screens[0] + vid.rowbytes * vid.height; - buf = deststop - vid.rowbytes * boxheight * vid.dupy; // 4 lines of space plus gaps between and some leeway + buf = deststop - vid.rowbytes * ((boxheight * 4) + (boxheight/2)*5); // 4 lines of space plus gaps between and some leeway for (; buf < deststop; ++buf) *buf = promptbgmap[*buf]; }