Merge branch 'master' into newintro

This commit is contained in:
lachwright 2019-11-30 12:30:12 +08:00
commit d88eef3e95
30 changed files with 573 additions and 396 deletions

View file

@ -3,6 +3,7 @@
For Sonic Robo Blast 2 Version 2.2 For Sonic Robo Blast 2 Version 2.2
Contributors (alphabetical): Contributors (alphabetical):
* Foxboy * Foxboy
* FuriousFox
* JJames19119 * JJames19119
* Kalaron * Kalaron
* Kristos * Kristos
@ -44,27 +45,32 @@ formatinterface = "SRB2MapSetIO";
//Sky textures for vanilla maps //Sky textures for vanilla maps
defaultskytextures 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"; SKY1 = "MAP01,MAP02,MAP03,MAP33,MAP50,MAP60,MAPF0,MAPM0";
SKY4 = "MAP04,MAP06,MAP51,MAPF8,MAPM1"; SKY2 = "MAPM7,MAPMB";
SKY6 = "MAP05"; SKY4 = "MAP04,MAP06,MAP61,MAPF6,MAPM1";
SKY7 = "MAP07,MAP08,MAP09,MAP52,MAPM2,MAPM5"; SKY6 = "MAP05,MAP51,MAPMA";
SKY10 = "MAP12,MAP53,MAPM3"; SKY7 = "MAPM2,MAPM5";
SKY11 = "MAP10,MAP11,MAP16,MAP55,MAPF2,MAPF5,MAPF6,MAPF9,MAPM7"; SKY8 = "MAP07,MAP08,MAP09,MAP52,MAP62,MAPF1";
SKY13 = "MAP13,MAP54,MAPAS"; SKY10 = "MAP10,MAP12,MAP53,MAP63,MAPM3";
SKY21 = "MAPAF,MAPF7,MAPM4"; SKY11 = "MAP11,MAPF7";
SKY22 = "MAP22,MAP23,MAP24,MAP25,MAP56,MAPAN,MAPAO,MAPF4,MAPM6"; SKY13 = "MAP13,MAP64";
SKY29 = "MAP58,MAPAV"; 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"; SKY30 = "MAP30";
SKY35 = "MAP41"; SKY31 = "MAP31";
SKY40 = "MAP40"; SKY35 = "MAP42";
SKY55 = "MAPF3,MAPM9"; SKY40 = "MAP41,MAP71,MAPM9";
SKY66 = "MAPAT"; SKY55 = "MAPF3,MAPM8";
SKY99 = "MAP57"; SKY68 = "MAPF8";
SKY103 = "MAPA3,MAPA4,MAPAU"; SKY99 = "MAP57,MAPZ0";
SKY107 = "MAPA7,MAPA8"; SKY159 = "MAP16";
SKY117 = "MAPAH,MAPAI"; SKY172 = "MAP40";
SKY127 = "MAPAR"; SKY300 = "MAP72";
SKY132 = "MAPAW"; SKY301 = "MAP73";
} }
// Default lump name for new map // Default lump name for new map
@ -90,9 +96,9 @@ skins
Sonic; Sonic;
Tails; Tails;
Knuckles; Knuckles;
Metalsonic;
Fang;
Amy; Amy;
Fang;
Metalsonic;
} }
// Gametypes // Gametypes
@ -3422,7 +3428,7 @@ thingtypes
121 121
{ {
title = "Minus"; title = "Minus";
sprite = "MNUSA1"; sprite = "MNUSA0";
width = 24; width = 24;
height = 32; height = 32;
} }
@ -3457,6 +3463,13 @@ thingtypes
height = 34; height = 34;
flags8text = "[8] Start on fire"; flags8text = "[8] Start on fire";
} }
137
{
title = "Dragonbomber";
sprite = "DRABA1";
width = 28;
height = 48;
}
105 105
{ {
title = "Jetty-Syn Bomber"; title = "Jetty-Syn Bomber";
@ -5726,6 +5739,24 @@ thingtypes
width = 24; width = 24;
height = 32; 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 dreamhill

View file

@ -135,7 +135,7 @@ static inline void B_BuildTailsTiccmd(mobj_t *sonic, mobj_t *tails, ticcmd_t *cm
// ******** // ********
// FLY MODE // FLY MODE
// spinmode check // spinmode check
if (spinmode) if (spinmode || player->exiting)
thinkfly = false; thinkfly = false;
else else
{ {

View file

@ -1633,7 +1633,7 @@ static void CL_LoadReceivedSavegame(void)
{ {
CONS_Printf(": %s", mapheaderinfo[gamemap-1]->lvlttl); CONS_Printf(": %s", mapheaderinfo[gamemap-1]->lvlttl);
if (!(mapheaderinfo[gamemap-1]->levelflags & LF_NOZONE)) if (!(mapheaderinfo[gamemap-1]->levelflags & LF_NOZONE))
CONS_Printf(M_GetText(" ZONE")); CONS_Printf(M_GetText(" Zone"));
if (actnum > 0) if (actnum > 0)
CONS_Printf(" %2d", actnum); CONS_Printf(" %2d", actnum);
} }

View file

@ -291,8 +291,11 @@ static void D_Display(void)
switch (gamestate) switch (gamestate)
{ {
case GS_TITLESCREEN: case GS_TITLESCREEN:
if (!titlemapinaction || !curbghide) {
F_TitleScreenDrawer(); F_TitleScreenDrawer();
break; break;
}
/* FALLTHRU */
case GS_LEVEL: case GS_LEVEL:
if (!gametic) if (!gametic)
break; break;
@ -363,11 +366,56 @@ static void D_Display(void)
// clean up border stuff // clean up border stuff
// see if the border needs to be initially drawn // 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 // 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) if (lastdraw)
{ {
@ -380,10 +428,15 @@ static void D_Display(void)
lastdraw = false; lastdraw = false;
} }
if (gamestate == GS_LEVEL)
{
ST_Drawer(); ST_Drawer();
F_TextPromptDrawer(); F_TextPromptDrawer();
HU_Drawer(); HU_Drawer();
} }
else
F_TitleScreenDrawer();
}
} }
// change gamma if needed // change gamma if needed
@ -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 // D_SRB2Loop
// ========================================================================= // =========================================================================
@ -664,6 +667,7 @@ void D_SRB2Loop(void)
// consoleplayer -> displayplayer (hear sounds from viewpoint) // consoleplayer -> displayplayer (hear sounds from viewpoint)
S_UpdateSounds(); // move positional sounds S_UpdateSounds(); // move positional sounds
S_UpdateClosedCaptions();
// check for media change, loop music.. // check for media change, loop music..
I_UpdateCD(); I_UpdateCD();
@ -729,6 +733,8 @@ void D_StartTitle(void)
for (i = 0; i < MAXPLAYERS; i++) for (i = 0; i < MAXPLAYERS; i++)
CL_ClearPlayer(i); CL_ClearPlayer(i);
players[consoleplayer].availabilities = players[1].availabilities = R_GetSkinAvailabilities(); // players[1] is supposed to be for 2p
splitscreen = false; splitscreen = false;
SplitScreen_OnChange(); SplitScreen_OnChange();
botingame = false; botingame = false;

View file

@ -54,7 +54,4 @@ const char *D_Home(void);
void D_AdvanceDemo(void); void D_AdvanceDemo(void);
void D_StartTitle(void); void D_StartTitle(void);
/* Here for title maps */
void D_Render(void);
#endif //__D_MAIN__ #endif //__D_MAIN__

View file

@ -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}; 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}}; 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}}; 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}; 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)) else if ((foundskin = R_SkinAvailable(cv_skin.string)) != -1 && R_SkinUsable(consoleplayer, foundskin))
{ {
boolean notsame; //boolean notsame;
cv_skin.value = foundskin; cv_skin.value = foundskin;
notsame = (cv_skin.value != players[consoleplayer].skin); //notsame = (cv_skin.value != players[consoleplayer].skin);
SetPlayerSkin(consoleplayer, cv_skin.string); SetPlayerSkin(consoleplayer, cv_skin.string);
CV_StealthSet(&cv_skin, skins[cv_skin.value].name); CV_StealthSet(&cv_skin, skins[cv_skin.value].name);
if (notsame) /*if (notsame)
{ {
CV_StealthSetValue(&cv_playercolor, skins[cv_skin.value].prefcolor); CV_StealthSetValue(&cv_playercolor, skins[cv_skin.value].prefcolor);
@ -1245,7 +1245,7 @@ static void SendNameAndColor(void)
if (players[consoleplayer].mo) if (players[consoleplayer].mo)
players[consoleplayer].mo->color = (UINT8)players[consoleplayer].skincolor; players[consoleplayer].mo->color = (UINT8)players[consoleplayer].skincolor;
} }*/
} }
else else
{ {
@ -1356,15 +1356,16 @@ static void SendNameAndColor2(void)
} }
else if ((foundskin = R_SkinAvailable(cv_skin2.string)) != -1 && R_SkinUsable(secondplaya, foundskin)) else if ((foundskin = R_SkinAvailable(cv_skin2.string)) != -1 && R_SkinUsable(secondplaya, foundskin))
{ {
boolean notsame; //boolean notsame;
cv_skin2.value = foundskin; cv_skin2.value = foundskin;
notsame = (cv_skin2.value != players[secondplaya].skin); //notsame = (cv_skin2.value != players[secondplaya].skin);
SetPlayerSkin(secondplaya, cv_skin2.string); 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); CV_StealthSetValue(&cv_playercolor2, skins[players[secondplaya].skin].prefcolor);
@ -1372,7 +1373,7 @@ static void SendNameAndColor2(void)
if (players[secondplaya].mo) if (players[secondplaya].mo)
players[secondplaya].mo->color = players[secondplaya].skincolor; players[secondplaya].mo->color = players[secondplaya].skincolor;
} }*/
} }
else else
{ {
@ -4289,6 +4290,8 @@ void Command_ExitGame_f(void)
for (i = 0; i < MAXPLAYERS; i++) for (i = 0; i < MAXPLAYERS; i++)
CL_ClearPlayer(i); CL_ClearPlayer(i);
players[consoleplayer].availabilities = players[1].availabilities = R_GetSkinAvailabilities(); // players[1] is supposed to be for 2p
splitscreen = false; splitscreen = false;
SplitScreen_OnChange(); SplitScreen_OnChange();
botingame = false; botingame = false;

View file

@ -3184,7 +3184,6 @@ static void readextraemblemdata(MYFILE *f, INT32 num)
// Now get the part after // Now get the part after
word2 = tmp += 2; word2 = tmp += 2;
strupr(word2);
value = atoi(word2); // used for numerical settings value = atoi(word2); // used for numerical settings
@ -3196,7 +3195,10 @@ static void readextraemblemdata(MYFILE *f, INT32 num)
sizeof (extraemblems[num-1].description), va("Extra emblem %d: objective", num)); sizeof (extraemblems[num-1].description), va("Extra emblem %d: objective", num));
else if (fastcmp(word, "CONDITIONSET")) else if (fastcmp(word, "CONDITIONSET"))
extraemblems[num-1].conditionset = (UINT8)value; extraemblems[num-1].conditionset = (UINT8)value;
else if (fastcmp(word, "SPRITE")) else
{
strupr(word2);
if (fastcmp(word, "SPRITE"))
{ {
if (word2[0] >= 'A' && word2[0] <= 'Z') if (word2[0] >= 'A' && word2[0] <= 'Z')
value = word2[0]; value = word2[0];
@ -3213,6 +3215,7 @@ static void readextraemblemdata(MYFILE *f, INT32 num)
else else
deh_warning("Extra emblem %d: unknown word '%s'", num, word); deh_warning("Extra emblem %d: unknown word '%s'", num, word);
} }
}
} while (!myfeof(f)); } while (!myfeof(f));
if (!extraemblems[num-1].sprite) if (!extraemblems[num-1].sprite)
@ -3262,7 +3265,6 @@ static void readunlockable(MYFILE *f, INT32 num)
// Now get the part after // Now get the part after
word2 = tmp += 2; word2 = tmp += 2;
strupr(word2);
i = atoi(word2); // used for numerical settings i = atoi(word2); // used for numerical settings
@ -3272,7 +3274,10 @@ static void readunlockable(MYFILE *f, INT32 num)
else if (fastcmp(word, "OBJECTIVE")) else if (fastcmp(word, "OBJECTIVE"))
deh_strlcpy(unlockables[num].objective, word2, deh_strlcpy(unlockables[num].objective, word2,
sizeof (unlockables[num].objective), va("Unlockable %d: objective", num)); sizeof (unlockables[num].objective), va("Unlockable %d: objective", num));
else if (fastcmp(word, "HEIGHT")) else
{
strupr(word2);
if (fastcmp(word, "HEIGHT"))
unlockables[num].height = (UINT16)i; unlockables[num].height = (UINT16)i;
else if (fastcmp(word, "CONDITIONSET")) else if (fastcmp(word, "CONDITIONSET"))
unlockables[num].conditionset = (UINT8)i; unlockables[num].conditionset = (UINT8)i;
@ -3321,6 +3326,7 @@ static void readunlockable(MYFILE *f, INT32 num)
else else
deh_warning("Unlockable %d: unknown word '%s'", num+1, word); deh_warning("Unlockable %d: unknown word '%s'", num+1, word);
} }
}
} while (!myfeof(f)); // finish when the line is empty } while (!myfeof(f)); // finish when the line is empty
Z_Free(s); Z_Free(s);
@ -4969,14 +4975,10 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
"S_MINUS_BURST4", "S_MINUS_BURST4",
"S_MINUS_BURST5", "S_MINUS_BURST5",
"S_MINUS_POPUP", "S_MINUS_POPUP",
"S_MINUS_UPWARD1", "S_MINUS_AERIAL1",
"S_MINUS_UPWARD2", "S_MINUS_AERIAL2",
"S_MINUS_UPWARD3", "S_MINUS_AERIAL3",
"S_MINUS_UPWARD4", "S_MINUS_AERIAL4",
"S_MINUS_DOWNWARD1",
"S_MINUS_DOWNWARD2",
"S_MINUS_DOWNWARD3",
"S_MINUS_DOWNWARD4",
// Minus dirt // Minus dirt
"S_MINUSDIRT1", "S_MINUSDIRT1",

