mirror of
https://git.do.srb2.org/STJr/SRB2.git
synced 2025-02-03 06:51:11 +00:00
e79654a33a
Time is now tracked internally in the game using I_GetPreciseTime and I_UpdateTime. I_Time now pulls from this internal timer. The system code no longer needs to keep track of time itself. This significantly improves frame and tic timing in interp mode, resulting in a much smoother image with essentially no judder at any framerate.
4683 lines
141 KiB
C
4683 lines
141 KiB
C
// SONIC ROBO BLAST 2
|
|
//-----------------------------------------------------------------------------
|
|
// Copyright (C) 1993-1996 by id Software, Inc.
|
|
// Copyright (C) 1998-2000 by DooM Legacy Team.
|
|
// Copyright (C) 1999-2022 by Sonic Team Junior.
|
|
//
|
|
// 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 "d_netcmd.h"
|
|
#include "f_finale.h"
|
|
#include "g_game.h"
|
|
#include "hu_stuff.h"
|
|
#include "r_local.h"
|
|
#include "s_sound.h"
|
|
#include "i_time.h"
|
|
#include "i_video.h"
|
|
#include "v_video.h"
|
|
#include "w_wad.h"
|
|
#include "z_zone.h"
|
|
#include "i_system.h"
|
|
#include "i_threads.h"
|
|
#include "m_menu.h"
|
|
#include "dehacked.h"
|
|
#include "g_input.h"
|
|
#include "console.h"
|
|
#include "m_random.h"
|
|
#include "m_misc.h" // moviemode functionality
|
|
#include "y_inter.h"
|
|
#include "m_cond.h"
|
|
#include "p_local.h"
|
|
#include "p_setup.h"
|
|
#include "st_stuff.h" // hud hiding
|
|
#include "fastcmp.h"
|
|
#include "console.h"
|
|
|
|
#include "lua_hud.h"
|
|
#include "lua_hook.h"
|
|
|
|
// Stage of animation:
|
|
// 0 = text, 1 = art screen
|
|
INT32 finalecount;
|
|
INT32 titlescrollxspeed = 20;
|
|
INT32 titlescrollyspeed = 0;
|
|
UINT8 titlemapinaction = TITLEMAP_OFF;
|
|
|
|
static INT32 timetonext; // Delay between screen changes
|
|
static INT32 continuetime; // Short delay when continuing
|
|
|
|
static tic_t animtimer; // Used for some animation timings
|
|
static INT16 skullAnimCounter; // Prompts: Chevron animation
|
|
|
|
static INT32 deplete;
|
|
static tic_t stoptimer;
|
|
|
|
static boolean keypressed = false;
|
|
|
|
// (no longer) De-Demo'd Title Screen
|
|
static INT32 menuanimtimer; // Title screen: background animation timing
|
|
mobj_t *titlemapcameraref = NULL;
|
|
|
|
// menu presentation state
|
|
char curbgname[9];
|
|
SINT8 curfadevalue;
|
|
INT32 curbgcolor;
|
|
INT32 curbgxspeed;
|
|
INT32 curbgyspeed;
|
|
boolean curbghide;
|
|
boolean hidetitlemap; // WARNING: set to false by M_SetupNextMenu and M_ClearMenus
|
|
|
|
static UINT8 curDemo = 0;
|
|
static UINT32 demoDelayLeft;
|
|
static UINT32 demoIdleLeft;
|
|
|
|
// customizable title screen graphics
|
|
|
|
ttmode_enum ttmode = TTMODE_OLD;
|
|
UINT8 ttscale = 1; // FRACUNIT / ttscale
|
|
// ttmode user vars
|
|
char ttname[9];
|
|
INT16 ttx = 0;
|
|
INT16 tty = 0;
|
|
INT16 ttloop = -1;
|
|
UINT16 tttics = 1;
|
|
|
|
boolean curhidepics;
|
|
ttmode_enum curttmode;
|
|
UINT8 curttscale;
|
|
// ttmode user vars
|
|
char curttname[9];
|
|
INT16 curttx;
|
|
INT16 curtty;
|
|
INT16 curttloop;
|
|
UINT16 curtttics;
|
|
|
|
// ttmode old
|
|
static patch_t *ttbanner; // white banner with "robo blast" and "2"
|
|
static patch_t *ttwing; // wing background
|
|
static patch_t *ttsonic; // "SONIC"
|
|
static patch_t *ttswave1; // Title Sonics
|
|
static patch_t *ttswave2;
|
|
static patch_t *ttswip1;
|
|
static patch_t *ttsprep1;
|
|
static patch_t *ttsprep2;
|
|
static patch_t *ttspop1;
|
|
static patch_t *ttspop2;
|
|
static patch_t *ttspop3;
|
|
static patch_t *ttspop4;
|
|
static patch_t *ttspop5;
|
|
static patch_t *ttspop6;
|
|
static patch_t *ttspop7;
|
|
|
|
// ttmode alacroix
|
|
static SINT8 testttscale = 0;
|
|
static SINT8 activettscale = 0;
|
|
boolean ttavailable[6];
|
|
boolean ttloaded[6];
|
|
|
|
static patch_t *ttribb[6][TTMAX_ALACROIX];
|
|
static patch_t *ttsont[6][TTMAX_ALACROIX];
|
|
static patch_t *ttrobo[6][TTMAX_ALACROIX];
|
|
static patch_t *tttwot[6][TTMAX_ALACROIX];
|
|
static patch_t *ttembl[6][TTMAX_ALACROIX];
|
|
static patch_t *ttrbtx[6][TTMAX_ALACROIX];
|
|
static patch_t *ttsoib[6][TTMAX_ALACROIX];
|
|
static patch_t *ttsoif[6][TTMAX_ALACROIX];
|
|
static patch_t *ttsoba[6][TTMAX_ALACROIX];
|
|
static patch_t *ttsobk[6][TTMAX_ALACROIX];
|
|
static patch_t *ttsodh[6][TTMAX_ALACROIX];
|
|
static patch_t *tttaib[6][TTMAX_ALACROIX];
|
|
static patch_t *tttaif[6][TTMAX_ALACROIX];
|
|
static patch_t *tttaba[6][TTMAX_ALACROIX];
|
|
static patch_t *tttabk[6][TTMAX_ALACROIX];
|
|
static patch_t *tttabt[6][TTMAX_ALACROIX];
|
|
static patch_t *tttaft[6][TTMAX_ALACROIX];
|
|
static patch_t *ttknib[6][TTMAX_ALACROIX];
|
|
static patch_t *ttknif[6][TTMAX_ALACROIX];
|
|
static patch_t *ttknba[6][TTMAX_ALACROIX];
|
|
static patch_t *ttknbk[6][TTMAX_ALACROIX];
|
|
static patch_t *ttkndh[6][TTMAX_ALACROIX];
|
|
|
|
#define TTEMBL (ttembl[activettscale-1])
|
|
#define TTRIBB (ttribb[activettscale-1])
|
|
#define TTSONT (ttsont[activettscale-1])
|
|
#define TTROBO (ttrobo[activettscale-1])
|
|
#define TTTWOT (tttwot[activettscale-1])
|
|
#define TTRBTX (ttrbtx[activettscale-1])
|
|
#define TTSOIB (ttsoib[activettscale-1])
|
|
#define TTSOIF (ttsoif[activettscale-1])
|
|
#define TTSOBA (ttsoba[activettscale-1])
|
|
#define TTSOBK (ttsobk[activettscale-1])
|
|
#define TTSODH (ttsodh[activettscale-1])
|
|
#define TTTAIB (tttaib[activettscale-1])
|
|
#define TTTAIF (tttaif[activettscale-1])
|
|
#define TTTABA (tttaba[activettscale-1])
|
|
#define TTTABK (tttabk[activettscale-1])
|
|
#define TTTABT (tttabt[activettscale-1])
|
|
#define TTTAFT (tttaft[activettscale-1])
|
|
#define TTKNIB (ttknib[activettscale-1])
|
|
#define TTKNIF (ttknif[activettscale-1])
|
|
#define TTKNBA (ttknba[activettscale-1])
|
|
#define TTKNBK (ttknbk[activettscale-1])
|
|
#define TTKNDH (ttkndh[activettscale-1])
|
|
|
|
static boolean sonic_blink = false;
|
|
static boolean sonic_blink_twice = false;
|
|
static boolean sonic_blinked_already = false;
|
|
static INT32 sonic_idle_start = 0;
|
|
static INT32 sonic_idle_end = 0;
|
|
static boolean tails_blink = false;
|
|
static boolean tails_blink_twice = false;
|
|
static boolean tails_blinked_already = false;
|
|
static INT32 tails_idle_start = 0;
|
|
static INT32 tails_idle_end = 0;
|
|
static boolean knux_blink = false;
|
|
static boolean knux_blink_twice = false;
|
|
static boolean knux_blinked_already = false;
|
|
static INT32 knux_idle_start = 0;
|
|
static INT32 knux_idle_end = 0;
|
|
|
|
// ttmode user
|
|
static patch_t *ttuser[TTMAX_USER];
|
|
static INT32 ttuser_count = 0;
|
|
|
|
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
|
|
//
|
|
boolean promptactive = false;
|
|
static mobj_t *promptmo;
|
|
static INT16 promptpostexectag;
|
|
static boolean promptblockcontrols;
|
|
static char *promptpagetext = NULL;
|
|
static INT32 callpromptnum = INT32_MAX;
|
|
static INT32 callpagenum = INT32_MAX;
|
|
static INT32 callplayer = INT32_MAX;
|
|
|
|
//
|
|
// 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;
|
|
|
|
// STJR Intro
|
|
char stjrintro[9] = "STJRI000";
|
|
|
|
static huddrawlist_h luahuddrawlist_title;
|
|
|
|
//
|
|
// 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;
|
|
}
|
|
|
|
// =============
|
|
// INTRO SCENE
|
|
// =============
|
|
#define NUMINTROSCENES 17
|
|
INT32 intro_scenenum = 0;
|
|
INT32 intro_curtime = 0;
|
|
|
|
const char *introtext[NUMINTROSCENES];
|
|
|
|
static tic_t introscenetime[NUMINTROSCENES] =
|
|
{
|
|
5*TICRATE, // STJr Presents
|
|
11*TICRATE + (TICRATE/2), // Two months had passed since...
|
|
15*TICRATE + (TICRATE/2), // As it was about to drain the rings...
|
|
14*TICRATE, // What Sonic, Tails, and Knuckles...
|
|
18*TICRATE, // About once every year, a strange...
|
|
19*TICRATE + (TICRATE/2), // Curses! Eggman yelled. That ridiculous...
|
|
19*TICRATE + (TICRATE/4), // It was only later that he had an idea...
|
|
10*TICRATE + (TICRATE/2), // Before beginning his scheme, Eggman decided to give Sonic...
|
|
16*TICRATE, // We're ready to fire in 15 seconds, the robot said...
|
|
16*TICRATE, // Meanwhile, Sonic was tearing across the zones...
|
|
16*TICRATE + (TICRATE/2), // Sonic knew he was getting closer to the city...
|
|
17*TICRATE, // Greenflower City was gone...
|
|
7*TICRATE, // You're not quite as dead as we thought, huh?...
|
|
8*TICRATE, // We'll see... let's give you a quick warm up...
|
|
18*TICRATE + (TICRATE/2), // Eggman took this as his cue and blasted off...
|
|
16*TICRATE, // Easy! We go find Eggman and stop his...
|
|
25*TICRATE, // I'm just finding what mission obje...
|
|
};
|
|
|
|
// custom intros
|
|
void F_StartCustomCutscene(INT32 cutscenenum, boolean precutscene, boolean resetplayer);
|
|
|
|
void F_StartIntro(void)
|
|
{
|
|
S_StopMusic();
|
|
S_StopSounds();
|
|
|
|
if (introtoplay)
|
|
{
|
|
if (!cutscenes[introtoplay - 1])
|
|
D_StartTitle();
|
|
else
|
|
F_StartCustomCutscene(introtoplay - 1, false, false);
|
|
return;
|
|
}
|
|
|
|
introtext[0] = " #";
|
|
|
|
introtext[1] = M_GetText(
|
|
"Two months had passed since Dr. Eggman\n"
|
|
"tried to take over the world using his\n"
|
|
"Ring Satellite.\n#");
|
|
|
|
introtext[2] = M_GetText(
|
|
"As it was about to drain the rings\n"
|
|
"away from the planet, Sonic burst into\n"
|
|
"the control room and for what he thought\n"
|
|
"would be the last time,\xB4 defeated\n"
|
|
"Dr. Eggman.\n#");
|
|
|
|
introtext[3] = M_GetText(
|
|
"\nWhat Sonic, Tails, and Knuckles had\n"
|
|
"not anticipated was that Eggman would\n"
|
|
"return,\xB8 bringing an all new threat.\n#");
|
|
|
|
introtext[4] = M_GetText(
|
|
"\xA8""About every five years, a strange asteroid\n"
|
|
"hovers around the planet.\xBF It suddenly\n"
|
|
"appears from nowhere, circles around, and\n"
|
|
"\xB6- just as mysteriously as it arrives -\xB6\n"
|
|
"vanishes after only one week.\xBF\n"
|
|
"No one knows why it appears, or how.\n#");
|
|
|
|
introtext[5] = M_GetText(
|
|
"\xA7\"Curses!\"\xA9\xBA Eggman yelled. \xA7\"That hedgehog\n"
|
|
"and his ridiculous friends will pay\n"
|
|
"dearly for this!\"\xA9\xC8 Just then his scanner\n"
|
|
"blipped as the Black Rock made its\n"
|
|
"appearance from nowhere.\xBF Eggman looked at\n"
|
|
"the screen, and just shrugged it off.\n#");
|
|
|
|
introtext[6] = M_GetText(
|
|
"It was hours later\n"
|
|
"that he had an\n"
|
|
"idea. \xBF\xA7\"The Black\n"
|
|
"Rock has a large\n"
|
|
"amount of energy\n"
|
|
"within it\xAC...\xA7\xBF\n"
|
|
"If I can somehow\n"
|
|
"harness this,\xB8 I\n"
|
|
"can turn it into\n"
|
|
"the ultimate\n"
|
|
"battle station\xAC...\xA7\xBF\n"
|
|
"And every last\n"
|
|
"person will be\n"
|
|
"begging for mercy,\xB8\xA8\n"
|
|
"including Sonic!\"\n#");
|
|
|
|
introtext[7] = M_GetText(
|
|
"\xA8\nBefore beginning his scheme,\n"
|
|
"Eggman decided to give Sonic\n"
|
|
"a reunion party...\n#");
|
|
|
|
introtext[8] = M_GetText(
|
|
"\xA5\"PRE-""\xB6""PARING-""\xB6""TO-""\xB4""FIRE-\xB6IN-""\xB6""15-""\xB6""SECONDS!\"\xA8\xB8\n"
|
|
"his targeting system crackled\n"
|
|
"robotically down the com-link. \xBF\xA7\"Good!\"\xA8\xB8\n"
|
|
"Eggman sat back in his eggmobile and\n"
|
|
"began to count down as he saw the\n"
|
|
"Greenflower mountain on the monitor.\n#");
|
|
|
|
introtext[9] = M_GetText(
|
|
"\xA5\"10...\xD2""9...\xD2""8...\"\xA8\xD2\n"
|
|
"Meanwhile, Sonic was tearing across the\n"
|
|
"zones. Everything became a blur as he\n"
|
|
"ran up slopes, skimmed over water,\n"
|
|
"and catapulted himself off rocks with\n"
|
|
"his phenomenal speed.\n#");
|
|
|
|
introtext[10] = M_GetText(
|
|
"\xA5\"6...\xD2""5...\xD2""4...\"\xA8\xD2\n"
|
|
"Sonic knew he was getting closer to the\n"
|
|
"zone, and pushed himself harder.\xB4 Finally,\n"
|
|
"the mountain appeared on the horizon.\xD2\xD2\n"
|
|
"\xA5\"3...\xD2""2...\xD2""1...\xD2""Zero.\"\n#");
|
|
|
|
introtext[11] = M_GetText(
|
|
"Greenflower Mountain was no more.\xC4\n"
|
|
"Sonic arrived just in time to see what\n"
|
|
"little of the 'ruins' were left.\n"
|
|
"The natural beauty of the zone\n"
|
|
"had been obliterated.\n#");
|
|
|
|
introtext[12] = M_GetText(
|
|
"\xA7\"You're not\n"
|
|
"quite as gone\n"
|
|
"as we thought,\n"
|
|
"huh?\xBF Are you\n"
|
|
"going to tell\n"
|
|
"us your plan as\n"
|
|
"usual or will I\n"
|
|
"\xA8\xB4'have to work\n"
|
|
"it out'\xA7 or\n"
|
|
"something?\"\xD2\xD2\n#");
|
|
|
|
introtext[13] = M_GetText(
|
|
"\"We'll see\xAA...\xA7\xBF let's give you a quick warm\n"
|
|
"up, Sonic!\xA6\xC4 JETTYSYNS!\xA7\xBD Open fire!\"\n#");
|
|
|
|
introtext[14] = M_GetText(
|
|
"Eggman took this\n"
|
|
"as his cue and\n"
|
|
"blasted off,\n"
|
|
"leaving Sonic\n"
|
|
"and Tails behind.\xB6\n"
|
|
"Tails looked at\n"
|
|
"the once-perfect\n"
|
|
"mountainside\n"
|
|
"with a grim face\n"
|
|
"and sighed.\xC6\n"
|
|
"\xA7\"Now\xB6 what do we\n"
|
|
"do?\",\xA9 he asked.\n#");
|
|
|
|
introtext[15] = M_GetText(
|
|
"\xA7\"Easy!\xBF We go\n"
|
|
"find Eggman\n"
|
|
"and stop his\n"
|
|
"latest\n"
|
|
"insane plan.\xBF\n"
|
|
"Just like\n"
|
|
"we've always\n"
|
|
"done,\xBA right?\xD2\n\n"
|
|
"\xAE...\xA9\xD2\n\n"
|
|
"\"Tails, what\n"
|
|
"\xAA*ARE*\xA9 you\n"
|
|
"doing?\"\n#");
|
|
|
|
introtext[16] = M_GetText(
|
|
"\xA8\"I'm just finding what mission obje\xAC\xB1...\xBF\n"
|
|
"\xA6""a-\xB8""ha!\xBF Here it is!\xA8\xBF This will only give us\n"
|
|
"the robot's primary objective.\xBF It says\xAC\xB1...\"\n"
|
|
"\xD2\xA3\x83"
|
|
"* LOCATE AND RETRIEVE: CHAOS EMERALDS *"
|
|
"\xBF\n"
|
|
"* CLOSEST LOCATION: GREENFLOWER ZONE *"
|
|
"\x80\n\xA9\xD2\xD2"
|
|
"\"All right, then\xAF... \xD2\xD2\xA7let's go!\"\n#");
|
|
|
|
/*
|
|
"What are we waiting for? The first emerald is ours!" Sonic was about to
|
|
run, when he saw a shadow pass over him, he recognized the silhouette
|
|
instantly.
|
|
"Knuckles!" Sonic said. The echidna stopped his glide and landed
|
|
facing Sonic. "What are you doing here?"
|
|
He replied, "This crisis affects the Floating Island,
|
|
if that explosion I saw is anything to go by."
|
|
If you're willing to help then... let's go!"
|
|
*/
|
|
|
|
G_SetGamestate(GS_INTRO);
|
|
gameaction = ga_nothing;
|
|
paused = false;
|
|
CON_ToggleOff();
|
|
F_NewCutscene(introtext[0]);
|
|
|
|
intro_scenenum = 0;
|
|
finalecount = animtimer = skullAnimCounter = stoptimer = 0;
|
|
timetonext = introscenetime[intro_scenenum];
|
|
}
|
|
|
|
//
|
|
// F_IntroDrawer
|
|
//
|
|
void F_IntroDrawer(void)
|
|
{
|
|
boolean highres = true;
|
|
INT32 cx = 8, cy = 128;
|
|
patch_t *background = NULL;
|
|
INT32 bgxoffs = 0;
|
|
void *patch;
|
|
|
|
// DRAW A FULL PIC INSTEAD OF FLAT!
|
|
switch (intro_scenenum)
|
|
{
|
|
case 0:
|
|
bgxoffs = 28;
|
|
break;
|
|
case 1:
|
|
background = W_CachePatchName("INTRO1", PU_PATCH_LOWPRIORITY);
|
|
break;
|
|
case 2:
|
|
background = W_CachePatchName("INTRO2", PU_PATCH_LOWPRIORITY);
|
|
break;
|
|
case 3:
|
|
background = W_CachePatchName("INTRO3", PU_PATCH_LOWPRIORITY);
|
|
break;
|
|
case 4:
|
|
background = W_CachePatchName("INTRO4", PU_PATCH_LOWPRIORITY);
|
|
break;
|
|
case 5:
|
|
if (intro_curtime >= 5*TICRATE)
|
|
background = W_CachePatchName("RADAR", PU_PATCH_LOWPRIORITY);
|
|
else
|
|
background = W_CachePatchName("DRAT", PU_PATCH_LOWPRIORITY);
|
|
break;
|
|
case 6:
|
|
background = W_CachePatchName("INTRO6", PU_PATCH_LOWPRIORITY);
|
|
cx = 180;
|
|
cy = 8;
|
|
break;
|
|
case 7:
|
|
{
|
|
if (intro_curtime >= 7*TICRATE + ((TICRATE/7)*2))
|
|
background = W_CachePatchName("SGRASS5", PU_PATCH_LOWPRIORITY);
|
|
else if (intro_curtime >= 7*TICRATE + (TICRATE/7))
|
|
background = W_CachePatchName("SGRASS4", PU_PATCH_LOWPRIORITY);
|
|
else if (intro_curtime >= 7*TICRATE)
|
|
background = W_CachePatchName("SGRASS3", PU_PATCH_LOWPRIORITY);
|
|
else if (intro_curtime >= 6*TICRATE)
|
|
background = W_CachePatchName("SGRASS2", PU_PATCH_LOWPRIORITY);
|
|
else
|
|
background = W_CachePatchName("SGRASS1", PU_PATCH_LOWPRIORITY);
|
|
break;
|
|
}
|
|
case 8:
|
|
background = W_CachePatchName("WATCHING", PU_PATCH_LOWPRIORITY);
|
|
break;
|
|
case 9:
|
|
background = W_CachePatchName("ZOOMING", PU_PATCH_LOWPRIORITY);
|
|
break;
|
|
case 10:
|
|
break;
|
|
case 11:
|
|
background = W_CachePatchName("INTRO5", PU_PATCH_LOWPRIORITY);
|
|
break;
|
|
case 12:
|
|
background = W_CachePatchName("REVENGE", PU_PATCH_LOWPRIORITY);
|
|
cx = 208;
|
|
cy = 8;
|
|
break;
|
|
case 13:
|
|
background = W_CachePatchName("CONFRONT", PU_PATCH_LOWPRIORITY);
|
|
cy += 48;
|
|
break;
|
|
case 14:
|
|
background = W_CachePatchName("TAILSSAD", PU_PATCH_LOWPRIORITY);
|
|
bgxoffs = 144;
|
|
cx = 8;
|
|
cy = 8;
|
|
break;
|
|
case 15:
|
|
if (intro_curtime >= 7*TICRATE)
|
|
background = W_CachePatchName("SONICDO2", PU_PATCH_LOWPRIORITY);
|
|
else
|
|
background = W_CachePatchName("SONICDO1", PU_PATCH_LOWPRIORITY);
|
|
cx = 224;
|
|
cy = 8;
|
|
break;
|
|
case 16:
|
|
background = W_CachePatchName("INTRO7", PU_PATCH_LOWPRIORITY);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31);
|
|
|
|
if (background)
|
|
{
|
|
if (highres)
|
|
V_DrawSmallScaledPatch(bgxoffs, 0, 0, background);
|
|
else
|
|
V_DrawScaledPatch(bgxoffs, 0, 0, background);
|
|
}
|
|
else if (intro_scenenum == 0) // STJr presents
|
|
{
|
|
if (intro_curtime > 1 && intro_curtime < (INT32)introscenetime[intro_scenenum])
|
|
{
|
|
V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31);
|
|
|
|
if (intro_curtime < TICRATE-5) // Make the text shine!
|
|
{
|
|
sprintf(stjrintro, "STJRI%03u", intro_curtime-1);
|
|
}
|
|
else if (intro_curtime >= TICRATE-6 && intro_curtime < 2*TICRATE-20) // Pause on black screen for just a second
|
|
{
|
|
return;
|
|
}
|
|
else if (intro_curtime == 2*TICRATE-19)
|
|
{
|
|
// Fade in the text
|
|
// The text fade out is automatically handled when switching to a new intro scene
|
|
strncpy(stjrintro, "STJRI029", 9);
|
|
background = W_CachePatchName(stjrintro, PU_PATCH_LOWPRIORITY);
|
|
V_DrawSmallScaledPatch(bgxoffs, 84, 0, background);
|
|
}
|
|
|
|
if (!WipeInAction) // Draw the patch if not in a wipe
|
|
{
|
|
background = W_CachePatchName(stjrintro, PU_PATCH_LOWPRIORITY);
|
|
V_DrawSmallScaledPatch(bgxoffs, 84, 0, background);
|
|
}
|
|
}
|
|
}
|
|
else if (intro_scenenum == 10) // Sky Runner
|
|
{
|
|
if (timetonext > 5*TICRATE && timetonext < 6*TICRATE)
|
|
{
|
|
if (!(finalecount & 3))
|
|
background = W_CachePatchName("BRITEGG1", PU_PATCH_LOWPRIORITY);
|
|
else
|
|
background = W_CachePatchName("DARKEGG1", PU_PATCH_LOWPRIORITY);
|
|
|
|
V_DrawSmallScaledPatch(0, 0, 0, background);
|
|
}
|
|
else if (timetonext > 3*TICRATE && timetonext < 4*TICRATE)
|
|
{
|
|
if (!(finalecount & 3))
|
|
background = W_CachePatchName("BRITEGG2", PU_PATCH_LOWPRIORITY);
|
|
else
|
|
background = W_CachePatchName("DARKEGG2", PU_PATCH_LOWPRIORITY);
|
|
|
|
V_DrawSmallScaledPatch(0, 0, 0, background);
|
|
}
|
|
else if (timetonext > 1*TICRATE && timetonext < 2*TICRATE)
|
|
{
|
|
if (!(finalecount & 3))
|
|
background = W_CachePatchName("BRITEGG3", PU_PATCH_LOWPRIORITY);
|
|
else
|
|
background = W_CachePatchName("DARKEGG3", PU_PATCH_LOWPRIORITY);
|
|
|
|
V_DrawSmallScaledPatch(0, 0, 0, background);
|
|
}
|
|
else
|
|
{
|
|
tic_t sonicdelay = max(0, timetonext - 16*TICRATE);
|
|
tic_t tailsdelay = max(0, timetonext - (9*TICRATE >> 1));
|
|
tic_t knucklesdelay = max(0, timetonext - (5*TICRATE >> 1));
|
|
INT32 sonicx = (timetonext >> 2) + min(sonicdelay, TICRATE >> 1) * sonicdelay;
|
|
INT32 tailsx = 32 + min(tailsdelay, TICRATE >> 1) * tailsdelay;
|
|
INT32 knucklesx = 96 + min(knucklesdelay, TICRATE >> 1) * knucklesdelay;
|
|
INT32 tailsy = 12 + P_ReturnThrustX(NULL, finalecount * ANGLE_22h, 2);
|
|
INT32 knucklesy = 48 - (timetonext >> 3);
|
|
INT32 skyx, grassx;
|
|
|
|
if (timetonext >= 0 && timetonext < 18)
|
|
{
|
|
deplete -= 16;
|
|
}
|
|
else
|
|
{
|
|
stoptimer = finalecount;
|
|
deplete = 96;
|
|
}
|
|
skyx = 2 * stoptimer % 320;
|
|
grassx = 16 * stoptimer % 320;
|
|
sonicx += deplete;
|
|
tailsx += sonicx;
|
|
knucklesx += sonicx;
|
|
sonicx += P_ReturnThrustX(NULL, finalecount * ANG10, 3);
|
|
|
|
V_DrawSmallScaledPatch(skyx, 0, 0, (patch = W_CachePatchName("INTROSKY", PU_PATCH_LOWPRIORITY)));
|
|
V_DrawSmallScaledPatch(skyx - 320, 0, 0, patch);
|
|
W_UnlockCachedPatch(patch);
|
|
V_DrawSmallScaledPatch(grassx, 0, 0, (patch = W_CachePatchName("INTROGRS", PU_PATCH_LOWPRIORITY)));
|
|
V_DrawSmallScaledPatch(grassx - 320, 0, 0, patch);
|
|
W_UnlockCachedPatch(patch);
|
|
|
|
if (finalecount & 1)
|
|
{
|
|
// Sonic
|
|
V_DrawSmallScaledPatch(sonicx, 54, 0, (patch = W_CachePatchName("RUN2", PU_PATCH_LOWPRIORITY)));
|
|
W_UnlockCachedPatch(patch);
|
|
|
|
// Appendages
|
|
if (finalecount & 2)
|
|
{
|
|
// Sonic's feet
|
|
V_DrawSmallScaledPatch(sonicx - 8, 92, 0, (patch = W_CachePatchName("PEELOUT4", PU_PATCH_LOWPRIORITY)));
|
|
W_UnlockCachedPatch(patch);
|
|
// Tails' tails
|
|
V_DrawSmallScaledPatch(tailsx, tailsy, 0, (patch = W_CachePatchName("HELICOP2", PU_PATCH_LOWPRIORITY)));
|
|
W_UnlockCachedPatch(patch);
|
|
}
|
|
else
|
|
{
|
|
// Sonic's feet
|
|
V_DrawSmallScaledPatch(sonicx - 8, 92, 0, (patch = W_CachePatchName("PEELOUT2", PU_PATCH_LOWPRIORITY)));
|
|
W_UnlockCachedPatch(patch);
|
|
// Tails' tails
|
|
V_DrawSmallScaledPatch(tailsx, tailsy, 0, (patch = W_CachePatchName("HELICOP1", PU_PATCH_LOWPRIORITY)));
|
|
W_UnlockCachedPatch(patch);
|
|
}
|
|
|
|
// Tails
|
|
V_DrawSmallScaledPatch(tailsx, tailsy, 0, (patch = W_CachePatchName("FLY2", PU_PATCH_LOWPRIORITY)));
|
|
W_UnlockCachedPatch(patch);
|
|
|
|
// Knuckles
|
|
V_DrawSmallScaledPatch(knucklesx, knucklesy, 0, (patch = W_CachePatchName("GLIDE2", PU_PATCH_LOWPRIORITY)));
|
|
W_UnlockCachedPatch(patch);
|
|
}
|
|
else
|
|
{
|
|
// Sonic
|
|
V_DrawSmallScaledPatch(sonicx, 54, 0, (patch = W_CachePatchName("RUN1", PU_PATCH_LOWPRIORITY)));
|
|
W_UnlockCachedPatch(patch);
|
|
|
|
// Appendages
|
|
if (finalecount & 2)
|
|
{
|
|
// Sonic's feet
|
|
V_DrawSmallScaledPatch(sonicx - 8, 92, 0, (patch = W_CachePatchName("PEELOUT3", PU_PATCH_LOWPRIORITY)));
|
|
W_UnlockCachedPatch(patch);
|
|
// Tails' tails
|
|
V_DrawSmallScaledPatch(tailsx, tailsy, 0, (patch = W_CachePatchName("HELICOP2", PU_PATCH_LOWPRIORITY)));
|
|
W_UnlockCachedPatch(patch);
|
|
}
|
|
else
|
|
{
|
|
// Sonic's feet
|
|
V_DrawSmallScaledPatch(sonicx - 8, 92, 0, (patch = W_CachePatchName("PEELOUT1", PU_PATCH_LOWPRIORITY)));
|
|
W_UnlockCachedPatch(patch);
|
|
// Tails' tails
|
|
V_DrawSmallScaledPatch(tailsx, tailsy, 0, (patch = W_CachePatchName("HELICOP1", PU_PATCH_LOWPRIORITY)));
|
|
W_UnlockCachedPatch(patch);
|
|
}
|
|
|
|
// Tails
|
|
V_DrawSmallScaledPatch(tailsx, tailsy, 0, (patch = W_CachePatchName("FLY1", PU_PATCH_LOWPRIORITY)));
|
|
W_UnlockCachedPatch(patch);
|
|
|
|
// Knuckles
|
|
V_DrawSmallScaledPatch(knucklesx, knucklesy, 0, (patch = W_CachePatchName("GLIDE1", PU_PATCH_LOWPRIORITY)));
|
|
W_UnlockCachedPatch(patch);
|
|
}
|
|
|
|
// Black bars to hide the sky on widescreen
|
|
V_DrawFill(-80, 0, 80, 256, 31);
|
|
V_DrawFill(BASEVIDWIDTH, 0, 80, 256, 31);
|
|
}
|
|
}
|
|
|
|
W_UnlockCachedPatch(background);
|
|
|
|
if (intro_scenenum == 4) // The asteroid SPINS!
|
|
{
|
|
if (intro_curtime > 1)
|
|
{
|
|
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_PATCH_LOWPRIORITY);
|
|
glow = W_CachePatchName(va("ENDGLOW%.1d", 2+(worktics & 1)), PU_PATCH_LOWPRIORITY);
|
|
|
|
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));
|
|
}
|
|
}
|
|
else if (intro_scenenum == 1 && intro_curtime < 5*TICRATE)
|
|
{
|
|
INT32 trans = intro_curtime + 10 - (5*TICRATE);
|
|
if (trans < 0)
|
|
trans = 0;
|
|
V_DrawRightAlignedString(BASEVIDWIDTH-4, BASEVIDHEIGHT-12, V_ALLOWLOWERCASE|(trans<<V_ALPHASHIFT), "\x86""Press ""\x82""ENTER""\x86"" to skip...");
|
|
}
|
|
|
|
V_DrawString(cx, cy, V_ALLOWLOWERCASE, cutscene_disptext);
|
|
}
|
|
|
|
//
|
|
// F_IntroTicker
|
|
//
|
|
void F_IntroTicker(void)
|
|
{
|
|
// advance animation
|
|
finalecount++;
|
|
|
|
timetonext--;
|
|
|
|
F_WriteText();
|
|
|
|
// check for skipping
|
|
if (keypressed)
|
|
keypressed = false;
|
|
|
|
wipestyleflags = WSF_CROSSFADE;
|
|
|
|
if (timetonext <= 0)
|
|
{
|
|
if (intro_scenenum == 0)
|
|
{
|
|
if (rendermode != render_none)
|
|
{
|
|
wipestyleflags = WSF_FADEOUT;
|
|
F_WipeStartScreen();
|
|
F_TryColormapFade(31);
|
|
|
|
F_IntroDrawer();
|
|
|
|
F_WipeEndScreen();
|
|
F_RunWipe(99,true);
|
|
}
|
|
|
|
S_ChangeMusicInternal("_intro", false);
|
|
}
|
|
else if (intro_scenenum == 10)
|
|
{
|
|
if (rendermode != render_none)
|
|
{
|
|
wipestyleflags = (WSF_FADEOUT|WSF_TOWHITE);
|
|
F_WipeStartScreen();
|
|
F_TryColormapFade(0);
|
|
|
|
F_IntroDrawer();
|
|
|
|
F_WipeEndScreen();
|
|
F_RunWipe(99,true);
|
|
}
|
|
}
|
|
else if (intro_scenenum == 16)
|
|
{
|
|
if (rendermode != render_none)
|
|
{
|
|
wipestyleflags = WSF_FADEOUT;
|
|
F_WipeStartScreen();
|
|
F_TryColormapFade(31);
|
|
|
|
F_IntroDrawer();
|
|
|
|
F_WipeEndScreen();
|
|
F_RunWipe(99,true);
|
|
}
|
|
|
|
// Stay on black for a bit. =)
|
|
{
|
|
tic_t nowtime, quittime, lasttime;
|
|
nowtime = lasttime = I_GetTime();
|
|
quittime = nowtime + NEWTICRATE*2; // Shortened the quit time, used to be 2 seconds
|
|
while (quittime > nowtime)
|
|
{
|
|
while (!((nowtime = I_GetTime()) - lasttime))
|
|
I_Sleep();
|
|
lasttime = nowtime;
|
|
|
|
I_OsPolling();
|
|
I_UpdateNoBlit();
|
|
#ifdef HAVE_THREADS
|
|
I_lock_mutex(&m_menu_mutex);
|
|
#endif
|
|
M_Drawer(); // menu is drawn even on top of wipes
|
|
#ifdef HAVE_THREADS
|
|
I_unlock_mutex(m_menu_mutex);
|
|
#endif
|
|
I_FinishUpdate(); // Update the screen with the image Tails 06-19-2001
|
|
|
|
if (moviemode) // make sure we save frames for the white hold too
|
|
M_SaveFrame();
|
|
}
|
|
}
|
|
|
|
D_StartTitle();
|
|
wipegamestate = GS_INTRO;
|
|
return;
|
|
}
|
|
|
|
F_NewCutscene(introtext[++intro_scenenum]);
|
|
timetonext = introscenetime[intro_scenenum];
|
|
|
|
F_WipeStartScreen();
|
|
wipegamestate = -1;
|
|
animtimer = stoptimer = 0;
|
|
}
|
|
|
|
intro_curtime = introscenetime[intro_scenenum] - timetonext;
|
|
|
|
if (rendermode != render_none)
|
|
{
|
|
if (intro_scenenum == 0 && intro_curtime == 2*TICRATE-19)
|
|
{
|
|
S_ChangeMusicInternal("_stjr", false);
|
|
|
|
wipestyleflags = WSF_FADEIN;
|
|
F_WipeStartScreen();
|
|
F_TryColormapFade(31);
|
|
|
|
F_IntroDrawer();
|
|
|
|
F_WipeEndScreen();
|
|
F_RunWipe(99,true);
|
|
}
|
|
else if ((intro_scenenum == 5 && intro_curtime == 5*TICRATE)
|
|
|| (intro_scenenum == 7 && intro_curtime == 6*TICRATE)
|
|
//|| (intro_scenenum == 11 && intro_curtime == 7*TICRATE)
|
|
|| (intro_scenenum == 15 && intro_curtime == 7*TICRATE))
|
|
{
|
|
F_WipeStartScreen();
|
|
F_WipeColorFill(31);
|
|
|
|
F_IntroDrawer();
|
|
|
|
F_WipeEndScreen();
|
|
F_RunWipe(99,true);
|
|
}
|
|
}
|
|
|
|
if (animtimer)
|
|
animtimer--;
|
|
}
|
|
|
|
//
|
|
// F_IntroResponder
|
|
//
|
|
boolean F_IntroResponder(event_t *event)
|
|
{
|
|
INT32 key = event->key;
|
|
|
|
// 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[] = {
|
|
"\1Sonic Robo Blast 2",
|
|
"\1Credits",
|
|
"",
|
|
"\1Game Design",
|
|
"Sonic Team Junior",
|
|
"\"SSNTails\"",
|
|
"Johnny \"Sonikku\" Wallbank",
|
|
"",
|
|
"\1Programming",
|
|
"Alam \"GBC\" Arias",
|
|
"Logan \"GBA\" Arias",
|
|
"Zolton \"Zippy_Zolton\" Auburn",
|
|
"Colette \"fickleheart\" Bordelon",
|
|
"Andrew \"orospakr\" Clunis",
|
|
"Sally \"TehRealSalt\" Cochenour",
|
|
"Gregor \"Oogaland\" Dick",
|
|
"Callum Dickinson",
|
|
"Scott \"Graue\" Feeney",
|
|
"Victor \"SteelT\" Fuentes",
|
|
"Nathan \"Jazz\" Giroux",
|
|
"\"Golden\"",
|
|
"Vivian \"toaster\" Grannell",
|
|
"Julio \"Chaos Zero 64\" Guir",
|
|
"\"Hannu_Hanhi\"", // For many OpenGL performance improvements!
|
|
"Kepa \"Nev3r\" Iceta",
|
|
"Thomas \"Shadow Hog\" Igoe",
|
|
"Iestyn \"Monster Iestyn\" Jealous",
|
|
"\"Kaito Sinclaire\"",
|
|
"\"Kalaron\"", // Coded some of Sryder13's collection of OpenGL fixes, especially fog
|
|
"Ronald \"Furyhunter\" Kinard", // The SDL2 port
|
|
"\"Lat'\"", // SRB2-CHAT, the chat window from Kart
|
|
"\"LZA\"",
|
|
"Matthew \"Shuffle\" Marsalko",
|
|
"Steven \"StroggOnMeth\" McGranahan",
|
|
"\"Morph\"", // For SRB2Morphed stuff
|
|
"Louis-Antoine \"LJ Sonic\" de Moulins", // de Rochefort doesn't quite fit on the screen sorry lol
|
|
"John \"JTE\" Muniz",
|
|
"Colin \"Sonict\" Pfaff",
|
|
"James \"james\" Robert Roman",
|
|
"Sean \"Sryder13\" Ryder",
|
|
"Ehab \"Wolfy\" Saeed",
|
|
"Tasos \"tatokis\" Sahanidis", // Corrected C FixedMul, making 64-bit builds netplay compatible
|
|
"Riku \"Ors\" Salminen", // Demo consistency improvements
|
|
"Jonas \"MascaraSnake\" Sauer",
|
|
"Wessel \"sphere\" Smit",
|
|
"\"SSNTails\"",
|
|
"\"Varren\"",
|
|
"\"VelocitOni\"", // Wrote the original dashmode script
|
|
"Ikaro \"Tatsuru\" Vinhas",
|
|
"Ben \"Cue\" Woodford",
|
|
"Lachlan \"Lach\" Wright",
|
|
"Marco \"mazmazz\" Zafra",
|
|
"",
|
|
"\1Art",
|
|
"Victor \"VAdaPEGA\" Ara\x1Fjo", // Araújo -- sorry for our limited font! D:
|
|
"\"Arrietty\"",
|
|
"Ryan \"Blaze Hedgehog\" Bloom",
|
|
"Graeme P. \"SuperPhanto\" Caldwell", // for the new brak render
|
|
"\"ChrispyPixels\"",
|
|
"Paul \"Boinciel\" Clempson",
|
|
"Sally \"TehRealSalt\" Cochenour",
|
|
"\"Dave Lite\"",
|
|
"Desmond \"Blade\" DesJardins",
|
|
"Sherman \"CoatRack\" DesJardins",
|
|
"\"DirkTheHusky\"",
|
|
"Jesse \"Jeck Jims\" Emerick",
|
|
"\"Fighter_Builder\"", // for the CEZ3 button debris
|
|
"Buddy \"KinkaJoy\" Fischer",
|
|
"Vivian \"toaster\" Grannell",
|
|
"James \"SwitchKaze\" Hale",
|
|
"James \"SeventhSentinel\" Hall",
|
|
"Kepa \"Nev3r\" Iceta",
|
|
"Iestyn \"Monster Iestyn\" Jealous",
|
|
"William \"GuyWithThePie\" Kloppenberg",
|
|
"Alice \"Alacroix\" de Lemos",
|
|
"Logan \"Hyperchaotix\" McCloud",
|
|
"Alexander \"DrTapeworm\" Moench-Ford",
|
|
"Andrew \"Senku Niola\" Moran",
|
|
"\"MotorRoach\"",
|
|
"Phillip \"TelosTurntable\" Robinson",
|
|
"\"Scizor300\"",
|
|
"Wessel \"sphere\" Smit",
|
|
"David \"Instant Sonic\" Spencer Jr.",
|
|
"\"SSNTails\"",
|
|
"Daniel \"Inazuma\" Trinh",
|
|
"\"VelocitOni\"",
|
|
"Jarrett \"JEV3\" Voight",
|
|
"",
|
|
"\1Music and Sound",
|
|
"\1Production",
|
|
"Victor \"VAdaPEGA\" Ara\x1Fjo", // Araújo
|
|
"Malcolm \"RedXVI\" Brown",
|
|
"Dave \"DemonTomatoDave\" Bulmer",
|
|
"Paul \"Boinciel\" Clempson",
|
|
"\"Cyan Helkaraxe\"",
|
|
"Shane \"CobaltBW\" Ellis",
|
|
"James \"SeventhSentinel\" Hall",
|
|
"Kepa \"Nev3r\" Iceta",
|
|
"Iestyn \"Monster Iestyn\" Jealous",
|
|
"Jarel \"Arrow\" Jones",
|
|
"Alexander \"DrTapeworm\" Moench-Ford",
|
|
"Stefan \"Stuf\" Rimalia",
|
|
"Shane Mychal Sexton",
|
|
"Dave \"Big Wave Dave\" Spencer",
|
|
"David \"instantSonic\" Spencer",
|
|
"\"SSNTails\"",
|
|
"",
|
|
"\1Level Design",
|
|
"Colette \"fickleheart\" Bordelon",
|
|
"Hank \"FuriousFox\" Brannock",
|
|
"Matthew \"Fawfulfan\" Chapman",
|
|
"Paul \"Boinciel\" Clempson",
|
|
"Sally \"TehRealSalt\" Cochenour",
|
|
"Desmond \"Blade\" DesJardins",
|
|
"Sherman \"CoatRack\" DesJardins",
|
|
"Ben \"Mystic\" Geyer",
|
|
"Nathan \"Jazz\" Giroux",
|
|
"Vivian \"toaster\" Grannell",
|
|
"Dan \"Blitzzo\" Hagerstrand",
|
|
"James \"SeventhSentinel\" Hall",
|
|
"Kepa \"Nev3r\" Iceta",
|
|
"Thomas \"Shadow Hog\" Igoe",
|
|
"\"Kaito Sinclaire\"",
|
|
"Alexander \"DrTapeworm\" Moench-Ford",
|
|
"\"Revan\"",
|
|
"Anna \"QueenDelta\" Sandlin",
|
|
"Wessel \"sphere\" Smit",
|
|
"\"SSNTails\"",
|
|
"Rob Tisdell",
|
|
"\"Torgo\"",
|
|
"Jarrett \"JEV3\" Voight",
|
|
"Johnny \"Sonikku\" Wallbank",
|
|
"Marco \"mazmazz\" Zafra",
|
|
"",
|
|
"\1Boss Design",
|
|
"Ben \"Mystic\" Geyer",
|
|
"Vivian \"toaster\" Grannell",
|
|
"Thomas \"Shadow Hog\" Igoe",
|
|
"John \"JTE\" Muniz",
|
|
"Samuel \"Prime 2.0\" Peters",
|
|
"\"SSNTails\"",
|
|
"Johnny \"Sonikku\" Wallbank",
|
|
"",
|
|
"\1Testing",
|
|
"Discord Community Testers",
|
|
"Hank \"FuriousFox\" Brannock",
|
|
"Cody \"Playah\" Koester",
|
|
"Skye \"OmegaVelocity\" Meredith",
|
|
"Stephen \"HEDGESMFG\" Moellering",
|
|
"Rosalie \"ST218\" Molina",
|
|
"Samuel \"Prime 2.0\" Peters",
|
|
"Colin \"Sonict\" Pfaff",
|
|
"Bill \"Tets\" Reed",
|
|
"",
|
|
"\1Special Thanks",
|
|
"id Software",
|
|
"Doom Legacy Project",
|
|
"FreeDoom Project", // Used some of the mancubus and rocket launcher sprites for Brak
|
|
"Kart Krew",
|
|
"Alex \"MistaED\" Fuller",
|
|
"Pascal \"CodeImp\" vd Heiden", // Doom Builder developer
|
|
"Randi Heit (<!>)", // For their MSPaint <!> sprite that we nicked
|
|
"Simon \"sirjuddington\" Judd", // SLADE developer
|
|
"SRB2 Community Contributors",
|
|
"",
|
|
"\1Produced By",
|
|
"Sonic Team Junior",
|
|
"",
|
|
"\1Published By",
|
|
"A 28K dialup modem",
|
|
"",
|
|
"\1Thank you ",
|
|
"\1for playing! ",
|
|
NULL
|
|
};
|
|
|
|
#define CREDITS_LEFT 8
|
|
#define CREDITS_RIGHT ((BASEVIDWIDTH) - 8)
|
|
|
|
static struct {
|
|
UINT32 x;
|
|
const char *patch;
|
|
} credits_pics[] = {
|
|
{CREDITS_LEFT, "CREDIT01"},
|
|
{CREDITS_RIGHT - (271 >> 1), "CREDIT02"},
|
|
{CREDITS_LEFT, "CREDIT03"},
|
|
{CREDITS_RIGHT - (316 >> 1), "CREDIT04"},
|
|
{CREDITS_LEFT, "CREDIT05"},
|
|
{CREDITS_RIGHT - (399 >> 1), "CREDIT06"},
|
|
{CREDITS_LEFT, "CREDIT07"},
|
|
{CREDITS_RIGHT - (302 >> 1), "CREDIT08"},
|
|
{CREDITS_LEFT, "CREDIT09"},
|
|
{CREDITS_RIGHT - (250 >> 1), "CREDIT10"},
|
|
{CREDITS_LEFT, "CREDIT11"},
|
|
{CREDITS_RIGHT - (279 >> 1), "CREDIT12"},
|
|
//{(BASEVIDWIDTH - (279 >> 1)) >> 1, "CREDIT12"},
|
|
// CREDIT13 is extra art and is not shown by default
|
|
{0, NULL}
|
|
};
|
|
|
|
#undef CREDITS_LEFT
|
|
#undef CREDITS_RIGHT
|
|
|
|
static UINT32 credits_height = 0;
|
|
static const UINT8 credits_numpics = sizeof(credits_pics)/sizeof(credits_pics[0]) - 1;
|
|
|
|
void F_StartCredits(void)
|
|
{
|
|
G_SetGamestate(GS_CREDITS);
|
|
|
|
// Just in case they're open ... somehow
|
|
M_ClearMenus(true);
|
|
|
|
if (creditscutscene)
|
|
{
|
|
F_StartCustomCutscene(creditscutscene - 1, false, false);
|
|
return;
|
|
}
|
|
|
|
gameaction = ga_nothing;
|
|
paused = false;
|
|
CON_ToggleOff();
|
|
S_StopMusic();
|
|
S_StopSounds();
|
|
|
|
S_ChangeMusicInternal("_creds", true);
|
|
|
|
finalecount = 0;
|
|
animtimer = 0;
|
|
timetonext = 2*TICRATE;
|
|
}
|
|
|
|
void F_CreditDrawer(void)
|
|
{
|
|
UINT16 i;
|
|
INT16 zagpos = (timetonext - finalecount - animtimer) % 32;
|
|
fixed_t y = (80<<FRACBITS) - (animtimer<<FRACBITS>>1);
|
|
|
|
V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31);
|
|
|
|
// Zig Zagz
|
|
V_DrawScaledPatch(-16, zagpos, V_SNAPTOLEFT, W_CachePatchName("LTZIGZAG", PU_PATCH_LOWPRIORITY));
|
|
V_DrawScaledPatch(-16, zagpos - 320, V_SNAPTOLEFT, W_CachePatchName("LTZIGZAG", PU_PATCH_LOWPRIORITY));
|
|
V_DrawScaledPatch(BASEVIDWIDTH + 16, zagpos, V_SNAPTORIGHT|V_FLIP, W_CachePatchName("LTZIGZAG", PU_PATCH_LOWPRIORITY));
|
|
V_DrawScaledPatch(BASEVIDWIDTH + 16, zagpos - 320, V_SNAPTORIGHT|V_FLIP, W_CachePatchName("LTZIGZAG", PU_PATCH_LOWPRIORITY));
|
|
|
|
// Draw background pictures first
|
|
for (i = 0; credits_pics[i].patch; i++)
|
|
V_DrawSciencePatch(credits_pics[i].x<<FRACBITS, (280<<FRACBITS) + (((i*credits_height)<<FRACBITS)/(credits_numpics)) - 4*(animtimer<<FRACBITS)/5, 0, W_CachePatchName(credits_pics[i].patch, PU_PATCH_LOWPRIORITY), FRACUNIT>>1);
|
|
|
|
// Dim the background
|
|
V_DrawFadeScreen(0xFF00, 16);
|
|
|
|
// 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;
|
|
case 2:
|
|
if (y>>FRACBITS > -10)
|
|
V_DrawStringAtFixed((BASEVIDWIDTH-V_StringWidth(&credits[i][1], V_ALLOWLOWERCASE|V_YELLOWMAP))<<FRACBITS>>1, y, V_ALLOWLOWERCASE|V_YELLOWMAP, &credits[i][1]);
|
|
y += 12<<FRACBITS;
|
|
break;
|
|
default:
|
|
if (y>>FRACBITS > -10)
|
|
V_DrawStringAtFixed(32<<FRACBITS, y, V_ALLOWLOWERCASE, credits[i]);
|
|
y += 12<<FRACBITS;
|
|
break;
|
|
}
|
|
if (FixedMul(y,vid.dupy) > vid.height)
|
|
break;
|
|
}
|
|
}
|
|
|
|
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) - (animtimer<<FRACBITS>>1);
|
|
|
|
// Calculate credits height to display art properly
|
|
if (credits_height == 0)
|
|
{
|
|
for (i = 0; credits[i]; i++)
|
|
{
|
|
switch(credits[i][0])
|
|
{
|
|
case 0: credits_height += 80; break;
|
|
case 1: credits_height += 30; break;
|
|
default: credits_height += 12; break;
|
|
}
|
|
}
|
|
credits_height = 131*credits_height/80; // account for scroll speeds. This is a guess now, so you may need to update this if you change the credits length.
|
|
}
|
|
|
|
// 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;
|
|
}
|
|
|
|
// Do this here rather than in the drawer you doofus! (this is why dedicated mode broke at credits)
|
|
if (!credits[i] && y <= 120<<FRACBITS && !finalecount)
|
|
{
|
|
timetonext = 5*TICRATE+1;
|
|
finalecount = 5*TICRATE;
|
|
}
|
|
|
|
if (timetonext)
|
|
timetonext--;
|
|
else
|
|
animtimer++;
|
|
|
|
if (finalecount && --finalecount == 0)
|
|
F_StartGameEvaluation();
|
|
}
|
|
|
|
boolean F_CreditResponder(event_t *event)
|
|
{
|
|
INT32 key = event->key;
|
|
|
|
// 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 (!(timesBeaten) && !(netgame || multiplayer) && !cv_debug)
|
|
return false;
|
|
|
|
if (event->type != ev_keydown)
|
|
return false;
|
|
|
|
if (key != KEY_ESCAPE && key != KEY_ENTER && key != KEY_SPACE && key != KEY_BACKSPACE)
|
|
return false;
|
|
|
|
if (keypressed)
|
|
return true;
|
|
|
|
keypressed = true;
|
|
return true;
|
|
}
|
|
|
|
// ============
|
|
// EVALUATION
|
|
// ============
|
|
|
|
#define SPARKLLOOPTIME 7 // must be odd
|
|
|
|
void F_StartGameEvaluation(void)
|
|
{
|
|
// Credits option in extras menu
|
|
if (cursaveslot == -1)
|
|
{
|
|
S_FadeOutStopMusic(2*MUSICRATE);
|
|
F_StartGameEnd();
|
|
return;
|
|
}
|
|
|
|
S_FadeOutStopMusic(5*MUSICRATE);
|
|
|
|
G_SetGamestate(GS_EVALUATION);
|
|
|
|
// Just in case they're open ... somehow
|
|
M_ClearMenus(true);
|
|
|
|
goodending = (ALL7EMERALDS(emeralds));
|
|
|
|
gameaction = ga_nothing;
|
|
paused = false;
|
|
CON_ToggleOff();
|
|
|
|
finalecount = -1;
|
|
sparklloop = 0;
|
|
}
|
|
|
|
void F_GameEvaluationDrawer(void)
|
|
{
|
|
INT32 x, y, i;
|
|
angle_t fa;
|
|
INT32 eemeralds_cur;
|
|
char patchname[7] = "CEMGx0";
|
|
const char* endingtext;
|
|
|
|
if (marathonmode)
|
|
endingtext = "THANKS FOR THE RUN!";
|
|
else if (goodending)
|
|
endingtext = "CONGRATULATIONS!";
|
|
else
|
|
endingtext = "TRY AGAIN...";
|
|
|
|
V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31);
|
|
|
|
// Draw all the good crap here.
|
|
|
|
if (finalecount > 0 && useBlackRock)
|
|
{
|
|
INT32 scale = FRACUNIT;
|
|
patch_t *rockpat;
|
|
UINT8 *colormap[2] = {NULL, NULL};
|
|
patch_t *glow;
|
|
INT32 trans = 0;
|
|
|
|
x = (((BASEVIDWIDTH-82)/2)+11)<<FRACBITS;
|
|
y = (((BASEVIDHEIGHT-82)/2)+12)<<FRACBITS;
|
|
|
|
if (finalecount < 5)
|
|
{
|
|
scale = (finalecount<<(FRACBITS-2));
|
|
x += (30*(FRACUNIT-scale));
|
|
y += (30*(FRACUNIT-scale));
|
|
}
|
|
|
|
if (goodending)
|
|
{
|
|
rockpat = W_CachePatchName(va("ROID00%.2d", 34 - (finalecount % 35)), PU_PATCH_LOWPRIORITY);
|
|
glow = W_CachePatchName(va("ENDGLOW%.1d", 2+(finalecount & 1)), PU_PATCH_LOWPRIORITY);
|
|
x -= FRACUNIT;
|
|
}
|
|
else
|
|
{
|
|
rockpat = W_CachePatchName("ROID0000", PU_PATCH_LOWPRIORITY);
|
|
glow = W_CachePatchName(va("ENDGLOW%.1d", (finalecount & 1)), PU_PATCH_LOWPRIORITY);
|
|
}
|
|
|
|
if (finalecount >= 5)
|
|
trans = (finalecount-5)>>1;
|
|
if (trans < 10)
|
|
V_DrawFixedPatch(x, y, scale, trans<<V_ALPHASHIFT, glow, NULL);
|
|
|
|
trans = (15-finalecount);
|
|
if (trans < 0)
|
|
trans = -trans;
|
|
|
|
if (finalecount < 15)
|
|
colormap[0] = R_GetTranslationColormap(TC_ALLWHITE, 0, GTC_CACHE);
|
|
V_DrawFixedPatch(x, y, scale, 0, rockpat, colormap[0]);
|
|
if (trans < 10)
|
|
{
|
|
colormap[1] = R_GetTranslationColormap(TC_BLINK, SKINCOLOR_AQUA, GTC_CACHE);
|
|
V_DrawFixedPatch(x, y, scale, trans<<V_ALPHASHIFT, rockpat, colormap[1]);
|
|
}
|
|
if (goodending)
|
|
{
|
|
INT32 j = (sparklloop & 1) ? 2 : 3;
|
|
if (j > (finalecount/SPARKLLOOPTIME))
|
|
j = (finalecount/SPARKLLOOPTIME);
|
|
while (j)
|
|
{
|
|
if (j > 1 || sparklloop >= 2)
|
|
{
|
|
// if j == 0 - alternate between 0 and 1
|
|
// 1 - 1 and 2
|
|
// 2 - 2 and not rendered
|
|
V_DrawFixedPatch(x+sparkloffs[j-1][0], y+sparkloffs[j-1][1], FRACUNIT, 0, W_CachePatchName(va("ENDSPKL%.1d", (j - ((sparklloop & 1) ? 0 : 1))), PU_PATCH_LOWPRIORITY), R_GetTranslationColormap(TC_DEFAULT, SKINCOLOR_AQUA, GTC_CACHE));
|
|
}
|
|
j--;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
patch_t *eggrock = W_CachePatchName("ENDEGRK5", PU_PATCH_LOWPRIORITY);
|
|
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_PATCH_LOWPRIORITY), 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_PATCH_LOWPRIORITY), 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)
|
|
{
|
|
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, "Multiplayer games\ncan't unlock\nextras!");
|
|
else
|
|
V_DrawString(8, 96, V_YELLOWMAP, "Modified games\ncan't unlock\nextras!");
|
|
}
|
|
#endif
|
|
|
|
if (marathonmode)
|
|
{
|
|
const char *rtatext, *cuttext;
|
|
rtatext = (marathonmode & MA_INGAME) ? "In-game timer" : "RTA timer";
|
|
cuttext = (marathonmode & MA_NOCUTSCENES) ? "" : " w/ cutscenes";
|
|
if (botskin)
|
|
endingtext = va("%s & %s, %s%s", skins[players[consoleplayer].skin].realname, skins[botskin-1].realname, rtatext, cuttext);
|
|
else
|
|
endingtext = va("%s, %s%s", skins[players[consoleplayer].skin].realname, rtatext, cuttext);
|
|
V_DrawCenteredString(BASEVIDWIDTH/2, 182, V_SNAPTOBOTTOM|(ultimatemode ? V_REDMAP : V_YELLOWMAP), endingtext);
|
|
}
|
|
}
|
|
|
|
void F_GameEvaluationTicker(void)
|
|
{
|
|
if (++finalecount > 10*TICRATE)
|
|
{
|
|
F_StartGameEnd();
|
|
return;
|
|
}
|
|
|
|
if (!useBlackRock)
|
|
;
|
|
else 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("\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\Multiplayer games can't unlock extras!");
|
|
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("\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\Modified games can't unlock extras!");
|
|
S_StartSound(NULL, sfx_s3k68);
|
|
}
|
|
}
|
|
}
|
|
|
|
#undef SPARKLLOOPTIME
|
|
|
|
// ==========
|
|
// ENDING
|
|
// ==========
|
|
|
|
#define INFLECTIONPOINT (6*TICRATE)
|
|
#define STOPPINGPOINT (14*TICRATE)
|
|
#define SPARKLLOOPTIME 15 // must be odd
|
|
|
|
static void F_CacheEnding(void)
|
|
{
|
|
endbrdr[1] = W_CachePatchName("ENDBRDR1", PU_PATCH_LOWPRIORITY);
|
|
|
|
endegrk[0] = W_CachePatchName("ENDEGRK0", PU_PATCH_LOWPRIORITY);
|
|
endegrk[1] = W_CachePatchName("ENDEGRK1", PU_PATCH_LOWPRIORITY);
|
|
|
|
endglow[0] = W_CachePatchName("ENDGLOW0", PU_PATCH_LOWPRIORITY);
|
|
endglow[1] = W_CachePatchName("ENDGLOW1", PU_PATCH_LOWPRIORITY);
|
|
|
|
endbgsp[0] = W_CachePatchName("ENDBGSP0", PU_PATCH_LOWPRIORITY);
|
|
endbgsp[1] = W_CachePatchName("ENDBGSP1", PU_PATCH_LOWPRIORITY);
|
|
endbgsp[2] = W_CachePatchName("ENDBGSP2", PU_PATCH_LOWPRIORITY);
|
|
|
|
endspkl[0] = W_CachePatchName("ENDSPKL0", PU_PATCH_LOWPRIORITY);
|
|
endspkl[1] = W_CachePatchName("ENDSPKL1", PU_PATCH_LOWPRIORITY);
|
|
endspkl[2] = W_CachePatchName("ENDSPKL2", PU_PATCH_LOWPRIORITY);
|
|
|
|
endxpld[0] = W_CachePatchName("ENDXPLD0", PU_PATCH_LOWPRIORITY);
|
|
endxpld[1] = W_CachePatchName("ENDXPLD1", PU_PATCH_LOWPRIORITY);
|
|
endxpld[2] = W_CachePatchName("ENDXPLD2", PU_PATCH_LOWPRIORITY);
|
|
endxpld[3] = W_CachePatchName("ENDXPLD3", PU_PATCH_LOWPRIORITY);
|
|
|
|
endescp[0] = W_CachePatchName("ENDESCP0", PU_PATCH_LOWPRIORITY);
|
|
endescp[1] = W_CachePatchName("ENDESCP1", PU_PATCH_LOWPRIORITY);
|
|
endescp[2] = W_CachePatchName("ENDESCP2", PU_PATCH_LOWPRIORITY);
|
|
endescp[3] = W_CachePatchName("ENDESCP3", PU_PATCH_LOWPRIORITY);
|
|
endescp[4] = W_CachePatchName("ENDESCP4", PU_PATCH_LOWPRIORITY);
|
|
|
|
// 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 > (XTRA_ENDING+2))
|
|
{
|
|
sprdef = &skins[skinnum].sprites[SPR2_XTRA];
|
|
// character head, skin specific
|
|
sprframe = &sprdef->spriteframes[XTRA_ENDING];
|
|
endfwrk[0] = W_CachePatchNum(sprframe->lumppat[0], PU_PATCH_LOWPRIORITY);
|
|
sprframe = &sprdef->spriteframes[XTRA_ENDING+1];
|
|
endfwrk[1] = W_CachePatchNum(sprframe->lumppat[0], PU_PATCH_LOWPRIORITY);
|
|
sprframe = &sprdef->spriteframes[XTRA_ENDING+2];
|
|
endfwrk[2] = W_CachePatchNum(sprframe->lumppat[0], PU_PATCH_LOWPRIORITY);
|
|
}
|
|
else // Show a star if your character doesn't have an ending firework display. (Basically the MISSINGs for this)
|
|
{
|
|
endfwrk[0] = W_CachePatchName("ENDFWRK3", PU_PATCH_LOWPRIORITY);
|
|
endfwrk[1] = W_CachePatchName("ENDFWRK4", PU_PATCH_LOWPRIORITY);
|
|
endfwrk[2] = W_CachePatchName("ENDFWRK5", PU_PATCH_LOWPRIORITY);
|
|
}
|
|
|
|
endbrdr[0] = W_CachePatchName("ENDBRDR2", PU_PATCH_LOWPRIORITY);
|
|
}
|
|
else
|
|
{
|
|
// eggman, skin nonspecific
|
|
endfwrk[0] = W_CachePatchName("ENDFWRK0", PU_PATCH_LOWPRIORITY);
|
|
endfwrk[1] = W_CachePatchName("ENDFWRK1", PU_PATCH_LOWPRIORITY);
|
|
endfwrk[2] = W_CachePatchName("ENDFWRK2", PU_PATCH_LOWPRIORITY);
|
|
|
|
endbrdr[0] = W_CachePatchName("ENDBRDR0", PU_PATCH_LOWPRIORITY);
|
|
}
|
|
}
|
|
|
|
static void F_CacheGoodEnding(void)
|
|
{
|
|
endegrk[0] = W_CachePatchName("ENDEGRK2", PU_PATCH_LOWPRIORITY);
|
|
endegrk[1] = W_CachePatchName("ENDEGRK3", PU_PATCH_LOWPRIORITY);
|
|
|
|
endglow[0] = W_CachePatchName("ENDGLOW2", PU_PATCH_LOWPRIORITY);
|
|
endglow[1] = W_CachePatchName("ENDGLOW3", PU_PATCH_LOWPRIORITY);
|
|
|
|
endxpld[0] = W_CachePatchName("ENDEGRK4", PU_PATCH_LOWPRIORITY);
|
|
}
|
|
|
|
void F_StartEnding(void)
|
|
{
|
|
G_SetGamestate(GS_ENDING);
|
|
wipetypepost = INT16_MAX;
|
|
|
|
// Just in case they're open ... somehow
|
|
M_ClearMenus(true);
|
|
|
|
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;
|
|
|
|
F_CacheEnding();
|
|
}
|
|
|
|
void F_EndingTicker(void)
|
|
{
|
|
if (++finalecount > STOPPINGPOINT)
|
|
{
|
|
F_StartCredits();
|
|
wipetypepre = INT16_MAX;
|
|
return;
|
|
}
|
|
|
|
if (finalecount == -8)
|
|
S_ChangeMusicInternal((goodending ? "_endg" : "_endb"), false);
|
|
|
|
if (goodending && finalecount == INFLECTIONPOINT) // time to swap some assets
|
|
F_CacheGoodEnding();
|
|
|
|
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_PATCH_LOWPRIORITY);
|
|
else
|
|
rockpat = W_CachePatchName(va("ROID00%.2d", 34 - ((finalecount - INFLECTIONPOINT) % 35)), PU_PATCH_LOWPRIORITY);
|
|
|
|
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;
|
|
skincolornum_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_PATCH_LOWPRIORITY), 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 > STOPPINGPOINT - 20)
|
|
{
|
|
trans = 10 + (finalecount - STOPPINGPOINT)/2;
|
|
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 == STOPPINGPOINT-(20+TICRATE)) ? 1 : 0)+BASEVIDHEIGHT-16, ((timesBeaten || finalecount >= STOPPINGPOINT-TICRATE) ? V_PURPLEMAP : V_BLUEMAP)|(trans<<V_ALPHASHIFT), " [S] ===>");
|
|
}
|
|
|
|
if (finalecount > STOPPINGPOINT-(20+(2*TICRATE)))
|
|
{
|
|
INT32 trans2 = abs((5*FINECOSINE((FixedAngle((finalecount*5)<<FRACBITS)>>ANGLETOFINESHIFT & FINEMASK)))>>FRACBITS)+2;
|
|
if (!donttouch)
|
|
{
|
|
trans = 10 + (STOPPINGPOINT-(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
|
|
// ==========
|
|
void F_StartGameEnd(void)
|
|
{
|
|
G_SetGamestate(GS_GAMEEND);
|
|
|
|
gameaction = ga_nothing;
|
|
paused = false;
|
|
CON_ToggleOff();
|
|
S_StopSounds();
|
|
|
|
// In case menus are still up?!!
|
|
M_ClearMenus(true);
|
|
|
|
timetonext = TICRATE;
|
|
}
|
|
|
|
//
|
|
// F_GameEndDrawer
|
|
//
|
|
void F_GameEndDrawer(void)
|
|
{
|
|
// this function does nothing
|
|
}
|
|
|
|
//
|
|
// F_GameEndTicker
|
|
//
|
|
void F_GameEndTicker(void)
|
|
{
|
|
if (timetonext > 0)
|
|
timetonext--;
|
|
else
|
|
D_StartTitle();
|
|
}
|
|
|
|
|
|
// ==============
|
|
// TITLE SCREEN
|
|
// ==============
|
|
|
|
void F_InitMenuPresValues(void)
|
|
{
|
|
menuanimtimer = 0;
|
|
prevMenuId = 0;
|
|
activeMenuId = MainDef.menuid;
|
|
|
|
// Set defaults for presentation values
|
|
strncpy(curbgname, "TITLESKY", 9);
|
|
curfadevalue = 16;
|
|
curbgcolor = -1;
|
|
curbgxspeed = (gamestate == GS_TIMEATTACK) ? 0 : titlescrollxspeed;
|
|
curbgyspeed = (gamestate == GS_TIMEATTACK) ? 22 : titlescrollyspeed;
|
|
curbghide = (gamestate == GS_TIMEATTACK) ? false : true;
|
|
|
|
curhidepics = hidetitlepics;
|
|
curttmode = ttmode;
|
|
curttscale = ttscale;
|
|
strncpy(curttname, ttname, 9);
|
|
curttx = ttx;
|
|
curtty = tty;
|
|
curttloop = ttloop;
|
|
curtttics = tttics;
|
|
|
|
// Find current presentation values
|
|
M_SetMenuCurBackground((gamestate == GS_TIMEATTACK) ? "RECATTBG" : "TITLESKY");
|
|
M_SetMenuCurFadeValue(16);
|
|
M_SetMenuCurTitlePics();
|
|
|
|
LUA_HUD_DestroyDrawList(luahuddrawlist_title);
|
|
luahuddrawlist_title = LUA_HUD_CreateDrawList();
|
|
}
|
|
|
|
//
|
|
// F_SkyScroll
|
|
//
|
|
void F_SkyScroll(INT32 scrollxspeed, INT32 scrollyspeed, const char *patchname)
|
|
{
|
|
INT32 xscrolled, x, xneg = (scrollxspeed > 0) - (scrollxspeed < 0), tilex;
|
|
INT32 yscrolled, y, yneg = (scrollyspeed > 0) - (scrollyspeed < 0), tiley;
|
|
boolean xispos = (scrollxspeed >= 0), yispos = (scrollyspeed >= 0);
|
|
INT32 dupz = (vid.dupx < vid.dupy ? vid.dupx : vid.dupy);
|
|
INT16 patwidth, patheight;
|
|
INT32 pw, ph; // scaled by dupz
|
|
patch_t *pat;
|
|
INT32 i, j;
|
|
fixed_t fracmenuanimtimer, xscrolltimer, yscrolltimer;
|
|
|
|
if (rendermode == render_none)
|
|
return;
|
|
|
|
if (!patchname || !patchname[0])
|
|
{
|
|
V_DrawFill(0, 0, vid.width, vid.height, 31);
|
|
return;
|
|
}
|
|
|
|
if (!scrollxspeed && !scrollyspeed)
|
|
{
|
|
V_DrawPatchFill(W_CachePatchName(patchname, PU_PATCH_LOWPRIORITY));
|
|
return;
|
|
}
|
|
|
|
pat = W_CachePatchName(patchname, PU_PATCH_LOWPRIORITY);
|
|
|
|
patwidth = pat->width;
|
|
patheight = pat->height;
|
|
pw = patwidth * dupz;
|
|
ph = patheight * dupz;
|
|
|
|
tilex = max(FixedCeil(FixedDiv(vid.width, pw)) >> FRACBITS, 1)+2; // one tile on both sides of center
|
|
tiley = max(FixedCeil(FixedDiv(vid.height, ph)) >> FRACBITS, 1)+2;
|
|
|
|
fracmenuanimtimer = (menuanimtimer * FRACUNIT) - (FRACUNIT - rendertimefrac);
|
|
xscrolltimer = ((fracmenuanimtimer*scrollxspeed)/16 + patwidth*xneg*FRACUNIT) % (patwidth * FRACUNIT);
|
|
yscrolltimer = ((fracmenuanimtimer*scrollyspeed)/16 + patheight*yneg*FRACUNIT) % (patheight * FRACUNIT);
|
|
|
|
// coordinate offsets
|
|
xscrolled = FixedInt(xscrolltimer * dupz);
|
|
yscrolled = FixedInt(yscrolltimer * dupz);
|
|
|
|
for (x = (xispos) ? -pw*(tilex-1)+pw : 0, i = 0;
|
|
i < tilex;
|
|
x += pw, i++)
|
|
{
|
|
for (y = (yispos) ? -ph*(tiley-1)+ph : 0, j = 0;
|
|
j < tiley;
|
|
y += ph, j++)
|
|
{
|
|
V_DrawScaledPatch(
|
|
(xispos) ? xscrolled - x : x + xscrolled,
|
|
(yispos) ? yscrolled - y : y + yscrolled,
|
|
V_NOSCALESTART, pat);
|
|
}
|
|
}
|
|
|
|
W_UnlockCachedPatch(pat);
|
|
}
|
|
|
|
#define LOADTTGFX(arr, name, maxf) \
|
|
lumpnum = W_CheckNumForName(name); \
|
|
if (lumpnum != LUMPERROR) \
|
|
{ \
|
|
arr[0] = W_CachePatchName(name, PU_PATCH_LOWPRIORITY); \
|
|
arr[min(1, maxf-1)] = 0; \
|
|
} \
|
|
else if (strlen(name) <= 6) \
|
|
{ \
|
|
fixed_t cnt = strlen(name); \
|
|
strncpy(lumpname, name, 7); \
|
|
for (i = 0; i < maxf-1; i++) \
|
|
{ \
|
|
sprintf(&lumpname[cnt], "%.2hu", (UINT16)(i+1)); \
|
|
lumpname[8] = 0; \
|
|
lumpnum = W_CheckNumForName(lumpname); \
|
|
if (lumpnum != LUMPERROR) \
|
|
arr[i] = W_CachePatchName(lumpname, PU_PATCH_LOWPRIORITY); \
|
|
else \
|
|
break; \
|
|
} \
|
|
arr[min(i, maxf-1)] = 0; \
|
|
} \
|
|
else \
|
|
arr[0] = 0;
|
|
|
|
static void F_CacheTitleScreen(void)
|
|
{
|
|
switch(curttmode)
|
|
{
|
|
case TTMODE_OLD:
|
|
case TTMODE_NONE:
|
|
ttbanner = W_CachePatchName("TTBANNER", PU_PATCH_LOWPRIORITY);
|
|
ttwing = W_CachePatchName("TTWING", PU_PATCH_LOWPRIORITY);
|
|
ttsonic = W_CachePatchName("TTSONIC", PU_PATCH_LOWPRIORITY);
|
|
ttswave1 = W_CachePatchName("TTSWAVE1", PU_PATCH_LOWPRIORITY);
|
|
ttswave2 = W_CachePatchName("TTSWAVE2", PU_PATCH_LOWPRIORITY);
|
|
ttswip1 = W_CachePatchName("TTSWIP1", PU_PATCH_LOWPRIORITY);
|
|
ttsprep1 = W_CachePatchName("TTSPREP1", PU_PATCH_LOWPRIORITY);
|
|
ttsprep2 = W_CachePatchName("TTSPREP2", PU_PATCH_LOWPRIORITY);
|
|
ttspop1 = W_CachePatchName("TTSPOP1", PU_PATCH_LOWPRIORITY);
|
|
ttspop2 = W_CachePatchName("TTSPOP2", PU_PATCH_LOWPRIORITY);
|
|
ttspop3 = W_CachePatchName("TTSPOP3", PU_PATCH_LOWPRIORITY);
|
|
ttspop4 = W_CachePatchName("TTSPOP4", PU_PATCH_LOWPRIORITY);
|
|
ttspop5 = W_CachePatchName("TTSPOP5", PU_PATCH_LOWPRIORITY);
|
|
ttspop6 = W_CachePatchName("TTSPOP6", PU_PATCH_LOWPRIORITY);
|
|
ttspop7 = W_CachePatchName("TTSPOP7", PU_PATCH_LOWPRIORITY);
|
|
break;
|
|
|
|
// don't load alacroix gfx yet; we do that upon first draw.
|
|
case TTMODE_ALACROIX:
|
|
break;
|
|
|
|
case TTMODE_USER:
|
|
{
|
|
UINT16 i;
|
|
lumpnum_t lumpnum;
|
|
char lumpname[9];
|
|
|
|
LOADTTGFX(ttuser, curttname, TTMAX_USER)
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void F_StartTitleScreen(void)
|
|
{
|
|
if (menupres[MN_MAIN].musname[0])
|
|
S_ChangeMusic(menupres[MN_MAIN].musname, menupres[MN_MAIN].mustrack, menupres[MN_MAIN].muslooping);
|
|
else
|
|
S_ChangeMusicInternal("_title", looptitle);
|
|
|
|
if (gamestate != GS_TITLESCREEN && gamestate != GS_WAITINGPLAYERS)
|
|
{
|
|
ttuser_count =\
|
|
ttloaded[0] = ttloaded[1] = ttloaded[2] = ttloaded[3] = ttloaded[4] = ttloaded[5] =\
|
|
testttscale = activettscale =\
|
|
sonic_blink = sonic_blink_twice = sonic_idle_start = sonic_idle_end =\
|
|
tails_blink = tails_blink_twice = tails_idle_start = tails_idle_end =\
|
|
knux_blink = knux_blink_twice = knux_idle_start = knux_idle_end = 0;
|
|
|
|
sonic_blinked_already = tails_blinked_already = knux_blinked_already = 1; // don't blink on the first idle cycle
|
|
|
|
if (curttmode == TTMODE_ALACROIX)
|
|
finalecount = -3; // hack so that frames don't advance during the entry wipe
|
|
else
|
|
finalecount = 0;
|
|
wipetypepost = menupres[MN_MAIN].enterwipe;
|
|
}
|
|
else
|
|
wipegamestate = GS_TITLESCREEN;
|
|
|
|
if (titlemap)
|
|
{
|
|
mapthing_t *startpos;
|
|
|
|
gamestate_t prevwipegamestate = wipegamestate;
|
|
titlemapinaction = TITLEMAP_LOADING;
|
|
titlemapcameraref = NULL;
|
|
gamemap = titlemap;
|
|
|
|
if (!mapheaderinfo[gamemap-1])
|
|
P_AllocMapHeader(gamemap-1);
|
|
|
|
maptol = mapheaderinfo[gamemap-1]->typeoflevel;
|
|
globalweather = mapheaderinfo[gamemap-1]->weather;
|
|
|
|
G_DoLoadLevel(true);
|
|
if (!titlemap)
|
|
return;
|
|
|
|
players[displayplayer].playerstate = PST_DEAD; // Don't spawn the player in dummy (I'm still a filthy cheater)
|
|
|
|
// Set Default Position
|
|
if (playerstarts[0])
|
|
startpos = playerstarts[0];
|
|
else if (deathmatchstarts[0])
|
|
startpos = deathmatchstarts[0];
|
|
else
|
|
startpos = NULL;
|
|
|
|
if (startpos)
|
|
{
|
|
camera.x = startpos->x << FRACBITS;
|
|
camera.y = startpos->y << FRACBITS;
|
|
camera.subsector = R_PointInSubsector(camera.x, camera.y);
|
|
camera.z = camera.subsector->sector->floorheight + (startpos->z << FRACBITS);
|
|
camera.angle = (startpos->angle % 360)*ANG1;
|
|
camera.aiming = 0;
|
|
}
|
|
else
|
|
{
|
|
camera.x = camera.y = camera.z = camera.angle = camera.aiming = 0;
|
|
camera.subsector = NULL; // toast is filthy too
|
|
}
|
|
|
|
camera.chase = true;
|
|
camera.height = 0;
|
|
|
|
// Run enter linedef exec for MN_MAIN, since this is where we start
|
|
if (menupres[MN_MAIN].entertag)
|
|
P_LinedefExecute(menupres[MN_MAIN].entertag, players[displayplayer].mo, NULL);
|
|
|
|
wipegamestate = prevwipegamestate;
|
|
}
|
|
else
|
|
{
|
|
titlemapinaction = TITLEMAP_OFF;
|
|
gamemap = 1; // g_game.c
|
|
CON_ClearHUD();
|
|
}
|
|
|
|
G_SetGamestate(GS_TITLESCREEN);
|
|
|
|
// IWAD dependent stuff.
|
|
|
|
animtimer = skullAnimCounter = 0;
|
|
|
|
demoDelayLeft = demoDelayTime;
|
|
demoIdleLeft = demoIdleTime;
|
|
|
|
F_CacheTitleScreen();
|
|
}
|
|
|
|
static void F_UnloadAlacroixGraphics(SINT8 oldttscale)
|
|
{
|
|
// This all gets freed by PU_PATCH_LOWPRIORITY when exiting the menus.
|
|
// When re-visiting the menus (e.g., from exiting in-game), the gfx are force-reloaded.
|
|
// So leftover addresses here should not be a problem.
|
|
|
|
UINT16 i;
|
|
oldttscale--; // zero-based index
|
|
for (i = 0; i < TTMAX_ALACROIX; i++)
|
|
{
|
|
if(ttembl[oldttscale][i]) { Patch_Free(ttembl[oldttscale][i]); ttembl[oldttscale][i] = 0; }
|
|
if(ttribb[oldttscale][i]) { Patch_Free(ttribb[oldttscale][i]); ttribb[oldttscale][i] = 0; }
|
|
if(ttsont[oldttscale][i]) { Patch_Free(ttsont[oldttscale][i]); ttsont[oldttscale][i] = 0; }
|
|
if(ttrobo[oldttscale][i]) { Patch_Free(ttrobo[oldttscale][i]); ttrobo[oldttscale][i] = 0; }
|
|
if(tttwot[oldttscale][i]) { Patch_Free(tttwot[oldttscale][i]); tttwot[oldttscale][i] = 0; }
|
|
if(ttrbtx[oldttscale][i]) { Patch_Free(ttrbtx[oldttscale][i]); ttrbtx[oldttscale][i] = 0; }
|
|
if(ttsoib[oldttscale][i]) { Patch_Free(ttsoib[oldttscale][i]); ttsoib[oldttscale][i] = 0; }
|
|
if(ttsoif[oldttscale][i]) { Patch_Free(ttsoif[oldttscale][i]); ttsoif[oldttscale][i] = 0; }
|
|
if(ttsoba[oldttscale][i]) { Patch_Free(ttsoba[oldttscale][i]); ttsoba[oldttscale][i] = 0; }
|
|
if(ttsobk[oldttscale][i]) { Patch_Free(ttsobk[oldttscale][i]); ttsobk[oldttscale][i] = 0; }
|
|
if(ttsodh[oldttscale][i]) { Patch_Free(ttsodh[oldttscale][i]); ttsodh[oldttscale][i] = 0; }
|
|
if(tttaib[oldttscale][i]) { Patch_Free(tttaib[oldttscale][i]); tttaib[oldttscale][i] = 0; }
|
|
if(tttaif[oldttscale][i]) { Patch_Free(tttaif[oldttscale][i]); tttaif[oldttscale][i] = 0; }
|
|
if(tttaba[oldttscale][i]) { Patch_Free(tttaba[oldttscale][i]); tttaba[oldttscale][i] = 0; }
|
|
if(tttabk[oldttscale][i]) { Patch_Free(tttabk[oldttscale][i]); tttabk[oldttscale][i] = 0; }
|
|
if(tttabt[oldttscale][i]) { Patch_Free(tttabt[oldttscale][i]); tttabt[oldttscale][i] = 0; }
|
|
if(tttaft[oldttscale][i]) { Patch_Free(tttaft[oldttscale][i]); tttaft[oldttscale][i] = 0; }
|
|
if(ttknib[oldttscale][i]) { Patch_Free(ttknib[oldttscale][i]); ttknib[oldttscale][i] = 0; }
|
|
if(ttknif[oldttscale][i]) { Patch_Free(ttknif[oldttscale][i]); ttknif[oldttscale][i] = 0; }
|
|
if(ttknba[oldttscale][i]) { Patch_Free(ttknba[oldttscale][i]); ttknba[oldttscale][i] = 0; }
|
|
if(ttknbk[oldttscale][i]) { Patch_Free(ttknbk[oldttscale][i]); ttknbk[oldttscale][i] = 0; }
|
|
if(ttkndh[oldttscale][i]) { Patch_Free(ttkndh[oldttscale][i]); ttkndh[oldttscale][i] = 0; }
|
|
}
|
|
ttloaded[oldttscale] = false;
|
|
}
|
|
|
|
static void F_LoadAlacroixGraphics(SINT8 newttscale)
|
|
{
|
|
UINT16 i, j;
|
|
lumpnum_t lumpnum;
|
|
char lumpname[9];
|
|
char names[22][5] = {
|
|
"EMBL",
|
|
"RIBB",
|
|
"SONT",
|
|
"ROBO",
|
|
"TWOT",
|
|
"RBTX",
|
|
"SOIB",
|
|
"SOIF",
|
|
"SOBA",
|
|
"SOBK",
|
|
"SODH",
|
|
"TAIB",
|
|
"TAIF",
|
|
"TABA",
|
|
"TABK",
|
|
"TABT",
|
|
"TAFT",
|
|
"KNIB",
|
|
"KNIF",
|
|
"KNBA",
|
|
"KNBK",
|
|
"KNDH"
|
|
};
|
|
char lumpnames[22][7];
|
|
|
|
newttscale--; // 0-based index
|
|
|
|
if (!ttloaded[newttscale])
|
|
{
|
|
for (j = 0; j < 22; j++)
|
|
sprintf(&lumpnames[j][0], "T%.1hu%s", (UINT16)( (UINT8)newttscale+1 ), names[j]);
|
|
|
|
LOADTTGFX(ttembl[newttscale], lumpnames[0], TTMAX_ALACROIX)
|
|
LOADTTGFX(ttribb[newttscale], lumpnames[1], TTMAX_ALACROIX)
|
|
LOADTTGFX(ttsont[newttscale], lumpnames[2], TTMAX_ALACROIX)
|
|
LOADTTGFX(ttrobo[newttscale], lumpnames[3], TTMAX_ALACROIX)
|
|
LOADTTGFX(tttwot[newttscale], lumpnames[4], TTMAX_ALACROIX)
|
|
LOADTTGFX(ttrbtx[newttscale], lumpnames[5], TTMAX_ALACROIX)
|
|
LOADTTGFX(ttsoib[newttscale], lumpnames[6], TTMAX_ALACROIX)
|
|
LOADTTGFX(ttsoif[newttscale], lumpnames[7], TTMAX_ALACROIX)
|
|
LOADTTGFX(ttsoba[newttscale], lumpnames[8], TTMAX_ALACROIX)
|
|
LOADTTGFX(ttsobk[newttscale], lumpnames[9], TTMAX_ALACROIX)
|
|
LOADTTGFX(ttsodh[newttscale], lumpnames[10], TTMAX_ALACROIX)
|
|
LOADTTGFX(tttaib[newttscale], lumpnames[11], TTMAX_ALACROIX)
|
|
LOADTTGFX(tttaif[newttscale], lumpnames[12], TTMAX_ALACROIX)
|
|
LOADTTGFX(tttaba[newttscale], lumpnames[13], TTMAX_ALACROIX)
|
|
LOADTTGFX(tttabk[newttscale], lumpnames[14], TTMAX_ALACROIX)
|
|
LOADTTGFX(tttabt[newttscale], lumpnames[15], TTMAX_ALACROIX)
|
|
LOADTTGFX(tttaft[newttscale], lumpnames[16], TTMAX_ALACROIX)
|
|
LOADTTGFX(ttknib[newttscale], lumpnames[17], TTMAX_ALACROIX)
|
|
LOADTTGFX(ttknif[newttscale], lumpnames[18], TTMAX_ALACROIX)
|
|
LOADTTGFX(ttknba[newttscale], lumpnames[19], TTMAX_ALACROIX)
|
|
LOADTTGFX(ttknbk[newttscale], lumpnames[20], TTMAX_ALACROIX)
|
|
LOADTTGFX(ttkndh[newttscale], lumpnames[21], TTMAX_ALACROIX)
|
|
|
|
ttloaded[newttscale] = true;
|
|
}
|
|
}
|
|
|
|
#undef LOADTTGFX
|
|
|
|
static void F_FigureActiveTtScale(void)
|
|
{
|
|
SINT8 newttscale = max(1, min(6, vid.dupx));
|
|
SINT8 oldttscale = activettscale;
|
|
|
|
if (newttscale == testttscale)
|
|
return;
|
|
|
|
// We have a new ttscale, so load gfx
|
|
if(oldttscale > 0)
|
|
F_UnloadAlacroixGraphics(oldttscale);
|
|
|
|
testttscale = newttscale;
|
|
|
|
// If ttscale is unavailable: look for lower scales, then higher scales.
|
|
for (; newttscale >= 1; newttscale--)
|
|
{
|
|
if (ttavailable[newttscale-1])
|
|
break;
|
|
}
|
|
|
|
for (; newttscale <= 6; newttscale++)
|
|
{
|
|
if (ttavailable[newttscale-1])
|
|
break;
|
|
}
|
|
|
|
activettscale = (newttscale >= 1 && newttscale <= 6) ? newttscale : 0;
|
|
|
|
if(activettscale > 0)
|
|
F_LoadAlacroixGraphics(activettscale);
|
|
}
|
|
|
|
// (no longer) De-Demo'd Title Screen
|
|
void F_TitleScreenDrawer(void)
|
|
{
|
|
boolean hidepics;
|
|
fixed_t sc = FRACUNIT / max(1, curttscale);
|
|
INT32 whitefade = 0;
|
|
UINT8 *whitecol[2] = {NULL, NULL};
|
|
|
|
if (modeattacking)
|
|
return; // We likely came here from retrying. Don't do a damn thing.
|
|
|
|
// Draw that sky!
|
|
if (curbgcolor >= 0)
|
|
V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, curbgcolor);
|
|
else if (!curbghide || !titlemapinaction || gamestate == GS_WAITINGPLAYERS)
|
|
F_SkyScroll(curbgxspeed, curbgyspeed, curbgname);
|
|
|
|
// Don't draw outside of the title screen, or if the patch isn't there.
|
|
if (gamestate != GS_TITLESCREEN && gamestate != GS_WAITINGPLAYERS)
|
|
return;
|
|
|
|
// Don't draw if title mode is set to Old/None and the patch isn't there
|
|
if (!ttwing && (curttmode == TTMODE_OLD || curttmode == TTMODE_NONE))
|
|
return;
|
|
|
|
// rei|miru: use title pics?
|
|
hidepics = curhidepics;
|
|
if (hidepics)
|
|
goto luahook;
|
|
|
|
switch(curttmode)
|
|
{
|
|
case TTMODE_OLD:
|
|
case TTMODE_NONE:
|
|
V_DrawSciencePatch(30<<FRACBITS, 14<<FRACBITS, 0, ttwing, sc);
|
|
|
|
if (finalecount < 57)
|
|
{
|
|
if (finalecount == 35)
|
|
V_DrawSciencePatch(115<<FRACBITS, 15<<FRACBITS, 0, ttspop1, sc);
|
|
else if (finalecount == 36)
|
|
V_DrawSciencePatch(114<<FRACBITS, 15<<FRACBITS, 0,ttspop2, sc);
|
|
else if (finalecount == 37)
|
|
V_DrawSciencePatch(113<<FRACBITS, 15<<FRACBITS, 0,ttspop3, sc);
|
|
else if (finalecount == 38)
|
|
V_DrawSciencePatch(112<<FRACBITS, 15<<FRACBITS, 0,ttspop4, sc);
|
|
else if (finalecount == 39)
|
|
V_DrawSciencePatch(111<<FRACBITS, 15<<FRACBITS, 0,ttspop5, sc);
|
|
else if (finalecount == 40)
|
|
V_DrawSciencePatch(110<<FRACBITS, 15<<FRACBITS, 0, ttspop6, sc);
|
|
else if (finalecount >= 41 && finalecount <= 44)
|
|
V_DrawSciencePatch(109<<FRACBITS, 15<<FRACBITS, 0, ttspop7, sc);
|
|
else if (finalecount >= 45 && finalecount <= 48)
|
|
V_DrawSciencePatch(108<<FRACBITS, 12<<FRACBITS, 0, ttsprep1, sc);
|
|
else if (finalecount >= 49 && finalecount <= 52)
|
|
V_DrawSciencePatch(107<<FRACBITS, 9<<FRACBITS, 0, ttsprep2, sc);
|
|
else if (finalecount >= 53 && finalecount <= 56)
|
|
V_DrawSciencePatch(106<<FRACBITS, 6<<FRACBITS, 0, ttswip1, sc);
|
|
V_DrawSciencePatch(93<<FRACBITS, 106<<FRACBITS, 0, ttsonic, sc);
|
|
}
|
|
else
|
|
{
|
|
V_DrawSciencePatch(93<<FRACBITS, 106<<FRACBITS, 0,ttsonic, sc);
|
|
if (finalecount/5 & 1)
|
|
V_DrawSciencePatch(100<<FRACBITS, 3<<FRACBITS, 0,ttswave1, sc);
|
|
else
|
|
V_DrawSciencePatch(100<<FRACBITS, 3<<FRACBITS, 0,ttswave2, sc);
|
|
}
|
|
|
|
V_DrawSciencePatch(48<<FRACBITS, 142<<FRACBITS, 0,ttbanner, sc);
|
|
break;
|
|
|
|
case TTMODE_ALACROIX:
|
|
//
|
|
// PRE-INTRO: WING ON BLACK BACKGROUND
|
|
//
|
|
|
|
// Figure the gfx scale and load gfx if necessary
|
|
F_FigureActiveTtScale();
|
|
|
|
if (!activettscale) // invalid scale, draw nothing
|
|
break;
|
|
sc = FRACUNIT / activettscale;
|
|
|
|
// Start at black background. Draw it until tic 30, where we replace with a white flash.
|
|
//
|
|
// TODO: How to NOT draw the titlemap while this background is drawn?
|
|
//
|
|
if (finalecount <= 29)
|
|
V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31);
|
|
// Flash at tic 30, timed to O__TITLE percussion. Hold the flash until tic 34.
|
|
// After tic 34, fade the flash until tic 44.
|
|
else
|
|
{
|
|
if (finalecount > 29 && finalecount < 35)
|
|
V_DrawFadeScreen(0, (whitefade = 9));
|
|
else if (finalecount > 34 && 44-finalecount > 0 && 44-finalecount < 10)
|
|
V_DrawFadeScreen(0, 44-finalecount);
|
|
if (39-finalecount > 0)
|
|
{
|
|
whitefade = (9 - (39-finalecount))<<V_ALPHASHIFT;
|
|
whitecol[0] = R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_SUPERGOLD3, GTC_CACHE);
|
|
whitecol[1] = R_GetTranslationColormap(TC_ALLWHITE, 0, GTC_CACHE);
|
|
}
|
|
}
|
|
|
|
// Draw emblem
|
|
V_DrawSciencePatch(40<<FRACBITS, 20<<FRACBITS, 0, TTEMBL[0], sc);
|
|
|
|
if (whitecol[0])
|
|
{
|
|
V_DrawFixedPatch(40<<FRACBITS, 20<<FRACBITS, sc, whitefade, TTEMBL[0], whitecol[0]);
|
|
V_DrawFixedPatch(40<<FRACBITS, 20<<FRACBITS, sc, V_TRANSLUCENT + ((whitefade/2) & V_ALPHAMASK), TTEMBL[0], whitecol[1]);
|
|
}
|
|
|
|
// Animate SONIC ROBO BLAST 2 before the white flash at tic 30.
|
|
if (finalecount <= 29)
|
|
{
|
|
// Ribbon unfurls, revealing SONIC text, from tic 0 to tic 24. SONIC text is pre-baked into this ribbon graphic.
|
|
V_DrawSciencePatch(39<<FRACBITS, 88<<FRACBITS, 0, TTRIBB[min(max(0, finalecount), 24)], sc);
|
|
|
|
// Darken non-text things.
|
|
V_DrawFadeScreen(0xFF00, 12);
|
|
|
|
// Animate SONIC text while the ribbon unfurls, from tic 0 to tic 28.
|
|
if(finalecount >= 0)
|
|
V_DrawSciencePatch(89<<FRACBITS, 92<<FRACBITS, 0, TTSONT[min(finalecount, 28)], sc);
|
|
|
|
// Fade in ROBO BLAST 2 starting at tic 10.
|
|
if (finalecount > 9)
|
|
{
|
|
INT32 fadeval = 0;
|
|
|
|
// Fade between tic 10 and tic 29.
|
|
if (finalecount < 30)
|
|
{
|
|
UINT8 fadecounter = 30-finalecount;
|
|
switch(fadecounter)
|
|
{
|
|
case 20: case 19: fadeval = V_90TRANS; break;
|
|
case 18: case 17: fadeval = V_80TRANS; break;
|
|
case 16: case 15: fadeval = V_70TRANS; break;
|
|
case 14: case 13: fadeval = V_60TRANS; break;
|
|
case 12: case 11: fadeval = V_TRANSLUCENT; break;
|
|
case 10: case 9: fadeval = V_40TRANS; break;
|
|
case 8: case 7: fadeval = V_30TRANS; break;
|
|
case 6: case 5: fadeval = V_20TRANS; break;
|
|
case 4: case 3: fadeval = V_10TRANS; break;
|
|
default: break;
|
|
}
|
|
}
|
|
V_DrawSciencePatch(79<<FRACBITS, 132<<FRACBITS, fadeval, TTROBO[0], sc);
|
|
|
|
// Draw the TWO from tic 16 to tic 31, so the TWO lands right when the screen flashes white.
|
|
if(finalecount > 15)
|
|
V_DrawSciencePatch(106<<FRACBITS, 118<<FRACBITS, fadeval, TTTWOT[min(finalecount-16, 15)], sc);
|
|
}
|
|
}
|
|
|
|
//
|
|
// ALACROIX CHARACTER FRAMES
|
|
//
|
|
// Start all animation from tic 34 (or whenever the white flash begins to fade; see below.)
|
|
// Delay the start a bit for better music timing.
|
|
//
|
|
|
|
#define CHARSTART 41
|
|
#define SONICSTART (CHARSTART+0)
|
|
#define SONICIDLE (SONICSTART+57)
|
|
#define SONICX 89
|
|
#define SONICY 13
|
|
#define TAILSSTART (CHARSTART+27)
|
|
#define TAILSIDLE (TAILSSTART+60)
|
|
#define TAILSX 35
|
|
#define TAILSY 19
|
|
#define KNUXSTART (CHARSTART+44)
|
|
#define KNUXIDLE (KNUXSTART+70)
|
|
#define KNUXX 167
|
|
#define KNUXY 7
|
|
|
|
// Decide who gets to blink or not.
|
|
// Make this decision at the END of an idle/blink cycle.
|
|
// Upon first idle, both idle_start and idle_end will be 0.
|
|
|
|
if (finalecount >= KNUXIDLE)
|
|
{
|
|
if (!knux_idle_start || finalecount - knux_idle_start >= knux_idle_end)
|
|
{
|
|
if (knux_blink)
|
|
{
|
|
knux_blink = false; // don't run the cycle twice in a row
|
|
knux_blinked_already = true;
|
|
}
|
|
else if (knux_blinked_already) // or after the first non-blink cycle, either.
|
|
knux_blinked_already = false;
|
|
else
|
|
{
|
|
// make this chance higher than Sonic/Tails because Knux's idle cycle is longer
|
|
knux_blink = !(M_RandomKey(100) % 2);
|
|
knux_blink_twice = knux_blink ? !(M_RandomKey(100) % 5) : false;
|
|
}
|
|
knux_idle_start = finalecount;
|
|
}
|
|
|
|
knux_idle_end = knux_blink ? (knux_blink_twice ? 17 : 7) : 46;
|
|
}
|
|
|
|
if (finalecount >= TAILSIDLE)
|
|
{
|
|
if (!tails_idle_start || finalecount - tails_idle_start >= tails_idle_end)
|
|
{
|
|
if (tails_blink)
|
|
{
|
|
tails_blink = false; // don't run the cycle twice in a row
|
|
tails_blinked_already = true;
|
|
}
|
|
else if (tails_blinked_already) // or after the first non-blink cycle, either.
|
|
tails_blinked_already = false;
|
|
else
|
|
{
|
|
tails_blink = !(M_RandomKey(100) % 3);
|
|
tails_blink_twice = tails_blink ? !(M_RandomKey(100) % 5) : false;
|
|
}
|
|
tails_idle_start = finalecount;
|
|
}
|
|
|
|
// Tails does not actually have a non-blink idle cycle, but make up a number
|
|
// so he can still blink.
|
|
tails_idle_end = tails_blink ? (tails_blink_twice ? 17 : 7) : 30;
|
|
}
|
|
|
|
if (finalecount >= SONICIDLE)
|
|
{
|
|
if (!sonic_idle_start || finalecount - sonic_idle_start >= sonic_idle_end)
|
|
{
|
|
if (sonic_blink)
|
|
{
|
|
sonic_blink = false; // don't run the cycle twice in a row
|
|
sonic_blinked_already = true;
|
|
}
|
|
else if (sonic_blinked_already) // or after the first non-blink cycle, either.
|
|
sonic_blinked_already = false;
|
|
else
|
|
{
|
|
sonic_blink = !(M_RandomKey(100) % 3);
|
|
sonic_blink_twice = sonic_blink ? !(M_RandomKey(100) % 5) : false;
|
|
}
|
|
sonic_idle_start = finalecount;
|
|
}
|
|
|
|
sonic_idle_end = sonic_blink ? (sonic_blink_twice ? 17 : 7) : 25;
|
|
}
|
|
|
|
|
|
//
|
|
// BACK TAIL LAYER
|
|
//
|
|
|
|
if (finalecount >= TAILSSTART)
|
|
{
|
|
if (finalecount >= TAILSIDLE)
|
|
{
|
|
//
|
|
// Tails Back Tail Layer Idle
|
|
//
|
|
SINT8 taftcount = (finalecount - (TAILSIDLE)) % 41;
|
|
if (taftcount >= 0 && taftcount < 5 )
|
|
V_DrawSciencePatch(TAILSX<<FRACBITS, TAILSY<<FRACBITS, 0, TTTABT[0 ], sc);
|
|
else if (taftcount >= 5 && taftcount < 9 )
|
|
V_DrawSciencePatch(TAILSX<<FRACBITS, TAILSY<<FRACBITS, 0, TTTABT[1 ], sc);
|
|
else if (taftcount >= 9 && taftcount < 12 )
|
|
V_DrawSciencePatch(TAILSX<<FRACBITS, TAILSY<<FRACBITS, 0, TTTABT[2 ], sc);
|
|
else if (taftcount >= 12 && taftcount < 14 )
|
|
V_DrawSciencePatch(TAILSX<<FRACBITS, TAILSY<<FRACBITS, 0, TTTABT[3 ], sc);
|
|
else if (taftcount >= 14 && taftcount < 17 )
|
|
V_DrawSciencePatch(TAILSX<<FRACBITS, TAILSY<<FRACBITS, 0, TTTABT[4 ], sc);
|
|
else if (taftcount >= 17 && taftcount < 21 )
|
|
V_DrawSciencePatch(TAILSX<<FRACBITS, TAILSY<<FRACBITS, 0, TTTABT[5 ], sc);
|
|
else if (taftcount >= 21 && taftcount < 24 )
|
|
V_DrawSciencePatch(TAILSX<<FRACBITS, TAILSY<<FRACBITS, 0, TTTABT[6 ], sc);
|
|
else if (taftcount >= 24 && taftcount < 25 )
|
|
V_DrawSciencePatch(TAILSX<<FRACBITS, TAILSY<<FRACBITS, 0, TTTABT[7 ], sc);
|
|
else if (taftcount >= 25 && taftcount < 28 )
|
|
V_DrawSciencePatch(TAILSX<<FRACBITS, TAILSY<<FRACBITS, 0, TTTABT[8 ], sc);
|
|
else if (taftcount >= 28 && taftcount < 31 )
|
|
V_DrawSciencePatch(TAILSX<<FRACBITS, TAILSY<<FRACBITS, 0, TTTABT[9 ], sc);
|
|
else if (taftcount >= 31 && taftcount < 35 )
|
|
V_DrawSciencePatch(TAILSX<<FRACBITS, TAILSY<<FRACBITS, 0, TTTABT[10], sc);
|
|
else if (taftcount >= 35 && taftcount < 41 )
|
|
V_DrawSciencePatch(TAILSX<<FRACBITS, TAILSY<<FRACBITS, 0, TTTABT[11], sc);
|
|
}
|
|
}
|
|
|
|
//
|
|
// FRONT TAIL LAYER
|
|
//
|
|
|
|
if (finalecount >= TAILSSTART)
|
|
{
|
|
if (finalecount >= TAILSIDLE)
|
|
{
|
|
//
|
|
// Tails Front Tail Layer Idle
|
|
//
|
|
SINT8 tabtcount = (finalecount - (TAILSIDLE)) % 41;
|
|
if (tabtcount >= 0 && tabtcount < 6 )
|
|
V_DrawSciencePatch(TAILSX<<FRACBITS, TAILSY<<FRACBITS, 0, TTTAFT[0 ], sc);
|
|
else if (tabtcount >= 6 && tabtcount < 11 )
|
|
V_DrawSciencePatch(TAILSX<<FRACBITS, TAILSY<<FRACBITS, 0, TTTAFT[1 ], sc);
|
|
else if (tabtcount >= 11 && tabtcount < 15 )
|
|
V_DrawSciencePatch(TAILSX<<FRACBITS, TAILSY<<FRACBITS, 0, TTTAFT[2 ], sc);
|
|
else if (tabtcount >= 15 && tabtcount < 18 )
|
|
V_DrawSciencePatch(TAILSX<<FRACBITS, TAILSY<<FRACBITS, 0, TTTAFT[3 ], sc);
|
|
else if (tabtcount >= 18 && tabtcount < 19 )
|
|
V_DrawSciencePatch(TAILSX<<FRACBITS, TAILSY<<FRACBITS, 0, TTTAFT[4 ], sc);
|
|
else if (tabtcount >= 19 && tabtcount < 22 )
|
|
V_DrawSciencePatch(TAILSX<<FRACBITS, TAILSY<<FRACBITS, 0, TTTAFT[5 ], sc);
|
|
else if (tabtcount >= 22 && tabtcount < 27 )
|
|
V_DrawSciencePatch(TAILSX<<FRACBITS, TAILSY<<FRACBITS, 0, TTTAFT[6 ], sc);
|
|
else if (tabtcount >= 27 && tabtcount < 30 )
|
|
V_DrawSciencePatch(TAILSX<<FRACBITS, TAILSY<<FRACBITS, 0, TTTAFT[7 ], sc);
|
|
else if (tabtcount >= 30 && tabtcount < 31 )
|
|
V_DrawSciencePatch(TAILSX<<FRACBITS, TAILSY<<FRACBITS, 0, TTTAFT[8 ], sc);
|
|
else if (tabtcount >= 31 && tabtcount < 34 )
|
|
V_DrawSciencePatch(TAILSX<<FRACBITS, TAILSY<<FRACBITS, 0, TTTAFT[9 ], sc);
|
|
else if (tabtcount >= 34 && tabtcount < 37 )
|
|
V_DrawSciencePatch(TAILSX<<FRACBITS, TAILSY<<FRACBITS, 0, TTTAFT[10], sc);
|
|
else if (tabtcount >= 37 && tabtcount < 41 )
|
|
V_DrawSciencePatch(TAILSX<<FRACBITS, TAILSY<<FRACBITS, 0, TTTAFT[11], sc);
|
|
}
|
|
}
|
|
|
|
//
|
|
// BACK LAYER CHARACTERS
|
|
//
|
|
|
|
if (finalecount >= KNUXSTART)
|
|
{
|
|
if (finalecount < KNUXIDLE)
|
|
{
|
|
//
|
|
// Knux Back Layer Intro
|
|
//
|
|
if (finalecount >= KNUXSTART+0 && finalecount < KNUXSTART+6 )
|
|
V_DrawSciencePatch(KNUXX<<FRACBITS, KNUXY<<FRACBITS, 0, TTKNIB[0 ], sc);
|
|
else if (finalecount >= KNUXSTART+6 && finalecount < KNUXSTART+10 )
|
|
V_DrawSciencePatch(KNUXX<<FRACBITS, KNUXY<<FRACBITS, 0, TTKNIB[1 ], sc);
|
|
else if (finalecount >= KNUXSTART+10 && finalecount < KNUXSTART+13 )
|
|
V_DrawSciencePatch(KNUXX<<FRACBITS, KNUXY<<FRACBITS, 0, TTKNIB[2 ], sc);
|
|
else if (finalecount >= KNUXSTART+13 && finalecount < KNUXSTART+15 )
|
|
V_DrawSciencePatch(KNUXX<<FRACBITS, KNUXY<<FRACBITS, 0, TTKNIB[3 ], sc);
|
|
else if (finalecount >= KNUXSTART+15 && finalecount < KNUXSTART+18 )
|
|
V_DrawSciencePatch(KNUXX<<FRACBITS, KNUXY<<FRACBITS, 0, TTKNIB[4 ], sc);
|
|
else if (finalecount >= KNUXSTART+18 && finalecount < KNUXSTART+22 )
|
|
V_DrawSciencePatch(KNUXX<<FRACBITS, KNUXY<<FRACBITS, 0, TTKNIB[5 ], sc);
|
|
else if (finalecount >= KNUXSTART+22 && finalecount < KNUXSTART+28 )
|
|
V_DrawSciencePatch(KNUXX<<FRACBITS, KNUXY<<FRACBITS, 0, TTKNIB[6 ], sc);
|
|
else if (finalecount >= KNUXSTART+28 && finalecount < KNUXSTART+32 )
|
|
V_DrawSciencePatch(KNUXX<<FRACBITS, KNUXY<<FRACBITS, 0, TTKNIB[7 ], sc);
|
|
else if (finalecount >= KNUXSTART+32 && finalecount < KNUXSTART+35 )
|
|
V_DrawSciencePatch(KNUXX<<FRACBITS, KNUXY<<FRACBITS, 0, TTKNIB[8 ], sc);
|
|
else if (finalecount >= KNUXSTART+35 && finalecount < KNUXSTART+40 )
|
|
V_DrawSciencePatch(KNUXX<<FRACBITS, KNUXY<<FRACBITS, 0, TTKNIB[9 ], sc);
|
|
else if (finalecount >= KNUXSTART+40 && finalecount < KNUXSTART+41 )
|
|
V_DrawSciencePatch(KNUXX<<FRACBITS, KNUXY<<FRACBITS, 0, TTKNIB[10], sc);
|
|
else if (finalecount >= KNUXSTART+41 && finalecount < KNUXSTART+44 )
|
|
V_DrawSciencePatch(KNUXX<<FRACBITS, KNUXY<<FRACBITS, 0, TTKNIB[11], sc);
|
|
else if (finalecount >= KNUXSTART+44 && finalecount < KNUXSTART+50 )
|
|
V_DrawSciencePatch(KNUXX<<FRACBITS, KNUXY<<FRACBITS, 0, TTKNIB[12], sc);
|
|
else if (finalecount >= KNUXSTART+50 && finalecount < KNUXSTART+56 )
|
|
V_DrawSciencePatch(KNUXX<<FRACBITS, KNUXY<<FRACBITS, 0, TTKNIB[13], sc);
|
|
else if (finalecount >= KNUXSTART+56 && finalecount < KNUXSTART+57 )
|
|
V_DrawSciencePatch(KNUXX<<FRACBITS, KNUXY<<FRACBITS, 0, TTKNIB[14], sc);
|
|
else if (finalecount >= KNUXSTART+57 && finalecount < KNUXSTART+60 )
|
|
V_DrawSciencePatch(KNUXX<<FRACBITS, KNUXY<<FRACBITS, 0, TTKNIB[15], sc);
|
|
else if (finalecount >= KNUXSTART+60 && finalecount < KNUXSTART+63 )
|
|
V_DrawSciencePatch(KNUXX<<FRACBITS, KNUXY<<FRACBITS, 0, TTKNIB[16], sc);
|
|
else if (finalecount >= KNUXSTART+63 && finalecount < KNUXSTART+67 )
|
|
V_DrawSciencePatch(KNUXX<<FRACBITS, KNUXY<<FRACBITS, 0, TTKNIB[17], sc);
|
|
else if (finalecount >= KNUXSTART+67 && finalecount < KNUXSTART+70 )
|
|
V_DrawSciencePatch(KNUXX<<FRACBITS, KNUXY<<FRACBITS, 0, TTKNIB[18], sc);
|
|
// Start idle animation (frame K20-B)
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Knux Back Layer Idle
|
|
//
|
|
if (!knux_blink)
|
|
V_DrawSciencePatch(KNUXX<<FRACBITS, KNUXY<<FRACBITS, 0, TTKNBA[0], sc);
|
|
else
|
|
{
|
|
//
|
|
// Knux Blinking
|
|
//
|
|
SINT8 idlecount = finalecount - knux_idle_start;
|
|
if (idlecount >= 0 && idlecount < 2 )
|
|
V_DrawSciencePatch(KNUXX<<FRACBITS, KNUXY<<FRACBITS, 0, TTKNBK[0], sc);
|
|
else if (idlecount >= 2 && idlecount < 6 )
|
|
V_DrawSciencePatch(KNUXX<<FRACBITS, KNUXY<<FRACBITS, 0, TTKNBK[1], sc);
|
|
else if (idlecount >= 6 && idlecount < 7 )
|
|
V_DrawSciencePatch(KNUXX<<FRACBITS, KNUXY<<FRACBITS, 0, TTKNBK[2], sc);
|
|
// We reach this point if knux_blink_twice == true
|
|
else if (idlecount >= 7 && idlecount < 10)
|
|
V_DrawSciencePatch(KNUXX<<FRACBITS, KNUXY<<FRACBITS, 0, TTKNBA[0], sc);
|
|
else if (idlecount >= 10 && idlecount < 12)
|
|
V_DrawSciencePatch(KNUXX<<FRACBITS, KNUXY<<FRACBITS, 0, TTKNBK[0], sc);
|
|
else if (idlecount >= 12 && idlecount < 16)
|
|
V_DrawSciencePatch(KNUXX<<FRACBITS, KNUXY<<FRACBITS, 0, TTKNBK[1], sc);
|
|
else if (idlecount >= 16 && idlecount < 17)
|
|
V_DrawSciencePatch(KNUXX<<FRACBITS, KNUXY<<FRACBITS, 0, TTKNBK[2], sc);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (finalecount >= TAILSSTART)
|
|
{
|
|
if (finalecount < TAILSIDLE)
|
|
{
|
|
//
|
|
// Tails Back Layer Intro
|
|
//
|
|
if (finalecount >= TAILSSTART+0 && finalecount < TAILSSTART+6 )
|
|
V_DrawSciencePatch(TAILSX<<FRACBITS, TAILSY<<FRACBITS, 0, TTTAIB[0 ], sc);
|
|
else if (finalecount >= TAILSSTART+6 && finalecount < TAILSSTART+10 )
|
|
V_DrawSciencePatch(TAILSX<<FRACBITS, TAILSY<<FRACBITS, 0, TTTAIB[1 ], sc);
|
|
else if (finalecount >= TAILSSTART+10 && finalecount < TAILSSTART+12 )
|
|
V_DrawSciencePatch(TAILSX<<FRACBITS, TAILSY<<FRACBITS, 0, TTTAIB[2 ], sc);
|
|
else if (finalecount >= TAILSSTART+12 && finalecount < TAILSSTART+16 )
|
|
V_DrawSciencePatch(TAILSX<<FRACBITS, TAILSY<<FRACBITS, 0, TTTAIB[3 ], sc);
|
|
else if (finalecount >= TAILSSTART+16 && finalecount < TAILSSTART+22 )
|
|
V_DrawSciencePatch(TAILSX<<FRACBITS, TAILSY<<FRACBITS, 0, TTTAIB[4 ], sc);
|
|
else if (finalecount >= TAILSSTART+22 && finalecount < TAILSSTART+23 )
|
|
V_DrawSciencePatch(TAILSX<<FRACBITS, TAILSY<<FRACBITS, 0, TTTAIB[5 ], sc);
|
|
else if (finalecount >= TAILSSTART+23 && finalecount < TAILSSTART+26 )
|
|
V_DrawSciencePatch(TAILSX<<FRACBITS, TAILSY<<FRACBITS, 0, TTTAIB[6 ], sc);
|
|
else if (finalecount >= TAILSSTART+26 && finalecount < TAILSSTART+30 )
|
|
V_DrawSciencePatch(TAILSX<<FRACBITS, TAILSY<<FRACBITS, 0, TTTAIB[7 ], sc);
|
|
else if (finalecount >= TAILSSTART+30 && finalecount < TAILSSTART+35 )
|
|
V_DrawSciencePatch(TAILSX<<FRACBITS, TAILSY<<FRACBITS, 0, TTTAIB[8 ], sc);
|
|
else if (finalecount >= TAILSSTART+35 && finalecount < TAILSSTART+41 )
|
|
V_DrawSciencePatch(TAILSX<<FRACBITS, TAILSY<<FRACBITS, 0, TTTAIB[9 ], sc);
|
|
else if (finalecount >= TAILSSTART+41 && finalecount < TAILSSTART+43 )
|
|
V_DrawSciencePatch(TAILSX<<FRACBITS, TAILSY<<FRACBITS, 0, TTTAIB[10], sc);
|
|
else if (finalecount >= TAILSSTART+43 && finalecount < TAILSSTART+47 )
|
|
V_DrawSciencePatch(TAILSX<<FRACBITS, TAILSY<<FRACBITS, 0, TTTAIB[11], sc);
|
|
else if (finalecount >= TAILSSTART+47 && finalecount < TAILSSTART+51 )
|
|
V_DrawSciencePatch(TAILSX<<FRACBITS, TAILSY<<FRACBITS, 0, TTTAIB[12], sc);
|
|
else if (finalecount >= TAILSSTART+51 && finalecount < TAILSSTART+53 )
|
|
V_DrawSciencePatch(TAILSX<<FRACBITS, TAILSY<<FRACBITS, 0, TTTAIB[13], sc);
|
|
else if (finalecount >= TAILSSTART+53 && finalecount < TAILSSTART+56 )
|
|
V_DrawSciencePatch(TAILSX<<FRACBITS, TAILSY<<FRACBITS, 0, TTTAIB[14], sc);
|
|
else if (finalecount >= TAILSSTART+56 && finalecount < TAILSSTART+60 )
|
|
V_DrawSciencePatch(TAILSX<<FRACBITS, TAILSY<<FRACBITS, 0, TTTAIB[15], sc);
|
|
// Start idle animation (frame T17-B)
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Tails Back Layer Idle
|
|
//
|
|
if (!tails_blink)
|
|
V_DrawSciencePatch(TAILSX<<FRACBITS, TAILSY<<FRACBITS, 0, TTTABA[0], sc);
|
|
else
|
|
{
|
|
//
|
|
// Tails Blinking
|
|
//
|
|
SINT8 idlecount = finalecount - tails_idle_start;
|
|
if (idlecount >= +0 && idlecount < +2 )
|
|
V_DrawSciencePatch(TAILSX<<FRACBITS, TAILSY<<FRACBITS, 0, TTTABK[0], sc);
|
|
else if (idlecount >= +2 && idlecount < +6 )
|
|
V_DrawSciencePatch(TAILSX<<FRACBITS, TAILSY<<FRACBITS, 0, TTTABK[1], sc);
|
|
else if (idlecount >= +6 && idlecount < +7 )
|
|
V_DrawSciencePatch(TAILSX<<FRACBITS, TAILSY<<FRACBITS, 0, TTTABK[2], sc);
|
|
// We reach this point if tails_blink_twice == true
|
|
else if (idlecount >= +7 && idlecount < +10)
|
|
V_DrawSciencePatch(TAILSX<<FRACBITS, TAILSY<<FRACBITS, 0, TTTABA[0], sc);
|
|
else if (idlecount >= +10 && idlecount < +12)
|
|
V_DrawSciencePatch(TAILSX<<FRACBITS, TAILSY<<FRACBITS, 0, TTTABK[0], sc);
|
|
else if (idlecount >= +12 && idlecount < +16)
|
|
V_DrawSciencePatch(TAILSX<<FRACBITS, TAILSY<<FRACBITS, 0, TTTABK[1], sc);
|
|
else if (idlecount >= +16 && idlecount < +17)
|
|
V_DrawSciencePatch(TAILSX<<FRACBITS, TAILSY<<FRACBITS, 0, TTTABK[2], sc);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (finalecount >= SONICSTART)
|
|
{
|
|
if (finalecount < SONICIDLE)
|
|
{
|
|
//
|
|
// Sonic Back Layer Intro
|
|
//
|
|
if (finalecount >= SONICSTART+0 && finalecount < SONICSTART+6 )
|
|
V_DrawSciencePatch(SONICX<<FRACBITS, SONICY<<FRACBITS, 0, TTSOIB[0 ], sc);
|
|
else if (finalecount >= SONICSTART+6 && finalecount < SONICSTART+11 )
|
|
V_DrawSciencePatch(SONICX<<FRACBITS, SONICY<<FRACBITS, 0, TTSOIB[1 ], sc);
|
|
else if (finalecount >= SONICSTART+11 && finalecount < SONICSTART+14 )
|
|
V_DrawSciencePatch(SONICX<<FRACBITS, SONICY<<FRACBITS, 0, TTSOIB[2 ], sc);
|
|
else if (finalecount >= SONICSTART+14 && finalecount < SONICSTART+18 )
|
|
V_DrawSciencePatch(SONICX<<FRACBITS, SONICY<<FRACBITS, 0, TTSOIB[3 ], sc);
|
|
else if (finalecount >= SONICSTART+18 && finalecount < SONICSTART+19 )
|
|
V_DrawSciencePatch(SONICX<<FRACBITS, SONICY<<FRACBITS, 0, TTSOIB[4 ], sc);
|
|
else if (finalecount >= SONICSTART+19 && finalecount < SONICSTART+27 )
|
|
V_DrawSciencePatch(SONICX<<FRACBITS, SONICY<<FRACBITS, 0, TTSOIB[5 ], sc);
|
|
else if (finalecount >= SONICSTART+27 && finalecount < SONICSTART+31 )
|
|
V_DrawSciencePatch(SONICX<<FRACBITS, SONICY<<FRACBITS, 0, TTSOIB[6 ], sc);
|
|
//else if (finalecount >= SONICSTART+31 && finalecount < SONICSTART+33 )
|
|
// Frame is blank
|
|
// V_DrawSciencePatch(SONICX<<FRACBITS, SONICY<<FRACBITS, 0, TTSOIB[7 ], sc);
|
|
else if (finalecount >= SONICSTART+33 && finalecount < SONICSTART+36 )
|
|
V_DrawSciencePatch(SONICX<<FRACBITS, SONICY<<FRACBITS, 0, TTSOIB[8 ], sc);
|
|
else if (finalecount >= SONICSTART+36 && finalecount < SONICSTART+40 )
|
|
V_DrawSciencePatch(SONICX<<FRACBITS, SONICY<<FRACBITS, 0, TTSOIB[9 ], sc);
|
|
else if (finalecount >= SONICSTART+40 && finalecount < SONICSTART+44 )
|
|
V_DrawSciencePatch(SONICX<<FRACBITS, SONICY<<FRACBITS, 0, TTSOIB[10], sc);
|
|
else if (finalecount >= SONICSTART+44 && finalecount < SONICSTART+47 )
|
|
V_DrawSciencePatch(SONICX<<FRACBITS, SONICY<<FRACBITS, 0, TTSOIB[11], sc);
|
|
else if (finalecount >= SONICSTART+47 && finalecount < SONICSTART+49 )
|
|
V_DrawSciencePatch(SONICX<<FRACBITS, SONICY<<FRACBITS, 0, TTSOIB[12], sc);
|
|
else if (finalecount >= SONICSTART+49 && finalecount < SONICSTART+50 )
|
|
V_DrawSciencePatch(SONICX<<FRACBITS, SONICY<<FRACBITS, 0, TTSOIB[13], sc);
|
|
else if (finalecount >= SONICSTART+50 && finalecount < SONICSTART+53 )
|
|
V_DrawSciencePatch(SONICX<<FRACBITS, SONICY<<FRACBITS, 0, TTSOIB[14], sc);
|
|
else if (finalecount >= SONICSTART+53 && finalecount < SONICSTART+57 )
|
|
V_DrawSciencePatch(SONICX<<FRACBITS, SONICY<<FRACBITS, 0, TTSOIB[15], sc);
|
|
// Start idle animation (frame S17-B)
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Sonic Back Layer Idle
|
|
//
|
|
if (!sonic_blink)
|
|
V_DrawSciencePatch(SONICX<<FRACBITS, SONICY<<FRACBITS, 0, TTSOBA[0], sc);
|
|
else
|
|
{
|
|
//
|
|
// Sonic Blinking
|
|
//
|
|
SINT8 idlecount = finalecount - sonic_idle_start;
|
|
if (idlecount >= 0 && idlecount < 2 )
|
|
V_DrawSciencePatch(SONICX<<FRACBITS, SONICY<<FRACBITS, 0, TTSOBK[0], sc);
|
|
else if (idlecount >= 2 && idlecount < 6 )
|
|
V_DrawSciencePatch(SONICX<<FRACBITS, SONICY<<FRACBITS, 0, TTSOBK[1], sc);
|
|
else if (idlecount >= 6 && idlecount < 7 )
|
|
V_DrawSciencePatch(SONICX<<FRACBITS, SONICY<<FRACBITS, 0, TTSOBK[2], sc);
|
|
// We reach this point if sonic_blink_twice == true
|
|
else if (idlecount >= 7 && idlecount < 10)
|
|
V_DrawSciencePatch(SONICX<<FRACBITS, SONICY<<FRACBITS, 0, TTSOBA[0], sc);
|
|
else if (idlecount >= 10 && idlecount < 12)
|
|
V_DrawSciencePatch(SONICX<<FRACBITS, SONICY<<FRACBITS, 0, TTSOBK[0], sc);
|
|
else if (idlecount >= 12 && idlecount < 16)
|
|
V_DrawSciencePatch(SONICX<<FRACBITS, SONICY<<FRACBITS, 0, TTSOBK[1], sc);
|
|
else if (idlecount >= 16 && idlecount < 17)
|
|
V_DrawSciencePatch(SONICX<<FRACBITS, SONICY<<FRACBITS, 0, TTSOBK[2], sc);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// LOGO LAYER
|
|
//
|
|
|
|
// After tic 34, starting when the flash fades,
|
|
// draw the combined ribbon and SONIC ROBO BLAST 2 logo. Note the different Y value, because this
|
|
// graphic is cropped differently from the unfurling ribbon.
|
|
if (finalecount > 29)
|
|
V_DrawSciencePatch(39<<FRACBITS, 93<<FRACBITS, 0, TTRBTX[0], sc);
|
|
|
|
if (whitecol[0])
|
|
{
|
|
V_DrawFixedPatch(39<<FRACBITS, 93<<FRACBITS, sc, whitefade, TTRBTX[0], whitecol[0]);
|
|
V_DrawFixedPatch(39<<FRACBITS, 93<<FRACBITS, sc, V_TRANSLUCENT + ((whitefade/2) & V_ALPHAMASK), TTRBTX[0], whitecol[1]);
|
|
}
|
|
|
|
//
|
|
// FRONT LAYER CHARACTERS
|
|
//
|
|
|
|
if (finalecount >= KNUXSTART)
|
|
{
|
|
if (finalecount < KNUXIDLE)
|
|
{
|
|
//
|
|
// Knux Front Layer Intro
|
|
//
|
|
if (finalecount >= KNUXSTART+22 && finalecount < KNUXSTART+28 )
|
|
V_DrawSciencePatch(KNUXX<<FRACBITS, KNUXY<<FRACBITS, 0, TTKNIF[6 ], sc);
|
|
else if (finalecount >= KNUXSTART+28 && finalecount < KNUXSTART+32 )
|
|
V_DrawSciencePatch(KNUXX<<FRACBITS, KNUXY<<FRACBITS, 0, TTKNIF[7 ], sc);
|
|
else if (finalecount >= KNUXSTART+32 && finalecount < KNUXSTART+35 )
|
|
V_DrawSciencePatch(KNUXX<<FRACBITS, KNUXY<<FRACBITS, 0, TTKNIF[8 ], sc);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Knux Front Layer Idle
|
|
//
|
|
if (!knux_blink)
|
|
{
|
|
SINT8 idlecount = finalecount - knux_idle_start;
|
|
if (idlecount >= 0 && idlecount < 5 )
|
|
V_DrawSciencePatch(KNUXX<<FRACBITS, KNUXY<<FRACBITS, 0, TTKNDH[0 ], sc);
|
|
else if (idlecount >= 5 && idlecount < 10)
|
|
V_DrawSciencePatch(KNUXX<<FRACBITS, KNUXY<<FRACBITS, 0, TTKNDH[1 ], sc);
|
|
else if (idlecount >= 10 && idlecount < 13)
|
|
V_DrawSciencePatch(KNUXX<<FRACBITS, KNUXY<<FRACBITS, 0, TTKNDH[2 ], sc);
|
|
else if (idlecount >= 13 && idlecount < 14)
|
|
V_DrawSciencePatch(KNUXX<<FRACBITS, KNUXY<<FRACBITS, 0, TTKNDH[3 ], sc);
|
|
else if (idlecount >= 14 && idlecount < 17)
|
|
V_DrawSciencePatch(KNUXX<<FRACBITS, KNUXY<<FRACBITS, 0, TTKNDH[4 ], sc);
|
|
else if (idlecount >= 17 && idlecount < 21)
|
|
V_DrawSciencePatch(KNUXX<<FRACBITS, KNUXY<<FRACBITS, 0, TTKNDH[5 ], sc);
|
|
else if (idlecount >= 21 && idlecount < 27)
|
|
V_DrawSciencePatch(KNUXX<<FRACBITS, KNUXY<<FRACBITS, 0, TTKNDH[6 ], sc);
|
|
else if (idlecount >= 27 && idlecount < 32)
|
|
V_DrawSciencePatch(KNUXX<<FRACBITS, KNUXY<<FRACBITS, 0, TTKNDH[7 ], sc);
|
|
else if (idlecount >= 32 && idlecount < 34)
|
|
V_DrawSciencePatch(KNUXX<<FRACBITS, KNUXY<<FRACBITS, 0, TTKNDH[8 ], sc);
|
|
else if (idlecount >= 34 && idlecount < 37)
|
|
V_DrawSciencePatch(KNUXX<<FRACBITS, KNUXY<<FRACBITS, 0, TTKNDH[9 ], sc);
|
|
else if (idlecount >= 37 && idlecount < 39)
|
|
V_DrawSciencePatch(KNUXX<<FRACBITS, KNUXY<<FRACBITS, 0, TTKNDH[10], sc);
|
|
else if (idlecount >= 39 && idlecount < 42)
|
|
V_DrawSciencePatch(KNUXX<<FRACBITS, KNUXY<<FRACBITS, 0, TTKNDH[11], sc);
|
|
else if (idlecount >= 42 && idlecount < 46)
|
|
V_DrawSciencePatch(KNUXX<<FRACBITS, KNUXY<<FRACBITS, 0, TTKNDH[12], sc);
|
|
}
|
|
else
|
|
V_DrawSciencePatch(KNUXX<<FRACBITS, KNUXY<<FRACBITS, 0, TTKNDH[0 ], sc);
|
|
}
|
|
}
|
|
|
|
if (finalecount >= TAILSSTART)
|
|
{
|
|
if (finalecount < TAILSIDLE)
|
|
{
|
|
//
|
|
// Tails Front Layer Intro
|
|
//
|
|
if (finalecount >= TAILSSTART+26 && finalecount < TAILSSTART+30 )
|
|
V_DrawSciencePatch(TAILSX<<FRACBITS, TAILSY<<FRACBITS, 0, TTTAIF[7 ], sc);
|
|
else if (finalecount >= TAILSSTART+30 && finalecount < TAILSSTART+35 )
|
|
V_DrawSciencePatch(TAILSX<<FRACBITS, TAILSY<<FRACBITS, 0, TTTAIF[8 ], sc);
|
|
else if (finalecount >= TAILSSTART+35 && finalecount < TAILSSTART+41 )
|
|
V_DrawSciencePatch(TAILSX<<FRACBITS, TAILSY<<FRACBITS, 0, TTTAIF[9 ], sc);
|
|
else if (finalecount >= TAILSSTART+41 && finalecount < TAILSSTART+43 )
|
|
V_DrawSciencePatch(TAILSX<<FRACBITS, TAILSY<<FRACBITS, 0, TTTAIF[10], sc);
|
|
else if (finalecount >= TAILSSTART+43 && finalecount < TAILSSTART+47 )
|
|
V_DrawSciencePatch(TAILSX<<FRACBITS, TAILSY<<FRACBITS, 0, TTTAIF[11], sc);
|
|
else if (finalecount >= TAILSSTART+47 && finalecount < TAILSSTART+51 )
|
|
V_DrawSciencePatch(TAILSX<<FRACBITS, TAILSY<<FRACBITS, 0, TTTAIF[12], sc);
|
|
}
|
|
// No Tails Front Layer Idle
|
|
}
|
|
|
|
if (finalecount >= SONICSTART)
|
|
{
|
|
if (finalecount < SONICIDLE)
|
|
{
|
|
//
|
|
// Sonic Front Layer Intro
|
|
//
|
|
if (finalecount >= SONICSTART+19 && finalecount < SONICSTART+27 )
|
|
V_DrawSciencePatch(SONICX<<FRACBITS, SONICY<<FRACBITS, 0, TTSOIF[5 ], sc);
|
|
else if (finalecount >= SONICSTART+27 && finalecount < SONICSTART+31 )
|
|
V_DrawSciencePatch(SONICX<<FRACBITS, SONICY<<FRACBITS, 0, TTSOIF[6 ], sc);
|
|
else if (finalecount >= SONICSTART+31 && finalecount < SONICSTART+33 )
|
|
V_DrawSciencePatch(SONICX<<FRACBITS, SONICY<<FRACBITS, 0, TTSOIF[7 ], sc);
|
|
else if (finalecount >= SONICSTART+33 && finalecount < SONICSTART+36 )
|
|
V_DrawSciencePatch(SONICX<<FRACBITS, SONICY<<FRACBITS, 0, TTSOIF[8 ], sc);
|
|
else if (finalecount >= SONICSTART+36 && finalecount < SONICSTART+40 )
|
|
V_DrawSciencePatch(SONICX<<FRACBITS, SONICY<<FRACBITS, 0, TTSOIF[9 ], sc);
|
|
else if (finalecount >= SONICSTART+40 && finalecount < SONICSTART+44 )
|
|
V_DrawSciencePatch(SONICX<<FRACBITS, SONICY<<FRACBITS, 0, TTSOIF[10], sc);
|
|
else if (finalecount >= SONICSTART+44 && finalecount < SONICSTART+47 )
|
|
V_DrawSciencePatch(SONICX<<FRACBITS, SONICY<<FRACBITS, 0, TTSOIF[11], sc);
|
|
// ...
|
|
else if (finalecount >= SONICSTART+53 && finalecount < SONICSTART+57 )
|
|
V_DrawSciencePatch(SONICX<<FRACBITS, SONICY<<FRACBITS, 0, TTSOIF[15], sc);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Sonic Front Layer Idle
|
|
//
|
|
if (!sonic_blink)
|
|
{
|
|
SINT8 idlecount = finalecount - sonic_idle_start;
|
|
if (idlecount >= 0 && idlecount < 5 )
|
|
V_DrawSciencePatch(SONICX<<FRACBITS, SONICY<<FRACBITS, 0, TTSODH[0], sc);
|
|
else if (idlecount >= 5 && idlecount < 8 )
|
|
V_DrawSciencePatch(SONICX<<FRACBITS, SONICY<<FRACBITS, 0, TTSODH[1], sc);
|
|
else if (idlecount >= 8 && idlecount < 9 )
|
|
V_DrawSciencePatch(SONICX<<FRACBITS, SONICY<<FRACBITS, 0, TTSODH[2], sc);
|
|
else if (idlecount >= 9 && idlecount < 12)
|
|
V_DrawSciencePatch(SONICX<<FRACBITS, SONICY<<FRACBITS, 0, TTSODH[3], sc);
|
|
else if (idlecount >= 12 && idlecount < 17)
|
|
V_DrawSciencePatch(SONICX<<FRACBITS, SONICY<<FRACBITS, 0, TTSODH[4], sc);
|
|
else if (idlecount >= 17 && idlecount < 19)
|
|
V_DrawSciencePatch(SONICX<<FRACBITS, SONICY<<FRACBITS, 0, TTSODH[5], sc);
|
|
else if (idlecount >= 19 && idlecount < 21)
|
|
V_DrawSciencePatch(SONICX<<FRACBITS, SONICY<<FRACBITS, 0, TTSODH[6], sc);
|
|
else if (idlecount >= 21 && idlecount < 22)
|
|
V_DrawSciencePatch(SONICX<<FRACBITS, SONICY<<FRACBITS, 0, TTSODH[7], sc);
|
|
else if (idlecount >= 22 && idlecount < 25)
|
|
V_DrawSciencePatch(SONICX<<FRACBITS, SONICY<<FRACBITS, 0, TTSODH[8], sc);
|
|
}
|
|
else
|
|
V_DrawSciencePatch(SONICX<<FRACBITS, SONICY<<FRACBITS, 0, TTSODH[0], sc);
|
|
}
|
|
}
|
|
|
|
#undef CHARSTART
|
|
#undef SONICSTART
|
|
#undef SONICIDLE
|
|
#undef SONICX
|
|
#undef SONICY
|
|
#undef TAILSSTART
|
|
#undef TAILSIDLE
|
|
#undef TAILSX
|
|
#undef TAILSY
|
|
#undef KNUXSTART
|
|
#undef KNUXIDLE
|
|
#undef KNUXX
|
|
#undef KNUXY
|
|
|
|
break;
|
|
|
|
case TTMODE_USER:
|
|
if (!ttuser[max(0, ttuser_count)])
|
|
{
|
|
if(curttloop > -1 && ttuser[curttloop])
|
|
ttuser_count = curttloop;
|
|
else if (ttuser[max(0, ttuser_count-1)])
|
|
ttuser_count = max(0, ttuser_count-1);
|
|
else
|
|
break; // draw nothing
|
|
}
|
|
|
|
V_DrawSciencePatch(curttx<<FRACBITS, curtty<<FRACBITS, 0, ttuser[ttuser_count], sc);
|
|
|
|
if (!(finalecount % max(1, curtttics)))
|
|
ttuser_count++;
|
|
break;
|
|
}
|
|
|
|
luahook:
|
|
if (renderisnewtic)
|
|
{
|
|
LUA_HUD_ClearDrawList(luahuddrawlist_title);
|
|
LUA_HUDHOOK(title, luahuddrawlist_title);
|
|
}
|
|
LUA_HUD_DrawList(luahuddrawlist_title);
|
|
}
|
|
|
|
// separate animation timer for backgrounds, since we also count
|
|
// during GS_TIMEATTACK
|
|
void F_MenuPresTicker(boolean run)
|
|
{
|
|
if (run)
|
|
menuanimtimer++;
|
|
}
|
|
|
|
// (no longer) De-Demo'd Title Screen
|
|
void F_TitleScreenTicker(boolean run)
|
|
{
|
|
if (run)
|
|
finalecount++;
|
|
|
|
// don't trigger if doing anything besides idling on title
|
|
if (gameaction != ga_nothing || gamestate != GS_TITLESCREEN)
|
|
return;
|
|
|
|
// Execute the titlemap camera settings
|
|
if (titlemapinaction)
|
|
{
|
|
thinker_t *th;
|
|
mobj_t *mo2;
|
|
mobj_t *cameraref = NULL;
|
|
|
|
// If there's a Line 422 Switch Cut-Away view, don't force us.
|
|
if (!titlemapcameraref || titlemapcameraref->type != MT_ALTVIEWMAN)
|
|
{
|
|
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
|
|
{
|
|
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
|
|
continue;
|
|
|
|
mo2 = (mobj_t *)th;
|
|
|
|
if (!mo2)
|
|
continue;
|
|
|
|
if (mo2->type != MT_ALTVIEWMAN)
|
|
continue;
|
|
|
|
cameraref = titlemapcameraref = mo2;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
cameraref = titlemapcameraref;
|
|
|
|
if (cameraref)
|
|
{
|
|
camera.x = cameraref->x;
|
|
camera.y = cameraref->y;
|
|
camera.z = cameraref->z;
|
|
camera.angle = cameraref->angle;
|
|
camera.aiming = cameraref->cusval;
|
|
camera.subsector = cameraref->subsector;
|
|
}
|
|
else
|
|
{
|
|
// Default behavior: Do a lil' camera spin if a title map is loaded;
|
|
camera.angle += titlescrollxspeed*ANG1/64;
|
|
}
|
|
}
|
|
|
|
// no demos to play? or, are they disabled?
|
|
if (!cv_rollingdemos.value || !numDemos)
|
|
return;
|
|
|
|
// Wait for a while (for the music to finish, preferably)
|
|
// before starting demos
|
|
if (demoDelayLeft)
|
|
{
|
|
--demoDelayLeft;
|
|
return;
|
|
}
|
|
|
|
// Hold up for a bit if menu or console active
|
|
if (menuactive || CON_Ready())
|
|
{
|
|
demoIdleLeft = demoIdleTime;
|
|
return;
|
|
}
|
|
|
|
// is it time?
|
|
if (!(--demoIdleLeft))
|
|
{
|
|
char dname[9];
|
|
lumpnum_t l;
|
|
|
|
// prevent console spam if failed
|
|
demoIdleLeft = demoIdleTime;
|
|
|
|
// Replay intro when done cycling through demos
|
|
if (curDemo == numDemos)
|
|
{
|
|
curDemo = 0;
|
|
F_StartIntro();
|
|
return;
|
|
}
|
|
|
|
// Setup demo name
|
|
snprintf(dname, 9, "DEMO_%03u", ++curDemo);
|
|
|
|
if ((l = W_CheckNumForName(dname)) == LUMPERROR)
|
|
{
|
|
CONS_Alert(CONS_ERROR, M_GetText("Demo lump \"%s\" doesn't exist\n"), dname);
|
|
F_StartIntro();
|
|
return;
|
|
}
|
|
|
|
titledemo = true;
|
|
G_DoPlayDemo(dname);
|
|
}
|
|
}
|
|
|
|
void F_TitleDemoTicker(void)
|
|
{
|
|
keypressed = false;
|
|
}
|
|
|
|
// ==========
|
|
// CONTINUE
|
|
// ==========
|
|
|
|
static skin_t *contskins[2];
|
|
static UINT8 cont_spr2[2][6];
|
|
static UINT8 *contcolormaps[2];
|
|
|
|
void F_StartContinue(void)
|
|
{
|
|
I_Assert(!netgame && !multiplayer);
|
|
|
|
if (continuesInSession && players[consoleplayer].continues <= 0)
|
|
{
|
|
Command_ExitGame_f();
|
|
return;
|
|
}
|
|
|
|
wipestyleflags = WSF_FADEOUT;
|
|
G_SetGamestate(GS_CONTINUING);
|
|
gameaction = ga_nothing;
|
|
|
|
keypressed = false;
|
|
paused = false;
|
|
CON_ToggleOff();
|
|
|
|
// In case menus are still up?!!
|
|
M_ClearMenus(true);
|
|
|
|
S_ChangeMusicInternal("_conti", false);
|
|
S_StopSounds();
|
|
|
|
contskins[0] = &skins[players[consoleplayer].skin];
|
|
cont_spr2[0][0] = P_GetSkinSprite2(contskins[0], SPR2_CNT1, NULL);
|
|
cont_spr2[0][2] = contskins[0]->contangle & 7;
|
|
contcolormaps[0] = R_GetTranslationColormap(players[consoleplayer].skin, players[consoleplayer].skincolor, GTC_CACHE);
|
|
cont_spr2[0][4] = contskins[0]->sprites[cont_spr2[0][0]].numframes;
|
|
cont_spr2[0][5] = max(1, contskins[0]->contspeed);
|
|
|
|
if (botskin)
|
|
{
|
|
INT32 secondplaya;
|
|
|
|
if (secondarydisplayplayer != consoleplayer)
|
|
secondplaya = secondarydisplayplayer;
|
|
else // HACK
|
|
secondplaya = 1;
|
|
|
|
contskins[1] = &skins[players[secondplaya].skin];
|
|
cont_spr2[1][0] = P_GetSkinSprite2(contskins[1], SPR2_CNT4, NULL);
|
|
cont_spr2[1][2] = (contskins[1]->contangle >> 3) & 7;
|
|
contcolormaps[1] = R_GetTranslationColormap(players[secondplaya].skin, players[secondplaya].skincolor, GTC_CACHE);
|
|
cont_spr2[1][4] = contskins[1]->sprites[cont_spr2[1][0]].numframes;
|
|
if (cont_spr2[1][0] == SPR2_CNT4)
|
|
cont_spr2[1][5] = 4; // sorry, this one is hardcoded
|
|
else
|
|
cont_spr2[1][5] = max(1, contskins[1]->contspeed);
|
|
}
|
|
else
|
|
{
|
|
contskins[1] = NULL;
|
|
contcolormaps[1] = NULL;
|
|
cont_spr2[1][0] = cont_spr2[1][2] = cont_spr2[1][4] = cont_spr2[1][5] = 0;
|
|
}
|
|
|
|
cont_spr2[0][1] = cont_spr2[0][3] =\
|
|
cont_spr2[1][1] = cont_spr2[1][3] = 0;
|
|
|
|
timetonext = (11*TICRATE)+11;
|
|
continuetime = 0;
|
|
}
|
|
|
|
//
|
|
// F_ContinueDrawer
|
|
// Moved continuing out of the HUD (hack removal!!)
|
|
//
|
|
void F_ContinueDrawer(void)
|
|
{
|
|
spritedef_t *sprdef;
|
|
spriteframe_t *sprframe;
|
|
patch_t *patch;
|
|
INT32 i, x = (BASEVIDWIDTH>>1), ncontinues = players[consoleplayer].continues;
|
|
char numbuf[9] = "CONTNUM*";
|
|
tic_t timeleft = (timetonext/TICRATE);
|
|
INT32 offsx = 0, offsy = 0, lift[2] = {0, 0};
|
|
|
|
if (continuetime >= 3*TICRATE)
|
|
{
|
|
V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 0);
|
|
return;
|
|
}
|
|
|
|
V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31);
|
|
|
|
if (timetonext >= (11*TICRATE)+10)
|
|
return;
|
|
|
|
V_DrawLevelTitle(x - (V_LevelNameWidth("Continue?")>>1), 16, 0, "Continue?");
|
|
|
|
// Two stars...
|
|
patch = W_CachePatchName("CONTSTAR", PU_PATCH_LOWPRIORITY);
|
|
V_DrawScaledPatch(x-32, 160, 0, patch);
|
|
V_DrawScaledPatch(x+32, 160, 0, patch);
|
|
|
|
// Time left!
|
|
if (timeleft > 9)
|
|
{
|
|
numbuf[7] = '1';
|
|
V_DrawScaledPatch(x - 10, 160, 0, W_CachePatchName(numbuf, PU_PATCH_LOWPRIORITY));
|
|
numbuf[7] = '0';
|
|
V_DrawScaledPatch(x + 10, 160, 0, W_CachePatchName(numbuf, PU_PATCH_LOWPRIORITY));
|
|
}
|
|
else
|
|
{
|
|
numbuf[7] = '0'+timeleft;
|
|
V_DrawScaledPatch(x, 160, 0, W_CachePatchName(numbuf, PU_PATCH_LOWPRIORITY));
|
|
}
|
|
|
|
// Draw the continue markers! Show continues.
|
|
if (!continuesInSession)
|
|
;
|
|
else if (ncontinues > 10)
|
|
{
|
|
if (!(continuetime & 1) || continuetime > 17)
|
|
V_DrawContinueIcon(x, 68, 0, players[consoleplayer].skin, players[consoleplayer].skincolor);
|
|
V_DrawScaledPatch(x+12, 66, 0, stlivex);
|
|
V_DrawRightAlignedString(x+38, 64, 0,
|
|
va("%d",(imcontinuing ? ncontinues-1 : ncontinues)));
|
|
}
|
|
else
|
|
{
|
|
x += (ncontinues/2) * 30;
|
|
if (!(ncontinues & 1))
|
|
x -= 15;
|
|
for (i = 0; i < ncontinues; ++i)
|
|
{
|
|
if (i == (ncontinues/2) && ((continuetime & 1) || continuetime > 17))
|
|
continue;
|
|
V_DrawContinueIcon(x - (i*30), 68, 0, players[consoleplayer].skin, players[consoleplayer].skincolor);
|
|
}
|
|
x = BASEVIDWIDTH>>1;
|
|
}
|
|
|
|
// Spotlight
|
|
V_DrawScaledPatch(x, 140, 0, W_CachePatchName("CONTSPOT", PU_PATCH_LOWPRIORITY));
|
|
|
|
// warping laser
|
|
if (continuetime)
|
|
{
|
|
INT32 w = min(continuetime, 28), brightness = (continuetime>>1) & 7;
|
|
if (brightness > 3)
|
|
brightness = 8-brightness;
|
|
V_DrawFadeFill(x-w, 0, w<<1, 140, 0, 0, (3+brightness));
|
|
}
|
|
|
|
if (contskins[1])
|
|
{
|
|
if (continuetime > 15)
|
|
{
|
|
angle_t work = FixedAngle((10*(continuetime-15))<<FRACBITS)>>ANGLETOFINESHIFT;
|
|
offsy = FINESINE(work)<<1;
|
|
offsx = (27*FINECOSINE(work))>>1;
|
|
}
|
|
else
|
|
offsx = 27<<(FRACBITS-1);
|
|
lift[1] = continuetime-10;
|
|
if (lift[1] < 0)
|
|
lift[1] = 0;
|
|
else if (lift[1] > TICRATE+5)
|
|
lift[1] = TICRATE+5;
|
|
}
|
|
|
|
lift[0] = continuetime-5;
|
|
if (lift[0] < 0)
|
|
lift[0] = 0;
|
|
else if (lift[0] > TICRATE+5)
|
|
lift[0] = TICRATE+5;
|
|
|
|
#define drawchar(dx, dy, n) {\
|
|
sprdef = &contskins[n]->sprites[cont_spr2[n][0]];\
|
|
sprframe = &sprdef->spriteframes[cont_spr2[n][1]];\
|
|
patch = W_CachePatchNum(sprframe->lumppat[cont_spr2[n][2]], PU_PATCH_LOWPRIORITY);\
|
|
V_DrawFixedPatch((dx), (dy), contskins[n]->highresscale, (sprframe->flip & (1<<cont_spr2[n][2])) ? V_FLIP : 0, patch, contcolormaps[n]);\
|
|
}
|
|
|
|
if (offsy < 0)
|
|
drawchar((BASEVIDWIDTH<<(FRACBITS-1))-offsx, ((140-lift[0])<<FRACBITS)-offsy, 0);
|
|
if (contskins[1])
|
|
drawchar((BASEVIDWIDTH<<(FRACBITS-1))+offsx, ((140-lift[1])<<FRACBITS)+offsy, 1);
|
|
if (offsy >= 0)
|
|
drawchar((BASEVIDWIDTH<<(FRACBITS-1))-offsx, ((140-lift[0])<<FRACBITS)-offsy, 0);
|
|
|
|
#undef drawchar
|
|
|
|
if (timetonext > (11*TICRATE))
|
|
V_DrawFadeScreen(31, timetonext-(11*TICRATE));
|
|
if (continuetime > ((3*TICRATE) - 10))
|
|
V_DrawFadeScreen(0, (continuetime - ((3*TICRATE) - 10)));
|
|
}
|
|
|
|
void F_ContinueTicker(void)
|
|
{
|
|
if (!imcontinuing)
|
|
{
|
|
if (timetonext > 0)
|
|
{
|
|
if (!(--timetonext))
|
|
{
|
|
Command_ExitGame_f();
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (++continuetime == 3*TICRATE)
|
|
{
|
|
G_Continue();
|
|
return;
|
|
}
|
|
|
|
if (continuetime > 5 && ((continuetime & 1) || continuetime > TICRATE) && (++cont_spr2[0][2]) >= 8)
|
|
cont_spr2[0][2] = 0;
|
|
|
|
if (continuetime > 10 && (!(continuetime & 1) || continuetime > TICRATE+5) && (++cont_spr2[1][2]) >= 8)
|
|
cont_spr2[1][2] = 0;
|
|
|
|
if (continuetime == (3*TICRATE)-10)
|
|
S_StartSound(NULL, sfx_cdfm56); // or 31
|
|
else if (continuetime == 5)
|
|
{
|
|
cont_spr2[0][0] = P_GetSkinSprite2(contskins[0], SPR2_CNT2, NULL);
|
|
cont_spr2[0][4] = contskins[0]->sprites[cont_spr2[0][0]].numframes;
|
|
cont_spr2[0][1] = cont_spr2[0][3] = 0;
|
|
cont_spr2[0][5] = 2;
|
|
}
|
|
else if (continuetime == TICRATE)
|
|
{
|
|
cont_spr2[0][0] = P_GetSkinSprite2(contskins[0], SPR2_CNT3, NULL);
|
|
cont_spr2[0][4] = contskins[0]->sprites[cont_spr2[0][0]].numframes;
|
|
cont_spr2[0][1] = cont_spr2[0][3] = 0;
|
|
}
|
|
else if (contskins[1])
|
|
{
|
|
if (continuetime == 10)
|
|
{
|
|
cont_spr2[1][0] = P_GetSkinSprite2(contskins[1], SPR2_CNT2, NULL);
|
|
cont_spr2[1][4] = contskins[1]->sprites[cont_spr2[1][0]].numframes;
|
|
cont_spr2[1][1] = cont_spr2[1][3] = 0;
|
|
cont_spr2[1][5] = 2;
|
|
}
|
|
else if (continuetime == TICRATE+5)
|
|
{
|
|
cont_spr2[1][0] = P_GetSkinSprite2(contskins[1], SPR2_CNT3, NULL);
|
|
cont_spr2[1][4] = contskins[1]->sprites[cont_spr2[1][0]].numframes;
|
|
cont_spr2[1][1] = cont_spr2[1][3] = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((++cont_spr2[0][3]) >= cont_spr2[0][5])
|
|
{
|
|
cont_spr2[0][3] = 0;
|
|
if (++cont_spr2[0][1] >= cont_spr2[0][4])
|
|
cont_spr2[0][1] = 0;
|
|
}
|
|
|
|
if (contskins[1] && (++cont_spr2[1][3]) >= cont_spr2[1][5])
|
|
{
|
|
cont_spr2[1][3] = 0;
|
|
if (++cont_spr2[1][1] >= cont_spr2[1][4])
|
|
cont_spr2[1][1] = 0;
|
|
}
|
|
}
|
|
|
|
boolean F_ContinueResponder(event_t *event)
|
|
{
|
|
INT32 key = event->key;
|
|
|
|
if (keypressed)
|
|
return true;
|
|
|
|
if (timetonext >= 21*TICRATE/2)
|
|
return false;
|
|
if (event->type != ev_keydown)
|
|
return false;
|
|
|
|
// remap virtual keys (mouse & joystick buttons)
|
|
switch (key)
|
|
{
|
|
case KEY_ENTER:
|
|
case KEY_SPACE:
|
|
case KEY_MOUSE1:
|
|
case KEY_JOY1:
|
|
case KEY_JOY1 + 2:
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
|
|
keypressed = true;
|
|
imcontinuing = true;
|
|
S_StartSound(NULL, sfx_kc6b);
|
|
I_FadeSong(0, MUSICRATE, &S_StopMusic);
|
|
|
|
return true;
|
|
}
|
|
|
|
// ==================
|
|
// CUSTOM CUTSCENES
|
|
// ==================
|
|
static INT32 scenenum, cutnum;
|
|
static INT32 picxpos, picypos, picnum, pictime, picmode, numpics, pictoloop;
|
|
static INT32 textxpos, textypos;
|
|
static boolean cutsceneover = false;
|
|
static boolean runningprecutscene = false, precutresetplayer = false;
|
|
|
|
static void F_AdvanceToNextScene(void)
|
|
{
|
|
if (rendermode != render_none)
|
|
{
|
|
F_WipeStartScreen();
|
|
|
|
// Fade to any palette color you want.
|
|
if (cutscenes[cutnum]->scene[scenenum].fadecolor)
|
|
{
|
|
V_DrawFill(0,0,BASEVIDWIDTH,BASEVIDHEIGHT,cutscenes[cutnum]->scene[scenenum].fadecolor);
|
|
|
|
F_WipeEndScreen();
|
|
F_RunWipe(cutscenes[cutnum]->scene[scenenum].fadeinid, true);
|
|
|
|
F_WipeStartScreen();
|
|
}
|
|
}
|
|
|
|
// Don't increment until after endcutscene check
|
|
// (possible overflow / bad patch names from the one tic drawn before the fade)
|
|
if (scenenum+1 >= cutscenes[cutnum]->numscenes)
|
|
{
|
|
F_EndCutScene();
|
|
return;
|
|
}
|
|
|
|
++scenenum;
|
|
|
|
timetonext = 0;
|
|
stoptimer = 0;
|
|
picnum = 0;
|
|
picxpos = cutscenes[cutnum]->scene[scenenum].xcoord[picnum];
|
|
picypos = cutscenes[cutnum]->scene[scenenum].ycoord[picnum];
|
|
|
|
if (cutscenes[cutnum]->scene[scenenum].musswitch[0])
|
|
S_ChangeMusicEx(cutscenes[cutnum]->scene[scenenum].musswitch,
|
|
cutscenes[cutnum]->scene[scenenum].musswitchflags,
|
|
cutscenes[cutnum]->scene[scenenum].musicloop,
|
|
cutscenes[cutnum]->scene[scenenum].musswitchposition, 0, 0);
|
|
|
|
// Fade to the next
|
|
F_NewCutscene(cutscenes[cutnum]->scene[scenenum].text);
|
|
|
|
picnum = 0;
|
|
picxpos = cutscenes[cutnum]->scene[scenenum].xcoord[picnum];
|
|
picypos = cutscenes[cutnum]->scene[scenenum].ycoord[picnum];
|
|
textxpos = cutscenes[cutnum]->scene[scenenum].textxpos;
|
|
textypos = cutscenes[cutnum]->scene[scenenum].textypos;
|
|
|
|
animtimer = pictime = cutscenes[cutnum]->scene[scenenum].picduration[picnum];
|
|
|
|
if (rendermode != render_none)
|
|
{
|
|
F_CutsceneDrawer();
|
|
|
|
F_WipeEndScreen();
|
|
F_RunWipe(cutscenes[cutnum]->scene[scenenum].fadeoutid, true);
|
|
}
|
|
}
|
|
|
|
// See also G_AfterIntermission, the only other place which handles intra-map/ending transitions
|
|
void F_EndCutScene(void)
|
|
{
|
|
cutsceneover = true; // do this first, just in case G_EndGame or something wants to turn it back false later
|
|
if (runningprecutscene)
|
|
{
|
|
if (server)
|
|
D_MapChange(gamemap, gametype, ultimatemode, precutresetplayer, 0, true, false);
|
|
}
|
|
else
|
|
{
|
|
if (cutnum == creditscutscene-1)
|
|
F_StartGameEvaluation();
|
|
else if (cutnum == introtoplay-1)
|
|
D_StartTitle();
|
|
else if (nextmap < 1100-1)
|
|
G_NextLevel();
|
|
else
|
|
G_EndGame();
|
|
}
|
|
}
|
|
|
|
void F_StartCustomCutscene(INT32 cutscenenum, boolean precutscene, boolean resetplayer)
|
|
{
|
|
if (!cutscenes[cutscenenum])
|
|
return;
|
|
|
|
G_SetGamestate(GS_CUTSCENE);
|
|
|
|
if (wipegamestate == GS_CUTSCENE)
|
|
wipegamestate = -1;
|
|
|
|
gameaction = ga_nothing;
|
|
paused = false;
|
|
CON_ToggleOff();
|
|
|
|
F_NewCutscene(cutscenes[cutscenenum]->scene[0].text);
|
|
|
|
cutsceneover = false;
|
|
runningprecutscene = precutscene;
|
|
precutresetplayer = resetplayer;
|
|
|
|
scenenum = picnum = 0;
|
|
cutnum = cutscenenum;
|
|
picxpos = cutscenes[cutnum]->scene[0].xcoord[0];
|
|
picypos = cutscenes[cutnum]->scene[0].ycoord[0];
|
|
textxpos = cutscenes[cutnum]->scene[0].textxpos;
|
|
textypos = cutscenes[cutnum]->scene[0].textypos;
|
|
|
|
pictime = cutscenes[cutnum]->scene[0].picduration[0];
|
|
|
|
keypressed = false;
|
|
finalecount = 0;
|
|
timetonext = 0;
|
|
animtimer = cutscenes[cutnum]->scene[0].picduration[0]; // Picture duration
|
|
stoptimer = 0;
|
|
|
|
if (cutscenes[cutnum]->scene[0].musswitch[0])
|
|
S_ChangeMusicEx(cutscenes[cutnum]->scene[0].musswitch,
|
|
cutscenes[cutnum]->scene[0].musswitchflags,
|
|
cutscenes[cutnum]->scene[0].musicloop,
|
|
cutscenes[cutnum]->scene[scenenum].musswitchposition, 0, 0);
|
|
else
|
|
S_StopMusic();
|
|
S_StopSounds();
|
|
}
|
|
|
|
//
|
|
// F_CutsceneDrawer
|
|
//
|
|
void F_CutsceneDrawer(void)
|
|
{
|
|
V_DrawFill(0,0, BASEVIDWIDTH, BASEVIDHEIGHT, 31);
|
|
|
|
if (cutscenes[cutnum]->scene[scenenum].picname[picnum][0] != '\0')
|
|
{
|
|
if (cutscenes[cutnum]->scene[scenenum].pichires[picnum])
|
|
V_DrawSmallScaledPatch(picxpos, picypos, 0,
|
|
W_CachePatchName(cutscenes[cutnum]->scene[scenenum].picname[picnum], PU_PATCH_LOWPRIORITY));
|
|
else
|
|
V_DrawScaledPatch(picxpos,picypos, 0,
|
|
W_CachePatchName(cutscenes[cutnum]->scene[scenenum].picname[picnum], PU_PATCH_LOWPRIORITY));
|
|
}
|
|
|
|
V_DrawString(textxpos, textypos, V_ALLOWLOWERCASE, cutscene_disptext);
|
|
}
|
|
|
|
void F_CutsceneTicker(void)
|
|
{
|
|
INT32 i;
|
|
|
|
// Online clients tend not to instantly get the map change, so just wait
|
|
// and don't send 30 of them.
|
|
if (cutsceneover)
|
|
return;
|
|
|
|
// advance animation
|
|
finalecount++;
|
|
cutscene_boostspeed = 0;
|
|
|
|
for (i = 0; i < MAXPLAYERS; i++)
|
|
{
|
|
if (netgame && i != serverplayer && !IsPlayerAdmin(i))
|
|
continue;
|
|
|
|
if (players[i].cmd.buttons & BT_SPIN)
|
|
{
|
|
keypressed = false;
|
|
cutscene_boostspeed = 1;
|
|
if (timetonext)
|
|
timetonext = 2;
|
|
}
|
|
}
|
|
|
|
if (animtimer)
|
|
{
|
|
animtimer--;
|
|
if (animtimer <= 0)
|
|
{
|
|
if (picnum < 7 && cutscenes[cutnum]->scene[scenenum].picname[picnum+1][0] != '\0')
|
|
{
|
|
picnum++;
|
|
picxpos = cutscenes[cutnum]->scene[scenenum].xcoord[picnum];
|
|
picypos = cutscenes[cutnum]->scene[scenenum].ycoord[picnum];
|
|
pictime = cutscenes[cutnum]->scene[scenenum].picduration[picnum];
|
|
animtimer = pictime;
|
|
}
|
|
else
|
|
timetonext = 2;
|
|
}
|
|
}
|
|
|
|
if (timetonext)
|
|
--timetonext;
|
|
|
|
if (++stoptimer > 2 && timetonext == 1)
|
|
F_AdvanceToNextScene();
|
|
else if (!timetonext && !F_WriteText())
|
|
timetonext = 5*TICRATE + 1;
|
|
}
|
|
|
|
boolean F_CutsceneResponder(event_t *event)
|
|
{
|
|
if (cutnum == introtoplay-1)
|
|
return F_IntroResponder(event);
|
|
|
|
return false;
|
|
}
|
|
|
|
// ==================
|
|
// TEXT PROMPTS
|
|
// ==================
|
|
|
|
static void F_GetPageTextGeometry(UINT8 *pagelines, boolean *rightside, INT32 *boxh, INT32 *texth, INT32 *texty, INT32 *namey, INT32 *chevrony, INT32 *textx, INT32 *textr)
|
|
{
|
|
// reuse:
|
|
// cutnum -> promptnum
|
|
// scenenum -> pagenum
|
|
lumpnum_t iconlump = W_CheckNumForName(textprompts[cutnum]->page[scenenum].iconname);
|
|
|
|
*pagelines = textprompts[cutnum]->page[scenenum].lines ? textprompts[cutnum]->page[scenenum].lines : 4;
|
|
*rightside = (iconlump != LUMPERROR && textprompts[cutnum]->page[scenenum].rightside);
|
|
|
|
// Vertical calculations
|
|
*boxh = *pagelines*2;
|
|
*texth = textprompts[cutnum]->page[scenenum].name[0] ? (*pagelines-1)*2 : *pagelines*2; // name takes up first line if it exists
|
|
*texty = BASEVIDHEIGHT - ((*texth * 4) + (*texth/2)*4);
|
|
*namey = BASEVIDHEIGHT - ((*boxh * 4) + (*boxh/2)*4);
|
|
*chevrony = BASEVIDHEIGHT - (((1*2) * 4) + ((1*2)/2)*4); // force on last line
|
|
|
|
// Horizontal calculations
|
|
// Shift text to the right if we have a character icon on the left side
|
|
// Add 4 margin against icon
|
|
*textx = (iconlump != LUMPERROR && !*rightside) ? ((*boxh * 4) + (*boxh/2)*4) + 4 : 4;
|
|
*textr = *rightside ? BASEVIDWIDTH - (((*boxh * 4) + (*boxh/2)*4) + 4) : BASEVIDWIDTH-4;
|
|
}
|
|
|
|
static fixed_t F_GetPromptHideHudBound(void)
|
|
{
|
|
UINT8 pagelines;
|
|
boolean rightside;
|
|
INT32 boxh, texth, texty, namey, chevrony;
|
|
INT32 textx, textr;
|
|
|
|
if (cutnum == INT32_MAX || scenenum == INT32_MAX || !textprompts[cutnum] || scenenum >= textprompts[cutnum]->numpages ||
|
|
!textprompts[cutnum]->page[scenenum].hidehud ||
|
|
(splitscreen && textprompts[cutnum]->page[scenenum].hidehud != 2)) // don't hide on splitscreen, unless hide all is forced
|
|
return 0;
|
|
else if (textprompts[cutnum]->page[scenenum].hidehud == 2) // hide all
|
|
return BASEVIDHEIGHT;
|
|
|
|
F_GetPageTextGeometry(&pagelines, &rightside, &boxh, &texth, &texty, &namey, &chevrony, &textx, &textr);
|
|
|
|
// calc boxheight (see V_DrawPromptBack)
|
|
boxh *= vid.dupy;
|
|
boxh = (boxh * 4) + (boxh/2)*5; // 4 lines of space plus gaps between and some leeway
|
|
|
|
// return a coordinate to check
|
|
// if negative: don't show hud elements below this coordinate (visually)
|
|
// if positive: don't show hud elements above this coordinate (visually)
|
|
return 0 - boxh; // \todo: if prompt at top of screen (someday), make this return positive
|
|
}
|
|
|
|
boolean F_GetPromptHideHudAll(void)
|
|
{
|
|
if (cutnum == INT32_MAX || scenenum == INT32_MAX || !textprompts[cutnum] || scenenum >= textprompts[cutnum]->numpages ||
|
|
!textprompts[cutnum]->page[scenenum].hidehud ||
|
|
(splitscreen && textprompts[cutnum]->page[scenenum].hidehud != 2)) // don't hide on splitscreen, unless hide all is forced
|
|
return false;
|
|
else if (textprompts[cutnum]->page[scenenum].hidehud == 2) // hide all
|
|
return true;
|
|
else
|
|
return false;
|
|
}
|
|
|
|
boolean F_GetPromptHideHud(fixed_t y)
|
|
{
|
|
INT32 ybound;
|
|
boolean fromtop;
|
|
fixed_t ytest;
|
|
|
|
if (!promptactive)
|
|
return false;
|
|
|
|
ybound = F_GetPromptHideHudBound();
|
|
fromtop = (ybound >= 0);
|
|
ytest = (fromtop ? ybound : BASEVIDHEIGHT + ybound);
|
|
|
|
return (fromtop ? y < ytest : y >= ytest); // true means hide
|
|
}
|
|
|
|
static void F_PreparePageText(char *pagetext)
|
|
{
|
|
UINT8 pagelines;
|
|
boolean rightside;
|
|
INT32 boxh, texth, texty, namey, chevrony;
|
|
INT32 textx, textr;
|
|
|
|
F_GetPageTextGeometry(&pagelines, &rightside, &boxh, &texth, &texty, &namey, &chevrony, &textx, &textr);
|
|
|
|
if (promptpagetext)
|
|
Z_Free(promptpagetext);
|
|
promptpagetext = (pagetext && pagetext[0]) ? V_WordWrap(textx, textr, 0, pagetext) : Z_StrDup("");
|
|
|
|
F_NewCutscene(promptpagetext);
|
|
cutscene_textspeed = textprompts[cutnum]->page[scenenum].textspeed ? textprompts[cutnum]->page[scenenum].textspeed : TICRATE/5;
|
|
cutscene_textcount = 0; // no delay in beginning
|
|
cutscene_boostspeed = 0; // don't print 8 characters to start
|
|
|
|
// \todo update control hot strings on re-config
|
|
// and somehow don't reset cutscene text counters
|
|
}
|
|
|
|
static void F_AdvanceToNextPage(void)
|
|
{
|
|
INT32 nextprompt = textprompts[cutnum]->page[scenenum].nextprompt ? textprompts[cutnum]->page[scenenum].nextprompt - 1 : INT32_MAX,
|
|
nextpage = textprompts[cutnum]->page[scenenum].nextpage ? textprompts[cutnum]->page[scenenum].nextpage - 1 : INT32_MAX,
|
|
oldcutnum = cutnum;
|
|
|
|
if (textprompts[cutnum]->page[scenenum].nexttag[0])
|
|
F_GetPromptPageByNamedTag(textprompts[cutnum]->page[scenenum].nexttag, &nextprompt, &nextpage);
|
|
|
|
// determine next prompt
|
|
if (nextprompt != INT32_MAX)
|
|
{
|
|
if (nextprompt <= MAX_PROMPTS && textprompts[nextprompt])
|
|
cutnum = nextprompt;
|
|
else
|
|
cutnum = INT32_MAX;
|
|
}
|
|
|
|
// determine next page
|
|
if (nextpage != INT32_MAX)
|
|
{
|
|
if (cutnum != INT32_MAX)
|
|
{
|
|
scenenum = nextpage;
|
|
if (scenenum >= MAX_PAGES || scenenum > textprompts[cutnum]->numpages-1)
|
|
scenenum = INT32_MAX;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (cutnum != oldcutnum)
|
|
scenenum = 0;
|
|
else if (scenenum + 1 < MAX_PAGES && scenenum < textprompts[cutnum]->numpages-1)
|
|
scenenum++;
|
|
else
|
|
scenenum = INT32_MAX;
|
|
}
|
|
|
|
// close the prompt if either num is invalid
|
|
if (cutnum == INT32_MAX || scenenum == INT32_MAX)
|
|
F_EndTextPrompt(false, false);
|
|
else
|
|
{
|
|
// on page mode, number of tics before allowing boost
|
|
// on timer mode, number of tics until page advances
|
|
timetonext = textprompts[cutnum]->page[scenenum].timetonext ? textprompts[cutnum]->page[scenenum].timetonext : TICRATE/10;
|
|
F_PreparePageText(textprompts[cutnum]->page[scenenum].text);
|
|
|
|
// gfx
|
|
picnum = textprompts[cutnum]->page[scenenum].pictostart;
|
|
numpics = textprompts[cutnum]->page[scenenum].numpics;
|
|
picmode = textprompts[cutnum]->page[scenenum].picmode;
|
|
pictoloop = textprompts[cutnum]->page[scenenum].pictoloop > 0 ? textprompts[cutnum]->page[scenenum].pictoloop - 1 : 0;
|
|
picxpos = textprompts[cutnum]->page[scenenum].xcoord[picnum];
|
|
picypos = textprompts[cutnum]->page[scenenum].ycoord[picnum];
|
|
animtimer = pictime = textprompts[cutnum]->page[scenenum].picduration[picnum];
|
|
|
|
// music change
|
|
if (textprompts[cutnum]->page[scenenum].musswitch[0])
|
|
S_ChangeMusic(textprompts[cutnum]->page[scenenum].musswitch,
|
|
textprompts[cutnum]->page[scenenum].musswitchflags,
|
|
textprompts[cutnum]->page[scenenum].musicloop);
|
|
}
|
|
}
|
|
|
|
void F_EndTextPrompt(boolean forceexec, boolean noexec)
|
|
{
|
|
boolean promptwasactive = promptactive;
|
|
promptactive = false;
|
|
callpromptnum = callpagenum = callplayer = INT32_MAX;
|
|
|
|
if (promptwasactive)
|
|
{
|
|
if (promptmo && promptmo->player && promptblockcontrols)
|
|
promptmo->reactiontime = TICRATE/4; // prevent jumping right away // \todo account freeze realtime for this)
|
|
// \todo reset frozen realtime?
|
|
}
|
|
|
|
// \todo net safety, maybe loop all player thinkers?
|
|
if ((promptwasactive || forceexec) && !noexec && promptpostexectag)
|
|
{
|
|
if (tmthing) // edge case where starting an invalid prompt immediately on level load will make P_MapStart fail
|
|
P_LinedefExecute(promptpostexectag, promptmo, NULL);
|
|
else
|
|
{
|
|
P_MapStart();
|
|
P_LinedefExecute(promptpostexectag, promptmo, NULL);
|
|
P_MapEnd();
|
|
}
|
|
}
|
|
}
|
|
|
|
void F_StartTextPrompt(INT32 promptnum, INT32 pagenum, mobj_t *mo, UINT16 postexectag, boolean blockcontrols, boolean freezerealtime)
|
|
{
|
|
INT32 i;
|
|
|
|
// if splitscreen and we already have a prompt active, ignore.
|
|
// \todo Proper per-player splitscreen support (individual prompts)
|
|
if (promptactive && splitscreen && promptnum == callpromptnum && pagenum == callpagenum)
|
|
return;
|
|
|
|
// \todo proper netgame support
|
|
if (netgame)
|
|
{
|
|
F_EndTextPrompt(true, false); // run the post-effects immediately
|
|
return;
|
|
}
|
|
|
|
// We share vars, so no starting text prompts over cutscenes or title screens!
|
|
keypressed = false;
|
|
finalecount = 0;
|
|
timetonext = 0;
|
|
animtimer = 0;
|
|
stoptimer = 0;
|
|
skullAnimCounter = 0;
|
|
|
|
// Set up state
|
|
promptmo = mo;
|
|
promptpostexectag = postexectag;
|
|
promptblockcontrols = blockcontrols;
|
|
(void)freezerealtime; // \todo freeze player->realtime, maybe this needs to cycle through player thinkers
|
|
|
|
// Initialize current prompt and scene
|
|
callpromptnum = promptnum;
|
|
callpagenum = pagenum;
|
|
cutnum = (promptnum < MAX_PROMPTS && textprompts[promptnum]) ? promptnum : INT32_MAX;
|
|
scenenum = (cutnum != INT32_MAX && pagenum < MAX_PAGES && pagenum <= textprompts[cutnum]->numpages-1) ? pagenum : INT32_MAX;
|
|
promptactive = (cutnum != INT32_MAX && scenenum != INT32_MAX);
|
|
|
|
if (promptactive)
|
|
{
|
|
// on page mode, number of tics before allowing boost
|
|
// on timer mode, number of tics until page advances
|
|
timetonext = textprompts[cutnum]->page[scenenum].timetonext ? textprompts[cutnum]->page[scenenum].timetonext : TICRATE/10;
|
|
F_PreparePageText(textprompts[cutnum]->page[scenenum].text);
|
|
|
|
// gfx
|
|
picnum = textprompts[cutnum]->page[scenenum].pictostart;
|
|
numpics = textprompts[cutnum]->page[scenenum].numpics;
|
|
picmode = textprompts[cutnum]->page[scenenum].picmode;
|
|
pictoloop = textprompts[cutnum]->page[scenenum].pictoloop > 0 ? textprompts[cutnum]->page[scenenum].pictoloop - 1 : 0;
|
|
picxpos = textprompts[cutnum]->page[scenenum].xcoord[picnum];
|
|
picypos = textprompts[cutnum]->page[scenenum].ycoord[picnum];
|
|
animtimer = pictime = textprompts[cutnum]->page[scenenum].picduration[picnum];
|
|
|
|
// music change
|
|
if (textprompts[cutnum]->page[scenenum].musswitch[0])
|
|
S_ChangeMusic(textprompts[cutnum]->page[scenenum].musswitch,
|
|
textprompts[cutnum]->page[scenenum].musswitchflags,
|
|
textprompts[cutnum]->page[scenenum].musicloop);
|
|
|
|
// get the calling player
|
|
if (promptblockcontrols && mo && mo->player)
|
|
{
|
|
for (i = 0; i < MAXPLAYERS; i++)
|
|
{
|
|
if (players[i].mo == mo)
|
|
{
|
|
callplayer = i;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
F_EndTextPrompt(true, false); // run the post-effects immediately
|
|
}
|
|
|
|
static boolean F_GetTextPromptTutorialTag(char *tag, INT32 length)
|
|
{
|
|
INT32 gcs = gcs_custom;
|
|
boolean suffixed = true;
|
|
|
|
if (!tag || !tag[0] || !tutorialmode)
|
|
return false;
|
|
|
|
if (!strncmp(tag, "TAM", 3)) // Movement
|
|
gcs = G_GetControlScheme(gamecontrol, gcl_movement, num_gcl_movement);
|
|
else if (!strncmp(tag, "TAC", 3)) // Camera
|
|
{
|
|
// Check for gcl_movement so we can differentiate between FPS and Platform schemes.
|
|
gcs = G_GetControlScheme(gamecontrol, gcl_movement, num_gcl_movement);
|
|
if (gcs == gcs_custom) // try again, maybe we'll get a match
|
|
gcs = G_GetControlScheme(gamecontrol, gcl_camera, num_gcl_camera);
|
|
if (gcs == gcs_fps && !cv_usemouse.value)
|
|
gcs = gcs_platform; // Platform (arrow) scheme is stand-in for no mouse
|
|
}
|
|
else if (!strncmp(tag, "TAD", 3)) // Movement and Camera
|
|
gcs = G_GetControlScheme(gamecontrol, gcl_movement_camera, num_gcl_movement_camera);
|
|
else if (!strncmp(tag, "TAJ", 3)) // Jump
|
|
gcs = G_GetControlScheme(gamecontrol, gcl_jump, num_gcl_jump);
|
|
else if (!strncmp(tag, "TAS", 3)) // Spin
|
|
gcs = G_GetControlScheme(gamecontrol, gcl_spin, num_gcl_spin);
|
|
else if (!strncmp(tag, "TAA", 3)) // Char ability
|
|
gcs = G_GetControlScheme(gamecontrol, gcl_jump, num_gcl_jump);
|
|
else if (!strncmp(tag, "TAW", 3)) // Shield ability
|
|
gcs = G_GetControlScheme(gamecontrol, gcl_jump_spin, num_gcl_jump_spin);
|
|
else
|
|
gcs = G_GetControlScheme(gamecontrol, gcl_tutorial_used, num_gcl_tutorial_used);
|
|
|
|
switch (gcs)
|
|
{
|
|
case gcs_fps:
|
|
// strncat(tag, "FPS", length);
|
|
suffixed = false;
|
|
break;
|
|
|
|
case gcs_platform:
|
|
strncat(tag, "PLATFORM", length);
|
|
break;
|
|
|
|
default:
|
|
strncat(tag, "CUSTOM", length);
|
|
break;
|
|
}
|
|
|
|
return suffixed;
|
|
}
|
|
|
|
void F_GetPromptPageByNamedTag(const char *tag, INT32 *promptnum, INT32 *pagenum)
|
|
{
|
|
INT32 nosuffixpromptnum = INT32_MAX, nosuffixpagenum = INT32_MAX;
|
|
INT32 tutorialpromptnum = (tutorialmode) ? TUTORIAL_PROMPT-1 : 0;
|
|
boolean suffixed = false, found = false;
|
|
char suffixedtag[33];
|
|
|
|
*promptnum = *pagenum = INT32_MAX;
|
|
|
|
if (!tag || !tag[0])
|
|
return;
|
|
|
|
strncpy(suffixedtag, tag, 33);
|
|
suffixedtag[32] = 0;
|
|
|
|
if (tutorialmode)
|
|
suffixed = F_GetTextPromptTutorialTag(suffixedtag, 33);
|
|
|
|
for (*promptnum = 0 + tutorialpromptnum; *promptnum < MAX_PROMPTS; (*promptnum)++)
|
|
{
|
|
if (!textprompts[*promptnum])
|
|
continue;
|
|
|
|
for (*pagenum = 0; *pagenum < textprompts[*promptnum]->numpages && *pagenum < MAX_PAGES; (*pagenum)++)
|
|
{
|
|
if (suffixed && fastcmp(suffixedtag, textprompts[*promptnum]->page[*pagenum].tag))
|
|
{
|
|
// this goes first because fastcmp ends early if first string is shorter
|
|
found = true;
|
|
break;
|
|
}
|
|
else if (nosuffixpromptnum == INT32_MAX && nosuffixpagenum == INT32_MAX && fastcmp(tag, textprompts[*promptnum]->page[*pagenum].tag))
|
|
{
|
|
if (suffixed)
|
|
{
|
|
nosuffixpromptnum = *promptnum;
|
|
nosuffixpagenum = *pagenum;
|
|
// continue searching for the suffixed tag
|
|
}
|
|
else
|
|
{
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (found)
|
|
break;
|
|
}
|
|
|
|
if (suffixed && !found && nosuffixpromptnum != INT32_MAX && nosuffixpagenum != INT32_MAX)
|
|
{
|
|
found = true;
|
|
*promptnum = nosuffixpromptnum;
|
|
*pagenum = nosuffixpagenum;
|
|
}
|
|
|
|
if (!found)
|
|
CONS_Debug(DBG_GAMELOGIC, "Text prompt: Can't find a page with named tag %s or suffixed tag %s\n", tag, suffixedtag);
|
|
}
|
|
|
|
void F_TextPromptDrawer(void)
|
|
{
|
|
// reuse:
|
|
// cutnum -> promptnum
|
|
// scenenum -> pagenum
|
|
lumpnum_t iconlump;
|
|
UINT8 pagelines;
|
|
boolean rightside;
|
|
INT32 boxh, texth, texty, namey, chevrony;
|
|
INT32 textx, textr;
|
|
|
|
// Data
|
|
patch_t *patch;
|
|
|
|
if (!promptactive)
|
|
return;
|
|
|
|
iconlump = W_CheckNumForName(textprompts[cutnum]->page[scenenum].iconname);
|
|
F_GetPageTextGeometry(&pagelines, &rightside, &boxh, &texth, &texty, &namey, &chevrony, &textx, &textr);
|
|
|
|
// Draw gfx first
|
|
if (picnum >= 0 && picnum < numpics && textprompts[cutnum]->page[scenenum].picname[picnum][0] != '\0')
|
|
{
|
|
if (textprompts[cutnum]->page[scenenum].pichires[picnum])
|
|
V_DrawSmallScaledPatch(picxpos, picypos, 0,
|
|
W_CachePatchName(textprompts[cutnum]->page[scenenum].picname[picnum], PU_PATCH_LOWPRIORITY));
|
|
else
|
|
V_DrawScaledPatch(picxpos,picypos, 0,
|
|
W_CachePatchName(textprompts[cutnum]->page[scenenum].picname[picnum], PU_PATCH_LOWPRIORITY));
|
|
}
|
|
|
|
// Draw background
|
|
V_DrawPromptBack(boxh, textprompts[cutnum]->page[scenenum].backcolor);
|
|
|
|
// Draw narrator icon
|
|
if (iconlump != LUMPERROR)
|
|
{
|
|
INT32 iconx, icony, scale, scaledsize;
|
|
patch = W_CachePatchName(textprompts[cutnum]->page[scenenum].iconname, PU_PATCH_LOWPRIORITY);
|
|
|
|
// scale and center
|
|
if (patch->width > patch->height)
|
|
{
|
|
scale = FixedDiv(((boxh * 4) + (boxh/2)*4) - 4, patch->width);
|
|
scaledsize = FixedMul(patch->height, scale);
|
|
iconx = (rightside ? BASEVIDWIDTH - (((boxh * 4) + (boxh/2)*4)) : 4) << FRACBITS;
|
|
icony = ((namey-4) << FRACBITS) + FixedDiv(BASEVIDHEIGHT - namey + 4 - scaledsize, 2); // account for 4 margin
|
|
}
|
|
else if (patch->height > patch->width)
|
|
{
|
|
scale = FixedDiv(((boxh * 4) + (boxh/2)*4) - 4, patch->height);
|
|
scaledsize = FixedMul(patch->width, scale);
|
|
iconx = (rightside ? BASEVIDWIDTH - (((boxh * 4) + (boxh/2)*4)) : 4) << FRACBITS;
|
|
icony = namey << FRACBITS;
|
|
iconx += FixedDiv(FixedMul(patch->height, scale) - scaledsize, 2);
|
|
}
|
|
else
|
|
{
|
|
scale = FixedDiv(((boxh * 4) + (boxh/2)*4) - 4, patch->width);
|
|
iconx = (rightside ? BASEVIDWIDTH - (((boxh * 4) + (boxh/2)*4)) : 4) << FRACBITS;
|
|
icony = namey << FRACBITS;
|
|
}
|
|
|
|
if (textprompts[cutnum]->page[scenenum].iconflip)
|
|
iconx += FixedMul(patch->width, scale) << FRACBITS;
|
|
|
|
V_DrawFixedPatch(iconx, icony, scale, (V_SNAPTOBOTTOM|(textprompts[cutnum]->page[scenenum].iconflip ? V_FLIP : 0)), patch, NULL);
|
|
W_UnlockCachedPatch(patch);
|
|
}
|
|
|
|
// Draw text
|
|
V_DrawString(textx, texty, (V_SNAPTOBOTTOM|V_ALLOWLOWERCASE), cutscene_disptext);
|
|
|
|
// Draw name
|
|
// Don't use V_YELLOWMAP here so that the name color can be changed with control codes
|
|
if (textprompts[cutnum]->page[scenenum].name[0])
|
|
V_DrawString(textx, namey, (V_SNAPTOBOTTOM|V_ALLOWLOWERCASE), textprompts[cutnum]->page[scenenum].name);
|
|
|
|
// Draw chevron
|
|
if (promptblockcontrols && !timetonext)
|
|
V_DrawString(textr-8, chevrony + (skullAnimCounter/5), (V_SNAPTOBOTTOM|V_YELLOWMAP), "\x1B"); // down arrow
|
|
}
|
|
|
|
#define nocontrolallowed(j) {\
|
|
players[j].powers[pw_nocontrol] = 1;\
|
|
if (players[j].mo)\
|
|
{\
|
|
if (players[j].mo->state == states+S_PLAY_STND && players[j].mo->tics != -1)\
|
|
players[j].mo->tics++;\
|
|
else if (players[j].mo->state == states+S_PLAY_WAIT)\
|
|
P_SetPlayerMobjState(players[j].mo, S_PLAY_STND);\
|
|
}\
|
|
}
|
|
|
|
void F_TextPromptTicker(void)
|
|
{
|
|
INT32 i;
|
|
|
|
if (!promptactive || paused || P_AutoPause())
|
|
return;
|
|
|
|
// advance animation
|
|
finalecount++;
|
|
cutscene_boostspeed = 0;
|
|
|
|
// for the chevron
|
|
if (--skullAnimCounter <= 0)
|
|
skullAnimCounter = 8;
|
|
|
|
// button handling
|
|
if (textprompts[cutnum]->page[scenenum].timetonext)
|
|
{
|
|
if (promptblockcontrols) // same procedure as below, just without the button handling
|
|
{
|
|
for (i = 0; i < MAXPLAYERS; i++)
|
|
{
|
|
if (netgame && i != serverplayer && !IsPlayerAdmin(i))
|
|
continue;
|
|
else if (splitscreen) {
|
|
// Both players' controls are locked,
|
|
// But only consoleplayer can advance the prompt.
|
|
// \todo Proper per-player splitscreen support (individual prompts)
|
|
if (i == consoleplayer || i == secondarydisplayplayer)
|
|
nocontrolallowed(i)
|
|
}
|
|
else if (i == consoleplayer)
|
|
nocontrolallowed(i)
|
|
|
|
if (!splitscreen)
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (timetonext >= 1)
|
|
timetonext--;
|
|
|
|
if (!timetonext)
|
|
F_AdvanceToNextPage();
|
|
|
|
F_WriteText();
|
|
}
|
|
else
|
|
{
|
|
if (promptblockcontrols)
|
|
{
|
|
for (i = 0; i < MAXPLAYERS; i++)
|
|
{
|
|
if (netgame && i != serverplayer && !IsPlayerAdmin(i))
|
|
continue;
|
|
else if (splitscreen) {
|
|
// Both players' controls are locked,
|
|
// But only the triggering player can advance the prompt.
|
|
if (i == consoleplayer || i == secondarydisplayplayer)
|
|
{
|
|
players[i].powers[pw_nocontrol] = 1;
|
|
|
|
if (callplayer == consoleplayer || callplayer == secondarydisplayplayer)
|
|
{
|
|
if (i != callplayer)
|
|
continue;
|
|
}
|
|
else if (i != consoleplayer)
|
|
continue;
|
|
}
|
|
else
|
|
continue;
|
|
}
|
|
else if (i == consoleplayer)
|
|
nocontrolallowed(i)
|
|
else
|
|
continue;
|
|
|
|
if ((players[i].cmd.buttons & BT_SPIN) || (players[i].cmd.buttons & BT_JUMP))
|
|
{
|
|
if (timetonext > 1)
|
|
timetonext--;
|
|
else if (cutscene_baseptr) // don't set boost if we just reset the string
|
|
cutscene_boostspeed = 1; // only after a slight delay
|
|
|
|
if (keypressed)
|
|
{
|
|
if (!splitscreen)
|
|
break;
|
|
else
|
|
continue;
|
|
}
|
|
|
|
if (!timetonext) // is 0 when finished generating text
|
|
{
|
|
F_AdvanceToNextPage();
|
|
if (promptactive)
|
|
S_StartSound(NULL, sfx_menu1);
|
|
}
|
|
keypressed = true; // prevent repeat events
|
|
}
|
|
else if (!(players[i].cmd.buttons & BT_SPIN) && !(players[i].cmd.buttons & BT_JUMP))
|
|
keypressed = false;
|
|
|
|
if (!splitscreen)
|
|
break;
|
|
}
|
|
}
|
|
|
|
// generate letter-by-letter text
|
|
if (scenenum >= MAX_PAGES ||
|
|
!textprompts[cutnum]->page[scenenum].text ||
|
|
!textprompts[cutnum]->page[scenenum].text[0] ||
|
|
!F_WriteText())
|
|
timetonext = !promptblockcontrols; // never show the chevron if we can't toggle pages
|
|
}
|
|
|
|
// gfx
|
|
if (picnum >= 0 && picnum < numpics)
|
|
{
|
|
if (animtimer <= 0)
|
|
{
|
|
boolean persistanimtimer = false;
|
|
|
|
if (picnum < numpics-1 && textprompts[cutnum]->page[scenenum].picname[picnum+1][0] != '\0')
|
|
picnum++;
|
|
else if (picmode == PROMPT_PIC_LOOP)
|
|
picnum = pictoloop;
|
|
else if (picmode == PROMPT_PIC_DESTROY)
|
|
picnum = -1;
|
|
else // if (picmode == PROMPT_PIC_PERSIST)
|
|
persistanimtimer = true;
|
|
|
|
if (!persistanimtimer && picnum >= 0)
|
|
{
|
|
picxpos = textprompts[cutnum]->page[scenenum].xcoord[picnum];
|
|
picypos = textprompts[cutnum]->page[scenenum].ycoord[picnum];
|
|
pictime = textprompts[cutnum]->page[scenenum].picduration[picnum];
|
|
animtimer = pictime;
|
|
}
|
|
}
|
|
else
|
|
animtimer--;
|
|
}
|
|
}
|