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

View File

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

View File

@ -517,7 +517,9 @@ static void readfreeslots(MYFILE *f)
continue;
// Copy in the spr2 name and increment free_spr2.
if (free_spr2 < NUMPLAYERSPRITES) {
CONS_Printf("Sprite SPR2_%s allocated.\n",word);
strncpy(spr2names[free_spr2],word,4);
spr2defaults[free_spr2] = 0;
spr2names[free_spr2++][4] = 0;
} else
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;
else if (fastcmp(word2, "EVALUATION")) i = 1101;
else if (fastcmp(word2, "CREDITS")) i = 1102;
else if (fastcmp(word2, "ENDING")) i = 1103;
else
// Support using the actual map name,
// 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_CEZPOLE",
"S_CEZBANNER",
"S_CEZBANNER1",
"S_CEZBANNER2",
"S_PINETREE",
"S_CEZBUSH1",
"S_CEZBUSH2",
@ -5708,7 +5712,8 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
"S_FLAMEHOLDER",
"S_FIRETORCH",
"S_WAVINGFLAG",
"S_WAVINGFLAGSEG",
"S_WAVINGFLAGSEG1",
"S_WAVINGFLAGSEG2",
"S_CRAWLASTATUE",
"S_FACESTABBERSTATUE",
"S_SUSPICIOUSFACESTABBERSTATUE_WAIT",
@ -7514,8 +7519,10 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s
"MT_SMALLFIREBAR", // Small Firebar
"MT_BIGFIREBAR", // Big Firebar
"MT_CEZFLOWER", // Flower
"MT_CEZPOLE", // Pole
"MT_CEZBANNER", // Banner
"MT_CEZPOLE1", // Pole (with red banner)
"MT_CEZPOLE2", // Pole (with blue banner)
"MT_CEZBANNER1", // Banner (red)
"MT_CEZBANNER2", // Banner (blue)
"MT_PINETREE", // Pine Tree
"MT_CEZBUSH1", // Bush 1
"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_FLAMEHOLDER", // Flame holder
"MT_FIRETORCH", // Fire torch
"MT_WAVINGFLAG", // Waving flag
"MT_WAVINGFLAGSEG", // Waving flag segment
"MT_WAVINGFLAG1", // Waving flag (red)
"MT_WAVINGFLAG2", // Waving flag (blue)
"MT_WAVINGFLAGSEG1", // Waving flag segment (red)
"MT_WAVINGFLAGSEG2", // Waving flag segment (blue)
"MT_CRAWLASTATUE", // Crawla statue
"MT_FACESTABBERSTATUE", // Facestabber statue
"MT_SUSPICIOUSFACESTABBERSTATUE", // :eggthinking:
@ -9493,6 +9502,7 @@ static inline int lib_freeslot(lua_State *L)
{
CONS_Printf("Sprite SPR2_%s allocated.\n",word);
strncpy(spr2names[free_spr2],word,4);
spr2defaults[free_spr2] = 0;
spr2names[free_spr2++][4] = 0;
} else
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.
extern INT16 nextmapoverride;
extern boolean skipstats;
extern UINT8 skipstats;
extern UINT32 ssspheres; // Total # of spheres in a level

View File