View file

@ -1681,6 +1681,7 @@ void F_GameEvaluationTicker(void)
// ========== // ==========
#define INFLECTIONPOINT (6*TICRATE) #define INFLECTIONPOINT (6*TICRATE)
#define STOPPINGPOINT (14*TICRATE)
#define SPARKLLOOPTIME 15 // must be odd #define SPARKLLOOPTIME 15 // must be odd
void F_StartEnding(void) void F_StartEnding(void)
@ -1739,7 +1740,7 @@ void F_StartEnding(void)
UINT8 skinnum = players[consoleplayer].skin; UINT8 skinnum = players[consoleplayer].skin;
spritedef_t *sprdef; spritedef_t *sprdef;
spriteframe_t *sprframe; 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]; sprdef = &skins[skinnum].sprites[SPR2_XTRA];
// character head, skin specific // character head, skin specific
@ -1772,7 +1773,7 @@ void F_StartEnding(void)
void F_EndingTicker(void) void F_EndingTicker(void)
{ {
if (++finalecount > INFLECTIONPOINT*2) if (++finalecount > STOPPINGPOINT)
{ {
F_StartCredits(); F_StartCredits();
wipetypepre = INT16_MAX; wipetypepre = INT16_MAX;
@ -2168,26 +2169,26 @@ void F_EndingDrawer(void)
if (finalecount < 10) if (finalecount < 10)
trans = (10-finalecount)/2; 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; 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 //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<<V_ALPHASHIFT), str); V_DrawCenteredString(BASEVIDWIDTH/2, 8, V_ALLOWLOWERCASE|(trans<<V_ALPHASHIFT), str);
V_DrawCharacter(32, BASEVIDHEIGHT-16, '>'|(trans<<V_ALPHASHIFT), false); V_DrawCharacter(32, BASEVIDHEIGHT-16, '>'|(trans<<V_ALPHASHIFT), false);
V_DrawString(40, ((finalecount == (2*INFLECTIONPOINT)-(20+TICRATE)) ? 1 : 0)+BASEVIDHEIGHT-16, ((timesBeaten || finalecount >= (2*INFLECTIONPOINT)-TICRATE) ? V_PURPLEMAP : V_BLUEMAP)|(trans<<V_ALPHASHIFT), " [S] ===>"); V_DrawString(40, ((finalecount == STOPPINGPOINT-(20+TICRATE)) ? 1 : 0)+BASEVIDHEIGHT-16, ((timesBeaten || finalecount >= STOPPINGPOINT-TICRATE) ? V_PURPLEMAP : V_BLUEMAP)|(trans<<V_ALPHASHIFT), " [S] ===>");
} }
if (finalecount > (2*INFLECTIONPOINT)-(20+(2*TICRATE))) if (finalecount > STOPPINGPOINT-(20+(2*TICRATE)))
{ {
INT32 trans2 = abs((5*FINECOSINE((FixedAngle((finalecount*5)<<FRACBITS)>>ANGLETOFINESHIFT & FINEMASK)))>>FRACBITS)+2; INT32 trans2 = abs((5*FINECOSINE((FixedAngle((finalecount*5)<<FRACBITS)>>ANGLETOFINESHIFT & FINEMASK)))>>FRACBITS)+2;
if (!donttouch) if (!donttouch)
{ {
trans = 10 + ((2*INFLECTIONPOINT)-(20+(2*TICRATE))) - finalecount; trans = 10 + (STOPPINGPOINT-(20+(2*TICRATE))) - finalecount;
if (trans > trans2) if (trans > trans2)
trans2 = trans; trans2 = trans;
} }
@ -2644,9 +2645,7 @@ void F_TitleScreenDrawer(void)
// Draw that sky! // Draw that sky!
if (curbgcolor >= 0) if (curbgcolor >= 0)
V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, curbgcolor); V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, curbgcolor);
else if (titlemapinaction && curbghide && ! hidetitlemap) else if (!curbghide || !titlemapinaction || gamestate == GS_WAITINGPLAYERS)
D_Render();
else
F_SkyScroll(curbgxspeed, curbgyspeed, curbgname); F_SkyScroll(curbgxspeed, curbgyspeed, curbgname);
// Don't draw outside of the title screen, or if the patch isn't there. // 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) if (run)
finalecount++; finalecount++;
// don't trigger if doing anything besides idling on title
if (gameaction != ga_nothing || gamestate != GS_TITLESCREEN)
return;
// Execute the titlemap camera settings // Execute the titlemap camera settings
if (titlemapinaction) 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? // no demos to play? or, are they disabled?
if (!cv_rollingdemos.value || !numDemos) if (!cv_rollingdemos.value || !numDemos)
return; return;
@ -3608,7 +3607,7 @@ void F_ContinueDrawer(void)
if (timetonext >= (11*TICRATE)+10) if (timetonext >= (11*TICRATE)+10)
return; return;
V_DrawLevelTitle(x - (V_LevelNameWidth("CONTINUE")>>1), 16, 0, "CONTINUE"); V_DrawLevelTitle(x - (V_LevelNameWidth("Continue?")>>1), 16, 0, "Continue?");
// Two stars... // Two stars...
patch = W_CachePatchName("CONTSTAR", PU_CACHE); patch = W_CachePatchName("CONTSTAR", PU_CACHE);

View file

@ -1019,11 +1019,11 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics)
movebkey = PLAYER1INPUTDOWN(gc_backward); movebkey = PLAYER1INPUTDOWN(gc_backward);
mouseaiming = (PLAYER1INPUTDOWN(gc_mouseaiming)) ^ 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; analogjoystickmove = cv_usejoystick.value && !Joystick.bGamepadStyle;
gamepadjoystickmove = 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 // Reset the vertical look if we're no longer joyaiming
if (!thisjoyaiming && joyaiming) if (!thisjoyaiming && joyaiming)
@ -1348,11 +1348,11 @@ void G_BuildTiccmd2(ticcmd_t *cmd, INT32 realtics)
movebkey = PLAYER2INPUTDOWN(gc_backward); movebkey = PLAYER2INPUTDOWN(gc_backward);
mouseaiming = (PLAYER2INPUTDOWN(gc_mouseaiming)) ^ 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; analogjoystickmove = cv_usejoystick2.value && !Joystick2.bGamepadStyle;
gamepadjoystickmove = 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 // Reset the vertical look if we're no longer joyaiming
if (!thisjoyaiming && joyaiming) if (!thisjoyaiming && joyaiming)
@ -2323,6 +2323,9 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
outofcoop = players[player].outofcoop; outofcoop = players[player].outofcoop;
pflags = (players[player].pflags & (PF_FLIPCAM|PF_ANALOGMODE|PF_DIRECTIONCHAR|PF_AUTOBRAKE|PF_TAGIT|PF_GAMETYPEOVER)); 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 // As long as we're not in multiplayer, carry over cheatcodes from map to map
if (!(netgame || multiplayer)) if (!(netgame || multiplayer))
pflags |= (players[player].pflags & (PF_GODMODE|PF_NOCLIP|PF_INVIS)); 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)) if (G_GametypeUsesLives() || ((netgame || multiplayer) && gametype == GT_COOP))
p->lives = cv_startinglives.value; p->lives = cv_startinglives.value;
if (countplayers && !notexiting) if ((countplayers && !notexiting) || G_IsSpecialStage(gamemap))
P_DoPlayerExit(p); P_DoPlayerExit(p);
} }
@ -2997,7 +3000,7 @@ boolean G_EnoughPlayersFinished(void)
continue; continue;
total++; total++;
if (players[i].pflags & PF_FINISHED) if ((players[i].pflags & PF_FINISHED) || players[i].exiting)
exiting++; exiting++;
} }
@ -3099,7 +3102,7 @@ boolean G_GametypeUsesLives(void)
// Coop, Competitive // Coop, Competitive
if ((gametype == GT_COOP || gametype == GT_COMPETITION) if ((gametype == GT_COOP || gametype == GT_COMPETITION)
&& !(modeattacking || metalrecording) // No lives in Time Attack && !(modeattacking || metalrecording) // No lives in Time Attack
//&& !G_IsSpecialStage(gamemap) && !G_IsSpecialStage(gamemap)
&& !(maptol & TOL_NIGHTS)) // No lives in NiGHTS && !(maptol & TOL_NIGHTS)) // No lives in NiGHTS
return true; return true;
return false; return false;

View file

@ -771,18 +771,25 @@ void HWR_InitTextureCache(void)
gr_textures2 = NULL; gr_textures2 = NULL;
} }
// Callback function for HWR_FreeTextureCache. // Callback function for HWR_FreeTextureCache.
static void FreeMipmapColormap(INT32 patchnum, void *patch) static void FreeMipmapColormap(INT32 patchnum, void *patch)
{ {
GLPatch_t* const grpatch = patch; GLPatch_t* const pat = patch;
(void)patchnum; //unused (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; // Confusing at first, but pat->mipmap->nextcolormap
grpatch->mipmap->nextcolormap = grmip->nextcolormap; // at the beginning of the loop is the first colormap
if (grmip->grInfo.data) Z_Free(grmip->grInfo.data); // from the linked list of colormaps
free(grmip); 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 // 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++) for (i = 0; i < numwadfiles; i++)
M_AATreeIterate(wadfiles[i]->hwrcache, FreeMipmapColormap); M_AATreeIterate(wadfiles[i]->hwrcache, FreeMipmapColormap);

View file

@ -635,7 +635,7 @@ playersprite_t spr2defaults[NUMPLAYERSPRITES] = {
0, // SPR2_TRNS, 0, // SPR2_TRNS,
FF_SPR2SUPER|SPR2_STND, // SPR2_NSTD, 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) 0, // SPR2_NFLY, (will never be referenced unless skin 0 lacks this)
SPR2_NFLY, // SPR2_NDRL, SPR2_NFLY, // SPR2_NDRL,
FF_SPR2SUPER|SPR2_STUN, // SPR2_NSTN, 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, 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, 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_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, 3, 1, {A_MinusPopup}, 0, 0, S_MINUS_AERIAL1}, // S_MINUS_POPUP
{SPR_MNUS, 0, 1, {A_MinusCheck}, 0, 0, S_MINUS_UPWARD2}, // S_MINUS_UPWARD1 {SPR_MNUS, 0, 1, {A_MinusCheck}, 0, 1, S_MINUS_AERIAL2}, // S_MINUS_AERIAL1
{SPR_MNUS, 1, 1, {A_MinusCheck}, 0, 0, S_MINUS_UPWARD3}, // S_MINUS_UPWARD2 {SPR_MNUS, 1, 1, {A_MinusCheck}, 0, 1, S_MINUS_AERIAL3}, // S_MINUS_AERIAL2
{SPR_MNUS, 2, 1, {A_MinusCheck}, 0, 0, S_MINUS_UPWARD4}, // S_MINUS_UPWARD3 {SPR_MNUS, 2, 1, {A_MinusCheck}, 0, 1, S_MINUS_AERIAL4}, // S_MINUS_AERIAL3
{SPR_MNUS, 3, 1, {A_MinusCheck}, 0, 0, S_MINUS_UPWARD1}, // S_MINUS_UPWARD4 {SPR_MNUS, 3, 1, {A_MinusCheck}, 0, 1, S_MINUS_AERIAL1}, // S_MINUS_AERIAL4
{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_MNUD, FF_ANIMATE, 6, {NULL}, 1, 5, S_MINUSDIRT2}, // S_MINUSDIRT1 {SPR_MNUD, FF_ANIMATE, 6, {NULL}, 1, 5, S_MINUSDIRT2}, // S_MINUSDIRT1
{SPR_MNUD, 5, 8, {NULL}, 3, 5, S_MINUSDIRT3}, // S_MINUSDIRT2 {SPR_MNUD, 5, 8, {NULL}, 3, 5, S_MINUSDIRT3}, // S_MINUSDIRT2
@ -13373,7 +13369,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
100, // mass 100, // mass
0, // damage 0, // damage
sfx_None, // activesound sfx_None, // activesound
MF_SPECIAL|MF_PAIN|MF_NOGRAVITY, // flags MF_SPECIAL|MF_PAIN|MF_NOGRAVITY|MF_FIRE, // flags
S_NULL // raisestate S_NULL // raisestate
}, },

View file

@ -1270,14 +1270,10 @@ typedef enum state
S_MINUS_BURST4, S_MINUS_BURST4,
S_MINUS_BURST5, S_MINUS_BURST5,
S_MINUS_POPUP, S_MINUS_POPUP,
S_MINUS_UPWARD1, S_MINUS_AERIAL1,
S_MINUS_UPWARD2, S_MINUS_AERIAL2,
S_MINUS_UPWARD3, S_MINUS_AERIAL3,
S_MINUS_UPWARD4, S_MINUS_AERIAL4,
S_MINUS_DOWNWARD1,
S_MINUS_DOWNWARD2,
S_MINUS_DOWNWARD3,
S_MINUS_DOWNWARD4,
// Minus dirt // Minus dirt
S_MINUSDIRT1, S_MINUSDIRT1,

View file

@ -284,6 +284,8 @@ void M_SilentUpdateUnlockablesAndEmblems(void)
continue; continue;
unlockables[i].unlocked = M_Achieved(unlockables[i].conditionset - 1); 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 // Emblem unlocking shit

View file

@ -6688,7 +6688,7 @@ static void M_DrawChecklist(void)
|| !unlockables[i].conditionset || unlockables[i].conditionset > MAXCONDITIONSETS) || !unlockables[i].conditionset || unlockables[i].conditionset > MAXCONDITIONSETS)
continue; 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++) for (j = i+1; j < MAXUNLOCKABLES; j++)
{ {
@ -8334,16 +8334,12 @@ static void M_SetupChoosePlayer(INT32 choice)
{ {
INT32 skinnum; INT32 skinnum;
UINT8 i; UINT8 i;
UINT8 firstvalid = 255; UINT8 firstvalid = 255, lastvalid = 255;
UINT8 lastvalid = 0;
boolean allowed = false; boolean allowed = false;
char *and; char *and;
(void)choice; (void)choice;
if (!(mapheaderinfo[startmap-1] if (!mapheaderinfo[startmap-1] || mapheaderinfo[startmap-1]->forcecharacter[0] == '\0')
&& (mapheaderinfo[startmap-1]->forcecharacter[0] != '\0'
|| (mapheaderinfo[startmap-1]->typeoflevel & TOL_NIGHTS)) // remove this later when everyone gets their own nights sprites, maybe
))
{ {
for (i = 0; i < 32; i++) // Handle charsels, availability, and unlocks. for (i = 0; i < 32; i++) // Handle charsels, availability, and unlocks.
{ {
@ -8353,6 +8349,8 @@ static void M_SetupChoosePlayer(INT32 choice)
if (and) if (and)
{ {
char firstskin[SKINNAMESIZE+1]; 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)); strncpy(firstskin, description[i].skinname, (and - description[i].skinname));
firstskin[(and - description[i].skinname)] = '\0'; firstskin[(and - description[i].skinname)] = '\0';
description[i].skinnum[0] = R_SkinAvailable(firstskin); description[i].skinnum[0] = R_SkinAvailable(firstskin);
@ -8381,7 +8379,7 @@ static void M_SetupChoosePlayer(INT32 choice)
if (!(description[i].picname[0])) 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]; spritedef_t *sprdef = &skins[skinnum].sprites[SPR2_XTRA];
spriteframe_t *sprframe = &sprdef->spriteframes[XTRA_CHARSEL]; spriteframe_t *sprframe = &sprdef->spriteframes[XTRA_CHARSEL];
@ -8406,17 +8404,16 @@ static void M_SetupChoosePlayer(INT32 choice)
} }
} }
if (firstvalid != 255) if (firstvalid == lastvalid) // We're being forced into a specific character, so might as well just skip it.
{ // 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.
{ {
M_ChoosePlayer(-1); M_ChoosePlayer(firstvalid);
return; 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); M_ChangeMenuMusic("_chsel", true);
/* the menus suck -James */ /* the menus suck -James */
@ -8743,7 +8740,7 @@ static void M_ChoosePlayer(INT32 choice)
UINT8 skinnum; UINT8 skinnum;
// skip this if forcecharacter or no characters available // skip this if forcecharacter or no characters available
if (choice == -1) if (choice == 255)
{ {
skinnum = botskin = 0; skinnum = botskin = 0;
botingame = false; botingame = false;
@ -8855,9 +8852,9 @@ static void M_DrawStatsMaps(int location)
M_DrawMapEmblems(mnum+1, 292, y); M_DrawMapEmblems(mnum+1, 292, y);
if (mapheaderinfo[mnum]->actnum != 0) 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 else
V_DrawString(20, y, V_YELLOWMAP, mapheaderinfo[mnum]->lvlttl); V_DrawString(20, y, V_YELLOWMAP|V_ALLOWLOWERCASE, mapheaderinfo[mnum]->lvlttl);
y += 8; y += 8;
@ -8901,7 +8898,7 @@ static void M_DrawStatsMaps(int location)
else else
V_DrawSmallScaledPatch(292, y, 0, W_CachePatchName("NEEDIT", PU_CACHE)); 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; y += 8;
@ -9112,7 +9109,7 @@ void M_DrawTimeAttackMenu(void)
// Character face! // 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]; spritedef_t *sprdef = &skins[cv_chooseskin.value-1].sprites[SPR2_XTRA];
spriteframe_t *sprframe = &sprdef->spriteframes[XTRA_CHARSEL]; spriteframe_t *sprframe = &sprdef->spriteframes[XTRA_CHARSEL];
@ -9388,6 +9385,7 @@ void M_DrawNightsAttackMenu(void)
{ {
emblem_t *em; emblem_t *em;
INT32 yHeight; INT32 yHeight;
INT32 xpos;
patch_t *PictureOfLevel; patch_t *PictureOfLevel;
lumpnum_t lumpnum; lumpnum_t lumpnum;
char beststr[40]; char beststr[40];
@ -9447,17 +9445,23 @@ void M_DrawNightsAttackMenu(void)
{ {
switch (em->type) switch (em->type)
{ {
case ET_NGRADE: yHeight = 48; break; case ET_NGRADE:
case ET_NTIME: yHeight = 68; break; xpos = 104+38;
yHeight = 48;
break;
case ET_NTIME:
xpos = 104+76;
yHeight = 68;
break;
default: default:
goto skipThisOne; goto skipThisOne;
} }
if (em->collected) 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)); R_GetTranslationColormap(TC_DEFAULT, M_GetEmblemColor(em), GTC_CACHE));
else 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: skipThisOne:
em = M_GetLevelEmblems(-1); em = M_GetLevelEmblems(-1);

View file

@ -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') if (gamestate == GS_LEVEL && mapheaderinfo[gamemap-1]->lvlttl[0] != '\0')
snprintf(lvlttltext, 48, "%s%s%s", snprintf(lvlttltext, 48, "%s%s%s",
mapheaderinfo[gamemap-1]->lvlttl, 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) : ""); (mapheaderinfo[gamemap-1]->actnum > 0) ? va(" %d",mapheaderinfo[gamemap-1]->actnum) : "");
else else
snprintf(lvlttltext, 48, "Unknown"); snprintf(lvlttltext, 48, "Unknown");

View file

@ -2476,12 +2476,8 @@ void A_VultureBlast(mobj_t *actor)
void A_VultureFly(mobj_t *actor) void A_VultureFly(mobj_t *actor)
{ {
fixed_t speedmax = 18*FRACUNIT; fixed_t speedmax = 18*FRACUNIT;
angle_t angledif = R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y) - actor->angle; angle_t angledif;
fixed_t dx = actor->target->x - actor->x; fixed_t dx, dy, dz, dxy, dm;
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;
mobj_t *dust; mobj_t *dust;
fixed_t momm; fixed_t momm;
@ -2490,6 +2486,18 @@ void A_VultureFly(mobj_t *actor)
return; return;
#endif #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) if (leveltime % 4 == 0)
S_StartSound(actor, actor->info->activesound); S_StartSound(actor, actor->info->activesound);
@ -5664,10 +5672,10 @@ void A_MinusPopup(mobj_t *actor)
S_StartSound(actor, sfx_s3k82); S_StartSound(actor, sfx_s3k82);
for (i = 1; i <= num; i++) 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); P_Thrust(rock, ani*i, FRACUNIT);
rock->momz = 3*FRACUNIT; P_SetObjectMomZ(rock, 3*FRACUNIT, false);
P_SetScale(rock, FRACUNIT/3); P_SetScale(rock, rock->scale/3);
} }
P_RadiusAttack(actor, actor, 2*actor->radius, 0); P_RadiusAttack(actor, actor, 2*actor->radius, 0);
if (actor->tracer) 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. // Description: If the minus hits the floor, dig back into the ground.
// //
// var1 = State to switch to (if 0, use seestate). // 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) void A_MinusCheck(mobj_t *actor)
{ {
INT32 locvar1 = var1; INT32 locvar1 = var1;
INT32 locvar2 = var2;
#ifdef HAVE_BLUA #ifdef HAVE_BLUA
if (LUA_CallAction("A_MinusCheck", actor)) 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); P_SetMobjState(actor, locvar1 ? (statenum_t)locvar1 : actor->info->seestate);
actor->flags = actor->info->flags; 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 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 if (!(actor->flags & MF_PUSHABLE)) // if being ridden, don't disappear
actor->fuse = 0; actor->fuse = 0;
else if (!actor->fuse && actor->movecount == 1) // otherwise if rock has moved, set its fuse else if (!actor->fuse && actor->movecount == 1) // otherwise if rock has moved, set its fuse

View file

@ -148,15 +148,19 @@ void P_ResetStarposts(void)
// //
boolean P_CanPickupItem(player_t *player, boolean weapon) boolean P_CanPickupItem(player_t *player, boolean weapon)
{ {
if (player->bot && weapon) if (!player->mo || player->mo->health <= 0)
return false; 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) if (player->powers[pw_flashing] > (flashingtics/4)*3 && player->powers[pw_flashing] < UINT16_MAX)
return false; return false;
if (player->mo && player->mo->health <= 0)
return false;
return true; 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)) 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()) && G_GametypeUsesLives())
{ {
target->player->lives -= 1; // Lose a life Tails 03-11-2000 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) if (flip)
momz *= -1; momz *= -1;
#define makechunk(angtweak, xmov, ymov) \ #define makechunk(angtweak, xmov, ymov) \
chunk = P_SpawnMobj(target->x, target->y, target->z, MT_SPIKE);\ chunk = P_SpawnMobjFromMobj(target, 0, 0, 0, MT_SPIKE);\
chunk->eflags |= flip;\
P_SetMobjState(chunk, target->info->xdeathstate);\ P_SetMobjState(chunk, target->info->xdeathstate);\
chunk->health = 0;\ chunk->health = 0;\
chunk->angle = angtweak;\ chunk->angle = angtweak;\
chunk->destscale = scale;\
P_SetScale(chunk, scale);\
P_UnsetThingPosition(chunk);\ P_UnsetThingPosition(chunk);\
chunk->flags = MF_NOCLIP;\ chunk->flags = MF_NOCLIP;\
chunk->x += xmov;\ chunk->x += xmov;\
@ -2839,14 +2840,10 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget
if (flip) if (flip)
momz *= -1; momz *= -1;
chunk = P_SpawnMobj(target->x, target->y, target->z, MT_SPIKE); chunk = P_SpawnMobjFromMobj(target, 0, 0, 0, MT_SPIKE);
chunk->eflags |= flip;
P_SetMobjState(chunk, target->info->deathstate); P_SetMobjState(chunk, target->info->deathstate);
chunk->health = 0; chunk->health = 0;
chunk->angle = ang + ANGLE_180; chunk->angle = ang + ANGLE_180;
chunk->destscale = scale;
P_SetScale(chunk, scale);
P_UnsetThingPosition(chunk); P_UnsetThingPosition(chunk);
chunk->flags = MF_NOCLIP; chunk->flags = MF_NOCLIP;
chunk->x -= xoffs; 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); sprflip = P_RandomChance(FRACUNIT/2);
#define makechunk(angtweak, xmov, ymov) \ #define makechunk(angtweak, xmov, ymov) \
chunk = P_SpawnMobj(target->x, target->y, target->z, MT_WALLSPIKE);\ chunk = P_SpawnMobjFromMobj(target, 0, 0, 0, MT_WALLSPIKE);\
chunk->eflags |= flip;\
P_SetMobjState(chunk, target->info->xdeathstate);\ P_SetMobjState(chunk, target->info->xdeathstate);\
chunk->health = 0;\ chunk->health = 0;\
chunk->angle = target->angle;\ chunk->angle = target->angle;\
chunk->destscale = scale;\
P_SetScale(chunk, scale);\
P_UnsetThingPosition(chunk);\ P_UnsetThingPosition(chunk);\
chunk->flags = MF_NOCLIP;\ chunk->flags = MF_NOCLIP;\
chunk->x += xmov - forwardxoffs;\ 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); sprflip = P_RandomChance(FRACUNIT/2);
chunk = P_SpawnMobj(target->x, target->y, target->z, MT_WALLSPIKE); chunk = P_SpawnMobjFromMobj(target, 0, 0, 0, MT_WALLSPIKE);
chunk->eflags |= flip;
P_SetMobjState(chunk, target->info->deathstate); P_SetMobjState(chunk, target->info->deathstate);
chunk->health = 0; chunk->health = 0;
chunk->angle = target->angle; chunk->angle = target->angle;
chunk->destscale = scale;
P_SetScale(chunk, scale);
P_UnsetThingPosition(chunk); P_UnsetThingPosition(chunk);
chunk->flags = MF_NOCLIP; chunk->flags = MF_NOCLIP;
chunk->x += forwardxoffs - xoffs; chunk->x += forwardxoffs - xoffs;

View file

@ -323,6 +323,7 @@ SINT8 P_MobjFlip(mobj_t *mobj);
fixed_t P_GetMobjGravity(mobj_t *mo); fixed_t P_GetMobjGravity(mobj_t *mo);
FUNCMATH boolean P_WeaponOrPanel(mobjtype_t type); 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); boolean P_CameraThinker(player_t *player, camera_t *thiscam, boolean resetcalled);
void P_Attract(mobj_t *source, mobj_t *enemy, boolean nightsgrab); void P_Attract(mobj_t *source, mobj_t *enemy, boolean nightsgrab);

View file

@ -784,12 +784,12 @@ static boolean PIT_CheckThing(mobj_t *thing)
if (thing->type == MT_SPIKE if (thing->type == MT_SPIKE
|| thing->type == MT_WALLSPIKE) || thing->type == MT_WALLSPIKE)
{ {
mobjtype_t type = thing->type; mobj_t *iter;
if (thing->flags & MF_SOLID) if (thing->flags & MF_SOLID)
S_StartSound(tmthing, thing->info->deathsound); S_StartSound(tmthing, thing->info->deathsound);
for (thing = thing->subsector->sector->thinglist; thing; thing = thing->snext) for (iter = thing->subsector->sector->thinglist; iter; iter = iter->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)) 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(thing, tmthing, tmthing, 0); P_KillMobj(iter, tmthing, tmthing, 0);
} }
else else
{ {
@ -823,12 +823,12 @@ static boolean PIT_CheckThing(mobj_t *thing)
if (thing->type == MT_SPIKE if (thing->type == MT_SPIKE
|| thing->type == MT_WALLSPIKE) || thing->type == MT_WALLSPIKE)
{ {
mobjtype_t type = thing->type; mobj_t *iter;
if (thing->flags & MF_SOLID) if (thing->flags & MF_SOLID)
S_StartSound(tmthing, thing->info->deathsound); S_StartSound(tmthing, thing->info->deathsound);
for (thing = thing->subsector->sector->thinglist; thing; thing = thing->snext) for (iter = thing->subsector->sector->thinglist; iter; iter = iter->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)) 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(thing, tmthing, tmthing, 0); P_KillMobj(iter, tmthing, tmthing, 0);
} }
else else
{ {
@ -1303,11 +1303,6 @@ static boolean PIT_CheckThing(mobj_t *thing)
return false; 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 // damage / explode
if (tmthing->flags & MF_ENEMY) // An actual ENEMY! (Like the deton, for example) if (tmthing->flags & MF_ENEMY) // An actual ENEMY! (Like the deton, for example)
P_DamageMobj(thing, tmthing, tmthing, 1, 0); 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); 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 // don't traverse any more
if (tmthing->type == MT_SHELL) 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)) if ((tmthing->flags & MF_SPRING || tmthing->type == MT_STEAM || tmthing->type == MT_SPIKE || tmthing->type == MT_WALLSPIKE) && (thing->player))
; // springs and gas jets should never be able to step up onto a player ; // springs, gas jets and springs should never be able to step up onto a player
// z checking at last // z checking at last
// Treat noclip things as non-solid! // Treat noclip things as non-solid!
else if ((thing->flags & (MF_SOLID|MF_NOCLIP)) == MF_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.x = tmhitthing->x + cosradius;
v2.y = tmhitthing->y + sinradius; 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.v1 = &v1;
junk.v2 = &v2; junk.v2 = &v2;
junk.dx = 2*cosradius; // v2.x - v1.x; junk.dx = 2*cosradius; // v2.x - v1.x;

View file

@ -255,7 +255,6 @@ boolean P_SetPlayerMobjState(mobj_t *mobj, statenum_t state)
case S_PLAY_WALK: case S_PLAY_WALK:
case S_PLAY_SKID: case S_PLAY_SKID:
case S_PLAY_FLOAT: case S_PLAY_FLOAT:
case S_PLAY_NIGHTS_FLOAT:
player->panim = PA_WALK; player->panim = PA_WALK;
break; break;
case S_PLAY_RUN: case S_PLAY_RUN:
@ -281,6 +280,7 @@ boolean P_SetPlayerMobjState(mobj_t *mobj, statenum_t state)
player->panim = PA_SPRING; player->panim = PA_SPRING;
break; break;
case S_PLAY_FALL: case S_PLAY_FALL:
case S_PLAY_NIGHTS_FLOAT:
player->panim = PA_FALL; player->panim = PA_FALL;
break; break;
case S_PLAY_FLY: case S_PLAY_FLY:
@ -3408,7 +3408,7 @@ void P_MobjCheckWater(mobj_t *mobj)
// Drown timer setting // Drown timer setting
if ((p->powers[pw_shield] & SH_PROTECTWATER) // Has water protection 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 || (maptol & TOL_NIGHTS) // Or in NiGHTS mode
|| (mariomode)) // Or in Mario mode... || (mariomode)) // Or in Mario mode...
{ {
@ -3724,17 +3724,10 @@ void P_DestroyRobots(void)
} }
} }
// P_CameraThinker // 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)
// Process the mobj-ish required functions of the camera
boolean P_CameraThinker(player_t *player, camera_t *thiscam, boolean resetcalled)
{ {
boolean itsatwodlevel = false;
postimg_t postimg = postimg_none; 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) if (player->pflags & PF_FLIPCAM && !(player->powers[pw_carry] == CR_NIGHTSMODE) && player->mo->eflags & MFE_VERTICALFLIP)
postimg = postimg_flip; postimg = postimg_flip;
@ -3762,13 +3755,27 @@ boolean P_CameraThinker(player_t *player, camera_t *thiscam, boolean resetcalled
postimg = postimg_heat; postimg = postimg_heat;
} }
if (postimg != postimg_none) if (postimg == postimg_none)
{ return;
if (splitscreen && player == &players[secondarydisplayplayer]) if (splitscreen && player == &players[secondarydisplayplayer])
postimgtype2 = postimg; postimgtype2 = postimg;
else else
postimgtype = postimg; 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) 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); seg = P_SpawnMobj(x, y, z, MT_MINECARTSEG);
P_SetMobjState(seg, (statenum_t)(S_MINECARTSEG_FRONT + i)); P_SetMobjState(seg, (statenum_t)(S_MINECARTSEG_FRONT + i));
if (i >= 2) if (i >= 2)
seg->extravalue1 = (i == 2) ? -18 : 18; seg->extravalue1 = (i == 2) ? -20 : 20;
else else
{ {
seg->extravalue2 = (i == 0) ? 24 : -24; seg->extravalue2 = (i == 0) ? 24 : -24;
@ -9709,6 +9716,16 @@ void P_MobjThinker(mobj_t *mobj)
#undef DRAGONTURNSPEED #undef DRAGONTURNSPEED
} }
break; 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: case MT_SPINFIRE:
if (mobj->flags & MF_NOGRAVITY) if (mobj->flags & MF_NOGRAVITY)
{ {
@ -11294,7 +11311,7 @@ void P_SpawnPlayer(INT32 playernum)
mobj->radius = FixedMul(skins[p->skin].radius, mobj->scale); mobj->radius = FixedMul(skins[p->skin].radius, mobj->scale);
mobj->height = P_GetPlayerHeight(p); 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) if (maptol & TOL_NIGHTS)
{ {

View file

@ -2812,12 +2812,12 @@ boolean P_SetupLevel(boolean skipprecip)
{ {
// Don't include these in the fade! // Don't include these in the fade!
char tx[64]; 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", snprintf(tx, 63, "%s%s%s",
mapheaderinfo[gamemap-1]->lvlttl, 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) : ""); (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(); I_UpdateNoVsync();
} }

View file

@ -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 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 if (line->flags & ML_EFFECT5) // Repeat Midtexture
{ {
// Additionally play the sound from tagged sectors' soundorgs // 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); 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; ffloor_t *rover;
boolean foundit = false; boolean foundit = false;
for(rover = mo->subsector->sector->ffloors; rover; rover = rover->next) for (i = 0; i < 2; camobj = players[secondarydisplayplayer].mo, i++)
{
if (!camobj)
continue;
if (foundit || (camobj->subsector->sector->tag == line->tag))
{
foundit = true;
break;
}
// 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) if (rover->master->frontsector->tag != line->tag)
continue; continue;
if (mo->z > P_GetSpecialTopZ(mo, sectors + rover->secnum, mo->subsector->sector)) if (camobj->z > P_GetSpecialTopZ(camobj, sectors + rover->secnum, camobj->subsector->sector))
continue; continue;
if (mo->z + mo->height < P_GetSpecialBottomZ(mo, sectors + rover->secnum, mo->subsector->sector)) if (camobj->z + camobj->height < P_GetSpecialBottomZ(camobj, sectors + rover->secnum, camobj->subsector->sector))
continue; continue;
foundit = true; foundit = true;
break;
}
} }
if (mo->subsector->sector->tag == line->tag) if (foundit)
foundit = true; S_StartSound(NULL, sfxnum);
if (!foundit)
return;
} }
} }
else else

