Merge branch 'ending' into 'master'

ENDINGS

See merge request STJr/SRB2Internal!264
This commit is contained in:
toaster 2019-08-03 16:23:51 -04:00
commit 8a0f1e7ed4
33 changed files with 1507 additions and 237 deletions

View File

@ -1608,7 +1608,7 @@ void CON_Drawer(void)
if (con_curlines > 0) if (con_curlines > 0)
CON_DrawConsole(); CON_DrawConsole();
else if (gamestate == GS_LEVEL else if (gamestate == GS_LEVEL
|| gamestate == GS_INTERMISSION || gamestate == GS_CUTSCENE || gamestate == GS_INTERMISSION || gamestate == GS_ENDING || gamestate == GS_CUTSCENE
|| gamestate == GS_CREDITS || gamestate == GS_EVALUATION) || gamestate == GS_CREDITS || gamestate == GS_EVALUATION)
CON_DrawHudlines(); CON_DrawHudlines();
} }

View File

@ -310,6 +310,12 @@ static void D_Display(void)
wipe = true; wipe = true;
break; break;
case GS_ENDING:
F_EndingDrawer();
HU_Erase();
HU_Drawer();
break;
case GS_CUTSCENE: case GS_CUTSCENE:
F_CutsceneDrawer(); F_CutsceneDrawer();
HU_Erase(); HU_Erase();

View File

@ -517,7 +517,9 @@ static void readfreeslots(MYFILE *f)
continue; continue;
// Copy in the spr2 name and increment free_spr2. // Copy in the spr2 name and increment free_spr2.
if (free_spr2 < NUMPLAYERSPRITES) { if (free_spr2 < NUMPLAYERSPRITES) {
CONS_Printf("Sprite SPR2_%s allocated.\n",word);
strncpy(spr2names[free_spr2],word,4); strncpy(spr2names[free_spr2],word,4);
spr2defaults[free_spr2] = 0;
spr2names[free_spr2++][4] = 0; spr2names[free_spr2++][4] = 0;
} else } else
CONS_Alert(CONS_WARNING, "Ran out of free SPR2 slots!\n"); CONS_Alert(CONS_WARNING, "Ran out of free SPR2 slots!\n");
@ -1108,6 +1110,7 @@ static void readlevelheader(MYFILE *f, INT32 num)
if (fastcmp(word2, "TITLE")) i = 1100; if (fastcmp(word2, "TITLE")) i = 1100;
else if (fastcmp(word2, "EVALUATION")) i = 1101; else if (fastcmp(word2, "EVALUATION")) i = 1101;
else if (fastcmp(word2, "CREDITS")) i = 1102; else if (fastcmp(word2, "CREDITS")) i = 1102;
else if (fastcmp(word2, "ENDING")) i = 1103;
else else
// Support using the actual map name, // Support using the actual map name,
// i.e., Nextlevel = AB, Nextlevel = FZ, etc. // i.e., Nextlevel = AB, Nextlevel = FZ, etc.
@ -9499,6 +9502,7 @@ static inline int lib_freeslot(lua_State *L)
{ {
CONS_Printf("Sprite SPR2_%s allocated.\n",word); CONS_Printf("Sprite SPR2_%s allocated.\n",word);
strncpy(spr2names[free_spr2],word,4); strncpy(spr2names[free_spr2],word,4);
spr2defaults[free_spr2] = 0;
spr2names[free_spr2++][4] = 0; spr2names[free_spr2++][4] = 0;
} else } else
CONS_Alert(CONS_WARNING, "Ran out of free SPR2 slots!\n"); CONS_Alert(CONS_WARNING, "Ran out of free SPR2 slots!\n");

View File

@ -234,7 +234,7 @@ extern textprompt_t *textprompts[MAX_PROMPTS];
// For the Custom Exit linedef. // For the Custom Exit linedef.
extern INT16 nextmapoverride; extern INT16 nextmapoverride;
extern boolean skipstats; extern UINT8 skipstats;
extern UINT32 ssspheres; // Total # of spheres in a level extern UINT32 ssspheres; // Total # of spheres in a level

View File

