Skip to content
Snippets Groups Projects
f_finale.c 34.9 KiB
Newer Older
Alam Ed Arias's avatar
Alam Ed Arias committed
// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
// Copyright (C) 1993-1996 by id Software, Inc.
// Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2018 by Sonic Team Junior.
Alam Ed Arias's avatar
Alam Ed Arias committed
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
// See the 'LICENSE' file for more details.
//-----------------------------------------------------------------------------
/// \file  f_finale.c
/// \brief Title screen, intro, game evaluation, and credits.

#include "doomdef.h"
#include "doomstat.h"
#include "d_main.h"
#include "f_finale.h"
#include "g_game.h"
#include "hu_stuff.h"
#include "r_local.h"
#include "s_sound.h"
Eidolon's avatar
Eidolon committed
#include "i_time.h"
Alam Ed Arias's avatar
Alam Ed Arias committed
#include "i_video.h"
#include "v_video.h"
#include "w_wad.h"
#include "z_zone.h"
#include "i_system.h"
#include "i_threads.h"
Alam Ed Arias's avatar
Alam Ed Arias committed
#include "m_menu.h"
#include "dehacked.h"
#include "g_input.h"
#include "console.h"
#include "m_random.h"
#include "y_inter.h"
#include "m_cond.h"

// Stage of animation:
// 0 = text, 1 = art screen
static INT32 finalecount;
Alam Ed Arias's avatar
Alam Ed Arias committed

static INT32 timetonext; // Delay between screen changes
static INT32 continuetime; // Short delay when continuing

static tic_t animtimer; // Used for some animation timings
Sal's avatar
Sal committed
static tic_t credbgtimer; // Credits background
Alam Ed Arias's avatar
Alam Ed Arias committed
static INT32 roidtics; // Asteroid spinning

static tic_t stoptimer;

static boolean keypressed = false;

// (no longer) De-Demo'd Title Screen
static UINT8  laststaff = 0;
Alam Ed Arias's avatar
Alam Ed Arias committed
static UINT32 demoDelayLeft;
static UINT32 demoIdleLeft;

static patch_t *ttbanner; // SONIC ROBO BLAST 2
static patch_t *ttkart; // *vroom* KART
static patch_t *ttcheckers; // *vroom* KART
static patch_t *ttkflash; // flash screen
Alam Ed Arias's avatar
Alam Ed Arias committed

static patch_t *driver[2]; // Driving character on the waiting screen
static UINT8 *waitcolormap; // colormap for the spinning character

Alam Ed Arias's avatar
Alam Ed Arias committed
static void F_SkyScroll(INT32 scrollspeed);

//
// CUTSCENE TEXT WRITING
//
static const char *cutscene_basetext = NULL;
static char cutscene_disptext[1024];
static INT32 cutscene_baseptr = 0;
static INT32 cutscene_writeptr = 0;
static INT32 cutscene_textcount = 0;
static INT32 cutscene_textspeed = 0;
static UINT8 cutscene_boostspeed = 0;
static tic_t cutscene_lasttextwrite = 0;
//
// This alters the text string cutscene_disptext.
// Use the typical string drawing functions to display it.
// Returns 0 if \0 is reached (end of input)
//
static UINT8 F_WriteText(void)
{
	INT32 numtowrite = 1;
	const char *c;
	tic_t ltw = I_GetTime();

	if (cutscene_lasttextwrite == ltw)
		return 1; // singletics prevention
	cutscene_lasttextwrite = ltw;

	if (cutscene_boostspeed)
	{
		// for custom cutscene speedup mode
		numtowrite = 8;
	}
	else
	{
		// Don't draw any characters if the count was 1 or more when we started
		if (--cutscene_textcount >= 0)
			return 1;

		if (cutscene_textspeed < 7)
			numtowrite = 8 - cutscene_textspeed;
	}

	for (;numtowrite > 0;++cutscene_baseptr)
	{
		c = &cutscene_basetext[cutscene_baseptr];
		if (!c || !*c || *c=='#')
			return 0;

		// \xA0 - \xAF = change text speed
		if ((UINT8)*c >= 0xA0 && (UINT8)*c <= 0xAF)
		{
			cutscene_textspeed = (INT32)((UINT8)*c - 0xA0);
			continue;
		}
		// \xB0 - \xD2 = delay character for up to one second (35 tics)
		else if ((UINT8)*c >= 0xB0 && (UINT8)*c <= (0xB0+TICRATE-1))
		{
			cutscene_textcount = (INT32)((UINT8)*c - 0xAF);
			numtowrite = 0;
			continue;
		}

		cutscene_disptext[cutscene_writeptr++] = *c;

		// Ignore other control codes (color)
		if ((UINT8)*c < 0x80)
			--numtowrite;
	}
	// Reset textcount for next tic based on speed
	// if it wasn't already set by a delay.
	if (cutscene_textcount < 0)
	{
		cutscene_textcount = 0;
		if (cutscene_textspeed > 7)
			cutscene_textcount = cutscene_textspeed - 7;
	}
	return 1;
}

