Merge remote-tracking branch 'origin/master' into musicplus-sdlmixerx

This commit is contained in:
mazmazz 2019-08-04 01:10:21 -04:00
commit b99f06c0c9
57 changed files with 2365 additions and 572 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.
@ -5699,7 +5702,8 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
"S_CEZFLOWER", "S_CEZFLOWER",
"S_CEZPOLE", "S_CEZPOLE",
"S_CEZBANNER", "S_CEZBANNER1",
"S_CEZBANNER2",
"S_PINETREE", "S_PINETREE",
"S_CEZBUSH1", "S_CEZBUSH1",
"S_CEZBUSH2", "S_CEZBUSH2",
@ -5708,7 +5712,8 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
"S_FLAMEHOLDER", "S_FLAMEHOLDER",
"S_FIRETORCH", "S_FIRETORCH",
"S_WAVINGFLAG", "S_WAVINGFLAG",
"S_WAVINGFLAGSEG", "S_WAVINGFLAGSEG1",
"S_WAVINGFLAGSEG2",
"S_CRAWLASTATUE", "S_CRAWLASTATUE",
"S_FACESTABBERSTATUE", "S_FACESTABBERSTATUE",
"S_SUSPICIOUSFACESTABBERSTATUE_WAIT", "S_SUSPICIOUSFACESTABBERSTATUE_WAIT",
@ -7514,8 +7519,10 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s
"MT_SMALLFIREBAR", // Small Firebar "MT_SMALLFIREBAR", // Small Firebar
"MT_BIGFIREBAR", // Big Firebar "MT_BIGFIREBAR", // Big Firebar
"MT_CEZFLOWER", // Flower "MT_CEZFLOWER", // Flower
"MT_CEZPOLE", // Pole "MT_CEZPOLE1", // Pole (with red banner)
"MT_CEZBANNER", // Banner "MT_CEZPOLE2", // Pole (with blue banner)
"MT_CEZBANNER1", // Banner (red)
"MT_CEZBANNER2", // Banner (blue)
"MT_PINETREE", // Pine Tree "MT_PINETREE", // Pine Tree
"MT_CEZBUSH1", // Bush 1 "MT_CEZBUSH1", // Bush 1
"MT_CEZBUSH2", // Bush 2 "MT_CEZBUSH2", // Bush 2
@ -7523,8 +7530,10 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s
"MT_CANDLEPRICKET", // Candle pricket "MT_CANDLEPRICKET", // Candle pricket
"MT_FLAMEHOLDER", // Flame holder "MT_FLAMEHOLDER", // Flame holder
"MT_FIRETORCH", // Fire torch "MT_FIRETORCH", // Fire torch
"MT_WAVINGFLAG", // Waving flag "MT_WAVINGFLAG1", // Waving flag (red)
"MT_WAVINGFLAGSEG", // Waving flag segment "MT_WAVINGFLAG2", // Waving flag (blue)
"MT_WAVINGFLAGSEG1", // Waving flag segment (red)
"MT_WAVINGFLAGSEG2", // Waving flag segment (blue)
"MT_CRAWLASTATUE", // Crawla statue "MT_CRAWLASTATUE", // Crawla statue
"MT_FACESTABBERSTATUE", // Facestabber statue "MT_FACESTABBERSTATUE", // Facestabber statue
"MT_SUSPICIOUSFACESTABBERSTATUE", // :eggthinking: "MT_SUSPICIOUSFACESTABBERSTATUE", // :eggthinking:
@ -9493,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; {
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", 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 (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)
{
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) for (i = 0; i < 7; ++i)
{ {
fa = (FixedAngle(eemeralds_cur*FRACUNIT)>>ANGLETOFINESHIFT) & FINEMASK; fa = (FixedAngle(eemeralds_cur)>>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 += (360<<FRACBITS)/7;
patchname[4] = 'A'+(char)i; patchname[4] = 'A'+(char)i;
if (emeralds & (1<<i)) V_DrawFixedPatch(x, y, FRACUNIT, ((emeralds & (1<<i)) ? 0 : V_80TRANS), 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();
}
} }
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);
@ -82,7 +86,6 @@ typedef enum
// Current menu parameters // Current menu parameters
extern UINT8 titlemapinaction;
extern mobj_t *titlemapcameraref; extern mobj_t *titlemapcameraref;
extern char curbgname[8]; extern char curbgname[8];
extern SINT8 curfadevalue; extern SINT8 curfadevalue;
@ -126,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
@ -142,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;
@ -4366,7 +4381,7 @@ void G_WriteGhostTic(mobj_t *ghost)
ghostext.flags = 0; ghostext.flags = 0;
} }
if (ghost->player && ghost->player->followmobj) if (ghost->player && ghost->player->followmobj) // bloats tails runs but what can ya do
{ {
INT16 temp; INT16 temp;
@ -4592,6 +4607,9 @@ void G_GhostTicker(void)
switch(g->color) switch(g->color)
{ {
default: default:
case GHC_RETURNSKIN:
g->mo->skin = g->oldmo.skin;
// fallthru
case GHC_NORMAL: // Go back to skin color case GHC_NORMAL: // Go back to skin color
g->mo->color = g->oldmo.color; g->mo->color = g->oldmo.color;
break; break;
@ -4602,6 +4620,9 @@ void G_GhostTicker(void)
case GHC_FIREFLOWER: // Fireflower case GHC_FIREFLOWER: // Fireflower
g->mo->color = SKINCOLOR_WHITE; g->mo->color = SKINCOLOR_WHITE;
break; break;
case GHC_NIGHTSSKIN: // not actually a colour
g->mo->skin = &skins[DEFAULTNIGHTSSKIN];
break;
} }
} }
if (xziptic & EZT_FLIP) if (xziptic & EZT_FLIP)

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;
@ -140,7 +142,9 @@ typedef enum
GHC_NORMAL = 0, GHC_NORMAL = 0,
GHC_SUPER, GHC_SUPER,
GHC_FIREFLOWER, GHC_FIREFLOWER,
GHC_INVINCIBLE GHC_INVINCIBLE,
GHC_NIGHTSSKIN, // not actually a colour
GHC_RETURNSKIN // ditto
} ghostcolor_t; } ghostcolor_t;
// Record/playback tics // Record/playback tics

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
@ -50,6 +52,7 @@ typedef enum
} gameaction_t; } gameaction_t;
extern gamestate_t gamestate; extern gamestate_t gamestate;
extern UINT8 titlemapinaction;
extern UINT8 ultimatemode; // was sk_insane extern UINT8 ultimatemode; // was sk_insane
extern gameaction_t gameaction; extern gameaction_t gameaction;

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]));
if (!column->topdelta)
{
const UINT8 *source = (const UINT8 *)(column) + 3; const UINT8 *source = (const UINT8 *)(column) + 3;
HWR_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, (column->topdelta == 0xff ? 31 : source[0])); 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]));
if (!column->topdelta)
{
const UINT8 *source = (const UINT8 *)(column) + 3; const UINT8 *source = (const UINT8 *)(column) + 3;
HWR_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, (column->topdelta == 0xff ? 31 : source[0])); 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)
@ -1791,7 +1793,11 @@ state_t states[NUMSTATES] =
// Blue Sphere for special stages // Blue Sphere for special stages
{SPR_SPHR, FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_BLUESPHERE {SPR_SPHR, FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_BLUESPHERE
{SPR_SPHR, FF_FULLBRIGHT|FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 1, 4, S_NULL}, // S_BLUESPHEREBONUS {SPR_SPHR, FF_FULLBRIGHT
#ifdef MANIASPHERES
|FF_ANIMATE|FF_RANDOMANIM
#endif
, -1, {NULL}, 1, 4, S_NULL}, // S_BLUESPHEREBONUS
{SPR_SPHR, 0, 20, {NULL}, 0, 0, S_NULL}, // S_BLUESPHERESPARK {SPR_SPHR, 0, 20, {NULL}, 0, 0, S_NULL}, // S_BLUESPHERESPARK
// Bomb Sphere // Bomb Sphere
@ -2322,9 +2328,10 @@ state_t states[NUMSTATES] =
{SPR_BFBR, FF_FULLBRIGHT|15, 1, {NULL}, 0, 0, S_BIGFIREBAR1}, // S_BIGFIREBAR16 {SPR_BFBR, FF_FULLBRIGHT|15, 1, {NULL}, 0, 0, S_BIGFIREBAR1}, // S_BIGFIREBAR16
{SPR_FWR4, 0, -1, {NULL}, 0, 0, S_NULL}, // S_CEZFLOWER {SPR_FWR4, 0, -1, {NULL}, 0, 0, S_NULL}, // S_CEZFLOWER
{SPR_BANR, 1, -1, {NULL}, 0, 0, S_NULL}, // S_CEZPOLE {SPR_BANR, 0, -1, {NULL}, 0, 0, S_NULL}, // S_CEZPOLE
{SPR_BANR, FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL}, // S_CEZBANNER {SPR_BANR, FF_PAPERSPRITE|1, -1, {NULL}, 0, 0, S_NULL}, // S_CEZBANNER1
{SPR_BANR, FF_PAPERSPRITE|2, -1, {NULL}, 0, 0, S_NULL}, // S_CEZBANNER2
{SPR_PINE, 0, -1, {NULL}, 0, 0, S_NULL}, // S_PINETREE {SPR_PINE, 0, -1, {NULL}, 0, 0, S_NULL}, // S_PINETREE
{SPR_CEZB, 0, -1, {NULL}, 0, 0, S_NULL}, // S_CEZBUSH1 {SPR_CEZB, 0, -1, {NULL}, 0, 0, S_NULL}, // S_CEZBUSH1
@ -2338,7 +2345,8 @@ state_t states[NUMSTATES] =
{SPR_CTRC, FF_FULLBRIGHT|FF_ANIMATE, 8*3, {A_FlameParticle}, 3, 3, S_FIRETORCH}, // S_FIRETORCH {SPR_CTRC, FF_FULLBRIGHT|FF_ANIMATE, 8*3, {A_FlameParticle}, 3, 3, S_FIRETORCH}, // S_FIRETORCH
{SPR_CFLG, 0, -1, {NULL}, 0, 0, S_NULL}, // S_WAVINGFLAG {SPR_CFLG, 0, -1, {NULL}, 0, 0, S_NULL}, // S_WAVINGFLAG
{SPR_CFLG, FF_PAPERSPRITE|1, -1, {NULL}, 0, 0, S_NULL}, // S_WAVINGFLAGSEG {SPR_CFLG, FF_PAPERSPRITE|1, -1, {NULL}, 0, 0, S_NULL}, // S_WAVINGFLAGSEG1
{SPR_CFLG, FF_PAPERSPRITE|2, -1, {NULL}, 0, 0, S_NULL}, // S_WAVINGFLAGSEG2
{SPR_CSTA, 0, -1, {NULL}, 0, 0, S_NULL}, // S_CRAWLASTATUE {SPR_CSTA, 0, -1, {NULL}, 0, 0, S_NULL}, // S_CRAWLASTATUE
@ -11018,7 +11026,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_NULL // raisestate S_NULL // raisestate
}, },
{ // MT_CEZPOLE { // MT_CEZPOLE1
1117, // doomednum 1117, // doomednum
S_CEZPOLE, // spawnstate S_CEZPOLE, // spawnstate
1000, // spawnhealth 1000, // spawnhealth
@ -11045,9 +11053,63 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_NULL // raisestate S_NULL // raisestate
}, },
{ // MT_CEZBANNER { // MT_CEZPOLE2
1118, // doomednum
S_CEZPOLE, // spawnstate
1000, // spawnhealth
S_NULL, // seestate
sfx_None, // seesound
8, // reactiontime
sfx_None, // attacksound
S_NULL, // painstate
0, // painchance
sfx_None, // painsound
S_NULL, // meleestate
S_NULL, // missilestate
S_NULL, // deathstate
S_NULL, // xdeathstate
sfx_None, // deathsound
0, // speed
40*FRACUNIT, // radius
224*FRACUNIT, // height
0, // display offset
100, // mass
0, // damage
sfx_None, // activesound
MF_NOTHINK|MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY, // flags
S_NULL // raisestate
},
{ // MT_CEZBANNER1
-1, // doomednum -1, // doomednum
S_CEZBANNER, // spawnstate S_CEZBANNER1, // spawnstate
1000, // spawnhealth
S_NULL, // seestate
sfx_None, // seesound
8, // reactiontime
sfx_None, // attacksound
S_NULL, // painstate
0, // painchance
sfx_None, // painsound
S_NULL, // meleestate
S_NULL, // missilestate
S_NULL, // deathstate
S_NULL, // xdeathstate
sfx_None, // deathsound
0, // speed
40*FRACUNIT, // radius
224*FRACUNIT, // height
0, // display offset
100, // mass
0, // damage
sfx_None, // activesound
MF_NOTHINK|MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY, // flags
S_NULL // raisestate
},
{ // MT_CEZBANNER2
-1, // doomednum
S_CEZBANNER2, // spawnstate
1000, // spawnhealth 1000, // spawnhealth
S_NULL, // seestate S_NULL, // seestate
sfx_None, // seesound sfx_None, // seesound
@ -11261,8 +11323,8 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_NULL // raisestate S_NULL // raisestate
}, },
{ // MT_WAVINGFLAG { // MT_WAVINGFLAG1
1118, // doomednum 1128, // doomednum
S_WAVINGFLAG, // spawnstate S_WAVINGFLAG, // spawnstate
1000, // spawnhealth 1000, // spawnhealth
S_NULL, // seestate S_NULL, // seestate
@ -11278,8 +11340,8 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_NULL, // xdeathstate S_NULL, // xdeathstate
sfx_None, // deathsound sfx_None, // deathsound
0, // speed 0, // speed
4*FRACUNIT, // radius 8*FRACUNIT, // radius
104*FRACUNIT, // height 208*FRACUNIT, // height
0, // display offset 0, // display offset
100, // mass 100, // mass
0, // damage 0, // damage
@ -11288,9 +11350,9 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_NULL // raisestate S_NULL // raisestate
}, },
{ // MT_WAVINGFLAGSEG { // MT_WAVINGFLAG2
-1, // doomednum 1129, // doomednum
S_WAVINGFLAGSEG, // spawnstate S_WAVINGFLAG, // spawnstate
1000, // spawnhealth 1000, // spawnhealth
S_NULL, // seestate S_NULL, // seestate
sfx_None, // seesound sfx_None, // seesound
@ -11305,7 +11367,61 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_NULL, // xdeathstate S_NULL, // xdeathstate
sfx_None, // deathsound sfx_None, // deathsound
0, // speed 0, // speed
4*FRACUNIT, // radius 8*FRACUNIT, // radius
208*FRACUNIT, // height
0, // display offset
100, // mass
0, // damage
sfx_None, // activesound
MF_SOLID, // flags
S_NULL // raisestate
},
{ // MT_WAVINGFLAGSEG1
-1, // doomednum
S_WAVINGFLAGSEG1, // spawnstate
1000, // spawnhealth
S_NULL, // seestate
sfx_None, // seesound
8, // reactiontime
sfx_None, // attacksound
S_NULL, // painstate
0, // painchance
sfx_None, // painsound
S_NULL, // meleestate
S_NULL, // missilestate
S_NULL, // deathstate
S_NULL, // xdeathstate
sfx_None, // deathsound
0, // speed
8*FRACUNIT, // radius
1, // height -- this is not a typo
0, // display offset
100, // mass
0, // damage
sfx_None, // activesound
MF_NOTHINK|MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_SCENERY, // flags
S_NULL // raisestate
},
{ // MT_WAVINGFLAGSEG2
-1, // doomednum
S_WAVINGFLAGSEG2, // spawnstate
1000, // spawnhealth
S_NULL, // seestate
sfx_None, // seesound
8, // reactiontime
sfx_None, // attacksound
S_NULL, // painstate
0, // painchance
sfx_None, // painsound
S_NULL, // meleestate
S_NULL, // missilestate
S_NULL, // deathstate
S_NULL, // xdeathstate
sfx_None, // deathsound
0, // speed
8*FRACUNIT, // radius
1, // height -- this is not a typo 1, // height -- this is not a typo
0, // display offset 0, // display offset
100, // mass 100, // mass

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,
@ -2458,7 +2459,8 @@ typedef enum state
S_CEZFLOWER, S_CEZFLOWER,
S_CEZPOLE, S_CEZPOLE,
S_CEZBANNER, S_CEZBANNER1,
S_CEZBANNER2,
S_PINETREE, S_PINETREE,
S_CEZBUSH1, S_CEZBUSH1,
S_CEZBUSH2, S_CEZBUSH2,
@ -2467,7 +2469,8 @@ typedef enum state
S_FLAMEHOLDER, S_FLAMEHOLDER,
S_FIRETORCH, S_FIRETORCH,
S_WAVINGFLAG, S_WAVINGFLAG,
S_WAVINGFLAGSEG, S_WAVINGFLAGSEG1,
S_WAVINGFLAGSEG2,
S_CRAWLASTATUE, S_CRAWLASTATUE,
S_FACESTABBERSTATUE, S_FACESTABBERSTATUE,
S_SUSPICIOUSFACESTABBERSTATUE_WAIT, S_SUSPICIOUSFACESTABBERSTATUE_WAIT,
@ -4295,8 +4298,10 @@ typedef enum mobj_type
MT_SMALLFIREBAR, // Small Firebar MT_SMALLFIREBAR, // Small Firebar
MT_BIGFIREBAR, // Big Firebar MT_BIGFIREBAR, // Big Firebar
MT_CEZFLOWER, // Flower MT_CEZFLOWER, // Flower
MT_CEZPOLE, // Pole MT_CEZPOLE1, // Pole (with red banner)
MT_CEZBANNER, // Banner MT_CEZPOLE2, // Pole (with blue banner)
MT_CEZBANNER1, // Banner (red)
MT_CEZBANNER2, // Banner (blue)
MT_PINETREE, // Pine Tree MT_PINETREE, // Pine Tree
MT_CEZBUSH1, // Bush 1 MT_CEZBUSH1, // Bush 1
MT_CEZBUSH2, // Bush 2 MT_CEZBUSH2, // Bush 2
@ -4304,8 +4309,10 @@ typedef enum mobj_type
MT_CANDLEPRICKET, // Candle pricket MT_CANDLEPRICKET, // Candle pricket
MT_FLAMEHOLDER, // Flame holder MT_FLAMEHOLDER, // Flame holder
MT_FIRETORCH, // Fire torch MT_FIRETORCH, // Fire torch
MT_WAVINGFLAG, // Waving flag MT_WAVINGFLAG1, // Waving flag (red)
MT_WAVINGFLAGSEG, // Waving flag segment MT_WAVINGFLAG2, // Waving flag (blue)
MT_WAVINGFLAGSEG1, // Waving flag segment (red)
MT_WAVINGFLAGSEG2, // Waving flag segment (blue)
MT_CRAWLASTATUE, // Crawla statue MT_CRAWLASTATUE, // Crawla statue
MT_FACESTABBERSTATUE, // Facestabber statue MT_FACESTABBERSTATUE, // Facestabber statue
MT_SUSPICIOUSFACESTABBERSTATUE, // :eggthinking: MT_SUSPICIOUSFACESTABBERSTATUE, // :eggthinking:

View file

@ -33,8 +33,6 @@
#define NOHUD if (hud_running)\ #define NOHUD if (hud_running)\
return luaL_error(L, "HUD rendering code should not call this function!"); return luaL_error(L, "HUD rendering code should not call this function!");
#define INLEVEL if (gamestate != GS_LEVEL)\
return luaL_error(L, "This function can only be used in a level!");
boolean luaL_checkboolean(lua_State *L, int narg) { boolean luaL_checkboolean(lua_State *L, int narg) {
luaL_checktype(L, narg, LUA_TBOOLEAN); luaL_checktype(L, narg, LUA_TBOOLEAN);
@ -2047,12 +2045,22 @@ static int lib_pStartQuake(lua_State *L)
static int lib_evCrumbleChain(lua_State *L) static int lib_evCrumbleChain(lua_State *L)
{ {
sector_t *sec = *((sector_t **)luaL_checkudata(L, 1, META_SECTOR)); sector_t *sec = NULL;
ffloor_t *rover = *((ffloor_t **)luaL_checkudata(L, 2, META_FFLOOR)); ffloor_t *rover = NULL;
NOHUD NOHUD
INLEVEL INLEVEL
if (!lua_isnone(L, 2))
{
if (!lua_isnil(L, 1))
{
sec = *((sector_t **)luaL_checkudata(L, 1, META_SECTOR));
if (!sec) if (!sec)
return LUA_ErrInvalid(L, "sector_t"); return LUA_ErrInvalid(L, "sector_t");
}
rover = *((ffloor_t **)luaL_checkudata(L, 2, META_FFLOOR));
}
else
rover = *((ffloor_t **)luaL_checkudata(L, 1, META_FFLOOR));
if (!rover) if (!rover)
return LUA_ErrInvalid(L, "ffloor_t"); return LUA_ErrInvalid(L, "ffloor_t");
EV_CrumbleChain(sec, rover); EV_CrumbleChain(sec, rover);
@ -2601,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

@ -28,9 +28,6 @@ return luaL_error(L, "HUD rendering code should not call this function!");
// for functions not allowed in hooks or coroutines (supercedes above) // for functions not allowed in hooks or coroutines (supercedes above)
#define NOHOOK if (!lua_lumploading)\ #define NOHOOK if (!lua_lumploading)\
return luaL_error(L, "This function cannot be called from within a hook or coroutine!"); return luaL_error(L, "This function cannot be called from within a hook or coroutine!");
// for functions only allowed within a level
#define INLEVEL if (gamestate != GS_LEVEL)\
return luaL_error(L, "This function can only be used in a level!");
static const char *cvname = NULL; static const char *cvname = NULL;

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

@ -333,8 +333,7 @@ static int lib_iterateSectorThinglist(lua_State *L)
mobj_t *state = NULL; mobj_t *state = NULL;
mobj_t *thing = NULL; mobj_t *thing = NULL;
if (gamestate != GS_LEVEL) INLEVEL
return luaL_error(L, "This function can only be used in a level!");
if (lua_gettop(L) < 2) if (lua_gettop(L) < 2)
return luaL_error(L, "Don't call sector.thinglist() directly, use it as 'for rover in sector.thinglist do <block> end'."); return luaL_error(L, "Don't call sector.thinglist() directly, use it as 'for rover in sector.thinglist do <block> end'.");
@ -369,8 +368,7 @@ static int lib_iterateSectorFFloors(lua_State *L)
ffloor_t *state = NULL; ffloor_t *state = NULL;
ffloor_t *ffloor = NULL; ffloor_t *ffloor = NULL;
if (gamestate != GS_LEVEL) INLEVEL
return luaL_error(L, "This function can only be used in a level!");
if (lua_gettop(L) < 2) if (lua_gettop(L) < 2)
return luaL_error(L, "Don't call sector.ffloors() directly, use it as 'for rover in sector.ffloors do <block> end'."); return luaL_error(L, "Don't call sector.ffloors() directly, use it as 'for rover in sector.ffloors do <block> end'.");
@ -1251,8 +1249,7 @@ static int bbox_get(lua_State *L)
static int lib_iterateSectors(lua_State *L) static int lib_iterateSectors(lua_State *L)
{ {
size_t i = 0; size_t i = 0;
if (gamestate != GS_LEVEL) INLEVEL
return luaL_error(L, "This function can only be used in a level!");
if (lua_gettop(L) < 2) if (lua_gettop(L) < 2)
return luaL_error(L, "Don't call sectors.iterate() directly, use it as 'for sector in sectors.iterate do <block> end'."); return luaL_error(L, "Don't call sectors.iterate() directly, use it as 'for sector in sectors.iterate do <block> end'.");
lua_settop(L, 2); lua_settop(L, 2);
@ -1270,8 +1267,7 @@ static int lib_iterateSectors(lua_State *L)
static int lib_getSector(lua_State *L) static int lib_getSector(lua_State *L)
{ {
int field; int field;
if (gamestate != GS_LEVEL) INLEVEL
return luaL_error(L, "You cannot access this outside of a level!");
lua_settop(L, 2); lua_settop(L, 2);
lua_remove(L, 1); // dummy userdata table is unused. lua_remove(L, 1); // dummy userdata table is unused.
if (lua_isnumber(L, 1)) if (lua_isnumber(L, 1))
@ -1305,8 +1301,7 @@ static int lib_numsectors(lua_State *L)
static int lib_iterateSubsectors(lua_State *L) static int lib_iterateSubsectors(lua_State *L)
{ {
size_t i = 0; size_t i = 0;
if (gamestate != GS_LEVEL) INLEVEL
return luaL_error(L, "This function can only be used in a level!");
if (lua_gettop(L) < 2) if (lua_gettop(L) < 2)
return luaL_error(L, "Don't call subsectors.iterate() directly, use it as 'for subsector in subsectors.iterate do <block> end'."); return luaL_error(L, "Don't call subsectors.iterate() directly, use it as 'for subsector in subsectors.iterate do <block> end'.");
lua_settop(L, 2); lua_settop(L, 2);
@ -1324,8 +1319,7 @@ static int lib_iterateSubsectors(lua_State *L)
static int lib_getSubsector(lua_State *L) static int lib_getSubsector(lua_State *L)
{ {
int field; int field;
if (gamestate != GS_LEVEL) INLEVEL
return luaL_error(L, "You cannot access this outside of a level!");
lua_settop(L, 2); lua_settop(L, 2);
lua_remove(L, 1); // dummy userdata table is unused. lua_remove(L, 1); // dummy userdata table is unused.
if (lua_isnumber(L, 1)) if (lua_isnumber(L, 1))
@ -1359,8 +1353,7 @@ static int lib_numsubsectors(lua_State *L)
static int lib_iterateLines(lua_State *L) static int lib_iterateLines(lua_State *L)
{ {
size_t i = 0; size_t i = 0;
if (gamestate != GS_LEVEL) INLEVEL
return luaL_error(L, "This function can only be used in a level!");
if (lua_gettop(L) < 2) if (lua_gettop(L) < 2)
return luaL_error(L, "Don't call lines.iterate() directly, use it as 'for line in lines.iterate do <block> end'."); return luaL_error(L, "Don't call lines.iterate() directly, use it as 'for line in lines.iterate do <block> end'.");
lua_settop(L, 2); lua_settop(L, 2);
@ -1378,8 +1371,7 @@ static int lib_iterateLines(lua_State *L)
static int lib_getLine(lua_State *L) static int lib_getLine(lua_State *L)
{ {
int field; int field;
if (gamestate != GS_LEVEL) INLEVEL
return luaL_error(L, "You cannot access this outside of a level!");
lua_settop(L, 2); lua_settop(L, 2);
lua_remove(L, 1); // dummy userdata table is unused. lua_remove(L, 1); // dummy userdata table is unused.
if (lua_isnumber(L, 1)) if (lua_isnumber(L, 1))
@ -1413,8 +1405,7 @@ static int lib_numlines(lua_State *L)
static int lib_iterateSides(lua_State *L) static int lib_iterateSides(lua_State *L)
{ {
size_t i = 0; size_t i = 0;
if (gamestate != GS_LEVEL) INLEVEL
return luaL_error(L, "This function can only be used in a level!");
if (lua_gettop(L) < 2) if (lua_gettop(L) < 2)
return luaL_error(L, "Don't call sides.iterate() directly, use it as 'for side in sides.iterate do <block> end'."); return luaL_error(L, "Don't call sides.iterate() directly, use it as 'for side in sides.iterate do <block> end'.");
lua_settop(L, 2); lua_settop(L, 2);
@ -1432,8 +1423,7 @@ static int lib_iterateSides(lua_State *L)
static int lib_getSide(lua_State *L) static int lib_getSide(lua_State *L)
{ {
int field; int field;
if (gamestate != GS_LEVEL) INLEVEL
return luaL_error(L, "You cannot access this outside of a level!");
lua_settop(L, 2); lua_settop(L, 2);
lua_remove(L, 1); // dummy userdata table is unused. lua_remove(L, 1); // dummy userdata table is unused.
if (lua_isnumber(L, 1)) if (lua_isnumber(L, 1))
@ -1467,8 +1457,7 @@ static int lib_numsides(lua_State *L)
static int lib_iterateVertexes(lua_State *L) static int lib_iterateVertexes(lua_State *L)
{ {
size_t i = 0; size_t i = 0;
if (gamestate != GS_LEVEL) INLEVEL
return luaL_error(L, "This function can only be used in a level!");
if (lua_gettop(L) < 2) if (lua_gettop(L) < 2)
return luaL_error(L, "Don't call vertexes.iterate() directly, use it as 'for vertex in vertexes.iterate do <block> end'."); return luaL_error(L, "Don't call vertexes.iterate() directly, use it as 'for vertex in vertexes.iterate do <block> end'.");
lua_settop(L, 2); lua_settop(L, 2);
@ -1486,8 +1475,7 @@ static int lib_iterateVertexes(lua_State *L)
static int lib_getVertex(lua_State *L) static int lib_getVertex(lua_State *L)
{ {
int field; int field;
if (gamestate != GS_LEVEL) INLEVEL
return luaL_error(L, "You cannot access this outside of a level!");
lua_settop(L, 2); lua_settop(L, 2);
lua_remove(L, 1); // dummy userdata table is unused. lua_remove(L, 1); // dummy userdata table is unused.
if (lua_isnumber(L, 1)) if (lua_isnumber(L, 1))
@ -1523,8 +1511,7 @@ static int lib_numvertexes(lua_State *L)
static int lib_iterateSegs(lua_State *L) static int lib_iterateSegs(lua_State *L)
{ {
size_t i = 0; size_t i = 0;
if (gamestate != GS_LEVEL) INLEVEL
return luaL_error(L, "This function can only be used in a level!");
if (lua_gettop(L) < 2) if (lua_gettop(L) < 2)
return luaL_error(L, "Don't call segs.iterate() directly, use it as 'for seg in segs.iterate do <block> end'."); return luaL_error(L, "Don't call segs.iterate() directly, use it as 'for seg in segs.iterate do <block> end'.");
lua_settop(L, 2); lua_settop(L, 2);
@ -1542,8 +1529,7 @@ static int lib_iterateSegs(lua_State *L)
static int lib_getSeg(lua_State *L) static int lib_getSeg(lua_State *L)
{ {
int field; int field;
if (gamestate != GS_LEVEL) INLEVEL
return luaL_error(L, "You cannot access this outside of a level!");
lua_settop(L, 2); lua_settop(L, 2);
lua_remove(L, 1); // dummy userdata table is unused. lua_remove(L, 1); // dummy userdata table is unused.
if (lua_isnumber(L, 1)) if (lua_isnumber(L, 1))
@ -1577,8 +1563,7 @@ static int lib_numsegs(lua_State *L)
static int lib_iterateNodes(lua_State *L) static int lib_iterateNodes(lua_State *L)
{ {
size_t i = 0; size_t i = 0;
if (gamestate != GS_LEVEL) INLEVEL
return luaL_error(L, "This function can only be used in a level!");
if (lua_gettop(L) < 2) if (lua_gettop(L) < 2)
return luaL_error(L, "Don't call nodes.iterate() directly, use it as 'for node in nodes.iterate do <block> end'."); return luaL_error(L, "Don't call nodes.iterate() directly, use it as 'for node in nodes.iterate do <block> end'.");
lua_settop(L, 2); lua_settop(L, 2);
@ -1596,8 +1581,7 @@ static int lib_iterateNodes(lua_State *L)
static int lib_getNode(lua_State *L) static int lib_getNode(lua_State *L)
{ {
int field; int field;
if (gamestate != GS_LEVEL) INLEVEL
return luaL_error(L, "You cannot access this outside of a level!");
lua_settop(L, 2); lua_settop(L, 2);
lua_remove(L, 1); // dummy userdata table is unused. lua_remove(L, 1); // dummy userdata table is unused.
if (lua_isnumber(L, 1)) if (lua_isnumber(L, 1))

View file

@ -804,7 +804,12 @@ static int mapthing_set(lua_State *L)
else if(fastcmp(field,"z")) else if(fastcmp(field,"z"))
mt->z = (INT16)luaL_checkinteger(L, 3); mt->z = (INT16)luaL_checkinteger(L, 3);
else if(fastcmp(field,"extrainfo")) else if(fastcmp(field,"extrainfo"))
mt->extrainfo = (UINT8)luaL_checkinteger(L, 3); {
INT32 extrainfo = luaL_checkinteger(L, 3);
if (extrainfo & ~15)
return luaL_error(L, "mapthing_t extrainfo set %d out of range (%d - %d)", extrainfo, 0, 15);
mt->extrainfo = (UINT8)extrainfo;
}
else if(fastcmp(field,"mobj")) else if(fastcmp(field,"mobj"))
mt->mobj = *((mobj_t **)luaL_checkudata(L, 3, META_MOBJ)); mt->mobj = *((mobj_t **)luaL_checkudata(L, 3, META_MOBJ));
else else
@ -816,8 +821,7 @@ static int mapthing_set(lua_State *L)
static int lib_iterateMapthings(lua_State *L) static int lib_iterateMapthings(lua_State *L)
{ {
size_t i = 0; size_t i = 0;
if (gamestate != GS_LEVEL) INLEVEL
return luaL_error(L, "This function can only be used in a level!");
if (lua_gettop(L) < 2) if (lua_gettop(L) < 2)
return luaL_error(L, "Don't call mapthings.iterate() directly, use it as 'for mapthing in mapthings.iterate do <block> end'."); return luaL_error(L, "Don't call mapthings.iterate() directly, use it as 'for mapthing in mapthings.iterate do <block> end'.");
lua_settop(L, 2); lua_settop(L, 2);
@ -835,8 +839,7 @@ static int lib_iterateMapthings(lua_State *L)
static int lib_getMapthing(lua_State *L) static int lib_getMapthing(lua_State *L)
{ {
int field; int field;
if (gamestate != GS_LEVEL) INLEVEL
return luaL_error(L, "You cannot access this outside of a level!");
lua_settop(L, 2); lua_settop(L, 2);
lua_remove(L, 1); // dummy userdata table is unused. lua_remove(L, 1); // dummy userdata table is unused.
if (lua_isnumber(L, 1)) if (lua_isnumber(L, 1))

View file

@ -25,8 +25,7 @@
static int lib_iteratePlayers(lua_State *L) static int lib_iteratePlayers(lua_State *L)
{ {
INT32 i = -1; INT32 i = -1;
if (gamestate != GS_LEVEL) INLEVEL
return luaL_error(L, "This function can only be used in a level!");
if (lua_gettop(L) < 2) if (lua_gettop(L) < 2)
{ {
//return luaL_error(L, "Don't call players.iterate() directly, use it as 'for player in players.iterate do <block> end'."); //return luaL_error(L, "Don't call players.iterate() directly, use it as 'for player in players.iterate do <block> end'.");
@ -53,8 +52,7 @@ static int lib_getPlayer(lua_State *L)
{ {
const char *field; const char *field;
// i -> players[i] // i -> players[i]
if (gamestate != GS_LEVEL) INLEVEL
return luaL_error(L, "You cannot access this outside of a level!");
if (lua_type(L, 2) == LUA_TNUMBER) if (lua_type(L, 2) == LUA_TNUMBER)
{ {
lua_Integer i = luaL_checkinteger(L, 2); lua_Integer i = luaL_checkinteger(L, 2);

View file

@ -15,6 +15,7 @@
#include "m_fixed.h" #include "m_fixed.h"
#include "doomtype.h" #include "doomtype.h"
#include "d_player.h" #include "d_player.h"
#include "g_state.h"
#include "blua/lua.h" #include "blua/lua.h"
#include "blua/lualib.h" #include "blua/lualib.h"
@ -97,4 +98,7 @@ void COM_Lua_f(void);
// uncomment if you want seg_t/node_t in Lua // uncomment if you want seg_t/node_t in Lua
// #define HAVE_LUA_SEGS // #define HAVE_LUA_SEGS
#define INLEVEL if (gamestate != GS_LEVEL && !titlemapinaction)\
return luaL_error(L, "This can only be used in a level!");
#endif #endif

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

@ -56,8 +56,7 @@ static int lib_iterateThinkers(lua_State *L)
thinker_t *th = NULL, *next = NULL; thinker_t *th = NULL, *next = NULL;
struct iterationState *it; struct iterationState *it;
if (gamestate != GS_LEVEL) INLEVEL
return luaL_error(L, "This function can only be used in a level!");
it = luaL_checkudata(L, 1, META_ITERATIONSTATE); it = luaL_checkudata(L, 1, META_ITERATIONSTATE);
@ -112,8 +111,7 @@ static int lib_startIterate(lua_State *L)
{ {
struct iterationState *it; struct iterationState *it;
if (gamestate != GS_LEVEL) INLEVEL
return luaL_error(L, "This function can only be used in a level!");
lua_pushvalue(L, lua_upvalueindex(1)); lua_pushvalue(L, lua_upvalueindex(1));
it = lua_newuserdata(L, sizeof(struct iterationState)); it = lua_newuserdata(L, sizeof(struct iterationState));

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

@ -2830,8 +2830,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)
@ -3531,6 +3531,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;
} }
} }
@ -7577,8 +7578,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);
@ -7732,7 +7744,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
@ -7743,7 +7755,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
@ -7752,7 +7764,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)
@ -8144,9 +8156,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

@ -3878,6 +3878,8 @@ bossjustdie:
} }
default: //eggmobiles default: //eggmobiles
{ {
UINT8 extrainfo = (mo->spawnpoint ? mo->spawnpoint->extrainfo : 0);
// Stop exploding and prepare to run. // Stop exploding and prepare to run.
P_SetMobjState(mo, mo->info->xdeathstate); P_SetMobjState(mo, mo->info->xdeathstate);
if (P_MobjWasRemoved(mo)) if (P_MobjWasRemoved(mo))
@ -3897,6 +3899,9 @@ bossjustdie:
if (mo2->type != MT_BOSSFLYPOINT) if (mo2->type != MT_BOSSFLYPOINT)
continue; continue;
if (mo2->spawnpoint && mo2->spawnpoint->extrainfo != extrainfo)
continue;
// If this one's further then the last one, don't go for it. // If this one's further then the last one, don't go for it.
if (mo->target && if (mo->target &&
P_AproxDistance(P_AproxDistance(mo->x - mo2->x, mo->y - mo2->y), mo->z - mo2->z) > P_AproxDistance(P_AproxDistance(mo->x - mo2->x, mo->y - mo2->y), mo->z - mo2->z) >
@ -12303,6 +12308,7 @@ void A_Boss5FindWaypoint(mobj_t *actor)
//INT32 locvar2 = var2; //INT32 locvar2 = var2;
boolean avoidcenter; boolean avoidcenter;
UINT32 i; UINT32 i;
UINT8 extrainfo = (actor->spawnpoint ? actor->spawnpoint->extrainfo : 0);
#ifdef HAVE_BLUA #ifdef HAVE_BLUA
if (LUA_CallAction("A_Boss5FindWaypoint", actor)) if (LUA_CallAction("A_Boss5FindWaypoint", actor))
return; return;
@ -12312,16 +12318,34 @@ void A_Boss5FindWaypoint(mobj_t *actor)
if (locvar1 == 2) // look for the boss waypoint if (locvar1 == 2) // look for the boss waypoint
{ {
for (i = 0; i < nummapthings; i++) thinker_t *th;
mobj_t *mo2;
P_SetTarget(&actor->tracer, NULL);
// Flee! Flee! Find a point to escape to! If none, just shoot upward!
// scan the thinkers to find the runaway point
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
{ {
if (!mapthings[i].mobj) if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
continue; continue;
if (mapthings[i].mobj->type != MT_BOSSFLYPOINT)
mo2 = (mobj_t *)th;
if (mo2->type != MT_BOSSFLYPOINT)
continue; continue;
P_SetTarget(&actor->tracer, mapthings[i].mobj);
break; if (mo2->spawnpoint && mo2->spawnpoint->extrainfo != extrainfo)
continue;
// If this one's further then the last one, don't go for it.
if (actor->tracer &&
P_AproxDistance(P_AproxDistance(actor->x - mo2->x, actor->y - mo2->y), actor->z - mo2->z) >
P_AproxDistance(P_AproxDistance(actor->x - actor->tracer->x, actor->y - actor->tracer->y), actor->z - actor->tracer->z))
continue;
// Otherwise... Do!
P_SetTarget(&actor->tracer, mo2);
} }
if (i == nummapthings) if (!actor->tracer)
return; // no boss flypoints found return; // no boss flypoints found
} }
else if (locvar1 == 1) // always go to ambush-marked waypoint else if (locvar1 == 1) // always go to ambush-marked waypoint
@ -12335,12 +12359,14 @@ void A_Boss5FindWaypoint(mobj_t *actor)
continue; continue;
if (mapthings[i].mobj->type != MT_FANGWAYPOINT) if (mapthings[i].mobj->type != MT_FANGWAYPOINT)
continue; continue;
if (mapthings[i].options & MTF_AMBUSH) if (mapthings[i].extrainfo != extrainfo)
{ continue;
if (!(mapthings[i].options & MTF_AMBUSH))
continue;
P_SetTarget(&actor->tracer, mapthings[i].mobj); P_SetTarget(&actor->tracer, mapthings[i].mobj);
break; break;
} }
}
if (i == nummapthings) if (i == nummapthings)
goto nowaypoints; goto nowaypoints;
@ -12363,6 +12389,8 @@ void A_Boss5FindWaypoint(mobj_t *actor)
continue; continue;
if (actor->tracer == mapthings[i].mobj) // this was your tracer last time if (actor->tracer == mapthings[i].mobj) // this was your tracer last time
continue; continue;
if (mapthings[i].extrainfo != extrainfo)
continue;
if (mapthings[i].options & MTF_AMBUSH) if (mapthings[i].options & MTF_AMBUSH)
{ {
if (avoidcenter) if (avoidcenter)
@ -12418,6 +12446,8 @@ void A_Boss5FindWaypoint(mobj_t *actor)
continue; continue;
if (actor->tracer == mapthings[i].mobj) // this was your tracer last time if (actor->tracer == mapthings[i].mobj) // this was your tracer last time
continue; continue;
if (mapthings[i].extrainfo != extrainfo)
continue;
if (mapthings[i].options & MTF_AMBUSH) if (mapthings[i].options & MTF_AMBUSH)
{ {
if (avoidcenter) if (avoidcenter)

View file

@ -719,6 +719,8 @@ void T_ContinuousFalling(levelspecthink_t *faller)
} }
} }
P_CheckSector(faller->sector, false); // you might think this is irrelevant. you would be wrong
faller->sector->floorspeed = faller->speed*faller->direction; faller->sector->floorspeed = faller->speed*faller->direction;
faller->sector->ceilspeed = 42; faller->sector->ceilspeed = 42;
faller->sector->moved = true; faller->sector->moved = true;
@ -3029,20 +3031,40 @@ INT32 EV_DoElevator(line_t *line, elevator_e elevtype, boolean customspeed)
void EV_CrumbleChain(sector_t *sec, ffloor_t *rover) void EV_CrumbleChain(sector_t *sec, ffloor_t *rover)
{ {
size_t i; size_t i, leftmostvertex, rightmostvertex, topmostvertex, bottommostvertex;
size_t leftmostvertex = 0, rightmostvertex = 0; fixed_t leftx, rightx, topy, bottomy, topz, bottomz, widthfactor, heightfactor, a, b, c, spacing;
size_t topmostvertex = 0, bottommostvertex = 0; mobjtype_t type;
fixed_t leftx, rightx; tic_t lifetime;
fixed_t topy, bottomy; INT16 flags;
fixed_t topz, bottomz;
fixed_t widthfactor = FRACUNIT, heightfactor = FRACUNIT;
fixed_t a, b, c;
mobjtype_t type = MT_ROCKCRUMBLE1;
fixed_t spacing = (32<<FRACBITS);
tic_t lifetime = 3*TICRATE;
INT16 flags = 0;
#define controlsec rover->master->frontsector sector_t *controlsec = rover->master->frontsector;
if (sec == NULL)
{
if (controlsec->numattached)
{
for (i = 0; i < controlsec->numattached; i++)
{
sec = &sectors[controlsec->attached[i]];
if (!sec->ffloors)
continue;
for (rover = sec->ffloors; rover; rover = rover->next)
{
if (rover->master->frontsector == controlsec)
EV_CrumbleChain(sec, rover);
}
}
}
return;
}
leftmostvertex = rightmostvertex = topmostvertex = bottommostvertex = 0;
widthfactor = heightfactor = FRACUNIT;
spacing = (32<<FRACBITS);
type = MT_ROCKCRUMBLE1;
lifetime = 3*TICRATE;
flags = 0;
if (controlsec->tag != 0) if (controlsec->tag != 0)
{ {

View file

@ -670,7 +670,10 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
P_DoMatchSuper(player); P_DoMatchSuper(player);
} }
else else
{
emeralds |= special->info->speed; emeralds |= special->info->speed;
stagefailed = false;
}
if (special->target && special->target->type == MT_EMERALDSPAWN) if (special->target && special->target->type == MT_EMERALDSPAWN)
{ {
@ -3652,7 +3655,7 @@ void P_PlayerRingBurst(player_t *player, INT32 num_rings)
{ {
INT32 i; INT32 i;
mobj_t *mo; mobj_t *mo;
angle_t fa; angle_t fa, va;
fixed_t ns; fixed_t ns;
fixed_t z; fixed_t z;
boolean nightsreplace = ((maptol & TOL_NIGHTS) && !G_IsSpecialStage(gamemap)); boolean nightsreplace = ((maptol & TOL_NIGHTS) && !G_IsSpecialStage(gamemap));
@ -3674,6 +3677,11 @@ void P_PlayerRingBurst(player_t *player, INT32 num_rings)
// Spill weapons first // Spill weapons first
P_PlayerWeaponPanelOrAmmoBurst(player); P_PlayerWeaponPanelOrAmmoBurst(player);
if (abs(player->mo->momx) > player->mo->scale || abs(player->mo->momy) > player->mo->scale)
va = R_PointToAngle2(player->mo->momx, player->mo->momy, 0, 0)>>ANGLETOFINESHIFT;
else
va = player->mo->angle>>ANGLETOFINESHIFT;
for (i = 0; i < num_rings; i++) for (i = 0; i < num_rings; i++)
{ {
INT32 objType = mobjinfo[MT_RING].reactiontime; INT32 objType = mobjinfo[MT_RING].reactiontime;
@ -3695,7 +3703,7 @@ void P_PlayerRingBurst(player_t *player, INT32 num_rings)
P_SetScale(mo, player->mo->scale); P_SetScale(mo, player->mo->scale);
// Angle offset by player angle, then slightly offset by amount of rings // Angle offset by player angle, then slightly offset by amount of rings
fa = ((i*FINEANGLES/16) + (player->mo->angle>>ANGLETOFINESHIFT) - ((num_rings-1)*FINEANGLES/32)) & FINEMASK; fa = ((i*FINEANGLES/16) + va - ((num_rings-1)*FINEANGLES/32)) & FINEMASK;
// Make rings spill out around the player in 16 directions like SA, but spill like Sonic 2. // Make rings spill out around the player in 16 directions like SA, but spill like Sonic 2.
// Technically a non-SA way of spilling rings. They just so happen to be a little similar. // Technically a non-SA way of spilling rings. They just so happen to be a little similar.

View file

@ -142,7 +142,7 @@ boolean P_IsObjectOnGround(mobj_t *mo);
boolean P_IsObjectOnGroundIn(mobj_t *mo, sector_t *sec); boolean P_IsObjectOnGroundIn(mobj_t *mo, sector_t *sec);
boolean P_InSpaceSector(mobj_t *mo); boolean P_InSpaceSector(mobj_t *mo);
boolean P_InQuicksand(mobj_t *mo); boolean P_InQuicksand(mobj_t *mo);
boolean P_PlayerHitFloor(player_t *player); boolean P_PlayerHitFloor(player_t *player, boolean dorollstuff);
void P_SetObjectMomZ(mobj_t *mo, fixed_t value, boolean relative); void P_SetObjectMomZ(mobj_t *mo, fixed_t value, boolean relative);
void P_RestoreMusic(player_t *player); void P_RestoreMusic(player_t *player);

View file

@ -342,7 +342,7 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object)
if (horizspeed) if (horizspeed)
{ {
object->player->drawangle = spring->angle; object->player->drawangle = spring->angle;
if (object->player->cmd.forwardmove == 0 && object->player->cmd.sidemove == 0) if (vertispeed || (object->player->cmd.forwardmove == 0 && object->player->cmd.sidemove == 0))
{ {
object->angle = spring->angle; object->angle = spring->angle;
@ -1808,7 +1808,7 @@ static boolean PIT_CheckLine(line_t *ld)
{ {
tmceilingz = opentop; tmceilingz = opentop;
ceilingline = ld; ceilingline = ld;
tmceilingrover = NULL; tmceilingrover = openceilingrover;
#ifdef ESLOPE #ifdef ESLOPE
tmceilingslope = opentopslope; tmceilingslope = opentopslope;
#endif #endif
@ -1817,7 +1817,7 @@ static boolean PIT_CheckLine(line_t *ld)
if (openbottom > tmfloorz) if (openbottom > tmfloorz)
{ {
tmfloorz = openbottom; tmfloorz = openbottom;
tmfloorrover = NULL; tmfloorrover = openfloorrover;
#ifdef ESLOPE #ifdef ESLOPE
tmfloorslope = openbottomslope; tmfloorslope = openbottomslope;
#endif #endif
@ -2089,6 +2089,7 @@ boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y)
#ifdef ESLOPE #ifdef ESLOPE
tmfloorslope = NULL; tmfloorslope = NULL;
#endif #endif
tmfloorrover = NULL;
} }
if (polybottom < tmceilingz && abs(delta1) >= abs(delta2)) { if (polybottom < tmceilingz && abs(delta1) >= abs(delta2)) {
@ -2096,6 +2097,7 @@ boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y)
#ifdef ESLOPE #ifdef ESLOPE
tmceilingslope = NULL; tmceilingslope = NULL;
#endif #endif
tmceilingrover = NULL;
} }
} }
plink = (polymaplink_t *)(plink->link.next); plink = (polymaplink_t *)(plink->link.next);
@ -2820,7 +2822,7 @@ boolean P_SceneryTryMove(mobj_t *thing, fixed_t x, fixed_t y)
static boolean P_ThingHeightClip(mobj_t *thing) static boolean P_ThingHeightClip(mobj_t *thing)
{ {
boolean floormoved; boolean floormoved;
fixed_t oldfloorz = thing->floorz; fixed_t oldfloorz = thing->floorz, oldz = thing->z;
ffloor_t *oldfloorrover = thing->floorrover; ffloor_t *oldfloorrover = thing->floorrover;
ffloor_t *oldceilingrover = thing->ceilingrover; ffloor_t *oldceilingrover = thing->ceilingrover;
boolean onfloor = P_IsObjectOnGround(thing);//(thing->z <= thing->floorz); boolean onfloor = P_IsObjectOnGround(thing);//(thing->z <= thing->floorz);
@ -2879,6 +2881,12 @@ static boolean P_ThingHeightClip(mobj_t *thing)
thing->z = thing->ceilingz - thing->height; thing->z = thing->ceilingz - thing->height;
} }
if (thing->z != oldz)
{
if (thing->player)
P_PlayerHitFloor(thing->player, false);
}
// debug: be sure it falls to the floor // debug: be sure it falls to the floor
thing->eflags &= ~MFE_ONGROUND; thing->eflags &= ~MFE_ONGROUND;
@ -4079,6 +4087,7 @@ static boolean PIT_ChangeSector(mobj_t *thing, boolean realcrush)
boolean P_CheckSector(sector_t *sector, boolean crunch) boolean P_CheckSector(sector_t *sector, boolean crunch)
{ {
msecnode_t *n; msecnode_t *n;
size_t i;
nofit = false; nofit = false;
crushchange = crunch; crushchange = crunch;
@ -4093,9 +4102,57 @@ boolean P_CheckSector(sector_t *sector, boolean crunch)
// First, let's see if anything will keep it from crushing. // First, let's see if anything will keep it from crushing.
// Sal: This stupid function chain is required to fix polyobjects not being able to crush.
// Monster Iestyn: don't use P_CheckSector actually just look for objects in the blockmap instead
validcount++;
for (i = 0; i < sector->linecount; i++)
{
if (sector->lines[i]->polyobj)
{
polyobj_t *po = sector->lines[i]->polyobj;
if (po->validcount == validcount)
continue; // skip if already checked
if (!(po->flags & POF_SOLID))
continue;
if (po->lines[0]->backsector == sector) // Make sure you're currently checking the control sector
{
INT32 x, y;
po->validcount = validcount;
for (y = po->blockbox[BOXBOTTOM]; y <= po->blockbox[BOXTOP]; ++y)
{
for (x = po->blockbox[BOXLEFT]; x <= po->blockbox[BOXRIGHT]; ++x)
{
mobj_t *mo;
if (x < 0 || y < 0 || x >= bmapwidth || y >= bmapheight)
continue;
mo = blocklinks[y * bmapwidth + x];
for (; mo; mo = mo->bnext)
{
// Monster Iestyn: do we need to check if a mobj has already been checked? ...probably not I suspect
if (!P_MobjTouchingPolyobj(po, mo))
continue;
if (!PIT_ChangeSector(mo, false))
{
nofit = true;
return nofit;
}
}
}
}
}
}
}
if (sector->numattached) if (sector->numattached)
{ {
size_t i;
sector_t *sec; sector_t *sec;
for (i = 0; i < sector->numattached; i++) for (i = 0; i < sector->numattached; i++)
{ {
@ -4155,9 +4212,53 @@ boolean P_CheckSector(sector_t *sector, boolean crunch)
} while (n); // repeat from scratch until all things left are marked valid } while (n); // repeat from scratch until all things left are marked valid
// Nothing blocked us, so lets crush for real! // Nothing blocked us, so lets crush for real!
// Sal: This stupid function chain is required to fix polyobjects not being able to crush.
// Monster Iestyn: don't use P_CheckSector actually just look for objects in the blockmap instead
validcount++;
for (i = 0; i < sector->linecount; i++)
{
if (sector->lines[i]->polyobj)
{
polyobj_t *po = sector->lines[i]->polyobj;
if (po->validcount == validcount)
continue; // skip if already checked
if (!(po->flags & POF_SOLID))
continue;
if (po->lines[0]->backsector == sector) // Make sure you're currently checking the control sector
{
INT32 x, y;
po->validcount = validcount;
for (y = po->blockbox[BOXBOTTOM]; y <= po->blockbox[BOXTOP]; ++y)
{
for (x = po->blockbox[BOXLEFT]; x <= po->blockbox[BOXRIGHT]; ++x)
{
mobj_t *mo;
if (x < 0 || y < 0 || x >= bmapwidth || y >= bmapheight)
continue;
mo = blocklinks[y * bmapwidth + x];
for (; mo; mo = mo->bnext)
{
// Monster Iestyn: do we need to check if a mobj has already been checked? ...probably not I suspect
if (!P_MobjTouchingPolyobj(po, mo))
continue;
PIT_ChangeSector(mo, true);
return nofit;
}
}
}
}
}
}
if (sector->numattached) if (sector->numattached)
{ {
size_t i;
sector_t *sec; sector_t *sec;
for (i = 0; i < sector->numattached; i++) for (i = 0; i < sector->numattached; i++)
{ {

View file

@ -311,6 +311,7 @@ fixed_t opentop, openbottom, openrange, lowfloor, highceiling;
#ifdef ESLOPE #ifdef ESLOPE
pslope_t *opentopslope, *openbottomslope; pslope_t *opentopslope, *openbottomslope;
#endif #endif
ffloor_t *openfloorrover, *openceilingrover;
// P_CameraLineOpening // P_CameraLineOpening
// P_LineOpening, but for camera // P_LineOpening, but for camera
@ -517,6 +518,8 @@ void P_LineOpening(line_t *linedef, mobj_t *mobj)
I_Assert(front != NULL); I_Assert(front != NULL);
I_Assert(back != NULL); I_Assert(back != NULL);
openfloorrover = openceilingrover = NULL;
{ // Set open and high/low values here { // Set open and high/low values here
fixed_t frontheight, backheight; fixed_t frontheight, backheight;
@ -641,6 +644,8 @@ void P_LineOpening(line_t *linedef, mobj_t *mobj)
pslope_t *ceilingslope = opentopslope; pslope_t *ceilingslope = opentopslope;
pslope_t *floorslope = openbottomslope; pslope_t *floorslope = openbottomslope;
#endif #endif
ffloor_t *floorrover = NULL;
ffloor_t *ceilingrover = NULL;
// Check for frontsector's fake floors // Check for frontsector's fake floors
for (rover = front->ffloors; rover; rover = rover->next) for (rover = front->ffloors; rover; rover = rover->next)
@ -668,6 +673,7 @@ void P_LineOpening(line_t *linedef, mobj_t *mobj)
#ifdef ESLOPE #ifdef ESLOPE
ceilingslope = *rover->b_slope; ceilingslope = *rover->b_slope;
#endif #endif
ceilingrover = rover;
} }
else if (bottomheight < highestceiling) else if (bottomheight < highestceiling)
highestceiling = bottomheight; highestceiling = bottomheight;
@ -680,6 +686,7 @@ void P_LineOpening(line_t *linedef, mobj_t *mobj)
#ifdef ESLOPE #ifdef ESLOPE
floorslope = *rover->t_slope; floorslope = *rover->t_slope;
#endif #endif
floorrover = rover;
} }
else if (topheight > lowestfloor) else if (topheight > lowestfloor)
lowestfloor = topheight; lowestfloor = topheight;
@ -712,6 +719,7 @@ void P_LineOpening(line_t *linedef, mobj_t *mobj)
#ifdef ESLOPE #ifdef ESLOPE
ceilingslope = *rover->b_slope; ceilingslope = *rover->b_slope;
#endif #endif
ceilingrover = rover;
} }
else if (bottomheight < highestceiling) else if (bottomheight < highestceiling)
highestceiling = bottomheight; highestceiling = bottomheight;
@ -724,6 +732,7 @@ void P_LineOpening(line_t *linedef, mobj_t *mobj)
#ifdef ESLOPE #ifdef ESLOPE
floorslope = *rover->t_slope; floorslope = *rover->t_slope;
#endif #endif
floorrover = rover;
} }
else if (topheight > lowestfloor) else if (topheight > lowestfloor)
lowestfloor = topheight; lowestfloor = topheight;
@ -743,6 +752,7 @@ void P_LineOpening(line_t *linedef, mobj_t *mobj)
#ifdef ESLOPE #ifdef ESLOPE
ceilingslope = NULL; ceilingslope = NULL;
#endif #endif
ceilingrover = NULL;
} }
else if (polysec->floorheight < highestceiling && delta1 >= delta2) else if (polysec->floorheight < highestceiling && delta1 >= delta2)
highestceiling = polysec->floorheight; highestceiling = polysec->floorheight;
@ -752,6 +762,7 @@ void P_LineOpening(line_t *linedef, mobj_t *mobj)
#ifdef ESLOPE #ifdef ESLOPE
floorslope = NULL; floorslope = NULL;
#endif #endif
floorrover = NULL;
} }
else if (polysec->ceilingheight > lowestfloor && delta1 < delta2) else if (polysec->ceilingheight > lowestfloor && delta1 < delta2)
lowestfloor = polysec->ceilingheight; lowestfloor = polysec->ceilingheight;
@ -765,6 +776,7 @@ void P_LineOpening(line_t *linedef, mobj_t *mobj)
#ifdef ESLOPE #ifdef ESLOPE
openbottomslope = floorslope; openbottomslope = floorslope;
#endif #endif
openfloorrover = floorrover;
} }
if (lowestceiling < opentop) { if (lowestceiling < opentop) {
@ -772,6 +784,7 @@ void P_LineOpening(line_t *linedef, mobj_t *mobj)
#ifdef ESLOPE #ifdef ESLOPE
opentopslope = ceilingslope; opentopslope = ceilingslope;
#endif #endif
openceilingrover = ceilingrover;
} }
if (lowestfloor > lowfloor) if (lowestfloor > lowfloor)

View file

@ -58,6 +58,7 @@ extern fixed_t opentop, openbottom, openrange, lowfloor, highceiling;
#ifdef ESLOPE #ifdef ESLOPE
extern pslope_t *opentopslope, *openbottomslope; extern pslope_t *opentopslope, *openbottomslope;
#endif #endif
extern ffloor_t *openfloorrover, *openceilingrover;
void P_LineOpening(line_t *plinedef, mobj_t *mobj); void P_LineOpening(line_t *plinedef, mobj_t *mobj);

View file

@ -1784,7 +1784,7 @@ static void P_PushableCheckBustables(mobj_t *mo)
continue; continue;
} }
EV_CrumbleChain(node->m_sector, rover); EV_CrumbleChain(NULL, rover); // node->m_sector
// Run a linedef executor?? // Run a linedef executor??
if (rover->master->flags & ML_EFFECT5) if (rover->master->flags & ML_EFFECT5)
@ -3047,7 +3047,7 @@ static void P_PlayerZMovement(mobj_t *mo)
} }
} }
clipmomz = P_PlayerHitFloor(mo->player); clipmomz = P_PlayerHitFloor(mo->player, true);
if (!(mo->player->pflags & PF_SPINNING) && mo->player->powers[pw_carry] != CR_NIGHTSMODE) if (!(mo->player->pflags & PF_SPINNING) && mo->player->powers[pw_carry] != CR_NIGHTSMODE)
mo->player->pflags &= ~PF_STARTDASH; mo->player->pflags &= ~PF_STARTDASH;
@ -3129,7 +3129,7 @@ nightsdone:
{ {
// DO THE MARIO! // DO THE MARIO!
if (rover->flags & FF_SHATTERBOTTOM) // Brick block! if (rover->flags & FF_SHATTERBOTTOM) // Brick block!
EV_CrumbleChain(node->m_sector, rover); EV_CrumbleChain(NULL, rover); // node->m_sector
else // Question block! else // Question block!
EV_MarioBlock(rover, node->m_sector, mo); EV_MarioBlock(rover, node->m_sector, mo);
} }
@ -5236,6 +5236,7 @@ static void P_Boss7Thinker(mobj_t *mobj)
INT32 i; INT32 i;
boolean foundgoop = false; boolean foundgoop = false;
INT32 closestNum; INT32 closestNum;
UINT8 extrainfo = (mobj->spawnpoint ? mobj->spawnpoint->extrainfo : 0);
// Looks for players in goop. If you find one, try to jump on him. // Looks for players in goop. If you find one, try to jump on him.
for (i = 0; i < MAXPLAYERS; i++) for (i = 0; i < MAXPLAYERS; i++)
@ -5261,18 +5262,24 @@ static void P_Boss7Thinker(mobj_t *mobj)
continue; continue;
mo2 = (mobj_t *)th; mo2 = (mobj_t *)th;
if (mo2->type == MT_BOSS3WAYPOINT && mo2->spawnpoint) if (mo2->type != MT_BOSS3WAYPOINT)
{ continue;
if (!mo2->spawnpoint)
continue;
if (mo2->spawnpoint->extrainfo != extrainfo)
continue;
if (mobj->health <= mobj->info->damage && !(mo2->spawnpoint->options & 7))
continue; // don't jump to center
dist = P_AproxDistance(players[i].mo->x - mo2->x, players[i].mo->y - mo2->y); dist = P_AproxDistance(players[i].mo->x - mo2->x, players[i].mo->y - mo2->y);
if (closestNum == -1 || dist < closestdist) if (!(closestNum == -1 || dist < closestdist))
{ continue;
closestNum = (mo2->spawnpoint->options & 7); closestNum = (mo2->spawnpoint->options & 7);
closestdist = dist; closestdist = dist;
foundgoop = true; foundgoop = true;
} }
}
}
waypointNum = closestNum; waypointNum = closestNum;
break; break;
} }
@ -5280,16 +5287,13 @@ static void P_Boss7Thinker(mobj_t *mobj)
if (!foundgoop) if (!foundgoop)
{ {
if (mobj->z > 1056*FRACUNIT)
waypointNum = 0;
else
waypointNum = 1 + P_RandomKey(4);
}
// Don't jump to the center when health is low. // Don't jump to the center when health is low.
// Force the player to beat you with missiles. // Force the player to beat you with missiles.
if (mobj->health <= mobj->info->damage && waypointNum == 0) if (mobj->z <= 1056*FRACUNIT || mobj->health <= mobj->info->damage)
waypointNum = 1 + P_RandomKey(4); waypointNum = 1 + P_RandomKey(4);
else
waypointNum = 0;
}
if (mobj->tracer && mobj->tracer->type == MT_BOSS3WAYPOINT if (mobj->tracer && mobj->tracer->type == MT_BOSS3WAYPOINT
&& mobj->tracer->spawnpoint && (mobj->tracer->spawnpoint->options & 7) == waypointNum) && mobj->tracer->spawnpoint && (mobj->tracer->spawnpoint->options & 7) == waypointNum)
@ -5299,15 +5303,12 @@ static void P_Boss7Thinker(mobj_t *mobj)
else else
waypointNum--; waypointNum--;
waypointNum %= 5; if (mobj->health <= mobj->info->damage)
waypointNum = ((waypointNum + 3) % 4) + 1; // plus four to avoid modulo being negative, minus one to avoid waypoint #0
if (waypointNum < 0) else
waypointNum = 0; waypointNum = ((waypointNum + 5) % 5);
} }
if (waypointNum == 0 && mobj->health <= mobj->info->damage)
waypointNum = 1 + (P_RandomFixed() & 1);
// scan the thinkers to find // scan the thinkers to find
// the waypoint to use // the waypoint to use
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next) for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
@ -5316,12 +5317,18 @@ static void P_Boss7Thinker(mobj_t *mobj)
continue; continue;
mo2 = (mobj_t *)th; mo2 = (mobj_t *)th;
if (mo2->type == MT_BOSS3WAYPOINT && mo2->spawnpoint && (mo2->spawnpoint->options & 7) == waypointNum) if (mo2->type != MT_BOSS3WAYPOINT)
{ continue;
if (!mo2->spawnpoint)
continue;
if ((mo2->spawnpoint->options & 7) != waypointNum)
continue;
if (mo2->spawnpoint->extrainfo != extrainfo)
continue;
hitspot = mo2; hitspot = mo2;
break; break;
} }
}
if (hitspot == NULL) if (hitspot == NULL)
{ {
@ -7004,6 +7011,9 @@ void P_MobjThinker(mobj_t *mobj)
if (mobj->flags & MF_NOTHINK) if (mobj->flags & MF_NOTHINK)
return; return;
if ((mobj->flags & MF_BOSS) && mobj->spawnpoint && (bossdisabled & (1<<mobj->spawnpoint->extrainfo)))
return;
// Remove dead target/tracer. // Remove dead target/tracer.
if (mobj->target && P_MobjWasRemoved(mobj->target)) if (mobj->target && P_MobjWasRemoved(mobj->target))
P_SetTarget(&mobj->target, NULL); P_SetTarget(&mobj->target, NULL);
@ -8072,7 +8082,8 @@ void P_MobjThinker(mobj_t *mobj)
mobj->tracer->z += mobj->height; mobj->tracer->z += mobj->height;
} }
break; break;
case MT_WAVINGFLAG: case MT_WAVINGFLAG1:
case MT_WAVINGFLAG2:
{ {
fixed_t base = (leveltime<<(FRACBITS+1)); fixed_t base = (leveltime<<(FRACBITS+1));
mobj_t *seg = mobj->tracer, *prev = mobj; mobj_t *seg = mobj->tracer, *prev = mobj;
@ -9675,15 +9686,14 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type)
case MT_BIGMINE: case MT_BIGMINE:
mobj->extravalue1 = FixedHypot(mobj->x, mobj->y)>>FRACBITS; mobj->extravalue1 = FixedHypot(mobj->x, mobj->y)>>FRACBITS;
break; break;
case MT_WAVINGFLAG: case MT_WAVINGFLAG1:
case MT_WAVINGFLAG2:
{ {
mobj_t *prev = mobj, *cur; mobj_t *prev = mobj, *cur;
UINT8 i; UINT8 i;
mobj->destscale <<= 2;
P_SetScale(mobj, mobj->destscale);
for (i = 0; i <= 16; i++) // probably should be < but staying authentic to the Lua version for (i = 0; i <= 16; i++) // probably should be < but staying authentic to the Lua version
{ {
cur = P_SpawnMobjFromMobj(mobj, 0, 0, 0, MT_WAVINGFLAGSEG); cur = P_SpawnMobjFromMobj(mobj, 0, 0, 0, ((mobj->type == MT_WAVINGFLAG1) ? MT_WAVINGFLAGSEG1 : MT_WAVINGFLAGSEG2));;
P_SetTarget(&prev->tracer, cur); P_SetTarget(&prev->tracer, cur);
cur->extravalue1 = i; cur->extravalue1 = i;
prev = cur; prev = cur;
@ -11100,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;
@ -11754,13 +11770,14 @@ ML_EFFECT5 : Don't stop thinking when too far away
P_SpawnMobjFromMobj(mobj, -1*FRACUNIT, 0, 0, MT_THZTREEBRANCH)->angle = mobjangle + ANGLE_270; P_SpawnMobjFromMobj(mobj, -1*FRACUNIT, 0, 0, MT_THZTREEBRANCH)->angle = mobjangle + ANGLE_270;
} }
break; break;
case MT_CEZPOLE: case MT_CEZPOLE1:
case MT_CEZPOLE2:
{ // Spawn the banner { // Spawn the banner
angle_t mobjangle = FixedAngle(mthing->angle<<FRACBITS); angle_t mobjangle = FixedAngle(mthing->angle<<FRACBITS);
P_SpawnMobjFromMobj(mobj, P_SpawnMobjFromMobj(mobj,
P_ReturnThrustX(mobj, mobjangle, 4<<FRACBITS), P_ReturnThrustX(mobj, mobjangle, 4<<FRACBITS),
P_ReturnThrustY(mobj, mobjangle, 4<<FRACBITS), P_ReturnThrustY(mobj, mobjangle, 4<<FRACBITS),
0, MT_CEZBANNER)->angle = mobjangle + ANGLE_90; 0, ((mobj->type == MT_CEZPOLE1) ? MT_CEZBANNER1 : MT_CEZBANNER2))->angle = mobjangle + ANGLE_90;
} }
break; break;
case MT_HHZTREE_TOP: case MT_HHZTREE_TOP:
@ -11984,6 +12001,15 @@ ML_EFFECT5 : Don't stop thinking when too far away
if (i == MT_YELLOWDIAG || i == MT_REDDIAG) if (i == MT_YELLOWDIAG || i == MT_REDDIAG)
mobj->angle += ANGLE_22h; mobj->angle += ANGLE_22h;
if (i == MT_YELLOWHORIZ || i == MT_REDHORIZ || i == MT_BLUEHORIZ)
{
if (mthing->options & MTF_OBJECTFLIP)
mobj->z -= 16*FRACUNIT;
else
mobj->z += 16*FRACUNIT;
}
if (mobj->flags & MF_NIGHTSITEM) if (mobj->flags & MF_NIGHTSITEM)
{ {
// Spawn already displayed // Spawn already displayed
@ -12011,6 +12037,9 @@ ML_EFFECT5 : Don't stop thinking when too far away
if (mthing->options & MTF_OBJECTSPECIAL) if (mthing->options & MTF_OBJECTSPECIAL)
{ {
if (i == MT_YELLOWDIAG || i == MT_REDDIAG)
mobj->flags |= MF_NOGRAVITY;
if ((mobj->flags & MF_MONITOR) && mobj->info->speed != 0) if ((mobj->flags & MF_MONITOR) && mobj->info->speed != 0)
{ {
// flag for strong/weak random boxes // flag for strong/weak random boxes
@ -12354,15 +12383,13 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing, boolean bonustime)
if (nightsreplace) if (nightsreplace)
ringthing = MT_NIGHTSSTAR; ringthing = MT_NIGHTSSTAR;
for (r = 1; r <= 5; r++)
{
if (mthing->options & MTF_OBJECTFLIP) if (mthing->options & MTF_OBJECTFLIP)
{ {
z = ( z = (
#ifdef ESLOPE #ifdef ESLOPE
sec->c_slope ? P_GetZAt(sec->c_slope, x, y) : sec->c_slope ? P_GetZAt(sec->c_slope, x, y) :
#endif #endif
sec->ceilingheight) - mobjinfo[ringthing].height - dist*r; sec->ceilingheight) - mobjinfo[ringthing].height;
if (mthing->options >> ZSHIFT) if (mthing->options >> ZSHIFT)
z -= ((mthing->options >> ZSHIFT) << FRACBITS); z -= ((mthing->options >> ZSHIFT) << FRACBITS);
} }
@ -12372,11 +12399,18 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing, boolean bonustime)
#ifdef ESLOPE #ifdef ESLOPE
sec->f_slope ? P_GetZAt(sec->f_slope, x, y) : sec->f_slope ? P_GetZAt(sec->f_slope, x, y) :
#endif #endif
sec->floorheight) + dist*r; sec->floorheight);
if (mthing->options >> ZSHIFT) if (mthing->options >> ZSHIFT)
z += ((mthing->options >> ZSHIFT) << FRACBITS); z += ((mthing->options >> ZSHIFT) << FRACBITS);
} }
for (r = 1; r <= 5; r++)
{
if (mthing->options & MTF_OBJECTFLIP)
z -= dist;
else
z += dist;
mobj = P_SpawnMobj(x, y, z, ringthing); mobj = P_SpawnMobj(x, y, z, ringthing);
if (mthing->options & MTF_OBJECTFLIP) if (mthing->options & MTF_OBJECTFLIP)
@ -12409,18 +12443,13 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing, boolean bonustime)
closestangle = FixedAngle(mthing->angle*FRACUNIT); closestangle = FixedAngle(mthing->angle*FRACUNIT);
fa = (closestangle >> ANGLETOFINESHIFT); fa = (closestangle >> ANGLETOFINESHIFT);
for (r = 1; r <= iterations; r++)
{
x += FixedMul(64*FRACUNIT, FINECOSINE(fa));
y += FixedMul(64*FRACUNIT, FINESINE(fa));
if (mthing->options & MTF_OBJECTFLIP) if (mthing->options & MTF_OBJECTFLIP)
{ {
z = ( z = (
#ifdef ESLOPE #ifdef ESLOPE
sec->c_slope ? P_GetZAt(sec->c_slope, x, y) : sec->c_slope ? P_GetZAt(sec->c_slope, x, y) :
#endif #endif
sec->ceilingheight) - mobjinfo[ringthing].height - 64*FRACUNIT*r; sec->ceilingheight) - mobjinfo[ringthing].height;
if (mthing->options >> ZSHIFT) if (mthing->options >> ZSHIFT)
z -= ((mthing->options >> ZSHIFT) << FRACBITS); z -= ((mthing->options >> ZSHIFT) << FRACBITS);
} }
@ -12430,11 +12459,21 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing, boolean bonustime)
#ifdef ESLOPE #ifdef ESLOPE
sec->f_slope ? P_GetZAt(sec->f_slope, x, y) : sec->f_slope ? P_GetZAt(sec->f_slope, x, y) :
#endif #endif
sec->floorheight) + 64*FRACUNIT*r; sec->floorheight);
if (mthing->options >> ZSHIFT) if (mthing->options >> ZSHIFT)
z += ((mthing->options >> ZSHIFT) << FRACBITS); z += ((mthing->options >> ZSHIFT) << FRACBITS);
} }
for (r = 1; r <= iterations; r++)
{
x += FixedMul(64*FRACUNIT, FINECOSINE(fa));
y += FixedMul(64*FRACUNIT, FINESINE(fa));
if (mthing->options & MTF_OBJECTFLIP)
z -= 64*FRACUNIT;
else
z += 64*FRACUNIT;
mobj = P_SpawnMobj(x, y, z, ringthing); mobj = P_SpawnMobj(x, y, z, ringthing);
if (mthing->options & MTF_OBJECTFLIP) if (mthing->options & MTF_OBJECTFLIP)

View file

@ -470,4 +470,5 @@ extern INT32 numhuntemeralds;
extern boolean runemeraldmanager; extern boolean runemeraldmanager;
extern UINT16 emeraldspawndelay; extern UINT16 emeraldspawndelay;
extern INT32 numstarposts; extern INT32 numstarposts;
extern UINT16 bossdisabled;
#endif #endif

View file

@ -1873,7 +1873,8 @@ void T_PolyObjWaypoint(polywaypoint_t *th)
po->lines[0]->backsector->floorheight = target->z - amtz; po->lines[0]->backsector->floorheight = target->z - amtz;
po->lines[0]->backsector->ceilingheight = target->z + amtz; po->lines[0]->backsector->ceilingheight = target->z + amtz;
// Sal: Remember to check your sectors! // Sal: Remember to check your sectors!
P_CheckSector(po->lines[0]->frontsector, (boolean)(po->damage)); // Monster Iestyn: we only need to bother with the back sector, now that P_CheckSector automatically checks the blockmap
// updating objects in the front one too just added teleporting to ground bugs
P_CheckSector(po->lines[0]->backsector, (boolean)(po->damage)); P_CheckSector(po->lines[0]->backsector, (boolean)(po->damage));
// Apply action to mirroring polyobjects as well // Apply action to mirroring polyobjects as well
start = 0; start = 0;
@ -1887,7 +1888,8 @@ void T_PolyObjWaypoint(polywaypoint_t *th)
po->lines[0]->backsector->floorheight += diffz; // move up/down by same amount as the parent did po->lines[0]->backsector->floorheight += diffz; // move up/down by same amount as the parent did
po->lines[0]->backsector->ceilingheight += diffz; po->lines[0]->backsector->ceilingheight += diffz;
// Sal: Remember to check your sectors! // Sal: Remember to check your sectors!
P_CheckSector(po->lines[0]->frontsector, (boolean)(po->damage)); // Monster Iestyn: we only need to bother with the back sector, now that P_CheckSector automatically checks the blockmap
// updating objects in the front one too just added teleporting to ground bugs
P_CheckSector(po->lines[0]->backsector, (boolean)(po->damage)); P_CheckSector(po->lines[0]->backsector, (boolean)(po->damage));
} }
@ -2050,8 +2052,9 @@ void T_PolyObjWaypoint(polywaypoint_t *th)
po->lines[0]->backsector->floorheight += momz; po->lines[0]->backsector->floorheight += momz;
po->lines[0]->backsector->ceilingheight += momz; po->lines[0]->backsector->ceilingheight += momz;
// Sal: Remember to check your sectors! // Sal: Remember to check your sectors!
P_CheckSector(po->lines[0]->frontsector, (boolean)(po->damage)); // frontsector is NEEDED for crushing // Monster Iestyn: we only need to bother with the back sector, now that P_CheckSector automatically checks the blockmap
P_CheckSector(po->lines[0]->backsector, (boolean)(po->damage)); // backsector may not be necessary, but just in case // updating objects in the front one too just added teleporting to ground bugs
P_CheckSector(po->lines[0]->backsector, (boolean)(po->damage));
// Apply action to mirroring polyobjects as well // Apply action to mirroring polyobjects as well
start = 0; start = 0;
@ -2065,7 +2068,8 @@ void T_PolyObjWaypoint(polywaypoint_t *th)
po->lines[0]->backsector->floorheight += momz; po->lines[0]->backsector->floorheight += momz;
po->lines[0]->backsector->ceilingheight += momz; po->lines[0]->backsector->ceilingheight += momz;
// Sal: Remember to check your sectors! // Sal: Remember to check your sectors!
P_CheckSector(po->lines[0]->frontsector, (boolean)(po->damage)); // Monster Iestyn: we only need to bother with the back sector, now that P_CheckSector automatically checks the blockmap
// updating objects in the front one too just added teleporting to ground bugs
P_CheckSector(po->lines[0]->backsector, (boolean)(po->damage)); P_CheckSector(po->lines[0]->backsector, (boolean)(po->damage));
} }
} }

View file

@ -3408,7 +3408,7 @@ static void P_NetUnArchiveThinkers(void)
{ {
for (;;) for (;;)
{ {
thinker_t* th; thinker_t* th = NULL;
tclass = READUINT8(save_p); tclass = READUINT8(save_p);
if (tclass == tc_end) if (tclass == tc_end)
@ -3990,6 +3990,7 @@ static void P_NetArchiveMisc(void)
WRITEUINT32(save_p, leveltime); WRITEUINT32(save_p, leveltime);
WRITEUINT32(save_p, ssspheres); WRITEUINT32(save_p, ssspheres);
WRITEINT16(save_p, lastmap); WRITEINT16(save_p, lastmap);
WRITEUINT16(save_p, bossdisabled);
WRITEUINT16(save_p, emeralds); WRITEUINT16(save_p, emeralds);
WRITEUINT8(save_p, stagefailed); WRITEUINT8(save_p, stagefailed);
@ -4067,6 +4068,7 @@ static inline boolean P_NetUnArchiveMisc(void)
leveltime = READUINT32(save_p); leveltime = READUINT32(save_p);
ssspheres = READUINT32(save_p); ssspheres = READUINT32(save_p);
lastmap = READINT16(save_p); lastmap = READINT16(save_p);
bossdisabled = READUINT16(save_p);
emeralds = READUINT16(save_p); emeralds = READUINT16(save_p);
stagefailed = READUINT8(save_p); stagefailed = READUINT8(save_p);

View file

@ -102,6 +102,7 @@ line_t *lines;
side_t *sides; side_t *sides;
mapthing_t *mapthings; mapthing_t *mapthings;
INT32 numstarposts; INT32 numstarposts;
UINT16 bossdisabled;
boolean levelloading; boolean levelloading;
UINT8 levelfadecol; UINT8 levelfadecol;
@ -859,12 +860,7 @@ void P_ReloadRings(void)
mt->z = (INT16)(R_PointInSubsector(mt->x << FRACBITS, mt->y << FRACBITS) mt->z = (INT16)(R_PointInSubsector(mt->x << FRACBITS, mt->y << FRACBITS)
->sector->floorheight>>FRACBITS); ->sector->floorheight>>FRACBITS);
P_SpawnHoopsAndRings(mt, P_SpawnHoopsAndRings(mt, true);
#ifdef MANIASPHERES
true);
#else
!G_IsSpecialStage(gamemap)); // prevent flashing spheres in special stages
#endif
} }
} }
for (i = 0; i < numHoops; i++) for (i = 0; i < numHoops; i++)
@ -878,11 +874,6 @@ void P_SwitchSpheresBonusMode(boolean bonustime)
mobj_t *mo; mobj_t *mo;
thinker_t *th; thinker_t *th;
#ifndef MANIASPHERES
if (G_IsSpecialStage(gamemap)) // prevent flashing spheres in special stages
return;
#endif
// scan the thinkers to find spheres to switch // scan the thinkers to find spheres to switch
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next) for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
{ {
@ -2215,7 +2206,7 @@ static void P_LevelInitStuff(void)
ssspheres = timeinmap = 0; ssspheres = timeinmap = 0;
// special stage // special stage
stagefailed = false; stagefailed = true; // assume failed unless proven otherwise - P_GiveEmerald or emerald touchspecial
// Reset temporary record data // Reset temporary record data
memset(&ntemprecords, 0, sizeof(nightsdata_t)); memset(&ntemprecords, 0, sizeof(nightsdata_t));
@ -3126,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;
@ -3437,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

@ -3554,6 +3554,29 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec)
} }
break; break;
case 449: // Enable bosses with parameter
{
INT32 bossid = sides[line->sidenum[0]].textureoffset>>FRACBITS;
if (bossid & ~15) // if any bits other than first 16 are set
{
CONS_Alert(CONS_WARNING,
M_GetText("Boss enable linedef (tag %d) has an invalid texture x offset.\nConsider changing it or removing it entirely.\n"),
line->tag);
break;
}
if (line->flags & ML_NOCLIMB)
{
bossdisabled |= (1<<bossid);
CONS_Debug(DBG_GAMELOGIC, "Line type 449 Executor: bossid disabled = %d", bossid);
}
else
{
bossdisabled &= ~(1<<bossid);
CONS_Debug(DBG_GAMELOGIC, "Line type 449 Executor: bossid enabled = %d", bossid);
}
break;
}
case 450: // Execute Linedef Executor - for recursion case 450: // Execute Linedef Executor - for recursion
P_LinedefExecute(line->tag, mo, NULL); P_LinedefExecute(line->tag, mo, NULL);
break; break;
@ -3918,6 +3941,18 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec)
} }
break; break;
case 460: // Award rings
{
INT16 rings = (sides[line->sidenum[0]].textureoffset>>FRACBITS);
INT32 delay = (sides[line->sidenum[0]].rowoffset>>FRACBITS);
if (mo && mo->player)
{
if (delay <= 0 || !(leveltime % delay))
P_GivePlayerRings(mo->player, rings);
}
}
break;
#ifdef POLYOBJECTS #ifdef POLYOBJECTS
case 480: // Polyobj_DoorSlide case 480: // Polyobj_DoorSlide
case 481: // Polyobj_DoorSwing case 481: // Polyobj_DoorSwing
@ -4601,7 +4636,10 @@ DoneSection2:
if (player->bot) if (player->bot)
break; break;
if (!(maptol & TOL_NIGHTS) && G_IsSpecialStage(gamemap) && player->nightstime > 6) if (!(maptol & TOL_NIGHTS) && G_IsSpecialStage(gamemap) && player->nightstime > 6)
{
player->nightstime = 6; // Just let P_Ticker take care of the rest. player->nightstime = 6; // Just let P_Ticker take care of the rest.
return;
}
// Exit (for FOF exits; others are handled in P_PlayerThink in p_user.c) // Exit (for FOF exits; others are handled in P_PlayerThink in p_user.c)
{ {
@ -4624,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;
@ -6401,6 +6439,9 @@ void P_SpawnSpecials(INT32 fromnetsave)
// but currently isn't. // but currently isn't.
(void)fromnetsave; (void)fromnetsave;
// yep, we do this here - "bossdisabled" is considered an apparatus of specials.
bossdisabled = 0;
// Init special SECTORs. // Init special SECTORs.
sector = sectors; sector = sectors;
for (i = 0; i < numsectors; i++, sector++) for (i = 0; i < numsectors; i++, sector++)
@ -7289,6 +7330,24 @@ void P_SpawnSpecials(INT32 fromnetsave)
case 431: case 431:
break; break;
case 449: // Enable bosses with parameter
{
INT32 bossid = sides[*lines[i].sidenum].textureoffset>>FRACBITS;
if (bossid & ~15) // if any bits other than first 16 are set
{
CONS_Alert(CONS_WARNING,
M_GetText("Boss enable linedef (tag %d) has an invalid texture x offset.\nConsider changing it or removing it entirely.\n"),
lines[i].tag);
break;
}
if (!(lines[i].flags & ML_NOCLIMB))
{
bossdisabled |= (1<<bossid); // gotta disable in the first place to enable
CONS_Debug(DBG_GAMELOGIC, "Line type 449 spawn effect: bossid disabled = %d", bossid);
}
break;
}
// 500 is used for a scroller // 500 is used for a scroller
// 501 is used for a scroller // 501 is used for a scroller
// 502 is used for a scroller // 502 is used for a scroller

View file

@ -518,10 +518,7 @@ static inline void P_DoSpecialStageStuff(void)
} }
} }
else else
{
sstimer = 0; sstimer = 0;
stagefailed = true;
}
} }
} }

View file

@ -302,15 +302,39 @@ void P_GiveEmerald(boolean spawnObj)
S_StartSound(NULL, sfx_cgot); // Got the emerald! S_StartSound(NULL, sfx_cgot); // Got the emerald!
emeralds |= (1 << em); emeralds |= (1 << em);
stagefailed = false;
if (spawnObj && playeringame[consoleplayer]) if (spawnObj)
{ {
// The Chaos Emerald begins to orbit us! // The Chaos Emerald begins to orbit us!
// Only give it to ONE person! // Only visibly give it to ONE person!
mobj_t *emmo = P_SpawnMobjFromMobj(players[consoleplayer].mo, 0, 0, players[consoleplayer].mo->height, MT_GOTEMERALD); UINT8 i, pnum = ((playeringame[consoleplayer]) && (!players[consoleplayer].spectator) && (players[consoleplayer].mo)) ? consoleplayer : 255;
P_SetTarget(&emmo->target, players[consoleplayer].mo); for (i = 0; i < MAXPLAYERS; i++)
{
mobj_t *emmo;
if (!playeringame[i])
continue;
if (players[i].spectator)
continue;
if (!players[i].mo)
continue;
emmo = P_SpawnMobjFromMobj(players[i].mo, 0, 0, players[i].mo->height, MT_GOTEMERALD);
P_SetTarget(&emmo->target, players[i].mo);
P_SetMobjState(emmo, mobjinfo[MT_GOTEMERALD].meleestate + em); P_SetMobjState(emmo, mobjinfo[MT_GOTEMERALD].meleestate + em);
P_SetTarget(&players[consoleplayer].mo->tracer, emmo); P_SetTarget(&players[i].mo->tracer, emmo);
if (pnum == 255)
{
i = pnum;
continue;
}
if (i == pnum)
continue;
emmo->flags2 |= MF2_DONTDRAW;
}
} }
} }
@ -597,7 +621,7 @@ static void P_DeNightserizePlayer(player_t *player)
player->mo->skin = &skins[player->skin]; player->mo->skin = &skins[player->skin];
player->followitem = skins[player->skin].followitem; player->followitem = skins[player->skin].followitem;
player->mo->color = player->skincolor; player->mo->color = player->skincolor;
G_GhostAddColor(GHC_NORMAL); G_GhostAddColor(GHC_RETURNSKIN);
// Restore aiming angle // Restore aiming angle
if (player == &players[consoleplayer]) if (player == &players[consoleplayer])
@ -615,7 +639,6 @@ static void P_DeNightserizePlayer(player_t *player)
if (playeringame[i] && players[i].powers[pw_carry] == CR_NIGHTSMODE) if (playeringame[i] && players[i].powers[pw_carry] == CR_NIGHTSMODE)
players[i].nightstime = 1; // force everyone else to fall too. players[i].nightstime = 1; // force everyone else to fall too.
player->exiting = 3*TICRATE; player->exiting = 3*TICRATE;
stagefailed = true; // NIGHT OVER
// If you screwed up, kiss your score and ring bonus goodbye. // If you screwed up, kiss your score and ring bonus goodbye.
// But only do this in special stage (and instakill!) In regular stages, wait til we hit the ground. // But only do this in special stage (and instakill!) In regular stages, wait til we hit the ground.
@ -716,6 +739,7 @@ void P_NightserizePlayer(player_t *player, INT32 nighttime)
if (!(cv_debug || devparm) && !(netgame || multiplayer || demoplayback)) if (!(cv_debug || devparm) && !(netgame || multiplayer || demoplayback))
player->mo->color = skins[DEFAULTNIGHTSSKIN].prefcolor; player->mo->color = skins[DEFAULTNIGHTSSKIN].prefcolor;
player->followitem = skins[DEFAULTNIGHTSSKIN].followitem; player->followitem = skins[DEFAULTNIGHTSSKIN].followitem;
G_GhostAddColor(GHC_NIGHTSSKIN);
} }
player->nightstime = player->startedtime = player->lapstartedtime = nighttime*TICRATE; player->nightstime = player->startedtime = player->lapstartedtime = nighttime*TICRATE;
@ -2007,13 +2031,15 @@ boolean P_InSpaceSector(mobj_t *mo) // Returns true if you are in space
// //
// Handles player hitting floor surface. // Handles player hitting floor surface.
// Returns whether to clip momz. // Returns whether to clip momz.
boolean P_PlayerHitFloor(player_t *player) boolean P_PlayerHitFloor(player_t *player, boolean dorollstuff)
{ {
boolean clipmomz; boolean clipmomz;
I_Assert(player->mo != NULL); I_Assert(player->mo != NULL);
if ((clipmomz = !(P_CheckDeathPitCollide(player->mo))) && player->mo->health && !player->spectator) if ((clipmomz = !(P_CheckDeathPitCollide(player->mo))) && player->mo->health && !player->spectator)
{
if (dorollstuff)
{ {
if ((player->charability2 == CA2_SPINDASH) && !(player->pflags & PF_THOKKED) && (player->cmd.buttons & BT_USE) && (FixedHypot(player->mo->momx, player->mo->momy) > (5*player->mo->scale))) if ((player->charability2 == CA2_SPINDASH) && !(player->pflags & PF_THOKKED) && (player->cmd.buttons & BT_USE) && (FixedHypot(player->mo->momx, player->mo->momy) > (5*player->mo->scale)))
{ {
@ -2022,15 +2048,22 @@ boolean P_PlayerHitFloor(player_t *player)
S_StartSound(player->mo, sfx_spin); S_StartSound(player->mo, sfx_spin);
} }
else else
{
player->pflags &= ~PF_SPINNING; player->pflags &= ~PF_SPINNING;
}
if (player->pflags & PF_GLIDING) // ground gliding if (player->pflags & PF_GLIDING) // ground gliding
{
if (dorollstuff)
{ {
player->skidtime = TICRATE; player->skidtime = TICRATE;
player->mo->tics = -1; player->mo->tics = -1;
} }
else if (player->charability2 == CA2_MELEE && (player->panim == PA_ABILITY2 && player->mo->state-states != S_PLAY_MELEE_LANDING)) else
player->pflags &= ~PF_GLIDING;
}
else if (player->charability2 == CA2_MELEE && player->panim == PA_ABILITY2)
{
if (player->mo->state-states != S_PLAY_MELEE_LANDING)
{ {
mobjtype_t type = player->revitem; mobjtype_t type = player->revitem;
P_SetPlayerMobjState(player->mo, S_PLAY_MELEE_LANDING); P_SetPlayerMobjState(player->mo, S_PLAY_MELEE_LANDING);
@ -2049,7 +2082,7 @@ boolean P_PlayerHitFloor(player_t *player)
fixed_t mu = FixedMul(player->maxdash, player->mo->scale); fixed_t mu = FixedMul(player->maxdash, player->mo->scale);
fixed_t mu2 = FixedHypot(player->mo->momx, player->mo->momy); fixed_t mu2 = FixedHypot(player->mo->momx, player->mo->momy);
fixed_t ev; fixed_t ev;
mobj_t *missile; mobj_t *missile = NULL;
if (mu2 < mu) if (mu2 < mu)
mu2 = mu; mu2 = mu;
ev = (50*FRACUNIT - (mu/25))/50; ev = (50*FRACUNIT - (mu/25))/50;
@ -2062,16 +2095,20 @@ boolean P_PlayerHitFloor(player_t *player)
P_ReturnThrustY(missile, throwang, mu)); // side to side component P_ReturnThrustY(missile, throwang, mu)); // side to side component
P_Thrust(missile, player->drawangle, mu2); // forward component P_Thrust(missile, player->drawangle, mu2); // forward component
P_SetObjectMomZ(missile, (4 + ((i&1)<<1))*FRACUNIT, true); P_SetObjectMomZ(missile, (4 + ((i&1)<<1))*FRACUNIT, true);
missile->momz += player->mo->pmomz;
missile->fuse = TICRATE/2; missile->fuse = TICRATE/2;
missile->extravalue2 = ev; missile->extravalue2 = ev;
i++; i++;
throwang += ANG30; throwang += ANG30;
} }
if (mobjinfo[type].seesound) if (mobjinfo[type].seesound && missile)
S_StartSound(missile, missile->info->seesound); S_StartSound(missile, missile->info->seesound);
} }
} }
}
else if (player->charability2 == CA2_GUNSLINGER && player->panim == PA_ABILITY2)
;
else if (player->pflags & PF_JUMPED || !(player->pflags & PF_SPINNING) else if (player->pflags & PF_JUMPED || !(player->pflags & PF_SPINNING)
|| player->powers[pw_tailsfly] || player->mo->state-states == S_PLAY_FLY_TIRED) || player->powers[pw_tailsfly] || player->mo->state-states == S_PLAY_FLY_TIRED)
{ {
@ -2102,7 +2139,6 @@ boolean P_PlayerHitFloor(player_t *player)
P_SetPlayerMobjState(player->mo, S_PLAY_STND); P_SetPlayerMobjState(player->mo, S_PLAY_STND);
} }
} }
}
if (!(player->pflags & PF_GLIDING)) if (!(player->pflags & PF_GLIDING))
player->pflags &= ~(PF_JUMPED|PF_NOJUMPDAMAGE); player->pflags &= ~(PF_JUMPED|PF_NOJUMPDAMAGE);
@ -2320,7 +2356,7 @@ static void P_CheckBustableBlocks(player_t *player)
//if (metalrecording) //if (metalrecording)
// G_RecordBustup(rover); // G_RecordBustup(rover);
EV_CrumbleChain(node->m_sector, rover); EV_CrumbleChain(NULL, rover); // node->m_sector
// Run a linedef executor?? // Run a linedef executor??
if (rover->master->flags & ML_EFFECT5) if (rover->master->flags & ML_EFFECT5)
@ -2537,7 +2573,7 @@ static void P_CheckQuicksand(player_t *player)
player->mo->z = ceilingheight - player->mo->height; player->mo->z = ceilingheight - player->mo->height;
if (player->mo->momz <= 0) if (player->mo->momz <= 0)
P_PlayerHitFloor(player); P_PlayerHitFloor(player, false);
} }
else else
{ {
@ -2549,7 +2585,7 @@ static void P_CheckQuicksand(player_t *player)
player->mo->z = floorheight; player->mo->z = floorheight;
if (player->mo->momz >= 0) if (player->mo->momz >= 0)
P_PlayerHitFloor(player); P_PlayerHitFloor(player, false);
} }
friction = abs(rover->master->v1->y - rover->master->v2->y)>>6; friction = abs(rover->master->v1->y - rover->master->v2->y)>>6;
@ -4410,6 +4446,10 @@ static void P_DoSpinAbility(player_t *player, ticcmd_t *cmd)
{ {
player->mo->z += P_MobjFlip(player->mo); player->mo->z += P_MobjFlip(player->mo);
P_SetObjectMomZ(player->mo, player->mindash, false); P_SetObjectMomZ(player->mo, player->mindash, false);
if (P_MobjFlip(player->mo)*player->mo->pmomz > 0)
player->mo->momz += player->mo->pmomz; // Add the platform's momentum to your jump.
else
player->mo->pmomz = 0;
if (player->mo->eflags & MFE_UNDERWATER) if (player->mo->eflags & MFE_UNDERWATER)
player->mo->momz >>= 1; player->mo->momz >>= 1;
#if 0 #if 0
@ -11641,7 +11681,6 @@ void P_PlayerAfterThink(player_t *player)
player->followmobj->threshold = player->mo->z; player->followmobj->threshold = player->mo->z;
player->followmobj->movecount = player->panim; player->followmobj->movecount = player->panim;
player->followmobj->angle = horizangle; player->followmobj->angle = horizangle;
player->followmobj->scale = player->mo->scale;
P_SetScale(player->followmobj, player->mo->scale); P_SetScale(player->followmobj, player->mo->scale);
player->followmobj->destscale = player->mo->destscale; player->followmobj->destscale = player->mo->destscale;
player->followmobj->radius = player->mo->radius; player->followmobj->radius = player->mo->radius;

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
@ -2446,9 +2450,11 @@ static void R_DrawMaskedList (drawnode_t* head)
void R_DrawMasked(maskcount_t* masks, UINT8 nummasks) void R_DrawMasked(maskcount_t* masks, UINT8 nummasks)
{ {
drawnode_t heads[nummasks]; /**< Drawnode lists; as many as number of views/portals. */ drawnode_t *heads; /**< Drawnode lists; as many as number of views/portals. */
SINT8 i; SINT8 i;
heads = calloc(nummasks, sizeof(drawnode_t));
for (i = 0; i < nummasks; i++) for (i = 0; i < nummasks; i++)
{ {
heads[i].next = heads[i].prev = &heads[i]; heads[i].next = heads[i].prev = &heads[i];
@ -2474,6 +2480,8 @@ void R_DrawMasked(maskcount_t* masks, UINT8 nummasks)
R_DrawMaskedList(&heads[nummasks - 1]); R_DrawMaskedList(&heads[nummasks - 1]);
R_ClearDrawNodes(&heads[nummasks - 1]); R_ClearDrawNodes(&heads[nummasks - 1]);
} }
free(heads);
} }
// ========================================================================== // ==========================================================================
@ -2503,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
@ -2525,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:
@ -2537,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;
} }
@ -2556,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;
@ -2988,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
@ -3018,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)
@ -3094,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);
@ -3130,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();
@ -3140,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);
@ -3265,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