@ -14,6 +14,7 @@
#include "doomdef.h" #include "doomdef.h"
#include "doomstat.h" #include "doomstat.h"
#include "d_main.h" #include "d_main.h"
#include "d_netcmd.h"
#include "f_finale.h" #include "f_finale.h"
#include "g_game.h" #include "g_game.h"
#include "hu_stuff.h" #include "hu_stuff.h"
@ -36,6 +37,7 @@
#include "p_setup.h" #include "p_setup.h"
#include "st_stuff.h" // hud hiding #include "st_stuff.h" // hud hiding
#include "fastcmp.h" #include "fastcmp.h"
#include "console.h"
#ifdef HAVE_BLUA #ifdef HAVE_BLUA
#include "lua_hud.h" #include "lua_hud.h"
@ -53,7 +55,6 @@ static INT32 continuetime; // Short delay when continuing
static tic_t animtimer; // Used for some animation timings static tic_t animtimer; // Used for some animation timings
static INT16 skullAnimCounter; // Prompts: Chevron animation static INT16 skullAnimCounter; // Prompts: Chevron animation
static INT32 roidtics; // Asteroid spinning
static INT32 deplete; static INT32 deplete;
static tic_t stoptimer; static tic_t stoptimer;
@ -95,10 +96,22 @@ static patch_t *ttspop5;
static patch_t *ttspop6; static patch_t *ttspop6;
static patch_t *ttspop7; static patch_t *ttspop7;
static boolean goodending;
static patch_t *endbrdr[2]; // border - blue, white, pink - where have i seen those colours before?
static patch_t *endbgsp[3]; // nebula, sun, planet
static patch_t *endegrk[2]; // eggrock - replaced midway through good ending
static patch_t *endfwrk[3]; // firework - replaced with skin when good ending
static patch_t *endspkl[3]; // sparkle
static patch_t *endglow[2]; // glow aura - replaced with black rock's midway through good ending
static patch_t *endxpld[4]; // mini explosion
static patch_t *endescp[5]; // escape pod + flame
static INT32 sparkloffs[3][2]; // eggrock explosions/blackrock sparkles
static INT32 sparklloop;
// //
// PROMPT STATE // PROMPT STATE
// //
static boolean promptactive = false; boolean promptactive = false;
static mobj_t *promptmo; static mobj_t *promptmo;
static INT16 promptpostexectag; static INT16 promptpostexectag;
static boolean promptblockcontrols; static boolean promptblockcontrols;
@ -230,6 +243,7 @@ void F_StartCustomCutscene(INT32 cutscenenum, boolean precutscene, boolean reset
void F_StartIntro(void) void F_StartIntro(void)
{ {
S_StopMusic(); S_StopMusic();
S_StopSounds();
if (introtoplay) if (introtoplay)
{ {
@ -393,7 +407,6 @@ void F_StartIntro(void)
intro_scenenum = 0; intro_scenenum = 0;
finalecount = animtimer = skullAnimCounter = stoptimer = 0; finalecount = animtimer = skullAnimCounter = stoptimer = 0;
roidtics = BASEVIDWIDTH - 64;
timetonext = introscenetime[intro_scenenum]; timetonext = introscenetime[intro_scenenum];
} }
@ -676,11 +689,42 @@ static void F_IntroDrawScene(void)
if (intro_scenenum == 4) // The asteroid SPINS! if (intro_scenenum == 4) // The asteroid SPINS!
{ {
if (roidtics >= 0) if (intro_curtime > 1)
{ {
V_DrawScaledPatch(roidtics, 24, 0, INT32 worktics = intro_curtime - 1;
(patch = W_CachePatchName(va("ROID00%.2d", intro_curtime%35), PU_CACHE))); INT32 scale = FRACUNIT;
W_UnlockCachedPatch(patch); patch_t *rockpat;
UINT8 *colormap = NULL;
patch_t *glow;
INT32 trans = 0;
INT32 x = ((BASEVIDWIDTH - 64)<<FRACBITS) - ((intro_curtime*FRACUNIT)/3);
INT32 y = 24<<FRACBITS;
if (worktics < 5)
{
scale = (worktics<<(FRACBITS-2));
x += (30*(FRACUNIT-scale));
y += (30*(FRACUNIT-scale));
}
rockpat = W_CachePatchName(va("ROID00%.2d", 34 - (worktics % 35)), PU_LEVEL);
glow = W_CachePatchName(va("ENDGLOW%.1d", 2+(worktics & 1)), PU_LEVEL);
if (worktics >= 5)
trans = (worktics-5)>>1;
if (trans < 10)
V_DrawFixedPatch(x, y, scale, trans<<V_ALPHASHIFT, glow, NULL);
trans = (15-worktics);
if (trans < 0)
trans = -trans;
if (finalecount < 15)
colormap = R_GetTranslationColormap(TC_ALLWHITE, 0, GTC_CACHE);
V_DrawFixedPatch(x, y, scale, 0, rockpat, colormap);
if (trans < 10)
V_DrawFixedPatch(x, y, scale, trans<<V_ALPHASHIFT, rockpat, R_GetTranslationColormap(TC_BLINK, SKINCOLOR_AQUA, GTC_CACHE));
} }
} }
@ -702,7 +746,7 @@ static void F_IntroDrawScene(void)
W_UnlockCachedPatch(sgrass); W_UnlockCachedPatch(sgrass);
} }
V_DrawString(cx, cy, 0, cutscene_disptext); V_DrawString(cx, cy, V_ALLOWLOWERCASE, cutscene_disptext);
} }
// //
@ -724,8 +768,6 @@ void F_IntroDrawer(void)
S_ChangeMusicInternal("_intro", false); S_ChangeMusicInternal("_intro", false);
} }
else if (intro_scenenum == 3)
roidtics = BASEVIDWIDTH - 64;
else if (intro_scenenum == 10) else if (intro_scenenum == 10)
{ {
// The only fade to white in the entire damn game. // The only fade to white in the entire damn game.
@ -849,9 +891,6 @@ void F_IntroTicker(void)
// advance animation // advance animation
finalecount++; finalecount++;
if (finalecount % 3 == 0)
roidtics--;
timetonext--; timetonext--;
F_WriteText(); F_WriteText();
@ -947,6 +986,7 @@ static const char *credits[] = {
"\1Assistance", "\1Assistance",
"\"chi.miru\"", // helped port slope drawing code from ZDoom "\"chi.miru\"", // helped port slope drawing code from ZDoom
"Andrew \"orospakr\" Clunis", "Andrew \"orospakr\" Clunis",
"Sally \"TehRealSalt\" Cochenour",
"Gregor \"Oogaland\" Dick", "Gregor \"Oogaland\" Dick",
"Louis-Antoine \"LJSonic\" de Moulins", // for fixing 2.1's netcode (de Rochefort doesn't quite fit on the screen sorry lol) "Louis-Antoine \"LJSonic\" de Moulins", // for fixing 2.1's netcode (de Rochefort doesn't quite fit on the screen sorry lol)
"Victor \"Steel Titanium\" Fuentes", "Victor \"Steel Titanium\" Fuentes",
@ -966,8 +1006,9 @@ static const char *credits[] = {
// Everyone else is acknowledged under "Special Thanks > SRB2 Community Contributors". // Everyone else is acknowledged under "Special Thanks > SRB2 Community Contributors".
"", "",
"\1Sprite Artists", "\1Sprite Artists",
"Odi \"Iceman404\" Atunzu", "\"Iceman404\"",
"Victor \"VAdaPEGA\" Ara\x1Fjo", // Araújo -- sorry for our limited font! D: "Victor \"VAdaPEGA\" Ara\x1Fjo", // Araújo -- sorry for our limited font! D:
"Sally \"TehRealSalt\" Cochenour",
"Jim \"MotorRoach\" DeMello", "Jim \"MotorRoach\" DeMello",
"Desmond \"Blade\" DesJardins", "Desmond \"Blade\" DesJardins",
"Sherman \"CoatRack\" DesJardins", "Sherman \"CoatRack\" DesJardins",
@ -1049,7 +1090,10 @@ static const char *credits[] = {
"Simon \"sirjuddington\" Judd", // SLADE developer "Simon \"sirjuddington\" Judd", // SLADE developer
// Acknowledged here are the following: // Acknowledged here are the following:
// Minor merge request authors, see guideline above // Minor merge request authors, see guideline above
// Golden - Expanded thin font // - Golden - Expanded thin font
// Creators of small quantities of sprite/texture assets
// - Arietty - New Green Hill-styled textures
// - Scizor300 - the only other contributor to the 2.0 SRB2 Asset Pack
"SRB2 Community Contributors", "SRB2 Community Contributors",
"", "",
"\1Produced By", "\1Produced By",
@ -1103,6 +1147,7 @@ void F_StartCredits(void)
paused = false; paused = false;
CON_ToggleOff(); CON_ToggleOff();
S_StopMusic(); S_StopMusic();
S_StopSounds();
S_ChangeMusicInternal("_creds", false); S_ChangeMusicInternal("_creds", false);
@ -1221,7 +1266,7 @@ boolean F_CreditResponder(event_t *event)
break; break;
} }
if (!(timesBeaten) && !(netgame || multiplayer)) if (!(timesBeaten) && !(netgame || multiplayer) && !cv_debug)
return false; return false;
if (event->type != ev_keydown) if (event->type != ev_keydown)
@ -1240,10 +1285,8 @@ boolean F_CreditResponder(event_t *event)
// ============ // ============
// EVALUATION // EVALUATION
// ============ // ============
#define INTERVAL 50
#define TRANSLEVEL V_80TRANS #define SPARKLLOOPTIME 7 // must be odd
static INT32 eemeralds_start;
static boolean drawemblem = false, drawchaosemblem = false;
void F_StartGameEvaluation(void) void F_StartGameEvaluation(void)
{ {
@ -1265,76 +1308,122 @@ void F_StartGameEvaluation(void)
if ((!modifiedgame || savemoddata) && !(netgame || multiplayer) && cursaveslot > 0) if ((!modifiedgame || savemoddata) && !(netgame || multiplayer) && cursaveslot > 0)
G_SaveGame((UINT32)cursaveslot); G_SaveGame((UINT32)cursaveslot);
goodending = (ALL7EMERALDS(emeralds));
gameaction = ga_nothing; gameaction = ga_nothing;
paused = false; paused = false;
CON_ToggleOff(); CON_ToggleOff();
finalecount = 0; finalecount = -1;
sparklloop = 0;
} }
void F_GameEvaluationDrawer(void) void F_GameEvaluationDrawer(void)
{ {
INT32 x, y, i; INT32 x, y, i;
const fixed_t radius = 48*FRACUNIT;
angle_t fa; angle_t fa;
INT32 eemeralds_cur; INT32 eemeralds_cur;
char patchname[7] = "CEMGx0"; char patchname[7] = "CEMGx0";
const char* endingtext = (goodending ? "CONGRATULATIONS!" : "TRY AGAIN...");
V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31); V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31);
// Draw all the good crap here. // Draw all the good crap here.
if (ALL7EMERALDS(emeralds))
V_DrawString(114, 16, 0, "GOT THEM ALL!");
else
V_DrawString(124, 16, 0, "TRY AGAIN!");
eemeralds_start++; if (finalecount > 0)
eemeralds_cur = eemeralds_start;
for (i = 0; i < 7; ++i)
{ {
fa = (FixedAngle(eemeralds_cur*FRACUNIT)>>ANGLETOFINESHIFT) & FINEMASK; INT32 scale = FRACUNIT;
x = 160 + FixedInt(FixedMul(FINECOSINE(fa),radius)); patch_t *rockpat;
y = 100 + FixedInt(FixedMul(FINESINE(fa),radius)); UINT8 *colormap[2] = {NULL, NULL};
patch_t *glow;
INT32 trans = 0;
patchname[4] = 'A'+(char)i; x = (((BASEVIDWIDTH-82)/2)+11)<<FRACBITS;
if (emeralds & (1<<i)) y = (((BASEVIDHEIGHT-82)/2)+12)<<FRACBITS;
V_DrawScaledPatch(x, y, 0, W_CachePatchName(patchname, PU_CACHE));
else
V_DrawTranslucentPatch(x, y, TRANSLEVEL, W_CachePatchName(patchname, PU_CACHE));
eemeralds_cur += INTERVAL; if (finalecount < 5)
}
if (eemeralds_start >= 360)
eemeralds_start -= 360;
if (finalecount == 5*TICRATE)
{
if ((!modifiedgame || savemoddata) && !(netgame || multiplayer))
{ {
++timesBeaten; scale = (finalecount<<(FRACBITS-2));
x += (30*(FRACUNIT-scale));
y += (30*(FRACUNIT-scale));
}
if (ALL7EMERALDS(emeralds)) if (goodending)
++timesBeatenWithEmeralds; {
rockpat = W_CachePatchName(va("ROID00%.2d", 34 - (finalecount % 35)), PU_LEVEL);
glow = W_CachePatchName(va("ENDGLOW%.1d", 2+(finalecount & 1)), PU_LEVEL);
x -= FRACUNIT;
}
else
{
rockpat = W_CachePatchName("ROID0000", PU_LEVEL);
glow = W_CachePatchName(va("ENDGLOW%.1d", (finalecount & 1)), PU_LEVEL);
}
if (ultimatemode) if (finalecount >= 5)
++timesBeatenUltimate; trans = (finalecount-5)>>1;
if (trans < 10)
V_DrawFixedPatch(x, y, scale, trans<<V_ALPHASHIFT, glow, NULL);
if (M_UpdateUnlockablesAndExtraEmblems()) trans = (15-finalecount);
S_StartSound(NULL, sfx_s3k68); if (trans < 0)
trans = -trans;
G_SaveGameData(); if (finalecount < 15)
colormap[0] = R_GetTranslationColormap(TC_ALLWHITE, 0, GTC_CACHE);
V_DrawFixedPatch(x, y, scale, 0, rockpat, colormap[0]);
if (trans < 10)
{
colormap[1] = R_GetTranslationColormap(TC_BLINK, SKINCOLOR_AQUA, GTC_CACHE);
V_DrawFixedPatch(x, y, scale, trans<<V_ALPHASHIFT, rockpat, colormap[1]);
}
if (goodending)
{
INT32 j = (sparklloop & 1) ? 2 : 3;
if (j > (finalecount/SPARKLLOOPTIME))
j = (finalecount/SPARKLLOOPTIME);
while (j)
{
if (j > 1 || sparklloop >= 2)
{
// if j == 0 - alternate between 0 and 1
// 1 - 1 and 2
// 2 - 2 and not rendered
V_DrawFixedPatch(x+sparkloffs[j-1][0], y+sparkloffs[j-1][1], FRACUNIT, 0, W_CachePatchName(va("ENDSPKL%.1d", (j - ((sparklloop & 1) ? 0 : 1))), PU_LEVEL), R_GetTranslationColormap(TC_DEFAULT, SKINCOLOR_AQUA, GTC_CACHE));
}
j--;
}
}
else
{
patch_t *eggrock = W_CachePatchName("ENDEGRK5", PU_LEVEL);
V_DrawFixedPatch(x, y, scale, 0, eggrock, colormap[0]);
if (trans < 10)
V_DrawFixedPatch(x, y, scale, trans<<V_ALPHASHIFT, eggrock, colormap[1]);
else if (sparklloop)
V_DrawFixedPatch(x, y, scale, (10-sparklloop)<<V_ALPHASHIFT,
W_CachePatchName("ENDEGRK0", PU_LEVEL), colormap[1]);
} }
} }
eemeralds_cur = (finalecount % 360)<<FRACBITS;
for (i = 0; i < 7; ++i)
{
fa = (FixedAngle(eemeralds_cur)>>ANGLETOFINESHIFT) & FINEMASK;
x = (BASEVIDWIDTH<<(FRACBITS-1)) + (60*FINECOSINE(fa));
y = ((BASEVIDHEIGHT+16)<<(FRACBITS-1)) + (60*FINESINE(fa));
eemeralds_cur += (360<<FRACBITS)/7;
patchname[4] = 'A'+(char)i;
V_DrawFixedPatch(x, y, FRACUNIT, ((emeralds & (1<<i)) ? 0 : V_80TRANS), W_CachePatchName(patchname, PU_LEVEL), NULL);
}
V_DrawCreditString((BASEVIDWIDTH - V_CreditStringWidth(endingtext))<<(FRACBITS-1), (BASEVIDHEIGHT-100)<<(FRACBITS-1), 0, endingtext);
#if 0 // the following looks like hot garbage the more unlockables we add, and we now have a lot of unlockables
if (finalecount >= 5*TICRATE) if (finalecount >= 5*TICRATE)
{ {
if (drawemblem)
V_DrawScaledPatch(120, 192, 0, W_CachePatchName("NWNGA0", PU_CACHE));
if (drawchaosemblem)
V_DrawScaledPatch(200, 192, 0, W_CachePatchName("NWNGA0", PU_CACHE));
V_DrawString(8, 16, V_YELLOWMAP, "Unlocked:"); V_DrawString(8, 16, V_YELLOWMAP, "Unlocked:");
if (!(netgame) && (!modifiedgame || savemoddata)) if (!(netgame) && (!modifiedgame || savemoddata))
@ -1357,16 +1446,603 @@ void F_GameEvaluationDrawer(void)
else else
V_DrawString(8, 96, V_YELLOWMAP, "Prizes not\nawarded in\nmodified games!"); V_DrawString(8, 96, V_YELLOWMAP, "Prizes not\nawarded in\nmodified games!");
} }
#endif
} }
void F_GameEvaluationTicker(void) void F_GameEvaluationTicker(void)
{ {
finalecount++; if (++finalecount > 10*TICRATE)
{
if (finalecount > 10*TICRATE)
F_StartGameEnd(); F_StartGameEnd();
return;
}
if (!goodending)
{
if (sparklloop)
sparklloop--;
if (finalecount == (5*TICRATE)/2
|| finalecount == (7*TICRATE)/2
|| finalecount == ((7*TICRATE)/2)+5)
{
S_StartSound(NULL, sfx_s3k5c);
sparklloop = 10;
}
}
else if (++sparklloop == SPARKLLOOPTIME) // time to roll the randomisation again
{
angle_t workingangle = FixedAngle((M_RandomKey(360))<<FRACBITS)>>ANGLETOFINESHIFT;
fixed_t workingradius = M_RandomKey(26);
sparkloffs[2][0] = sparkloffs[1][0];
sparkloffs[2][1] = sparkloffs[1][1];
sparkloffs[1][0] = sparkloffs[0][0];
sparkloffs[1][1] = sparkloffs[0][1];
sparkloffs[0][0] = (30<<FRACBITS) + workingradius*FINECOSINE(workingangle);
sparkloffs[0][1] = (30<<FRACBITS) + workingradius*FINESINE(workingangle);
sparklloop = 0;
}
if (finalecount == 5*TICRATE)
{
if (netgame || multiplayer) // modify this when we finally allow unlocking stuff in 2P
{
HU_SetCEchoFlags(V_YELLOWMAP|V_RETURN8);
HU_SetCEchoDuration(6);
HU_DoCEcho("\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\Prizes only awarded in singleplayer!");
S_StartSound(NULL, sfx_s3k68);
}
else if (!modifiedgame || savemoddata)
{
++timesBeaten;
if (ALL7EMERALDS(emeralds))
++timesBeatenWithEmeralds;
if (ultimatemode)
++timesBeatenUltimate;
if (M_UpdateUnlockablesAndExtraEmblems())
S_StartSound(NULL, sfx_s3k68);
G_SaveGameData();
}
else
{
HU_SetCEchoFlags(V_YELLOWMAP|V_RETURN8);
HU_SetCEchoDuration(6);
HU_DoCEcho("\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\Prizes not awarded in modified games!");
S_StartSound(NULL, sfx_s3k68);
}
}
} }
#undef SPARKLLOOPTIME
// ==========
// ENDING
// ==========
#define INFLECTIONPOINT (6*TICRATE)
#define SPARKLLOOPTIME 15 // must be odd
void F_StartEnding(void)
{
G_SetGamestate(GS_ENDING);
wipetypepost = INT16_MAX;
// Just in case they're open ... somehow
M_ClearMenus(true);
// Save before the credits sequence.
if ((!modifiedgame || savemoddata) && !(netgame || multiplayer) && cursaveslot > 0)
G_SaveGame((UINT32)cursaveslot);
gameaction = ga_nothing;
paused = false;
CON_ToggleOff();
S_StopMusic(); // todo: placeholder
S_StopSounds();
finalecount = -10; // what? this totally isn't a hack. why are you asking?
memset(sparkloffs, 0, sizeof(INT32)*3*2);
sparklloop = 0;
endbrdr[1] = W_CachePatchName("ENDBRDR1", PU_LEVEL);
endegrk[0] = W_CachePatchName("ENDEGRK0", PU_LEVEL);
endegrk[1] = W_CachePatchName("ENDEGRK1", PU_LEVEL);
endglow[0] = W_CachePatchName("ENDGLOW0", PU_LEVEL);
endglow[1] = W_CachePatchName("ENDGLOW1", PU_LEVEL);
endbgsp[0] = W_CachePatchName("ENDBGSP0", PU_LEVEL);
endbgsp[1] = W_CachePatchName("ENDBGSP1", PU_LEVEL);
endbgsp[2] = W_CachePatchName("ENDBGSP2", PU_LEVEL);
endspkl[0] = W_CachePatchName("ENDSPKL0", PU_LEVEL);
endspkl[1] = W_CachePatchName("ENDSPKL1", PU_LEVEL);
endspkl[2] = W_CachePatchName("ENDSPKL2", PU_LEVEL);
endxpld[0] = W_CachePatchName("ENDXPLD0", PU_LEVEL);
endxpld[1] = W_CachePatchName("ENDXPLD1", PU_LEVEL);
endxpld[2] = W_CachePatchName("ENDXPLD2", PU_LEVEL);
endxpld[3] = W_CachePatchName("ENDXPLD3", PU_LEVEL);
endescp[0] = W_CachePatchName("ENDESCP0", PU_LEVEL);
endescp[1] = W_CachePatchName("ENDESCP1", PU_LEVEL);
endescp[2] = W_CachePatchName("ENDESCP2", PU_LEVEL);
endescp[3] = W_CachePatchName("ENDESCP3", PU_LEVEL);
endescp[4] = W_CachePatchName("ENDESCP4", PU_LEVEL);
// so we only need to check once
if ((goodending = ALL7EMERALDS(emeralds)))
{
UINT8 skinnum = players[consoleplayer].skin;
spritedef_t *sprdef;
spriteframe_t *sprframe;
if (skins[skinnum].sprites[SPR2_XTRA].numframes >= 5)
{
sprdef = &skins[skinnum].sprites[SPR2_XTRA];
// character head, skin specific
sprframe = &sprdef->spriteframes[2];
endfwrk[0] = W_CachePatchNum(sprframe->lumppat[0], PU_LEVEL);
sprframe = &sprdef->spriteframes[3];
endfwrk[1] = W_CachePatchNum(sprframe->lumppat[0], PU_LEVEL);
sprframe = &sprdef->spriteframes[4];
endfwrk[2] = W_CachePatchNum(sprframe->lumppat[0], PU_LEVEL);
}
else // eh, yknow what? too lazy to put MISSINGs here. eggman wins if you don't give your character an ending firework display.
{
endfwrk[0] = W_CachePatchName("ENDFWRK0", PU_LEVEL);
endfwrk[1] = W_CachePatchName("ENDFWRK1", PU_LEVEL);
endfwrk[2] = W_CachePatchName("ENDFWRK2", PU_LEVEL);
}
endbrdr[0] = W_CachePatchName("ENDBRDR2", PU_LEVEL);
}
else
{
// eggman, skin nonspecific
endfwrk[0] = W_CachePatchName("ENDFWRK0", PU_LEVEL);
endfwrk[1] = W_CachePatchName("ENDFWRK1", PU_LEVEL);
endfwrk[2] = W_CachePatchName("ENDFWRK2", PU_LEVEL);
endbrdr[0] = W_CachePatchName("ENDBRDR0", PU_LEVEL);
}
}
void F_EndingTicker(void)
{
if (++finalecount > INFLECTIONPOINT*2)
{
F_StartCredits();
wipetypepre = INT16_MAX;
return;
}
if (goodending && finalecount == INFLECTIONPOINT) // time to swap some assets
{
endegrk[0] = W_CachePatchName("ENDEGRK2", PU_LEVEL);
endegrk[1] = W_CachePatchName("ENDEGRK3", PU_LEVEL);
endglow[0] = W_CachePatchName("ENDGLOW2", PU_LEVEL);
endglow[1] = W_CachePatchName("ENDGLOW3", PU_LEVEL);
endxpld[0] = W_CachePatchName("ENDEGRK4", PU_LEVEL);
}
if (++sparklloop == SPARKLLOOPTIME) // time to roll the randomisation again
{
angle_t workingangle = FixedAngle((M_RandomRange(-170, 80))<<FRACBITS)>>ANGLETOFINESHIFT;
fixed_t workingradius = M_RandomKey(26);
sparkloffs[0][0] = (30<<FRACBITS) + workingradius*FINECOSINE(workingangle);
sparkloffs[0][1] = (30<<FRACBITS) + workingradius*FINESINE(workingangle);
sparklloop = 0;
}
}
void F_EndingDrawer(void)
{
INT32 x, y, i, j, parallaxticker;
patch_t *rockpat;
if (!goodending || finalecount < INFLECTIONPOINT)
rockpat = W_CachePatchName("ROID0000", PU_LEVEL);
else
rockpat = W_CachePatchName(va("ROID00%.2d", 34 - ((finalecount - INFLECTIONPOINT) % 35)), PU_LEVEL);
V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31);
parallaxticker = finalecount - INFLECTIONPOINT;
x = -((parallaxticker*20)<<FRACBITS)/INFLECTIONPOINT;
y = ((parallaxticker*7)<<FRACBITS)/INFLECTIONPOINT;
i = (((BASEVIDWIDTH-82)/2)+11)<<FRACBITS;
j = (((BASEVIDHEIGHT-82)/2)+12)<<FRACBITS;
if (finalecount <= -10)
;
else if (finalecount < 0)
V_DrawFadeFill(24, 24, BASEVIDWIDTH-48, BASEVIDHEIGHT-48, 0, 0, 10+finalecount);
else if (finalecount <= 20)
{
V_DrawFill(24, 24, BASEVIDWIDTH-48, BASEVIDHEIGHT-48, 0);
if (finalecount && finalecount < 20)
{
INT32 trans = (10-finalecount);
if (trans < 0)
{
trans = -trans;
V_DrawScaledPatch(BASEVIDWIDTH/2, BASEVIDHEIGHT/2, 0, endbrdr[0]);
}
V_DrawScaledPatch(BASEVIDWIDTH/2, BASEVIDHEIGHT/2, trans<<V_ALPHASHIFT, endbrdr[1]);
}
else if (finalecount == 20)
V_DrawScaledPatch(BASEVIDWIDTH/2, BASEVIDHEIGHT/2, 0, endbrdr[0]);
}
else if (goodending && (parallaxticker == -2 || !parallaxticker))
{
V_DrawFill(24, 24, BASEVIDWIDTH-48, BASEVIDHEIGHT-48, 0);
V_DrawFixedPatch(x+i, y+j, FRACUNIT, 0, endegrk[0],
R_GetTranslationColormap(TC_BLINK, SKINCOLOR_BLACK, GTC_CACHE));
//V_DrawScaledPatch(BASEVIDWIDTH/2, BASEVIDHEIGHT/2, 0, endbrdr[1]);
}
else if (goodending && parallaxticker == -1)
{
V_DrawFixedPatch(x+i, y+j, FRACUNIT, 0, rockpat,
R_GetTranslationColormap(TC_ALLWHITE, 0, GTC_CACHE));
V_DrawScaledPatch(BASEVIDWIDTH/2, BASEVIDHEIGHT/2, 0, endbrdr[1]);
}
else
{
boolean doexplosions = false;
boolean borderstuff = false;
INT32 tweakx = 0, tweaky = 0;
if (parallaxticker < 75) // f background's supposed to be visible
{
V_DrawFixedPatch(-(x/10), -(y/10), FRACUNIT, 0, endbgsp[0], NULL); // nebula
V_DrawFixedPatch(-(x/5), -(y/5), FRACUNIT, 0, endbgsp[1], NULL); // sun
V_DrawFixedPatch( 0, -(y/2), FRACUNIT, 0, endbgsp[2], NULL); // planet
// player's escape pod
V_DrawFixedPatch((200<<FRACBITS)+(finalecount<<(FRACBITS-2)),
(100<<FRACBITS)+(finalecount<<(FRACBITS-2)),
FRACUNIT, 0, endescp[4], NULL);
if (parallaxticker > -19)
{
INT32 trans = (-parallaxticker)>>1;
if (trans < 0)
trans = 0;
V_DrawFixedPatch((200<<FRACBITS)+(finalecount<<(FRACBITS-2)),
(100<<FRACBITS)+(finalecount<<(FRACBITS-2)),
FRACUNIT, trans<<V_ALPHASHIFT, endescp[(finalecount/2)&3], NULL);
}
if (goodending && parallaxticker > 0) // gunchedrock
{
INT32 scale = FRACUNIT + ((parallaxticker-10)<<7);
INT32 trans = parallaxticker>>2;
UINT8 *colormap = R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_JET, GTC_CACHE);
if (parallaxticker < 10)
{
tweakx = parallaxticker<<FRACBITS;
tweaky = ((7*parallaxticker)<<(FRACBITS-2))/5;
}
else
{
tweakx = 10<<FRACBITS;
tweaky = 7<<(FRACBITS-1);
}
i += tweakx;
j -= tweaky;
x <<= 1;
y <<= 1;
// center detritrus
V_DrawFixedPatch(i-x, j-y, FRACUNIT, 0, endegrk[0], colormap);
if (trans < 10)
V_DrawFixedPatch(i-x, j-y, FRACUNIT, trans<<V_ALPHASHIFT, endegrk[0], NULL);
// ring detritrus
V_DrawFixedPatch((30*(FRACUNIT-scale))+i-(2*x), (30*(FRACUNIT-scale))+j-(2*y) - ((7<<FRACBITS)/2), scale, 0, endegrk[1], colormap);
if (trans < 10)
V_DrawFixedPatch((30*(FRACUNIT-scale))+i-(2*x), (30*(FRACUNIT-scale))+j-(2*y), scale, trans<<V_ALPHASHIFT, endegrk[1], NULL);
scale += ((parallaxticker-10)<<7);
// shard detritrus
V_DrawFixedPatch((30*(FRACUNIT-scale))+i-(x/2), (30*(FRACUNIT-scale))+j-(y/2) - ((7<<FRACBITS)/2), scale, 0, endxpld[0], colormap);
if (trans < 10)
V_DrawFixedPatch((30*(FRACUNIT-scale))+i-(x/2), (30*(FRACUNIT-scale))+j-(y/2), scale, trans<<V_ALPHASHIFT, endxpld[0], NULL);
}
}
else if (goodending)
{
tweakx = 10<<FRACBITS;
tweaky = 7<<(FRACBITS-1);
i += tweakx;
j += tweaky;
x <<= 1;
y <<= 1;
}
if (goodending && parallaxticker > 0)
{
i -= (3+(tweakx<<1));
j += tweaky<<2;
}
if (parallaxticker <= 70) // eggrock/blackrock
{
INT32 trans;
fixed_t scale = FRACUNIT;
UINT8 *colormap[2] = {NULL, NULL};
x += i;
y += j;
if (parallaxticker > 66)
{
scale = ((70 - parallaxticker)<<(FRACBITS-2));
x += (30*(FRACUNIT-scale));
y += (30*(FRACUNIT-scale));
}
else if ((parallaxticker > 60) || (goodending && parallaxticker > 0))
;
else
{
doexplosions = true;
if (!sparklloop)
{
x += ((sparkloffs[0][0] < 30<<FRACBITS) ? FRACUNIT : -FRACUNIT);
y += ((sparkloffs[0][1] < 30<<FRACBITS) ? FRACUNIT : -FRACUNIT);
}
}
if (goodending && finalecount > INFLECTIONPOINT)
parallaxticker -= 40;
if ((-parallaxticker/4) < 5)
{
trans = (-parallaxticker/4) + 5;
if (trans < 0)
trans = 0;
V_DrawFixedPatch(x, y, scale, trans<<V_ALPHASHIFT, endglow[(finalecount & 1) ? 0 : 1], NULL);
}
if (goodending && finalecount > INFLECTIONPOINT)
{
if (finalecount < INFLECTIONPOINT+10)
V_DrawFadeFill(24, 24, BASEVIDWIDTH-48, BASEVIDHEIGHT-48, 0, 0, INFLECTIONPOINT+10-finalecount);
parallaxticker -= 30;
}
if ((parallaxticker/2) > -15)
colormap[0] = R_GetTranslationColormap(TC_ALLWHITE, 0, GTC_CACHE);
V_DrawFixedPatch(x, y, scale, 0, rockpat, colormap[0]);
if ((parallaxticker/2) > -25)
{
trans = (parallaxticker/2) + 15;
if (trans < 0)
trans = -trans;
if (trans < 10)
V_DrawFixedPatch(x, y, scale, trans<<V_ALPHASHIFT, rockpat,
R_GetTranslationColormap(TC_BLINK, SKINCOLOR_AQUA, GTC_CACHE));
}
if (goodending && finalecount > INFLECTIONPOINT)
{
if (finalecount < INFLECTIONPOINT+10)
V_DrawFixedPatch(x, y, scale, (finalecount-INFLECTIONPOINT)<<V_ALPHASHIFT, rockpat,
R_GetTranslationColormap(TC_BLINK, SKINCOLOR_BLACK, GTC_CACHE));
}
else
{
if ((-parallaxticker/2) < -5)
colormap[1] = R_GetTranslationColormap(TC_ALLWHITE, 0, GTC_CACHE);
V_DrawFixedPatch(x, y, scale, 0, endegrk[0], colormap[1]);
if ((-parallaxticker/2) < 5)
{
trans = (-parallaxticker/2) + 5;
if (trans < 0)
trans = -trans;
if (trans < 10)
V_DrawFixedPatch(x, y, scale, trans<<V_ALPHASHIFT, endegrk[1], NULL);
}
}
}
else // firework
{
fixed_t scale = FRACUNIT;
INT32 frame;
UINT8 *colormap = NULL;
parallaxticker -= 70;
x += ((BASEVIDWIDTH-3)<<(FRACBITS-1)) - tweakx;
y += (BASEVIDHEIGHT<<(FRACBITS-1)) + tweaky;
borderstuff = true;
if (parallaxticker < 5)
{
scale = (parallaxticker<<FRACBITS)/4;
V_DrawFadeFill(24, 24, BASEVIDWIDTH-48, BASEVIDHEIGHT-48, 0, 31, parallaxticker*2);
}
else
scale += (parallaxticker-4)<<5;
if (goodending)
colormap = R_GetTranslationColormap(players[consoleplayer].skin, players[consoleplayer].skincolor, GTC_CACHE);
if ((frame = ((parallaxticker & 1) ? 1 : 0) + (parallaxticker/TICRATE)) < 3)
V_DrawFixedPatch(x, y, scale, 0, endfwrk[frame], colormap);
}
// explosions
if (sparklloop >= 3 && doexplosions)
{
INT32 boomtime = parallaxticker - sparklloop;
x = ((((BASEVIDWIDTH-82)/2)+11)<<FRACBITS) - ((boomtime*20)<<FRACBITS)/INFLECTIONPOINT;
y = ((((BASEVIDHEIGHT-82)/2)+12)<<FRACBITS) + ((boomtime*7)<<FRACBITS)/INFLECTIONPOINT;
V_DrawFixedPatch(x + sparkloffs[0][0], y + sparkloffs[0][1],
FRACUNIT, 0, endxpld[sparklloop/4], NULL);
}
// initial fade
if (finalecount < 30)
V_DrawFadeFill(24, 24, BASEVIDWIDTH-48, BASEVIDHEIGHT-48, 0, 0, 30-finalecount);
// border - only emeralds can exist outside it
{
INT32 trans = 0;
if (borderstuff)
trans = (10*parallaxticker)/(3*TICRATE);
if (trans < 10)
V_DrawScaledPatch(BASEVIDWIDTH/2, BASEVIDHEIGHT/2, trans<<V_ALPHASHIFT, endbrdr[0]);
if (borderstuff && parallaxticker < 11)
V_DrawScaledPatch(BASEVIDWIDTH/2, BASEVIDHEIGHT/2, (parallaxticker-1)<<V_ALPHASHIFT, endbrdr[1]);
else if (goodending && finalecount > INFLECTIONPOINT && finalecount < INFLECTIONPOINT+10)
V_DrawScaledPatch(BASEVIDWIDTH/2, BASEVIDHEIGHT/2, (finalecount-INFLECTIONPOINT)<<V_ALPHASHIFT, endbrdr[1]);
}
// emeralds and emerald accessories
if (goodending && finalecount >= TICRATE && finalecount < INFLECTIONPOINT)
{
INT32 workingtime = finalecount - TICRATE;
fixed_t radius = ((vid.width/vid.dupx)*(INFLECTIONPOINT - TICRATE - workingtime))/(INFLECTIONPOINT - TICRATE);
angle_t fa;
INT32 eemeralds_cur[4];
char patchname[7] = "CEMGx0";
radius <<= FRACBITS;
for (i = 0; i < 4; ++i)
{
if (i == 1)
workingtime -= sparklloop;
else if (i)
workingtime -= SPARKLLOOPTIME;
eemeralds_cur[i] = (workingtime % 360)<<FRACBITS;
}
// sparkles
for (i = 0; i < 7; ++i)
{
UINT8* colormap;
skincolors_t col = SKINCOLOR_GREEN;
switch (i)
{
case 1:
col = SKINCOLOR_MAGENTA;
break;
case 2:
col = SKINCOLOR_BLUE;
break;
case 3:
col = SKINCOLOR_SKY;
break;
case 4:
col = SKINCOLOR_ORANGE;
break;
case 5:
col = SKINCOLOR_RED;
break;
case 6:
col = SKINCOLOR_GREY;
default:
case 0:
break;
}
colormap = R_GetTranslationColormap(TC_DEFAULT, col, GTC_CACHE);
j = (sparklloop & 1) ? 2 : 3;
while (j)
{
fa = (FixedAngle(eemeralds_cur[j])>>ANGLETOFINESHIFT) & FINEMASK;
x = (BASEVIDWIDTH<<(FRACBITS-1)) + FixedMul(FINECOSINE(fa),radius);
y = (BASEVIDHEIGHT<<(FRACBITS-1)) + FixedMul(FINESINE(fa),radius);
eemeralds_cur[j] += (360<<FRACBITS)/7;
// if j == 0 - alternate between 0 and 1
// 1 - 1 and 2
// 2 - 2 and not rendered
V_DrawFixedPatch(x, y, FRACUNIT, 0, endspkl[(j - ((sparklloop & 1) ? 0 : 1))], colormap);
j--;
}
}
// ...then emeralds themselves
for (i = 0; i < 7; ++i)
{
fa = (FixedAngle(eemeralds_cur[0])>>ANGLETOFINESHIFT) & FINEMASK;
x = (BASEVIDWIDTH<<(FRACBITS-1)) + FixedMul(FINECOSINE(fa),radius);
y = ((BASEVIDHEIGHT+16)<<(FRACBITS-1)) + FixedMul(FINESINE(fa),radius);
eemeralds_cur[0] += (360<<FRACBITS)/7;
patchname[4] = 'A'+(char)i;
V_DrawFixedPatch(x, y, FRACUNIT, 0, W_CachePatchName(patchname, PU_LEVEL), NULL);
}
} // if (goodending...
} // (finalecount > 20)
// look, i make an ending for you last-minute, the least you could do is let me have this
if (cv_soundtest.value == 413)
{
INT32 trans = 0;
boolean donttouch = false;
const char *str;
if (goodending)
str = va("[S] %s: Engage.", skins[players[consoleplayer].skin].realname);
else
str = "[S] Eggman: Abscond.";
if (finalecount < 10)
trans = (10-finalecount)/2;
else if (finalecount > (2*INFLECTIONPOINT) - 20)
{
trans = 10 + (finalecount/2) - INFLECTIONPOINT;
donttouch = true;
}
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] ===>");
}
if (finalecount > (2*INFLECTIONPOINT)-(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;
if (trans > trans2)
trans2 = trans;
}
else
trans2 += 2*trans;
if (trans2 < 10)
V_DrawCharacter(26, BASEVIDHEIGHT-33, '\x1C'|(trans2<<V_ALPHASHIFT), false);
}
}
}
#undef SPARKLLOOPTIME
// ========== // ==========
// GAME END // GAME END
// ========== // ==========
@ -1378,6 +2054,7 @@ void F_StartGameEnd(void)
paused = false; paused = false;
CON_ToggleOff(); CON_ToggleOff();
S_StopMusic(); S_StopMusic();
S_StopSounds();
// In case menus are still up?!! // In case menus are still up?!!
M_ClearMenus(true); M_ClearMenus(true);
@ -1892,7 +2569,7 @@ boolean F_ContinueResponder(event_t *event)
keypressed = true; keypressed = true;
imcontinuing = true; imcontinuing = true;
continuetime = TICRATE; continuetime = TICRATE;
S_StartSound(0, sfx_itemup); S_StartSound(NULL, sfx_itemup);
return true; return true;
} }
@ -2004,6 +2681,7 @@ void F_StartCustomCutscene(INT32 cutscenenum, boolean precutscene, boolean reset
cutscenes[cutnum]->scene[scenenum].musswitchposition, 0, 0); cutscenes[cutnum]->scene[scenenum].musswitchposition, 0, 0);
else else
S_StopMusic(); S_StopMusic();
S_StopSounds();
} }
// //
@ -2044,7 +2722,7 @@ void F_CutsceneDrawer(void)
F_RunWipe(cutscenes[cutnum]->scene[scenenum].fadeoutid, true); F_RunWipe(cutscenes[cutnum]->scene[scenenum].fadeoutid, true);
} }
V_DrawString(textxpos, textypos, 0, cutscene_disptext); V_DrawString(textxpos, textypos, V_ALLOWLOWERCASE, cutscene_disptext);
} }
void F_CutsceneTicker(void) void F_CutsceneTicker(void)

