A good and bad ending cutscene now exist.

Also:
* SPR2_XTRA - instead of defining lumpnames in S_SKIN, those kinds of assets can just be bundled into the spriteset. Required for ending cutscene stuff, I guess, but also done for HUD life icon and character select image (aside from Sonic&Tails, still SOC'd in).
* Minor oversights in SPR2 support corrected.
* Better evaluation, featuring ending assets.
* Intro has warping-in blackrock, reusing ending assets.
* Cutscene text now supports lowercase (intro and custom).
* Disable the asset-fucking "gamma correction" I put in over two years ago when implementing colour cube. (This is the only thing I could move into another branch if you MUST, but it's basically invisble in the diff so w/e.)
* Don't blank the screen if the top left pixel of a screen-covering patch is transparent. (Checked via nonzero topdelta for first column)

Bugs:
* OPENGL ONLY: The first ~20 frames of both endings are fucked. A little help here? Might be HWR_DrawFadeFill's fault, which I just created. OR it could be in f_finale, but I doubt it, since it doesn't appear in Software.
This commit is contained in:
toaster 2019-07-28 00:32:57 +01:00
parent cb278388f0
commit 063e350c63
26 changed files with 1445 additions and 200 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.
@ -9493,6 +9496,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

@ -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,6 +96,17 @@ 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 INT32 sparkloffs[8][3][2]; // seven emerald sparkles + eggrock explosions
static INT32 sparklloop;
// //
// PROMPT STATE // PROMPT STATE
// //
@ -230,6 +242,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 +406,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 +688,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", 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 +745,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 +767,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 +890,6 @@ void F_IntroTicker(void)
// advance animation // advance animation
finalecount++; finalecount++;
if (finalecount % 3 == 0)
roidtics--;
timetonext--; timetonext--;
F_WriteText(); F_WriteText();
@ -1103,6 +1141,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 +1260,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 +1279,8 @@ boolean F_CreditResponder(event_t *event)
// ============ // ============
// EVALUATION // EVALUATION
// ============ // ============
#define INTERVAL 50 #define INTERVAL (360/7)
#define TRANSLEVEL V_80TRANS #define TRANSLEVEL V_80TRANS
static INT32 eemeralds_start;
static boolean drawemblem = false, drawchaosemblem = false;
void F_StartGameEvaluation(void) void F_StartGameEvaluation(void)
{ {
@ -1265,17 +1302,18 @@ 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;
} }
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";
@ -1283,57 +1321,94 @@ void F_GameEvaluationDrawer(void)
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)) if (goodending)
V_DrawString(114, 16, 0, "GOT THEM ALL!"); V_DrawString(114, 16, 0, "GOT THEM ALL!");
else else
V_DrawString(124, 16, 0, "TRY AGAIN!"); V_DrawString(124, 16, 0, "TRY AGAIN!");
eemeralds_start++; if (finalecount > 0)
eemeralds_cur = eemeralds_start; {
INT32 scale = FRACUNIT;
patch_t *rockpat;
UINT8 *colormap[2] = {NULL, NULL};
patch_t *glow;
INT32 trans = 0;
x = (((BASEVIDWIDTH-82)/2)+11)<<FRACBITS;
y = (((BASEVIDHEIGHT-82)/2)+12)<<FRACBITS;
if (finalecount < 5)
{
scale = (finalecount<<(FRACBITS-2));
x += (30*(FRACUNIT-scale));
y += (30*(FRACUNIT-scale));
}
if (goodending)
{
rockpat = W_CachePatchName(va("ROID00%.2d", finalecount % 35), PU_LEVEL);
glow = W_CachePatchName(va("ENDGLOW%.1d", 2+(finalecount & 1)), PU_LEVEL);
x -= 3<<FRACBITS;
}
else
{
rockpat = W_CachePatchName("ROID0000", PU_LEVEL);
glow = W_CachePatchName(va("ENDGLOW%.1d", (finalecount & 1)), PU_LEVEL);
}
if (finalecount >= 5)
trans = (finalecount-5)>>1;
if (trans < 10)
V_DrawFixedPatch(x, y, scale, trans<<V_ALPHASHIFT, glow, NULL);
trans = (15-finalecount);
if (trans < 0)
trans = -trans;
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)
{
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;
for (i = 0; i < 7; ++i) for (i = 0; i < 7; ++i)
{ {
fa = (FixedAngle(eemeralds_cur*FRACUNIT)>>ANGLETOFINESHIFT) & FINEMASK; fa = (FixedAngle(eemeralds_cur*FRACUNIT)>>ANGLETOFINESHIFT) & FINEMASK;
x = 160 + FixedInt(FixedMul(FINECOSINE(fa),radius)); x = (BASEVIDWIDTH<<(FRACBITS-1)) + (60*FINECOSINE(fa));
y = 100 + FixedInt(FixedMul(FINESINE(fa),radius)); y = ((BASEVIDHEIGHT+16)<<(FRACBITS-1)) + (60*FINESINE(fa));
eemeralds_cur += INTERVAL;
if (i & 1)
eemeralds_cur++;
patchname[4] = 'A'+(char)i; patchname[4] = 'A'+(char)i;
if (emeralds & (1<<i)) V_DrawFixedPatch(x, y, FRACUNIT, ((emeralds & (1<<i)) ? 0 : TRANSLEVEL), W_CachePatchName(patchname, PU_LEVEL), NULL);
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 (eemeralds_start >= 360)
eemeralds_start -= 360;
if (finalecount == 5*TICRATE)
{
if ((!modifiedgame || savemoddata) && !(netgame || multiplayer))
{
++timesBeaten;
if (ALL7EMERALDS(emeralds))
++timesBeatenWithEmeralds;
if (ultimatemode)
++timesBeatenUltimate;
if (M_UpdateUnlockablesAndExtraEmblems())
S_StartSound(NULL, sfx_s3k68);
G_SaveGameData();
}
} }
if (finalecount >= 5*TICRATE) if (finalecount >= 5*TICRATE)
{ {
#if 0
if (drawemblem) if (drawemblem)
V_DrawScaledPatch(120, 192, 0, W_CachePatchName("NWNGA0", PU_CACHE)); V_DrawScaledPatch(120, 192, 0, W_CachePatchName("NWNGA0", PU_CACHE));
if (drawchaosemblem) if (drawchaosemblem)
V_DrawScaledPatch(200, 192, 0, W_CachePatchName("NWNGA0", PU_CACHE)); V_DrawScaledPatch(200, 192, 0, W_CachePatchName("NWNGA0", PU_CACHE));
#endif
V_DrawString(8, 16, V_YELLOWMAP, "Unlocked:"); V_DrawString(8, 16, V_YELLOWMAP, "Unlocked:");
@ -1363,10 +1438,579 @@ void F_GameEvaluationTicker(void)
{ {
finalecount++; finalecount++;
if (sparklloop)
sparklloop--;
if (!goodending
&& (finalecount == (5*TICRATE)/2
|| finalecount == (7*TICRATE)/2
|| finalecount == ((7*TICRATE)/2)+5))
{
S_StartSound(NULL, sfx_s3k5c);
sparklloop = 10;
}
if (finalecount == 5*TICRATE)
{
if ((!modifiedgame || savemoddata) && !(netgame || multiplayer))
{
++timesBeaten;
if (ALL7EMERALDS(emeralds))
++timesBeatenWithEmeralds;
if (ultimatemode)
++timesBeatenUltimate;
if (M_UpdateUnlockablesAndExtraEmblems())
S_StartSound(NULL, sfx_s3k68);
G_SaveGameData();
}
}
if (finalecount > 10*TICRATE) if (finalecount > 10*TICRATE)
F_StartGameEnd(); F_StartGameEnd();
} }
// ==========
// ENDING
// ==========
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)*8*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);
// 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);
}
#define colset(map, a, b, c) \
map[1] = (UINT8)a;\
map[3] = (UINT8)b;\
map[9] = (UINT8)c
colset(purplemap, 164, 165, 169);
}
#define SPARKLLOOPTIME 15 // must be odd
#define INFLECTIONPOINT (6*TICRATE)
void F_EndingTicker(void)
{
angle_t workingangle;
fixed_t workingradius;
if (++finalecount == INFLECTIONPOINT && goodending) // time to swap some assets
{
Z_Free(endegrk[0]);
endegrk[0] = W_CachePatchName("ENDEGRK2", PU_LEVEL);
Z_Free(endegrk[1]);
endegrk[1] = W_CachePatchName("ENDEGRK3", PU_LEVEL);
Z_Free(endglow[0]);
endglow[0] = W_CachePatchName("ENDGLOW2", PU_LEVEL);
Z_Free(endglow[1]);
endglow[1] = W_CachePatchName("ENDGLOW3", PU_LEVEL);
Z_Free(endxpld[0]);
endxpld[0] = W_CachePatchName("ENDEGRK4", PU_LEVEL);
}
if (++sparklloop == SPARKLLOOPTIME) // time to roll the randomisation again
{
sparklloop = 0;
if (goodending)
{
UINT8 i;
for (i = 0; i < 7; ++i)
{
sparkloffs[i][2][0] = sparkloffs[i][1][0];
sparkloffs[i][2][1] = sparkloffs[i][1][1];
sparkloffs[i][1][0] = sparkloffs[i][0][0];
sparkloffs[i][1][1] = sparkloffs[i][0][1];
sparkloffs[i][0][0] = M_RandomRange(-11, 11)<<FRACBITS;
sparkloffs[i][0][1] = M_RandomRange(-19, 3)<<FRACBITS;
}
}
workingangle = FixedAngle((M_RandomRange(-170, 80))<<FRACBITS)>>ANGLETOFINESHIFT;
workingradius = M_RandomKey(26);
sparkloffs[7][0][0] = (30<<FRACBITS) + workingradius*FINECOSINE(workingangle);
sparkloffs[7][0][1] = (30<<FRACBITS) + workingradius*FINESINE(workingangle);
}
if (finalecount > INFLECTIONPOINT*2)
{
F_StartCredits();
wipetypepre = INT16_MAX;
colset(purplemap, 160, 161, 163);
#undef colset
}
}
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", (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)
{
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
if (goodending && parallaxticker > 0) // gunchedrock
{
if (parallaxticker < 10)
{
tweakx = parallaxticker<<FRACBITS;
tweaky = ((7*parallaxticker)<<(FRACBITS-2))/5;
}
else
{
tweakx = 10<<FRACBITS;
tweaky = 7<<(FRACBITS-1);
}
i += tweakx;
j -= tweaky;
#define TFTMOPTIMUSFADE
INT32 scale = FRACUNIT + ((parallaxticker-10)<<7);
#ifdef TFTMOPTIMUSFADE
INT32 trans = parallaxticker>>2;
UINT8 *colormap = R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_JET, GTC_CACHE);
#endif
x <<= 1;
y <<= 1;
// center detritrus
V_DrawFixedPatch(i-x, j-y, FRACUNIT, 0, endegrk[0],
#ifdef TFTMOPTIMUSFADE
colormap);
if (trans < 10)
V_DrawFixedPatch(i-x, j-y, FRACUNIT, trans<<V_ALPHASHIFT, endegrk[0],
#endif
NULL);
// ring detritrus
V_DrawFixedPatch((30*(FRACUNIT-scale))+i-(2*x), (30*(FRACUNIT-scale))+j-(2*y) - ((7<<FRACBITS)/2), scale, 0, endegrk[1],
#ifdef TFTMOPTIMUSFADE
colormap);
if (trans < 10)
V_DrawFixedPatch((30*(FRACUNIT-scale))+i-(2*x), (30*(FRACUNIT-scale))+j-(2*y), scale, trans<<V_ALPHASHIFT, endegrk[1],
#endif
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],
#ifdef TFTMOPTIMUSFADE
colormap);
if (trans < 10)
V_DrawFixedPatch((30*(FRACUNIT-scale))+i-(x/2), (30*(FRACUNIT-scale))+j-(y/2), scale, trans<<V_ALPHASHIFT, endxpld[0],
#endif
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)
{
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[7][0][0] < 30<<FRACBITS) ? FRACUNIT : -FRACUNIT);
y += ((sparkloffs[7][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
{
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);
}
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[7][0][0], y + sparkloffs[7][0][1],
FRACUNIT, 0, endxpld[sparklloop/4], NULL);
}
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]);
}
if (goodending && finalecount >= TICRATE && finalecount < INFLECTIONPOINT)
{
INT32 workingtime = finalecount - TICRATE;
fixed_t radius[4];
angle_t fa;
INT32 eemeralds_cur[4];
char patchname[7] = "CEMGx0";
for (i = 0; i < 4; ++i)
{
if (i == 1)
workingtime -= sparklloop;
else if (i)
workingtime -= SPARKLLOOPTIME;
eemeralds_cur[i] = workingtime % 360;
radius[i] = ((vid.width/vid.dupx)*(INFLECTIONPOINT - TICRATE - workingtime))/(INFLECTIONPOINT - TICRATE);
radius[i] <<= FRACBITS;
}
for (i = 0; i < 7; ++i)
{
fa = (FixedAngle(eemeralds_cur[0]*FRACUNIT)>>ANGLETOFINESHIFT) & FINEMASK;
x = (BASEVIDWIDTH<<(FRACBITS-1)) + FixedMul(FINECOSINE(fa),radius[0]);
y = ((BASEVIDHEIGHT+16)<<(FRACBITS-1)) + FixedMul(FINESINE(fa),radius[0]);
eemeralds_cur[0] += INTERVAL;
if (i & 1)
eemeralds_cur[0]++;
patchname[4] = 'A'+(char)i;
V_DrawFixedPatch(x, y, FRACUNIT, 0, W_CachePatchName(patchname, PU_LEVEL), NULL);
}
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]*FRACUNIT)>>ANGLETOFINESHIFT) & FINEMASK;
x = (BASEVIDWIDTH<<(FRACBITS-1)) + FixedMul(FINECOSINE(fa),radius[j]) + sparkloffs[i][j-1][0];
y = ((BASEVIDHEIGHT+16)<<(FRACBITS-1)) + FixedMul(FINESINE(fa),radius[j]) + sparkloffs[i][j-1][1];
eemeralds_cur[j] += INTERVAL;
if (i & 1)
eemeralds_cur[j]++;
// 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--;
}
}
} // 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)
{
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);
}
}
}
// ========== // ==========
// GAME END // GAME END
// ========== // ==========
@ -1378,6 +2022,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 +2537,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 +2649,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 +2690,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);
@ -126,6 +130,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
@ -142,15 +147,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

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