View file

@ -481,6 +481,9 @@ static inline void P_DoSpecialStageStuff(void)
tic_t oldnightstime = players[i].nightstime; tic_t oldnightstime = players[i].nightstime;
countspheres += players[i].spheres; countspheres += players[i].spheres;
if (!oldnightstime)
continue;
// If in water, deplete timer 6x as fast. // If in water, deplete timer 6x as fast.
if (players[i].mo->eflags & (MFE_TOUCHWATER|MFE_UNDERWATER) && !(players[i].powers[pw_shield] & SH_PROTECTWATER)) if (players[i].mo->eflags & (MFE_TOUCHWATER|MFE_UNDERWATER) && !(players[i].powers[pw_shield] & SH_PROTECTWATER))
players[i].nightstime -= 5; players[i].nightstime -= 5;
@ -506,12 +509,11 @@ static inline void P_DoSpecialStageStuff(void)
{ {
// Halt all the players // Halt all the players
for (i = 0; i < MAXPLAYERS; i++) 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].mo->momx = players[i].mo->momy = 0;
players[i].exiting = (14*TICRATE)/5 + 1; players[i].exiting = (14*TICRATE)/5 + 1;
} }
sstimer = 0; sstimer = 0;
P_GiveEmerald(true); P_GiveEmerald(true);
P_RestoreMusic(&players[consoleplayer]); P_RestoreMusic(&players[consoleplayer]);