View File

@ -46,6 +46,9 @@ void F_GameEvaluationDrawer(void);
void F_StartGameEvaluation(void); void F_StartGameEvaluation(void);
void F_GameEvaluationTicker(void); void F_GameEvaluationTicker(void);
void F_EndingTicker(void);
void F_EndingDrawer(void);
void F_CreditTicker(void); void F_CreditTicker(void);
void F_CreditDrawer(void); void F_CreditDrawer(void);
@ -63,6 +66,7 @@ boolean F_GetPromptHideHud(fixed_t y);
void F_StartGameEnd(void); void F_StartGameEnd(void);
void F_StartIntro(void); void F_StartIntro(void);
void F_StartTitleScreen(void); void F_StartTitleScreen(void);
void F_StartEnding(void);
void F_StartCredits(void); void F_StartCredits(void);
boolean F_ContinueResponder(event_t *event); boolean F_ContinueResponder(event_t *event);
@ -125,6 +129,7 @@ enum
wipe_evaluation_toblack, wipe_evaluation_toblack,
wipe_gameend_toblack, wipe_gameend_toblack,
wipe_intro_toblack, wipe_intro_toblack,
wipe_ending_toblack,
wipe_cutscene_toblack, wipe_cutscene_toblack,
// custom intermissions // custom intermissions
@ -141,15 +146,16 @@ enum
wipe_evaluation_final, wipe_evaluation_final,
wipe_gameend_final, wipe_gameend_final,
wipe_intro_final, wipe_intro_final,
wipe_ending_final,
wipe_cutscene_final, wipe_cutscene_final,
// custom intermissions // custom intermissions
wipe_specinter_final, wipe_specinter_final,
wipe_multinter_final, wipe_multinter_final,
NUMWIPEDEFS NUMWIPEDEFS,
WIPEFINALSHIFT = (wipe_level_final-wipe_level_toblack)
}; };
#define WIPEFINALSHIFT 13
extern UINT8 wipedefs[NUMWIPEDEFS]; extern UINT8 wipedefs[NUMWIPEDEFS];
#endif #endif

