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
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

View File

@ -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
{

View File

@ -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);
}

View File

@ -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;

View File

@ -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__

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};
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;

View File

@ -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",

View File

@ -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<<V_ALPHASHIFT), str);
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;
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);

View File

@ -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;

View File

@ -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);

View File

@ -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
},

View File

@ -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,

View File

@ -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

View File

@ -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);

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')
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");

View File

@ -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

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -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)
{

View File

@ -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();
}

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
{
// 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

View File

@ -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]);

View File

@ -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<<FRACBITS;
@ -9482,7 +9505,6 @@ static void P_DeathThink(player_t *player)
}
else if ((netgame || multiplayer) && player->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);

View File

@ -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, abs(offset2))+1;
// The following two are alternate sorting methods which might be more applicable in some circumstances. TODO - maybe enable via MF2?
// sortscale = max(yscale, yscale2);
@ -1349,9 +1352,20 @@ static void R_ProjectSprite(mobj_t *thing)
{
scalestep = 0;
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)
{

View File

@ -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;
}
}
}

View File

@ -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);

View File

@ -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"},

View File

@ -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];

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)
{
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];
}