static void F_NewCutscene(const char *basetext)
{
	cutscene_basetext = basetext;
	memset(cutscene_disptext,0,sizeof(cutscene_disptext));
	cutscene_writeptr = cutscene_baseptr = 0;
	cutscene_textspeed = 9;
	cutscene_textcount = TICRATE/2;
}

//
// F_SkyScroll
//
static void F_SkyScroll(INT32 scrollspeed)
{
Sal's avatar
Sal committed
	INT32 x, y, w;
	patch_t *pat, *pat2;
	INT32 anim2 = 0;

	pat = W_CachePatchName("TITLEBG1", PU_CACHE);
	pat2 = W_CachePatchName("TITLEBG2", PU_CACHE);
Alam Ed Arias's avatar
Alam Ed Arias committed

Sal's avatar
Sal committed
	w = vid.width / vid.dupx;
Alam Ed Arias's avatar
Alam Ed Arias committed

	animtimer = ((finalecount*scrollspeed)/16) % SHORT(pat->width);
Sal's avatar
Sal committed
	anim2 = SHORT(pat2->width) - (((finalecount*scrollspeed)/16) % SHORT(pat2->width));
Alam Ed Arias's avatar
Alam Ed Arias committed

Sal's avatar
Sal committed
	// SRB2Kart: F_DrawPatchCol is over-engineered; recoded to be less shitty and error-prone
	if (rendermode != render_none)
	{
		V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 120);
Alam Ed Arias's avatar
Alam Ed Arias committed

		x = -((INT32)animtimer);
Sal's avatar
Sal committed
		y = 0;
		while (x < w)
Sryder's avatar
Sryder committed
		{
Sal's avatar
Sal committed
			V_DrawFixedPatch(x*FRACUNIT, y*FRACUNIT, FRACUNIT, V_SNAPTOTOP|V_SNAPTOLEFT, pat, NULL);
			x += SHORT(pat->width);
Alam Arias's avatar
Alam Arias committed
		}
Sal's avatar
Sal committed
		x = -anim2;
		y = BASEVIDHEIGHT - SHORT(pat2->height);
		while (x < w)
		{
			V_DrawFixedPatch(x*FRACUNIT, y*FRACUNIT, FRACUNIT, V_SNAPTOBOTTOM|V_SNAPTOLEFT, pat2, NULL);
			x += SHORT(pat2->width);
Sryder's avatar
Sryder committed
		}
Alam Ed Arias's avatar
Alam Ed Arias committed
	}

	W_UnlockCachedPatch(pat);
Sal's avatar
Sal committed
	W_UnlockCachedPatch(pat2);
Alam Ed Arias's avatar
Alam Ed Arias committed
}

// =============
//  INTRO SCENE
// =============
Sryder's avatar
Sryder committed
#define NUMINTROSCENES 1
Alam Ed Arias's avatar
Alam Ed Arias committed
INT32 intro_scenenum = 0;
INT32 intro_curtime = 0;

const char *introtext[NUMINTROSCENES];

static tic_t introscenetime[NUMINTROSCENES] =
{
Sal's avatar
Sal committed
	 4*TICRATE,	// KART KR(eW
Alam Ed Arias's avatar
Alam Ed Arias committed
};

// custom intros
void F_StartCustomCutscene(INT32 cutscenenum, boolean precutscene, boolean resetplayer);

void F_StartIntro(void)
{
	if (gamestate)
	{
		F_WipeStartScreen();
		V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31);
		F_WipeEndScreen();
		F_RunWipe(wipedefs[wipe_level_final], false);
	}

Alam Ed Arias's avatar
Alam Ed Arias committed
	if (introtoplay)
	{
		if (!cutscenes[introtoplay - 1])
			D_StartTitle();
		else
			F_StartCustomCutscene(introtoplay - 1, false, false);
		return;
	}

	introtext[0] = " #";

	G_SetGamestate(GS_INTRO);
	gameaction = ga_nothing;
	paused = false;
	CON_ToggleOff();
	F_NewCutscene(introtext[0]);

	intro_scenenum = 0;
	finalecount = animtimer = stoptimer = 0;
	roidtics = BASEVIDWIDTH - 64;
	timetonext = introscenetime[intro_scenenum];
Sryder's avatar
Sryder committed
	S_StopMusic();
