2014-03-15 16:59:03 +00:00
// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
2016-07-06 04:09:17 +00:00
// Copyright (C) 2004-2016 by Sonic Team Junior.
2014-03-15 16:59:03 +00:00
//
// 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 y_inter.c
2016-07-06 04:09:17 +00:00
/// \brief Tally screens, or "Intermissions" as they were formally called in Doom
2014-03-15 16:59:03 +00:00
# include "doomdef.h"
# include "doomstat.h"
# include "d_main.h"
# include "f_finale.h"
# include "g_game.h"
# include "hu_stuff.h"
# include "i_net.h"
# include "i_video.h"
# include "p_tick.h"
# include "r_defs.h"
# include "r_things.h"
# include "s_sound.h"
# include "st_stuff.h"
# include "v_video.h"
# include "w_wad.h"
# include "y_inter.h"
# include "z_zone.h"
# include "m_menu.h"
# include "m_misc.h"
# include "i_system.h"
# include "p_setup.h"
# include "r_local.h"
# include "p_local.h"
# include "m_cond.h" // condition sets
2018-02-04 04:47:47 +00:00
# include "m_random.h" // P_RandomKey
# include "g_input.h" // PLAYER1INPUTDOWN
2018-01-27 06:17:08 +00:00
2014-03-15 16:59:03 +00:00
# ifdef HWRENDER
# include "hardware/hw_main.h"
# endif
# ifdef PC_DOS
# include <stdio.h> // for snprintf
int snprintf ( char * str , size_t n , const char * fmt , . . . ) ;
//int vsnprintf(char *str, size_t n, const char *fmt, va_list ap);
# endif
typedef struct
{
char patch [ 9 ] ;
INT32 points ;
UINT8 display ;
} y_bonus_t ;
typedef union
{
struct
{
2017-09-28 20:54:26 +00:00
char passed1 [ 21 ] ; // KNUCKLES GOT / CRAWLA HONCHO
2014-04-14 05:14:58 +00:00
char passed2 [ 16 ] ; // THROUGH THE ACT / PASSED THE ACT
2014-03-15 16:59:03 +00:00
INT32 passedx1 ;
INT32 passedx2 ;
y_bonus_t bonuses [ 4 ] ;
patch_t * bonuspatches [ 4 ] ;
SINT8 gotperfbonus ; // Used for visitation flags.
UINT32 score , total ; // fake score, total
UINT32 tics ; // time
patch_t * ttlnum ; // act number being displayed
patch_t * ptotal ; // TOTAL
UINT8 gotlife ; // Number of extra lives obtained
} coop ;
struct
{
2017-09-28 20:54:26 +00:00
char passed1 [ 29 ] ; // KNUCKLES GOT / CRAWLA HONCHO
2016-07-06 04:09:17 +00:00
char passed2 [ 17 ] ; // A CHAOS EMERALD / GOT THEM ALL!
char passed3 [ 15 ] ; // CAN NOW BECOME
char passed4 [ SKINNAMESIZE + 7 ] ; // SUPER CRAWLA HONCHO
2014-03-15 16:59:03 +00:00
INT32 passedx1 ;
INT32 passedx2 ;
2016-07-06 04:09:17 +00:00
INT32 passedx3 ;
INT32 passedx4 ;
2014-03-15 16:59:03 +00:00
y_bonus_t bonus ;
patch_t * bonuspatch ;
patch_t * pscore ; // SCORE
UINT32 score ; // fake score
// Continues
UINT8 continues ;
patch_t * pcontinues ;
INT32 * playerchar ; // Continue HUD
UINT8 * playercolor ;
UINT8 gotlife ; // Number of extra lives obtained
} spec ;
struct
{
UINT32 scores [ MAXPLAYERS ] ; // Winner's score
UINT8 * color [ MAXPLAYERS ] ; // Winner's color #
boolean spectator [ MAXPLAYERS ] ; // Spectator list
INT32 * character [ MAXPLAYERS ] ; // Winner's character #
INT32 num [ MAXPLAYERS ] ; // Winner's player #
char * name [ MAXPLAYERS ] ; // Winner's name
patch_t * result ; // RESULT
patch_t * blueflag ;
patch_t * redflag ; // int_ctf uses this struct too.
INT32 numplayers ; // Number of players being displayed
char levelstring [ 40 ] ; // holds levelnames up to 32 characters
2017-02-07 22:19:04 +00:00
// SRB2kart
int increase [ MAXPLAYERS ] ; //how much did the score increase by?
int time [ MAXPLAYERS ] ; //Tournament Time
2014-03-15 16:59:03 +00:00
} match ;
struct
{
UINT8 * color [ MAXPLAYERS ] ; // Winner's color #
INT32 * character [ MAXPLAYERS ] ; // Winner's character #
INT32 num [ MAXPLAYERS ] ; // Winner's player #
char name [ MAXPLAYERS ] [ 9 ] ; // Winner's name
UINT32 times [ MAXPLAYERS ] ;
UINT32 rings [ MAXPLAYERS ] ;
UINT32 maxrings [ MAXPLAYERS ] ;
UINT32 monitors [ MAXPLAYERS ] ;
UINT32 scores [ MAXPLAYERS ] ;
UINT32 points [ MAXPLAYERS ] ;
INT32 numplayers ; // Number of players being displayed
char levelstring [ 40 ] ; // holds levelnames up to 32 characters
} competition ;
} y_data ;
static y_data data ;
// graphics
static patch_t * bgpatch = NULL ; // INTERSCR
static patch_t * widebgpatch = NULL ; // INTERSCW
static patch_t * bgtile = NULL ; // SPECTILE/SRB2BACK
static patch_t * interpic = NULL ; // custom picture defined in map header
static boolean usetile ;
2014-03-21 18:42:55 +00:00
boolean usebuffer = false ;
2014-03-15 16:59:03 +00:00
static boolean useinterpic ;
static INT32 timer ;
static INT32 intertic ;
static INT32 endtic = - 1 ;
intertype_t intertype = int_none ;
2017-02-07 22:19:04 +00:00
//static void Y_AwardCoopBonuses(void);
//static void Y_AwardSpecialStageBonus(void);
static void Y_CalculateTournamentPoints ( void ) ; // SRB2kart
2014-03-15 16:59:03 +00:00
static void Y_CalculateCompetitionWinners ( void ) ;
2017-02-07 22:19:04 +00:00
//static void Y_CalculateTimeRaceWinners(void);
2014-03-15 16:59:03 +00:00
static void Y_CalculateMatchWinners ( void ) ;
static void Y_FollowIntermission ( void ) ;
static void Y_UnloadData ( void ) ;
2018-01-27 06:17:08 +00:00
// SRB2Kart: voting stuff
typedef struct
{
char str [ 40 ] ;
patch_t * pic ;
2018-02-04 04:47:47 +00:00
} y_votelvlinfo ;
2018-01-27 06:17:08 +00:00
typedef struct
{
2018-02-23 01:04:52 +00:00
SINT8 selection ;
2018-02-04 04:47:47 +00:00
UINT8 delay ;
2018-02-11 00:02:15 +00:00
UINT8 ranim ;
UINT8 rtics ;
UINT8 roffset ;
2018-02-13 23:13:27 +00:00
UINT8 rsynctime ;
UINT8 rendoff ;
2018-02-04 04:47:47 +00:00
} y_voteclient ;
2018-01-27 06:17:08 +00:00
2018-02-04 04:47:47 +00:00
static y_votelvlinfo levelinfo [ 4 ] ;
static y_voteclient voteclient ;
2018-01-27 06:17:08 +00:00
static INT32 votetic ;
static INT32 voteendtic = - 1 ;
static patch_t * cursor = NULL ;
2018-01-28 04:52:01 +00:00
static patch_t * randomlvl = NULL ;
2018-01-27 06:17:08 +00:00
static void Y_UnloadVoteData ( void ) ;
2017-07-05 16:05:39 +00:00
// Stuff copy+pasted from st_stuff.c
static INT32 SCX ( INT32 x )
{
return FixedInt ( FixedMul ( x < < FRACBITS , vid . fdupx ) ) ;
}
static INT32 SCY ( INT32 z )
{
return FixedInt ( FixedMul ( z < < FRACBITS , vid . fdupy ) ) ;
}
2017-07-05 21:30:18 +00:00
# define ST_DrawNumFromHud(h,n) V_DrawTallNum(SCX(hudinfo[h].x), SCY(hudinfo[h].y), V_NOSCALESTART, n)
# define ST_DrawPadNumFromHud(h,n,q) V_DrawPaddedTallNum(SCX(hudinfo[h].x), SCY(hudinfo[h].y), V_NOSCALESTART, n, q)
# define ST_DrawPatchFromHud(h,p) V_DrawScaledPatch(SCX(hudinfo[h].x), SCY(hudinfo[h].y), V_NOSCALESTART, p)
2017-07-05 16:05:39 +00:00
2014-03-15 16:59:03 +00:00
//
// Y_IntermissionDrawer
//
// Called by D_Display. Nothing is modified here; all it does is draw.
// Neat concept, huh?
//
void Y_IntermissionDrawer ( void )
{
// Bonus loops
INT32 i ;
if ( intertype = = int_none | | rendermode = = render_none )
return ;
if ( ! usebuffer )
V_DrawFill ( 0 , 0 , BASEVIDWIDTH , BASEVIDHEIGHT , 31 ) ;
if ( useinterpic )
V_DrawScaledPatch ( 0 , 0 , 0 , interpic ) ;
else if ( ! usetile )
{
if ( rendermode = = render_soft & & usebuffer )
VID_BlitLinearScreen ( screens [ 1 ] , screens [ 0 ] , vid . width * vid . bpp , vid . height , vid . width * vid . bpp , vid . rowbytes ) ;
# ifdef HWRENDER
else if ( rendermode ! = render_soft & & usebuffer )
{
HWR_DrawIntermissionBG ( ) ;
}
# endif
else
{
if ( widebgpatch & & rendermode = = render_soft & & vid . width / vid . dupx = = 400 )
V_DrawScaledPatch ( 0 , 0 , V_SNAPTOLEFT , widebgpatch ) ;
else
V_DrawScaledPatch ( 0 , 0 , 0 , bgpatch ) ;
}
}
else
V_DrawPatchFill ( bgtile ) ;
2017-02-07 22:19:04 +00:00
// SRB2kart 290117 - compeltely replaced this block.
if ( intertype = = int_timeattack )
2014-03-15 16:59:03 +00:00
{
// draw time
2017-10-17 20:23:38 +00:00
ST_DrawPatchFromHud ( HUD_TIME , sbotime ) ;
2017-02-07 22:19:04 +00:00
if ( cv_timetic . value )
2017-10-17 20:23:38 +00:00
ST_DrawNumFromHud ( HUD_SECONDS , data . coop . tics ) ;
2014-03-15 16:59:03 +00:00
else
{
2017-10-17 20:23:38 +00:00
INT32 seconds , minutes , tictrn ;
2014-03-15 16:59:03 +00:00
2017-10-17 20:23:38 +00:00
seconds = G_TicsToSeconds ( data . coop . tics ) ;
minutes = G_TicsToMinutes ( data . coop . tics , true ) ;
tictrn = G_TicsToCentiseconds ( data . coop . tics ) ;
ST_DrawNumFromHud ( HUD_MINUTES , minutes ) ; // Minutes
ST_DrawPatchFromHud ( HUD_TIMECOLON , sbocolon ) ; // Colon
ST_DrawPadNumFromHud ( HUD_SECONDS , seconds , 2 ) ; // Seconds
/* // SRB2kart - pulled from old coop block, just in case we need it
// we should show centiseconds on the intermission screen too, if the conditions are right.
if ( modeattacking | | cv_timetic . value = = 2 )
{
ST_DrawPatchFromHud ( HUD_TIMETICCOLON , sboperiod ) ; // Period
ST_DrawPadNumFromHud ( HUD_TICS , tictrn , 2 ) ; // Tics
} */
ST_DrawPatchFromHud ( HUD_TIMETICCOLON , sboperiod ) ; // Period
ST_DrawPadNumFromHud ( HUD_TICS , tictrn , 2 ) ; // Tics
}
2014-03-15 16:59:03 +00:00
// draw the "got through act" lines and act number
V_DrawLevelTitle ( data . coop . passedx1 , 49 , 0 , data . coop . passed1 ) ;
V_DrawLevelTitle ( data . coop . passedx2 , 49 + V_LevelNameHeight ( data . coop . passed2 ) + 2 , 0 , data . coop . passed2 ) ;
if ( mapheaderinfo [ gamemap - 1 ] - > actnum )
V_DrawScaledPatch ( 244 , 57 , 0 , data . coop . ttlnum ) ;
2017-02-07 22:19:04 +00:00
//if (gottimebonus && endtic != -1)
// V_DrawCenteredString(BASEVIDWIDTH/2, 172, V_YELLOWMAP, "TIME BONUS UNLOCKED!");
2014-03-15 16:59:03 +00:00
}
2017-02-07 22:19:04 +00:00
else if ( intertype = = int_race )
2014-03-15 16:59:03 +00:00
{
2017-03-04 22:13:19 +00:00
INT32 j = 0 ;
2017-02-07 22:19:04 +00:00
INT32 x = 4 ;
INT32 y = 48 ;
char name [ MAXPLAYERNAME + 1 ] ;
2016-07-06 04:09:17 +00:00
2017-02-07 22:19:04 +00:00
boolean completed [ MAXPLAYERS ] ;
memset ( completed , 0 , sizeof ( completed ) ) ;
2016-07-06 04:09:17 +00:00
2017-02-07 22:19:04 +00:00
// draw the level name
V_DrawCenteredString ( BASEVIDWIDTH / 2 , 20 , 0 , data . match . levelstring ) ;
V_DrawFill ( 4 , 42 , 312 , 1 , 0 ) ;
2014-03-15 16:59:03 +00:00
2017-02-07 22:19:04 +00:00
if ( data . match . numplayers > 8 )
2014-03-15 16:59:03 +00:00
{
2017-02-07 22:19:04 +00:00
V_DrawFill ( 160 , 32 , 1 , 152 , 0 ) ;
V_DrawCenteredString ( x + 6 + ( BASEVIDWIDTH / 2 ) , 32 , V_YELLOWMAP , " # " ) ;
V_DrawString ( x + 36 + ( BASEVIDWIDTH / 2 ) , 32 , V_YELLOWMAP , " NAME " ) ;
V_DrawRightAlignedString ( x + 110 , 32 , V_YELLOWMAP , " TIME " ) ;
V_DrawRightAlignedString ( x + 152 , 32 , V_YELLOWMAP , " SCORE " ) ;
2016-07-06 04:09:17 +00:00
}
2017-02-07 22:19:04 +00:00
V_DrawCenteredString ( x + 6 , 32 , V_YELLOWMAP , " # " ) ;
V_DrawString ( x + 36 , 32 , V_YELLOWMAP , " NAME " ) ;
if ( data . match . numplayers > 8 )
2016-07-06 04:09:17 +00:00
{
2017-02-07 22:19:04 +00:00
V_DrawRightAlignedString ( x + ( BASEVIDWIDTH / 2 ) + 110 , 32 , V_YELLOWMAP , " TIME " ) ;
2014-03-15 16:59:03 +00:00
}
else
2016-07-06 04:09:17 +00:00
{
2017-02-07 22:19:04 +00:00
V_DrawRightAlignedString ( x + ( BASEVIDWIDTH / 2 ) + 62 , 32 , V_YELLOWMAP , " TIME " ) ;
2016-07-06 04:09:17 +00:00
}
2014-03-15 16:59:03 +00:00
2017-02-07 22:19:04 +00:00
V_DrawRightAlignedString ( x + ( BASEVIDWIDTH / 2 ) + 152 , 32 , V_YELLOWMAP , " SCORE " ) ;
for ( i = 0 ; i < data . match . numplayers ; i + + )
2014-03-15 16:59:03 +00:00
{
2017-02-07 22:19:04 +00:00
char strtime [ 10 ] ;
if ( data . match . spectator [ i ] )
continue ;
V_DrawCenteredString ( x + 6 , y , 0 , va ( " %d " , j + 1 ) ) ;
j + + ; //We skip spectators, but not their number.
if ( playeringame [ data . match . num [ i ] ] )
2014-03-15 16:59:03 +00:00
{
2017-02-07 22:19:04 +00:00
if ( data . match . color [ i ] = = 0 )
V_DrawSmallScaledPatch ( x + 16 , y - 4 , 0 , faceprefix [ * data . match . character [ i ] ] ) ;
else
{
UINT8 * colormap = R_GetTranslationColormap ( * data . match . character [ i ] , * data . match . color [ i ] , GTC_CACHE ) ;
V_DrawSmallMappedPatch ( x + 16 , y - 4 , 0 , faceprefix [ * data . match . character [ i ] ] , colormap ) ;
}
2014-03-15 16:59:03 +00:00
2017-02-07 22:19:04 +00:00
if ( data . match . numplayers > 8 )
{
strlcpy ( name , data . match . name [ i ] , 6 ) ;
}
else
STRBUFCPY ( name , data . match . name [ i ] ) ;
2014-03-15 16:59:03 +00:00
2017-02-07 22:19:04 +00:00
V_DrawString ( x + 36 , y , V_ALLOWLOWERCASE , name ) ;
2014-03-15 16:59:03 +00:00
2017-02-07 22:19:04 +00:00
snprintf ( strtime , sizeof strtime , " %d " , data . match . scores [ i ] - data . match . increase [ i ] ) ;
if ( data . match . numplayers > 8 )
{
V_DrawRightAlignedString ( x + 152 , y , V_YELLOWMAP , strtime ) ;
}
else
{
V_DrawRightAlignedString ( x + 152 + BASEVIDWIDTH / 2 , y , V_YELLOWMAP , strtime ) ;
}
if ( data . match . increase [ i ] > 9 )
snprintf ( strtime , sizeof strtime , " (+%02d) " , data . match . increase [ i ] ) ;
else
snprintf ( strtime , sizeof strtime , " (+ %d) " , data . match . increase [ i ] ) ;
if ( data . match . numplayers < = 8 ) // Only draw this with less than 8 players, otherwise we won't be able to fit the times in
{
V_DrawString ( x + 84 + BASEVIDWIDTH / 2 , y , 0 , strtime ) ;
}
snprintf ( strtime , sizeof strtime , " %i:%02i.%02i " , G_TicsToMinutes ( data . match . time [ i ] , true ) ,
G_TicsToSeconds ( data . match . time [ i ] ) , G_TicsToCentiseconds ( data . match . time [ i ] ) ) ;
strtime [ sizeof strtime - 1 ] = ' \0 ' ;
if ( data . match . numplayers > 8 )
{
V_DrawRightAlignedString ( x + 134 , y , 0 , strtime ) ;
}
else
{
V_DrawRightAlignedString ( x + 80 + BASEVIDWIDTH / 2 , y , 0 , strtime ) ;
}
completed [ i ] = true ;
}
y + = 16 ;
if ( y > 160 )
2014-03-15 16:59:03 +00:00
{
2017-02-07 22:19:04 +00:00
y = 48 ;
x + = BASEVIDWIDTH / 2 ;
2014-03-15 16:59:03 +00:00
}
}
}
2017-02-07 22:19:04 +00:00
else if ( intertype = = int_match )
2014-03-15 16:59:03 +00:00
{
INT32 j = 0 ;
INT32 x = 4 ;
INT32 y = 48 ;
char name [ MAXPLAYERNAME + 1 ] ;
char strtime [ 10 ] ;
// draw the header
V_DrawScaledPatch ( 112 , 2 , 0 , data . match . result ) ;
// draw the level name
V_DrawCenteredString ( BASEVIDWIDTH / 2 , 20 , 0 , data . match . levelstring ) ;
V_DrawFill ( 4 , 42 , 312 , 1 , 0 ) ;
if ( data . match . numplayers > 9 )
{
V_DrawFill ( 160 , 32 , 1 , 152 , 0 ) ;
if ( intertype = = int_race )
V_DrawRightAlignedString ( x + 152 , 32 , V_YELLOWMAP , " TIME " ) ;
else
V_DrawRightAlignedString ( x + 152 , 32 , V_YELLOWMAP , " SCORE " ) ;
V_DrawCenteredString ( x + ( BASEVIDWIDTH / 2 ) + 6 , 32 , V_YELLOWMAP , " # " ) ;
V_DrawString ( x + ( BASEVIDWIDTH / 2 ) + 36 , 32 , V_YELLOWMAP , " NAME " ) ;
}
V_DrawCenteredString ( x + 6 , 32 , V_YELLOWMAP , " # " ) ;
V_DrawString ( x + 36 , 32 , V_YELLOWMAP , " NAME " ) ;
if ( intertype = = int_race )
V_DrawRightAlignedString ( x + ( BASEVIDWIDTH / 2 ) + 152 , 32 , V_YELLOWMAP , " TIME " ) ;
else
V_DrawRightAlignedString ( x + ( BASEVIDWIDTH / 2 ) + 152 , 32 , V_YELLOWMAP , " SCORE " ) ;
for ( i = 0 ; i < data . match . numplayers ; i + + )
{
if ( data . match . spectator [ i ] )
continue ; //Ignore spectators.
V_DrawCenteredString ( x + 6 , y , 0 , va ( " %d " , j + 1 ) ) ;
j + + ; //We skip spectators, but not their number.
if ( playeringame [ data . match . num [ i ] ] )
{
// Draw the back sprite, it looks ugly if we don't
V_DrawSmallScaledPatch ( x + 16 , y - 4 , 0 , livesback ) ;
if ( data . match . color [ i ] = = 0 )
V_DrawSmallScaledPatch ( x + 16 , y - 4 , 0 , faceprefix [ * data . match . character [ i ] ] ) ;
else
{
UINT8 * colormap = R_GetTranslationColormap ( * data . match . character [ i ] , * data . match . color [ i ] , GTC_CACHE ) ;
V_DrawSmallMappedPatch ( x + 16 , y - 4 , 0 , faceprefix [ * data . match . character [ i ] ] , colormap ) ;
}
if ( data . match . numplayers > 9 )
{
if ( intertype = = int_race )
strlcpy ( name , data . match . name [ i ] , 8 ) ;
else
strlcpy ( name , data . match . name [ i ] , 9 ) ;
}
else
STRBUFCPY ( name , data . match . name [ i ] ) ;
V_DrawString ( x + 36 , y , V_ALLOWLOWERCASE , name ) ;
if ( data . match . numplayers > 9 )
{
if ( intertype = = int_match )
V_DrawRightAlignedString ( x + 152 , y , 0 , va ( " %i " , data . match . scores [ i ] ) ) ;
else if ( intertype = = int_race )
{
if ( players [ data . match . num [ i ] ] . pflags & PF_TIMEOVER )
snprintf ( strtime , sizeof strtime , " DNF " ) ;
else
snprintf ( strtime , sizeof strtime ,
" %i:%02i.%02i " ,
G_TicsToMinutes ( data . match . scores [ i ] , true ) ,
G_TicsToSeconds ( data . match . scores [ i ] ) , G_TicsToCentiseconds ( data . match . scores [ i ] ) ) ;
strtime [ sizeof strtime - 1 ] = ' \0 ' ;
V_DrawRightAlignedString ( x + 152 , y , 0 , strtime ) ;
}
}
else
{
if ( intertype = = int_match )
V_DrawRightAlignedString ( x + 152 + BASEVIDWIDTH / 2 , y , 0 , va ( " %u " , data . match . scores [ i ] ) ) ;
else if ( intertype = = int_race )
{
if ( players [ data . match . num [ i ] ] . pflags & PF_TIMEOVER )
snprintf ( strtime , sizeof strtime , " DNF " ) ;
else
snprintf ( strtime , sizeof strtime , " %i:%02i.%02i " , G_TicsToMinutes ( data . match . scores [ i ] , true ) ,
G_TicsToSeconds ( data . match . scores [ i ] ) , G_TicsToCentiseconds ( data . match . scores [ i ] ) ) ;
strtime [ sizeof strtime - 1 ] = ' \0 ' ;
V_DrawRightAlignedString ( x + 152 + BASEVIDWIDTH / 2 , y , 0 , strtime ) ;
}
}
}
y + = 16 ;
if ( y > 176 )
{
y = 48 ;
x + = BASEVIDWIDTH / 2 ;
}
}
}
else if ( intertype = = int_ctf | | intertype = = int_teammatch )
{
INT32 x = 4 , y = 0 ;
INT32 redplayers = 0 , blueplayers = 0 ;
char name [ MAXPLAYERNAME + 1 ] ;
// Show the team flags and the team score at the top instead of "RESULTS"
V_DrawSmallScaledPatch ( 128 - SHORT ( data . match . blueflag - > width ) / 4 , 2 , 0 , data . match . blueflag ) ;
V_DrawCenteredString ( 128 , 16 , 0 , va ( " %u " , bluescore ) ) ;
V_DrawSmallScaledPatch ( 192 - SHORT ( data . match . redflag - > width ) / 4 , 2 , 0 , data . match . redflag ) ;
V_DrawCenteredString ( 192 , 16 , 0 , va ( " %u " , redscore ) ) ;
// draw the level name
V_DrawCenteredString ( BASEVIDWIDTH / 2 , 24 , 0 , data . match . levelstring ) ;
V_DrawFill ( 4 , 42 , 312 , 1 , 0 ) ;
//vert. line
V_DrawFill ( 160 , 32 , 1 , 152 , 0 ) ;
//strings at the top of the list
V_DrawCenteredString ( x + 6 , 32 , V_YELLOWMAP , " # " ) ;
V_DrawCenteredString ( x + ( BASEVIDWIDTH / 2 ) + 6 , 32 , V_YELLOWMAP , " # " ) ;
V_DrawString ( x + 36 , 32 , V_YELLOWMAP , " NAME " ) ;
V_DrawString ( x + ( BASEVIDWIDTH / 2 ) + 36 , 32 , V_YELLOWMAP , " NAME " ) ;
V_DrawRightAlignedString ( x + 152 , 32 , V_YELLOWMAP , " SCORE " ) ;
V_DrawRightAlignedString ( x + ( BASEVIDWIDTH / 2 ) + 152 , 32 , V_YELLOWMAP , " SCORE " ) ;
for ( i = 0 ; i < data . match . numplayers ; i + + )
{
if ( playeringame [ data . match . num [ i ] ] & & ! ( data . match . spectator [ i ] ) )
{
UINT8 * colormap = R_GetTranslationColormap ( * data . match . character [ i ] , * data . match . color [ i ] , GTC_CACHE ) ;
if ( * data . match . color [ i ] = = SKINCOLOR_RED ) //red
{
if ( redplayers + + > 9 )
continue ;
x = 4 + ( BASEVIDWIDTH / 2 ) ;
y = ( redplayers * 16 ) + 32 ;
V_DrawCenteredString ( x + 6 , y , 0 , va ( " %d " , redplayers ) ) ;
}
else if ( * data . match . color [ i ] = = SKINCOLOR_BLUE ) //blue
{
if ( blueplayers + + > 9 )
continue ;
x = 4 ;
y = ( blueplayers * 16 ) + 32 ;
V_DrawCenteredString ( x + 6 , y , 0 , va ( " %d " , blueplayers ) ) ;
}
else
continue ;
// Draw the back sprite, it looks ugly if we don't
V_DrawSmallScaledPatch ( x + 16 , y - 4 , 0 , livesback ) ;
//color is ALWAYS going to be 6/7 here, no need to check if it's nonzero.
V_DrawSmallMappedPatch ( x + 16 , y - 4 , 0 , faceprefix [ * data . match . character [ i ] ] , colormap ) ;
strlcpy ( name , data . match . name [ i ] , 9 ) ;
V_DrawString ( x + 36 , y , V_ALLOWLOWERCASE , name ) ;
V_DrawRightAlignedString ( x + 152 , y , 0 , va ( " %u " , data . match . scores [ i ] ) ) ;
}
}
}
else if ( intertype = = int_classicrace )
{
INT32 x = 4 ;
INT32 y = 48 ;
UINT32 ptime , pring , pmaxring , pmonitor , pscore ;
char sstrtime [ 10 ] ;
// draw the level name
V_DrawCenteredString ( BASEVIDWIDTH / 2 , 8 , 0 , data . competition . levelstring ) ;
V_DrawFill ( 4 , 42 , 312 , 1 , 0 ) ;
V_DrawCenteredString ( x + 6 , 32 , V_YELLOWMAP , " # " ) ;
V_DrawString ( x + 36 , 32 , V_YELLOWMAP , " NAME " ) ;
// Time
V_DrawRightAlignedString ( x + 160 , 32 , V_YELLOWMAP , " TIME " ) ;
// Rings
2018-01-29 01:37:53 +00:00
V_DrawThinString ( x + 168 , 31 , V_YELLOWMAP , " RING " ) ;
2014-03-15 16:59:03 +00:00
// Total rings
2018-01-29 01:37:53 +00:00
V_DrawThinString ( x + 191 , 22 , V_YELLOWMAP , " TOTAL " ) ;
V_DrawThinString ( x + 196 , 31 , V_YELLOWMAP , " RING " ) ;
2014-03-15 16:59:03 +00:00
// Monitors
2018-01-29 01:37:53 +00:00
V_DrawThinString ( x + 223 , 22 , V_YELLOWMAP , " ITEM " ) ;
V_DrawThinString ( x + 229 , 31 , V_YELLOWMAP , " BOX " ) ;
2014-03-15 16:59:03 +00:00
// Score
V_DrawRightAlignedString ( x + 288 , 32 , V_YELLOWMAP , " SCORE " ) ;
// Points
V_DrawRightAlignedString ( x + 312 , 32 , V_YELLOWMAP , " PT " ) ;
for ( i = 0 ; i < data . competition . numplayers ; i + + )
{
ptime = ( data . competition . times [ i ] & ~ 0x80000000 ) ;
pring = ( data . competition . rings [ i ] & ~ 0x80000000 ) ;
pmaxring = ( data . competition . maxrings [ i ] & ~ 0x80000000 ) ;
pmonitor = ( data . competition . monitors [ i ] & ~ 0x80000000 ) ;
pscore = ( data . competition . scores [ i ] & ~ 0x80000000 ) ;
V_DrawCenteredString ( x + 6 , y , 0 , va ( " %d " , i + 1 ) ) ;
if ( playeringame [ data . competition . num [ i ] ] )
{
// Draw the back sprite, it looks ugly if we don't
V_DrawSmallScaledPatch ( x + 16 , y - 4 , 0 , livesback ) ;
if ( data . competition . color [ i ] = = 0 )
V_DrawSmallScaledPatch ( x + 16 , y - 4 , 0 , faceprefix [ * data . competition . character [ i ] ] ) ;
else
{
UINT8 * colormap = R_GetTranslationColormap ( * data . competition . character [ i ] , * data . competition . color [ i ] , GTC_CACHE ) ;
V_DrawSmallMappedPatch ( x + 16 , y - 4 , 0 , faceprefix [ * data . competition . character [ i ] ] , colormap ) ;
}
// already constrained to 8 characters
V_DrawString ( x + 36 , y , V_ALLOWLOWERCASE , data . competition . name [ i ] ) ;
if ( players [ data . competition . num [ i ] ] . pflags & PF_TIMEOVER )
snprintf ( sstrtime , sizeof sstrtime , " Time Over " ) ;
else if ( players [ data . competition . num [ i ] ] . lives < = 0 )
snprintf ( sstrtime , sizeof sstrtime , " Game Over " ) ;
else
snprintf ( sstrtime , sizeof sstrtime , " %i:%02i.%02i " , G_TicsToMinutes ( ptime , true ) ,
G_TicsToSeconds ( ptime ) , G_TicsToCentiseconds ( ptime ) ) ;
sstrtime [ sizeof sstrtime - 1 ] = ' \0 ' ;
// Time
2018-01-29 01:37:53 +00:00
V_DrawRightAlignedThinString ( x + 160 , y - 1 , ( ( data . competition . times [ i ] & 0x80000000 ) ? V_YELLOWMAP : 0 ) , sstrtime ) ;
2014-03-15 16:59:03 +00:00
// Rings
2018-01-29 01:37:53 +00:00
V_DrawRightAlignedThinString ( x + 188 , y - 1 , V_MONOSPACE | ( ( data . competition . rings [ i ] & 0x80000000 ) ? V_YELLOWMAP : 0 ) , va ( " %u " , pring ) ) ;
2014-03-15 16:59:03 +00:00
// Total rings
2018-01-29 01:37:53 +00:00
V_DrawRightAlignedThinString ( x + 216 , y - 1 , V_MONOSPACE | ( ( data . competition . maxrings [ i ] & 0x80000000 ) ? V_YELLOWMAP : 0 ) , va ( " %u " , pmaxring ) ) ;
2014-03-15 16:59:03 +00:00
// Monitors
2018-01-29 01:37:53 +00:00
V_DrawRightAlignedThinString ( x + 244 , y - 1 , V_MONOSPACE | ( ( data . competition . monitors [ i ] & 0x80000000 ) ? V_YELLOWMAP : 0 ) , va ( " %u " , pmonitor ) ) ;
2014-03-15 16:59:03 +00:00
// Score
2018-01-29 01:37:53 +00:00
V_DrawRightAlignedThinString ( x + 288 , y - 1 , V_MONOSPACE | ( ( data . competition . scores [ i ] & 0x80000000 ) ? V_YELLOWMAP : 0 ) , va ( " %u " , pscore ) ) ;
2014-03-15 16:59:03 +00:00
// Final Points
V_DrawRightAlignedString ( x + 312 , y , V_YELLOWMAP , va ( " %d " , data . competition . points [ i ] ) ) ;
}
y + = 16 ;
if ( y > 176 )
break ;
}
}
if ( timer )
V_DrawCenteredString ( BASEVIDWIDTH / 2 , 188 , V_YELLOWMAP ,
va ( " start in %d seconds " , timer / TICRATE ) ) ;
// Make it obvious that scrambling is happening next round.
if ( cv_scrambleonchange . value & & cv_teamscramble . value & & ( intertic / TICRATE % 2 = = 0 ) )
V_DrawCenteredString ( BASEVIDWIDTH / 2 , BASEVIDHEIGHT / 2 , V_YELLOWMAP , M_GetText ( " Teams will be scrambled next round! " ) ) ;
}
//
// Y_Ticker
//
// Manages fake score tally for single player end of act, and decides when intermission is over.
//
void Y_Ticker ( void )
{
if ( intertype = = int_none )
return ;
// Check for pause or menu up in single player
2015-01-01 19:50:31 +00:00
if ( paused | | P_AutoPause ( ) )
2014-03-15 16:59:03 +00:00
return ;
intertic + + ;
// Team scramble code for team match and CTF.
// Don't do this if we're going to automatically scramble teams next round.
if ( G_GametypeHasTeams ( ) & & cv_teamscramble . value & & ! cv_scrambleonchange . value & & server )
{
// If we run out of time in intermission, the beauty is that
// the P_Ticker() team scramble code will pick it up.
if ( ( intertic % ( TICRATE / 7 ) ) = = 0 )
P_DoTeamscrambling ( ) ;
}
// multiplayer uses timer (based on cv_inttime)
if ( timer )
{
if ( ! - - timer )
{
Y_EndIntermission ( ) ;
Y_FollowIntermission ( ) ;
return ;
}
}
// single player is hardcoded to go away after awhile
else if ( intertic = = endtic )
{
Y_EndIntermission ( ) ;
Y_FollowIntermission ( ) ;
return ;
}
if ( endtic ! = - 1 )
return ; // tally is done
2017-02-07 22:19:04 +00:00
/* // SRB2kart
2014-03-15 16:59:03 +00:00
if ( intertype = = int_coop ) // coop or single player, normal level
{
INT32 i ;
UINT32 oldscore = data . coop . score ;
boolean skip = false ;
boolean anybonuses = false ;
if ( ! intertic ) // first time only
2016-07-06 04:09:17 +00:00
S_ChangeMusicInternal ( " lclear " , false ) ; // don't loop it
2014-03-15 16:59:03 +00:00
if ( intertic < TICRATE ) // one second pause before tally begins
return ;
for ( i = 0 ; i < MAXPLAYERS ; i + + )
2016-08-21 02:15:06 +00:00
if ( playeringame [ i ] & & ( players [ i ] . cmd . buttons & BT_BRAKE | | players [ i ] . cmd . buttons & BT_ACCELERATE ) )
2014-03-15 16:59:03 +00:00
skip = true ;
// bonuses count down by 222 each tic
for ( i = 0 ; i < 4 ; + + i )
{
if ( ! data . coop . bonuses [ i ] . points )
continue ;
data . coop . bonuses [ i ] . points - = 222 ;
data . coop . total + = 222 ;
data . coop . score + = 222 ;
if ( data . coop . bonuses [ i ] . points < 0 | | skip = = true ) // too far?
{
data . coop . score + = data . coop . bonuses [ i ] . points ;
data . coop . total + = data . coop . bonuses [ i ] . points ;
data . coop . bonuses [ i ] . points = 0 ;
}
if ( data . coop . bonuses [ i ] . points > 0 )
anybonuses = true ;
}
if ( ! anybonuses )
{
endtic = intertic + 3 * TICRATE ; // 3 second pause after end of tally
S_StartSound ( NULL , sfx_chchng ) ; // cha-ching!
// Update when done with tally
if ( ( ! modifiedgame | | savemoddata ) & & ! ( netgame | | multiplayer ) & & ! demoplayback )
{
if ( M_UpdateUnlockablesAndExtraEmblems ( ) )
S_StartSound ( NULL , sfx_ncitem ) ;
G_SaveGameData ( ) ;
}
}
else if ( ! ( intertic & 1 ) )
S_StartSound ( NULL , sfx_ptally ) ; // tally sound effect
if ( data . coop . gotlife > 0 & & ( skip = = true | | data . coop . score % 50000 < oldscore % 50000 ) ) // just passed a 50000 point mark
{
// lives are already added since tally is fake, but play the music
P_PlayLivesJingle ( NULL ) ;
- - data . coop . gotlife ;
}
}
else if ( intertype = = int_spec ) // coop or single player, special stage
{
INT32 i ;
UINT32 oldscore = data . spec . score ;
boolean skip = false ;
static INT32 tallydonetic = 0 ;
if ( ! intertic ) // first time only
{
2016-07-06 04:09:17 +00:00
S_ChangeMusicInternal ( " lclear " , false ) ; // don't loop it
2014-03-15 16:59:03 +00:00
tallydonetic = 0 ;
}
if ( intertic < TICRATE ) // one second pause before tally begins
return ;
for ( i = 0 ; i < MAXPLAYERS ; i + + )
2016-08-21 02:15:06 +00:00
if ( playeringame [ i ] & & ( players [ i ] . cmd . buttons & BT_BRAKE | | players [ i ] . cmd . buttons & BT_ACCELERATE ) )
2014-03-15 16:59:03 +00:00
skip = true ;
if ( tallydonetic ! = 0 )
{
if ( intertic > tallydonetic )
{
2016-07-06 04:09:17 +00:00
endtic = intertic + 4 * TICRATE ; // 4 second pause after end of tally
2014-03-15 16:59:03 +00:00
S_StartSound ( NULL , sfx_flgcap ) ; // cha-ching!
}
return ;
}
// ring bonus counts down by 222 each tic
data . spec . bonus . points - = 222 ;
data . spec . score + = 222 ;
if ( data . spec . bonus . points < 0 | | skip = = true ) // went too far
{
data . spec . score + = data . spec . bonus . points ;
data . spec . bonus . points = 0 ;
}
if ( ! data . spec . bonus . points )
{
if ( data . spec . continues & 0x80 ) // don't set endtic yet!
tallydonetic = intertic + ( 3 * TICRATE ) / 2 ;
else // okay we're good.
2016-07-06 04:09:17 +00:00
endtic = intertic + 4 * TICRATE ; // 4 second pause after end of tally
2014-03-15 16:59:03 +00:00
S_StartSound ( NULL , sfx_chchng ) ; // cha-ching!
// Update when done with tally
if ( ( ! modifiedgame | | savemoddata ) & & ! ( netgame | | multiplayer ) & & ! demoplayback )
{
if ( M_UpdateUnlockablesAndExtraEmblems ( ) )
S_StartSound ( NULL , sfx_ncitem ) ;
G_SaveGameData ( ) ;
}
}
else if ( ! ( intertic & 1 ) )
S_StartSound ( NULL , sfx_ptally ) ; // tally sound effect
if ( data . spec . gotlife > 0 & & ( skip = = true | | data . spec . score % 50000 < oldscore % 50000 ) ) // just passed a 50000 point mark
{
// lives are already added since tally is fake, but play the music
P_PlayLivesJingle ( NULL ) ;
- - data . spec . gotlife ;
}
}
2017-02-07 22:19:04 +00:00
*/
if ( intertype = = int_timeattack )
{
if ( ! intertic )
endtic = intertic + 10 * TICRATE ; // 10 second pause after end of tally
}
else if ( intertype = = int_race )
{
INT32 q = 0 , r = 0 ;
/* // SRB2kart - removed temporarily.
if ( ! intertic ) {
if ( ! ( ( music_playing = = " karwin " ) // Mario Kart Win
| | ( music_playing = = " karok " ) // Mario Kart Ok
| | ( music_playing = = " karlos " ) ) ) // Mario Kart Lose
S_ChangeMusicInternal ( " racent " , true ) ; // Backup Plan
} */
if ( intertic < TICRATE | | intertic % 8 )
return ;
for ( q = 0 ; q < data . match . numplayers ; q + + )
{
if ( data . match . increase [ q ] ) {
data . match . increase [ q ] - - ;
r + + ;
}
}
if ( r )
S_StartSound ( NULL , sfx_menu1 ) ;
else
2017-10-17 00:23:26 +00:00
if ( modeattacking )
endtic = intertic + 10 * TICRATE ; // 10 second pause after end of tally
else
endtic = intertic + 3 * TICRATE ; // 3 second pause after end of tally
2017-02-07 22:19:04 +00:00
}
2014-03-15 16:59:03 +00:00
else if ( intertype = = int_match | | intertype = = int_ctf | | intertype = = int_teammatch ) // match
{
if ( ! intertic ) // first time only
2016-07-06 04:09:17 +00:00
S_ChangeMusicInternal ( " racent " , true ) ; // loop it
2014-03-15 16:59:03 +00:00
// If a player has left or joined, recalculate scores.
if ( data . match . numplayers ! = D_NumPlayers ( ) )
Y_CalculateMatchWinners ( ) ;
}
else if ( intertype = = int_race | | intertype = = int_classicrace ) // race
{
if ( ! intertic ) // first time only
2016-07-06 04:09:17 +00:00
S_ChangeMusicInternal ( " racent " , true ) ; // loop it
2014-03-15 16:59:03 +00:00
// Don't bother recalcing for race. It doesn't make as much sense.
}
}
//
2014-11-12 00:55:07 +00:00
// Y_UpdateRecordReplays
2014-03-15 16:59:03 +00:00
//
2014-11-12 00:55:07 +00:00
// Update replay files/data, etc. for Record Attack
// See G_SetNightsRecords for NiGHTS Attack.
2014-03-15 16:59:03 +00:00
//
2014-11-12 00:55:07 +00:00
static void Y_UpdateRecordReplays ( void )
2014-03-15 16:59:03 +00:00
{
const size_t glen = strlen ( srb2home ) + 1 + strlen ( " replay " ) + 1 + strlen ( timeattackfolder ) + 1 + strlen ( " MAPXX " ) + 1 ;
char * gpath ;
char lastdemo [ 256 ] , bestdemo [ 256 ] ;
UINT8 earnedEmblems ;
// Record new best time
if ( ! mainrecords [ gamemap - 1 ] )
G_AllocMainRecordData ( gamemap - 1 ) ;
if ( ( mainrecords [ gamemap - 1 ] - > time = = 0 ) | | ( players [ consoleplayer ] . realtime < mainrecords [ gamemap - 1 ] - > time ) )
mainrecords [ gamemap - 1 ] - > time = players [ consoleplayer ] . realtime ;
2018-01-22 00:15:26 +00:00
if ( ( mainrecords [ gamemap - 1 ] - > lap = = 0 ) | | ( bestlap < mainrecords [ gamemap - 1 ] - > lap ) )
mainrecords [ gamemap - 1 ] - > lap = bestlap ;
2014-03-15 16:59:03 +00:00
// Save demo!
bestdemo [ 255 ] = ' \0 ' ;
lastdemo [ 255 ] = ' \0 ' ;
2018-01-22 00:15:26 +00:00
G_SetDemoTime ( players [ consoleplayer ] . realtime , bestlap ) ;
2014-03-15 16:59:03 +00:00
G_CheckDemoStatus ( ) ;
I_mkdir ( va ( " %s " PATHSEP " replay " , srb2home ) , 0755 ) ;
I_mkdir ( va ( " %s " PATHSEP " replay " PATHSEP " %s " , srb2home , timeattackfolder ) , 0755 ) ;
if ( ( gpath = malloc ( glen ) ) = = NULL )
I_Error ( " Out of memory for replay filepath \n " ) ;
sprintf ( gpath , " %s " PATHSEP " replay " PATHSEP " %s " PATHSEP " %s " , srb2home , timeattackfolder , G_BuildMapName ( gamemap ) ) ;
snprintf ( lastdemo , 255 , " %s-%s-last.lmp " , gpath , cv_chooseskin . string ) ;
if ( FIL_FileExists ( lastdemo ) )
{
UINT8 * buf ;
size_t len = FIL_ReadFile ( lastdemo , & buf ) ;
snprintf ( bestdemo , 255 , " %s-%s-time-best.lmp " , gpath , cv_chooseskin . string ) ;
if ( ! FIL_FileExists ( bestdemo ) | | G_CmpDemoTime ( bestdemo , lastdemo ) & 1 )
{ // Better time, save this demo.
if ( FIL_FileExists ( bestdemo ) )
remove ( bestdemo ) ;
FIL_WriteFile ( bestdemo , buf , len ) ;
CONS_Printf ( " \x83 %s \x80 %s '%s' \n " , M_GetText ( " NEW RECORD TIME! " ) , M_GetText ( " Saved replay as " ) , bestdemo ) ;
}
2018-01-22 00:15:26 +00:00
snprintf ( bestdemo , 255 , " %s-%s-lap-best.lmp " , gpath , cv_chooseskin . string ) ;
if ( ! FIL_FileExists ( bestdemo ) | | G_CmpDemoTime ( bestdemo , lastdemo ) & ( 1 < < 1 ) )
{ // Better lap time, save this demo.
if ( FIL_FileExists ( bestdemo ) )
remove ( bestdemo ) ;
FIL_WriteFile ( bestdemo , buf , len ) ;
CONS_Printf ( " \x83 %s \x80 %s '%s' \n " , M_GetText ( " NEW RECORD LAP! " ) , M_GetText ( " Saved replay as " ) , bestdemo ) ;
}
2014-03-15 16:59:03 +00:00
//CONS_Printf("%s '%s'\n", M_GetText("Saved replay as"), lastdemo);
Z_Free ( buf ) ;
}
free ( gpath ) ;
// Check emblems when level data is updated
if ( ( earnedEmblems = M_CheckLevelEmblems ( ) ) )
CONS_Printf ( M_GetText ( " \x82 " " Earned %hu emblem%s for Record Attack records. \n " ) , ( UINT16 ) earnedEmblems , earnedEmblems > 1 ? " s " : " " ) ;
// Update timeattack menu's replay availability.
CV_AddValue ( & cv_nextmap , 1 ) ;
CV_AddValue ( & cv_nextmap , - 1 ) ;
}
//
// Y_StartIntermission
//
// Called by G_DoCompleted. Sets up data for intermission drawer/ticker.
//
void Y_StartIntermission ( void )
{
INT32 i ;
intertic = - 1 ;
# ifdef PARANOIA
if ( endtic ! = - 1 )
I_Error ( " endtic is dirty " ) ;
# endif
if ( ! multiplayer )
{
timer = 0 ;
2017-02-07 22:19:04 +00:00
/*
2014-03-15 16:59:03 +00:00
if ( G_IsSpecialStage ( gamemap ) )
intertype = ( maptol & TOL_NIGHTS ) ? int_nightsspec : int_spec ;
else
intertype = ( maptol & TOL_NIGHTS ) ? int_nights : int_coop ;
2017-02-07 22:19:04 +00:00
*/
2017-10-17 00:23:26 +00:00
/* // srb2kart: time attack tally is UGLY rn
2017-02-07 22:19:04 +00:00
if ( modeattacking )
intertype = int_timeattack ;
else
2017-10-17 00:23:26 +00:00
*/
2017-02-07 22:19:04 +00:00
intertype = int_race ;
2014-03-15 16:59:03 +00:00
}
else
{
if ( cv_inttime . value = = 0 & & gametype = = GT_COOP )
timer = 0 ;
else
{
timer = cv_inttime . value * TICRATE ;
if ( ! timer )
timer = 1 ;
}
2017-02-07 22:19:04 +00:00
/* // SRB2kart
2014-03-15 16:59:03 +00:00
if ( gametype = = GT_COOP )
{
// Nights intermission is single player only
// Don't add it here
if ( G_IsSpecialStage ( gamemap ) )
intertype = int_spec ;
else
intertype = int_coop ;
}
2017-02-07 22:19:04 +00:00
else */
if ( gametype = = GT_TEAMMATCH )
2014-03-15 16:59:03 +00:00
intertype = int_teammatch ;
else if ( gametype = = GT_MATCH
| | gametype = = GT_TAG
2015-01-01 19:50:31 +00:00
| | gametype = = GT_HIDEANDSEEK )
2014-03-15 16:59:03 +00:00
intertype = int_match ;
else if ( gametype = = GT_RACE )
intertype = int_race ;
else if ( gametype = = GT_COMPETITION )
intertype = int_classicrace ;
else if ( gametype = = GT_CTF )
intertype = int_ctf ;
}
// We couldn't display the intermission even if we wanted to.
2017-05-19 15:31:23 +00:00
// But we still need to give the players their score bonuses, dummy.
//if (dedicated) return;
2014-03-15 16:59:03 +00:00
// This should always exist, but just in case...
if ( ! mapheaderinfo [ prevmap ] )
P_AllocMapHeader ( prevmap ) ;
switch ( intertype )
{
case int_nights :
// Can't fail
2018-01-22 00:15:26 +00:00
//G_SetNightsRecords();
2014-03-15 16:59:03 +00:00
// Check records
{
UINT8 earnedEmblems = M_CheckLevelEmblems ( ) ;
if ( earnedEmblems )
CONS_Printf ( M_GetText ( " \x82 " " Earned %hu emblem%s for NiGHTS records. \n " ) , ( UINT16 ) earnedEmblems , earnedEmblems > 1 ? " s " : " " ) ;
}
// fall back into the coop intermission for now
2017-02-07 22:19:04 +00:00
intertype = int_timeattack ;
2017-09-28 13:39:47 +00:00
/* FALLTHRU */
2017-02-07 22:19:04 +00:00
case int_timeattack : // coop or single player, normal level // SRB2kart 230117 - replaced int_coop
2014-03-15 16:59:03 +00:00
{
// award time and ring bonuses
2017-02-07 22:19:04 +00:00
// Y_AwardCoopBonuses();
2014-03-15 16:59:03 +00:00
// setup time data
data . coop . tics = players [ consoleplayer ] . realtime ;
if ( ( ! modifiedgame | | savemoddata ) & & ! multiplayer & & ! demoplayback )
{
// Update visitation flags
mapvisited [ gamemap - 1 ] | = MV_BEATEN ;
if ( ALL7EMERALDS ( emeralds ) )
mapvisited [ gamemap - 1 ] | = MV_ALLEMERALDS ;
2018-01-22 00:15:26 +00:00
/*if (ultimatemode)
2014-03-15 16:59:03 +00:00
mapvisited [ gamemap - 1 ] | = MV_ULTIMATE ;
if ( data . coop . gotperfbonus )
2018-01-22 00:15:26 +00:00
mapvisited [ gamemap - 1 ] | = MV_PERFECT ; */
2014-03-15 16:59:03 +00:00
if ( modeattacking = = ATTACKING_RECORD )
2014-11-12 00:55:07 +00:00
Y_UpdateRecordReplays ( ) ;
2014-03-15 16:59:03 +00:00
}
for ( i = 0 ; i < 4 ; + + i )
data . coop . bonuspatches [ i ] = W_CachePatchName ( data . coop . bonuses [ i ] . patch , PU_STATIC ) ;
data . coop . ptotal = W_CachePatchName ( " YB_TOTAL " , PU_STATIC ) ;
// get act number
if ( mapheaderinfo [ prevmap ] - > actnum )
data . coop . ttlnum = W_CachePatchName ( va ( " TTL%.2d " , mapheaderinfo [ prevmap ] - > actnum ) ,
PU_STATIC ) ;
else
data . coop . ttlnum = W_CachePatchName ( " TTL01 " , PU_STATIC ) ;
// get background patches
widebgpatch = W_CachePatchName ( " INTERSCW " , PU_STATIC ) ;
bgpatch = W_CachePatchName ( " INTERSCR " , PU_STATIC ) ;
// grab an interscreen if appropriate
if ( mapheaderinfo [ gamemap - 1 ] - > interscreen [ 0 ] ! = ' # ' )
{
interpic = W_CachePatchName ( mapheaderinfo [ gamemap - 1 ] - > interscreen , PU_STATIC ) ;
useinterpic = true ;
usebuffer = false ;
}
else
{
useinterpic = false ;
2014-03-21 20:28:41 +00:00
# ifdef HWRENDER
if ( rendermode = = render_opengl )
usebuffer = true ; // This needs to be here for OpenGL, otherwise usebuffer is never set to true for it, and thus there's no screenshot in the intermission
# endif
2014-03-15 16:59:03 +00:00
}
usetile = false ;
// set up the "got through act" message according to skin name
2014-04-14 05:14:58 +00:00
// too long so just show "YOU GOT THROUGH THE ACT"
if ( strlen ( skins [ players [ consoleplayer ] . skin ] . realname ) > 13 )
2014-03-15 16:59:03 +00:00
{
2014-04-14 05:14:58 +00:00
strcpy ( data . coop . passed1 , " YOU GOT " ) ;
strcpy ( data . coop . passed2 , ( mapheaderinfo [ gamemap - 1 ] - > actnum ) ? " THROUGH ACT " : " THROUGH THE ACT " ) ;
2014-03-15 16:59:03 +00:00
}
2014-04-14 05:14:58 +00:00
// long enough that "X GOT" won't fit so use "X PASSED THE ACT"
else if ( strlen ( skins [ players [ consoleplayer ] . skin ] . realname ) > 8 )
2014-03-15 16:59:03 +00:00
{
strcpy ( data . coop . passed1 , skins [ players [ consoleplayer ] . skin ] . realname ) ;
2014-04-14 05:14:58 +00:00
strcpy ( data . coop . passed2 , ( mapheaderinfo [ gamemap - 1 ] - > actnum ) ? " PASSED ACT " : " PASSED THE ACT " ) ;
}
// length is okay for normal use
else
{
snprintf ( data . coop . passed1 , sizeof data . coop . passed1 , " %s GOT " ,
skins [ players [ consoleplayer ] . skin ] . realname ) ;
strcpy ( data . coop . passed2 , ( mapheaderinfo [ gamemap - 1 ] - > actnum ) ? " THROUGH ACT " : " THROUGH THE ACT " ) ;
}
// set X positions
if ( mapheaderinfo [ gamemap - 1 ] - > actnum )
{
2014-03-15 16:59:03 +00:00
data . coop . passedx1 = 62 + ( 176 - V_LevelNameWidth ( data . coop . passed1 ) ) / 2 ;
2014-04-14 05:14:58 +00:00
data . coop . passedx2 = 62 + ( 176 - V_LevelNameWidth ( data . coop . passed2 ) ) / 2 ;
}
else
{
data . coop . passedx1 = ( BASEVIDWIDTH - V_LevelNameWidth ( data . coop . passed1 ) ) / 2 ;
data . coop . passedx2 = ( BASEVIDWIDTH - V_LevelNameWidth ( data . coop . passed2 ) ) / 2 ;
2014-03-15 16:59:03 +00:00
}
2014-04-14 05:14:58 +00:00
// The above value is not precalculated because it needs only be computed once
// at the start of intermission, and precalculating it would preclude mods
// changing the font to one of a slightly different width.
2014-03-15 16:59:03 +00:00
break ;
}
2017-02-07 22:19:04 +00:00
/* // SRB2kart 230117 - removed
2014-03-15 16:59:03 +00:00
case int_nightsspec :
if ( modeattacking & & stagefailed )
{
// Nuh-uh. Get out of here.
Y_EndIntermission ( ) ;
Y_FollowIntermission ( ) ;
break ;
}
if ( ! stagefailed )
G_SetNightsRecords ( ) ;
// Check records
{
UINT8 earnedEmblems = M_CheckLevelEmblems ( ) ;
if ( earnedEmblems )
CONS_Printf ( M_GetText ( " \x82 " " Earned %hu emblem%s for NiGHTS records. \n " ) , ( UINT16 ) earnedEmblems , earnedEmblems > 1 ? " s " : " " ) ;
}
// fall back into the special stage intermission for now
intertype = int_spec ;
2017-10-17 20:23:38 +00:00
// FALLTHRU
2014-03-15 16:59:03 +00:00
case int_spec : // coop or single player, special stage
{
// Update visitation flags?
2014-03-17 12:13:16 +00:00
if ( ( ! modifiedgame | | savemoddata ) & & ! multiplayer & & ! demoplayback )
{
if ( ! stagefailed )
mapvisited [ gamemap - 1 ] | = MV_BEATEN ;
}
2014-03-15 16:59:03 +00:00
// give out ring bonuses
Y_AwardSpecialStageBonus ( ) ;
data . spec . bonuspatch = W_CachePatchName ( data . spec . bonus . patch , PU_STATIC ) ;
data . spec . pscore = W_CachePatchName ( " YB_SCORE " , PU_STATIC ) ;
data . spec . pcontinues = W_CachePatchName ( " YB_CONTI " , PU_STATIC ) ;
// get background tile
bgtile = W_CachePatchName ( " SPECTILE " , PU_STATIC ) ;
// grab an interscreen if appropriate
if ( mapheaderinfo [ gamemap - 1 ] - > interscreen [ 0 ] ! = ' # ' )
{
interpic = W_CachePatchName ( mapheaderinfo [ gamemap - 1 ] - > interscreen , PU_STATIC ) ;
useinterpic = true ;
}
else
useinterpic = false ;
// tile if using the default background
usetile = ! useinterpic ;
// get special stage specific patches
2017-02-18 18:39:25 +00:00
if ( ! stagefailed & & ALL7EMERALDS ( emeralds ) )
2014-03-15 16:59:03 +00:00
{
data . spec . cemerald = W_CachePatchName ( " GOTEMALL " , PU_STATIC ) ;
data . spec . headx = 70 ;
data . spec . nowsuper = players [ consoleplayer ] . skin
? NULL : W_CachePatchName ( " NOWSUPER " , PU_STATIC ) ;
}
else
{
data . spec . cemerald = W_CachePatchName ( " CEMERALD " , PU_STATIC ) ;
data . spec . headx = 48 ;
data . spec . nowsuper = NULL ;
2017-02-18 18:39:25 +00:00
}
2016-07-06 04:09:17 +00:00
// Super form stuff (normally blank)
data . spec . passed3 [ 0 ] = ' \0 ' ;
data . spec . passed4 [ 0 ] = ' \0 ' ;
2016-03-31 13:51:04 +00:00
// Super form stuff (normally blank)
data . spec . passed3 [ 0 ] = ' \0 ' ;
data . spec . passed4 [ 0 ] = ' \0 ' ;
2014-03-15 16:59:03 +00:00
// set up the "got through act" message according to skin name
if ( stagefailed )
{
strcpy ( data . spec . passed2 , " SPECIAL STAGE " ) ;
data . spec . passed1 [ 0 ] = ' \0 ' ;
}
else if ( ALL7EMERALDS ( emeralds ) )
{
snprintf ( data . spec . passed1 ,
sizeof data . spec . passed1 , " %s " ,
skins [ players [ consoleplayer ] . skin ] . realname ) ;
data . spec . passed1 [ sizeof data . spec . passed1 - 1 ] = ' \0 ' ;
strcpy ( data . spec . passed2 , " GOT THEM ALL! " ) ;
2016-07-06 04:09:17 +00:00
if ( skins [ players [ consoleplayer ] . skin ] . flags & SF_SUPER )
{
strcpy ( data . spec . passed3 , " CAN NOW BECOME " ) ;
snprintf ( data . spec . passed4 ,
sizeof data . spec . passed4 , " SUPER %s " ,
skins [ players [ consoleplayer ] . skin ] . realname ) ;
data . spec . passed4 [ sizeof data . spec . passed4 - 1 ] = ' \0 ' ;
}
2014-03-15 16:59:03 +00:00
}
else
{
2016-07-06 04:09:17 +00:00
if ( strlen ( skins [ players [ consoleplayer ] . skin ] . realname ) < = SKINNAMESIZE - 5 )
2014-03-15 16:59:03 +00:00
{
snprintf ( data . spec . passed1 ,
sizeof data . spec . passed1 , " %s GOT " ,
skins [ players [ consoleplayer ] . skin ] . realname ) ;
data . spec . passed1 [ sizeof data . spec . passed1 - 1 ] = ' \0 ' ;
}
else
strcpy ( data . spec . passed1 , " YOU GOT " ) ;
strcpy ( data . spec . passed2 , " A CHAOS EMERALD " ) ;
}
data . spec . passedx1 = ( BASEVIDWIDTH - V_LevelNameWidth ( data . spec . passed1 ) ) / 2 ;
data . spec . passedx2 = ( BASEVIDWIDTH - V_LevelNameWidth ( data . spec . passed2 ) ) / 2 ;
2016-07-06 04:09:17 +00:00
data . spec . passedx3 = ( BASEVIDWIDTH - V_LevelNameWidth ( data . spec . passed3 ) ) / 2 ;
data . spec . passedx4 = ( BASEVIDWIDTH - V_LevelNameWidth ( data . spec . passed4 ) ) / 2 ;
2014-03-15 16:59:03 +00:00
break ;
2017-02-07 22:19:04 +00:00
} */
2014-03-15 16:59:03 +00:00
case int_match :
{
// Calculate who won
Y_CalculateMatchWinners ( ) ;
// set up the levelstring
2017-10-18 00:04:46 +00:00
if ( mapheaderinfo [ prevmap ] - > zonttl )
{
if ( mapheaderinfo [ prevmap ] - > actnum )
snprintf ( data . match . levelstring ,
sizeof data . match . levelstring ,
" %.32s %.32s * %d * " ,
mapheaderinfo [ prevmap ] - > lvlttl , mapheaderinfo [ prevmap ] - > zonttl , mapheaderinfo [ prevmap ] - > actnum ) ;
else
snprintf ( data . match . levelstring ,
sizeof data . match . levelstring ,
" * %.32s %.32s * " ,
mapheaderinfo [ prevmap ] - > lvlttl , mapheaderinfo [ prevmap ] - > zonttl ) ;
}
2014-03-15 16:59:03 +00:00
else
2017-10-18 00:04:46 +00:00
{
if ( mapheaderinfo [ prevmap ] - > actnum )
snprintf ( data . match . levelstring ,
sizeof data . match . levelstring ,
" %.32s * %d * " ,
mapheaderinfo [ prevmap ] - > lvlttl , mapheaderinfo [ prevmap ] - > actnum ) ;
else
snprintf ( data . match . levelstring ,
sizeof data . match . levelstring ,
" * %.32s * " ,
mapheaderinfo [ prevmap ] - > lvlttl ) ;
}
2014-03-15 16:59:03 +00:00
data . match . levelstring [ sizeof data . match . levelstring - 1 ] = ' \0 ' ;
// get RESULT header
data . match . result =
W_CachePatchName ( " RESULT " , PU_STATIC ) ;
bgtile = W_CachePatchName ( " SRB2BACK " , PU_STATIC ) ;
usetile = true ;
useinterpic = false ;
break ;
}
case int_race : // (time-only race)
{
2017-10-17 00:23:26 +00:00
if ( ( ! modifiedgame | | savemoddata ) & & ! multiplayer & & ! demoplayback ) // remove this once we have a proper time attack screen
{
// setup time data
data . coop . tics = players [ consoleplayer ] . realtime ;
2018-02-23 01:04:52 +00:00
2017-10-17 00:23:26 +00:00
// Update visitation flags
mapvisited [ gamemap - 1 ] | = MV_BEATEN ;
if ( ALL7EMERALDS ( emeralds ) )
mapvisited [ gamemap - 1 ] | = MV_ALLEMERALDS ;
2018-01-22 00:15:26 +00:00
/*if (ultimatemode)
2017-10-17 00:23:26 +00:00
mapvisited [ gamemap - 1 ] | = MV_ULTIMATE ;
if ( data . coop . gotperfbonus )
2018-01-22 00:15:26 +00:00
mapvisited [ gamemap - 1 ] | = MV_PERFECT ; */
2017-10-17 00:23:26 +00:00
if ( modeattacking = = ATTACKING_RECORD )
Y_UpdateRecordReplays ( ) ;
}
2018-02-23 01:04:52 +00:00
2014-03-15 16:59:03 +00:00
// Calculate who won
2017-02-07 22:19:04 +00:00
Y_CalculateTournamentPoints ( ) ;
2014-03-15 16:59:03 +00:00
// set up the levelstring
2017-10-17 22:23:36 +00:00
if ( mapheaderinfo [ prevmap ] - > zonttl )
{
if ( mapheaderinfo [ prevmap ] - > actnum )
snprintf ( data . match . levelstring ,
sizeof data . match . levelstring ,
" %.32s %.32s * %d * " ,
mapheaderinfo [ prevmap ] - > lvlttl , mapheaderinfo [ prevmap ] - > zonttl , mapheaderinfo [ prevmap ] - > actnum ) ;
else
snprintf ( data . match . levelstring ,
sizeof data . match . levelstring ,
" * %.32s %.32s * " ,
mapheaderinfo [ prevmap ] - > lvlttl , mapheaderinfo [ prevmap ] - > zonttl ) ;
}
2014-03-15 16:59:03 +00:00
else
2017-10-17 22:23:36 +00:00
{
if ( mapheaderinfo [ prevmap ] - > actnum )
snprintf ( data . match . levelstring ,
sizeof data . match . levelstring ,
" %.32s * %d * " ,
mapheaderinfo [ prevmap ] - > lvlttl , mapheaderinfo [ prevmap ] - > actnum ) ;
else
snprintf ( data . match . levelstring ,
sizeof data . match . levelstring ,
" * %.32s * " ,
mapheaderinfo [ prevmap ] - > lvlttl ) ;
}
2014-03-15 16:59:03 +00:00
data . match . levelstring [ sizeof data . match . levelstring - 1 ] = ' \0 ' ;
// get RESULT header
2017-02-07 22:19:04 +00:00
//data.match.result = W_CachePatchName("RESULT", PU_STATIC);
2014-03-15 16:59:03 +00:00
bgtile = W_CachePatchName ( " SRB2BACK " , PU_STATIC ) ;
usetile = true ;
useinterpic = false ;
break ;
}
case int_teammatch :
case int_ctf :
{
// Calculate who won
Y_CalculateMatchWinners ( ) ;
// set up the levelstring
if ( mapheaderinfo [ prevmap ] - > actnum )
snprintf ( data . match . levelstring ,
sizeof data . match . levelstring ,
" %.32s * %d * " ,
mapheaderinfo [ prevmap ] - > lvlttl , mapheaderinfo [ prevmap ] - > actnum ) ;
else
snprintf ( data . match . levelstring ,
sizeof data . match . levelstring ,
" * %.32s * " ,
mapheaderinfo [ prevmap ] - > lvlttl ) ;
data . match . levelstring [ sizeof data . match . levelstring - 1 ] = ' \0 ' ;
if ( intertype = = int_ctf )
{
data . match . redflag = rflagico ;
data . match . blueflag = bflagico ;
}
else // team match
{
data . match . redflag = rmatcico ;
data . match . blueflag = bmatcico ;
}
bgtile = W_CachePatchName ( " SRB2BACK " , PU_STATIC ) ;
usetile = true ;
useinterpic = false ;
break ;
}
case int_classicrace : // classic (full race)
{
// find out who won
Y_CalculateCompetitionWinners ( ) ;
// set up the levelstring
if ( mapheaderinfo [ prevmap ] - > actnum )
snprintf ( data . competition . levelstring ,
sizeof data . competition . levelstring ,
" %.32s * %d * " ,
mapheaderinfo [ prevmap ] - > lvlttl , mapheaderinfo [ prevmap ] - > actnum ) ;
else
snprintf ( data . competition . levelstring ,
sizeof data . competition . levelstring ,
" * %.32s * " ,
mapheaderinfo [ prevmap ] - > lvlttl ) ;
data . competition . levelstring [ sizeof data . competition . levelstring - 1 ] = ' \0 ' ;
// get background tile
bgtile = W_CachePatchName ( " SRB2BACK " , PU_STATIC ) ;
usetile = true ;
useinterpic = false ;
break ;
}
case int_none :
default :
break ;
}
}
//
// Y_CalculateMatchWinners
//
static void Y_CalculateMatchWinners ( void )
{
INT32 i , j ;
boolean completed [ MAXPLAYERS ] ;
// Initialize variables
memset ( data . match . scores , 0 , sizeof ( data . match . scores ) ) ;
memset ( data . match . color , 0 , sizeof ( data . match . color ) ) ;
memset ( data . match . character , 0 , sizeof ( data . match . character ) ) ;
memset ( data . match . spectator , 0 , sizeof ( data . match . spectator ) ) ;
memset ( completed , 0 , sizeof ( completed ) ) ;
data . match . numplayers = 0 ;
i = j = 0 ;
for ( j = 0 ; j < MAXPLAYERS ; j + + )
{
if ( ! playeringame [ j ] )
continue ;
for ( i = 0 ; i < MAXPLAYERS ; i + + )
{
if ( ! playeringame [ i ] )
continue ;
if ( players [ i ] . score > = data . match . scores [ data . match . numplayers ] & & completed [ i ] = = false )
{
data . match . scores [ data . match . numplayers ] = players [ i ] . score ;
data . match . color [ data . match . numplayers ] = & players [ i ] . skincolor ;
data . match . character [ data . match . numplayers ] = & players [ i ] . skin ;
data . match . name [ data . match . numplayers ] = player_names [ i ] ;
data . match . spectator [ data . match . numplayers ] = players [ i ] . spectator ;
data . match . num [ data . match . numplayers ] = i ;
}
}
completed [ data . match . num [ data . match . numplayers ] ] = true ;
data . match . numplayers + + ;
}
}
2017-02-07 22:19:04 +00:00
/*
2014-03-15 16:59:03 +00:00
//
// Y_CalculateTimeRaceWinners
//
static void Y_CalculateTimeRaceWinners ( void )
{
INT32 i , j ;
boolean completed [ MAXPLAYERS ] ;
// Initialize variables
for ( i = 0 ; i < MAXPLAYERS ; i + + )
data . match . scores [ i ] = INT32_MAX ;
memset ( data . match . color , 0 , sizeof ( data . match . color ) ) ;
memset ( data . match . character , 0 , sizeof ( data . match . character ) ) ;
memset ( data . match . spectator , 0 , sizeof ( data . match . spectator ) ) ;
memset ( completed , 0 , sizeof ( completed ) ) ;
data . match . numplayers = 0 ;
i = j = 0 ;
for ( j = 0 ; j < MAXPLAYERS ; j + + )
{
if ( ! playeringame [ j ] )
continue ;
for ( i = 0 ; i < MAXPLAYERS ; i + + )
{
if ( ! playeringame [ i ] )
continue ;
if ( players [ i ] . realtime < = data . match . scores [ data . match . numplayers ] & & completed [ i ] = = false )
{
data . match . scores [ data . match . numplayers ] = players [ i ] . realtime ;
data . match . color [ data . match . numplayers ] = & players [ i ] . skincolor ;
data . match . character [ data . match . numplayers ] = & players [ i ] . skin ;
data . match . name [ data . match . numplayers ] = player_names [ i ] ;
data . match . num [ data . match . numplayers ] = i ;
}
}
completed [ data . match . num [ data . match . numplayers ] ] = true ;
data . match . numplayers + + ;
}
}
2017-02-07 22:19:04 +00:00
*/
2014-03-15 16:59:03 +00:00
//
// Y_CalculateCompetitionWinners
//
static void Y_CalculateCompetitionWinners ( void )
{
INT32 i , j ;
boolean bestat [ 5 ] ;
boolean completed [ MAXPLAYERS ] ;
INT32 winner ; // shortcut
UINT32 points [ MAXPLAYERS ] ;
UINT32 times [ MAXPLAYERS ] ;
UINT32 rings [ MAXPLAYERS ] ;
UINT32 maxrings [ MAXPLAYERS ] ;
UINT32 monitors [ MAXPLAYERS ] ;
UINT32 scores [ MAXPLAYERS ] ;
memset ( data . competition . points , 0 , sizeof ( data . competition . points ) ) ;
memset ( points , 0 , sizeof ( points ) ) ;
memset ( completed , 0 , sizeof ( completed ) ) ;
// Award points.
for ( i = 0 ; i < MAXPLAYERS ; i + + )
{
if ( ! playeringame [ i ] )
continue ;
for ( j = 0 ; j < 5 ; j + + )
bestat [ j ] = true ;
times [ i ] = players [ i ] . realtime ;
rings [ i ] = ( UINT32 ) max ( players [ i ] . health - 1 , 0 ) ;
maxrings [ i ] = ( UINT32 ) players [ i ] . totalring ;
monitors [ i ] = ( UINT32 ) players [ i ] . numboxes ;
scores [ i ] = ( UINT32 ) min ( players [ i ] . score , 99999990 ) ;
for ( j = 0 ; j < MAXPLAYERS ; j + + )
{
if ( ! playeringame [ j ] | | j = = i )
continue ;
if ( players [ i ] . realtime < = players [ j ] . realtime )
points [ i ] + + ;
else
bestat [ 0 ] = false ;
if ( max ( players [ i ] . health - 1 , 0 ) > = max ( players [ j ] . health - 1 , 0 ) )
points [ i ] + + ;
else
bestat [ 1 ] = false ;
if ( players [ i ] . totalring > = players [ j ] . totalring )
points [ i ] + + ;
else
bestat [ 2 ] = false ;
if ( players [ i ] . numboxes > = players [ j ] . numboxes )
points [ i ] + + ;
else
bestat [ 3 ] = false ;
if ( players [ i ] . score > = players [ j ] . score )
points [ i ] + + ;
else
bestat [ 4 ] = false ;
}
// Highlight best scores
if ( bestat [ 0 ] )
times [ i ] | = 0x80000000 ;
if ( bestat [ 1 ] )
rings [ i ] | = 0x80000000 ;
if ( bestat [ 2 ] )
maxrings [ i ] | = 0x80000000 ;
if ( bestat [ 3 ] )
monitors [ i ] | = 0x80000000 ;
if ( bestat [ 4 ] )
scores [ i ] | = 0x80000000 ;
}
// Now we go through and set the data.competition struct properly
data . competition . numplayers = 0 ;
for ( i = 0 ; i < MAXPLAYERS ; i + + )
{
if ( ! playeringame [ i ] )
continue ;
winner = 0 ;
for ( j = 0 ; j < MAXPLAYERS ; j + + )
{
if ( ! playeringame [ j ] )
continue ;
if ( points [ j ] > = data . competition . points [ data . competition . numplayers ] & & completed [ j ] = = false )
{
data . competition . points [ data . competition . numplayers ] = points [ j ] ;
data . competition . num [ data . competition . numplayers ] = winner = j ;
}
}
// We know this person won this spot, now let's set everything appropriately
data . competition . times [ data . competition . numplayers ] = times [ winner ] ;
data . competition . rings [ data . competition . numplayers ] = rings [ winner ] ;
data . competition . maxrings [ data . competition . numplayers ] = maxrings [ winner ] ;
data . competition . monitors [ data . competition . numplayers ] = monitors [ winner ] ;
data . competition . scores [ data . competition . numplayers ] = scores [ winner ] ;
snprintf ( data . competition . name [ data . competition . numplayers ] , 9 , " %s " , player_names [ winner ] ) ;
data . competition . name [ data . competition . numplayers ] [ 8 ] = ' \0 ' ;
data . competition . color [ data . competition . numplayers ] = & players [ winner ] . skincolor ;
data . competition . character [ data . competition . numplayers ] = & players [ winner ] . skin ;
completed [ winner ] = true ;
data . competition . numplayers + + ;
}
}
// ============
// COOP BONUSES
// ============
//
// Y_SetNullBonus
// No bonus in this slot, but we need to set some things anyway.
//
static void Y_SetNullBonus ( player_t * player , y_bonus_t * bstruct )
{
( void ) player ;
memset ( bstruct , 0 , sizeof ( y_bonus_t ) ) ;
strncpy ( bstruct - > patch , " MISSING " , sizeof ( bstruct - > patch ) ) ;
}
//
// Y_SetTimeBonus
//
static void Y_SetTimeBonus ( player_t * player , y_bonus_t * bstruct )
{
INT32 secs , bonus ;
strncpy ( bstruct - > patch , " YB_TIME " , sizeof ( bstruct - > patch ) ) ;
bstruct - > display = true ;
// calculate time bonus
secs = player - > realtime / TICRATE ;
if ( secs < 30 ) /* :30 */ bonus = 100000 ;
else if ( secs < 45 ) /* :45 */ bonus = 50000 ;
else if ( secs < 60 ) /* 1:00 */ bonus = 10000 ;
else if ( secs < 90 ) /* 1:30 */ bonus = 5000 ;
else if ( secs < 120 ) /* 2:00 */ bonus = 4000 ;
else if ( secs < 180 ) /* 3:00 */ bonus = 3000 ;
else if ( secs < 240 ) /* 4:00 */ bonus = 2000 ;
else if ( secs < 300 ) /* 5:00 */ bonus = 1000 ;
else if ( secs < 360 ) /* 6:00 */ bonus = 500 ;
else if ( secs < 420 ) /* 7:00 */ bonus = 400 ;
else if ( secs < 480 ) /* 8:00 */ bonus = 300 ;
else if ( secs < 540 ) /* 9:00 */ bonus = 200 ;
else if ( secs < 600 ) /* 10:00 */ bonus = 100 ;
else /* TIME TAKEN: TOO LONG */ bonus = 0 ;
bstruct - > points = bonus ;
}
//
// Y_SetRingBonus
//
static void Y_SetRingBonus ( player_t * player , y_bonus_t * bstruct )
{
strncpy ( bstruct - > patch , " YB_RING " , sizeof ( bstruct - > patch ) ) ;
bstruct - > display = true ;
bstruct - > points = max ( 0 , ( player - > health - 1 ) * 100 ) ;
}
//
// Y_SetLinkBonus
//
2017-02-18 18:39:25 +00:00
/*
static void Y_SetLinkBonus ( player_t * player , y_bonus_t * bstruct ) // SRB2kart - unused.
2014-03-15 16:59:03 +00:00
{
strncpy ( bstruct - > patch , " YB_LINK " , sizeof ( bstruct - > patch ) ) ;
bstruct - > display = true ;
bstruct - > points = max ( 0 , ( player - > maxlink - 1 ) * 100 ) ;
}
2017-02-18 18:39:25 +00:00
*/
2014-03-15 16:59:03 +00:00
//
// Y_SetGuardBonus
//
static void Y_SetGuardBonus ( player_t * player , y_bonus_t * bstruct )
{
INT32 bonus ;
strncpy ( bstruct - > patch , " YB_GUARD " , sizeof ( bstruct - > patch ) ) ;
bstruct - > display = true ;
if ( player - > timeshit = = 0 ) bonus = 10000 ;
else if ( player - > timeshit = = 1 ) bonus = 5000 ;
else if ( player - > timeshit = = 2 ) bonus = 1000 ;
else if ( player - > timeshit = = 3 ) bonus = 500 ;
else if ( player - > timeshit = = 4 ) bonus = 100 ;
else bonus = 0 ;
bstruct - > points = bonus ;
}
//
// Y_SetPerfectBonus
//
static void Y_SetPerfectBonus ( player_t * player , y_bonus_t * bstruct )
{
INT32 i ;
( void ) player ;
memset ( bstruct , 0 , sizeof ( y_bonus_t ) ) ;
strncpy ( bstruct - > patch , " YB_PERFE " , sizeof ( bstruct - > patch ) ) ;
if ( data . coop . gotperfbonus = = - 1 )
{
INT32 sharedringtotal = 0 ;
for ( i = 0 ; i < MAXPLAYERS ; i + + )
{
if ( ! playeringame [ i ] ) continue ;
sharedringtotal + = players [ i ] . health - 1 ;
}
if ( ! sharedringtotal | | sharedringtotal < nummaprings )
data . coop . gotperfbonus = 0 ;
else
data . coop . gotperfbonus = 1 ;
}
if ( ! data . coop . gotperfbonus )
return ;
bstruct - > display = true ;
bstruct - > points = 50000 ;
}
// This list can be extended in the future with SOC/Lua, perhaps.
typedef void ( * bonus_f ) ( player_t * , y_bonus_t * ) ;
bonus_f bonuses_list [ 4 ] [ 4 ] = {
{
Y_SetNullBonus ,
Y_SetNullBonus ,
Y_SetNullBonus ,
Y_SetNullBonus ,
} ,
{
Y_SetNullBonus ,
Y_SetTimeBonus ,
Y_SetRingBonus ,
Y_SetPerfectBonus ,
} ,
{
Y_SetNullBonus ,
Y_SetGuardBonus ,
Y_SetRingBonus ,
Y_SetNullBonus ,
} ,
{
Y_SetNullBonus ,
Y_SetGuardBonus ,
Y_SetRingBonus ,
Y_SetPerfectBonus ,
} ,
} ;
2017-02-07 22:19:04 +00:00
/* // SRB2kart 230117 - Replaced with Y_CalculateTournamentPoints
2014-03-15 16:59:03 +00:00
//
// Y_AwardCoopBonuses
//
// Awards the time and ring bonuses.
//
static void Y_AwardCoopBonuses ( void )
{
INT32 i , j , bonusnum , oldscore , ptlives ;
y_bonus_t localbonuses [ 4 ] ;
// set score/total first
data . coop . total = 0 ;
data . coop . score = players [ consoleplayer ] . score ;
data . coop . gotperfbonus = - 1 ;
memset ( data . coop . bonuses , 0 , sizeof ( data . coop . bonuses ) ) ;
memset ( data . coop . bonuspatches , 0 , sizeof ( data . coop . bonuspatches ) ) ;
for ( i = 0 ; i < MAXPLAYERS ; + + i )
{
if ( ! playeringame [ i ] | | players [ i ] . lives < 1 ) // not active or game over
bonusnum = 0 ; // all null
else
bonusnum = mapheaderinfo [ prevmap ] - > bonustype + 1 ; // -1 is none
oldscore = players [ i ] . score ;
for ( j = 0 ; j < 4 ; + + j ) // Set bonuses
{
( bonuses_list [ bonusnum ] [ j ] ) ( & players [ i ] , & localbonuses [ j ] ) ;
players [ i ] . score + = localbonuses [ j ] . points ;
}
ptlives = ( ! ultimatemode & & ! modeattacking ) ? max ( ( players [ i ] . score / 50000 ) - ( oldscore / 50000 ) , 0 ) : 0 ;
if ( ptlives )
P_GivePlayerLives ( & players [ i ] , ptlives ) ;
if ( i = = consoleplayer )
{
data . coop . gotlife = ptlives ;
M_Memcpy ( & data . coop . bonuses , & localbonuses , sizeof ( data . coop . bonuses ) ) ;
}
}
// Just in case the perfect bonus wasn't checked.
if ( data . coop . gotperfbonus < 0 )
data . coop . gotperfbonus = 0 ;
}
//
// Y_AwardSpecialStageBonus
//
// Gives a ring bonus only.
static void Y_AwardSpecialStageBonus ( void )
{
INT32 i , oldscore , ptlives ;
y_bonus_t localbonus ;
data . spec . score = players [ consoleplayer ] . score ;
memset ( & data . spec . bonus , 0 , sizeof ( data . spec . bonus ) ) ;
data . spec . bonuspatch = NULL ;
for ( i = 0 ; i < MAXPLAYERS ; i + + )
{
oldscore = players [ i ] . score ;
if ( ! playeringame [ i ] | | players [ i ] . lives < 1 ) // not active or game over
Y_SetNullBonus ( & players [ i ] , & localbonus ) ;
else if ( useNightsSS ) // Link instead of Score
Y_SetLinkBonus ( & players [ i ] , & localbonus ) ;
else
Y_SetRingBonus ( & players [ i ] , & localbonus ) ;
players [ i ] . score + = localbonus . points ;
// grant extra lives right away since tally is faked
ptlives = ( ! ultimatemode & & ! modeattacking ) ? max ( ( players [ i ] . score / 50000 ) - ( oldscore / 50000 ) , 0 ) : 0 ;
if ( ptlives )
P_GivePlayerLives ( & players [ i ] , ptlives ) ;
if ( i = = consoleplayer )
{
M_Memcpy ( & data . spec . bonus , & localbonus , sizeof ( data . spec . bonus ) ) ;
data . spec . gotlife = ptlives ;
// Continues related
data . spec . continues = min ( players [ i ] . continues , 8 ) ;
if ( players [ i ] . gotcontinue )
data . spec . continues | = 0x80 ;
data . spec . playercolor = & players [ i ] . skincolor ;
data . spec . playerchar = & players [ i ] . skin ;
}
}
}
2017-02-07 22:19:04 +00:00
*/
//
// Y_CalculateTournamentPoints
//
static void Y_CalculateTournamentPoints ( void )
{
INT32 i , j ;
boolean completed [ MAXPLAYERS ] ;
INT32 numplayersingame = 0 ;
2017-03-04 22:13:19 +00:00
INT32 increase [ MAXPLAYERS ] ;
2017-02-07 22:19:04 +00:00
for ( i = 0 ; i < MAXPLAYERS ; i + + )
{
if ( playeringame [ i ] )
numplayersingame + + ;
2017-03-10 02:29:30 +00:00
}
2017-02-17 20:03:10 +00:00
2017-03-10 02:29:30 +00:00
for ( i = 0 ; i < numplayersingame ; i + + )
{
2017-03-04 22:13:19 +00:00
increase [ i ] = numplayersingame - i ;
2017-02-07 22:19:04 +00:00
2017-03-04 22:13:19 +00:00
if ( increase [ i ] < 0 )
increase [ i ] = 0 ;
}
2017-02-07 22:19:04 +00:00
// Initialize variables
for ( j = 0 ; j < MAXPLAYERS ; j + + )
data . match . scores [ j ] = INT32_MAX ;
memset ( data . match . time , 0 , sizeof ( data . match . time ) ) ;
memset ( data . match . color , 0 , sizeof ( data . match . color ) ) ;
memset ( data . match . character , 0 , sizeof ( data . match . character ) ) ;
memset ( data . match . spectator , 0 , sizeof ( data . match . spectator ) ) ;
memset ( data . match . increase , 0 , sizeof ( data . match . increase ) ) ;
memset ( completed , 0 , sizeof ( completed ) ) ;
data . match . numplayers = 0 ;
i = j = 0 ;
for ( j = 0 ; j < MAXPLAYERS ; j + + )
{
if ( ! playeringame [ j ] )
continue ;
for ( i = 0 ; i < MAXPLAYERS ; i + + )
{
if ( ! playeringame [ i ] )
continue ;
if ( players [ i ] . realtime < = data . match . scores [ data . match . numplayers ] & & completed [ i ] = = false )
{
data . match . time [ data . match . numplayers ] = players [ i ] . realtime ;
data . match . scores [ data . match . numplayers ] = players [ i ] . realtime ;
data . match . color [ data . match . numplayers ] = & players [ i ] . skincolor ;
data . match . character [ data . match . numplayers ] = & players [ i ] . skin ;
data . match . name [ data . match . numplayers ] = player_names [ i ] ;
data . match . spectator [ data . match . numplayers ] = players [ i ] . spectator ;
data . match . num [ data . match . numplayers ] = i ;
}
}
completed [ data . match . num [ data . match . numplayers ] ] = true ;
if ( ! ( players [ data . match . num [ data . match . numplayers ] ] . pflags & PF_TIMEOVER
| | players [ data . match . num [ data . match . numplayers ] ] . spectator ) )
data . match . increase [ data . match . numplayers ] = increase [ data . match . numplayers ] ;
players [ data . match . num [ data . match . numplayers ] ] . score + = data . match . increase [ data . match . numplayers ] ;
data . match . scores [ data . match . numplayers ] = players [ data . match . num [ data . match . numplayers ] ] . score ;
data . match . numplayers + + ;
}
}
2014-03-15 16:59:03 +00:00
// ======
//
// Y_EndIntermission
//
void Y_EndIntermission ( void )
{
Y_UnloadData ( ) ;
endtic = - 1 ;
intertype = int_none ;
2014-03-21 18:42:55 +00:00
usebuffer = false ;
2014-03-15 16:59:03 +00:00
}
//
// Y_EndGame
//
// Why end the game?
// Because Y_FollowIntermission and F_EndCutscene would
// both do this exact same thing *in different ways* otherwise,
// which made it so that you could only unlock Ultimate mode
// if you had a cutscene after the final level and crap like that.
// This function simplifies it so only one place has to be updated
// when something new is added.
void Y_EndGame ( void )
{
// Only do evaluation and credits in coop games.
if ( gametype = = GT_COOP )
{
if ( nextmap = = 1102 - 1 ) // end game with credits
{
F_StartCredits ( ) ;
return ;
}
if ( nextmap = = 1101 - 1 ) // end game with evaluation
{
F_StartGameEvaluation ( ) ;
return ;
}
}
// 1100 or competitive multiplayer, so go back to title screen.
D_StartTitle ( ) ;
}
//
// Y_FollowIntermission
//
static void Y_FollowIntermission ( void )
{
if ( modeattacking )
{
M_EndModeAttackRun ( ) ;
return ;
}
if ( nextmap < 1100 - 1 )
{
// normal level
2018-01-28 01:59:29 +00:00
G_AfterIntermission ( ) ;
2014-03-15 16:59:03 +00:00
return ;
}
// Start a custom cutscene if there is one.
if ( mapheaderinfo [ gamemap - 1 ] - > cutscenenum & & ! modeattacking )
{
F_StartCustomCutscene ( mapheaderinfo [ gamemap - 1 ] - > cutscenenum - 1 , false , false ) ;
return ;
}
Y_EndGame ( ) ;
}
# define UNLOAD(x) Z_ChangeTag(x, PU_CACHE); x = NULL
//
// Y_UnloadData
//
static void Y_UnloadData ( void )
{
// In hardware mode, don't Z_ChangeTag a pointer returned by W_CachePatchName().
// It doesn't work and is unnecessary.
if ( rendermode ! = render_soft )
return ;
// unload the background patches
UNLOAD ( bgpatch ) ;
UNLOAD ( widebgpatch ) ;
UNLOAD ( bgtile ) ;
UNLOAD ( interpic ) ;
switch ( intertype )
{
2017-02-07 22:19:04 +00:00
/*
2014-03-15 16:59:03 +00:00
case int_coop :
// unload the coop and single player patches
UNLOAD ( data . coop . ttlnum ) ;
UNLOAD ( data . coop . bonuspatches [ 3 ] ) ;
UNLOAD ( data . coop . bonuspatches [ 2 ] ) ;
UNLOAD ( data . coop . bonuspatches [ 1 ] ) ;
UNLOAD ( data . coop . bonuspatches [ 0 ] ) ;
UNLOAD ( data . coop . ptotal ) ;
break ;
case int_spec :
// unload the special stage patches
//UNLOAD(data.spec.cemerald);
//UNLOAD(data.spec.nowsuper);
UNLOAD ( data . spec . bonuspatch ) ;
UNLOAD ( data . spec . pscore ) ;
UNLOAD ( data . spec . pcontinues ) ;
break ;
2017-02-07 22:19:04 +00:00
*/
2014-03-15 16:59:03 +00:00
case int_match :
case int_race :
UNLOAD ( data . match . result ) ;
break ;
case int_ctf :
UNLOAD ( data . match . blueflag ) ;
UNLOAD ( data . match . redflag ) ;
break ;
default :
//without this default,
//int_none, int_tag, int_chaos, and int_classicrace
//are not handled
break ;
}
}
2018-01-27 06:17:08 +00:00
// SRB2Kart: Voting!
//
2018-01-28 01:59:29 +00:00
// Y_VoteDrawer
2018-01-27 06:17:08 +00:00
//
2018-01-28 01:59:29 +00:00
// Draws the voting screen!
2018-01-27 06:17:08 +00:00
//
2018-01-28 01:59:29 +00:00
void Y_VoteDrawer ( void )
2018-01-27 06:17:08 +00:00
{
2018-01-28 01:59:29 +00:00
INT32 i , x , y = 0 ;
2018-01-27 06:17:08 +00:00
2018-01-28 01:59:29 +00:00
if ( rendermode = = render_none )
return ;
2018-01-27 06:17:08 +00:00
2018-01-28 01:59:29 +00:00
if ( votetic > = voteendtic & & voteendtic ! = - 1 )
return ;
2018-01-27 06:17:08 +00:00
2018-01-28 01:59:29 +00:00
V_DrawFill ( 0 , 0 , BASEVIDWIDTH , BASEVIDHEIGHT , 31 ) ;
2018-01-27 06:17:08 +00:00
2018-01-28 04:52:01 +00:00
if ( widebgpatch & & rendermode = = render_soft & & vid . width / vid . dupx > 320 )
V_DrawScaledPatch ( ( ( vid . width / 2 ) / vid . dupx ) - ( SHORT ( widebgpatch - > width ) / 2 ) ,
( vid . height / vid . dupy ) - SHORT ( widebgpatch - > height ) ,
V_SNAPTOTOP | V_SNAPTOLEFT , widebgpatch ) ;
else
V_DrawScaledPatch ( ( ( vid . width / 2 ) / vid . dupx ) - ( SHORT ( bgpatch - > width ) / 2 ) , // Keep the width/height adjustments, for screens that are less wide than 320(?)
( vid . height / vid . dupy ) - SHORT ( bgpatch - > height ) ,
V_SNAPTOTOP | V_SNAPTOLEFT , bgpatch ) ;
2018-01-27 06:17:08 +00:00
2018-01-28 01:59:29 +00:00
y = 30 ;
2018-01-27 06:17:08 +00:00
for ( i = 0 ; i < 4 ; i + + )
{
2018-01-28 04:52:01 +00:00
char str [ 40 ] ;
patch_t * pic ;
2018-01-27 06:17:08 +00:00
2018-01-28 04:52:01 +00:00
if ( i = = 3 )
{
snprintf ( str , sizeof str , " %.32s " , " RANDOM " ) ;
str [ sizeof str - 1 ] = ' \0 ' ;
pic = randomlvl ;
}
else
{
2018-02-04 04:47:47 +00:00
strcpy ( str , levelinfo [ i ] . str ) ;
pic = levelinfo [ i ] . pic ;
2018-01-28 04:52:01 +00:00
}
2018-01-27 06:17:08 +00:00
2018-02-04 04:47:47 +00:00
if ( i = = voteclient . selection )
2018-01-28 04:52:01 +00:00
{
2018-02-04 04:47:47 +00:00
if ( votes [ consoleplayer ] = = - 1 )
2018-01-28 04:52:01 +00:00
{
V_DrawScaledPatch ( BASEVIDWIDTH - 124 , y + 21 , V_SNAPTORIGHT , cursor ) ;
if ( votetic % 4 > 1 )
V_DrawFill ( BASEVIDWIDTH - 101 , y - 1 , 82 , 52 , 120 | V_SNAPTORIGHT ) ;
else
V_DrawFill ( BASEVIDWIDTH - 101 , y - 1 , 82 , 52 , 103 | V_SNAPTORIGHT ) ;
}
V_DrawSmallScaledPatch ( BASEVIDWIDTH - 100 , y , V_SNAPTORIGHT , pic ) ;
2018-01-30 00:22:08 +00:00
V_DrawRightAlignedThinString ( BASEVIDWIDTH - 20 , 40 + y , V_SNAPTORIGHT , str ) ;
2018-01-28 01:59:29 +00:00
y + = 55 ;
}
else
2018-01-27 06:17:08 +00:00
{
2018-01-28 04:52:01 +00:00
V_DrawTinyScaledPatch ( BASEVIDWIDTH - 60 , y , V_SNAPTORIGHT , pic ) ;
2018-01-28 01:59:29 +00:00
y + = 30 ;
2018-01-27 06:17:08 +00:00
}
2018-01-28 01:59:29 +00:00
}
2018-01-27 06:17:08 +00:00
2018-01-28 01:59:29 +00:00
x = 20 ;
y = 15 ;
2018-01-27 06:17:08 +00:00
2018-02-04 04:47:47 +00:00
for ( i = 0 ; i < MAXPLAYERS ; i + + )
2018-01-28 01:59:29 +00:00
{
2018-02-17 06:53:44 +00:00
if ( ( playeringame [ i ] & & ! players [ i ] . spectator ) & & votes [ i ] ! = - 1 )
2018-01-27 06:17:08 +00:00
{
2018-01-28 04:52:01 +00:00
patch_t * pic ;
2018-02-11 00:02:15 +00:00
if ( votes [ i ] = = 3 & & ( i ! = pickedvote | | voteendtic = = - 1 ) )
2018-01-28 04:52:01 +00:00
pic = randomlvl ;
else
2018-02-04 04:47:47 +00:00
pic = levelinfo [ votes [ i ] ] . pic ;
2018-01-28 04:52:01 +00:00
2018-02-11 00:02:15 +00:00
if ( ! timer & & i = = voteclient . ranim )
2018-01-28 04:52:01 +00:00
{
V_DrawScaledPatch ( x - 18 , y + 9 , V_SNAPTOLEFT , cursor ) ;
if ( votetic % 4 > 1 )
V_DrawFill ( x - 1 , y - 1 , 42 , 27 , 120 | V_SNAPTOLEFT ) ;
else
V_DrawFill ( x - 1 , y - 1 , 42 , 27 , 103 | V_SNAPTOLEFT ) ;
}
V_DrawTinyScaledPatch ( x , y , V_SNAPTOLEFT , pic ) ;
2018-01-28 01:59:29 +00:00
2018-02-04 04:47:47 +00:00
if ( players [ i ] . skincolor = = 0 )
V_DrawSmallScaledPatch ( x + 24 , y + 9 , V_SNAPTOLEFT , faceprefix [ players [ i ] . skin ] ) ;
2018-01-27 06:17:08 +00:00
else
{
2018-02-04 04:47:47 +00:00
UINT8 * colormap = R_GetTranslationColormap ( players [ i ] . skin , players [ i ] . skincolor , GTC_CACHE ) ;
V_DrawSmallMappedPatch ( x + 24 , y + 9 , V_SNAPTOLEFT , faceprefix [ players [ i ] . skin ] , colormap ) ;
2018-01-27 06:17:08 +00:00
}
2018-02-04 04:47:47 +00:00
}
2018-01-27 06:17:08 +00:00
2018-02-04 04:47:47 +00:00
if ( splitscreen ) // only 1p has a vote in splitscreen
break ;
2018-01-27 06:17:08 +00:00
2018-02-04 04:47:47 +00:00
y + = 30 ;
if ( y > BASEVIDHEIGHT - 38 )
{
x + = 100 ;
y = 15 ;
2018-01-27 06:17:08 +00:00
}
}
2018-01-28 01:59:29 +00:00
2018-02-04 04:47:47 +00:00
if ( timer )
2018-02-08 05:45:59 +00:00
V_DrawCenteredString ( BASEVIDWIDTH / 2 , 188 , V_YELLOWMAP | V_SNAPTOBOTTOM ,
va ( " Vote ends in %d seconds " , timer / TICRATE ) ) ;
2018-01-27 06:17:08 +00:00
}
//
// Y_VoteTicker
//
// Vote screen thinking :eggthinking:
//
void Y_VoteTicker ( void )
{
2018-02-04 04:47:47 +00:00
boolean pressed = false ;
2018-01-27 06:17:08 +00:00
INT32 i ;
if ( paused | | P_AutoPause ( ) )
return ;
votetic + + ;
2018-01-28 04:52:01 +00:00
if ( votetic = = voteendtic )
2018-01-27 06:17:08 +00:00
{
2018-01-28 04:52:01 +00:00
Y_UnloadVoteData ( ) ; // Y_EndVote resets voteendtic too early apparently, causing the game to try to render patches that we just unloaded...
2018-01-28 01:59:29 +00:00
Y_FollowIntermission ( ) ;
2018-01-27 06:17:08 +00:00
return ;
}
2018-02-04 04:47:47 +00:00
for ( i = 0 ; i < MAXPLAYERS ; i + + ) // Correct votes as early as possible, before they're processed by the game at all
{
if ( ! playeringame [ i ] | | players [ i ] . spectator )
2018-02-17 06:53:44 +00:00
votes [ i ] = - 1 ; // Spectators are the lower class, and have effectively no voice in the government. Democracy sucks.
2018-02-08 05:45:59 +00:00
else if ( pickedvote ! = - 1 & & votes [ i ] = = - 1 & & ! splitscreen )
2018-02-04 04:47:47 +00:00
votes [ i ] = 3 ; // Slow people get random
}
2018-02-17 06:53:44 +00:00
if ( server & & pickedvote ! = - 1 & & votes [ pickedvote ] = = - 1 ) // Uh oh! The person who got picked left! Recalculate, quick!
2018-02-04 04:47:47 +00:00
D_PickVote ( ) ;
2018-01-28 01:59:29 +00:00
if ( ! votetic )
2018-02-13 23:13:27 +00:00
S_ChangeMusicInternal ( " vote " , true ) ;
2018-01-28 01:59:29 +00:00
2018-02-04 04:47:47 +00:00
if ( timer )
timer - - ;
2018-01-27 06:17:08 +00:00
2018-02-04 04:47:47 +00:00
if ( voteclient . delay )
voteclient . delay - - ;
2018-01-27 06:17:08 +00:00
2018-02-04 04:47:47 +00:00
if ( pickedvote ! = - 1 )
2018-01-27 06:17:08 +00:00
{
2018-02-04 04:47:47 +00:00
timer = 0 ;
2018-02-13 23:13:27 +00:00
voteclient . rsynctime + + ;
2018-01-27 06:17:08 +00:00
2018-02-04 04:47:47 +00:00
if ( voteendtic = = - 1 )
{
UINT8 tempvotes [ MAXPLAYERS ] ;
UINT8 numvotes = 0 ;
2018-01-27 06:17:08 +00:00
2018-02-04 04:47:47 +00:00
for ( i = 0 ; i < MAXPLAYERS ; i + + )
{
if ( votes [ i ] = = - 1 )
continue ;
tempvotes [ numvotes ] = i ;
numvotes + + ;
}
2018-01-28 01:59:29 +00:00
2018-02-11 00:02:15 +00:00
voteclient . rtics - - ;
if ( voteclient . rtics < = 0 )
{
voteclient . roffset + + ;
2018-02-17 06:53:44 +00:00
voteclient . rtics = min ( 20 , ( 3 * voteclient . roffset / 4 ) + 5 ) ;
2018-02-13 23:13:27 +00:00
S_StartSound ( NULL , sfx_kc39 ) ;
2018-02-11 00:02:15 +00:00
}
2018-02-13 23:13:27 +00:00
if ( voteclient . rendoff = = 0 | | voteclient . roffset < voteclient . rendoff )
voteclient . ranim = tempvotes [ ( ( pickedvote + voteclient . roffset ) % numvotes ) ] ;
2018-02-11 00:02:15 +00:00
2018-02-17 06:53:44 +00:00
if ( voteclient . roffset > = 20 )
2018-02-11 00:02:15 +00:00
{
2018-02-13 23:13:27 +00:00
if ( voteclient . rendoff = = 0 )
{
if ( tempvotes [ ( ( pickedvote + voteclient . roffset + 4 ) % numvotes ) ] = = pickedvote
2018-02-17 06:53:44 +00:00
& & voteclient . rsynctime % 50 = = 0 ) // Song is 1.45 seconds long (sorry @ whoever wants to replace it in a music wad :V)
2018-02-13 23:13:27 +00:00
{
voteclient . rendoff = voteclient . roffset + 4 ;
S_ChangeMusicInternal ( " voteeb " , false ) ;
}
}
else if ( voteclient . roffset > = voteclient . rendoff )
{
voteendtic = votetic + ( 3 * TICRATE ) ;
S_StartSound ( NULL , sfx_kc48 ) ;
}
2018-02-11 00:02:15 +00:00
}
2018-01-27 06:17:08 +00:00
}
2018-02-11 00:02:15 +00:00
else
voteclient . ranim = pickedvote ;
2018-02-04 04:47:47 +00:00
}
else
{
if ( votetic < 3 * ( NEWTICRATE / 7 ) ) // give it some time before letting you control it :V
return ;
2018-01-27 06:17:08 +00:00
2018-02-17 06:53:44 +00:00
if ( ( playeringame [ consoleplayer ] & & ! players [ consoleplayer ] . spectator )
& & ! voteclient . delay & & pickedvote = = - 1 & & votes [ consoleplayer ] = = - 1 )
2018-01-27 06:17:08 +00:00
{
2018-02-09 21:04:52 +00:00
if ( InputDown ( gc_aimforward , 1 ) | | JoyAxis ( AXISMOVE , 1 ) < 0 )
2018-02-04 04:47:47 +00:00
{
voteclient . selection - - ;
pressed = true ;
}
2018-02-09 21:04:52 +00:00
if ( ( InputDown ( gc_aimbackward , 1 ) | | JoyAxis ( AXISMOVE , 1 ) > 0 ) & & ! pressed )
2018-02-04 04:47:47 +00:00
{
voteclient . selection + + ;
pressed = true ;
}
if ( voteclient . selection < 0 )
voteclient . selection = 3 ;
if ( voteclient . selection > 3 )
voteclient . selection = 0 ;
2018-02-09 21:04:52 +00:00
if ( InputDown ( gc_accelerate , 1 ) & & ! pressed )
2018-02-04 04:47:47 +00:00
{
D_ModifyClientVote ( voteclient . selection ) ;
pressed = true ;
}
2018-01-27 06:17:08 +00:00
}
2018-02-04 04:47:47 +00:00
if ( pressed )
2018-01-27 06:17:08 +00:00
{
2018-02-13 23:13:27 +00:00
S_StartSound ( NULL , sfx_kc4a ) ;
2018-02-04 04:47:47 +00:00
voteclient . delay = NEWTICRATE / 7 ;
2018-01-27 06:17:08 +00:00
}
2018-02-04 04:47:47 +00:00
if ( server )
2018-01-27 06:17:08 +00:00
{
2018-02-04 04:47:47 +00:00
if ( splitscreen )
{
2018-02-17 06:53:44 +00:00
if ( votes [ 0 ] = = - 1 )
return ;
2018-02-04 04:47:47 +00:00
}
else
{
for ( i = 0 ; i < MAXPLAYERS ; i + + )
{
2018-02-17 06:53:44 +00:00
if ( ( playeringame [ i ] & & ! players [ i ] . spectator ) & & votes [ i ] = = - 1 )
return ;
2018-02-04 04:47:47 +00:00
}
}
2018-01-28 04:55:43 +00:00
2018-02-17 06:53:44 +00:00
timer = 0 ;
if ( voteendtic = = - 1 )
2018-02-04 04:47:47 +00:00
D_PickVote ( ) ;
}
2018-01-28 01:59:29 +00:00
}
2018-01-27 06:17:08 +00:00
}
//
2018-01-28 01:59:29 +00:00
// Y_StartVote
2018-01-27 06:17:08 +00:00
//
2018-01-28 01:59:29 +00:00
// MK online style voting screen, appears after intermission
2018-01-27 06:17:08 +00:00
//
2018-01-28 01:59:29 +00:00
void Y_StartVote ( void )
2018-01-27 06:17:08 +00:00
{
2018-01-28 01:59:29 +00:00
INT32 i = 0 ;
2018-01-27 06:17:08 +00:00
2018-01-28 01:59:29 +00:00
votetic = - 1 ;
2018-01-27 06:17:08 +00:00
2018-01-28 01:59:29 +00:00
# ifdef PARANOIA
if ( voteendtic ! = - 1 )
I_Error ( " voteendtic is dirty " ) ;
# endif
2018-01-27 06:17:08 +00:00
2018-01-28 01:59:29 +00:00
widebgpatch = W_CachePatchName ( " INTERSCW " , PU_STATIC ) ;
bgpatch = W_CachePatchName ( " INTERSCR " , PU_STATIC ) ;
cursor = W_CachePatchName ( " M_CURSOR " , PU_STATIC ) ;
2018-01-28 04:52:01 +00:00
randomlvl = W_CachePatchName ( " RANDOMLV " , PU_STATIC ) ;
2018-01-27 06:17:08 +00:00
2018-02-04 04:47:47 +00:00
timer = cv_votetime . value * TICRATE ;
pickedvote = - 1 ;
voteclient . selection = 0 ;
voteclient . delay = 0 ;
2018-02-11 00:02:15 +00:00
voteclient . ranim = 0 ;
voteclient . rtics = 1 ;
voteclient . roffset = 0 ;
2018-02-13 23:13:27 +00:00
voteclient . rsynctime = 0 ;
voteclient . rendoff = 0 ;
2018-01-28 01:59:29 +00:00
for ( i = 0 ; i < MAXPLAYERS ; i + + )
2018-02-04 04:47:47 +00:00
votes [ i ] = - 1 ;
2018-01-27 06:17:08 +00:00
2018-01-28 01:59:29 +00:00
for ( i = 0 ; i < 4 ; i + + )
2018-01-27 06:17:08 +00:00
{
2018-01-28 04:52:01 +00:00
lumpnum_t lumpnum ;
2018-01-27 06:17:08 +00:00
2018-01-28 04:52:01 +00:00
// set up the str
2018-01-30 02:39:13 +00:00
if ( mapheaderinfo [ votelevels [ i ] ] - > zonttl )
2018-01-28 01:59:29 +00:00
{
2018-01-30 02:39:13 +00:00
if ( mapheaderinfo [ votelevels [ i ] ] - > actnum )
2018-02-04 04:47:47 +00:00
snprintf ( levelinfo [ i ] . str ,
sizeof levelinfo [ i ] . str ,
2018-01-28 04:52:01 +00:00
" %.32s %.32s %d " ,
2018-01-30 02:39:13 +00:00
mapheaderinfo [ votelevels [ i ] ] - > lvlttl , mapheaderinfo [ votelevels [ i ] ] - > zonttl , mapheaderinfo [ votelevels [ i ] ] - > actnum ) ;
2018-01-28 04:52:01 +00:00
else
2018-02-04 04:47:47 +00:00
snprintf ( levelinfo [ i ] . str ,
sizeof levelinfo [ i ] . str ,
2018-01-28 04:52:01 +00:00
" %.32s %.32s " ,
2018-01-30 02:39:13 +00:00
mapheaderinfo [ votelevels [ i ] ] - > lvlttl , mapheaderinfo [ votelevels [ i ] ] - > zonttl ) ;
2018-01-28 01:59:29 +00:00
}
else
2018-01-27 06:17:08 +00:00
{
2018-01-30 02:39:13 +00:00
if ( mapheaderinfo [ votelevels [ i ] ] - > actnum )
2018-02-04 04:47:47 +00:00
snprintf ( levelinfo [ i ] . str ,
sizeof levelinfo [ i ] . str ,
2018-01-28 04:52:01 +00:00
" %.32s %d " ,
2018-01-30 02:39:13 +00:00
mapheaderinfo [ votelevels [ i ] ] - > lvlttl , mapheaderinfo [ votelevels [ i ] ] - > actnum ) ;
2018-01-28 01:59:29 +00:00
else
2018-02-04 04:47:47 +00:00
snprintf ( levelinfo [ i ] . str ,
sizeof levelinfo [ i ] . str ,
2018-01-28 04:52:01 +00:00
" %.32s " ,
2018-01-30 02:39:13 +00:00
mapheaderinfo [ votelevels [ i ] ] - > lvlttl ) ;
2018-01-28 04:52:01 +00:00
}
2018-01-28 01:59:29 +00:00
2018-02-04 04:47:47 +00:00
levelinfo [ i ] . str [ sizeof levelinfo [ i ] . str - 1 ] = ' \0 ' ;
2018-01-28 01:59:29 +00:00
2018-01-30 02:39:13 +00:00
lumpnum = W_CheckNumForName ( va ( " %sP " , G_BuildMapName ( votelevels [ i ] + 1 ) ) ) ;
2018-01-28 04:52:01 +00:00
if ( lumpnum ! = LUMPERROR )
2018-02-04 04:47:47 +00:00
levelinfo [ i ] . pic = W_CachePatchName ( va ( " %sP " , G_BuildMapName ( votelevels [ i ] + 1 ) ) , PU_STATIC ) ;
2018-01-28 04:52:01 +00:00
else
2018-02-04 04:47:47 +00:00
levelinfo [ i ] . pic = W_CachePatchName ( " BLANKLVL " , PU_STATIC ) ;
2018-01-27 06:17:08 +00:00
}
}
//
// Y_EndVote
//
void Y_EndVote ( void )
{
Y_UnloadVoteData ( ) ;
voteendtic = - 1 ;
}
//
// Y_UnloadVoteData
//
static void Y_UnloadVoteData ( void )
{
if ( rendermode ! = render_soft )
return ;
UNLOAD ( widebgpatch ) ;
2018-01-28 01:59:29 +00:00
UNLOAD ( bgpatch ) ;
2018-01-27 06:17:08 +00:00
UNLOAD ( cursor ) ;
2018-01-28 04:52:01 +00:00
UNLOAD ( randomlvl ) ;
2018-01-27 06:17:08 +00:00
2018-02-04 04:47:47 +00:00
UNLOAD ( levelinfo [ 3 ] . pic ) ;
UNLOAD ( levelinfo [ 2 ] . pic ) ;
UNLOAD ( levelinfo [ 1 ] . pic ) ;
UNLOAD ( levelinfo [ 0 ] . pic ) ;
2018-01-27 06:17:08 +00:00
}
2018-02-04 04:47:47 +00:00
//
// Y_SetupVoteFinish
//
2018-02-23 01:04:52 +00:00
void Y_SetupVoteFinish ( SINT8 pick , SINT8 level )
2018-02-04 04:47:47 +00:00
{
2018-02-17 06:53:44 +00:00
if ( pickedvote = = - 1 )
{
INT32 i ;
SINT8 votecompare = - 1 ;
boolean allsame = true ;
voteclient . rsynctime = 0 ;
for ( i = 0 ; i < MAXPLAYERS ; i + + )
{
2018-02-20 23:18:10 +00:00
if ( ( playeringame [ i ] & & ! players [ i ] . spectator ) & & votes [ i ] = = - 1 )
2018-02-17 06:53:44 +00:00
votes [ i ] = 3 ;
if ( votes [ i ] = = - 1 )
continue ;
if ( votecompare = = - 1 )
votecompare = votes [ i ] ;
else if ( votes [ i ] ! = votecompare )
allsame = false ;
}
if ( allsame )
{
voteendtic = votetic + ( 5 * TICRATE ) ;
S_StartSound ( NULL , sfx_kc48 ) ;
S_ChangeMusicInternal ( " voteeb " , false ) ;
}
else
S_ChangeMusicInternal ( " voteea " , true ) ;
}
2018-02-04 04:47:47 +00:00
pickedvote = pick ;
nextmap = votelevels [ level ] ;
timer = 0 ;
}