View File

@ -54,6 +54,7 @@ UINT8 wipedefs[NUMWIPEDEFS] = {
0, // wipe_evaluation_toblack 0, // wipe_evaluation_toblack
0, // wipe_gameend_toblack 0, // wipe_gameend_toblack
99, // wipe_intro_toblack (hardcoded) 99, // wipe_intro_toblack (hardcoded)
0, // wipe_ending_toblack
99, // wipe_cutscene_toblack (hardcoded) 99, // wipe_cutscene_toblack (hardcoded)
0, // wipe_specinter_toblack 0, // wipe_specinter_toblack
@ -69,6 +70,7 @@ UINT8 wipedefs[NUMWIPEDEFS] = {
0, // wipe_evaluation_final 0, // wipe_evaluation_final
0, // wipe_gameend_final 0, // wipe_gameend_final
99, // wipe_intro_final (hardcoded) 99, // wipe_intro_final (hardcoded)
0, // wipe_ending_final
99, // wipe_cutscene_final (hardcoded) 99, // wipe_cutscene_final (hardcoded)
0, // wipe_specinter_final 0, // wipe_specinter_final

View File

@ -152,7 +152,7 @@ cutscene_t *cutscenes[128];
textprompt_t *textprompts[MAX_PROMPTS]; textprompt_t *textprompts[MAX_PROMPTS];
INT16 nextmapoverride; INT16 nextmapoverride;
boolean skipstats; UINT8 skipstats;
// Pointers to each CTF flag // Pointers to each CTF flag
mobj_t *redflag; mobj_t *redflag;
@ -1842,7 +1842,7 @@ boolean G_Responder(event_t *ev)
return true; return true;
} }
} }
else if (gamestate == GS_CREDITS) else if (gamestate == GS_CREDITS || gamestate == GS_ENDING) // todo: keep ending here?
{ {
if (HU_Responder(ev)) if (HU_Responder(ev))
return true; // chat ate the event return true; // chat ate the event
@ -2032,6 +2032,12 @@ void G_Ticker(boolean run)
F_IntroTicker(); F_IntroTicker();
break; break;
case GS_ENDING:
if (run)
F_EndingTicker();
HU_Ticker();
break;
case GS_CUTSCENE: case GS_CUTSCENE:
if (run) if (run)
F_CutsceneTicker(); F_CutsceneTicker();
@ -2645,7 +2651,7 @@ void G_DoReborn(INT32 playernum)
//nextmapoverride = spstage_start; //nextmapoverride = spstage_start;
nextmapoverride = gamemap; nextmapoverride = gamemap;
countdown2 = TICRATE; countdown2 = TICRATE;
skipstats = true; skipstats = 2;
for (i = 0; i < MAXPLAYERS; i++) for (i = 0; i < MAXPLAYERS; i++)
{ {
@ -2849,6 +2855,10 @@ void G_ExitLevel(void)
// Remove CEcho text on round end. // Remove CEcho text on round end.
HU_ClearCEcho(); HU_ClearCEcho();
} }
else if (gamestate == GS_ENDING)
{
F_StartCredits();
}
else if (gamestate == GS_CREDITS) else if (gamestate == GS_CREDITS)
{ {
F_StartGameEvaluation(); F_StartGameEvaluation();
@ -3116,7 +3126,7 @@ static void G_DoCompleted(void)
nextmap = cm; nextmap = cm;
} }
if (nextmap < 0 || (nextmap >= NUMMAPS && nextmap < 1100-1) || nextmap > 1102-1) if (nextmap < 0 || (nextmap >= NUMMAPS && nextmap < 1100-1) || nextmap > 1103-1)
I_Error("Followed map %d to invalid map %d\n", prevmap + 1, nextmap + 1); I_Error("Followed map %d to invalid map %d\n", prevmap + 1, nextmap + 1);
// wrap around in race // wrap around in race
@ -3170,7 +3180,7 @@ void G_AfterIntermission(void)
{ {
HU_ClearCEcho(); HU_ClearCEcho();
if (mapheaderinfo[gamemap-1]->cutscenenum && !modeattacking) // Start a custom cutscene. if (mapheaderinfo[gamemap-1]->cutscenenum && !modeattacking && skipstats <= 1) // Start a custom cutscene.
F_StartCustomCutscene(mapheaderinfo[gamemap-1]->cutscenenum-1, false, false); F_StartCustomCutscene(mapheaderinfo[gamemap-1]->cutscenenum-1, false, false);
else else
{ {
@ -3282,6 +3292,11 @@ void G_EndGame(void)
// Only do evaluation and credits in coop games. // Only do evaluation and credits in coop games.
if (gametype == GT_COOP) if (gametype == GT_COOP)
{ {
if (nextmap == 1103-1) // end game with ending
{
F_StartEnding();
return;
}
if (nextmap == 1102-1) // end game with credits if (nextmap == 1102-1) // end game with credits
{ {
F_StartCredits(); F_StartCredits();
@ -3700,7 +3715,7 @@ void G_SaveGame(UINT32 slot)
backup = va("%s",savename); backup = va("%s",savename);
// save during evaluation or credits? game's over, folks! // save during evaluation or credits? game's over, folks!
if (gamestate == GS_CREDITS || gamestate == GS_EVALUATION) if (gamestate == GS_ENDING || gamestate == GS_CREDITS || gamestate == GS_EVALUATION)
gamecomplete = true; gamecomplete = true;
gameaction = ga_nothing; gameaction = ga_nothing;

View File

@ -56,6 +56,8 @@ extern INT16 rw_maximums[NUM_WEAPONS];
extern INT32 pausedelay; extern INT32 pausedelay;
extern boolean pausebreakkey; extern boolean pausebreakkey;
extern boolean promptactive;
// used in game menu // used in game menu
extern consvar_t cv_tutorialprompt; extern consvar_t cv_tutorialprompt;
extern consvar_t cv_chatwidth, cv_chatnotifications, cv_chatheight, cv_chattime, cv_consolechat, cv_chatbacktint, cv_chatspamprotection, cv_compactscoreboard; extern consvar_t cv_chatwidth, cv_chatnotifications, cv_chatheight, cv_chattime, cv_consolechat, cv_chatbacktint, cv_chatspamprotection, cv_compactscoreboard;

View File

@ -27,12 +27,14 @@ typedef enum
GS_TITLESCREEN, // title screen GS_TITLESCREEN, // title screen
GS_TIMEATTACK, // time attack menu GS_TIMEATTACK, // time attack menu
GS_CREDITS, // credit sequence GS_CREDITS, // credit sequence
GS_EVALUATION, // Evaluation at the end of a game. GS_EVALUATION, // Evaluation at the end of a game.
GS_GAMEEND, // game end sequence GS_GAMEEND, // game end sequence - "did you get all those chaos emeralds?"
// Hardcoded fades or other fading methods // Hardcoded fades or other fading methods
GS_INTRO, // introduction GS_INTRO, // introduction
GS_ENDING, // currently shared between bad and good endings
GS_CUTSCENE, // custom cutscene GS_CUTSCENE, // custom cutscene
// Not fadable // Not fadable

View File

@ -283,7 +283,7 @@ void HWR_DrawFixedPatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscale,
if (!(option & V_SCALEPATCHMASK)) if (!(option & V_SCALEPATCHMASK))
{ {
// if it's meant to cover the whole screen, black out the rest // if it's meant to cover the whole screen, black out the rest (ONLY IF TOP LEFT ISN'T TRANSPARENT)
// cx and cy are possibly *slightly* off from float maths // cx and cy are possibly *slightly* off from float maths
// This is done before here compared to software because we directly alter cx and cy to centre // This is done before here compared to software because we directly alter cx and cy to centre
if (cx >= -0.1f && cx <= 0.1f && SHORT(gpatch->width) == BASEVIDWIDTH && cy >= -0.1f && cy <= 0.1f && SHORT(gpatch->height) == BASEVIDHEIGHT) if (cx >= -0.1f && cx <= 0.1f && SHORT(gpatch->width) == BASEVIDWIDTH && cy >= -0.1f && cy <= 0.1f && SHORT(gpatch->height) == BASEVIDHEIGHT)
@ -291,8 +291,11 @@ void HWR_DrawFixedPatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscale,
// Need to temporarily cache the real patch to get the colour of the top left pixel // Need to temporarily cache the real patch to get the colour of the top left pixel
patch_t *realpatch = W_CacheLumpNumPwad(gpatch->wadnum, gpatch->lumpnum, PU_STATIC); patch_t *realpatch = W_CacheLumpNumPwad(gpatch->wadnum, gpatch->lumpnum, PU_STATIC);
const column_t *column = (const column_t *)((const UINT8 *)(realpatch) + LONG((realpatch)->columnofs[0])); const column_t *column = (const column_t *)((const UINT8 *)(realpatch) + LONG((realpatch)->columnofs[0]));
const UINT8 *source = (const UINT8 *)(column) + 3; if (!column->topdelta)
HWR_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, (column->topdelta == 0xff ? 31 : source[0])); {
const UINT8 *source = (const UINT8 *)(column) + 3;
HWR_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, (column->topdelta == 0xff ? 31 : source[0]));
}
Z_Free(realpatch); Z_Free(realpatch);
} }
// centre screen // centre screen
@ -439,7 +442,7 @@ void HWR_DrawCroppedPatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscal
if (!(option & V_SCALEPATCHMASK)) if (!(option & V_SCALEPATCHMASK))
{ {
// if it's meant to cover the whole screen, black out the rest // if it's meant to cover the whole screen, black out the rest (ONLY IF TOP LEFT ISN'T TRANSPARENT)
// cx and cy are possibly *slightly* off from float maths // cx and cy are possibly *slightly* off from float maths
// This is done before here compared to software because we directly alter cx and cy to centre // This is done before here compared to software because we directly alter cx and cy to centre
if (cx >= -0.1f && cx <= 0.1f && SHORT(gpatch->width) == BASEVIDWIDTH && cy >= -0.1f && cy <= 0.1f && SHORT(gpatch->height) == BASEVIDHEIGHT) if (cx >= -0.1f && cx <= 0.1f && SHORT(gpatch->width) == BASEVIDWIDTH && cy >= -0.1f && cy <= 0.1f && SHORT(gpatch->height) == BASEVIDHEIGHT)
@ -447,8 +450,11 @@ void HWR_DrawCroppedPatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscal
// Need to temporarily cache the real patch to get the colour of the top left pixel // Need to temporarily cache the real patch to get the colour of the top left pixel
patch_t *realpatch = W_CacheLumpNumPwad(gpatch->wadnum, gpatch->lumpnum, PU_STATIC); patch_t *realpatch = W_CacheLumpNumPwad(gpatch->wadnum, gpatch->lumpnum, PU_STATIC);
const column_t *column = (const column_t *)((const UINT8 *)(realpatch) + LONG((realpatch)->columnofs[0])); const column_t *column = (const column_t *)((const UINT8 *)(realpatch) + LONG((realpatch)->columnofs[0]));
const UINT8 *source = (const UINT8 *)(column) + 3; if (!column->topdelta)
HWR_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, (column->topdelta == 0xff ? 31 : source[0])); {
const UINT8 *source = (const UINT8 *)(column) + 3;
HWR_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, (column->topdelta == 0xff ? 31 : source[0]));
}
Z_Free(realpatch); Z_Free(realpatch);
} }
// centre screen // centre screen
@ -683,8 +689,183 @@ void HWR_FadeScreenMenuBack(UINT16 color, UINT8 strength)
} }
else // Do TRANSMAP** fade. else // Do TRANSMAP** fade.
{ {
Surf.FlatColor.rgba = pLocalPalette[color].rgba; Surf.FlatColor.rgba = V_GetColor(color).rgba;
Surf.FlatColor.s.alpha = (UINT8)(strength*25.5f); Surf.FlatColor.s.alpha = softwaretranstogl[strength];
}
HWD.pfnDrawPolygon(&Surf, v, 4, PF_NoTexture|PF_Modulated|PF_Translucent|PF_NoDepthTest);
}
// -----------------+
// HWR_DrawFadeFill : draw flat coloured rectangle, with transparency
// -----------------+
void HWR_DrawFadeFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 color, UINT16 actualcolor, UINT8 strength)
{
FOutVector v[4];
FSurfaceInfo Surf;
float fx, fy, fw, fh;
UINT8 perplayershuffle = 0;
// 3--2
// | /|
// |/ |
// 0--1
if (splitscreen && (color & V_PERPLAYER))
{
fixed_t adjusty = ((color & V_NOSCALESTART) ? vid.height : BASEVIDHEIGHT)/2.0f;
h >>= 1;
y >>= 1;
#ifdef QUADS
if (splitscreen > 1) // 3 or 4 players
{
fixed_t adjustx = ((color & V_NOSCALESTART) ? vid.height : BASEVIDHEIGHT)/2.0f;
w >>= 1;
x >>= 1;
if (stplyr == &players[displayplayer])
{
if (!(color & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
perplayershuffle |= 1;
if (!(color & (V_SNAPTOLEFT|V_SNAPTORIGHT)))
perplayershuffle |= 4;
color &= ~V_SNAPTOBOTTOM|V_SNAPTORIGHT;
}
else if (stplyr == &players[secondarydisplayplayer])
{
if (!(color & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
perplayershuffle |= 1;
if (!(color & (V_SNAPTOLEFT|V_SNAPTORIGHT)))
perplayershuffle |= 8;
x += adjustx;
color &= ~V_SNAPTOBOTTOM|V_SNAPTOLEFT;
}
else if (stplyr == &players[thirddisplayplayer])
{
if (!(color & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
perplayershuffle |= 2;
if (!(color & (V_SNAPTOLEFT|V_SNAPTORIGHT)))
perplayershuffle |= 4;
y += adjusty;
color &= ~V_SNAPTOTOP|V_SNAPTORIGHT;
}
else //if (stplyr == &players[fourthdisplayplayer])
{
if (!(color & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
perplayershuffle |= 2;
if (!(color & (V_SNAPTOLEFT|V_SNAPTORIGHT)))
perplayershuffle |= 8;
x += adjustx;
y += adjusty;
color &= ~V_SNAPTOTOP|V_SNAPTOLEFT;
}
}
else
#endif
// 2 players
{
if (stplyr == &players[displayplayer])
{
if (!(color & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
perplayershuffle |= 1;
color &= ~V_SNAPTOBOTTOM;
}
else //if (stplyr == &players[secondarydisplayplayer])
{
if (!(color & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
perplayershuffle |= 2;
y += adjusty;
color &= ~V_SNAPTOTOP;
}
}
}
fx = (float)x;
fy = (float)y;
fw = (float)w;
fh = (float)h;
if (!(color & V_NOSCALESTART))
{
float dupx = (float)vid.dupx, dupy = (float)vid.dupy;
fx *= dupx;
fy *= dupy;
fw *= dupx;
fh *= dupy;
if (fabsf((float)vid.width - (float)BASEVIDWIDTH * dupx) > 1.0E-36f)
{
if (color & V_SNAPTORIGHT)
fx += ((float)vid.width - ((float)BASEVIDWIDTH * dupx));
else if (!(color & V_SNAPTOLEFT))
fx += ((float)vid.width - ((float)BASEVIDWIDTH * dupx)) / 2;
if (perplayershuffle & 4)
fx -= ((float)vid.width - ((float)BASEVIDWIDTH * dupx)) / 4;
else if (perplayershuffle & 8)
fx += ((float)vid.width - ((float)BASEVIDWIDTH * dupx)) / 4;
}
if (fabsf((float)vid.height - (float)BASEVIDHEIGHT * dupy) > 1.0E-36f)
{
// same thing here
if (color & V_SNAPTOBOTTOM)
fy += ((float)vid.height - ((float)BASEVIDHEIGHT * dupy));
else if (!(color & V_SNAPTOTOP))
fy += ((float)vid.height - ((float)BASEVIDHEIGHT * dupy)) / 2;
if (perplayershuffle & 1)
fy -= ((float)vid.height - ((float)BASEVIDHEIGHT * dupy)) / 4;
else if (perplayershuffle & 2)
fy += ((float)vid.height - ((float)BASEVIDHEIGHT * dupy)) / 4;
}
}
if (fx >= vid.width || fy >= vid.height)
return;
if (fx < 0)
{
fw += fx;
fx = 0;
}
if (fy < 0)
{
fh += fy;
fy = 0;
}
if (fw <= 0 || fh <= 0)
return;
if (fx + fw > vid.width)
fw = (float)vid.width - fx;
if (fy + fh > vid.height)
fh = (float)vid.height - fy;
fx = -1 + fx / (vid.width / 2);
fy = 1 - fy / (vid.height / 2);
fw = fw / (vid.width / 2);
fh = fh / (vid.height / 2);
v[0].x = v[3].x = fx;
v[2].x = v[1].x = fx + fw;
v[0].y = v[1].y = fy;
v[2].y = v[3].y = fy - fh;
//Hurdler: do we still use this argb color? if not, we should remove it
v[0].argb = v[1].argb = v[2].argb = v[3].argb = 0xff00ff00; //;
v[0].z = v[1].z = v[2].z = v[3].z = 1.0f;
v[0].sow = v[3].sow = 0.0f;
v[2].sow = v[1].sow = 1.0f;
v[0].tow = v[1].tow = 0.0f;
v[2].tow = v[3].tow = 1.0f;
if (actualcolor & 0xFF00) // Do COLORMAP fade.
{
Surf.FlatColor.rgba = UINT2RGBA(0x01010160);
Surf.FlatColor.s.alpha = (strength*8);
}
else // Do TRANSMAP** fade.
{
Surf.FlatColor.rgba = V_GetColor(actualcolor).rgba;
Surf.FlatColor.s.alpha = softwaretranstogl[strength];
} }
HWD.pfnDrawPolygon(&Surf, v, 4, PF_NoTexture|PF_Modulated|PF_Translucent|PF_NoDepthTest); HWD.pfnDrawPolygon(&Surf, v, 4, PF_NoTexture|PF_Modulated|PF_Translucent|PF_NoDepthTest);
} }
@ -905,54 +1086,117 @@ void HWR_DrawConsoleFill(INT32 x, INT32 y, INT32 w, INT32 h, UINT32 color, INT32
FSurfaceInfo Surf; FSurfaceInfo Surf;
float fx, fy, fw, fh; float fx, fy, fw, fh;
if (w < 0 || h < 0) UINT8 perplayershuffle = 0;
return; // consistency w/ software
// 3--2 // 3--2
// | /| // | /|
// |/ | // |/ |
// 0--1 // 0--1
if (splitscreen && (color & V_PERPLAYER))
{
fixed_t adjusty = ((color & V_NOSCALESTART) ? vid.height : BASEVIDHEIGHT)/2.0f;
h >>= 1;
y >>= 1;
#ifdef QUADS
if (splitscreen > 1) // 3 or 4 players
{
fixed_t adjustx = ((color & V_NOSCALESTART) ? vid.height : BASEVIDHEIGHT)/2.0f;
w >>= 1;
x >>= 1;
if (stplyr == &players[displayplayer])
{
if (!(color & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
perplayershuffle |= 1;
if (!(color & (V_SNAPTOLEFT|V_SNAPTORIGHT)))
perplayershuffle |= 4;
color &= ~V_SNAPTOBOTTOM|V_SNAPTORIGHT;
}
else if (stplyr == &players[secondarydisplayplayer])
{
if (!(color & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
perplayershuffle |= 1;
if (!(color & (V_SNAPTOLEFT|V_SNAPTORIGHT)))
perplayershuffle |= 8;
x += adjustx;
color &= ~V_SNAPTOBOTTOM|V_SNAPTOLEFT;
}
else if (stplyr == &players[thirddisplayplayer])
{
if (!(color & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
perplayershuffle |= 2;
if (!(color & (V_SNAPTOLEFT|V_SNAPTORIGHT)))
perplayershuffle |= 4;
y += adjusty;
color &= ~V_SNAPTOTOP|V_SNAPTORIGHT;
}
else //if (stplyr == &players[fourthdisplayplayer])
{
if (!(color & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
perplayershuffle |= 2;
if (!(color & (V_SNAPTOLEFT|V_SNAPTORIGHT)))
perplayershuffle |= 8;
x += adjustx;
y += adjusty;
color &= ~V_SNAPTOTOP|V_SNAPTOLEFT;
}
}
else
#endif
// 2 players
{
if (stplyr == &players[displayplayer])
{
if (!(color & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
perplayershuffle |= 1;
color &= ~V_SNAPTOBOTTOM;
}
else //if (stplyr == &players[secondarydisplayplayer])
{
if (!(color & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
perplayershuffle |= 2;
y += adjusty;
color &= ~V_SNAPTOTOP;
}
}
}
fx = (float)x; fx = (float)x;
fy = (float)y; fy = (float)y;
fw = (float)w; fw = (float)w;
fh = (float)h; fh = (float)h;
if (!(options & V_NOSCALESTART)) if (!(color & V_NOSCALESTART))
{ {
float dupx = (float)vid.dupx, dupy = (float)vid.dupy; float dupx = (float)vid.dupx, dupy = (float)vid.dupy;
if (x == 0 && y == 0 && w == BASEVIDWIDTH && h == BASEVIDHEIGHT)
{
RGBA_t rgbaColour = V_GetColor(color);
FRGBAFloat clearColour;
clearColour.red = (float)rgbaColour.s.red / 255;
clearColour.green = (float)rgbaColour.s.green / 255;
clearColour.blue = (float)rgbaColour.s.blue / 255;
clearColour.alpha = 1;
HWD.pfnClearBuffer(true, false, &clearColour);
return;
}
fx *= dupx; fx *= dupx;
fy *= dupy; fy *= dupy;
fw *= dupx; fw *= dupx;
fh *= dupy; fh *= dupy;
if (fabsf((float)vid.width - ((float)BASEVIDWIDTH * dupx)) > 1.0E-36f) if (fabsf((float)vid.width - (float)BASEVIDWIDTH * dupx) > 1.0E-36f)
{ {
if (options & V_SNAPTORIGHT) if (color & V_SNAPTORIGHT)
fx += ((float)vid.width - ((float)BASEVIDWIDTH * dupx)); fx += ((float)vid.width - ((float)BASEVIDWIDTH * dupx));
else if (!(options & V_SNAPTOLEFT)) else if (!(color & V_SNAPTOLEFT))
fx += ((float)vid.width - ((float)BASEVIDWIDTH * dupx)) / 2; fx += ((float)vid.width - ((float)BASEVIDWIDTH * dupx)) / 2;
if (perplayershuffle & 4)
fx -= ((float)vid.width - ((float)BASEVIDWIDTH * dupx)) / 4;
else if (perplayershuffle & 8)
fx += ((float)vid.width - ((float)BASEVIDWIDTH * dupx)) / 4;
} }
if (fabsf((float)vid.height - ((float)BASEVIDHEIGHT * dupy)) > 1.0E-36f) if (fabsf((float)vid.height - (float)BASEVIDHEIGHT * dupy) > 1.0E-36f)
{ {
// same thing here // same thing here
if (options & V_SNAPTOBOTTOM) if (color & V_SNAPTOBOTTOM)
fy += ((float)vid.height - ((float)BASEVIDHEIGHT * dupy)); fy += ((float)vid.height - ((float)BASEVIDHEIGHT * dupy));
else if (!(options & V_SNAPTOTOP)) else if (!(color & V_SNAPTOTOP))
fy += ((float)vid.height - ((float)BASEVIDHEIGHT * dupy)) / 2; fy += ((float)vid.height - ((float)BASEVIDHEIGHT * dupy)) / 2;
if (perplayershuffle & 1)
fy -= ((float)vid.height - ((float)BASEVIDHEIGHT * dupy)) / 4;
else if (perplayershuffle & 2)
fy += ((float)vid.height - ((float)BASEVIDHEIGHT * dupy)) / 4;
} }
} }
@ -1012,9 +1256,6 @@ void HWR_DrawFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 color)
UINT8 perplayershuffle = 0; UINT8 perplayershuffle = 0;
if (w < 0 || h < 0)
return; // consistency w/ software
// 3--2 // 3--2
// | /| // | /|
// |/ | // |/ |

View File

@ -49,6 +49,7 @@ void HWR_CreatePlanePolygons(INT32 bspnum);
void HWR_CreateStaticLightmaps(INT32 bspnum); void HWR_CreateStaticLightmaps(INT32 bspnum);
void HWR_PrepLevelCache(size_t pnumtextures); void HWR_PrepLevelCache(size_t pnumtextures);
void HWR_DrawFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 color); void HWR_DrawFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 color);
void HWR_DrawFadeFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 color, UINT16 actualcolor, UINT8 strength);
void HWR_DrawConsoleFill(INT32 x, INT32 y, INT32 w, INT32 h, UINT32 color, INT32 options); // Lat: separate flags from color since color needs to be an uint to work right. void HWR_DrawConsoleFill(INT32 x, INT32 y, INT32 w, INT32 h, UINT32 color, INT32 options); // Lat: separate flags from color since color needs to be an uint to work right.
void HWR_DrawPic(INT32 x,INT32 y,lumpnum_t lumpnum); void HWR_DrawPic(INT32 x,INT32 y,lumpnum_t lumpnum);

View File

@ -1198,6 +1198,9 @@ static UINT8 P_GetModelSprite2(md2_t *md2, skin_t *skin, UINT8 spr2, player_t *p
if (!md2 || !skin) if (!md2 || !skin)
return 0; return 0;
if ((spr2 & ~FF_SPR2SUPER) >= free_spr2)
return 0;
while (!(md2->model->spr2frames[spr2*2 + 1]) while (!(md2->model->spr2frames[spr2*2 + 1])
&& spr2 != SPR2_STND && spr2 != SPR2_STND
&& ++i != 32) // recursion limiter && ++i != 32) // recursion limiter
@ -1220,7 +1223,10 @@ static UINT8 P_GetModelSprite2(md2_t *md2, skin_t *skin, UINT8 spr2, player_t *p
& SF_NOJUMPSPIN) ? SPR2_SPNG : SPR2_ROLL; & SF_NOJUMPSPIN) ? SPR2_SPNG : SPR2_ROLL;
break; break;
case SPR2_TIRE: case SPR2_TIRE:
spr2 = (player && player->charability == CA_SWIM) ? SPR2_SWIM : SPR2_FLY; spr2 = ((player
? player->charability
: skin->ability)
== CA_SWIM) ? SPR2_SWIM : SPR2_FLY;
break; break;
// Use the handy list, that's what it's there for! // Use the handy list, that's what it's there for!
@ -1232,6 +1238,9 @@ static UINT8 P_GetModelSprite2(md2_t *md2, skin_t *skin, UINT8 spr2, player_t *p
spr2 |= super; spr2 |= super;
} }
if (i >= 32) // probably an infinite loop...
return 0;
return spr2; return spr2;
} }

View File

@ -2138,7 +2138,7 @@ void HU_Drawer(void)
if (!Playing() if (!Playing()
|| gamestate == GS_INTERMISSION || gamestate == GS_CUTSCENE || gamestate == GS_INTERMISSION || gamestate == GS_CUTSCENE
|| gamestate == GS_CREDITS || gamestate == GS_EVALUATION || gamestate == GS_CREDITS || gamestate == GS_EVALUATION
|| gamestate == GS_GAMEEND) || gamestate == GS_ENDING || gamestate == GS_GAMEEND)
return; return;
// draw multiplayer rankings // draw multiplayer rankings

View File

@ -578,7 +578,8 @@ char spr2names[NUMPLAYERSPRITES][5] =
"TALB", "TALB",
"SIGN", "SIGN",
"LIFE" "LIFE",
"XTRA",
}; };
playersprite_t free_spr2 = SPR2_FIRSTFREESLOT; playersprite_t free_spr2 = SPR2_FIRSTFREESLOT;
@ -595,7 +596,7 @@ playersprite_t spr2defaults[NUMPLAYERSPRITES] = {
SPR2_DEAD, // SPR2_DRWN, SPR2_DEAD, // SPR2_DRWN,
0, // SPR2_ROLL, 0, // SPR2_ROLL,
SPR2_SPNG, // SPR2_GASP, SPR2_SPNG, // SPR2_GASP,
0, // SPR2_JUMP, (conditional) 0, // SPR2_JUMP, (conditional, will never be referenced)
SPR2_FALL, // SPR2_SPNG, SPR2_FALL, // SPR2_SPNG,
SPR2_WALK, // SPR2_FALL, SPR2_WALK, // SPR2_FALL,
0, // SPR2_EDGE, 0, // SPR2_EDGE,
@ -605,7 +606,7 @@ playersprite_t spr2defaults[NUMPLAYERSPRITES] = {
SPR2_SPNG, // SPR2_FLY , SPR2_SPNG, // SPR2_FLY ,
SPR2_FLY , // SPR2_SWIM, SPR2_FLY , // SPR2_SWIM,
0, // SPR2_TIRE, (conditional) 0, // SPR2_TIRE, (conditional, will never be referenced)
SPR2_FLY , // SPR2_GLID, SPR2_FLY , // SPR2_GLID,
SPR2_CLMB, // SPR2_CLNG, SPR2_CLMB, // SPR2_CLNG,
@ -632,7 +633,7 @@ playersprite_t spr2defaults[NUMPLAYERSPRITES] = {
SPR2_NSTN, // SPR2_NPUL, SPR2_NSTN, // SPR2_NPUL,
FF_SPR2SUPER|SPR2_ROLL, // SPR2_NATK, FF_SPR2SUPER|SPR2_ROLL, // SPR2_NATK,
0, // SPR2_NGT0, (should never be referenced) 0, // SPR2_NGT0, (will never be referenced unless skin 0 lacks this)
SPR2_NGT0, // SPR2_NGT1, SPR2_NGT0, // SPR2_NGT1,
SPR2_NGT1, // SPR2_NGT2, SPR2_NGT1, // SPR2_NGT2,
SPR2_NGT2, // SPR2_NGT3, SPR2_NGT2, // SPR2_NGT3,
@ -660,7 +661,7 @@ playersprite_t spr2defaults[NUMPLAYERSPRITES] = {
SPR2_NGTB, // SPR2_DRLB, SPR2_NGTB, // SPR2_DRLB,
SPR2_NGTC, // SPR2_DRLC, SPR2_NGTC, // SPR2_DRLC,
0, // SPR2_TAL0, 0, // SPR2_TAL0, (this will look mighty stupid but oh well)
SPR2_TAL0, // SPR2_TAL1, SPR2_TAL0, // SPR2_TAL1,
SPR2_TAL1, // SPR2_TAL2, SPR2_TAL1, // SPR2_TAL2,
SPR2_TAL2, // SPR2_TAL3, SPR2_TAL2, // SPR2_TAL3,
@ -675,6 +676,7 @@ playersprite_t spr2defaults[NUMPLAYERSPRITES] = {
0, // SPR2_SIGN, 0, // SPR2_SIGN,
0, // SPR2_LIFE, 0, // SPR2_LIFE,
0, // SPR2_XTRA (should never be referenced)
}; };
// Doesn't work with g++, needs actionf_p1 (don't modify this comment) // Doesn't work with g++, needs actionf_p1 (don't modify this comment)

View File

@ -834,6 +834,7 @@ typedef enum playersprite
SPR2_SIGN, // end sign head SPR2_SIGN, // end sign head
SPR2_LIFE, // life monitor icon SPR2_LIFE, // life monitor icon
SPR2_XTRA, // stuff that isn't in-game - keep this last in the list
SPR2_FIRSTFREESLOT, SPR2_FIRSTFREESLOT,
SPR2_LASTFREESLOT = 0x7f, SPR2_LASTFREESLOT = 0x7f,

View File

@ -2609,12 +2609,12 @@ static int lib_gSetCustomExitVars(lua_State *L)
nextmapoverride = (INT16)luaL_checknumber(L, 1); nextmapoverride = (INT16)luaL_checknumber(L, 1);
lua_remove(L, 1); // remove nextmapoverride; skipstats now 1 if available lua_remove(L, 1); // remove nextmapoverride; skipstats now 1 if available
} }
skipstats = lua_optboolean(L, 1); skipstats = luaL_optinteger(L, 2, 0);
} }
else else
{ {
nextmapoverride = 0; nextmapoverride = 0;
skipstats = false; skipstats = 0;
} }
// --- // ---

View File

@ -157,6 +157,18 @@ static int lib_setSpr2default(lua_State *L)
playersprite_t i; playersprite_t i;
UINT8 j = 0; UINT8 j = 0;
if (hud_running)
return luaL_error(L, "Do not alter spr2defaults[] in HUD rendering code!");
// todo: maybe allow setting below first freeslot..? step 1 is toggling this, step 2 is testing to see whether it's net-safe
#ifdef SETALLSPR2DEFAULTS
#define FIRSTMODIFY 0
#else
#define FIRSTMODIFY SPR2_FIRSTFREESLOT
if (free_spr2 == SPR2_FIRSTFREESLOT)
return luaL_error(L, "You can only modify the spr2defaults[] entries of sprite2 freeslots, and none are currently added.");
#endif
lua_remove(L, 1); // don't care about spr2defaults[] dummy userdata. lua_remove(L, 1); // don't care about spr2defaults[] dummy userdata.
if (lua_isnumber(L, 1)) if (lua_isnumber(L, 1))
@ -175,8 +187,9 @@ static int lib_setSpr2default(lua_State *L)
else else
return luaL_error(L, "spr2defaults[] invalid index"); return luaL_error(L, "spr2defaults[] invalid index");
if (i < SPR2_FIRSTFREESLOT || i >= free_spr2) if (i < FIRSTMODIFY || i >= free_spr2)
return luaL_error(L, "spr2defaults[] index %d out of range (%d - %d)", i, SPR2_FIRSTFREESLOT, free_spr2-1); return luaL_error(L, "spr2defaults[] index %d out of range (%d - %d)", i, FIRSTMODIFY, free_spr2-1);
#undef FIRSTMODIFY
if (lua_isnumber(L, 2)) if (lua_isnumber(L, 2))
j = lua_tonumber(L, 2); j = lua_tonumber(L, 2);
@ -189,11 +202,13 @@ static int lib_setSpr2default(lua_State *L)
break; break;
} }
if (j == free_spr2) if (j == free_spr2)
return luaL_error(L, "spr2defaults[] invalid index"); return luaL_error(L, "spr2defaults[] invalid set");
} }
else
return luaL_error(L, "spr2defaults[] invalid set");
if (j >= free_spr2) if (j < 0 || j >= free_spr2)
j = 0; // return luaL_error(L, "spr2defaults[] set %d out of range (%d - %d)", j, 0, free_spr2-1); return luaL_error(L, "spr2defaults[] set %d out of range (%d - %d)", j, 0, free_spr2-1);
spr2defaults[i] = j; spr2defaults[i] = j;
return 0; return 0;

View File

@ -27,9 +27,6 @@ enum skin {
skin_flags, skin_flags,
skin_realname, skin_realname,
skin_hudname, skin_hudname,
skin_charsel,
skin_face,
skin_superface,
skin_ability, skin_ability,
skin_ability2, skin_ability2,
skin_thokitem, skin_thokitem,
@ -66,9 +63,6 @@ static const char *const skin_opt[] = {
"flags", "flags",
"realname", "realname",
"hudname", "hudname",
"charsel",
"face",
"superface",
"ability", "ability",
"ability2", "ability2",
"thokitem", "thokitem",
@ -104,7 +98,6 @@ static int skin_get(lua_State *L)
{ {
skin_t *skin = *((skin_t **)luaL_checkudata(L, 1, META_SKIN)); skin_t *skin = *((skin_t **)luaL_checkudata(L, 1, META_SKIN));
enum skin field = luaL_checkoption(L, 2, NULL, skin_opt); enum skin field = luaL_checkoption(L, 2, NULL, skin_opt);
INT32 i;
// skins are always valid, only added, never removed // skins are always valid, only added, never removed
I_Assert(skin != NULL); I_Assert(skin != NULL);
@ -131,24 +124,6 @@ static int skin_get(lua_State *L)
case skin_hudname: case skin_hudname:
lua_pushstring(L, skin->hudname); lua_pushstring(L, skin->hudname);
break; break;
case skin_charsel:
for (i = 0; i < 8; i++)
if (!skin->charsel[i])
break;
lua_pushlstring(L, skin->charsel, i);
break;
case skin_face:
for (i = 0; i < 8; i++)
if (!skin->face[i])
break;
lua_pushlstring(L, skin->face, i);
break;
case skin_superface:
for (i = 0; i < 8; i++)
if (!skin->superface[i])
break;
lua_pushlstring(L, skin->superface, i);
break;
case skin_ability: case skin_ability:
lua_pushinteger(L, skin->ability); lua_pushinteger(L, skin->ability);
break; break;

View File

@ -240,7 +240,7 @@ UINT8 M_UpdateUnlockablesAndExtraEmblems(void)
if (cechoLines) if (cechoLines)
{ {
char slashed[1024] = ""; char slashed[1024] = "";
for (i = 0; (i < 21) && (i < 24 - cechoLines); ++i) for (i = 0; (i < 19) && (i < 24 - cechoLines); ++i)
slashed[i] = '\\'; slashed[i] = '\\';
slashed[i] = 0; slashed[i] = 0;

View File

@ -2810,8 +2810,8 @@ boolean M_Responder(event_t *ev)
void (*routine)(INT32 choice); // for some casting problem void (*routine)(INT32 choice); // for some casting problem
if (dedicated || (demoplayback && titledemo) if (dedicated || (demoplayback && titledemo)
|| gamestate == GS_INTRO || gamestate == GS_CUTSCENE || gamestate == GS_GAMEEND || gamestate == GS_INTRO || gamestate == GS_ENDING || gamestate == GS_CUTSCENE
|| gamestate == GS_CREDITS || gamestate == GS_EVALUATION) || gamestate == GS_CREDITS || gamestate == GS_EVALUATION || gamestate == GS_GAMEEND)
return false; return false;
if (noFurtherInput) if (noFurtherInput)
@ -3511,6 +3511,7 @@ void M_InitCharacterTables(void)
strcpy(description[i].picname, ""); strcpy(description[i].picname, "");
strcpy(description[i].skinname, ""); strcpy(description[i].skinname, "");
description[i].prev = description[i].next = 0; description[i].prev = description[i].next = 0;
description[i].pic = NULL;
} }
} }
@ -7557,8 +7558,19 @@ static void M_SetupChoosePlayer(INT32 choice)
if (i == char_on) if (i == char_on)
allowed = true; allowed = true;
if (description[i].picname[0] == '\0') if (!(description[i].picname[0]))
strncpy(description[i].picname, skins[skinnum].charsel, 8); {
if (skins[skinnum].sprites[SPR2_XTRA].numframes >= 2)
{
spritedef_t *sprdef = &skins[skinnum].sprites[SPR2_XTRA];
spriteframe_t *sprframe = &sprdef->spriteframes[1];
description[i].pic = W_CachePatchNum(sprframe->lumppat[0], PU_CACHE);
}
else
description[i].pic = W_CachePatchName("MISSING", PU_CACHE);
}
else
description[i].pic = W_CachePatchName(description[i].picname, PU_CACHE);
} }
// else -- Technically, character select icons without corresponding skins get bundled away behind this too. Sucks to be them. // else -- Technically, character select icons without corresponding skins get bundled away behind this too. Sucks to be them.
Z_Free(name); Z_Free(name);
@ -7712,7 +7724,7 @@ static void M_DrawSetupChoosePlayerMenu(void)
// Draw prev character if it's visible and its number isn't greater than the current one or there's more than two // Draw prev character if it's visible and its number isn't greater than the current one or there's more than two
if (o < 32) if (o < 32)
{ {
patch = W_CachePatchName(description[prev].picname, PU_CACHE); patch = description[prev].pic;
if (SHORT(patch->width) >= 256) if (SHORT(patch->width) >= 256)
V_DrawCroppedPatch(8<<FRACBITS, (my + 8)<<FRACBITS, FRACUNIT/2, 0, patch, 0, SHORT(patch->height) + 2*(o-32), SHORT(patch->width), 64 - 2*o); V_DrawCroppedPatch(8<<FRACBITS, (my + 8)<<FRACBITS, FRACUNIT/2, 0, patch, 0, SHORT(patch->height) + 2*(o-32), SHORT(patch->width), 64 - 2*o);
else else
@ -7723,7 +7735,7 @@ static void M_DrawSetupChoosePlayerMenu(void)
// Draw next character if it's visible and its number isn't less than the current one or there's more than two // Draw next character if it's visible and its number isn't less than the current one or there's more than two
if (o < 128) // (next != i) was previously a part of this, but it's implicitly true if (prev != i) is true. if (o < 128) // (next != i) was previously a part of this, but it's implicitly true if (prev != i) is true.
{ {
patch = W_CachePatchName(description[next].picname, PU_CACHE); patch = description[next].pic;
if (SHORT(patch->width) >= 256) if (SHORT(patch->width) >= 256)
V_DrawCroppedPatch(8<<FRACBITS, (my + 168 - o)<<FRACBITS, FRACUNIT/2, 0, patch, 0, 0, SHORT(patch->width), 2*o); V_DrawCroppedPatch(8<<FRACBITS, (my + 168 - o)<<FRACBITS, FRACUNIT/2, 0, patch, 0, 0, SHORT(patch->width), 2*o);
else else
@ -7732,7 +7744,7 @@ static void M_DrawSetupChoosePlayerMenu(void)
} }
} }
patch = W_CachePatchName(description[i].picname, PU_CACHE); patch = description[i].pic;
if (o >= 0 && o <= 32) if (o >= 0 && o <= 32)
{ {
if (SHORT(patch->width) >= 256) if (SHORT(patch->width) >= 256)
@ -8124,9 +8136,16 @@ void M_DrawTimeAttackMenu(void)
V_DrawString(currentMenu->x, cursory, V_YELLOWMAP, currentMenu->menuitems[itemOn].text); V_DrawString(currentMenu->x, cursory, V_YELLOWMAP, currentMenu->menuitems[itemOn].text);
// Character face! // Character face!
if (W_CheckNumForName(skins[cv_chooseskin.value-1].charsel) != LUMPERROR)
{ {
PictureOfUrFace = W_CachePatchName(skins[cv_chooseskin.value-1].charsel, PU_CACHE); if (skins[cv_chooseskin.value-1].sprites[SPR2_XTRA].numframes >= 2)
{
spritedef_t *sprdef = &skins[cv_chooseskin.value-1].sprites[SPR2_XTRA];
spriteframe_t *sprframe = &sprdef->spriteframes[1];
PictureOfUrFace = W_CachePatchNum(sprframe->lumppat[0], PU_CACHE);
}
else
PictureOfUrFace = W_CachePatchName("MISSING", PU_CACHE);
if (PictureOfUrFace->width >= 256) if (PictureOfUrFace->width >= 256)
V_DrawTinyScaledPatch(224, 120, 0, PictureOfUrFace); V_DrawTinyScaledPatch(224, 120, 0, PictureOfUrFace);
else else

View File

@ -316,6 +316,7 @@ typedef struct
char notes[441]; char notes[441];
char picname[8]; char picname[8];
char skinname[SKINNAMESIZE*2+2]; // skin&skin\0 char skinname[SKINNAMESIZE*2+2]; // skin&skin\0
patch_t *pic;
UINT8 prev; UINT8 prev;
UINT8 next; UINT8 next;
} description_t; } description_t;

View File

@ -11110,6 +11110,12 @@ You should think about modifying the deathmatch starts to take full advantage of
else else
skyboxviewpnts[mthing->extrainfo] = mobj; skyboxviewpnts[mthing->extrainfo] = mobj;
break; break;
case MT_EGGSTATUE:
if (tutorialmode != (mthing->options & MTF_OBJECTSPECIAL))
{
mobj->color = SKINCOLOR_GOLD;
mobj->colorized = true;
}
case MT_EGGMOBILE3: case MT_EGGMOBILE3:
mobj->cusval = mthing->extrainfo; mobj->cusval = mthing->extrainfo;
break; break;

View File

@ -3117,7 +3117,7 @@ boolean P_SetupLevel(boolean skipprecip)
R_PrecacheLevel(); R_PrecacheLevel();
nextmapoverride = 0; nextmapoverride = 0;
skipstats = false; skipstats = 0;
if (!(netgame || multiplayer) && (!modifiedgame || savemoddata)) if (!(netgame || multiplayer) && (!modifiedgame || savemoddata))
mapvisited[gamemap-1] |= MV_VISITED; mapvisited[gamemap-1] |= MV_VISITED;
@ -3428,13 +3428,13 @@ boolean P_AddWadFile(const char *wadfilename)
ST_UnloadGraphics(); ST_UnloadGraphics();
HU_LoadGraphics(); HU_LoadGraphics();
ST_LoadGraphics(); ST_LoadGraphics();
ST_ReloadSkinFaceGraphics();
// //
// look for skins // look for skins
// //
R_AddSkins(wadnum); // faB: wadfile index in wadfiles[] R_AddSkins(wadnum); // faB: wadfile index in wadfiles[]
R_PatchSkins(wadnum); // toast: PATCH PATCH R_PatchSkins(wadnum); // toast: PATCH PATCH
ST_ReloadSkinFaceGraphics();
// //
// search for maps // search for maps

View File

@ -4662,7 +4662,7 @@ DoneSection2:
nextmapoverride = (INT16)(lines[lineindex].frontsector->floorheight>>FRACBITS); nextmapoverride = (INT16)(lines[lineindex].frontsector->floorheight>>FRACBITS);
if (lines[lineindex].flags & ML_NOCLIMB) if (lines[lineindex].flags & ML_NOCLIMB)
skipstats = true; skipstats = 1;
} }
} }
break; break;

View File

@ -486,7 +486,11 @@ void R_InitSprites(void)
// it can be is do before loading config for skin cvar possible value // it can be is do before loading config for skin cvar possible value
R_InitSkins(); R_InitSkins();
for (i = 0; i < numwadfiles; i++) for (i = 0; i < numwadfiles; i++)
{
R_AddSkins((UINT16)i); R_AddSkins((UINT16)i);
R_PatchSkins((UINT16)i);
}
ST_ReloadSkinFaceGraphics();
// //
// check if all sprites have frames // check if all sprites have frames
@ -2507,6 +2511,9 @@ UINT8 P_GetSkinSprite2(skin_t *skin, UINT8 spr2, player_t *player)
if (!skin) if (!skin)
return 0; return 0;
if ((spr2 & ~FF_SPR2SUPER) >= free_spr2)
return 0;
while (!(skin->sprites[spr2].numframes) while (!(skin->sprites[spr2].numframes)
&& spr2 != SPR2_STND && spr2 != SPR2_STND
&& ++i < 32) // recursion limiter && ++i < 32) // recursion limiter
@ -2529,8 +2536,10 @@ UINT8 P_GetSkinSprite2(skin_t *skin, UINT8 spr2, player_t *player)
& SF_NOJUMPSPIN) ? SPR2_SPNG : SPR2_ROLL; & SF_NOJUMPSPIN) ? SPR2_SPNG : SPR2_ROLL;
break; break;
case SPR2_TIRE: case SPR2_TIRE:
spr2 = (player && player->charability == CA_SWIM) ? SPR2_SWIM : SPR2_FLY; spr2 = ((player
break; ? player->charability
: skin->ability)
== CA_SWIM) ? SPR2_SWIM : SPR2_FLY;
// Use the handy list, that's what it's there for! // Use the handy list, that's what it's there for!
default: default:
@ -2541,6 +2550,9 @@ UINT8 P_GetSkinSprite2(skin_t *skin, UINT8 spr2, player_t *player)
spr2 |= super; spr2 |= super;
} }
if (i >= 32) // probably an infinite loop...
return 0;
return spr2; return spr2;
} }
@ -2560,9 +2572,6 @@ static void Sk_SetDefaultValue(skin_t *skin)
strcpy(skin->realname, "Someone"); strcpy(skin->realname, "Someone");
strcpy(skin->hudname, "???"); strcpy(skin->hudname, "???");
strncpy(skin->charsel, "CHRSONIC", 9);
strncpy(skin->face, "MISSING", 8);
strncpy(skin->superface, "MISSING", 8);
skin->starttranscolor = 96; skin->starttranscolor = 96;
skin->prefcolor = SKINCOLOR_GREEN; skin->prefcolor = SKINCOLOR_GREEN;
@ -2992,7 +3001,7 @@ void R_AddSkins(UINT16 wadnum)
char *value; char *value;
size_t size; size_t size;
skin_t *skin; skin_t *skin;
boolean hudname, realname, superface; boolean hudname, realname;
// //
// search for all skin markers in pwad // search for all skin markers in pwad
@ -3022,7 +3031,7 @@ void R_AddSkins(UINT16 wadnum)
skin = &skins[numskins]; skin = &skins[numskins];
Sk_SetDefaultValue(skin); Sk_SetDefaultValue(skin);
skin->wadnum = wadnum; skin->wadnum = wadnum;
hudname = realname = superface = false; hudname = realname = false;
// parse // parse
stoken = strtok (buf2, "\r\n= "); stoken = strtok (buf2, "\r\n= ");
while (stoken) while (stoken)
@ -3098,24 +3107,6 @@ void R_AddSkins(UINT16 wadnum)
if (!realname) if (!realname)
STRBUFCPY(skin->realname, skin->hudname); STRBUFCPY(skin->realname, skin->hudname);
} }
else if (!stricmp(stoken, "charsel"))
{
strupr(value);
strncpy(skin->charsel, value, sizeof skin->charsel);
}
else if (!stricmp(stoken, "face"))
{
strupr(value);
strncpy(skin->face, value, sizeof skin->face);
if (!superface)
strncpy(skin->superface, value, sizeof skin->superface);
}
else if (!stricmp(stoken, "superface"))
{
superface = true;
strupr(value);
strncpy(skin->superface, value, sizeof skin->superface);
}
else if (!stricmp(stoken, "availability")) else if (!stricmp(stoken, "availability"))
{ {
skin->availability = atoi(value); skin->availability = atoi(value);
@ -3134,6 +3125,7 @@ next_token:
// Add sprites // Add sprites
R_LoadSkinSprites(wadnum, &lump, &lastlump, skin); R_LoadSkinSprites(wadnum, &lump, &lastlump, skin);
//ST_LoadFaceGraphics(numskins); -- nah let's do this elsewhere
R_FlushTranslationColormapCache(); R_FlushTranslationColormapCache();
@ -3144,9 +3136,6 @@ next_token:
skin_cons_t[numskins].strvalue = skin->name; skin_cons_t[numskins].strvalue = skin->name;
#endif #endif
// add face graphics
ST_LoadFaceGraphics(skin->face, skin->superface, numskins);
#ifdef HWRENDER #ifdef HWRENDER
if (rendermode == render_opengl) if (rendermode == render_opengl)
HWR_AddPlayerMD2(numskins); HWR_AddPlayerMD2(numskins);
@ -3269,6 +3258,9 @@ next_token:
// Patch sprites // Patch sprites
R_LoadSkinSprites(wadnum, &lump, &lastlump, skin); R_LoadSkinSprites(wadnum, &lump, &lastlump, skin);
//ST_LoadFaceGraphics(skinnum); -- nah let's do this elsewhere
R_FlushTranslationColormapCache();
if (!skin->availability) // Safe to print... if (!skin->availability) // Safe to print...
CONS_Printf(M_GetText("Patched skin '%s'\n"), skin->name); CONS_Printf(M_GetText("Patched skin '%s'\n"), skin->name);

View File

@ -88,7 +88,6 @@ typedef struct
char realname[SKINNAMESIZE+1]; // Display name for level completion. char realname[SKINNAMESIZE+1]; // Display name for level completion.
char hudname[SKINNAMESIZE+1]; // HUD name to display (officially exactly 5 characters long) char hudname[SKINNAMESIZE+1]; // HUD name to display (officially exactly 5 characters long)
char charsel[9], face[9], superface[9]; // Arbitrarily named patch lumps
UINT8 ability; // ability definition UINT8 ability; // ability definition
UINT8 ability2; // secondary ability definition UINT8 ability2; // secondary ability definition

View File

@ -519,6 +519,7 @@ void S_StartCaption(sfxenum_t sfx_id, INT32 cnum, UINT16 lifespan)
void S_StartSoundAtVolume(const void *origin_p, sfxenum_t sfx_id, INT32 volume) void S_StartSoundAtVolume(const void *origin_p, sfxenum_t sfx_id, INT32 volume)
{ {
INT32 sep, pitch, priority, cnum; INT32 sep, pitch, priority, cnum;
const sfxenum_t actual_id = sfx_id;
sfxinfo_t *sfx; sfxinfo_t *sfx;
const mobj_t *origin = (const mobj_t *)origin_p; const mobj_t *origin = (const mobj_t *)origin_p;
@ -657,7 +658,7 @@ void S_StartSoundAtVolume(const void *origin_p, sfxenum_t sfx_id, INT32 volume)
#endif #endif
// Handle closed caption input. // Handle closed caption input.
S_StartCaption(sfx_id, cnum, MAXCAPTIONTICS); S_StartCaption(actual_id, cnum, MAXCAPTIONTICS);
// Assigns the handle to one of the channels in the // Assigns the handle to one of the channels in the
// mix/output buffer. // mix/output buffer.
@ -710,7 +711,7 @@ dontplay:
#endif #endif
// Handle closed caption input. // Handle closed caption input.
S_StartCaption(sfx_id, cnum, MAXCAPTIONTICS); S_StartCaption(actual_id, cnum, MAXCAPTIONTICS);
// Assigns the handle to one of the channels in the // Assigns the handle to one of the channels in the
// mix/output buffer. // mix/output buffer.
@ -1682,7 +1683,17 @@ void S_StopMusic(void)
if (cv_closedcaptioning.value) if (cv_closedcaptioning.value)
{ {
if (closedcaptions[0].s-S_sfx == sfx_None) if (closedcaptions[0].s-S_sfx == sfx_None)
closedcaptions[0].t = CAPTIONFADETICS; {
if (gamestate != wipegamestate)
{
closedcaptions[0].c = NULL;
closedcaptions[0].s = NULL;
closedcaptions[0].t = 0;
closedcaptions[0].b = 0;
}
else
closedcaptions[0].t = CAPTIONFADETICS;
}
} }
} }

View File

@ -438,7 +438,9 @@ void SCR_ClosedCaptions(void)
if (gamestate == GS_LEVEL) if (gamestate == GS_LEVEL)
{ {
if (splitscreen) if (promptactive)
basey -= 28;
else if (splitscreen)
basey -= 8; basey -= 8;
else if ((modeattacking == ATTACKING_NIGHTS) else if ((modeattacking == ATTACKING_NIGHTS)
|| (!(maptol & TOL_NIGHTS) || (!(maptol & TOL_NIGHTS)

View File

@ -227,7 +227,7 @@ void ST_doPaletteStuff(void)
void ST_UnloadGraphics(void) void ST_UnloadGraphics(void)
{ {
Z_FreeTags(PU_HUDGFX, PU_HUDGFX); Z_FreeTag(PU_HUDGFX);
} }
void ST_LoadGraphics(void) void ST_LoadGraphics(void)
@ -343,10 +343,24 @@ 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(char *facestr, char *superstr, INT32 skinnum) void ST_LoadFaceGraphics(INT32 skinnum)
{ {
faceprefix[skinnum] = W_CachePatchName(facestr, PU_HUDGFX); if (skins[skinnum].sprites[SPR2_XTRA].numframes)
superprefix[skinnum] = W_CachePatchName(superstr, PU_HUDGFX); {
spritedef_t *sprdef = &skins[skinnum].sprites[SPR2_XTRA];
spriteframe_t *sprframe = &sprdef->spriteframes[0];
faceprefix[skinnum] = W_CachePatchNum(sprframe->lumppat[0], PU_HUDGFX);
if (skins[skinnum].sprites[(SPR2_XTRA|FF_SPR2SUPER)].numframes)
{
sprdef = &skins[skinnum].sprites[SPR2_XTRA|FF_SPR2SUPER];
sprframe = &sprdef->spriteframes[0];
superprefix[skinnum] = W_CachePatchNum(sprframe->lumppat[0], PU_HUDGFX);
}
else
superprefix[skinnum] = faceprefix[skinnum]; // not manually freed, okay to set to same pointer
}
else
faceprefix[skinnum] = superprefix[skinnum] = W_CachePatchName("MISSING", PU_HUDGFX); // ditto
facefreed[skinnum] = false; facefreed[skinnum] = false;
} }
@ -355,7 +369,7 @@ void ST_ReloadSkinFaceGraphics(void)
INT32 i; INT32 i;
for (i = 0; i < numskins; i++) for (i = 0; i < numskins; i++)
ST_LoadFaceGraphics(skins[i].face, skins[i].superface, i); ST_LoadFaceGraphics(i);
} }
static inline void ST_InitData(void) static inline void ST_InitData(void)

View File

@ -42,7 +42,7 @@ void ST_UnloadGraphics(void);
void ST_LoadGraphics(void); void ST_LoadGraphics(void);
// face load graphics, called when skin changes // face load graphics, called when skin changes
void ST_LoadFaceGraphics(char *facestr, char *superstr, INT32 playernum); void ST_LoadFaceGraphics(INT32 playernum);
void ST_ReloadSkinFaceGraphics(void); void ST_ReloadSkinFaceGraphics(void);
void ST_doPaletteStuff(void); void ST_doPaletteStuff(void);

View File

@ -309,12 +309,14 @@ static boolean InitCube(void)
return true; return true;
} }
#ifdef BACKWARDSCOMPATCORRECTION
/* /*
So it turns out that the way gamma was implemented previously, the default So it turns out that the way gamma was implemented previously, the default
colour profile of the game was messed up. Since this bad decision has been colour profile of the game was messed up. Since this bad decision has been
around for a long time, and the intent is to keep the base game looking the around for a long time, and the intent is to keep the base game looking the
same, I'm not gonna be the one to remove this base modification. same, I'm not gonna be the one to remove this base modification.
toast 20/04/17 toast 20/04/17
... welp yes i am (27/07/19, see the ifdef around it)
*/ */
const UINT8 correctiontable[256] = const UINT8 correctiontable[256] =
{1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16, {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,
@ -333,6 +335,7 @@ const UINT8 correctiontable[256] =
208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223, 208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,
224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239, 224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,
240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255}; 240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255};
#endif
// keep a copy of the palette so that we can get the RGB value for a color index at any time. // keep a copy of the palette so that we can get the RGB value for a color index at any time.
static void LoadPalette(const char *lumpname) static void LoadPalette(const char *lumpname)
@ -351,12 +354,18 @@ static void LoadPalette(const char *lumpname)
pal = W_CacheLumpNum(lumpnum, PU_CACHE); pal = W_CacheLumpNum(lumpnum, PU_CACHE);
for (i = 0; i < palsize; i++) for (i = 0; i < palsize; i++)
{ {
#ifdef BACKWARDSCOMPATCORRECTION
pMasterPalette[i].s.red = pLocalPalette[i].s.red = correctiontable[*pal++]; pMasterPalette[i].s.red = pLocalPalette[i].s.red = correctiontable[*pal++];
pMasterPalette[i].s.green = pLocalPalette[i].s.green = correctiontable[*pal++]; pMasterPalette[i].s.green = pLocalPalette[i].s.green = correctiontable[*pal++];
pMasterPalette[i].s.blue = pLocalPalette[i].s.blue = correctiontable[*pal++]; pMasterPalette[i].s.blue = pLocalPalette[i].s.blue = correctiontable[*pal++];
#else
pMasterPalette[i].s.red = pLocalPalette[i].s.red = *pal++;
pMasterPalette[i].s.green = pLocalPalette[i].s.green = *pal++;
pMasterPalette[i].s.blue = pLocalPalette[i].s.blue = *pal++;
#endif
pMasterPalette[i].s.alpha = pLocalPalette[i].s.alpha = 0xFF; pMasterPalette[i].s.alpha = pLocalPalette[i].s.alpha = 0xFF;
// lerp of colour cubing! // lerp of colour cubing! if you want, make it smoother yourself
if (cube) if (cube)
{ {
float working[4][3]; float working[4][3];
@ -732,12 +741,15 @@ void V_DrawFixedPatch(fixed_t x, fixed_t y, fixed_t pscale, INT32 scrn, patch_t
// Center it if necessary // Center it if necessary
if (!(scrn & V_SCALEPATCHMASK)) if (!(scrn & V_SCALEPATCHMASK))
{ {
// if it's meant to cover the whole screen, black out the rest // if it's meant to cover the whole screen, black out the rest (ONLY IF TOP LEFT ISN'T TRANSPARENT)
if (x == 0 && SHORT(patch->width) == BASEVIDWIDTH && y == 0 && SHORT(patch->height) == BASEVIDHEIGHT) if (x == 0 && SHORT(patch->width) == BASEVIDWIDTH && y == 0 && SHORT(patch->height) == BASEVIDHEIGHT)
{ {
column = (const column_t *)((const UINT8 *)(patch) + LONG(patch->columnofs[0])); column = (const column_t *)((const UINT8 *)(patch) + LONG(patch->columnofs[0]));
source = (const UINT8 *)(column) + 3; if (!column->topdelta)
V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, (column->topdelta == 0xff ? 31 : source[0])); {
source = (const UINT8 *)(column) + 3;
V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, source[0]);
}
} }
if (vid.width != BASEVIDWIDTH * dupx) if (vid.width != BASEVIDWIDTH * dupx)
@ -984,12 +996,7 @@ void V_DrawCroppedPatch(fixed_t x, fixed_t y, fixed_t pscale, INT32 scrn, patch_
if (!(scrn & V_SCALEPATCHMASK)) if (!(scrn & V_SCALEPATCHMASK))
{ {
// if it's meant to cover the whole screen, black out the rest // if it's meant to cover the whole screen, black out the rest
if (x == 0 && SHORT(patch->width) == BASEVIDWIDTH && y == 0 && SHORT(patch->height) == BASEVIDHEIGHT) // no the patch is cropped do not do this ever
{
column = (const column_t *)((const UINT8 *)(patch) + LONG(patch->columnofs[0]));
source = (const UINT8 *)(column) + 3;
V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, (column->topdelta == 0xff ? 31 : source[0]));
}
if (vid.width != BASEVIDWIDTH * dupx) if (vid.width != BASEVIDWIDTH * dupx)
{ {
@ -1349,13 +1356,16 @@ static UINT32 V_GetHWConsBackColor(void)
// THANK YOU MPC!!! // THANK YOU MPC!!!
// and thanks toaster for cleaning it up.
void V_DrawFillConsoleMap(INT32 x, INT32 y, INT32 w, INT32 h, INT32 c) void V_DrawFillConsoleMap(INT32 x, INT32 y, INT32 w, INT32 h, INT32 c)
{ {
UINT8 *dest; UINT8 *dest;
INT32 u, v; const UINT8 *deststop;
INT32 u;
UINT8 *fadetable; UINT8 *fadetable;
UINT32 alphalevel = 0; UINT32 alphalevel = 0;
UINT8 perplayershuffle = 0;
if (rendermode == render_none) if (rendermode == render_none)
return; return;
@ -1369,16 +1379,91 @@ void V_DrawFillConsoleMap(INT32 x, INT32 y, INT32 w, INT32 h, INT32 c)
} }
#endif #endif
if ((alphalevel = ((c & V_ALPHAMASK) >> V_ALPHASHIFT)))
{
if (alphalevel == 13)
alphalevel = hudminusalpha[cv_translucenthud.value];
else if (alphalevel == 14)
alphalevel = 10 - cv_translucenthud.value;
else if (alphalevel == 15)
alphalevel = hudplusalpha[cv_translucenthud.value];
if (alphalevel >= 10)
return; // invis
}
if (splitscreen && (c & V_PERPLAYER))
{
fixed_t adjusty = ((c & V_NOSCALESTART) ? vid.height : BASEVIDHEIGHT)>>1;
h >>= 1;
y >>= 1;
#ifdef QUADS
if (splitscreen > 1) // 3 or 4 players
{
fixed_t adjustx = ((c & V_NOSCALESTART) ? vid.height : BASEVIDHEIGHT)>>1;
w >>= 1;
x >>= 1;
if (stplyr == &players[displayplayer])
{
if (!(c & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
perplayershuffle |= 1;
if (!(c & (V_SNAPTOLEFT|V_SNAPTORIGHT)))
perplayershuffle |= 4;
c &= ~V_SNAPTOBOTTOM|V_SNAPTORIGHT;
}
else if (stplyr == &players[secondarydisplayplayer])
{
if (!(c & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
perplayershuffle |= 1;
if (!(c & (V_SNAPTOLEFT|V_SNAPTORIGHT)))
perplayershuffle |= 8;
x += adjustx;
c &= ~V_SNAPTOBOTTOM|V_SNAPTOLEFT;
}
else if (stplyr == &players[thirddisplayplayer])
{
if (!(c & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
perplayershuffle |= 2;
if (!(c & (V_SNAPTOLEFT|V_SNAPTORIGHT)))
perplayershuffle |= 4;
y += adjusty;
c &= ~V_SNAPTOTOP|V_SNAPTORIGHT;
}
else //if (stplyr == &players[fourthdisplayplayer])
{
if (!(c & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
perplayershuffle |= 2;
if (!(c & (V_SNAPTOLEFT|V_SNAPTORIGHT)))
perplayershuffle |= 8;
x += adjustx;
y += adjusty;
c &= ~V_SNAPTOTOP|V_SNAPTOLEFT;
}
}
else
#endif
// 2 players
{
if (stplyr == &players[displayplayer])
{
if (!(c & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
perplayershuffle |= 1;
c &= ~V_SNAPTOBOTTOM;
}
else //if (stplyr == &players[secondarydisplayplayer])
{
if (!(c & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
perplayershuffle |= 2;
y += adjusty;
c &= ~V_SNAPTOTOP;
}
}
}
if (!(c & V_NOSCALESTART)) if (!(c & V_NOSCALESTART))
{ {
INT32 dupx = vid.dupx, dupy = vid.dupy; INT32 dupx = vid.dupx, dupy = vid.dupy;
if (x == 0 && y == 0 && w == BASEVIDWIDTH && h == BASEVIDHEIGHT)
{ // Clear the entire screen, from dest to deststop. Yes, this really works.
memset(screens[0], (UINT8)(c&255), vid.width * vid.height * vid.bpp);
return;
}
x *= dupx; x *= dupx;
y *= dupy; y *= dupy;
w *= dupx; w *= dupx;
@ -1393,6 +1478,10 @@ void V_DrawFillConsoleMap(INT32 x, INT32 y, INT32 w, INT32 h, INT32 c)
x += (vid.width - (BASEVIDWIDTH * dupx)); x += (vid.width - (BASEVIDWIDTH * dupx));
else if (!(c & V_SNAPTOLEFT)) else if (!(c & V_SNAPTOLEFT))
x += (vid.width - (BASEVIDWIDTH * dupx)) / 2; x += (vid.width - (BASEVIDWIDTH * dupx)) / 2;
if (perplayershuffle & 4)
x -= (vid.width - (BASEVIDWIDTH * dupx)) / 4;
else if (perplayershuffle & 8)
x += (vid.width - (BASEVIDWIDTH * dupx)) / 4;
} }
if (vid.height != BASEVIDHEIGHT * dupy) if (vid.height != BASEVIDHEIGHT * dupy)
{ {
@ -1401,6 +1490,10 @@ void V_DrawFillConsoleMap(INT32 x, INT32 y, INT32 w, INT32 h, INT32 c)
y += (vid.height - (BASEVIDHEIGHT * dupy)); y += (vid.height - (BASEVIDHEIGHT * dupy));
else if (!(c & V_SNAPTOTOP)) else if (!(c & V_SNAPTOTOP))
y += (vid.height - (BASEVIDHEIGHT * dupy)) / 2; y += (vid.height - (BASEVIDHEIGHT * dupy)) / 2;
if (perplayershuffle & 1)
y -= (vid.height - (BASEVIDHEIGHT * dupy)) / 4;
else if (perplayershuffle & 2)
y += (vid.height - (BASEVIDHEIGHT * dupy)) / 4;
} }
} }
@ -1423,34 +1516,206 @@ void V_DrawFillConsoleMap(INT32 x, INT32 y, INT32 w, INT32 h, INT32 c)
h = vid.height-y; h = vid.height-y;
dest = screens[0] + y*vid.width + x; dest = screens[0] + y*vid.width + x;
deststop = screens[0] + vid.rowbytes * vid.height;
if ((alphalevel = ((c & V_ALPHAMASK) >> V_ALPHASHIFT)))
{
if (alphalevel == 13)
alphalevel = hudminusalpha[cv_translucenthud.value];
else if (alphalevel == 14)
alphalevel = 10 - cv_translucenthud.value;
else if (alphalevel == 15)
alphalevel = hudplusalpha[cv_translucenthud.value];
if (alphalevel >= 10)
return; // invis
}
c &= 255; c &= 255;
// Jimita (12-04-2018) // Jimita (12-04-2018)
w = min(w, vid.width); if (alphalevel)
h = min(h, vid.height); {
fadetable = ((UINT8 *)transtables + ((alphalevel-1)<<FF_TRANSSHIFT) + (c*256)); fadetable = ((UINT8 *)transtables + ((alphalevel-1)<<FF_TRANSSHIFT) + (c*256));
for (v = 0; v < h; v++, dest += vid.width) for (;(--h >= 0) && dest < deststop; dest += vid.width)
for (u = 0; u < w; u++)
{ {
if (!alphalevel) u = 0;
dest[u] = consolebgmap[dest[u]]; while (u < w)
else {
dest[u] = fadetable[consolebgmap[dest[u]]]; dest[u] = fadetable[consolebgmap[dest[u]]];
u++;
}
} }
}
else
{
for (;(--h >= 0) && dest < deststop; dest += vid.width)
{
u = 0;
while (u < w)
{
dest[u] = consolebgmap[dest[u]];
u++;
}
}
}
}
//
// If color is 0x00 to 0xFF, draw transtable (strength range 0-9).
// Else, use COLORMAP lump (strength range 0-31).
// c is not color, it is for flags only. transparency flags will be ignored.
// IF YOU ARE NOT CAREFUL, THIS CAN AND WILL CRASH!
// I have kept the safety checks for strength out of this function;
// I don't trust Lua users with it, so it doesn't matter.
//
void V_DrawFadeFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 c, UINT16 color, UINT8 strength)
{
UINT8 *dest;
const UINT8 *deststop;
INT32 u;
UINT8 *fadetable;
UINT8 perplayershuffle = 0;
if (rendermode == render_none)
return;
#ifdef HWRENDER
if (rendermode != render_soft && rendermode != render_none)
{
// ughhhhh please can someone else do this? thanks ~toast 25/7/19 in 38 degrees centigrade w/o AC
HWR_DrawFadeFill(x, y, w, h, c, color, strength); // toast two days later - left above comment in 'cause it's funny
return;
}
#endif
if (splitscreen && (c & V_PERPLAYER))
{
fixed_t adjusty = ((c & V_NOSCALESTART) ? vid.height : BASEVIDHEIGHT)>>1;
h >>= 1;
y >>= 1;
#ifdef QUADS
if (splitscreen > 1) // 3 or 4 players
{
fixed_t adjustx = ((c & V_NOSCALESTART) ? vid.height : BASEVIDHEIGHT)>>1;
w >>= 1;
x >>= 1;
if (stplyr == &players[displayplayer])
{
if (!(c & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
perplayershuffle |= 1;
if (!(c & (V_SNAPTOLEFT|V_SNAPTORIGHT)))
perplayershuffle |= 4;
c &= ~V_SNAPTOBOTTOM|V_SNAPTORIGHT;
}
else if (stplyr == &players[secondarydisplayplayer])
{
if (!(c & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
perplayershuffle |= 1;
if (!(c & (V_SNAPTOLEFT|V_SNAPTORIGHT)))
perplayershuffle |= 8;
x += adjustx;
c &= ~V_SNAPTOBOTTOM|V_SNAPTOLEFT;
}
else if (stplyr == &players[thirddisplayplayer])
{
if (!(c & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
perplayershuffle |= 2;
if (!(c & (V_SNAPTOLEFT|V_SNAPTORIGHT)))
perplayershuffle |= 4;
y += adjusty;
c &= ~V_SNAPTOTOP|V_SNAPTORIGHT;
}
else //if (stplyr == &players[fourthdisplayplayer])
{
if (!(c & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
perplayershuffle |= 2;
if (!(c & (V_SNAPTOLEFT|V_SNAPTORIGHT)))
perplayershuffle |= 8;
x += adjustx;
y += adjusty;
c &= ~V_SNAPTOTOP|V_SNAPTOLEFT;
}
}
else
#endif
// 2 players
{
if (stplyr == &players[displayplayer])
{
if (!(c & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
perplayershuffle |= 1;
c &= ~V_SNAPTOBOTTOM;
}
else //if (stplyr == &players[secondarydisplayplayer])
{
if (!(c & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
perplayershuffle |= 2;
y += adjusty;
c &= ~V_SNAPTOTOP;
}
}
}
if (!(c & V_NOSCALESTART))
{
INT32 dupx = vid.dupx, dupy = vid.dupy;
x *= dupx;
y *= dupy;
w *= dupx;
h *= dupy;
// Center it if necessary
if (vid.width != BASEVIDWIDTH * dupx)
{
// dupx adjustments pretend that screen width is BASEVIDWIDTH * dupx,
// so center this imaginary screen
if (c & V_SNAPTORIGHT)
x += (vid.width - (BASEVIDWIDTH * dupx));
else if (!(c & V_SNAPTOLEFT))
x += (vid.width - (BASEVIDWIDTH * dupx)) / 2;
if (perplayershuffle & 4)
x -= (vid.width - (BASEVIDWIDTH * dupx)) / 4;
else if (perplayershuffle & 8)
x += (vid.width - (BASEVIDWIDTH * dupx)) / 4;
}
if (vid.height != BASEVIDHEIGHT * dupy)
{
// same thing here
if (c & V_SNAPTOBOTTOM)
y += (vid.height - (BASEVIDHEIGHT * dupy));
else if (!(c & V_SNAPTOTOP))
y += (vid.height - (BASEVIDHEIGHT * dupy)) / 2;
if (perplayershuffle & 1)
y -= (vid.height - (BASEVIDHEIGHT * dupy)) / 4;
else if (perplayershuffle & 2)
y += (vid.height - (BASEVIDHEIGHT * dupy)) / 4;
}
}
if (x >= vid.width || y >= vid.height)
return; // off the screen
if (x < 0) {
w += x;
x = 0;
}
if (y < 0) {
h += y;
y = 0;
}
if (w <= 0 || h <= 0)
return; // zero width/height wouldn't draw anything
if (x + w > vid.width)
w = vid.width-x;
if (y + h > vid.height)
h = vid.height-y;
dest = screens[0] + y*vid.width + x;
deststop = screens[0] + vid.rowbytes * vid.height;
c &= 255;
fadetable = ((color & 0xFF00) // Color is not palette index?
? ((UINT8 *)colormaps + strength*256) // Do COLORMAP fade.
: ((UINT8 *)transtables + ((9-strength)<<FF_TRANSSHIFT) + color*256)); // Else, do TRANSMAP** fade.
for (;(--h >= 0) && dest < deststop; dest += vid.width)
{
u = 0;
while (u < w)
{
dest[u] = fadetable[dest[u]];
u++;
}
}
} }
// //

View File

@ -158,6 +158,8 @@ void V_DrawFlatFill(INT32 x, INT32 y, INT32 w, INT32 h, lumpnum_t flatnum);
// fade down the screen buffer before drawing the menu over // fade down the screen buffer before drawing the menu over
void V_DrawFadeScreen(UINT16 color, UINT8 strength); void V_DrawFadeScreen(UINT16 color, UINT8 strength);
// available to lua over my dead body, which will probably happen in this heat
void V_DrawFadeFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 c, UINT16 color, UINT8 strength);
void V_DrawFadeConsBack(INT32 plines); void V_DrawFadeConsBack(INT32 plines);
void V_DrawPromptBack(INT32 boxheight, INT32 color); void V_DrawPromptBack(INT32 boxheight, INT32 color);