@ -524,6 +524,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;
@ -662,7 +663,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.
@ -715,7 +716,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.
@ -1675,9 +1676,19 @@ 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)
{
if (gamestate != wipegamestate)
{
closedcaptions[0].c = NULL;
closedcaptions[0].s = NULL;
closedcaptions[0].t = 0;
closedcaptions[0].b = 0;
}
else
closedcaptions[0].t = CAPTIONFADETICS; closedcaptions[0].t = CAPTIONFADETICS;
} }
} }
}
// //
// Stop and resume music, during game PAUSE. // Stop and resume music, during game PAUSE.
@ -1982,8 +1993,10 @@ void GameMIDIMusic_OnChange(void)
} }
} }
#ifdef HAVE_OPENMPT
void ModFilter_OnChange(void) void ModFilter_OnChange(void)
{ {
if (openmpt_mhandle) if (openmpt_mhandle)
openmpt_module_set_render_param(openmpt_mhandle, OPENMPT_MODULE_RENDER_INTERPOLATIONFILTER_LENGTH, cv_modfilter.value); openmpt_module_set_render_param(openmpt_mhandle, OPENMPT_MODULE_RENDER_INTERPOLATIONFILTER_LENGTH, cv_modfilter.value);
} }
#endif

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

@ -277,6 +277,7 @@
<ClInclude Include="..\r_local.h" /> <ClInclude Include="..\r_local.h" />
<ClInclude Include="..\r_main.h" /> <ClInclude Include="..\r_main.h" />
<ClInclude Include="..\r_plane.h" /> <ClInclude Include="..\r_plane.h" />
<ClInclude Include="..\r_portal.h" />
<ClInclude Include="..\r_segs.h" /> <ClInclude Include="..\r_segs.h" />
<ClInclude Include="..\r_sky.h" /> <ClInclude Include="..\r_sky.h" />
<ClInclude Include="..\r_splats.h" /> <ClInclude Include="..\r_splats.h" />
@ -430,6 +431,7 @@
</ClCompile> </ClCompile>
<ClCompile Include="..\r_main.c" /> <ClCompile Include="..\r_main.c" />
<ClCompile Include="..\r_plane.c" /> <ClCompile Include="..\r_plane.c" />
<ClCompile Include="..\r_portal.c" />
<ClCompile Include="..\r_segs.c" /> <ClCompile Include="..\r_segs.c" />
<ClCompile Include="..\r_sky.c" /> <ClCompile Include="..\r_sky.c" />
<ClCompile Include="..\r_splats.c" /> <ClCompile Include="..\r_splats.c" />