Eidolon's avatar
Eidolon committed
// F_IntroDrawer
Alam Ed Arias's avatar
Alam Ed Arias committed
//
Eidolon's avatar
Eidolon committed
void F_IntroDrawer(void)
Alam Ed Arias's avatar
Alam Ed Arias committed
{
	boolean highres = false;
	INT32 cx = 8, cy = 128;
	patch_t *background = NULL;
	INT32 bgxoffs = 0;

	// DRAW A FULL PIC INSTEAD OF FLAT!
Sryder's avatar
Sryder committed
	if (intro_scenenum == 0)
Alam Ed Arias's avatar
Alam Ed Arias committed
	{
Sryder's avatar
Sryder committed
		background = W_CachePatchName("KARTKREW", PU_CACHE);
Sryder's avatar
Sryder committed
		highres = true;
Alam Ed Arias's avatar
Alam Ed Arias committed
	}

Sryder's avatar
Sryder committed
	V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 120);
Alam Ed Arias's avatar
Alam Ed Arias committed

	if (background)
	{
		if (highres)
			V_DrawSmallScaledPatch(bgxoffs, 0, 0, background);
		else
			V_DrawScaledPatch(bgxoffs, 0, 0, background);
	}

	W_UnlockCachedPatch(background);

	V_DrawString(cx, cy, 0, cutscene_disptext);
}

//
// F_IntroTicker
//
void F_IntroTicker(void)
{
	// advance animation
	finalecount++;

	if (finalecount % 3 == 0)
		roidtics--;

	timetonext--;

		if (timetonext <= 0)
		{
			intro_scenenum++;
			if (rendermode != render_none)
			{
				F_WipeStartScreen();
				V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31);
				F_WipeEndScreen();
				F_RunWipe(99,true);
			}

			// Stay on black for a bit. =)
			{
				tic_t quittime;
				quittime = I_GetTime() + NEWTICRATE*2; // Shortened the quit time, used to be 2 seconds
				while (quittime > I_GetTime())
				{
					I_Sleep(cv_sleep.value);
					I_UpdateTime(cv_timescale.value);
				}
			}

			D_StartTitle();
			return;
		}
		if (finalecount == 8)
			S_StartSound(NULL, sfx_vroom);
		else if (finalecount == 47)
		{
			// Need to use M_Random otherwise it always uses the same sound
			INT32 rskin = M_RandomKey(numskins);
			UINT8 rtaunt = M_RandomKey(2);
			sfxenum_t rsound = skins[rskin].soundsid[SKSKBST1+rtaunt];
			S_StartSound(NULL, rsound);
		}
	}

Alam Ed Arias's avatar
Alam Ed Arias committed
	F_WriteText();

	// check for skipping
	if (keypressed)
		keypressed = false;
}

//
// F_IntroResponder
//
boolean F_IntroResponder(event_t *event)
{
	INT32 key = event->data1;

	// remap virtual keys (mouse & joystick buttons)
	switch (key)
	{
		case KEY_MOUSE1:
			key = KEY_ENTER;
			break;
		case KEY_MOUSE1 + 1:
			key = KEY_BACKSPACE;
			break;
		case KEY_JOY1:
		case KEY_JOY1 + 2:
			key = KEY_ENTER;
			break;
		case KEY_JOY1 + 3:
			key = 'n';
			break;
		case KEY_JOY1 + 1:
			key = KEY_BACKSPACE;
			break;
		case KEY_HAT1:
			key = KEY_UPARROW;
			break;
		case KEY_HAT1 + 1:
			key = KEY_DOWNARROW;
			break;
		case KEY_HAT1 + 2:
			key = KEY_LEFTARROW;
			break;
		case KEY_HAT1 + 3:
			key = KEY_RIGHTARROW;
			break;
	}

	if (event->type != ev_keydown && key != 301)
		return false;

	if (key != 27 && key != KEY_ENTER && key != KEY_SPACE && key != KEY_BACKSPACE)
		return false;

	if (keypressed)
		return false;

	keypressed = true;
	return true;
}