@ -14,6 +14,7 @@
#include "doomdef.h"
#include "doomstat.h"
#include "d_main.h"
#include "d_netcmd.h"
#include "f_finale.h"
#include "g_game.h"
#include "hu_stuff.h"
@ -36,6 +37,7 @@
#include "p_setup.h"
#include "st_stuff.h" // hud hiding
#include "fastcmp.h"
#include "console.h"
#ifdef HAVE_BLUA
#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 INT16 skullAnimCounter; // Prompts: Chevron animation
static INT32 roidtics; // Asteroid spinning
static INT32 deplete;
static tic_t stoptimer;
@ -95,10 +96,22 @@ static patch_t *ttspop5;
static patch_t *ttspop6;
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
//
static boolean promptactive = false;
boolean promptactive = false;
static mobj_t *promptmo;
static INT16 promptpostexectag;
static boolean promptblockcontrols;
@ -230,6 +243,7 @@ void F_StartCustomCutscene(INT32 cutscenenum, boolean precutscene, boolean reset
void F_StartIntro(void)
{
S_StopMusic();
S_StopSounds();
if (introtoplay)
{
@ -393,7 +407,6 @@ void F_StartIntro(void)
intro_scenenum = 0;
finalecount = animtimer = skullAnimCounter = stoptimer = 0;
roidtics = BASEVIDWIDTH - 64;
timetonext = introscenetime[intro_scenenum];
}
@ -676,11 +689,42 @@ static void F_IntroDrawScene(void)
if (intro_scenenum == 4) // The asteroid SPINS!
{
if (roidtics >= 0)
if (intro_curtime > 1)
{
V_DrawScaledPatch(roidtics, 24, 0,
(patch = W_CachePatchName(va("ROID00%.2d", intro_curtime%35), PU_CACHE)));
W_UnlockCachedPatch(patch);
INT32 worktics = intro_curtime - 1;
INT32 scale = FRACUNIT;
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);
}
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);
}
else if (intro_scenenum == 3)
roidtics = BASEVIDWIDTH - 64;
else if (intro_scenenum == 10)
{
// The only fade to white in the entire damn game.
@ -849,9 +891,6 @@ void F_IntroTicker(void)
// advance animation
finalecount++;
if (finalecount % 3 == 0)
roidtics--;
timetonext--;
F_WriteText();
@ -947,6 +986,7 @@ static const char *credits[] = {
"\1Assistance",
"\"chi.miru\"", // helped port slope drawing code from ZDoom
"Andrew \"orospakr\" Clunis",
"Sally \"TehRealSalt\" Cochenour",
"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)
"Victor \"Steel Titanium\" Fuentes",
@ -966,8 +1006,9 @@ static const char *credits[] = {
// Everyone else is acknowledged under "Special Thanks > SRB2 Community Contributors".
"",
"\1Sprite Artists",
"Odi \"Iceman404\" Atunzu",
"\"Iceman404\"",
"Victor \"VAdaPEGA\" Ara\x1Fjo", // Araújo -- sorry for our limited font! D:
"Sally \"TehRealSalt\" Cochenour",
"Jim \"MotorRoach\" DeMello",
"Desmond \"Blade\" DesJardins",
"Sherman \"CoatRack\" DesJardins",
@ -1049,7 +1090,10 @@ static const char *credits[] = {
"Simon \"sirjuddington\" Judd", // SLADE developer
// Acknowledged here are the following:
// 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",
"",
"\1Produced By",
@ -1103,6 +1147,7 @@ void F_StartCredits(void)
paused = false;
CON_ToggleOff();
S_StopMusic();
S_StopSounds();
S_ChangeMusicInternal("_creds", false);
@ -1221,7 +1266,7 @@ boolean F_CreditResponder(event_t *event)
break;
}
if (!(timesBeaten) && !(netgame || multiplayer))
if (!(timesBeaten) && !(netgame || multiplayer) && !cv_debug)
return false;
if (event->type != ev_keydown)
@ -1240,10 +1285,8 @@ boolean F_CreditResponder(event_t *event)
// ============
// EVALUATION
// ============
#define INTERVAL 50
#define TRANSLEVEL V_80TRANS
static INT32 eemeralds_start;
static boolean drawemblem = false, drawchaosemblem = false;
#define SPARKLLOOPTIME 7 // must be odd
void F_StartGameEvaluation(void)
{
@ -1265,76 +1308,122 @@ void F_StartGameEvaluation(void)
if ((!modifiedgame || savemoddata) && !(netgame || multiplayer) && cursaveslot > 0)
G_SaveGame((UINT32)cursaveslot);
goodending = (ALL7EMERALDS(emeralds));
gameaction = ga_nothing;
paused = false;
CON_ToggleOff();
finalecount = 0;
finalecount = -1;
sparklloop = 0;
}
void F_GameEvaluationDrawer(void)
{
INT32 x, y, i;
const fixed_t radius = 48*FRACUNIT;
angle_t fa;
INT32 eemeralds_cur;
char patchname[7] = "CEMGx0";
const char* endingtext = (goodending ? "CONGRATULATIONS!" : "TRY AGAIN...");
V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31);
// 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++;
eemeralds_cur = eemeralds_start;
for (i = 0; i < 7; ++i)
if (finalecount > 0)
{
fa = (FixedAngle(eemeralds_cur*FRACUNIT)>>ANGLETOFINESHIFT) & FINEMASK;
x = 160 + FixedInt(FixedMul(FINECOSINE(fa),radius));
y = 100 + FixedInt(FixedMul(FINESINE(fa),radius));
INT32 scale = FRACUNIT;
patch_t *rockpat;
UINT8 *colormap[2] = {NULL, NULL};
patch_t *glow;
INT32 trans = 0;
patchname[4] = 'A'+(char)i;
if (emeralds & (1<<i))
V_DrawScaledPatch(x, y, 0, W_CachePatchName(patchname, PU_CACHE));
else
V_DrawTranslucentPatch(x, y, TRANSLEVEL, W_CachePatchName(patchname, PU_CACHE));
x = (((BASEVIDWIDTH-82)/2)+11)<<FRACBITS;
y = (((BASEVIDHEIGHT-82)/2)+12)<<FRACBITS;
eemeralds_cur += INTERVAL;
}
if (eemeralds_start >= 360)
eemeralds_start -= 360;
if (finalecount == 5*TICRATE)
{
if ((!modifiedgame || savemoddata) && !(netgame || multiplayer))
if (finalecount < 5)
{
++timesBeaten;
scale = (finalecount<<(FRACBITS-2));
x += (30*(FRACUNIT-scale));
y += (30*(FRACUNIT-scale));
}
if (ALL7EMERALDS(emeralds))
++timesBeatenWithEmeralds;
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 (ultimatemode)
++timesBeatenUltimate;
if (finalecount >= 5)
trans = (finalecount-5)>>1;
if (trans < 10)
V_DrawFixedPatch(x, y, scale, trans<<V_ALPHASHIFT, glow, NULL);
if (M_UpdateUnlockablesAndExtraEmblems())
S_StartSound(NULL, sfx_s3k68);
trans = (15-finalecount);
if (trans < 0)
trans = -trans;
G_SaveGameData();
if (finalecount < 15)
colormap[0] = R_GetTranslationColormap(TC_ALLWHITE, 0, GTC_CACHE);
V_DrawFixedPatch(x, y, scale, 0, rockpat, colormap[0]);
if (trans < 10)
{
colormap[1] = R_GetTranslationColormap(TC_BLINK, SKINCOLOR_AQUA, GTC_CACHE);
V_DrawFixedPatch(x, y, scale, trans<<V_ALPHASHIFT, rockpat, colormap[1]);
}
if (goodending)
{
INT32 j = (sparklloop & 1) ? 2 : 3;
if (j > (finalecount/SPARKLLOOPTIME))
j = (finalecount/SPARKLLOOPTIME);
while (j)
{
if (j > 1 || sparklloop >= 2)
{
// if j == 0 - alternate between 0 and 1
// 1 - 1 and 2
// 2 - 2 and not rendered
V_DrawFixedPatch(x+sparkloffs[j-1][0], y+sparkloffs[j-1][1], FRACUNIT, 0, W_CachePatchName(va("ENDSPKL%.1d", (j - ((sparklloop & 1) ? 0 : 1))), PU_LEVEL), R_GetTranslationColormap(TC_DEFAULT, SKINCOLOR_AQUA, GTC_CACHE));
}
j--;
}
}
else
{
patch_t *eggrock = W_CachePatchName("ENDEGRK5", PU_LEVEL);
V_DrawFixedPatch(x, y, scale, 0, eggrock, colormap[0]);
if (trans < 10)
V_DrawFixedPatch(x, y, scale, trans<<V_ALPHASHIFT, eggrock, colormap[1]);
else if (sparklloop)
V_DrawFixedPatch(x, y, scale, (10-sparklloop)<<V_ALPHASHIFT,
W_CachePatchName("ENDEGRK0", PU_LEVEL), colormap[1]);
}
}
eemeralds_cur = (finalecount % 360)<<FRACBITS;
for (i = 0; i < 7; ++i)
{
fa = (FixedAngle(eemeralds_cur)>>ANGLETOFINESHIFT) & FINEMASK;
x = (BASEVIDWIDTH<<(FRACBITS-1)) + (60*FINECOSINE(fa));
y = ((BASEVIDHEIGHT+16)<<(FRACBITS-1)) + (60*FINESINE(fa));
eemeralds_cur += (360<<FRACBITS)/7;
patchname[4] = 'A'+(char)i;
V_DrawFixedPatch(x, y, FRACUNIT, ((emeralds & (1<<i)) ? 0 : V_80TRANS), W_CachePatchName(patchname, PU_LEVEL), NULL);
}
V_DrawCreditString((BASEVIDWIDTH - V_CreditStringWidth(endingtext))<<(FRACBITS-1), (BASEVIDHEIGHT-100)<<(FRACBITS-1), 0, endingtext);
#if 0 // the following looks like hot garbage the more unlockables we add, and we now have a lot of unlockables
if (finalecount >= 5*TICRATE)
{
if (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:");
if (!(netgame) && (!modifiedgame || savemoddata))
@ -1357,16 +1446,603 @@ void F_GameEvaluationDrawer(void)
else
V_DrawString(8, 96, V_YELLOWMAP, "Prizes not\nawarded in\nmodified games!");
}
#endif
}
void F_GameEvaluationTicker(void)
{
finalecount++;
if (finalecount > 10*TICRATE)
if (++finalecount > 10*TICRATE)
{
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
// ==========
@ -1378,6 +2054,7 @@ void F_StartGameEnd(void)
paused = false;
CON_ToggleOff();
S_StopMusic();
S_StopSounds();
// In case menus are still up?!!
M_ClearMenus(true);
@ -1892,7 +2569,7 @@ boolean F_ContinueResponder(event_t *event)
keypressed = true;
imcontinuing = true;
continuetime = TICRATE;
S_StartSound(0, sfx_itemup);
S_StartSound(NULL, sfx_itemup);
return true;
}
@ -2004,6 +2681,7 @@ void F_StartCustomCutscene(INT32 cutscenenum, boolean precutscene, boolean reset
cutscenes[cutnum]->scene[scenenum].musswitchposition, 0, 0);
else
S_StopMusic();
S_StopSounds();
}
//
@ -2044,7 +2722,7 @@ void F_CutsceneDrawer(void)
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)

View File

@ -46,6 +46,9 @@ void F_GameEvaluationDrawer(void);
void F_StartGameEvaluation(void);
void F_GameEvaluationTicker(void);
void F_EndingTicker(void);
void F_EndingDrawer(void);
void F_CreditTicker(void);
void F_CreditDrawer(void);
@ -63,6 +66,7 @@ boolean F_GetPromptHideHud(fixed_t y);
void F_StartGameEnd(void);
void F_StartIntro(void);
void F_StartTitleScreen(void);
void F_StartEnding(void);
void F_StartCredits(void);
boolean F_ContinueResponder(event_t *event);
@ -82,7 +86,6 @@ typedef enum
// Current menu parameters
extern UINT8 titlemapinaction;
extern mobj_t *titlemapcameraref;
extern char curbgname[8];
extern SINT8 curfadevalue;
@ -126,6 +129,7 @@ enum
wipe_evaluation_toblack,
wipe_gameend_toblack,
wipe_intro_toblack,
wipe_ending_toblack,
wipe_cutscene_toblack,
// custom intermissions
@ -142,15 +146,16 @@ enum
wipe_evaluation_final,
wipe_gameend_final,
wipe_intro_final,
wipe_ending_final,
wipe_cutscene_final,
// custom intermissions
wipe_specinter_final,
wipe_multinter_final,
NUMWIPEDEFS
NUMWIPEDEFS,
WIPEFINALSHIFT = (wipe_level_final-wipe_level_toblack)
};
#define WIPEFINALSHIFT 13
extern UINT8 wipedefs[NUMWIPEDEFS];
#endif

View File

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

View File

@ -152,7 +152,7 @@ cutscene_t *cutscenes[128];
textprompt_t *textprompts[MAX_PROMPTS];
INT16 nextmapoverride;
boolean skipstats;
UINT8 skipstats;
// Pointers to each CTF flag
mobj_t *redflag;
@ -1842,7 +1842,7 @@ boolean G_Responder(event_t *ev)
return true;
}
}
else if (gamestate == GS_CREDITS)
else if (gamestate == GS_CREDITS || gamestate == GS_ENDING) // todo: keep ending here?
{
if (HU_Responder(ev))
return true; // chat ate the event
@ -2032,6 +2032,12 @@ void G_Ticker(boolean run)
F_IntroTicker();
break;
case GS_ENDING:
if (run)
F_EndingTicker();
HU_Ticker();
break;
case GS_CUTSCENE:
if (run)
F_CutsceneTicker();
@ -2645,7 +2651,7 @@ void G_DoReborn(INT32 playernum)
//nextmapoverride = spstage_start;
nextmapoverride = gamemap;
countdown2 = TICRATE;
skipstats = true;
skipstats = 2;
for (i = 0; i < MAXPLAYERS; i++)
{
@ -2849,6 +2855,10 @@ void G_ExitLevel(void)
// Remove CEcho text on round end.
HU_ClearCEcho();
}
else if (gamestate == GS_ENDING)
{
F_StartCredits();
}
else if (gamestate == GS_CREDITS)
{
F_StartGameEvaluation();
@ -3116,7 +3126,7 @@ static void G_DoCompleted(void)
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);
// wrap around in race
@ -3170,7 +3180,7 @@ void G_AfterIntermission(void)
{
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);
else
{
@ -3282,6 +3292,11 @@ void G_EndGame(void)
// Only do evaluation and credits in coop games.
if (gametype == GT_COOP)
{
if (nextmap == 1103-1) // end game with ending
{
F_StartEnding();
return;
}
if (nextmap == 1102-1) // end game with credits
{
F_StartCredits();
@ -3700,7 +3715,7 @@ void G_SaveGame(UINT32 slot)
backup = va("%s",savename);
// 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;
gameaction = ga_nothing;
@ -4366,7 +4381,7 @@ void G_WriteGhostTic(mobj_t *ghost)
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;
@ -4592,6 +4607,9 @@ void G_GhostTicker(void)
switch(g->color)
{
default:
case GHC_RETURNSKIN:
g->mo->skin = g->oldmo.skin;
// fallthru
case GHC_NORMAL: // Go back to skin color
g->mo->color = g->oldmo.color;
break;
@ -4602,6 +4620,9 @@ void G_GhostTicker(void)
case GHC_FIREFLOWER: // Fireflower
g->mo->color = SKINCOLOR_WHITE;
break;
case GHC_NIGHTSSKIN: // not actually a colour
g->mo->skin = &skins[DEFAULTNIGHTSSKIN];
break;
}
}
if (xziptic & EZT_FLIP)

View File

@ -56,6 +56,8 @@ extern INT16 rw_maximums[NUM_WEAPONS];
extern INT32 pausedelay;
extern boolean pausebreakkey;
extern boolean promptactive;
// used in game menu
extern consvar_t cv_tutorialprompt;
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_SUPER,
GHC_FIREFLOWER,
GHC_INVINCIBLE
GHC_INVINCIBLE,
GHC_NIGHTSSKIN, // not actually a colour
GHC_RETURNSKIN // ditto
} ghostcolor_t;
// Record/playback tics

View File

@ -27,12 +27,14 @@ typedef enum
GS_TITLESCREEN, // title screen
GS_TIMEATTACK, // time attack menu
GS_CREDITS, // credit sequence
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
GS_INTRO, // introduction
GS_ENDING, // currently shared between bad and good endings
GS_CUTSCENE, // custom cutscene
// Not fadable
@ -50,6 +52,7 @@ typedef enum
} gameaction_t;
extern gamestate_t gamestate;
extern UINT8 titlemapinaction;
extern UINT8 ultimatemode; // was sk_insane
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 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
// 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)
@ -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
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 UINT8 *source = (const UINT8 *)(column) + 3;
HWR_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, (column->topdelta == 0xff ? 31 : source[0]));
if (!column->topdelta)
{
const UINT8 *source = (const UINT8 *)(column) + 3;
HWR_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, (column->topdelta == 0xff ? 31 : source[0]));
}
Z_Free(realpatch);
}
// 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 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
// 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)
@ -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
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 UINT8 *source = (const UINT8 *)(column) + 3;
HWR_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, (column->topdelta == 0xff ? 31 : source[0]));
if (!column->topdelta)
{
const UINT8 *source = (const UINT8 *)(column) + 3;
HWR_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, (column->topdelta == 0xff ? 31 : source[0]));
}
Z_Free(realpatch);
}
// centre screen
@ -683,8 +689,183 @@ void HWR_FadeScreenMenuBack(UINT16 color, UINT8 strength)
}
else // Do TRANSMAP** fade.
{
Surf.FlatColor.rgba = pLocalPalette[color].rgba;
Surf.FlatColor.s.alpha = (UINT8)(strength*25.5f);
Surf.FlatColor.rgba = V_GetColor(color).rgba;
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);
}
@ -905,54 +1086,117 @@ void HWR_DrawConsoleFill(INT32 x, INT32 y, INT32 w, INT32 h, UINT32 color, INT32
FSurfaceInfo Surf;
float fx, fy, fw, fh;
if (w < 0 || h < 0)
return; // consistency w/ software
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 (!(options & V_NOSCALESTART))
if (!(color & V_NOSCALESTART))
{
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;
fy *= dupy;
fw *= dupx;
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));
else if (!(options & V_SNAPTOLEFT))
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)
if (fabsf((float)vid.height - (float)BASEVIDHEIGHT * dupy) > 1.0E-36f)
{
// same thing here
if (options & V_SNAPTOBOTTOM)
if (color & V_SNAPTOBOTTOM)
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;
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;
if (w < 0 || h < 0)
return; // consistency w/ software
// 3--2
// | /|
// |/ |

View File

@ -49,6 +49,7 @@ void HWR_CreatePlanePolygons(INT32 bspnum);
void HWR_CreateStaticLightmaps(INT32 bspnum);
void HWR_PrepLevelCache(size_t pnumtextures);
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_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)
return 0;
if ((spr2 & ~FF_SPR2SUPER) >= free_spr2)
return 0;
while (!(md2->model->spr2frames[spr2*2 + 1])
&& spr2 != SPR2_STND
&& ++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;
break;
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;
// 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;
}
if (i >= 32) // probably an infinite loop...
return 0;
return spr2;
}