View file

@ -453,6 +453,9 @@
<ClInclude Include="..\hardware\hw_clip.h"> <ClInclude Include="..\hardware\hw_clip.h">
<Filter>Hw_Hardware</Filter> <Filter>Hw_Hardware</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\r_portal.h">
<Filter>R_Rend</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<CustomBuild Include="..\tmap.nas"> <CustomBuild Include="..\tmap.nas">
@ -894,6 +897,10 @@
<ClCompile Include="..\hardware\hw_clip.c"> <ClCompile Include="..\hardware\hw_clip.c">
<Filter>Hw_Hardware</Filter> <Filter>Hw_Hardware</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\apng.c" />
<ClCompile Include="..\r_portal.c">
<Filter>R_Rend</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Image Include="Srb2SDL.ico"> <Image Include="Srb2SDL.ico">

View file

@ -196,7 +196,7 @@ consvar_t cv_miditimiditypath = {"midisoundbank", "./timidity", CV_SAVE, NULL, N
static void var_cleanup(void) static void var_cleanup(void)
{ {
loop_point = song_length = 0.0f; song_length = loop_point = 0.0f;
music_bytes = fading_source = fading_target =\ music_bytes = fading_source = fading_target =\
fading_timer = fading_duration = 0; fading_timer = fading_duration = 0;

View file

@ -110,6 +110,7 @@ static patch_t *orngstat;
static patch_t *redstat; static patch_t *redstat;
static patch_t *yelstat; static patch_t *yelstat;
static patch_t *nbracket; static patch_t *nbracket;
static patch_t *nring;
static patch_t *nhud[12]; static patch_t *nhud[12];
static patch_t *nsshud; static patch_t *nsshud;
static patch_t *nbon[12]; static patch_t *nbon[12];
@ -226,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)
@ -311,6 +312,7 @@ void ST_LoadGraphics(void)
redstat = W_CachePatchName("REDSTAT", PU_HUDGFX); redstat = W_CachePatchName("REDSTAT", PU_HUDGFX);
yelstat = W_CachePatchName("YELSTAT", PU_HUDGFX); yelstat = W_CachePatchName("YELSTAT", PU_HUDGFX);
nbracket = W_CachePatchName("NBRACKET", PU_HUDGFX); nbracket = W_CachePatchName("NBRACKET", PU_HUDGFX);
nring = W_CachePatchName("NRNG1", PU_HUDGFX);
for (i = 0; i < 12; ++i) for (i = 0; i < 12; ++i)
{ {
nhud[i] = W_CachePatchName(va("NHUD%d", i+1), PU_HUDGFX); nhud[i] = W_CachePatchName(va("NHUD%d", i+1), PU_HUDGFX);
@ -341,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;
} }
@ -353,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)
@ -1545,7 +1561,7 @@ static void ST_drawNiGHTSLink(void)
static void ST_drawNiGHTSHUD(void) static void ST_drawNiGHTSHUD(void)
{ {
INT32 origamount; INT32 origamount;
INT32 total_spherecount; INT32 total_spherecount, total_ringcount;
const boolean oldspecialstage = (G_IsSpecialStage(gamemap) && !(maptol & TOL_NIGHTS)); const boolean oldspecialstage = (G_IsSpecialStage(gamemap) && !(maptol & TOL_NIGHTS));
// Drill meter // Drill meter
@ -1617,33 +1633,28 @@ static void ST_drawNiGHTSHUD(void)
#endif #endif
ST_DrawTopLeftOverlayPatch(16, 8, nbracket); ST_DrawTopLeftOverlayPatch(16, 8, nbracket);
if (G_IsSpecialStage(gamemap)) if (G_IsSpecialStage(gamemap))
#ifdef MANIASPHERES
ST_DrawTopLeftOverlayPatch(24, 16, ( ST_DrawTopLeftOverlayPatch(24, 16, (
(stplyr->bonustime && (leveltime & 4)) ? nssbon : nsshud)); (stplyr->bonustime && (leveltime & 4) && (states[S_BLUESPHEREBONUS].frame & FF_ANIMATE)) ? nssbon : nsshud));
#else
ST_DrawTopLeftOverlayPatch(24, 16, (nsshud));
#endif
else else
ST_DrawTopLeftOverlayPatch(24, 16, *(((stplyr->bonustime) ? nbon : nhud)+((leveltime/2)%12))); ST_DrawTopLeftOverlayPatch(24, 16, *(((stplyr->bonustime) ? nbon : nhud)+((leveltime/2)%12)));
if (G_IsSpecialStage(gamemap)) if (G_IsSpecialStage(gamemap))
{ {
INT32 i; INT32 i;
total_spherecount = 0; total_spherecount = total_ringcount = 0;
for (i = 0; i < MAXPLAYERS; i++) for (i = 0; i < MAXPLAYERS; i++)
if (playeringame[i] /*&& players[i].powers[pw_carry] == CR_NIGHTSMODE*/ && players[i].spheres) {
if (!playeringame[i])
continue;
total_spherecount += players[i].spheres; total_spherecount += players[i].spheres;
total_ringcount += players[i].rings;
}
} }
else else
total_spherecount = stplyr->spheres;
/*if (oldspecialstage)
{ {
if (total_spherecount < ssspheres) total_spherecount = stplyr->spheres;
total_spherecount = ssspheres - total_spherecount; total_ringcount = stplyr->spheres;
else }
total_spherecount = 0;
}*/
if (stplyr->capsule) if (stplyr->capsule)
{ {
@ -1731,6 +1742,27 @@ static void ST_drawNiGHTSHUD(void)
else else
ST_DrawTopLeftOverlayPatch(40, 8 + 5, narrow[8]); ST_DrawTopLeftOverlayPatch(40, 8 + 5, narrow[8]);
if (oldspecialstage)
{
// invert for s3k style junk
total_spherecount = ssspheres - total_spherecount;
if (total_spherecount < 0)
total_spherecount = 0;
if (nummaprings > 0) // don't count down if there ISN'T a valid maximum number of rings, like sonic 3
{
total_ringcount = nummaprings - total_ringcount;
if (total_ringcount < 0)
total_ringcount = 0;
}
// now rings! you know, for that perfect bonus.
V_DrawScaledPatch(272, 8, V_PERPLAYER|V_SNAPTOTOP|V_SNAPTORIGHT|V_HUDTRANS, nbracket);
V_DrawScaledPatch(280, 16+1, V_PERPLAYER|V_SNAPTOTOP|V_SNAPTORIGHT|V_HUDTRANS, nring);
V_DrawScaledPatch(280, 8+5, V_FLIP|V_PERPLAYER|V_SNAPTOTOP|V_SNAPTORIGHT|V_HUDTRANS, narrow[8]);
V_DrawTallNum(272, 8 + 11, V_PERPLAYER|V_SNAPTOTOP|V_SNAPTORIGHT|V_HUDTRANS, total_ringcount);
}
if (total_spherecount >= 100) if (total_spherecount >= 100)
V_DrawTallNum((total_spherecount >= 1000) ? 76 : 72, 8 + 11, V_PERPLAYER|V_SNAPTOTOP|V_SNAPTOLEFT|V_HUDTRANS, total_spherecount); V_DrawTallNum((total_spherecount >= 1000) ? 76 : 72, 8 + 11, V_PERPLAYER|V_SNAPTOTOP|V_SNAPTOLEFT|V_HUDTRANS, total_spherecount);
else else

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]));
if (!column->topdelta)
{
source = (const UINT8 *)(column) + 3; source = (const UINT8 *)(column) + 3;
V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, (column->topdelta == 0xff ? 31 : source[0])); 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,33 +1516,205 @@ 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++) {
u = 0;
while (u < w)
{ {
if (!alphalevel)
dest[u] = consolebgmap[dest[u]];
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);

View file

@ -293,6 +293,7 @@
</ClCompile> </ClCompile>
<ClCompile Include="..\r_main.c" /> <ClCompile Include="..\r_main.c" />
<ClCompile Include="..\r_plane.c" /> <ClCompile Include="..\r_plane.c" />
<ClCompile Include="..\r_portal.c" />
<ClCompile Include="..\r_segs.c" /> <ClCompile Include="..\r_segs.c" />
<ClCompile Include="..\r_sky.c" /> <ClCompile Include="..\r_sky.c" />
<ClCompile Include="..\r_splats.c" /> <ClCompile Include="..\r_splats.c" />
@ -443,6 +444,7 @@
<ClInclude Include="..\r_local.h" /> <ClInclude Include="..\r_local.h" />
<ClInclude Include="..\r_main.h" /> <ClInclude Include="..\r_main.h" />
<ClInclude Include="..\r_plane.h" /> <ClInclude Include="..\r_plane.h" />
<ClInclude Include="..\r_portal.h" />
<ClInclude Include="..\r_segs.h" /> <ClInclude Include="..\r_segs.h" />
<ClInclude Include="..\r_sky.h" /> <ClInclude Include="..\r_sky.h" />
<ClInclude Include="..\r_splats.h" /> <ClInclude Include="..\r_splats.h" />

View file

@ -456,6 +456,10 @@
<ClCompile Include="..\hardware\hw_clip.c"> <ClCompile Include="..\hardware\hw_clip.c">
<Filter>Hw_Hardware</Filter> <Filter>Hw_Hardware</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\apng.c" />
<ClCompile Include="..\r_portal.c">
<Filter>R_Rend</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="afxres.h"> <ClInclude Include="afxres.h">
@ -857,6 +861,10 @@
<ClInclude Include="..\hardware\hw_clip.h"> <ClInclude Include="..\hardware\hw_clip.h">
<Filter>Hw_Hardware</Filter> <Filter>Hw_Hardware</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\apng.h" />
<ClInclude Include="..\r_portal.h">
<Filter>R_Rend</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Image Include="Srb2win.ico"> <Image Include="Srb2win.ico">

View file

@ -86,8 +86,8 @@ typedef union
INT32 passedx3; INT32 passedx3;
INT32 passedx4; INT32 passedx4;
y_bonus_t bonus; y_bonus_t bonuses[2];
patch_t *bonuspatch; patch_t *bonuspatches[2];
patch_t *pscore; // SCORE patch_t *pscore; // SCORE
UINT32 score; // fake score UINT32 score; // fake score
@ -326,34 +326,36 @@ void Y_IntermissionDrawer(void)
// draw the header // draw the header
if (intertic <= 2*TICRATE) if (intertic <= 2*TICRATE)
animatetic = 0; animatetic = 0;
else if (!animatetic && data.spec.bonus.points == 0 && data.spec.passed3[0] != '\0') else if (!animatetic && data.spec.bonuses[0].points == 0 && data.spec.bonuses[1].points == 0 && data.spec.passed3[0] != '\0')
animatetic = intertic + TICRATE; animatetic = intertic + TICRATE;
if (animatetic && (tic_t)intertic >= animatetic) if (animatetic && (tic_t)intertic >= animatetic)
{ {
const INT32 scradjust = (vid.width/vid.dupx)>>3; // 40 for BASEVIDWIDTH const INT32 scradjust = (vid.width/vid.dupx)>>3; // 40 for BASEVIDWIDTH
INT32 animatetimer = (intertic - animatetic); INT32 animatetimer = (intertic - animatetic);
if (animatetimer <= 14) if (animatetimer <= 16)
{ {
xoffset1 = -(animatetimer * scradjust); xoffset1 = -(animatetimer * scradjust);
xoffset2 = -((animatetimer- 2) * scradjust); xoffset2 = -((animatetimer- 2) * scradjust);
xoffset3 = -((animatetimer- 4) * scradjust); xoffset3 = -((animatetimer- 4) * scradjust);
xoffset4 = -((animatetimer- 6) * scradjust); xoffset4 = -((animatetimer- 6) * scradjust);
xoffset5 = -((animatetimer- 8) * scradjust); xoffset5 = -((animatetimer- 8) * scradjust);
xoffset6 = -((animatetimer-10) * scradjust);
if (xoffset2 > 0) xoffset2 = 0; if (xoffset2 > 0) xoffset2 = 0;
if (xoffset3 > 0) xoffset3 = 0; if (xoffset3 > 0) xoffset3 = 0;
if (xoffset4 > 0) xoffset4 = 0; if (xoffset4 > 0) xoffset4 = 0;
if (xoffset5 > 0) xoffset5 = 0; if (xoffset5 > 0) xoffset5 = 0;
if (xoffset6 > 0) xoffset6 = 0;
} }
else if (animatetimer < 32) else if (animatetimer < 34)
{ {
drawsection = 1; drawsection = 1;
xoffset1 = (22-animatetimer) * scradjust; xoffset1 = (24-animatetimer) * scradjust;
xoffset2 = (24-animatetimer) * scradjust; xoffset2 = (26-animatetimer) * scradjust;
xoffset3 = (26-animatetimer) * scradjust; xoffset3 = (28-animatetimer) * scradjust;
xoffset4 = (28-animatetimer) * scradjust; xoffset4 = (30-animatetimer) * scradjust;
xoffset5 = (30-animatetimer) * scradjust; xoffset5 = (32-animatetimer) * scradjust;
xoffset6 = (32-animatetimer) * scradjust; xoffset6 = (34-animatetimer) * scradjust;
if (xoffset1 < 0) xoffset1 = 0; if (xoffset1 < 0) xoffset1 = 0;
if (xoffset2 < 0) xoffset2 = 0; if (xoffset2 < 0) xoffset2 = 0;
if (xoffset3 < 0) xoffset3 = 0; if (xoffset3 < 0) xoffset3 = 0;
@ -370,9 +372,9 @@ void Y_IntermissionDrawer(void)
if (drawsection == 1) if (drawsection == 1)
{ {
const char *ringtext = "\x86" "50 RINGS, NO SHIELD"; const char *ringtext = "\x82" "50 RINGS, NO SHIELD";
const char *tut1text = "\x86" "PRESS " "\x82" "SPIN"; const char *tut1text = "\x82" "PRESS " "\x80" "SPIN";
const char *tut2text = "\x86" "MID-" "\x82" "JUMP"; const char *tut2text = "\x82" "MID-" "\x80" "JUMP";
ttheight = 16; ttheight = 16;
V_DrawLevelTitle(data.spec.passedx1 + xoffset1, ttheight, 0, data.spec.passed1); V_DrawLevelTitle(data.spec.passedx1 + xoffset1, ttheight, 0, data.spec.passed1);
ttheight += V_LevelNameHeight(data.spec.passed3) + 2; ttheight += V_LevelNameHeight(data.spec.passed3) + 2;
@ -389,6 +391,7 @@ void Y_IntermissionDrawer(void)
} }
else else
{ {
INT32 yoffset = 0;
if (data.spec.passed1[0] != '\0') if (data.spec.passed1[0] != '\0')
{ {
ttheight = 24; ttheight = 24;
@ -402,22 +405,31 @@ void Y_IntermissionDrawer(void)
V_DrawLevelTitle(data.spec.passedx2 + xoffset1, ttheight, 0, data.spec.passed2); V_DrawLevelTitle(data.spec.passedx2 + xoffset1, ttheight, 0, data.spec.passed2);
} }
V_DrawScaledPatch(152 + xoffset3, 108, 0, data.spec.bonuspatch); V_DrawScaledPatch(152 + xoffset3, 108, 0, data.spec.bonuspatches[0]);
V_DrawTallNum(BASEVIDWIDTH + xoffset3 - 68, 109, 0, data.spec.bonus.points); V_DrawTallNum(BASEVIDWIDTH + xoffset3 - 68, 109, 0, data.spec.bonuses[0].points);
V_DrawScaledPatch(152 + xoffset4, 124, 0, data.spec.pscore); if (data.spec.bonuses[1].display)
V_DrawTallNum(BASEVIDWIDTH + xoffset4 - 68, 125, 0, data.spec.score); {
V_DrawScaledPatch(152 + xoffset4, 124, 0, data.spec.bonuspatches[1]);
V_DrawTallNum(BASEVIDWIDTH + xoffset4 - 68, 125, 0, data.spec.bonuses[1].points);
yoffset = 16;
// hack; pass the buck along...
xoffset4 = xoffset5;
xoffset5 = xoffset6;
}
V_DrawScaledPatch(152 + xoffset4, 124+yoffset, 0, data.spec.pscore);
V_DrawTallNum(BASEVIDWIDTH + xoffset4 - 68, 125+yoffset, 0, data.spec.score);
// Draw continues! // Draw continues!
if (!multiplayer /* && (data.spec.continues & 0x80) */) // Always draw outside of netplay if (!multiplayer /* && (data.spec.continues & 0x80) */) // Always draw outside of netplay
{ {
UINT8 continues = data.spec.continues & 0x7F; UINT8 continues = data.spec.continues & 0x7F;
V_DrawScaledPatch(152 + xoffset5, 150, 0, data.spec.pcontinues); V_DrawScaledPatch(152 + xoffset5, 150+yoffset, 0, data.spec.pcontinues);
for (i = 0; i < continues; ++i) for (i = 0; i < continues; ++i)
{ {
if ((data.spec.continues & 0x80) && i == continues-1 && (endtic < 0 || intertic%20 < 10)) if ((data.spec.continues & 0x80) && i == continues-1 && (endtic < 0 || intertic%20 < 10))
break; break;
V_DrawContinueIcon(246 + xoffset5 - (i*12), 162, 0, *data.spec.playerchar, *data.spec.playercolor); V_DrawContinueIcon(246 + xoffset5 - (i*12), 162+yoffset, 0, *data.spec.playerchar, *data.spec.playercolor);
} }
} }
} }
@ -904,7 +916,7 @@ void Y_Ticker(void)
{ {
INT32 i; INT32 i;
UINT32 oldscore = data.spec.score; UINT32 oldscore = data.spec.score;
boolean skip = false, super = false; boolean skip = false, super = false, anybonuses = false;
if (!intertic) // first time only if (!intertic) // first time only
{ {
@ -946,16 +958,26 @@ void Y_Ticker(void)
return; return;
} }
// ring bonus counts down by 222 each tic // bonuses count down by 222 each tic
data.spec.bonus.points -= 222; for (i = 0; i < 2; ++i)
data.spec.score += 222;
if (data.spec.bonus.points < 0 || skip == true) // went too far
{ {
data.spec.score += data.spec.bonus.points; if (!data.spec.bonuses[i].points)
data.spec.bonus.points = 0; continue;
data.spec.bonuses[i].points -= 222;
data.spec.score += 222;
if (data.spec.bonuses[i].points < 0 || skip == true) // too far?
{
data.spec.score += data.spec.bonuses[i].points;
data.spec.bonuses[i].points = 0;
}
if (data.spec.score > MAXSCORE)
data.spec.score = MAXSCORE;
if (data.spec.bonuses[i].points > 0)
anybonuses = true;
} }
if (!data.spec.bonus.points) if (!anybonuses)
{ {
tallydonetic = intertic; tallydonetic = intertic;
if (!((data.spec.continues & 0x80) || (super && ALL7EMERALDS(emeralds)))) // don't set endtic yet! if (!((data.spec.continues & 0x80) || (super && ALL7EMERALDS(emeralds)))) // don't set endtic yet!
@ -1301,7 +1323,9 @@ void Y_StartIntermission(void)
// give out ring bonuses // give out ring bonuses
Y_AwardSpecialStageBonus(); Y_AwardSpecialStageBonus();
data.spec.bonuspatch = W_CachePatchName(data.spec.bonus.patch, PU_STATIC); for (i = 0; i < 2; ++i)
data.spec.bonuspatches[i] = W_CachePatchName(data.spec.bonuses[i].patch, PU_STATIC);
data.spec.pscore = W_CachePatchName("YB_SCORE", PU_STATIC); data.spec.pscore = W_CachePatchName("YB_SCORE", PU_STATIC);
data.spec.pcontinues = W_CachePatchName("YB_CONTI", PU_STATIC); data.spec.pcontinues = W_CachePatchName("YB_CONTI", PU_STATIC);
@ -1831,7 +1855,7 @@ static void Y_SetPerfectBonus(player_t *player, y_bonus_t *bstruct)
memset(bstruct, 0, sizeof(y_bonus_t)); memset(bstruct, 0, sizeof(y_bonus_t));
strncpy(bstruct->patch, "YB_PERFE", sizeof(bstruct->patch)); strncpy(bstruct->patch, "YB_PERFE", sizeof(bstruct->patch));
if (data.coop.gotperfbonus == -1) if (intertype != int_coop || data.coop.gotperfbonus == -1)
{ {
INT32 sharedringtotal = 0; INT32 sharedringtotal = 0;
for (i = 0; i < MAXPLAYERS; i++) for (i = 0; i < MAXPLAYERS; i++)
@ -1840,16 +1864,34 @@ static void Y_SetPerfectBonus(player_t *player, y_bonus_t *bstruct)
sharedringtotal += players[i].rings; sharedringtotal += players[i].rings;
} }
if (!sharedringtotal || nummaprings == -1 || sharedringtotal < nummaprings) if (!sharedringtotal || nummaprings == -1 || sharedringtotal < nummaprings)
data.coop.gotperfbonus = 0; bstruct->display = false;
else else
data.coop.gotperfbonus = 1; {
}
if (!data.coop.gotperfbonus)
return;
bstruct->display = true; bstruct->display = true;
bstruct->points = 50000; bstruct->points = 50000;
} }
}
if (intertype != int_coop)
return;
data.coop.gotperfbonus = (bstruct->display ? 1 : 0);
}
static void Y_SetSpecialRingBonus(player_t *player, y_bonus_t *bstruct)
{
INT32 i, sharedringtotal = 0;
(void)player;
strncpy(bstruct->patch, "YB_RING", sizeof(bstruct->patch));
bstruct->display = true;
for (i = 0; i < MAXPLAYERS; i++)
{
if (!playeringame[i]) continue;
sharedringtotal += players[i].rings;
}
bstruct->points = max(0, (sharedringtotal) * 100);
}
// This list can be extended in the future with SOC/Lua, perhaps. // This list can be extended in the future with SOC/Lua, perhaps.
typedef void (*bonus_f)(player_t *, y_bonus_t *); typedef void (*bonus_f)(player_t *, y_bonus_t *);
@ -1953,23 +1995,33 @@ static void Y_AwardCoopBonuses(void)
static void Y_AwardSpecialStageBonus(void) static void Y_AwardSpecialStageBonus(void)
{ {
INT32 i, oldscore, ptlives; INT32 i, oldscore, ptlives;
y_bonus_t localbonus; y_bonus_t localbonuses[2];
data.spec.score = players[consoleplayer].score; data.spec.score = players[consoleplayer].score;
memset(&data.spec.bonus, 0, sizeof(data.spec.bonus)); memset(data.spec.bonuses, 0, sizeof(data.spec.bonuses));
data.spec.bonuspatch = NULL; memset(data.spec.bonuspatches, 0, sizeof(data.coop.bonuspatches));
for (i = 0; i < MAXPLAYERS; i++) for (i = 0; i < MAXPLAYERS; i++)
{ {
oldscore = players[i].score; oldscore = players[i].score;
if (!playeringame[i] || players[i].lives < 1) // not active or game over if (!playeringame[i] || players[i].lives < 1) // not active or game over
Y_SetNullBonus(&players[i], &localbonus); {
else if (maptol & TOL_NIGHTS) // Mare score instead of Rings Y_SetNullBonus(&players[i], &localbonuses[0]);
Y_SetNightsBonus(&players[i], &localbonus); Y_SetNullBonus(&players[i], &localbonuses[1]);
}
else if (maptol & TOL_NIGHTS) // NiGHTS bonus score instead of Rings
{
Y_SetNightsBonus(&players[i], &localbonuses[0]);
Y_SetNullBonus(&players[i], &localbonuses[1]);
}
else else
Y_SetRingBonus(&players[i], &localbonus); {
players[i].score += localbonus.points; Y_SetSpecialRingBonus(&players[i], &localbonuses[0]);
Y_SetPerfectBonus(&players[i], &localbonuses[1]);
}
players[i].score += localbonuses[0].points;
players[i].score += localbonuses[1].points;
if (players[i].score > MAXSCORE) if (players[i].score > MAXSCORE)
players[i].score = MAXSCORE; players[i].score = MAXSCORE;
@ -1982,7 +2034,7 @@ static void Y_AwardSpecialStageBonus(void)
if (i == consoleplayer) if (i == consoleplayer)
{ {
data.spec.gotlife = (((netgame || multiplayer) && gametype == GT_COOP && cv_cooplives.value == 0) ? 0 : ptlives); data.spec.gotlife = (((netgame || multiplayer) && gametype == GT_COOP && cv_cooplives.value == 0) ? 0 : ptlives);
M_Memcpy(&data.spec.bonus, &localbonus, sizeof(data.spec.bonus)); M_Memcpy(&data.spec.bonuses, &localbonuses, sizeof(data.spec.bonuses));
// Continues related // Continues related
data.spec.continues = min(players[i].continues, 8); data.spec.continues = min(players[i].continues, 8);
@ -2057,7 +2109,8 @@ static void Y_UnloadData(void)
// unload the special stage patches // unload the special stage patches
//UNLOAD(data.spec.cemerald); //UNLOAD(data.spec.cemerald);
//UNLOAD(data.spec.nowsuper); //UNLOAD(data.spec.nowsuper);
UNLOAD(data.spec.bonuspatch); UNLOAD(data.spec.bonuspatches[1]);
UNLOAD(data.spec.bonuspatches[0]);
UNLOAD(data.spec.pscore); UNLOAD(data.spec.pscore);
UNLOAD(data.spec.pcontinues); UNLOAD(data.spec.pcontinues);
break; break;