// =========
//  CREDITS
// =========
static const char *credits[] = {
Sal's avatar
Sal committed
	"\1SRB2Kart",
Alam Ed Arias's avatar
Alam Ed Arias committed
	"\1Credits",
Alam Ed Arias's avatar
Alam Ed Arias committed
	"",
	"\1Game Design",
Sal's avatar
Sal committed
	"Sally \"TehRealSalt\" Cochenour",
	"Jeffery \"Chromatian\" Scott",
	"\"VelocitOni\"",
Alam Ed Arias's avatar
Alam Ed Arias committed
	"",
Sal's avatar
Sal committed
	"\1Lead Programming",
Sal's avatar
Sal committed
	"Sally \"TehRealSalt\" Cochenour",
toaster's avatar
toaster committed
	"Ronald \"Eidolon\" Kinard",
	"James Robert Roman",
	"Sean \"Sryder\" Ryder",
	"Ehab \"wolfs\" Saeed",
	"\"ZarroTsu\"",
Alam Ed Arias's avatar
Alam Ed Arias committed
	"",
Sal's avatar
Sal committed
	"\1Support Programming",
toaster's avatar
toaster committed
	"\"Lach\"",
Sal's avatar
Sal committed
	"\"Lat\'\"",
toaster's avatar
toaster committed
	"AJ \"Tyron\" Martinez",
Sal's avatar
Sal committed
	"\"Monster Iestyn\"",
wolfs's avatar
wolfs committed
	"\"SteelT\"",
Sal's avatar
Sal committed
	"",
toaster's avatar
toaster committed
	"\1External Programming",
	"Alam Ed Arias",
	"\"alphaRexJames\"",
	"\"Ashnal\"",
	"\"filpAM\"",
	"\"FlykeSpice\"",
	"\"Hannu Hanhi\"",
	"\"himie\"",
	"\"JugadorXEI\"",
	"\"Kimberly\"",
	"\"Lighto97\"",
	"\"mazmazz\"",
	"\"minenice\"",
	"\"Shuffle\"",
	"\"Snu\"",
	"",
Sal's avatar
Sal committed
	"\1Lead Artists",
Sal's avatar
Sal committed
	"\"VelocitOni\"",
	"",
	"\1Support Artists",
	"Sally \"TehRealSalt\" Cochenour",
toaster's avatar
toaster committed
	"\"Chengi\"",
	"\"Chrispy\"",
Sal's avatar
Sal committed
	"Sherman \"CoatRack\" DesJardins",
Sal's avatar
Sal committed
	"\"DrTapeworm\"",
Sal's avatar
Sal committed
	"Jesse \"Jeck Jims\" Emerick",
Sal's avatar
Sal committed
	"Wesley \"Charyb\" Gillebaard",
toaster's avatar
toaster committed
	"\"Nev3r\"",
Sal's avatar
Sal committed
	"Vivian \"toaster\" Grannell",
Sal's avatar
Sal committed
	"James \"SeventhSentinel\" Hall",
Sal's avatar
Sal committed
	"\"Lat\'\"",
toaster's avatar
toaster committed
	"\"rairai104n\"",
Sal's avatar
Sal committed
	"\"Tyrannosaur Chao\"",
	"\"ZarroTsu\"",
	"",
	"\1External Artists",
wolfs's avatar
wolfs committed
	"\"1-Up Mason\"",
Sal's avatar
Sal committed
	"\"DirkTheHusky\"",
wolfs's avatar
wolfs committed
	"\"LJSTAR\"",
Sal's avatar
Sal committed
	"\"MotorRoach\"",
Sal's avatar
Sal committed
	"\"Ritz\"",
	"\"Rob\"",
	"\"SmithyGNC\"",
Sal's avatar
Sal committed
	"\"Snu\"",
Sal's avatar
Sal committed
	"\"Spherallic\"",
wolfs's avatar
wolfs committed
	"\"TelosTurntable\"",
Sal's avatar
Sal committed
	"\"VAdaPEGA\"",
Sal's avatar
Sal committed
	"\"Virt\"",
wolfs's avatar
wolfs committed
	"\"Voltrix\"",
Alam Ed Arias's avatar
Alam Ed Arias committed
	"",
Sal's avatar
Sal committed
	"\1Sound Design",
	"James \"SeventhSentinel\" Hall",
	"Sonic Team",
	"\"VAdaPEGA\"",
	"\"VelocitOni\"",
	"",
toaster's avatar
toaster committed
	"\1Original Music",
Sal's avatar
Sal committed
	"\"DrTapeworm\"",
Sal's avatar
Sal committed
	"Wesley \"Charyb\" Gillebaard",
Sal's avatar
Sal committed
	"James \"SeventhSentinel\" Hall",
Alam Ed Arias's avatar
Alam Ed Arias committed
	"",
Sal's avatar
Sal committed
	"\1Lead Level Design",
Sal's avatar
Sal committed
	"\"Blitz-T\"",
	"Sally \"TehRealSalt\" Cochenour",
Sal's avatar
Sal committed
	"Jeffery \"Chromatian\" Scott",
	"\"Tyrannosaur Chao\"",
	"",
	"\1Support Level Design",
	"\"Chaos Zero 64\"",
	"\"D00D64\"",
	"\"DrTapeworm\"",
	"Paul \"Boinciel\" Clempson",
	"Sherman \"CoatRack\" DesJardins",
Sal's avatar
Sal committed
	"Vivian \"toaster\" Grannell",
wolfs's avatar
wolfs committed
	"\"Gunla\"",
Sal's avatar
Sal committed
	"\"Lat\'\"",
wolfs's avatar
wolfs committed
	"\"MK\"",
	"\"Ninferno\"",
	"Sean \"Sryder\" Ryder",
	"\"Ryuspark\"",
Sal's avatar
Sal committed
	"\"Simsmagic\"",
James R.'s avatar
James R. committed
	"Ivo Solarin",
Sal's avatar
Sal committed
	"\"SP47\"",
wolfs's avatar
wolfs committed
	"\"TG\"",
	"\"Victor Rush Turbo\"",
Sal's avatar
Sal committed
	"",
	"\1Testing",
toaster's avatar
toaster committed
	"RKH License holders",
Sal's avatar
Sal committed
	"\"CyberIF\"",
	"\"Dani\"",
	"Karol \"Fooruman\" D""\x1E""browski", // Dąbrowski, <Sryder> accents in srb2 :ytho:
toaster's avatar
toaster committed
	"\"Virt\"",
Alam Ed Arias's avatar
Alam Ed Arias committed
	"",
	"\1Special Thanks",
Sal's avatar
Sal committed
	"SEGA",
	"Sonic Team",
	"SRB2 & Sonic Team Jr. (www.srb2.org)",
	"\"Chaos Zero 64\"",
Alam Ed Arias's avatar
Alam Ed Arias committed
	"",
	"\1Produced By",
Sal's avatar
Sal committed
	"Kart Krew",
Alam Ed Arias's avatar
Alam Ed Arias committed
	"",
Sal's avatar
Sal committed
	"\1In Memory of",
	"\"Tyler52\"",
	"",
Sal's avatar
Sal committed
	"",
Alam Ed Arias's avatar
Alam Ed Arias committed
	"\1Thank you",
	"\1for playing!",
	NULL
};