View File

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

View File

@ -578,7 +578,8 @@ char spr2names[NUMPLAYERSPRITES][5] =
"TALB",
"SIGN",
"LIFE"
"LIFE",
"XTRA",
};
playersprite_t free_spr2 = SPR2_FIRSTFREESLOT;
@ -595,7 +596,7 @@ playersprite_t spr2defaults[NUMPLAYERSPRITES] = {
SPR2_DEAD, // SPR2_DRWN,
0, // SPR2_ROLL,
SPR2_SPNG, // SPR2_GASP,
0, // SPR2_JUMP, (conditional)
0, // SPR2_JUMP, (conditional, will never be referenced)
SPR2_FALL, // SPR2_SPNG,
SPR2_WALK, // SPR2_FALL,
0, // SPR2_EDGE,
@ -605,7 +606,7 @@ playersprite_t spr2defaults[NUMPLAYERSPRITES] = {
SPR2_SPNG, // SPR2_FLY ,
SPR2_FLY , // SPR2_SWIM,
0, // SPR2_TIRE, (conditional)
0, // SPR2_TIRE, (conditional, will never be referenced)
SPR2_FLY , // SPR2_GLID,
SPR2_CLMB, // SPR2_CLNG,
@ -632,7 +633,7 @@ playersprite_t spr2defaults[NUMPLAYERSPRITES] = {
SPR2_NSTN, // SPR2_NPUL,
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_NGT1, // SPR2_NGT2,
SPR2_NGT2, // SPR2_NGT3,
@ -660,7 +661,7 @@ playersprite_t spr2defaults[NUMPLAYERSPRITES] = {
SPR2_NGTB, // SPR2_DRLB,
SPR2_NGTC, // SPR2_DRLC,
0, // SPR2_TAL0,
0, // SPR2_TAL0, (this will look mighty stupid but oh well)
SPR2_TAL0, // SPR2_TAL1,
SPR2_TAL1, // SPR2_TAL2,
SPR2_TAL2, // SPR2_TAL3,
@ -675,6 +676,7 @@ playersprite_t spr2defaults[NUMPLAYERSPRITES] = {
0, // SPR2_SIGN,
0, // SPR2_LIFE,
0, // SPR2_XTRA (should never be referenced)
};
// 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
{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
// Bomb Sphere
@ -2322,9 +2328,10 @@ state_t states[NUMSTATES] =
{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_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_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_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
@ -11018,7 +11026,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_NULL // raisestate
},
{ // MT_CEZPOLE
{ // MT_CEZPOLE1
1117, // doomednum
S_CEZPOLE, // spawnstate
1000, // spawnhealth
@ -11045,9 +11053,63 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
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
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
S_NULL, // seestate
sfx_None, // seesound
@ -11261,8 +11323,8 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_NULL // raisestate
},
{ // MT_WAVINGFLAG
1118, // doomednum
{ // MT_WAVINGFLAG1
1128, // doomednum
S_WAVINGFLAG, // spawnstate
1000, // spawnhealth
S_NULL, // seestate
@ -11278,8 +11340,8 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_NULL, // xdeathstate
sfx_None, // deathsound
0, // speed
4*FRACUNIT, // radius
104*FRACUNIT, // height
8*FRACUNIT, // radius
208*FRACUNIT, // height
0, // display offset
100, // mass
0, // damage
@ -11288,9 +11350,9 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_NULL // raisestate
},
{ // MT_WAVINGFLAGSEG
-1, // doomednum
S_WAVINGFLAGSEG, // spawnstate
{ // MT_WAVINGFLAG2
1129, // doomednum
S_WAVINGFLAG, // spawnstate
1000, // spawnhealth
S_NULL, // seestate
sfx_None, // seesound
@ -11305,7 +11367,61 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_NULL, // xdeathstate
sfx_None, // deathsound
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
0, // display offset
100, // mass

View File

@ -834,6 +834,7 @@ typedef enum playersprite
SPR2_SIGN, // end sign head
SPR2_LIFE, // life monitor icon
SPR2_XTRA, // stuff that isn't in-game - keep this last in the list
SPR2_FIRSTFREESLOT,
SPR2_LASTFREESLOT = 0x7f,
@ -2458,7 +2459,8 @@ typedef enum state
S_CEZFLOWER,
S_CEZPOLE,
S_CEZBANNER,
S_CEZBANNER1,
S_CEZBANNER2,
S_PINETREE,
S_CEZBUSH1,
S_CEZBUSH2,
@ -2467,7 +2469,8 @@ typedef enum state
S_FLAMEHOLDER,
S_FIRETORCH,
S_WAVINGFLAG,
S_WAVINGFLAGSEG,
S_WAVINGFLAGSEG1,
S_WAVINGFLAGSEG2,
S_CRAWLASTATUE,
S_FACESTABBERSTATUE,
S_SUSPICIOUSFACESTABBERSTATUE_WAIT,
@ -4295,8 +4298,10 @@ typedef enum mobj_type
MT_SMALLFIREBAR, // Small Firebar
MT_BIGFIREBAR, // Big Firebar
MT_CEZFLOWER, // Flower
MT_CEZPOLE, // Pole
MT_CEZBANNER, // Banner
MT_CEZPOLE1, // Pole (with red banner)
MT_CEZPOLE2, // Pole (with blue banner)
MT_CEZBANNER1, // Banner (red)
MT_CEZBANNER2, // Banner (blue)
MT_PINETREE, // Pine Tree
MT_CEZBUSH1, // Bush 1
MT_CEZBUSH2, // Bush 2
@ -4304,8 +4309,10 @@ typedef enum mobj_type
MT_CANDLEPRICKET, // Candle pricket
MT_FLAMEHOLDER, // Flame holder
MT_FIRETORCH, // Fire torch
MT_WAVINGFLAG, // Waving flag
MT_WAVINGFLAGSEG, // Waving flag segment
MT_WAVINGFLAG1, // Waving flag (red)
MT_WAVINGFLAG2, // Waving flag (blue)
MT_WAVINGFLAGSEG1, // Waving flag segment (red)
MT_WAVINGFLAGSEG2, // Waving flag segment (blue)
MT_CRAWLASTATUE, // Crawla statue
MT_FACESTABBERSTATUE, // Facestabber statue
MT_SUSPICIOUSFACESTABBERSTATUE, // :eggthinking:

View File

@ -33,8 +33,6 @@
#define NOHUD if (hud_running)\
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) {
luaL_checktype(L, narg, LUA_TBOOLEAN);
@ -2047,12 +2045,22 @@ static int lib_pStartQuake(lua_State *L)
static int lib_evCrumbleChain(lua_State *L)
{
sector_t *sec = *((sector_t **)luaL_checkudata(L, 1, META_SECTOR));
ffloor_t *rover = *((ffloor_t **)luaL_checkudata(L, 2, META_FFLOOR));
sector_t *sec = NULL;
ffloor_t *rover = NULL;
NOHUD
INLEVEL
if (!sec)
return LUA_ErrInvalid(L, "sector_t");
if (!lua_isnone(L, 2))
{
if (!lua_isnil(L, 1))
{
sec = *((sector_t **)luaL_checkudata(L, 1, META_SECTOR));
if (!sec)
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)
return LUA_ErrInvalid(L, "ffloor_t");
EV_CrumbleChain(sec, rover);
@ -2601,12 +2609,12 @@ static int lib_gSetCustomExitVars(lua_State *L)
nextmapoverride = (INT16)luaL_checknumber(L, 1);
lua_remove(L, 1); // remove nextmapoverride; skipstats now 1 if available
}
skipstats = lua_optboolean(L, 1);
skipstats = luaL_optinteger(L, 2, 0);
}
else
{
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)
#define NOHOOK if (!lua_lumploading)\
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;

View File

@ -157,6 +157,18 @@ static int lib_setSpr2default(lua_State *L)
playersprite_t i;
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.
if (lua_isnumber(L, 1))
@ -175,8 +187,9 @@ static int lib_setSpr2default(lua_State *L)
else
return luaL_error(L, "spr2defaults[] invalid index");
if (i < SPR2_FIRSTFREESLOT || i >= free_spr2)
return luaL_error(L, "spr2defaults[] index %d out of range (%d - %d)", i, SPR2_FIRSTFREESLOT, free_spr2-1);
if (i < FIRSTMODIFY || i >= free_spr2)
return luaL_error(L, "spr2defaults[] index %d out of range (%d - %d)", i, FIRSTMODIFY, free_spr2-1);
#undef FIRSTMODIFY
if (lua_isnumber(L, 2))
j = lua_tonumber(L, 2);
@ -189,11 +202,13 @@ static int lib_setSpr2default(lua_State *L)
break;
}
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)
j = 0; // return luaL_error(L, "spr2defaults[] set %d out of range (%d - %d)", j, 0, free_spr2-1);
if (j < 0 || j >= free_spr2)
return luaL_error(L, "spr2defaults[] set %d out of range (%d - %d)", j, 0, free_spr2-1);
spr2defaults[i] = j;
return 0;

View File

@ -333,8 +333,7 @@ static int lib_iterateSectorThinglist(lua_State *L)
mobj_t *state = NULL;
mobj_t *thing = NULL;
if (gamestate != GS_LEVEL)
return luaL_error(L, "This function can only be used in a level!");
INLEVEL
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'.");
@ -369,8 +368,7 @@ static int lib_iterateSectorFFloors(lua_State *L)
ffloor_t *state = NULL;
ffloor_t *ffloor = NULL;
if (gamestate != GS_LEVEL)
return luaL_error(L, "This function can only be used in a level!");
INLEVEL
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'.");
@ -1251,8 +1249,7 @@ static int bbox_get(lua_State *L)
static int lib_iterateSectors(lua_State *L)
{
size_t i = 0;
if (gamestate != GS_LEVEL)
return luaL_error(L, "This function can only be used in a level!");
INLEVEL
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'.");
lua_settop(L, 2);
@ -1270,8 +1267,7 @@ static int lib_iterateSectors(lua_State *L)
static int lib_getSector(lua_State *L)
{
int field;
if (gamestate != GS_LEVEL)
return luaL_error(L, "You cannot access this outside of a level!");
INLEVEL
lua_settop(L, 2);
lua_remove(L, 1); // dummy userdata table is unused.
if (lua_isnumber(L, 1))
@ -1305,8 +1301,7 @@ static int lib_numsectors(lua_State *L)
static int lib_iterateSubsectors(lua_State *L)
{
size_t i = 0;
if (gamestate != GS_LEVEL)
return luaL_error(L, "This function can only be used in a level!");
INLEVEL
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'.");
lua_settop(L, 2);
@ -1324,8 +1319,7 @@ static int lib_iterateSubsectors(lua_State *L)
static int lib_getSubsector(lua_State *L)
{
int field;
if (gamestate != GS_LEVEL)
return luaL_error(L, "You cannot access this outside of a level!");
INLEVEL
lua_settop(L, 2);
lua_remove(L, 1); // dummy userdata table is unused.
if (lua_isnumber(L, 1))
@ -1359,8 +1353,7 @@ static int lib_numsubsectors(lua_State *L)
static int lib_iterateLines(lua_State *L)
{
size_t i = 0;
if (gamestate != GS_LEVEL)
return luaL_error(L, "This function can only be used in a level!");
INLEVEL
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'.");
lua_settop(L, 2);
@ -1378,8 +1371,7 @@ static int lib_iterateLines(lua_State *L)
static int lib_getLine(lua_State *L)
{
int field;
if (gamestate != GS_LEVEL)
return luaL_error(L, "You cannot access this outside of a level!");
INLEVEL
lua_settop(L, 2);
lua_remove(L, 1); // dummy userdata table is unused.
if (lua_isnumber(L, 1))
@ -1413,8 +1405,7 @@ static int lib_numlines(lua_State *L)
static int lib_iterateSides(lua_State *L)
{
size_t i = 0;
if (gamestate != GS_LEVEL)
return luaL_error(L, "This function can only be used in a level!");
INLEVEL
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'.");
lua_settop(L, 2);
@ -1432,8 +1423,7 @@ static int lib_iterateSides(lua_State *L)
static int lib_getSide(lua_State *L)
{
int field;
if (gamestate != GS_LEVEL)
return luaL_error(L, "You cannot access this outside of a level!");
INLEVEL
lua_settop(L, 2);
lua_remove(L, 1); // dummy userdata table is unused.
if (lua_isnumber(L, 1))
@ -1467,8 +1457,7 @@ static int lib_numsides(lua_State *L)
static int lib_iterateVertexes(lua_State *L)
{
size_t i = 0;
if (gamestate != GS_LEVEL)
return luaL_error(L, "This function can only be used in a level!");
INLEVEL
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'.");
lua_settop(L, 2);
@ -1486,8 +1475,7 @@ static int lib_iterateVertexes(lua_State *L)
static int lib_getVertex(lua_State *L)
{
int field;
if (gamestate != GS_LEVEL)
return luaL_error(L, "You cannot access this outside of a level!");
INLEVEL
lua_settop(L, 2);
lua_remove(L, 1); // dummy userdata table is unused.
if (lua_isnumber(L, 1))
@ -1523,8 +1511,7 @@ static int lib_numvertexes(lua_State *L)
static int lib_iterateSegs(lua_State *L)
{
size_t i = 0;
if (gamestate != GS_LEVEL)
return luaL_error(L, "This function can only be used in a level!");
INLEVEL
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'.");
lua_settop(L, 2);
@ -1542,8 +1529,7 @@ static int lib_iterateSegs(lua_State *L)
static int lib_getSeg(lua_State *L)
{
int field;
if (gamestate != GS_LEVEL)
return luaL_error(L, "You cannot access this outside of a level!");
INLEVEL
lua_settop(L, 2);
lua_remove(L, 1); // dummy userdata table is unused.
if (lua_isnumber(L, 1))
@ -1577,8 +1563,7 @@ static int lib_numsegs(lua_State *L)
static int lib_iterateNodes(lua_State *L)
{
size_t i = 0;
if (gamestate != GS_LEVEL)
return luaL_error(L, "This function can only be used in a level!");
INLEVEL
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'.");
lua_settop(L, 2);
@ -1596,8 +1581,7 @@ static int lib_iterateNodes(lua_State *L)
static int lib_getNode(lua_State *L)
{
int field;
if (gamestate != GS_LEVEL)
return luaL_error(L, "You cannot access this outside of a level!");
INLEVEL
lua_settop(L, 2);
lua_remove(L, 1); // dummy userdata table is unused.
if (lua_isnumber(L, 1))

View File

@ -804,7 +804,12 @@ static int mapthing_set(lua_State *L)
else if(fastcmp(field,"z"))
mt->z = (INT16)luaL_checkinteger(L, 3);
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"))
mt->mobj = *((mobj_t **)luaL_checkudata(L, 3, META_MOBJ));
else
@ -816,8 +821,7 @@ static int mapthing_set(lua_State *L)
static int lib_iterateMapthings(lua_State *L)
{
size_t i = 0;
if (gamestate != GS_LEVEL)
return luaL_error(L, "This function can only be used in a level!");
INLEVEL
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'.");
lua_settop(L, 2);
@ -835,8 +839,7 @@ static int lib_iterateMapthings(lua_State *L)
static int lib_getMapthing(lua_State *L)
{
int field;
if (gamestate != GS_LEVEL)
return luaL_error(L, "You cannot access this outside of a level!");
INLEVEL
lua_settop(L, 2);
lua_remove(L, 1); // dummy userdata table is unused.
if (lua_isnumber(L, 1))

View File

@ -25,8 +25,7 @@
static int lib_iteratePlayers(lua_State *L)
{
INT32 i = -1;
if (gamestate != GS_LEVEL)
return luaL_error(L, "This function can only be used in a level!");
INLEVEL
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'.");
@ -53,8 +52,7 @@ static int lib_getPlayer(lua_State *L)
{
const char *field;
// i -> players[i]
if (gamestate != GS_LEVEL)
return luaL_error(L, "You cannot access this outside of a level!");
INLEVEL
if (lua_type(L, 2) == LUA_TNUMBER)
{
lua_Integer i = luaL_checkinteger(L, 2);

View File

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

View File

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

View File

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

View File

@ -240,7 +240,7 @@ UINT8 M_UpdateUnlockablesAndExtraEmblems(void)
if (cechoLines)
{
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] = 0;

View File

@ -2830,8 +2830,8 @@ boolean M_Responder(event_t *ev)
void (*routine)(INT32 choice); // for some casting problem
if (dedicated || (demoplayback && titledemo)
|| gamestate == GS_INTRO || gamestate == GS_CUTSCENE || gamestate == GS_GAMEEND
|| gamestate == GS_CREDITS || gamestate == GS_EVALUATION)
|| gamestate == GS_INTRO || gamestate == GS_ENDING || gamestate == GS_CUTSCENE
|| gamestate == GS_CREDITS || gamestate == GS_EVALUATION || gamestate == GS_GAMEEND)
return false;
if (noFurtherInput)
@ -3531,6 +3531,7 @@ void M_InitCharacterTables(void)
strcpy(description[i].picname, "");
strcpy(description[i].skinname, "");
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)
allowed = true;
if (description[i].picname[0] == '\0')
strncpy(description[i].picname, skins[skinnum].charsel, 8);
if (!(description[i].picname[0]))
{
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.
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
if (o < 32)
{
patch = W_CachePatchName(description[prev].picname, PU_CACHE);
patch = description[prev].pic;
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);
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
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)
V_DrawCroppedPatch(8<<FRACBITS, (my + 168 - o)<<FRACBITS, FRACUNIT/2, 0, patch, 0, 0, SHORT(patch->width), 2*o);
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 (SHORT(patch->width) >= 256)
@ -8144,9 +8156,16 @@ void M_DrawTimeAttackMenu(void)
V_DrawString(currentMenu->x, cursory, V_YELLOWMAP, currentMenu->menuitems[itemOn].text);
// 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)
V_DrawTinyScaledPatch(224, 120, 0, PictureOfUrFace);
else

View File

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

View File

@ -3878,6 +3878,8 @@ bossjustdie:
}
default: //eggmobiles
{
UINT8 extrainfo = (mo->spawnpoint ? mo->spawnpoint->extrainfo : 0);
// Stop exploding and prepare to run.
P_SetMobjState(mo, mo->info->xdeathstate);
if (P_MobjWasRemoved(mo))
@ -3897,6 +3899,9 @@ bossjustdie:
if (mo2->type != MT_BOSSFLYPOINT)
continue;
if (mo2->spawnpoint && mo2->spawnpoint->extrainfo != extrainfo)
continue;
// If this one's further then the last one, don't go for it.
if (mo->target &&
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;
boolean avoidcenter;
UINT32 i;
UINT8 extrainfo = (actor->spawnpoint ? actor->spawnpoint->extrainfo : 0);
#ifdef HAVE_BLUA
if (LUA_CallAction("A_Boss5FindWaypoint", actor))
return;
@ -12312,16 +12318,34 @@ void A_Boss5FindWaypoint(mobj_t *actor)
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;
if (mapthings[i].mobj->type != MT_BOSSFLYPOINT)
mo2 = (mobj_t *)th;
if (mo2->type != MT_BOSSFLYPOINT)
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
}
else if (locvar1 == 1) // always go to ambush-marked waypoint
@ -12335,11 +12359,13 @@ void A_Boss5FindWaypoint(mobj_t *actor)
continue;
if (mapthings[i].mobj->type != MT_FANGWAYPOINT)
continue;
if (mapthings[i].options & MTF_AMBUSH)
{
P_SetTarget(&actor->tracer, mapthings[i].mobj);
break;
}
if (mapthings[i].extrainfo != extrainfo)
continue;
if (!(mapthings[i].options & MTF_AMBUSH))
continue;
P_SetTarget(&actor->tracer, mapthings[i].mobj);
break;
}
if (i == nummapthings)
@ -12363,6 +12389,8 @@ void A_Boss5FindWaypoint(mobj_t *actor)
continue;
if (actor->tracer == mapthings[i].mobj) // this was your tracer last time
continue;
if (mapthings[i].extrainfo != extrainfo)
continue;
if (mapthings[i].options & MTF_AMBUSH)
{
if (avoidcenter)
@ -12418,6 +12446,8 @@ void A_Boss5FindWaypoint(mobj_t *actor)
continue;
if (actor->tracer == mapthings[i].mobj) // this was your tracer last time
continue;
if (mapthings[i].extrainfo != extrainfo)
continue;
if (mapthings[i].options & MTF_AMBUSH)
{
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->ceilspeed = 42;
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)
{
size_t i;
size_t leftmostvertex = 0, rightmostvertex = 0;
size_t topmostvertex = 0, bottommostvertex = 0;
fixed_t leftx, rightx;
fixed_t topy, bottomy;
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;
size_t i, leftmostvertex, rightmostvertex, topmostvertex, bottommostvertex;
fixed_t leftx, rightx, topy, bottomy, topz, bottomz, widthfactor, heightfactor, a, b, c, spacing;
mobjtype_t type;
tic_t lifetime;
INT16 flags;
#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)
{

View File

@ -670,7 +670,10 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
P_DoMatchSuper(player);
}
else
{
emeralds |= special->info->speed;
stagefailed = false;
}
if (special->target && special->target->type == MT_EMERALDSPAWN)
{
@ -3652,7 +3655,7 @@ void P_PlayerRingBurst(player_t *player, INT32 num_rings)
{
INT32 i;
mobj_t *mo;
angle_t fa;
angle_t fa, va;
fixed_t ns;
fixed_t z;
boolean nightsreplace = ((maptol & TOL_NIGHTS) && !G_IsSpecialStage(gamemap));
@ -3674,6 +3677,11 @@ void P_PlayerRingBurst(player_t *player, INT32 num_rings)
// Spill weapons first
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++)
{
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);
// 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.
// 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_InSpaceSector(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_RestoreMusic(player_t *player);

View File

@ -342,7 +342,7 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object)
if (horizspeed)
{
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;
@ -1808,7 +1808,7 @@ static boolean PIT_CheckLine(line_t *ld)
{
tmceilingz = opentop;
ceilingline = ld;
tmceilingrover = NULL;
tmceilingrover = openceilingrover;
#ifdef ESLOPE
tmceilingslope = opentopslope;
#endif
@ -1817,7 +1817,7 @@ static boolean PIT_CheckLine(line_t *ld)
if (openbottom > tmfloorz)
{
tmfloorz = openbottom;
tmfloorrover = NULL;
tmfloorrover = openfloorrover;
#ifdef ESLOPE
tmfloorslope = openbottomslope;
#endif
@ -2089,6 +2089,7 @@ boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y)
#ifdef ESLOPE
tmfloorslope = NULL;
#endif
tmfloorrover = NULL;
}
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
tmceilingslope = NULL;
#endif
tmceilingrover = NULL;
}
}
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)
{
boolean floormoved;
fixed_t oldfloorz = thing->floorz;
fixed_t oldfloorz = thing->floorz, oldz = thing->z;
ffloor_t *oldfloorrover = thing->floorrover;
ffloor_t *oldceilingrover = thing->ceilingrover;
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;
}
if (thing->z != oldz)
{
if (thing->player)
P_PlayerHitFloor(thing->player, false);
}
// debug: be sure it falls to the floor
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)
{
msecnode_t *n;
size_t i;
nofit = false;
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.
// 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)
{
size_t i;
sector_t *sec;
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
// 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)
{
size_t i;
sector_t *sec;
for (i = 0; i < sector->numattached; i++)
{

View File

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

View File

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

View File

@ -1784,7 +1784,7 @@ static void P_PushableCheckBustables(mobj_t *mo)
continue;
}
EV_CrumbleChain(node->m_sector, rover);
EV_CrumbleChain(NULL, rover); // node->m_sector
// Run a linedef executor??
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)
mo->player->pflags &= ~PF_STARTDASH;
@ -3129,7 +3129,7 @@ nightsdone:
{
// DO THE MARIO!
if (rover->flags & FF_SHATTERBOTTOM) // Brick block!
EV_CrumbleChain(node->m_sector, rover);
EV_CrumbleChain(NULL, rover); // node->m_sector
else // Question block!
EV_MarioBlock(rover, node->m_sector, mo);
}
@ -4674,7 +4674,7 @@ static void P_Boss4PinchSpikeballs(mobj_t *mobj, angle_t angle, fixed_t dz)
}
dz /= 9;
while ((base = base->tracer)) // there are 10 per spoke, remember that
{
dx = (originx + P_ReturnThrustX(mobj, angle, (9*132)<<FRACBITS) - mobj->x)/9;
@ -5236,6 +5236,7 @@ static void P_Boss7Thinker(mobj_t *mobj)
INT32 i;
boolean foundgoop = false;
INT32 closestNum;
UINT8 extrainfo = (mobj->spawnpoint ? mobj->spawnpoint->extrainfo : 0);
// Looks for players in goop. If you find one, try to jump on him.
for (i = 0; i < MAXPLAYERS; i++)
@ -5261,17 +5262,23 @@ static void P_Boss7Thinker(mobj_t *mobj)
continue;
mo2 = (mobj_t *)th;
if (mo2->type == MT_BOSS3WAYPOINT && mo2->spawnpoint)
{
dist = P_AproxDistance(players[i].mo->x - mo2->x, players[i].mo->y - mo2->y);
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
if (closestNum == -1 || dist < closestdist)
{
closestNum = (mo2->spawnpoint->options & 7);
closestdist = dist;
foundgoop = true;
}
}
dist = P_AproxDistance(players[i].mo->x - mo2->x, players[i].mo->y - mo2->y);
if (!(closestNum == -1 || dist < closestdist))
continue;
closestNum = (mo2->spawnpoint->options & 7);
closestdist = dist;
foundgoop = true;
}
waypointNum = closestNum;
break;
@ -5280,17 +5287,14 @@ static void P_Boss7Thinker(mobj_t *mobj)
if (!foundgoop)
{
if (mobj->z > 1056*FRACUNIT)
waypointNum = 0;
else
// Don't jump to the center when health is low.
// Force the player to beat you with missiles.
if (mobj->z <= 1056*FRACUNIT || mobj->health <= mobj->info->damage)
waypointNum = 1 + P_RandomKey(4);
else
waypointNum = 0;
}
// Don't jump to the center when health is low.
// Force the player to beat you with missiles.
if (mobj->health <= mobj->info->damage && waypointNum == 0)
waypointNum = 1 + P_RandomKey(4);
if (mobj->tracer && mobj->tracer->type == MT_BOSS3WAYPOINT
&& mobj->tracer->spawnpoint && (mobj->tracer->spawnpoint->options & 7) == waypointNum)
{
@ -5299,15 +5303,12 @@ static void P_Boss7Thinker(mobj_t *mobj)
else
waypointNum--;
waypointNum %= 5;
if (waypointNum < 0)
waypointNum = 0;
if (mobj->health <= mobj->info->damage)
waypointNum = ((waypointNum + 3) % 4) + 1; // plus four to avoid modulo being negative, minus one to avoid waypoint #0
else
waypointNum = ((waypointNum + 5) % 5);
}
if (waypointNum == 0 && mobj->health <= mobj->info->damage)
waypointNum = 1 + (P_RandomFixed() & 1);
// scan the thinkers to find
// the waypoint to use
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
@ -5316,11 +5317,17 @@ static void P_Boss7Thinker(mobj_t *mobj)
continue;
mo2 = (mobj_t *)th;
if (mo2->type == MT_BOSS3WAYPOINT && mo2->spawnpoint && (mo2->spawnpoint->options & 7) == waypointNum)
{
hitspot = mo2;
break;
}
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;
break;
}
if (hitspot == NULL)
@ -7004,6 +7011,9 @@ void P_MobjThinker(mobj_t *mobj)
if (mobj->flags & MF_NOTHINK)
return;
if ((mobj->flags & MF_BOSS) && mobj->spawnpoint && (bossdisabled & (1<<mobj->spawnpoint->extrainfo)))
return;
// Remove dead target/tracer.
if (mobj->target && P_MobjWasRemoved(mobj->target))
P_SetTarget(&mobj->target, NULL);
@ -8072,7 +8082,8 @@ void P_MobjThinker(mobj_t *mobj)
mobj->tracer->z += mobj->height;
}
break;
case MT_WAVINGFLAG:
case MT_WAVINGFLAG1:
case MT_WAVINGFLAG2:
{
fixed_t base = (leveltime<<(FRACBITS+1));
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:
mobj->extravalue1 = FixedHypot(mobj->x, mobj->y)>>FRACBITS;
break;
case MT_WAVINGFLAG:
case MT_WAVINGFLAG1:
case MT_WAVINGFLAG2:
{
mobj_t *prev = mobj, *cur;
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
{
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);
cur->extravalue1 = i;
prev = cur;
@ -11100,6 +11110,12 @@ You should think about modifying the deathmatch starts to take full advantage of
else
skyboxviewpnts[mthing->extrainfo] = mobj;
break;
case MT_EGGSTATUE:
if (tutorialmode != (mthing->options & MTF_OBJECTSPECIAL))
{
mobj->color = SKINCOLOR_GOLD;
mobj->colorized = true;
}
case MT_EGGMOBILE3:
mobj->cusval = mthing->extrainfo;
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;
}
break;
case MT_CEZPOLE:
case MT_CEZPOLE1:
case MT_CEZPOLE2:
{ // Spawn the banner
angle_t mobjangle = FixedAngle(mthing->angle<<FRACBITS);
P_SpawnMobjFromMobj(mobj,
P_ReturnThrustX(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;
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)
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)
{
// Spawn already displayed
@ -12011,6 +12037,9 @@ ML_EFFECT5 : Don't stop thinking when too far away
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)
{
// flag for strong/weak random boxes
@ -12354,28 +12383,33 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing, boolean bonustime)
if (nightsreplace)
ringthing = MT_NIGHTSSTAR;
if (mthing->options & MTF_OBJECTFLIP)
{
z = (
#ifdef ESLOPE
sec->c_slope ? P_GetZAt(sec->c_slope, x, y) :
#endif
sec->ceilingheight) - mobjinfo[ringthing].height;
if (mthing->options >> ZSHIFT)
z -= ((mthing->options >> ZSHIFT) << FRACBITS);
}
else
{
z = (
#ifdef ESLOPE
sec->f_slope ? P_GetZAt(sec->f_slope, x, y) :
#endif
sec->floorheight);
if (mthing->options >> ZSHIFT)
z += ((mthing->options >> ZSHIFT) << FRACBITS);
}
for (r = 1; r <= 5; r++)
{
if (mthing->options & MTF_OBJECTFLIP)
{
z = (
#ifdef ESLOPE
sec->c_slope ? P_GetZAt(sec->c_slope, x, y) :
#endif
sec->ceilingheight) - mobjinfo[ringthing].height - dist*r;
if (mthing->options >> ZSHIFT)
z -= ((mthing->options >> ZSHIFT) << FRACBITS);
}
z -= dist;
else
{
z = (
#ifdef ESLOPE
sec->f_slope ? P_GetZAt(sec->f_slope, x, y) :
#endif
sec->floorheight) + dist*r;
if (mthing->options >> ZSHIFT)
z += ((mthing->options >> ZSHIFT) << FRACBITS);
}
z += dist;
mobj = P_SpawnMobj(x, y, z, ringthing);
@ -12409,31 +12443,36 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing, boolean bonustime)
closestangle = FixedAngle(mthing->angle*FRACUNIT);
fa = (closestangle >> ANGLETOFINESHIFT);
if (mthing->options & MTF_OBJECTFLIP)
{
z = (
#ifdef ESLOPE
sec->c_slope ? P_GetZAt(sec->c_slope, x, y) :
#endif
sec->ceilingheight) - mobjinfo[ringthing].height;
if (mthing->options >> ZSHIFT)
z -= ((mthing->options >> ZSHIFT) << FRACBITS);
}
else
{
z = (
#ifdef ESLOPE
sec->f_slope ? P_GetZAt(sec->f_slope, x, y) :
#endif
sec->floorheight);
if (mthing->options >> ZSHIFT)
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 = (
#ifdef ESLOPE
sec->c_slope ? P_GetZAt(sec->c_slope, x, y) :
#endif
sec->ceilingheight) - mobjinfo[ringthing].height - 64*FRACUNIT*r;
if (mthing->options >> ZSHIFT)
z -= ((mthing->options >> ZSHIFT) << FRACBITS);
}
z -= 64*FRACUNIT;
else
{
z = (
#ifdef ESLOPE
sec->f_slope ? P_GetZAt(sec->f_slope, x, y) :
#endif
sec->floorheight) + 64*FRACUNIT*r;
if (mthing->options >> ZSHIFT)
z += ((mthing->options >> ZSHIFT) << FRACBITS);
}
z += 64*FRACUNIT;
mobj = P_SpawnMobj(x, y, z, ringthing);

View File

@ -470,4 +470,5 @@ extern INT32 numhuntemeralds;
extern boolean runemeraldmanager;
extern UINT16 emeraldspawndelay;
extern INT32 numstarposts;
extern UINT16 bossdisabled;
#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->ceilingheight = target->z + amtz;
// 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));
// Apply action to mirroring polyobjects as well
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->ceilingheight += diffz;
// 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));
}
@ -2050,8 +2052,9 @@ void T_PolyObjWaypoint(polywaypoint_t *th)
po->lines[0]->backsector->floorheight += momz;
po->lines[0]->backsector->ceilingheight += momz;
// Sal: Remember to check your sectors!
P_CheckSector(po->lines[0]->frontsector, (boolean)(po->damage)); // frontsector is NEEDED for crushing
P_CheckSector(po->lines[0]->backsector, (boolean)(po->damage)); // backsector may not be necessary, but just in case
// 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));
// Apply action to mirroring polyobjects as well
start = 0;
@ -2065,7 +2068,8 @@ void T_PolyObjWaypoint(polywaypoint_t *th)
po->lines[0]->backsector->floorheight += momz;
po->lines[0]->backsector->ceilingheight += momz;
// 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));
}
}

View File

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

View File

@ -102,6 +102,7 @@ line_t *lines;
side_t *sides;
mapthing_t *mapthings;
INT32 numstarposts;
UINT16 bossdisabled;
boolean levelloading;
UINT8 levelfadecol;
@ -859,12 +860,7 @@ void P_ReloadRings(void)
mt->z = (INT16)(R_PointInSubsector(mt->x << FRACBITS, mt->y << FRACBITS)
->sector->floorheight>>FRACBITS);
P_SpawnHoopsAndRings(mt,
#ifdef MANIASPHERES
true);
#else
!G_IsSpecialStage(gamemap)); // prevent flashing spheres in special stages
#endif
P_SpawnHoopsAndRings(mt, true);
}
}
for (i = 0; i < numHoops; i++)
@ -878,11 +874,6 @@ void P_SwitchSpheresBonusMode(boolean bonustime)
mobj_t *mo;
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
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;
// special stage
stagefailed = false;
stagefailed = true; // assume failed unless proven otherwise - P_GiveEmerald or emerald touchspecial
// Reset temporary record data
memset(&ntemprecords, 0, sizeof(nightsdata_t));
@ -3126,7 +3117,7 @@ boolean P_SetupLevel(boolean skipprecip)
R_PrecacheLevel();
nextmapoverride = 0;
skipstats = false;
skipstats = 0;
if (!(netgame || multiplayer) && (!modifiedgame || savemoddata))
mapvisited[gamemap-1] |= MV_VISITED;
@ -3437,13 +3428,13 @@ boolean P_AddWadFile(const char *wadfilename)
ST_UnloadGraphics();
HU_LoadGraphics();
ST_LoadGraphics();
ST_ReloadSkinFaceGraphics();
//
// look for skins
//
R_AddSkins(wadnum); // faB: wadfile index in wadfiles[]
R_PatchSkins(wadnum); // toast: PATCH PATCH
ST_ReloadSkinFaceGraphics();
//
// search for maps

View File

@ -3554,6 +3554,29 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec)
}
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
P_LinedefExecute(line->tag, mo, NULL);
break;
@ -3918,6 +3941,18 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec)
}
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
case 480: // Polyobj_DoorSlide
case 481: // Polyobj_DoorSwing
@ -4601,7 +4636,10 @@ DoneSection2:
if (player->bot)
break;
if (!(maptol & TOL_NIGHTS) && G_IsSpecialStage(gamemap) && player->nightstime > 6)
{
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)
{
@ -4624,7 +4662,7 @@ DoneSection2:
nextmapoverride = (INT16)(lines[lineindex].frontsector->floorheight>>FRACBITS);
if (lines[lineindex].flags & ML_NOCLIMB)
skipstats = true;
skipstats = 1;
}
}
break;
@ -6401,6 +6439,9 @@ void P_SpawnSpecials(INT32 fromnetsave)
// but currently isn't.
(void)fromnetsave;
// yep, we do this here - "bossdisabled" is considered an apparatus of specials.
bossdisabled = 0;
// Init special SECTORs.
sector = sectors;
for (i = 0; i < numsectors; i++, sector++)
@ -7289,6 +7330,24 @@ void P_SpawnSpecials(INT32 fromnetsave)
case 431:
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
// 501 is used for a scroller
// 502 is used for a scroller

View File

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

View File

@ -302,15 +302,39 @@ void P_GiveEmerald(boolean spawnObj)
S_StartSound(NULL, sfx_cgot); // Got the emerald!
emeralds |= (1 << em);
stagefailed = false;
if (spawnObj && playeringame[consoleplayer])
if (spawnObj)
{
// The Chaos Emerald begins to orbit us!
// Only give it to ONE person!
mobj_t *emmo = P_SpawnMobjFromMobj(players[consoleplayer].mo, 0, 0, players[consoleplayer].mo->height, MT_GOTEMERALD);
P_SetTarget(&emmo->target, players[consoleplayer].mo);
P_SetMobjState(emmo, mobjinfo[MT_GOTEMERALD].meleestate + em);
P_SetTarget(&players[consoleplayer].mo->tracer, emmo);
// Only visibly give it to ONE person!
UINT8 i, pnum = ((playeringame[consoleplayer]) && (!players[consoleplayer].spectator) && (players[consoleplayer].mo)) ? consoleplayer : 255;
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_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->followitem = skins[player->skin].followitem;
player->mo->color = player->skincolor;
G_GhostAddColor(GHC_NORMAL);
G_GhostAddColor(GHC_RETURNSKIN);
// Restore aiming angle
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)
players[i].nightstime = 1; // force everyone else to fall too.
player->exiting = 3*TICRATE;
stagefailed = true; // NIGHT OVER
// 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.
@ -716,6 +739,7 @@ void P_NightserizePlayer(player_t *player, INT32 nighttime)
if (!(cv_debug || devparm) && !(netgame || multiplayer || demoplayback))
player->mo->color = skins[DEFAULTNIGHTSSKIN].prefcolor;
player->followitem = skins[DEFAULTNIGHTSSKIN].followitem;
G_GhostAddColor(GHC_NIGHTSSKIN);
}
player->nightstime = player->startedtime = player->lapstartedtime = nighttime*TICRATE;
@ -2007,7 +2031,7 @@ boolean P_InSpaceSector(mobj_t *mo) // Returns true if you are in space
//
// Handles player hitting floor surface.
// Returns whether to clip momz.
boolean P_PlayerHitFloor(player_t *player)
boolean P_PlayerHitFloor(player_t *player, boolean dorollstuff)
{
boolean clipmomz;
@ -2015,22 +2039,31 @@ boolean P_PlayerHitFloor(player_t *player)
if ((clipmomz = !(P_CheckDeathPitCollide(player->mo))) && player->mo->health && !player->spectator)
{
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 (dorollstuff)
{
player->pflags |= PF_SPINNING;
P_SetPlayerMobjState(player->mo, S_PLAY_ROLL);
S_StartSound(player->mo, sfx_spin);
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)))
{
player->pflags |= PF_SPINNING;
P_SetPlayerMobjState(player->mo, S_PLAY_ROLL);
S_StartSound(player->mo, sfx_spin);
}
else
player->pflags &= ~PF_SPINNING;
}
else
{
player->pflags &= ~PF_SPINNING;
if (player->pflags & PF_GLIDING) // ground gliding
if (player->pflags & PF_GLIDING) // ground gliding
{
if (dorollstuff)
{
player->skidtime = TICRATE;
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;
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 mu2 = FixedHypot(player->mo->momx, player->mo->momy);
fixed_t ev;
mobj_t *missile;
mobj_t *missile = NULL;
if (mu2 < mu)
mu2 = mu;
ev = (50*FRACUNIT - (mu/25))/50;
@ -2062,45 +2095,48 @@ boolean P_PlayerHitFloor(player_t *player)
P_ReturnThrustY(missile, throwang, mu)); // side to side component
P_Thrust(missile, player->drawangle, mu2); // forward component
P_SetObjectMomZ(missile, (4 + ((i&1)<<1))*FRACUNIT, true);
missile->momz += player->mo->pmomz;
missile->fuse = TICRATE/2;
missile->extravalue2 = ev;
i++;
throwang += ANG30;
}
if (mobjinfo[type].seesound)
if (mobjinfo[type].seesound && missile)
S_StartSound(missile, missile->info->seesound);
}
}
else if (player->pflags & PF_JUMPED || !(player->pflags & PF_SPINNING)
}
else if (player->charability2 == CA2_GUNSLINGER && player->panim == PA_ABILITY2)
;
else if (player->pflags & PF_JUMPED || !(player->pflags & PF_SPINNING)
|| player->powers[pw_tailsfly] || player->mo->state-states == S_PLAY_FLY_TIRED)
{
if (player->cmomx || player->cmomy)
{
if (player->cmomx || player->cmomy)
{
if (player->charflags & SF_DASHMODE && player->dashmode >= 3*TICRATE && player->panim != PA_DASH)
P_SetPlayerMobjState(player->mo, S_PLAY_DASH);
else if (player->speed >= FixedMul(player->runspeed, player->mo->scale)
&& (player->panim != PA_RUN || player->mo->state-states == S_PLAY_FLOAT_RUN))
P_SetPlayerMobjState(player->mo, S_PLAY_RUN);
else if ((player->rmomx || player->rmomy)
&& (player->panim != PA_WALK || player->mo->state-states == S_PLAY_FLOAT))
P_SetPlayerMobjState(player->mo, S_PLAY_WALK);
else if (!player->rmomx && !player->rmomy && player->panim != PA_IDLE)
P_SetPlayerMobjState(player->mo, S_PLAY_STND);
}
else
{
if (player->charflags & SF_DASHMODE && player->dashmode >= 3*TICRATE && player->panim != PA_DASH)
P_SetPlayerMobjState(player->mo, S_PLAY_DASH);
else if (player->speed >= FixedMul(player->runspeed, player->mo->scale)
&& (player->panim != PA_RUN || player->mo->state-states == S_PLAY_FLOAT_RUN))
P_SetPlayerMobjState(player->mo, S_PLAY_RUN);
else if ((player->mo->momx || player->mo->momy)
&& (player->panim != PA_WALK || player->mo->state-states == S_PLAY_FLOAT))
P_SetPlayerMobjState(player->mo, S_PLAY_WALK);
else if (!player->mo->momx && !player->mo->momy && player->panim != PA_IDLE)
P_SetPlayerMobjState(player->mo, S_PLAY_STND);
}
if (player->charflags & SF_DASHMODE && player->dashmode >= 3*TICRATE && player->panim != PA_DASH)
P_SetPlayerMobjState(player->mo, S_PLAY_DASH);
else if (player->speed >= FixedMul(player->runspeed, player->mo->scale)
&& (player->panim != PA_RUN || player->mo->state-states == S_PLAY_FLOAT_RUN))
P_SetPlayerMobjState(player->mo, S_PLAY_RUN);
else if ((player->rmomx || player->rmomy)
&& (player->panim != PA_WALK || player->mo->state-states == S_PLAY_FLOAT))
P_SetPlayerMobjState(player->mo, S_PLAY_WALK);
else if (!player->rmomx && !player->rmomy && player->panim != PA_IDLE)
P_SetPlayerMobjState(player->mo, S_PLAY_STND);
}
else
{
if (player->charflags & SF_DASHMODE && player->dashmode >= 3*TICRATE && player->panim != PA_DASH)
P_SetPlayerMobjState(player->mo, S_PLAY_DASH);
else if (player->speed >= FixedMul(player->runspeed, player->mo->scale)
&& (player->panim != PA_RUN || player->mo->state-states == S_PLAY_FLOAT_RUN))
P_SetPlayerMobjState(player->mo, S_PLAY_RUN);
else if ((player->mo->momx || player->mo->momy)
&& (player->panim != PA_WALK || player->mo->state-states == S_PLAY_FLOAT))
P_SetPlayerMobjState(player->mo, S_PLAY_WALK);
else if (!player->mo->momx && !player->mo->momy && player->panim != PA_IDLE)
P_SetPlayerMobjState(player->mo, S_PLAY_STND);
}
}
@ -2320,7 +2356,7 @@ static void P_CheckBustableBlocks(player_t *player)
//if (metalrecording)
// G_RecordBustup(rover);
EV_CrumbleChain(node->m_sector, rover);
EV_CrumbleChain(NULL, rover); // node->m_sector
// Run a linedef executor??
if (rover->master->flags & ML_EFFECT5)
@ -2537,7 +2573,7 @@ static void P_CheckQuicksand(player_t *player)
player->mo->z = ceilingheight - player->mo->height;
if (player->mo->momz <= 0)
P_PlayerHitFloor(player);
P_PlayerHitFloor(player, false);
}
else
{
@ -2549,7 +2585,7 @@ static void P_CheckQuicksand(player_t *player)
player->mo->z = floorheight;
if (player->mo->momz >= 0)
P_PlayerHitFloor(player);
P_PlayerHitFloor(player, false);
}
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);
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)
player->mo->momz >>= 1;
#if 0
@ -11641,7 +11681,6 @@ void P_PlayerAfterThink(player_t *player)
player->followmobj->threshold = player->mo->z;
player->followmobj->movecount = player->panim;
player->followmobj->angle = horizangle;
player->followmobj->scale = player->mo->scale;
P_SetScale(player->followmobj, player->mo->scale);
player->followmobj->destscale = player->mo->destscale;
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
R_InitSkins();
for (i = 0; i < numwadfiles; i++)
{
R_AddSkins((UINT16)i);
R_PatchSkins((UINT16)i);
}
ST_ReloadSkinFaceGraphics();
//
// 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)
{
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;
heads = calloc(nummasks, sizeof(drawnode_t));
for (i = 0; i < nummasks; 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_ClearDrawNodes(&heads[nummasks - 1]);
}
free(heads);
}
// ==========================================================================
@ -2503,6 +2511,9 @@ UINT8 P_GetSkinSprite2(skin_t *skin, UINT8 spr2, player_t *player)
if (!skin)
return 0;
if ((spr2 & ~FF_SPR2SUPER) >= free_spr2)
return 0;
while (!(skin->sprites[spr2].numframes)
&& spr2 != SPR2_STND
&& ++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;
break;
case SPR2_TIRE:
spr2 = (player && player->charability == CA_SWIM) ? SPR2_SWIM : SPR2_FLY;
break;
spr2 = ((player
? player->charability
: skin->ability)
== CA_SWIM) ? SPR2_SWIM : SPR2_FLY;
// Use the handy list, that's what it's there for!
default:
@ -2537,6 +2550,9 @@ UINT8 P_GetSkinSprite2(skin_t *skin, UINT8 spr2, player_t *player)
spr2 |= super;
}
if (i >= 32) // probably an infinite loop...
return 0;
return spr2;
}
@ -2556,9 +2572,6 @@ static void Sk_SetDefaultValue(skin_t *skin)
strcpy(skin->realname, "Someone");
strcpy(skin->hudname, "???");
strncpy(skin->charsel, "CHRSONIC", 9);
strncpy(skin->face, "MISSING", 8);
strncpy(skin->superface, "MISSING", 8);
skin->starttranscolor = 96;
skin->prefcolor = SKINCOLOR_GREEN;
@ -2988,7 +3001,7 @@ void R_AddSkins(UINT16 wadnum)
char *value;
size_t size;
skin_t *skin;
boolean hudname, realname, superface;
boolean hudname, realname;
//
// search for all skin markers in pwad
@ -3018,7 +3031,7 @@ void R_AddSkins(UINT16 wadnum)
skin = &skins[numskins];
Sk_SetDefaultValue(skin);
skin->wadnum = wadnum;
hudname = realname = superface = false;
hudname = realname = false;
// parse
stoken = strtok (buf2, "\r\n= ");
while (stoken)
@ -3094,24 +3107,6 @@ void R_AddSkins(UINT16 wadnum)
if (!realname)
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"))
{
skin->availability = atoi(value);
@ -3130,6 +3125,7 @@ next_token:
// Add sprites
R_LoadSkinSprites(wadnum, &lump, &lastlump, skin);
//ST_LoadFaceGraphics(numskins); -- nah let's do this elsewhere
R_FlushTranslationColormapCache();
@ -3140,9 +3136,6 @@ next_token:
skin_cons_t[numskins].strvalue = skin->name;
#endif
// add face graphics
ST_LoadFaceGraphics(skin->face, skin->superface, numskins);
#ifdef HWRENDER
if (rendermode == render_opengl)
HWR_AddPlayerMD2(numskins);
@ -3265,6 +3258,9 @@ next_token:
// Patch sprites
R_LoadSkinSprites(wadnum, &lump, &lastlump, skin);
//ST_LoadFaceGraphics(skinnum); -- nah let's do this elsewhere
R_FlushTranslationColormapCache();
if (!skin->availability) // Safe to print...
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 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 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)
{
INT32 sep, pitch, priority, cnum;
const sfxenum_t actual_id = sfx_id;
sfxinfo_t *sfx;
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
// 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
// mix/output buffer.
@ -715,7 +716,7 @@ dontplay:
#endif
// 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
// mix/output buffer.
@ -1675,7 +1676,17 @@ void S_StopMusic(void)
if (cv_closedcaptioning.value)
{
if (closedcaptions[0].s-S_sfx == sfx_None)
closedcaptions[0].t = CAPTIONFADETICS;
{
if (gamestate != wipegamestate)
{
closedcaptions[0].c = NULL;
closedcaptions[0].s = NULL;
closedcaptions[0].t = 0;
closedcaptions[0].b = 0;
}
else
closedcaptions[0].t = CAPTIONFADETICS;
}
}
}
@ -1982,8 +1993,10 @@ void GameMIDIMusic_OnChange(void)
}
}
#ifdef HAVE_OPENMPT
void ModFilter_OnChange(void)
{
if (openmpt_mhandle)
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 (splitscreen)
if (promptactive)
basey -= 28;
else if (splitscreen)
basey -= 8;
else if ((modeattacking == ATTACKING_NIGHTS)
|| (!(maptol & TOL_NIGHTS)

View File

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

View File

@ -453,6 +453,9 @@
<ClInclude Include="..\hardware\hw_clip.h">
<Filter>Hw_Hardware</Filter>
</ClInclude>
<ClInclude Include="..\r_portal.h">
<Filter>R_Rend</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<CustomBuild Include="..\tmap.nas">
@ -894,6 +897,10 @@
<ClCompile Include="..\hardware\hw_clip.c">
<Filter>Hw_Hardware</Filter>
</ClCompile>
<ClCompile Include="..\apng.c" />
<ClCompile Include="..\r_portal.c">
<Filter>R_Rend</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<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)
{
loop_point = song_length = 0.0f;
song_length = loop_point = 0.0f;
music_bytes = fading_source = fading_target =\
fading_timer = fading_duration = 0;

View File

@ -110,6 +110,7 @@ static patch_t *orngstat;
static patch_t *redstat;
static patch_t *yelstat;
static patch_t *nbracket;
static patch_t *nring;
static patch_t *nhud[12];
static patch_t *nsshud;
static patch_t *nbon[12];
@ -226,7 +227,7 @@ void ST_doPaletteStuff(void)
void ST_UnloadGraphics(void)
{
Z_FreeTags(PU_HUDGFX, PU_HUDGFX);
Z_FreeTag(PU_HUDGFX);
}
void ST_LoadGraphics(void)
@ -311,6 +312,7 @@ void ST_LoadGraphics(void)
redstat = W_CachePatchName("REDSTAT", PU_HUDGFX);
yelstat = W_CachePatchName("YELSTAT", PU_HUDGFX);
nbracket = W_CachePatchName("NBRACKET", PU_HUDGFX);
nring = W_CachePatchName("NRNG1", PU_HUDGFX);
for (i = 0; i < 12; ++i)
{
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
void ST_LoadFaceGraphics(char *facestr, char *superstr, INT32 skinnum)
void ST_LoadFaceGraphics(INT32 skinnum)
{
faceprefix[skinnum] = W_CachePatchName(facestr, PU_HUDGFX);
superprefix[skinnum] = W_CachePatchName(superstr, PU_HUDGFX);
if (skins[skinnum].sprites[SPR2_XTRA].numframes)
{
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;
}
@ -353,7 +369,7 @@ void ST_ReloadSkinFaceGraphics(void)
INT32 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)
@ -1545,7 +1561,7 @@ static void ST_drawNiGHTSLink(void)
static void ST_drawNiGHTSHUD(void)
{
INT32 origamount;
INT32 total_spherecount;
INT32 total_spherecount, total_ringcount;
const boolean oldspecialstage = (G_IsSpecialStage(gamemap) && !(maptol & TOL_NIGHTS));
// Drill meter
@ -1617,33 +1633,28 @@ static void ST_drawNiGHTSHUD(void)
#endif
ST_DrawTopLeftOverlayPatch(16, 8, nbracket);
if (G_IsSpecialStage(gamemap))
#ifdef MANIASPHERES
ST_DrawTopLeftOverlayPatch(24, 16, (
(stplyr->bonustime && (leveltime & 4)) ? nssbon : nsshud));
#else
ST_DrawTopLeftOverlayPatch(24, 16, (nsshud));
#endif
(stplyr->bonustime && (leveltime & 4) && (states[S_BLUESPHEREBONUS].frame & FF_ANIMATE)) ? nssbon : nsshud));
else
ST_DrawTopLeftOverlayPatch(24, 16, *(((stplyr->bonustime) ? nbon : nhud)+((leveltime/2)%12)));
if (G_IsSpecialStage(gamemap))
{
INT32 i;
total_spherecount = 0;
total_spherecount = total_ringcount = 0;
for (i = 0; i < MAXPLAYERS; i++)
if (playeringame[i] /*&& players[i].powers[pw_carry] == CR_NIGHTSMODE*/ && players[i].spheres)
total_spherecount += players[i].spheres;
{
if (!playeringame[i])
continue;
total_spherecount += players[i].spheres;
total_ringcount += players[i].rings;
}
}
else
total_spherecount = stplyr->spheres;
/*if (oldspecialstage)
{
if (total_spherecount < ssspheres)
total_spherecount = ssspheres - total_spherecount;
else
total_spherecount = 0;
}*/
total_spherecount = stplyr->spheres;
total_ringcount = stplyr->spheres;
}
if (stplyr->capsule)
{
@ -1731,6 +1742,27 @@ static void ST_drawNiGHTSHUD(void)
else
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)
V_DrawTallNum((total_spherecount >= 1000) ? 76 : 72, 8 + 11, V_PERPLAYER|V_SNAPTOTOP|V_SNAPTOLEFT|V_HUDTRANS, total_spherecount);
else

View File

@ -42,7 +42,7 @@ void ST_UnloadGraphics(void);
void ST_LoadGraphics(void);
// 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_doPaletteStuff(void);

View File

@ -309,12 +309,14 @@ static boolean InitCube(void)
return true;
}
#ifdef BACKWARDSCOMPATCORRECTION
/*
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
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.
toast 20/04/17
... welp yes i am (27/07/19, see the ifdef around it)
*/
const UINT8 correctiontable[256] =
{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,
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};
#endif
// 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)
@ -351,12 +354,18 @@ static void LoadPalette(const char *lumpname)
pal = W_CacheLumpNum(lumpnum, PU_CACHE);
for (i = 0; i < palsize; i++)
{
#ifdef BACKWARDSCOMPATCORRECTION
pMasterPalette[i].s.red = pLocalPalette[i].s.red = correctiontable[*pal++];
pMasterPalette[i].s.green = pLocalPalette[i].s.green = 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;
// lerp of colour cubing!
// lerp of colour cubing! if you want, make it smoother yourself
if (cube)
{
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
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)
{
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 (!column->topdelta)
{
source = (const UINT8 *)(column) + 3;
V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, source[0]);
}
}
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 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)
{
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]));
}
// no the patch is cropped do not do this ever
if (vid.width != BASEVIDWIDTH * dupx)
{
@ -1349,13 +1356,16 @@ static UINT32 V_GetHWConsBackColor(void)
// THANK YOU MPC!!!
// and thanks toaster for cleaning it up.
void V_DrawFillConsoleMap(INT32 x, INT32 y, INT32 w, INT32 h, INT32 c)
{
UINT8 *dest;
INT32 u, v;
const UINT8 *deststop;
INT32 u;
UINT8 *fadetable;
UINT32 alphalevel = 0;
UINT8 perplayershuffle = 0;
if (rendermode == render_none)
return;
@ -1369,16 +1379,91 @@ void V_DrawFillConsoleMap(INT32 x, INT32 y, INT32 w, INT32 h, INT32 c)
}
#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))
{
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;
y *= dupy;
w *= dupx;
@ -1393,6 +1478,10 @@ void V_DrawFillConsoleMap(INT32 x, INT32 y, INT32 w, INT32 h, INT32 c)
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)
{
@ -1401,6 +1490,10 @@ void V_DrawFillConsoleMap(INT32 x, INT32 y, INT32 w, INT32 h, INT32 c)
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;
}
}
@ -1423,34 +1516,206 @@ void V_DrawFillConsoleMap(INT32 x, INT32 y, INT32 w, INT32 h, INT32 c)
h = vid.height-y;
dest = screens[0] + y*vid.width + x;
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
}
deststop = screens[0] + vid.rowbytes * vid.height;
c &= 255;
// Jimita (12-04-2018)
w = min(w, vid.width);
h = min(h, vid.height);
fadetable = ((UINT8 *)transtables + ((alphalevel-1)<<FF_TRANSSHIFT) + (c*256));
for (v = 0; v < h; v++, dest += vid.width)
for (u = 0; u < w; u++)
if (alphalevel)
{
fadetable = ((UINT8 *)transtables + ((alphalevel-1)<<FF_TRANSSHIFT) + (c*256));
for (;(--h >= 0) && dest < deststop; dest += vid.width)
{
if (!alphalevel)
dest[u] = consolebgmap[dest[u]];
else
u = 0;
while (u < w)
{
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
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_DrawPromptBack(INT32 boxheight, INT32 color);

View File

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

View File

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

View File

@ -86,8 +86,8 @@ typedef union
INT32 passedx3;
INT32 passedx4;
y_bonus_t bonus;
patch_t *bonuspatch;
y_bonus_t bonuses[2];
patch_t *bonuspatches[2];
patch_t *pscore; // SCORE
UINT32 score; // fake score
@ -326,34 +326,36 @@ void Y_IntermissionDrawer(void)
// draw the header
if (intertic <= 2*TICRATE)
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;
if (animatetic && (tic_t)intertic >= animatetic)
{
const INT32 scradjust = (vid.width/vid.dupx)>>3; // 40 for BASEVIDWIDTH
INT32 animatetimer = (intertic - animatetic);
if (animatetimer <= 14)
if (animatetimer <= 16)
{
xoffset1 = -(animatetimer * scradjust);
xoffset2 = -((animatetimer-2) * scradjust);
xoffset3 = -((animatetimer-4) * scradjust);
xoffset4 = -((animatetimer-6) * scradjust);
xoffset5 = -((animatetimer-8) * scradjust);
xoffset1 = -(animatetimer * scradjust);
xoffset2 = -((animatetimer- 2) * scradjust);
xoffset3 = -((animatetimer- 4) * scradjust);
xoffset4 = -((animatetimer- 6) * scradjust);
xoffset5 = -((animatetimer- 8) * scradjust);
xoffset6 = -((animatetimer-10) * scradjust);
if (xoffset2 > 0) xoffset2 = 0;
if (xoffset3 > 0) xoffset3 = 0;
if (xoffset4 > 0) xoffset4 = 0;
if (xoffset5 > 0) xoffset5 = 0;
if (xoffset6 > 0) xoffset6 = 0;
}
else if (animatetimer < 32)
else if (animatetimer < 34)
{
drawsection = 1;
xoffset1 = (22-animatetimer) * scradjust;
xoffset2 = (24-animatetimer) * scradjust;
xoffset3 = (26-animatetimer) * scradjust;
xoffset4 = (28-animatetimer) * scradjust;
xoffset5 = (30-animatetimer) * scradjust;
xoffset6 = (32-animatetimer) * scradjust;
xoffset1 = (24-animatetimer) * scradjust;
xoffset2 = (26-animatetimer) * scradjust;
xoffset3 = (28-animatetimer) * scradjust;
xoffset4 = (30-animatetimer) * scradjust;
xoffset5 = (32-animatetimer) * scradjust;
xoffset6 = (34-animatetimer) * scradjust;
if (xoffset1 < 0) xoffset1 = 0;
if (xoffset2 < 0) xoffset2 = 0;
if (xoffset3 < 0) xoffset3 = 0;
@ -370,9 +372,9 @@ void Y_IntermissionDrawer(void)
if (drawsection == 1)
{
const char *ringtext = "\x86" "50 RINGS, NO SHIELD";
const char *tut1text = "\x86" "PRESS " "\x82" "SPIN";
const char *tut2text = "\x86" "MID-" "\x82" "JUMP";
const char *ringtext = "\x82" "50 RINGS, NO SHIELD";
const char *tut1text = "\x82" "PRESS " "\x80" "SPIN";
const char *tut2text = "\x82" "MID-" "\x80" "JUMP";
ttheight = 16;
V_DrawLevelTitle(data.spec.passedx1 + xoffset1, ttheight, 0, data.spec.passed1);
ttheight += V_LevelNameHeight(data.spec.passed3) + 2;
@ -389,6 +391,7 @@ void Y_IntermissionDrawer(void)
}
else
{
INT32 yoffset = 0;
if (data.spec.passed1[0] != '\0')
{
ttheight = 24;
@ -402,22 +405,31 @@ void Y_IntermissionDrawer(void)
V_DrawLevelTitle(data.spec.passedx2 + xoffset1, ttheight, 0, data.spec.passed2);
}
V_DrawScaledPatch(152 + xoffset3, 108, 0, data.spec.bonuspatch);
V_DrawTallNum(BASEVIDWIDTH + xoffset3 - 68, 109, 0, data.spec.bonus.points);
V_DrawScaledPatch(152 + xoffset4, 124, 0, data.spec.pscore);
V_DrawTallNum(BASEVIDWIDTH + xoffset4 - 68, 125, 0, data.spec.score);
V_DrawScaledPatch(152 + xoffset3, 108, 0, data.spec.bonuspatches[0]);
V_DrawTallNum(BASEVIDWIDTH + xoffset3 - 68, 109, 0, data.spec.bonuses[0].points);
if (data.spec.bonuses[1].display)
{
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!
if (!multiplayer /* && (data.spec.continues & 0x80) */) // Always draw outside of netplay
{
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)
{
if ((data.spec.continues & 0x80) && i == continues-1 && (endtic < 0 || intertic%20 < 10))
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;
UINT32 oldscore = data.spec.score;
boolean skip = false, super = false;
boolean skip = false, super = false, anybonuses = false;
if (!intertic) // first time only
{
@ -946,16 +958,26 @@ void Y_Ticker(void)
return;
}
// ring bonus counts down by 222 each tic
data.spec.bonus.points -= 222;
data.spec.score += 222;
if (data.spec.bonus.points < 0 || skip == true) // went too far
// bonuses count down by 222 each tic
for (i = 0; i < 2; ++i)
{
data.spec.score += data.spec.bonus.points;
data.spec.bonus.points = 0;
if (!data.spec.bonuses[i].points)
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;
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
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.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));
strncpy(bstruct->patch, "YB_PERFE", sizeof(bstruct->patch));
if (data.coop.gotperfbonus == -1)
if (intertype != int_coop || data.coop.gotperfbonus == -1)
{
INT32 sharedringtotal = 0;
for (i = 0; i < MAXPLAYERS; i++)
@ -1840,15 +1864,33 @@ static void Y_SetPerfectBonus(player_t *player, y_bonus_t *bstruct)
sharedringtotal += players[i].rings;
}
if (!sharedringtotal || nummaprings == -1 || sharedringtotal < nummaprings)
data.coop.gotperfbonus = 0;
bstruct->display = false;
else
data.coop.gotperfbonus = 1;
{
bstruct->display = true;
bstruct->points = 50000;
}
}
if (!data.coop.gotperfbonus)
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;
bstruct->points = 50000;
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.
@ -1953,23 +1995,33 @@ static void Y_AwardCoopBonuses(void)
static void Y_AwardSpecialStageBonus(void)
{
INT32 i, oldscore, ptlives;
y_bonus_t localbonus;
y_bonus_t localbonuses[2];
data.spec.score = players[consoleplayer].score;
memset(&data.spec.bonus, 0, sizeof(data.spec.bonus));
data.spec.bonuspatch = NULL;
memset(data.spec.bonuses, 0, sizeof(data.spec.bonuses));
memset(data.spec.bonuspatches, 0, sizeof(data.coop.bonuspatches));
for (i = 0; i < MAXPLAYERS; i++)
{
oldscore = players[i].score;
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_SetNightsBonus(&players[i], &localbonus);
{
Y_SetNullBonus(&players[i], &localbonuses[0]);
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
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)
players[i].score = MAXSCORE;
@ -1982,7 +2034,7 @@ static void Y_AwardSpecialStageBonus(void)
if (i == consoleplayer)
{
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
data.spec.continues = min(players[i].continues, 8);
@ -2057,7 +2109,8 @@ static void Y_UnloadData(void)
// unload the special stage patches
//UNLOAD(data.spec.cemerald);
//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.pcontinues);
break;