@ -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,12 +689,191 @@ 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); 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;
if (w < 0 || h < 0)
return; // consistency w/ software
// 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);
}
// Draw the console background with translucency support // Draw the console background with translucency support
void HWR_DrawConsoleBack(UINT32 color, INT32 height) void HWR_DrawConsoleBack(UINT32 color, INT32 height)
{ {
@ -905,6 +1090,8 @@ 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;
UINT8 perplayershuffle = 0;
if (w < 0 || h < 0) if (w < 0 || h < 0)
return; // consistency w/ software return; // consistency w/ software
@ -913,46 +1100,110 @@ void HWR_DrawConsoleFill(INT32 x, INT32 y, INT32 w, INT32 h, UINT32 color, INT32
// |/ | // |/ |
// 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;
} }
} }

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

@ -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",
@ -131,24 +125,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

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

@ -3437,13 +3437,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

@ -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
@ -2503,6 +2507,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
@ -2525,8 +2532,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:
@ -2537,6 +2546,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;
} }
@ -2556,9 +2568,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;
@ -2988,7 +2997,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
@ -3018,7 +3027,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)
@ -3094,24 +3103,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);
@ -3130,6 +3121,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();
@ -3140,9 +3132,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);
@ -3265,6 +3254,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

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

@ -226,7 +226,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)
@ -341,10 +341,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;
} }
@ -353,7 +367,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)
@ -1349,13 +1361,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 +1384,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 +1483,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 +1495,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 +1521,208 @@ 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 0 // only if for use in-game, otherwise not worth the processor time
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;
}
}
}
#endif
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);