static struct {
	UINT32 x, y;
	const char *patch;
Sal's avatar
Sal committed
	UINT8 colorize;
Alam Ed Arias's avatar
Alam Ed Arias committed
} credits_pics[] = {
Sal's avatar
Sal committed
	// We don't have time to be fancy, let's just colorize some item sprites :V
toaster's avatar
toaster committed
	{224, 80+(216* 1), "K_ITJAWZ", SKINCOLOR_CREAMSICLE},
	{224, 80+(216* 2), "K_ITSPB",  SKINCOLOR_GARDEN},
	{224, 80+(216* 3), "K_ITBANA", SKINCOLOR_LILAC},
	{224, 80+(216* 4), "K_ITHYUD", SKINCOLOR_DREAM},
	{224, 80+(216* 5), "K_ITBHOG", SKINCOLOR_TANGERINE},
	{224, 80+(216* 6), "K_ITSHRK", SKINCOLOR_JAWZ},
	{224, 80+(216* 7), "K_ITSHOE", SKINCOLOR_MINT},
	{224, 80+(216* 8), "K_ITGROW", SKINCOLOR_RUBY},
	{224, 80+(216* 9), "K_ITPOGO", SKINCOLOR_SAPPHIRE},
	{224, 80+(216*10), "K_ITRSHE", SKINCOLOR_YELLOW},
	{224, 80+(216*11), "K_ITORB4", SKINCOLOR_DUSK},
	{224, 80+(216*12), "K_ITEGGM", SKINCOLOR_GREEN},
	{224, 80+(216*13), "K_ITMINE", SKINCOLOR_BRONZE},
	{224, 80+(216*14), "K_ITTHNS", SKINCOLOR_RASPBERRY},
	{224, 80+(216*15), "K_ITINV1", SKINCOLOR_GREY},
Sal's avatar
Sal committed
	// This Tyler52 gag is troublesome
	// Alignment should be ((spaces+1 * 100) + (headers+1 * 38) + (lines * 15))
toaster's avatar
toaster committed
	// Current max image spacing: (216*17)
	{112, (16*100)+(19*38)+(100*15), "TYLER52", SKINCOLOR_NONE},
Sal's avatar
Sal committed
	{0, 0, NULL, SKINCOLOR_NONE}
Alam Ed Arias's avatar
Alam Ed Arias committed
};

void F_StartCredits(void)
{
	G_SetGamestate(GS_CREDITS);

	// Just in case they're open ... somehow
	M_ClearMenus(true);

	// Save the second we enter the credits
	if ((!modifiedgame || savemoddata) && !(netgame || multiplayer) && cursaveslot >= 0)
		G_SaveGame((UINT32)cursaveslot);

	if (creditscutscene)
	{
		F_StartCustomCutscene(creditscutscene - 1, false, false);
		return;
	}

	gameaction = ga_nothing;
	paused = false;
	CON_ToggleOff();
	S_StopMusic();

	S_ChangeMusicInternal("credit", false);
	S_ShowMusicCredit();
Alam Ed Arias's avatar
Alam Ed Arias committed

	finalecount = 0;
	animtimer = 0;
	timetonext = 2*TICRATE;
}

void F_CreditDrawer(void)
{
	UINT16 i;
	fixed_t y = (80<<FRACBITS) - 5*(animtimer<<FRACBITS)/8;

toaster's avatar
toaster committed
	V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31);
