2017-03-18 20:19:32 +00:00
/*
* * wi_stuff . cpp
* * Support code for intermission status screens
* *
* * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* * Copyright 2003 - 2017 Christoph Oelckers
* * All rights reserved .
* *
* * Redistribution and use in source and binary forms , with or without
* * modification , are permitted provided that the following conditions
* * are met :
* *
* * 1. Redistributions of source code must retain the above copyright
* * notice , this list of conditions and the following disclaimer .
* * 2. Redistributions in binary form must reproduce the above copyright
* * notice , this list of conditions and the following disclaimer in the
* * documentation and / or other materials provided with the distribution .
* * 3. The name of the author may not be used to endorse or promote products
* * derived from this software without specific prior written permission .
* *
* * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ` ` AS IS ' ' AND ANY EXPRESS OR
* * IMPLIED WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE IMPLIED WARRANTIES
* * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED .
* * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT , INDIRECT ,
* * INCIDENTAL , SPECIAL , EXEMPLARY , OR CONSEQUENTIAL DAMAGES ( INCLUDING , BUT
* * NOT LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES ; LOSS OF USE ,
* * DATA , OR PROFITS ; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY
* * THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT LIABILITY , OR TORT
* * ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF
* * THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE .
* * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* *
*/
2016-03-01 15:47:10 +00:00
# include <ctype.h>
# include <stdio.h>
# include "m_random.h"
# include "m_swap.h"
# include "i_system.h"
# include "w_wad.h"
# include "g_game.h"
# include "g_level.h"
# include "s_sound.h"
# include "doomstat.h"
# include "v_video.h"
# include "i_video.h"
# include "wi_stuff.h"
# include "c_console.h"
# include "hu_stuff.h"
# include "v_palette.h"
# include "s_sndseq.h"
# include "sc_man.h"
# include "v_text.h"
# include "gi.h"
# include "d_player.h"
# include "d_netinf.h"
# include "b_bot.h"
# include "textures/textures.h"
# include "r_data/r_translate.h"
# include "templates.h"
# include "gstrings.h"
2016-10-12 17:22:33 +00:00
# include "cmdlib.h"
2017-01-08 17:45:30 +00:00
# include "g_levellocals.h"
2017-04-12 23:12:04 +00:00
# include "vm.h"
2016-03-01 15:47:10 +00:00
2017-02-22 22:52:25 +00:00
CVAR ( Bool , wi_percents , true , CVAR_ARCHIVE )
CVAR ( Bool , wi_showtotaltime , true , CVAR_ARCHIVE )
CVAR ( Bool , wi_noautostartmap , false , CVAR_USERINFO | CVAR_ARCHIVE )
CVAR ( Int , wi_autoadvance , 0 , CVAR_SERVERINFO )
2016-03-01 15:47:10 +00:00
2017-02-25 16:55:20 +00:00
// States for the intermission
enum EState
{
NoState = - 1 ,
StatCount ,
ShowNextLoc ,
LeavingIntermission
} ;
2016-03-01 15:47:10 +00:00
2017-02-22 22:52:25 +00:00
static const char * WI_Cmd [ ] = {
" Background " ,
" Splat " ,
" Pointer " ,
" Spots " ,
2016-03-01 15:47:10 +00:00
2017-02-22 22:52:25 +00:00
" IfEntering " ,
" IfNotEntering " ,
" IfVisited " ,
" IfNotVisited " ,
" IfLeaving " ,
" IfNotLeaving " ,
" IfTravelling " ,
" IfNotTravelling " ,
2016-03-01 15:47:10 +00:00
2017-02-22 22:52:25 +00:00
" Animation " ,
" Pic " ,
2016-03-01 15:47:10 +00:00
2017-02-22 22:52:25 +00:00
" NoAutostartMap " ,
2016-03-01 15:47:10 +00:00
2017-02-22 22:52:25 +00:00
NULL
2016-03-01 15:47:10 +00:00
} ;
2017-03-18 12:25:22 +00:00
class DInterBackground : public DObject
2016-03-01 15:47:10 +00:00
{
2017-03-18 12:25:22 +00:00
DECLARE_ABSTRACT_CLASS ( DInterBackground , DObject )
2017-02-22 22:52:25 +00:00
// These animation variables, structures, etc. are used for the
// DOOM/Ultimate DOOM intermission screen animations. This is
// totally different from any sprite or texture/flat animations
enum EAnim
{
ANIM_ALWAYS , // determined by patch entry
ANIM_PIC , // continuous
// condition bitflags
ANIM_IFVISITED = 8 ,
ANIM_IFNOTVISITED = 16 ,
ANIM_IFENTERING = 32 ,
ANIM_IFNOTENTERING = 64 ,
ANIM_IFLEAVING = 128 ,
ANIM_IFNOTLEAVING = 256 ,
ANIM_IFTRAVELLING = 512 ,
ANIM_IFNOTTRAVELLING = 1024 ,
ANIM_TYPE = 7 ,
ANIM_CONDITION = ~ 7 ,
} ;
struct yahpt_t
{
int x , y ;
} ;
struct lnode_t
{
int x ; // x/y coordinate pair structure
int y ;
2017-02-25 16:55:20 +00:00
FString Level ;
2017-02-22 22:52:25 +00:00
} ;
struct in_anim_t
{
int type ; // Made an int so I can use '|'
int period ; // period in tics between animations
yahpt_t loc ; // location of animation
int data ; // ALWAYS: n/a, RANDOM: period deviation (<256)
2017-02-22 23:16:14 +00:00
TArray < FTexture * > frames ; // actual graphics for frames of animations
2017-02-22 22:52:25 +00:00
2017-02-25 16:55:20 +00:00
// following must be initialized to zero before use!
2017-02-22 22:52:25 +00:00
int nexttic ; // next value of bcnt (used in conjunction with period)
int ctr ; // next frame number to animate
int state ; // used by RANDOM and LEVEL when animating
2017-02-22 23:16:14 +00:00
FString LevelName ;
FString LevelName2 ;
void Reset ( )
{
type = period = loc . x = loc . y = data = nexttic = ctr = state = 0 ;
LevelName = " " ;
LevelName2 = " " ;
frames . Clear ( ) ;
}
2017-02-22 22:52:25 +00:00
} ;
2017-02-25 16:55:20 +00:00
private :
2017-02-22 22:52:25 +00:00
TArray < lnode_t > lnodes ;
TArray < in_anim_t > anims ;
2017-02-25 16:55:20 +00:00
int bcnt = 0 ; // used for timing of background animation
2017-02-22 22:52:25 +00:00
TArray < FTexture * > yah ; // You Are Here graphic
2017-02-25 16:55:20 +00:00
FTexture * splat = nullptr ; // splat
FTexture * background = nullptr ;
wbstartstruct_t * wbs ;
2017-03-18 12:25:22 +00:00
2017-02-25 16:55:20 +00:00
public :
2017-02-22 22:52:25 +00:00
2017-03-18 12:25:22 +00:00
DInterBackground ( wbstartstruct_t * wbst ) ;
bool LoadBackground ( bool isenterpic ) ;
void updateAnimatedBack ( ) ;
void drawBackground ( int state , bool drawsplat , bool snl_pointeron ) ;
private :
2017-02-22 22:52:25 +00:00
2017-02-25 16:55:20 +00:00
bool IsExMy ( const char * name )
2017-02-22 22:52:25 +00:00
{
// Only check for the first 3 episodes. They are the only ones with default intermission scripts.
2017-03-18 12:25:22 +00:00
// Level names can be upper- and lower case so use tolower to check.
2017-02-25 16:55:20 +00:00
return ( tolower ( name [ 0 ] ) = = ' e ' & & name [ 1 ] > = ' 1 ' & & name [ 1 ] < = ' 3 ' & & tolower ( name [ 2 ] ) = = ' m ' ) ;
2017-02-22 22:52:25 +00:00
}
2017-03-18 12:25:22 +00:00
//====================================================================
//
// Draws the splats and the 'You are here' arrows
//
//====================================================================
2017-02-22 22:52:25 +00:00
2017-03-18 12:25:22 +00:00
int MapToIndex ( const char * map )
2017-02-22 22:52:25 +00:00
{
2017-03-18 12:25:22 +00:00
unsigned int i ;
2017-02-22 22:52:25 +00:00
2017-03-18 12:25:22 +00:00
for ( i = 0 ; i < lnodes . Size ( ) ; i + + )
2017-02-22 22:52:25 +00:00
{
2017-03-18 12:25:22 +00:00
if ( ! lnodes [ i ] . Level . CompareNoCase ( map ) )
break ;
2017-02-22 22:52:25 +00:00
}
2017-03-18 12:25:22 +00:00
return i ;
}
//====================================================================
//
// Draws the splats and the 'You are here' arrows
//
//====================================================================
void drawOnLnode ( int n , FTexture * c [ ] , int numc )
{
int i ;
for ( i = 0 ; i < numc ; i + + )
2016-03-01 15:47:10 +00:00
{
2017-03-18 12:25:22 +00:00
int left ;
int top ;
int right ;
int bottom ;
right = c [ i ] - > GetScaledWidth ( ) ;
bottom = c [ i ] - > GetScaledHeight ( ) ;
left = lnodes [ n ] . x - c [ i ] - > GetScaledLeftOffset ( ) ;
top = lnodes [ n ] . y - c [ i ] - > GetScaledTopOffset ( ) ;
right + = left ;
bottom + = top ;
if ( left > = 0 & & right < 320 & & top > = 0 & & bottom < 200 )
{
screen - > DrawTexture ( c [ i ] , lnodes [ n ] . x , lnodes [ n ] . y , DTA_320x200 , true , TAG_DONE ) ;
break ;
}
2017-02-22 22:52:25 +00:00
}
2017-03-18 12:25:22 +00:00
}
} ;
2017-02-22 22:52:25 +00:00
2017-03-18 12:25:22 +00:00
DInterBackground : : DInterBackground ( wbstartstruct_t * wbst )
{
wbs = wbst ;
}
DEFINE_ACTION_FUNCTION ( DInterBackground , Create )
{
PARAM_PROLOGUE ;
PARAM_POINTER ( wbst , wbstartstruct_t ) ;
2017-04-14 11:31:58 +00:00
ACTION_RETURN_POINTER ( Create < DInterBackground > ( wbst ) ) ;
2017-03-18 12:25:22 +00:00
}
//====================================================================
//
// Loads the background - either from a single texture
// or an intermission lump.
// Unfortunately the texture manager is incapable of recognizing text
// files so if you use a script you have to prefix its name by '$' in
// MAPINFO.
//
//====================================================================
bool DInterBackground : : LoadBackground ( bool isenterpic )
{
const char * lumpname = NULL ;
char buffer [ 10 ] ;
in_anim_t an ;
lnode_t pt ;
FTextureID texture ;
bool noautostartmap = false ;
bcnt = 0 ;
texture . SetInvalid ( ) ;
if ( isenterpic )
{
level_info_t * li = FindLevelInfo ( wbs - > next ) ;
if ( li ! = NULL ) lumpname = li - > EnterPic ;
}
else
{
lumpname = level . info - > ExitPic ;
}
// Try to get a default if nothing specified
if ( lumpname = = NULL | | lumpname [ 0 ] = = 0 )
{
lumpname = NULL ;
switch ( gameinfo . gametype )
2017-02-22 22:52:25 +00:00
{
2017-03-18 12:25:22 +00:00
case GAME_Chex :
case GAME_Doom :
if ( ! ( gameinfo . flags & GI_MAPxx ) )
2016-03-01 15:47:10 +00:00
{
2017-03-18 12:25:22 +00:00
const char * level = isenterpic ? wbs - > next : wbs - > current ;
if ( IsExMy ( level ) )
2016-03-01 15:47:10 +00:00
{
2017-03-18 12:25:22 +00:00
mysnprintf ( buffer , countof ( buffer ) , " $IN_EPI%c " , level [ 1 ] ) ;
lumpname = buffer ;
2016-03-01 15:47:10 +00:00
}
2017-03-18 12:25:22 +00:00
}
if ( ! lumpname )
{
if ( isenterpic )
2016-03-01 15:47:10 +00:00
{
2017-03-18 12:25:22 +00:00
// One special case needs to be handled here!
// If going from E1-E3 to E4 the default should be used, not the exit pic.
2016-03-01 15:47:10 +00:00
2017-03-18 12:25:22 +00:00
// Not if the exit pic is user defined!
if ( level . info - > ExitPic . IsNotEmpty ( ) ) return false ;
2016-03-01 15:47:10 +00:00
2017-03-18 12:25:22 +00:00
// E1-E3 need special treatment when playing Doom 1.
if ( ! ( gameinfo . flags & GI_MAPxx ) )
{
// not if the last level is not from the first 3 episodes
if ( ! IsExMy ( wbs - > current ) ) return false ;
2016-03-01 15:47:10 +00:00
2017-03-18 12:25:22 +00:00
// not if the next level is one of the first 3 episodes
if ( IsExMy ( wbs - > next ) ) return false ;
2016-03-01 15:47:10 +00:00
}
}
2017-03-18 12:25:22 +00:00
lumpname = " INTERPIC " ;
}
break ;
2016-03-01 15:47:10 +00:00
2017-03-18 12:25:22 +00:00
case GAME_Heretic :
if ( isenterpic )
{
if ( IsExMy ( wbs - > next ) )
2017-02-22 22:52:25 +00:00
{
2017-03-18 12:25:22 +00:00
mysnprintf ( buffer , countof ( buffer ) , " $IN_HTC%c " , wbs - > next [ 1 ] ) ;
lumpname = buffer ;
2017-02-22 22:52:25 +00:00
}
2017-03-18 12:25:22 +00:00
}
if ( ! lumpname )
{
2017-02-25 16:55:20 +00:00
if ( isenterpic ) return false ;
2017-03-18 12:25:22 +00:00
lumpname = " FLOOR16 " ;
2017-02-22 22:52:25 +00:00
}
2017-03-18 12:25:22 +00:00
break ;
2016-03-01 15:47:10 +00:00
2017-03-18 12:25:22 +00:00
case GAME_Hexen :
if ( isenterpic ) return false ;
lumpname = " INTERPIC " ;
break ;
2016-03-01 15:47:10 +00:00
2017-03-18 12:25:22 +00:00
case GAME_Strife :
default :
// Strife doesn't have an intermission pic so choose something neutral.
if ( isenterpic ) return false ;
lumpname = gameinfo . BorderFlat ;
break ;
2017-02-22 22:52:25 +00:00
}
2017-03-18 12:25:22 +00:00
}
if ( lumpname = = NULL )
{
// shouldn't happen!
background = NULL ;
return false ;
}
lnodes . Clear ( ) ;
anims . Clear ( ) ;
yah . Clear ( ) ;
splat = NULL ;
// a name with a starting '$' indicates an intermission script
if ( * lumpname ! = ' $ ' )
{
2018-03-25 18:26:16 +00:00
texture = TexMan . CheckForTexture ( lumpname , ETextureType : : MiscPatch , FTextureManager : : TEXMAN_TryAny ) ;
2017-03-18 12:25:22 +00:00
}
else
{
int lumpnum = Wads . CheckNumForFullName ( lumpname + 1 , true ) ;
if ( lumpnum > = 0 )
2017-02-22 22:52:25 +00:00
{
2017-03-18 12:25:22 +00:00
FScanner sc ( lumpnum ) ;
while ( sc . GetString ( ) )
2016-03-01 15:47:10 +00:00
{
2017-03-18 12:25:22 +00:00
an . Reset ( ) ;
int caseval = sc . MustMatchString ( WI_Cmd ) ;
switch ( caseval )
2016-03-01 15:47:10 +00:00
{
2017-03-18 12:25:22 +00:00
case 0 : // Background
sc . MustGetString ( ) ;
2018-03-25 18:26:16 +00:00
texture = TexMan . CheckForTexture ( sc . String , ETextureType : : MiscPatch , FTextureManager : : TEXMAN_TryAny ) ;
2017-03-18 12:25:22 +00:00
break ;
2016-03-01 15:47:10 +00:00
2017-03-18 12:25:22 +00:00
case 1 : // Splat
sc . MustGetString ( ) ;
splat = TexMan [ sc . String ] ;
break ;
2017-02-22 22:52:25 +00:00
2017-03-18 12:25:22 +00:00
case 2 : // Pointers
while ( sc . GetString ( ) & & ! sc . Crossed )
{
yah . Push ( TexMan [ sc . String ] ) ;
}
if ( sc . Crossed )
sc . UnGet ( ) ;
break ;
2017-02-22 22:52:25 +00:00
2017-03-18 12:25:22 +00:00
case 3 : // Spots
sc . MustGetStringName ( " { " ) ;
while ( ! sc . CheckString ( " } " ) )
{
sc . MustGetString ( ) ;
pt . Level = sc . String ;
sc . MustGetNumber ( ) ;
pt . x = sc . Number ;
sc . MustGetNumber ( ) ;
pt . y = sc . Number ;
lnodes . Push ( pt ) ;
}
break ;
2016-03-01 15:47:10 +00:00
2017-03-18 12:25:22 +00:00
case 4 : // IfEntering
an . type = ANIM_IFENTERING ;
goto readanimation ;
2016-03-01 15:47:10 +00:00
2017-03-18 12:25:22 +00:00
case 5 : // IfEntering
an . type = ANIM_IFNOTENTERING ;
goto readanimation ;
2016-03-01 15:47:10 +00:00
2017-03-18 12:25:22 +00:00
case 6 : // IfVisited
an . type = ANIM_IFVISITED ;
goto readanimation ;
2016-03-01 15:47:10 +00:00
2017-03-18 12:25:22 +00:00
case 7 : // IfNotVisited
an . type = ANIM_IFNOTVISITED ;
goto readanimation ;
2016-03-01 15:47:10 +00:00
2017-03-18 12:25:22 +00:00
case 8 : // IfLeaving
an . type = ANIM_IFLEAVING ;
goto readanimation ;
2017-02-25 16:55:20 +00:00
2017-03-18 12:25:22 +00:00
case 9 : // IfNotLeaving
an . type = ANIM_IFNOTLEAVING ;
goto readanimation ;
2016-03-01 15:47:10 +00:00
2017-03-18 12:25:22 +00:00
case 10 : // IfTravelling
an . type = ANIM_IFTRAVELLING ;
sc . MustGetString ( ) ;
an . LevelName2 = sc . String ;
goto readanimation ;
2016-03-01 15:47:10 +00:00
2017-03-18 12:25:22 +00:00
case 11 : // IfNotTravelling
an . type = ANIM_IFTRAVELLING ;
sc . MustGetString ( ) ;
an . LevelName2 = sc . String ;
goto readanimation ;
2017-02-22 22:52:25 +00:00
2017-03-18 12:25:22 +00:00
case 14 : // NoAutostartMap
noautostartmap = true ;
break ;
2017-02-22 22:52:25 +00:00
2017-03-18 12:25:22 +00:00
readanimation :
sc . MustGetString ( ) ;
an . LevelName = sc . String ;
sc . MustGetString ( ) ;
caseval = sc . MustMatchString ( WI_Cmd ) ;
2017-02-22 22:52:25 +00:00
2017-03-18 12:25:22 +00:00
default :
switch ( caseval )
{
case 12 : // Animation
an . type | = ANIM_ALWAYS ;
sc . MustGetNumber ( ) ;
an . loc . x = sc . Number ;
sc . MustGetNumber ( ) ;
an . loc . y = sc . Number ;
sc . MustGetNumber ( ) ;
an . period = sc . Number ;
an . nexttic = 1 + ( M_Random ( ) % an . period ) ;
if ( sc . GetString ( ) )
2016-03-01 15:47:10 +00:00
{
2017-03-18 12:25:22 +00:00
if ( sc . Compare ( " ONCE " ) )
2016-03-01 15:47:10 +00:00
{
2017-03-18 12:25:22 +00:00
an . data = 1 ;
2016-03-01 15:47:10 +00:00
}
2017-02-22 22:52:25 +00:00
else
2016-03-01 15:47:10 +00:00
{
2017-03-18 12:25:22 +00:00
sc . UnGet ( ) ;
2016-03-01 15:47:10 +00:00
}
2017-03-18 12:25:22 +00:00
}
if ( ! sc . CheckString ( " { " ) )
{
2017-02-22 22:52:25 +00:00
sc . MustGetString ( ) ;
2017-03-18 12:25:22 +00:00
an . frames . Push ( TexMan [ sc . String ] ) ;
2017-02-22 22:52:25 +00:00
}
2017-03-18 12:25:22 +00:00
else
{
while ( ! sc . CheckString ( " } " ) )
{
sc . MustGetString ( ) ;
an . frames . Push ( TexMan [ sc . String ] ) ;
}
}
an . ctr = - 1 ;
anims . Push ( an ) ;
break ;
case 13 : // Pic
an . type | = ANIM_PIC ;
sc . MustGetNumber ( ) ;
an . loc . x = sc . Number ;
sc . MustGetNumber ( ) ;
an . loc . y = sc . Number ;
sc . MustGetString ( ) ;
an . frames . Reserve ( 1 ) ; // allocate exactly one element
an . frames [ 0 ] = TexMan [ sc . String ] ;
anims . Push ( an ) ;
break ;
default :
sc . ScriptError ( " Unknown token %s in intermission script " , sc . String ) ;
2016-03-01 15:47:10 +00:00
}
}
}
}
2017-03-18 12:25:22 +00:00
else
{
Printf ( " Intermission script %s not found! \n " , lumpname + 1 ) ;
2018-03-25 18:26:16 +00:00
texture = TexMan . GetTexture ( " INTERPIC " , ETextureType : : MiscPatch ) ;
2017-03-18 12:25:22 +00:00
}
2016-03-01 15:47:10 +00:00
}
2017-03-18 12:25:22 +00:00
background = TexMan [ texture ] ;
return noautostartmap ;
}
2016-03-01 15:47:10 +00:00
2017-03-18 12:25:22 +00:00
DEFINE_ACTION_FUNCTION ( DInterBackground , LoadBackground )
{
PARAM_SELF_PROLOGUE ( DInterBackground ) ;
PARAM_BOOL ( isenterpic ) ;
ACTION_RETURN_BOOL ( self - > LoadBackground ( isenterpic ) ) ;
}
2016-03-01 15:47:10 +00:00
2017-03-18 12:25:22 +00:00
//====================================================================
//
// made this more generic and configurable through a script
// Removed all the ugly special case handling for different game modes
//
//====================================================================
void DInterBackground : : updateAnimatedBack ( )
{
unsigned int i ;
2017-02-22 22:52:25 +00:00
2017-03-18 12:25:22 +00:00
bcnt + + ;
for ( i = 0 ; i < anims . Size ( ) ; i + + )
{
in_anim_t * a = & anims [ i ] ;
switch ( a - > type & ANIM_TYPE )
2016-03-01 15:47:10 +00:00
{
2017-03-18 12:25:22 +00:00
case ANIM_ALWAYS :
if ( bcnt > = a - > nexttic )
2016-03-01 15:47:10 +00:00
{
2017-03-18 12:25:22 +00:00
if ( + + a - > ctr > = ( int ) a - > frames . Size ( ) )
2016-03-01 15:47:10 +00:00
{
2017-03-18 12:25:22 +00:00
if ( a - > data = = 0 ) a - > ctr = 0 ;
else a - > ctr - - ;
2016-03-01 15:47:10 +00:00
}
2017-03-18 12:25:22 +00:00
a - > nexttic = bcnt + a - > period ;
}
break ;
2017-02-25 16:55:20 +00:00
2017-03-18 12:25:22 +00:00
case ANIM_PIC :
a - > ctr = 0 ;
break ;
2017-02-25 16:55:20 +00:00
2016-03-01 15:47:10 +00:00
}
}
2017-03-18 12:25:22 +00:00
}
2016-03-01 15:47:10 +00:00
2017-03-18 12:25:22 +00:00
DEFINE_ACTION_FUNCTION ( DInterBackground , updateAnimatedBack )
{
PARAM_SELF_PROLOGUE ( DInterBackground ) ;
self - > updateAnimatedBack ( ) ;
return 0 ;
}
2016-03-01 15:47:10 +00:00
2017-03-18 12:25:22 +00:00
//====================================================================
//
// Draws the background including all animations
//
//====================================================================
2017-02-22 22:52:25 +00:00
2017-03-18 12:25:22 +00:00
void DInterBackground : : drawBackground ( int state , bool drawsplat , bool snl_pointeron )
{
unsigned int i ;
double animwidth = 320 ; // For a flat fill or clear background scale animations to 320x200
double animheight = 200 ;
if ( background )
{
// background
2018-03-25 18:26:16 +00:00
if ( background - > UseType = = ETextureType : : MiscPatch )
2016-03-01 15:47:10 +00:00
{
2017-03-18 12:25:22 +00:00
// scale all animations below to fit the size of the base pic
// The base pic is always scaled to fit the screen so this allows
// placing the animations precisely where they belong on the base pic
animwidth = background - > GetScaledWidthDouble ( ) ;
animheight = background - > GetScaledHeightDouble ( ) ;
2020-06-06 08:19:02 +00:00
if ( gameinfo . fullscreenautoaspect = = 3 & & animheight = = 200 & & animwidth > 320 ) animwidth = 320 ; // deal with widescreen replacements that keep the original coordinates.
2017-03-18 12:25:22 +00:00
screen - > DrawTexture ( background , 0 , 0 , DTA_Fullscreen , true , TAG_DONE ) ;
2016-03-01 15:47:10 +00:00
}
2017-02-25 16:55:20 +00:00
else
2016-03-01 15:47:10 +00:00
{
2017-03-18 12:25:22 +00:00
screen - > FlatFill ( 0 , 0 , SCREENWIDTH , SCREENHEIGHT , background ) ;
2016-03-01 15:47:10 +00:00
}
2017-03-18 12:25:22 +00:00
}
else
{
screen - > Clear ( 0 , 0 , SCREENWIDTH , SCREENHEIGHT , 0 , 0 ) ;
}
2016-03-01 15:47:10 +00:00
2017-03-18 12:25:22 +00:00
for ( i = 0 ; i < anims . Size ( ) ; i + + )
{
in_anim_t * a = & anims [ i ] ;
2019-01-23 20:37:51 +00:00
level_info_t * li ;
2016-03-01 15:47:10 +00:00
2017-03-18 12:25:22 +00:00
switch ( a - > type & ANIM_CONDITION )
{
case ANIM_IFVISITED :
li = FindLevelInfo ( a - > LevelName ) ;
if ( li = = NULL | | ! ( li - > flags & LEVEL_VISITED ) ) continue ;
break ;
2016-03-01 15:47:10 +00:00
2017-03-18 12:25:22 +00:00
case ANIM_IFNOTVISITED :
li = FindLevelInfo ( a - > LevelName ) ;
if ( li = = NULL | | ( li - > flags & LEVEL_VISITED ) ) continue ;
break ;
2016-03-01 15:47:10 +00:00
2017-03-18 12:25:22 +00:00
// StatCount means 'leaving' - everything else means 'entering'!
case ANIM_IFENTERING :
if ( state = = StatCount | | strnicmp ( a - > LevelName , wbs - > next , 8 ) ) continue ;
break ;
2016-03-01 15:47:10 +00:00
2017-03-18 12:25:22 +00:00
case ANIM_IFNOTENTERING :
if ( state ! = StatCount & & ! strnicmp ( a - > LevelName , wbs - > next , 8 ) ) continue ;
break ;
2016-03-01 15:47:10 +00:00
2017-03-18 12:25:22 +00:00
case ANIM_IFLEAVING :
if ( state ! = StatCount | | strnicmp ( a - > LevelName , wbs - > current , 8 ) ) continue ;
break ;
2017-02-22 22:52:25 +00:00
2017-03-18 12:25:22 +00:00
case ANIM_IFNOTLEAVING :
if ( state = = StatCount & & ! strnicmp ( a - > LevelName , wbs - > current , 8 ) ) continue ;
break ;
2017-02-25 16:55:20 +00:00
2017-03-18 12:25:22 +00:00
case ANIM_IFTRAVELLING :
if ( strnicmp ( a - > LevelName2 , wbs - > current , 8 ) | | strnicmp ( a - > LevelName , wbs - > next , 8 ) ) continue ;
break ;
2017-02-25 16:55:20 +00:00
2017-03-18 12:25:22 +00:00
case ANIM_IFNOTTRAVELLING :
if ( ! strnicmp ( a - > LevelName2 , wbs - > current , 8 ) & & ! strnicmp ( a - > LevelName , wbs - > next , 8 ) ) continue ;
break ;
2016-03-01 15:47:10 +00:00
}
2017-03-18 12:25:22 +00:00
if ( a - > ctr > = 0 )
screen - > DrawTexture ( a - > frames [ a - > ctr ] , a - > loc . x , a - > loc . y ,
DTA_VirtualWidthF , animwidth , DTA_VirtualHeightF , animheight , TAG_DONE ) ;
2017-02-25 16:55:20 +00:00
}
2017-03-18 12:25:22 +00:00
if ( drawsplat )
2017-02-25 16:55:20 +00:00
{
2017-03-18 12:25:22 +00:00
for ( i = 0 ; i < lnodes . Size ( ) ; i + + )
2017-02-25 16:55:20 +00:00
{
2017-03-18 12:25:22 +00:00
level_info_t * li = FindLevelInfo ( lnodes [ i ] . Level ) ;
if ( li & & li - > flags & LEVEL_VISITED ) drawOnLnode ( i , & splat , 1 ) ; // draw a splat on taken cities.
2017-02-25 16:55:20 +00:00
}
2016-03-01 15:47:10 +00:00
}
2017-03-18 12:25:22 +00:00
// draw flashing ptr
if ( snl_pointeron & & yah . Size ( ) )
2017-02-25 16:55:20 +00:00
{
2017-03-18 12:25:22 +00:00
unsigned int v = MapToIndex ( wbs - > next ) ;
// Draw only if it points to a valid level on the current screen!
if ( v < lnodes . Size ( ) ) drawOnLnode ( v , & yah [ 0 ] , yah . Size ( ) ) ;
}
}
2017-02-25 16:55:20 +00:00
2017-03-18 12:25:22 +00:00
DEFINE_ACTION_FUNCTION ( DInterBackground , drawBackground )
{
PARAM_SELF_PROLOGUE ( DInterBackground ) ;
PARAM_INT ( state ) ;
PARAM_BOOL ( splat ) ;
PARAM_BOOL ( pointer ) ;
self - > drawBackground ( state , splat , pointer ) ;
return 0 ;
}
2017-02-25 16:55:20 +00:00
2017-03-18 12:25:22 +00:00
IMPLEMENT_CLASS ( DInterBackground , true , false )
2017-02-25 16:55:20 +00:00
2017-03-18 20:19:32 +00:00
DObject * WI_Screen ;
2017-03-18 12:25:22 +00:00
//====================================================================
//
//
//
//====================================================================
2017-02-25 16:55:20 +00:00
2017-03-18 20:19:32 +00:00
void WI_Ticker ( )
2017-02-25 16:55:20 +00:00
{
2017-03-18 20:19:32 +00:00
if ( WI_Screen )
2017-02-25 16:55:20 +00:00
{
2017-03-18 20:19:32 +00:00
IFVIRTUALPTRNAME ( WI_Screen , " StatusScreen " , Ticker )
2017-02-25 16:55:20 +00:00
{
2017-03-18 20:19:32 +00:00
VMValue self = WI_Screen ;
2017-04-12 23:12:04 +00:00
VMCall ( func , & self , 1 , nullptr , 0 ) ;
2017-02-25 16:55:20 +00:00
}
}
2017-03-18 20:19:32 +00:00
}
2017-02-25 16:55:20 +00:00
2017-03-18 20:19:32 +00:00
//====================================================================
//
// Called by main loop,
// draws the intermission directly into the screen buffer.
//
//====================================================================
2017-02-25 16:55:20 +00:00
2017-03-18 20:19:32 +00:00
void WI_Drawer ( )
2017-02-25 16:55:20 +00:00
{
2017-03-18 20:19:32 +00:00
if ( WI_Screen )
2016-03-01 15:47:10 +00:00
{
2017-03-18 20:19:32 +00:00
IFVIRTUALPTRNAME ( WI_Screen , " StatusScreen " , Drawer )
2017-02-22 22:52:25 +00:00
{
2020-03-17 07:50:00 +00:00
screen - > FillBorder ( nullptr ) ;
2020-06-06 08:19:02 +00:00
screen - > ClearClipRect ( ) ;
2017-03-18 20:19:32 +00:00
VMValue self = WI_Screen ;
2017-04-12 23:12:04 +00:00
VMCall ( func , & self , 1 , nullptr , 0 ) ;
2017-03-28 11:06:24 +00:00
screen - > ClearClipRect ( ) ; // make sure the scripts don't leave a valid clipping rect behind.
2016-03-01 15:47:10 +00:00
2017-03-18 20:19:32 +00:00
// The internal handling here is somewhat poor. After being set to 'LeavingIntermission'
// the screen is needed for one more draw operation so we cannot delete it right away but only here.
if ( WI_Screen - > IntVar ( " CurState " ) = = LeavingIntermission )
2016-03-01 15:47:10 +00:00
{
2017-03-18 20:19:32 +00:00
WI_Screen - > Destroy ( ) ;
GC : : DelSoftRoot ( WI_Screen ) ;
WI_Screen = nullptr ;
2016-03-01 15:47:10 +00:00
}
2017-02-22 22:52:25 +00:00
}
2016-03-01 15:47:10 +00:00
}
2017-03-18 20:19:32 +00:00
}
2016-03-01 15:47:10 +00:00
2017-03-18 20:19:32 +00:00
//====================================================================
//
// Setup for an intermission screen.
//
//====================================================================
2016-03-01 15:47:10 +00:00
2017-03-18 20:19:32 +00:00
void WI_Start ( wbstartstruct_t * wbstartstruct )
{
FName screenclass = deathmatch ? gameinfo . statusscreen_dm : multiplayer ? gameinfo . statusscreen_coop : gameinfo . statusscreen_single ;
auto cls = PClass : : FindClass ( screenclass ) ;
2016-03-01 15:47:10 +00:00
2017-03-18 20:19:32 +00:00
if ( cls = = nullptr | | ! cls - > IsDescendantOf ( " StatusScreen " ) )
2017-02-22 22:52:25 +00:00
{
2017-03-18 20:19:32 +00:00
// Name was invalid - pick some working default.
Printf ( " Status screen class %s not found - reverting to default " , screenclass . GetChars ( ) ) ;
screenclass = deathmatch ? NAME_DeathmatchStatusScreen : multiplayer ? NAME_CoopStatusScreen : NAME_RavenStatusScreen ;
cls = PClass : : FindClass ( screenclass ) ;
if ( cls = = nullptr )
2017-02-22 22:52:25 +00:00
{
2018-05-25 08:05:30 +00:00
I_FatalError ( " Cannot create status screen " ) ;
2017-02-22 22:52:25 +00:00
}
2016-03-01 15:47:10 +00:00
}
2019-10-25 13:16:49 +00:00
// Set up some global stuff that is always needed.
auto info = FindLevelInfo ( wbstartstruct - > next , false ) ;
if ( info = = nullptr )
{
wbstartstruct - > next = " " ;
}
else wbstartstruct - > nextname = info - > LookupLevelName ( ) ;
2017-03-18 20:19:32 +00:00
V_SetBlend ( 0 , 0 , 0 , 0 ) ;
WI_Screen = cls - > CreateNew ( ) ;
IFVIRTUALPTRNAME ( WI_Screen , " StatusScreen " , Start )
2016-03-01 15:47:10 +00:00
{
2017-03-18 20:19:32 +00:00
VMValue val [ 2 ] = { WI_Screen , wbstartstruct } ;
2017-04-12 23:12:04 +00:00
VMCall ( func , val , 2 , nullptr , 0 ) ;
2016-03-01 15:47:10 +00:00
}
2017-03-18 20:19:32 +00:00
GC : : AddSoftRoot ( WI_Screen ) ;
}
2016-03-01 15:47:10 +00:00
2017-03-18 20:19:32 +00:00
//====================================================================
//
//
//
//====================================================================
2016-03-01 15:47:10 +00:00
2017-03-18 20:19:32 +00:00
DEFINE_ACTION_FUNCTION ( DStatusScreen , GetPlayerWidths )
{
PARAM_PROLOGUE ;
int maxnamewidth , maxscorewidth , maxiconheight ;
HU_GetPlayerWidths ( maxnamewidth , maxscorewidth , maxiconheight ) ;
if ( numret > 0 ) ret [ 0 ] . SetInt ( maxnamewidth ) ;
if ( numret > 1 ) ret [ 1 ] . SetInt ( maxscorewidth ) ;
if ( numret > 2 ) ret [ 2 ] . SetInt ( maxiconheight ) ;
return MIN ( numret , 3 ) ;
}
2016-03-01 15:47:10 +00:00
2017-03-18 20:19:32 +00:00
//====================================================================
//
//
//
//====================================================================
2016-03-01 15:47:10 +00:00
2017-03-18 20:19:32 +00:00
DEFINE_ACTION_FUNCTION ( DStatusScreen , GetRowColor )
{
PARAM_PROLOGUE ;
PARAM_POINTER ( p , player_t ) ;
PARAM_BOOL ( highlight ) ;
ACTION_RETURN_INT ( HU_GetRowColor ( p , highlight ) ) ;
}
2016-03-01 15:47:10 +00:00
2017-03-18 20:19:32 +00:00
//====================================================================
//
//
//
//====================================================================
2016-03-01 15:47:10 +00:00
2017-03-18 20:19:32 +00:00
DEFINE_ACTION_FUNCTION ( DStatusScreen , GetSortedPlayers )
{
PARAM_PROLOGUE ;
PARAM_POINTER ( array , TArray < int > ) ;
PARAM_BOOL ( teamplay ) ;
2017-02-22 22:52:25 +00:00
2017-03-18 20:19:32 +00:00
player_t * sortedplayers [ MAXPLAYERS ] ;
// Sort all players
for ( int i = 0 ; i < MAXPLAYERS ; i + + )
2016-03-01 15:47:10 +00:00
{
2017-03-18 20:19:32 +00:00
sortedplayers [ i ] = & players [ i ] ;
2016-03-01 15:47:10 +00:00
}
2017-03-18 20:19:32 +00:00
if ( teamplay )
qsort ( sortedplayers , MAXPLAYERS , sizeof ( player_t * ) , compareteams ) ;
else
qsort ( sortedplayers , MAXPLAYERS , sizeof ( player_t * ) , comparepoints ) ;
2016-03-01 15:47:10 +00:00
2017-03-18 20:19:32 +00:00
array - > Resize ( MAXPLAYERS ) ;
for ( unsigned i = 0 ; i < MAXPLAYERS ; i + + )
2016-03-01 15:47:10 +00:00
{
2017-03-18 20:19:32 +00:00
( * array ) [ i ] = int ( sortedplayers [ i ] - players ) ;
2016-03-01 15:47:10 +00:00
}
2017-03-18 20:19:32 +00:00
return 0 ;
}
2016-03-01 15:47:10 +00:00
2017-03-18 20:19:32 +00:00
//====================================================================
//
//
//
//====================================================================
2017-03-18 18:34:03 +00:00
2017-02-23 23:28:33 +00:00
DEFINE_FIELD_X ( WBPlayerStruct , wbplayerstruct_t , skills ) ;
DEFINE_FIELD_X ( WBPlayerStruct , wbplayerstruct_t , sitems ) ;
DEFINE_FIELD_X ( WBPlayerStruct , wbplayerstruct_t , ssecret ) ;
DEFINE_FIELD_X ( WBPlayerStruct , wbplayerstruct_t , stime ) ;
DEFINE_FIELD_X ( WBPlayerStruct , wbplayerstruct_t , frags ) ;
DEFINE_FIELD_X ( WBPlayerStruct , wbplayerstruct_t , fragcount ) ;
DEFINE_FIELD_X ( WBStartStruct , wbstartstruct_t , finished_ep ) ;
DEFINE_FIELD_X ( WBStartStruct , wbstartstruct_t , next_ep ) ;
DEFINE_FIELD_X ( WBStartStruct , wbstartstruct_t , current ) ;
DEFINE_FIELD_X ( WBStartStruct , wbstartstruct_t , next ) ;
2017-03-18 18:34:03 +00:00
DEFINE_FIELD_X ( WBStartStruct , wbstartstruct_t , nextname ) ;
2019-08-02 07:11:40 +00:00
DEFINE_FIELD_X ( WBStartStruct , wbstartstruct_t , nextauthor ) ;
DEFINE_FIELD_X ( WBStartStruct , wbstartstruct_t , thisauthor ) ;
2017-02-23 23:28:33 +00:00
DEFINE_FIELD_X ( WBStartStruct , wbstartstruct_t , LName0 ) ;
DEFINE_FIELD_X ( WBStartStruct , wbstartstruct_t , LName1 ) ;
DEFINE_FIELD_X ( WBStartStruct , wbstartstruct_t , maxkills ) ;
DEFINE_FIELD_X ( WBStartStruct , wbstartstruct_t , maxitems ) ;
DEFINE_FIELD_X ( WBStartStruct , wbstartstruct_t , maxsecret ) ;
DEFINE_FIELD_X ( WBStartStruct , wbstartstruct_t , maxfrags ) ;
DEFINE_FIELD_X ( WBStartStruct , wbstartstruct_t , partime ) ;
DEFINE_FIELD_X ( WBStartStruct , wbstartstruct_t , sucktime ) ;
DEFINE_FIELD_X ( WBStartStruct , wbstartstruct_t , totaltime ) ;
DEFINE_FIELD_X ( WBStartStruct , wbstartstruct_t , pnum ) ;
DEFINE_FIELD_X ( WBStartStruct , wbstartstruct_t , plyr ) ;
2017-03-18 11:16:44 +00:00