View file

@ -343,13 +343,15 @@ void P_GiveEmerald(boolean spawnObj)
continue; continue;
emmo = P_SpawnMobjFromMobj(players[i].mo, 0, 0, players[i].mo->height, MT_GOTEMERALD); 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_SetTarget(&emmo->target, players[i].mo);
P_SetMobjState(emmo, mobjinfo[MT_GOTEMERALD].meleestate + em); P_SetMobjState(emmo, mobjinfo[MT_GOTEMERALD].meleestate + em);
P_SetTarget(&players[i].mo->tracer, emmo); P_SetTarget(&players[i].mo->tracer, emmo);
if (pnum == 255) if (pnum == 255)
{ {
i = pnum; pnum = i;
continue; continue;
} }
@ -1223,6 +1225,7 @@ void P_GivePlayerSpheres(player_t *player, INT32 num_spheres)
// //
void P_GivePlayerLives(player_t *player, INT32 numlives) void P_GivePlayerLives(player_t *player, INT32 numlives)
{ {
UINT8 prevlives = player->lives;
if (!player) if (!player)
return; return;
@ -1239,10 +1242,9 @@ void P_GivePlayerLives(player_t *player, INT32 numlives)
if ((netgame || multiplayer) && gametype == GT_COOP && cv_cooplives.value == 0) if ((netgame || multiplayer) && gametype == GT_COOP && cv_cooplives.value == 0)
{ {
UINT8 prevlives = player->lives;
P_GivePlayerRings(player, 100*numlives); P_GivePlayerRings(player, 100*numlives);
if (player->lives - prevlives >= numlives) if (player->lives - prevlives >= numlives)
return; goto docooprespawn;
numlives = (numlives + prevlives - player->lives); numlives = (numlives + prevlives - player->lives);
} }
@ -1256,6 +1258,15 @@ void P_GivePlayerLives(player_t *player, INT32 numlives)
player->lives = 99; player->lives = 99;
else if (player->lives < 1) else if (player->lives < 1)
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) void P_GiveCoopLives(player_t *player, INT32 numlives, boolean sound)
@ -2153,6 +2164,10 @@ void P_DoPlayerFinish(player_t *player)
if (netgame) if (netgame)
CONS_Printf(M_GetText("%s has completed the level.\n"), player_names[player-players]); 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) else if (!player->skidtime)
player->pflags &= ~PF_GLIDING; 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) 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]; 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; 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 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); P_SetObjectMomZ(player->mo, 2*FRACUNIT, true);
if (cmd->forwardmove) if (cmd->forwardmove)
P_SetObjectMomZ(player->mo, 2*player->mo->momz/3, false); player->mo->momz = 2*player->mo->momz/3;
} }
if (thrust) if (thrust)
P_Thrust(player->mo, player->mo->angle, FixedMul(4*FRACUNIT, player->mo->scale)); // Lil' boost up. 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 // Revving
else if ((cmd->buttons & BT_USE) && (player->pflags & PF_STARTDASH)) 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) if (player->dashspeed < player->maxdash)
{ {
#define chargecalculation (6*(player->dashspeed - player->mindash))/(player->maxdash - player->mindash) #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(); G_GhostAddRev();
} }
} }
// If not moving up or down, and travelling faster than a speed of five while not holding // If not moving up or down, and travelling faster than a speed of five while not holding
// down the spin button and not spinning. // down the spin button and not spinning.
// AKA Just go into a spin on the ground, you idiot. ;) // 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 // Rolling normally
if (onground && player->pflags & PF_SPINNING && !(player->pflags & PF_STARTDASH) 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))) 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 else
{ {
player->skidtime = 0; player->skidtime = 0;
@ -5550,7 +5571,7 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd)
else else
potentialmomz = ((player->speed < 10*player->mo->scale) potentialmomz = ((player->speed < 10*player->mo->scale)
? (player->speed - 10*player->mo->scale)/5 ? (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) if (P_MobjFlip(player->mo)*player->mo->momz < potentialmomz)
player->mo->momz = P_MobjFlip(player->mo)*potentialmomz; player->mo->momz = P_MobjFlip(player->mo)*potentialmomz;
player->pflags &= ~PF_SPINNING; player->pflags &= ~PF_SPINNING;
@ -5945,6 +5966,8 @@ static void P_3dMovement(player_t *player)
// When sliding, don't allow forward/back // When sliding, don't allow forward/back
if (player->pflags & PF_SLIDING) if (player->pflags & PF_SLIDING)
cmd->forwardmove = 0; cmd->forwardmove = 0;
else if (onground && player->mo->state == states+S_PLAY_PAIN)
P_SetPlayerMobjState(player->mo, S_PLAY_WALK);
player->aiming = cmd->aiming<<FRACBITS; player->aiming = cmd->aiming<<FRACBITS;
@ -9482,7 +9505,6 @@ static void P_DeathThink(player_t *player)
} }
else if ((netgame || multiplayer) && player->deadtimer >= 8*TICRATE) else if ((netgame || multiplayer) && player->deadtimer >= 8*TICRATE)
{ {
INT32 i, deadtimercheck = INT32_MAX; INT32 i, deadtimercheck = INT32_MAX;
// In a net/multiplayer game, and out of lives // In a net/multiplayer game, and out of lives
@ -9652,15 +9674,25 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall
mo = player->mo; mo = player->mo;
if (player->playerstate == PST_REBORN)
{
P_CalcChasePostImg(player, thiscam);
return true;
}
if (player->exiting) 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; sign = mo->target;
else if ((player->powers[pw_carry] == CR_NIGHTSMODE) else if ((player->powers[pw_carry] == CR_NIGHTSMODE)
&& !(player->mo->state >= &states[S_PLAY_NIGHTS_TRANS1] && !(player->mo->state >= &states[S_PLAY_NIGHTS_TRANS1]
&& player->mo->state <= &states[S_PLAY_NIGHTS_TRANS6])) && player->mo->state <= &states[S_PLAY_NIGHTS_TRANS6]))
{
P_CalcChasePostImg(player, thiscam);
return true; return true;
} }
}
cameranoclip = (player->powers[pw_carry] == CR_NIGHTSMODE || player->pflags & PF_NOCLIP) || (mo->flags & (MF_NOCLIP|MF_NOCLIPHEIGHT)); // Noclipping player camera noclips too!! 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; camorbit = (!stricmp(cv_cam_orbit.defaultvalue, "off")) ? false : true;
camrotate = atoi(cv_cam_rotate.defaultvalue); camrotate = atoi(cv_cam_rotate.defaultvalue);
camdist = FixedMul((INT32)(atof(cv_cam_dist.defaultvalue) * FRACUNIT), mo->scale); 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) else if (thiscam == &camera)
{ {
@ -9749,7 +9781,7 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall
camorbit = cv_cam_orbit.value; camorbit = cv_cam_orbit.value;
camrotate = cv_cam_rotate.value; camrotate = cv_cam_rotate.value;
camdist = FixedMul(cv_cam_dist.value, mo->scale); 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 else // Camera 2
{ {
@ -9758,9 +9790,12 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall
camorbit = cv_cam2_orbit.value; camorbit = cv_cam2_orbit.value;
camrotate = cv_cam2_rotate.value; camrotate = cv_cam2_rotate.value;
camdist = FixedMul(cv_cam2_dist.value, mo->scale); 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 #ifdef REDSANALOG
if (P_AnalogMove(player) && (player->cmd.buttons & (BT_CAMLEFT|BT_CAMRIGHT)) == (BT_CAMLEFT|BT_CAMRIGHT)) { if (P_AnalogMove(player) && (player->cmd.buttons & (BT_CAMLEFT|BT_CAMRIGHT)) == (BT_CAMLEFT|BT_CAMRIGHT)) {
camstill = true; camstill = true;
@ -9871,9 +9906,10 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall
dist <<= 1; dist <<= 1;
} }
if (!(twodlevel || (mo->flags2 & MF2_TWOD)) && !(player->powers[pw_carry] == CR_NIGHTSMODE))
dist = FixedMul(dist, player->camerascale);
checkdist = dist;
checkdist = (dist = FixedMul(dist, player->camerascale));
if (checkdist < 128*FRACUNIT) if (checkdist < 128*FRACUNIT)
checkdist = 128*FRACUNIT; checkdist = 128*FRACUNIT;
@ -10396,6 +10432,7 @@ boolean P_SpectatorJoinGame(player_t *player)
return false; 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) static void P_CalcPostImg(player_t *player)
{ {
sector_t *sector = player->mo->subsector->sector; sector_t *sector = player->mo->subsector->sector;
@ -11470,7 +11507,7 @@ void P_PlayerThink(player_t *player)
if (player->pflags & PF_FINISHED) if (player->pflags & PF_FINISHED)
{ {
if (cv_exitmove.value && !G_EnoughPlayersFinished()) if ((gametype == GT_COOP && cv_exitmove.value) && !G_EnoughPlayersFinished())
player->exiting = 0; player->exiting = 0;
else else
P_DoPlayerExit(player); P_DoPlayerExit(player);

View file

@ -1137,8 +1137,6 @@ static void R_ProjectSprite(mobj_t *thing)
UINT32 rollangle = AngleFixed(arollangle)>>FRACBITS; UINT32 rollangle = AngleFixed(arollangle)>>FRACBITS;
#endif #endif
fixed_t ang_scale = FRACUNIT;
// transform the origin point // transform the origin point
tr_x = thing->x - viewx; tr_x = thing->x - viewx;
tr_y = thing->y - viewy; tr_y = thing->y - viewy;
@ -1223,8 +1221,6 @@ static void R_ProjectSprite(mobj_t *thing)
if (sprframe->rotate != SRF_SINGLE || papersprite) if (sprframe->rotate != SRF_SINGLE || papersprite)
{ {
ang = R_PointToAngle (thing->x, thing->y) - (thing->player ? thing->player->drawangle : thing->angle); 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) if (sprframe->rotate == SRF_SINGLE)
@ -1286,24 +1282,11 @@ static void R_ProjectSprite(mobj_t *thing)
else else
offset = -spr_offset; offset = -spr_offset;
offset = FixedMul(offset, this_scale); 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); 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) if (papersprite)
{ {
fixed_t yscale2, cosmul, sinmul, tz2; fixed_t xscale2, yscale2, cosmul, sinmul, tz2;
INT32 range; INT32 range;
if (ang >= ANGLE_180) if (ang >= ANGLE_180)
@ -1323,6 +1306,16 @@ static void R_ProjectSprite(mobj_t *thing)
yscale = FixedDiv(projectiony, tz); yscale = FixedDiv(projectiony, tz);
if (yscale < 64) return; // Fix some funky visuals 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_x += FixedMul(offset2, cosmul);
tr_y += FixedMul(offset2, sinmul); tr_y += FixedMul(offset2, sinmul);
gxt = FixedMul(tr_x, viewcos); gxt = FixedMul(tr_x, viewcos);
@ -1331,15 +1324,25 @@ static void R_ProjectSprite(mobj_t *thing)
yscale2 = FixedDiv(projectiony, tz2); yscale2 = FixedDiv(projectiony, tz2);
if (yscale2 < 64) return; // ditto 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 if (max(tz, tz2) < FixedMul(MINZ, this_scale)) // non-papersprite clipping is handled earlier
return; return;
if (x2 > x1) if ((range = x2 - x1) <= 0)
range = (x2 - x1);
else
range = 1; range = 1;
scalestep = (yscale2 - yscale)/range ?: 1; scalestep = (yscale2 - yscale)/range;
scalestep = scalestep ? scalestep : 1;
xscale = FixedDiv(range<<FRACBITS, abs(offset2))+1;
// The following two are alternate sorting methods which might be more applicable in some circumstances. TODO - maybe enable via MF2? // The following two are alternate sorting methods which might be more applicable in some circumstances. TODO - maybe enable via MF2?
// sortscale = max(yscale, yscale2); // sortscale = max(yscale, yscale2);
@ -1349,9 +1352,20 @@ static void R_ProjectSprite(mobj_t *thing)
{ {
scalestep = 0; scalestep = 0;
yscale = sortscale; yscale = sortscale;
} tx += offset;
x1 = (centerxfrac + FixedMul(tx,xscale))>>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) if ((thing->flags2 & MF2_LINKDRAW) && thing->tracer) // toast 16/09/16 (SYMMETRY)
{ {

View file

@ -860,7 +860,6 @@ static INT32 actualmidimusicvolume;
void S_UpdateSounds(void) void S_UpdateSounds(void)
{ {
INT32 audible, cnum, volume, sep, pitch; INT32 audible, cnum, volume, sep, pitch;
UINT8 i;
channel_t *c; channel_t *c;
listener_t listener; listener_t listener;
@ -1017,8 +1016,11 @@ void S_UpdateSounds(void)
notinlevel: notinlevel:
I_UpdateSound(); I_UpdateSound();
}
{ void S_UpdateClosedCaptions(void)
{
UINT8 i;
boolean gamestopped = (paused || P_AutoPause()); boolean gamestopped = (paused || P_AutoPause());
for (i = 0; i < NUMCAPTIONS; i++) // update captions for (i = 0; i < NUMCAPTIONS; i++) // update captions
{ {
@ -1040,7 +1042,6 @@ notinlevel:
closedcaptions[i].t = CAPTIONFADETICS; closedcaptions[i].t = CAPTIONFADETICS;
} }
} }
}
} }
void S_SetSfxVolume(INT32 volume) void S_SetSfxVolume(INT32 volume)

View file

@ -303,6 +303,7 @@ boolean S_FadeOutStopMusic(UINT32 ms);
// Updates music & sounds // Updates music & sounds
// //
void S_UpdateSounds(void); 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); FUNCMATH fixed_t S_CalculateSoundDistance(fixed_t px1, fixed_t py1, fixed_t pz1, fixed_t px2, fixed_t py2, fixed_t pz2);

View file

@ -92,7 +92,7 @@ sfxinfo_t S_sfx[NUMSFX] =
{"pstop", false, 100, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Crusher stomp"}, {"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 {"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 {"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"}, {"ambmac", false, 60, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Machinery"},
{"spsmsh", false, 60, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Heavy impact"}, {"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"}, {"shrpsp", true, 60, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Spincushion"},
{"shrpgo", false, 60, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Launch"}, {"shrpgo", false, 60, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Launch"},
{"mswarp", false, 60, 16, -1, NULL, 0, -1, -1, LUMPERROR, "Spinning out"}, {"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"}, {"boingf", false, 60, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Bouncing"},
{"corkp", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Cork fired"}, {"corkp", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Cork fired"},
{"corkh", false, 32, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Cork hit"}, {"corkh", false, 32, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Cork hit"},

View file

@ -353,12 +353,12 @@ void ST_LoadGraphics(void)
// made separate so that skins code can reload custom face graphics // made separate so that skins code can reload custom face graphics
void ST_LoadFaceGraphics(INT32 skinnum) 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]; spritedef_t *sprdef = &skins[skinnum].sprites[SPR2_XTRA];
spriteframe_t *sprframe = &sprdef->spriteframes[XTRA_LIFEPIC]; spriteframe_t *sprframe = &sprdef->spriteframes[XTRA_LIFEPIC];
faceprefix[skinnum] = W_CachePatchNum(sprframe->lumppat[0], PU_HUDGFX); 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]; sprdef = &skins[skinnum].sprites[SPR2_XTRA|FF_SPR2SUPER];
sprframe = &sprdef->spriteframes[0]; sprframe = &sprdef->spriteframes[0];

View file

@ -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) 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]; spritedef_t *sprdef = &skins[skinnum].sprites[SPR2_XTRA];
spriteframe_t *sprframe = &sprdef->spriteframes[XTRA_CONTINUE]; spriteframe_t *sprframe = &sprdef->spriteframes[XTRA_CONTINUE];
@ -1902,14 +1902,15 @@ void V_DrawPromptBack(INT32 boxheight, INT32 color)
{ {
UINT8 *deststop, *buf; UINT8 *deststop, *buf;
boxheight = ((boxheight * 4) + (boxheight/2)*5);
if (color >= 256 && color < 512) 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); V_DrawFill((BASEVIDWIDTH-(vid.width/vid.dupx))/2, BASEVIDHEIGHT-boxheight, (vid.width/vid.dupx),boxheight, (color-256)|V_SNAPTOBOTTOM);
return; return;
} }
boxheight *= vid.dupy;
if (color == INT32_MAX) if (color == INT32_MAX)
color = cons_backcolor.value; 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, // heavily simplified -- we don't need to know x or y position,
// just the start and stop positions // just the start and stop positions
deststop = screens[0] + vid.rowbytes * vid.height; 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) for (; buf < deststop; ++buf)
*buf = promptbgmap[*buf]; *buf = promptbgmap[*buf];
} }