Alam Ed Arias's avatar
Alam Ed Arias committed

Sal's avatar
Sal committed
	// Draw background
Sal's avatar
Sal committed
	V_DrawSciencePatch(0, 0 - FixedMul(32<<FRACBITS, FixedDiv(credbgtimer%TICRATE, TICRATE)), V_SNAPTOTOP, W_CachePatchName("CREDTILE", PU_CACHE), FRACUNIT);
Sal's avatar
Sal committed

Sal's avatar
Sal committed
	V_DrawSciencePatch(0, 0 - FixedMul(40<<FRACBITS, FixedDiv(credbgtimer%(TICRATE/2), (TICRATE/2))), V_SNAPTOTOP, W_CachePatchName("CREDZIGZ", PU_CACHE), FRACUNIT);
	V_DrawSciencePatch(320<<FRACBITS, 0 - FixedMul(40<<FRACBITS, FixedDiv(credbgtimer%(TICRATE/2), (TICRATE/2))), V_SNAPTOTOP|V_FLIP, W_CachePatchName("CREDZIGZ", PU_CACHE), FRACUNIT);
Sal's avatar
Sal committed

	// Draw pictures
Alam Ed Arias's avatar
Alam Ed Arias committed
	for (i = 0; credits_pics[i].patch; i++)
Sal's avatar
Sal committed
	{
		UINT8 *colormap = NULL;
		fixed_t sc = FRACUNIT>>1;

		if (credits_pics[i].colorize != SKINCOLOR_NONE)
		{
			colormap = R_GetTranslationColormap(TC_RAINBOW, credits_pics[i].colorize, GTC_MENUCACHE);
Sal's avatar
Sal committed
			sc = FRACUNIT; // quick hack so I don't have to add another field to credits_pics
		}

		V_DrawFixedPatch(credits_pics[i].x<<FRACBITS, (credits_pics[i].y<<FRACBITS) - 4*(animtimer<<FRACBITS)/5, sc, 0, W_CachePatchName(credits_pics[i].patch, PU_CACHE), colormap);
	}
Alam Ed Arias's avatar
Alam Ed Arias committed

Marco Z's avatar
Marco Z committed
	// Dim the background
Sal's avatar
Sal committed
	//V_DrawFadeScreen();
Alam Ed Arias's avatar
Alam Ed Arias committed
	// Draw credits text on top
	for (i = 0; credits[i]; i++)
	{
		switch(credits[i][0])
		{
		case 0:
			y += 80<<FRACBITS;
			break;
		case 1:
			if (y>>FRACBITS > -20)
				V_DrawCreditString((160 - (V_CreditStringWidth(&credits[i][1])>>1))<<FRACBITS, y, 0, &credits[i][1]);
			y += 30<<FRACBITS;
			break;
		default:
			if (y>>FRACBITS > -10)
				V_DrawStringAtFixed(32<<FRACBITS, y, V_ALLOWLOWERCASE, credits[i]);
			y += 12<<FRACBITS;
			break;
		}
		if (((y>>FRACBITS) * vid.dupy) > vid.height)
Alam Ed Arias's avatar
Alam Ed Arias committed
			break;
	}
toaster's avatar
toaster committed

	// RR isn't any time soon as of writing, but v1.4 is expected to be the last v1 release. Let's give it a proper send off.
	if (finalecount)
	{
		const char *goodbyefornow = "See you in ""\x82""Dr. Robotnik's Ring Racers""\x80""!";
		fixed_t lpad = ((vid.width/vid.dupx) - BASEVIDWIDTH)<<FRACBITS;
		fixed_t w = V_StringWidth(goodbyefornow, V_ALLOWLOWERCASE)<<FRACBITS;
		fixed_t x = FixedMul(((BASEVIDWIDTH<<FRACBITS)+w+lpad), ((finalecount-1)<<FRACBITS)/(5*TICRATE)) - w - (lpad/2);
		V_DrawString(x>>FRACBITS, y>>FRACBITS, V_ALLOWLOWERCASE, goodbyefornow); // for some reason DrawStringAtFixed can't tolerate colour codes
	}
Alam Ed Arias's avatar
Alam Ed Arias committed

void F_CreditTicker(void)
{
	// "Simulate" the drawing of the credits so that dedicated mode doesn't get stuck
	UINT16 i;
	fixed_t y = (80<<FRACBITS) - 5*(animtimer<<FRACBITS)/8;
	// Draw credits text on top
	for (i = 0; credits[i]; i++)
	{
		switch(credits[i][0])
		{
			case 0: y += 80<<FRACBITS; break;
			case 1: y += 30<<FRACBITS; break;
			default: y += 12<<FRACBITS; break;
		}
		if (FixedMul(y,vid.dupy) > vid.height)
			break;
	}
Alam Ed Arias's avatar
Alam Ed Arias committed

	// Do this here rather than in the drawer you doofus! (this is why dedicated mode broke at credits)
Alam Ed Arias's avatar
Alam Ed Arias committed
	if (!credits[i] && y <= 120<<FRACBITS && !finalecount)
	{
		timetonext = 5*TICRATE+1;
		finalecount = 5*TICRATE;
	}

	if (timetonext)
		timetonext--;
	else
		animtimer++;

Sal's avatar
Sal committed
	credbgtimer++;

Alam Ed Arias's avatar
Alam Ed Arias committed
	if (finalecount && --finalecount == 0)
		F_StartGameEvaluation();
}

boolean F_CreditResponder(event_t *event)
{
	INT32 key = event->data1;

	// remap virtual keys (mouse & joystick buttons)
	switch (key)
	{
		case KEY_MOUSE1:
			key = KEY_ENTER;
			break;
		case KEY_MOUSE1 + 1:
			key = KEY_BACKSPACE;
			break;
		case KEY_JOY1:
		case KEY_JOY1 + 2:
			key = KEY_ENTER;
			break;
		case KEY_JOY1 + 3:
			key = 'n';
			break;
		case KEY_JOY1 + 1:
			key = KEY_BACKSPACE;
			break;
		case KEY_HAT1:
			key = KEY_UPARROW;
			break;
		case KEY_HAT1 + 1:
			key = KEY_DOWNARROW;
			break;
		case KEY_HAT1 + 2:
			key = KEY_LEFTARROW;
			break;
		case KEY_HAT1 + 3:
			key = KEY_RIGHTARROW;
			break;
	}

	if (event->type != ev_keydown)
		return false;

	if (key == KEY_DOWNARROW || key == KEY_SPACE)
	{
		if (!timetonext && !finalecount)
			animtimer += 7;
		return false;
	}

	/*if (!(timesBeaten) && !(netgame || multiplayer))
		return false;*/

	if (key != KEY_ESCAPE && key != KEY_ENTER && key != KEY_BACKSPACE)
Alam Ed Arias's avatar
Alam Ed Arias committed
		return false;

	if (keypressed)
		return true;

	keypressed = true;
	return true;
}

// ============
//  EVALUATION
// ============
#define INTERVAL 50
#define TRANSLEVEL V_80TRANS
static INT32 eemeralds_start;
static boolean drawemblem = false, drawchaosemblem = false;

void F_StartGameEvaluation(void)
{
	// Credits option in secrets menu
	if (cursaveslot == -2)
	{
		F_StartGameEnd();
		return;
	}

	G_SetGamestate(GS_EVALUATION);

	// Just in case they're open ... somehow
	M_ClearMenus(true);

	// Save the second we enter the evaluation
	// We need to do this again!  Remember, it's possible a mod designed skipped
	// the credits sequence!
	if ((!modifiedgame || savemoddata) && !(netgame || multiplayer) && cursaveslot >= 0)
		G_SaveGame((UINT32)cursaveslot);

	gameaction = ga_nothing;
	paused = false;
	CON_ToggleOff();

	finalecount = 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";

	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)
	{
		fa = (FixedAngle(eemeralds_cur*FRACUNIT)>>ANGLETOFINESHIFT) & FINEMASK;
		x = 160 + FixedInt(FixedMul(FINECOSINE(fa),radius));
		y = 100 + FixedInt(FixedMul(FINESINE(fa),radius));

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

		eemeralds_cur += INTERVAL;
	}
	if (eemeralds_start >= 360)
		eemeralds_start -= 360;

	if (finalecount == 5*TICRATE)
	{
		if ((!modifiedgame || savemoddata) && !(netgame || multiplayer))
		{
			++timesBeaten;

			if (ALL7EMERALDS(emeralds))
				++timesBeatenWithEmeralds;
			/*if (ultimatemode)
				++timesBeatenUltimate;*/
			if (M_UpdateUnlockablesAndExtraEmblems(false))
Alam Ed Arias's avatar
Alam Ed Arias committed
				S_StartSound(NULL, sfx_ncitem);

Alam Ed Arias's avatar
Alam Ed Arias committed
		}
	}

	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))
		{
			INT32 startcoord = 32;

			for (i = 0; i < MAXUNLOCKABLES; i++)
			{
				if (unlockables[i].conditionset && unlockables[i].conditionset < MAXCONDITIONSETS
					&& unlockables[i].type && !unlockables[i].nocecho)
				{
					if (unlockables[i].unlocked)
						V_DrawString(8, startcoord, 0, unlockables[i].name);
					startcoord += 8;
				}
			}
		}
		else if (netgame)
			V_DrawString(8, 96, V_YELLOWMAP, "Prizes only\nawarded in\nsingle player!");
		else
			V_DrawString(8, 96, V_YELLOWMAP, "Prizes not\nawarded in\nmodified games!");
	}
}

void F_GameEvaluationTicker(void)
{
	finalecount++;

	if (finalecount > 10*TICRATE)
		F_StartGameEnd();
}

// ==========
//  GAME END
// ==========
void F_StartGameEnd(void)
{
	G_SetGamestate(GS_GAMEEND);

	gameaction = ga_nothing;
	paused = false;
	CON_ToggleOff();
	S_StopMusic();

	// In case menus are still up?!!
	M_ClearMenus(true);

	timetonext = TICRATE;
}

//
// F_GameEndDrawer
//
void F_GameEndDrawer(void)
{
Alam Ed Arias's avatar
Alam Ed Arias committed
}

//
// F_GameEndTicker
//
void F_GameEndTicker(void)
{
	if (timetonext > 0)
		timetonext--;
	else
		D_StartTitle();
}


// ==============
//  TITLE SCREEN
// ==============
void F_StartTitleScreen(void)
{
	if (gamestate != GS_TITLESCREEN && gamestate != GS_WAITINGPLAYERS)
		finalecount = 0;
	else
		wipegamestate = GS_TITLESCREEN;
	G_SetGamestate(GS_TITLESCREEN);
	CON_ClearHUD();

	// IWAD dependent stuff.

	if (!demo.fromtitle) // SRB2Kart: Don't reset music if the right track is already playing
		S_StopMusic();
	demo.fromtitle = false;
Alam Ed Arias's avatar
Alam Ed Arias committed

	animtimer = 0;

	demoDelayLeft = demoDelayTime;
	demoIdleLeft = demoIdleTime;

	ttbanner = W_CachePatchName("TTKBANNR", PU_LEVEL);
	ttkart = W_CachePatchName("TTKART", PU_LEVEL);
	ttcheckers = W_CachePatchName("TTCHECK", PU_LEVEL);
	ttkflash = W_CachePatchName("TTKFLASH", PU_LEVEL);
Alam Ed Arias's avatar
Alam Ed Arias committed
}

// (no longer) De-Demo'd Title Screen
void F_TitleScreenDrawer(void)
{
	if (modeattacking)
		return; // We likely came here from retrying. Don't do a damn thing.

toaster's avatar
toaster committed
	// Don't draw outside of the title screen, or if the patch isn't there.
	if (!ttbanner || (gamestate != GS_TITLESCREEN && gamestate != GS_WAITINGPLAYERS))
toaster's avatar
toaster committed
	{
		F_SkyScroll(titlescrollspeed);
Alam Ed Arias's avatar
Alam Ed Arias committed
		return;
toaster's avatar
toaster committed
	}
Alam Ed Arias's avatar
Alam Ed Arias committed

toaster's avatar
toaster committed
	if (finalecount < 50)
Alam Ed Arias's avatar
Alam Ed Arias committed
	{
		V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31);
toaster's avatar
toaster committed

		V_DrawSmallScaledPatch(84, 36, 0, ttbanner);

		if (finalecount >= 20)
			V_DrawSmallScaledPatch(84, 87, 0, ttkart);
		else if (finalecount >= 10)
			V_DrawSciencePatch((84<<FRACBITS) - FixedDiv(180<<FRACBITS, 10<<FRACBITS)*(20-finalecount), (87<<FRACBITS), 0, ttkart, FRACUNIT/2);
Alam Ed Arias's avatar
Alam Ed Arias committed
	}
toaster's avatar
toaster committed
	else if (finalecount < 52)
	{
		V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 120);
toaster's avatar
toaster committed
		V_DrawSmallScaledPatch(84, 36, 0, ttkflash);
	}
Alam Ed Arias's avatar
Alam Ed Arias committed
	else
	{
toaster's avatar
toaster committed
		INT32 transval = 0;

		if (finalecount <= (50+(9<<1)))
			transval = (finalecount - 50)>>1;

		F_SkyScroll(titlescrollspeed);
		V_DrawSciencePatch(0, 0 - FixedMul(40<<FRACBITS, FixedDiv(finalecount%70, 70)), V_SNAPTOTOP|V_SNAPTOLEFT, ttcheckers, FRACUNIT);
		V_DrawSciencePatch(280<<FRACBITS, -(40<<FRACBITS) + FixedMul(40<<FRACBITS, FixedDiv(finalecount%70, 70)), V_SNAPTOTOP|V_SNAPTORIGHT, ttcheckers, FRACUNIT);
Alam Ed Arias's avatar
Alam Ed Arias committed

toaster's avatar
toaster committed
		if (transval)
			V_DrawFadeScreen(120, 10 - transval);

		V_DrawSmallScaledPatch(84, 36, 0, ttbanner);