/*
sequence . c - scripted sequences for CS : CZDS
Copyright ( C ) 2017 a1batross
This program is free software : you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation , either version 3 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
*/
# include <ctype.h>
# include "common.h"
# include "eiface.h"
# include "sequence.h"
sequenceCommandLine_s g_fileScopeDefaults ;
sequenceCommandLine_s g_blockScopeDefaults ;
sequenceEntry_s * g_sequenceList = NULL ;
sentenceGroupEntry_s * g_sentenceGroupList = NULL ;
qboolean g_sequenceParseFileIsGlobal ;
unsigned int g_nonGlobalSentences = 0 ;
char g_sequenceParseFileName [ MAX_STRING ] ;
int g_lineNum = 1 ;
char * g_scan = NULL ;
char * g_lineScan = NULL ;
const sequenceCommandMapping_s g_sequenceCommandMappingTable [ ] =
{
{ SEQUENCE_COMMAND_PAUSE , " pause " , SEQUENCE_TYPE_COMMAND } ,
{ SEQUENCE_COMMAND_TEXT , " text " , SEQUENCE_TYPE_COMMAND } ,
{ SEQUENCE_COMMAND_SOUND , " sound " , SEQUENCE_TYPE_COMMAND } ,
{ SEQUENCE_COMMAND_FIRETARGETS , " firetargets " , SEQUENCE_TYPE_COMMAND } ,
{ SEQUENCE_COMMAND_KILLTARGETS , " killtargets " , SEQUENCE_TYPE_COMMAND } ,
{ SEQUENCE_COMMAND_GOSUB , " gosub " , SEQUENCE_TYPE_COMMAND } ,
{ SEQUENCE_COMMAND_SENTENCE , " sentence " , SEQUENCE_TYPE_COMMAND } ,
{ SEQUENCE_COMMAND_REPEAT , " repeat " , SEQUENCE_TYPE_COMMAND } ,
{ SEQUENCE_COMMAND_SETDEFAULTS , " setdefaults " , SEQUENCE_TYPE_COMMAND } ,
{ SEQUENCE_COMMAND_MODIFIER , " modifier " , SEQUENCE_TYPE_COMMAND } ,
{ SEQUENCE_COMMAND_POSTMODIFIER , " postmodifier " , SEQUENCE_TYPE_COMMAND } ,
{ SEQUENCE_COMMAND_NOOP , " noop " , SEQUENCE_TYPE_COMMAND } ,
{ SEQUENCE_MODIFIER_EFFECT , " effect " , SEQUENCE_TYPE_MODIFIER } ,
{ SEQUENCE_MODIFIER_POSITION , " position " , SEQUENCE_TYPE_MODIFIER } ,
{ SEQUENCE_MODIFIER_COLOR , " color " , SEQUENCE_TYPE_MODIFIER } ,
{ SEQUENCE_MODIFIER_COLOR2 , " color2 " , SEQUENCE_TYPE_MODIFIER } ,
{ SEQUENCE_MODIFIER_FADEIN , " fadein " , SEQUENCE_TYPE_MODIFIER } ,
{ SEQUENCE_MODIFIER_FADEOUT , " fadeout " , SEQUENCE_TYPE_MODIFIER } ,
{ SEQUENCE_MODIFIER_HOLDTIME , " holdtime " , SEQUENCE_TYPE_MODIFIER } ,
{ SEQUENCE_MODIFIER_FXTIME , " fxtime " , SEQUENCE_TYPE_MODIFIER } ,
{ SEQUENCE_MODIFIER_SPEAKER , " speaker " , SEQUENCE_TYPE_MODIFIER } ,
{ SEQUENCE_MODIFIER_LISTENER , " listener " , SEQUENCE_TYPE_MODIFIER } ,
{ SEQUENCE_MODIFIER_TEXTCHANNEL , " channel " , SEQUENCE_TYPE_MODIFIER }
} ;
/*
= = = = = = = = = = = = =
Sequence_GetCommandEnumForName
= = = = = = = = = = = = =
*/
sequenceCommandEnum_e Sequence_GetCommandEnumForName ( const char * commandName , sequenceCommandType_e type )
{
int i ;
for ( i = 0 ; i < ARRAYSIZE ( g_sequenceCommandMappingTable ) ; i + + )
{
const sequenceCommandMapping_s * mapping = g_sequenceCommandMappingTable + i ;
if ( mapping - > commandType = = type & & ! Q_stricmp ( mapping - > commandName , commandName ) )
return mapping - > commandEnum ;
}
return SEQUENCE_COMMAND_ERROR ;
}
/*
= = = = = = = = = = = = =
Sequence_ResetDefaults
= = = = = = = = = = = = =
*/
void Sequence_ResetDefaults ( sequenceCommandLine_s * destination , sequenceCommandLine_s * source )
{
if ( ! source )
{
static client_textmessage_t defaultClientMessage =
{
0 , // effect
- 1 , - 1 , - 1 , - 1 , // rgba1
- 1 , - 1 , - 1 , - 1 , // rgba2
0.5 , 0.5 , // xy
0.2 , 0.2 , // fade-in/out
1.6 , // holdtime
1.0 , // fxtime
NULL , NULL // pName, pMessage
} ;
destination - > clientMessage = defaultClientMessage ;
destination - > textChannel = 0 ;
destination - > delay = 0 ;
destination - > repeatCount = 0 ;
destination - > nextCommandLine = NULL ;
destination - > soundFileName = NULL ;
destination - > speakerName = NULL ;
destination - > listenerName = NULL ;
return ;
}
destination - > clientMessage = source - > clientMessage ;
destination - > clientMessage . pName = NULL ;
destination - > clientMessage . pMessage = NULL ;
destination - > textChannel = source - > textChannel ;
destination - > delay = source - > delay ;
destination - > repeatCount = source - > repeatCount ;
destination - > nextCommandLine = NULL ;
destination - > soundFileName = NULL ;
Z_Free ( destination - > speakerName ) ;
destination - > speakerName = copystring ( source - > speakerName ) ;
Z_Free ( destination - > listenerName ) ;
destination - > listenerName = copystring ( source - > listenerName ) ;
}
/*
= = = = = = = = = = = = =
Sequence_WriteDefaults
= = = = = = = = = = = = =
*/
void Sequence_WriteDefaults ( sequenceCommandLine_s * source , sequenceCommandLine_s * destination )
{
if ( ! destination )
Con_Reportf ( S_ERROR " Attempt to bake defaults into a non-existant command. " ) ;
if ( ! source )
Con_Reportf ( S_ERROR " Attempt to bake defaults from a non-existant command. " ) ;
if ( source - > modifierBitField & SEQUENCE_MODIFIER_EFFECT_BIT )
{
destination - > clientMessage . effect = source - > clientMessage . effect ;
}
if ( source - > modifierBitField & SEQUENCE_MODIFIER_POSITION_BIT )
{
destination - > clientMessage . x = source - > clientMessage . x ;
destination - > clientMessage . y = source - > clientMessage . y ;
}
if ( source - > modifierBitField & SEQUENCE_MODIFIER_COLOR_BIT )
{
destination - > clientMessage . r1 = source - > clientMessage . r1 ;
destination - > clientMessage . g1 = source - > clientMessage . g1 ;
destination - > clientMessage . b1 = source - > clientMessage . b1 ;
destination - > clientMessage . a1 = source - > clientMessage . a1 ;
}
if ( source - > modifierBitField & SEQUENCE_MODIFIER_COLOR2_BIT )
{
destination - > clientMessage . r2 = source - > clientMessage . r2 ;
destination - > clientMessage . g2 = source - > clientMessage . g2 ;
destination - > clientMessage . b2 = source - > clientMessage . b2 ;
destination - > clientMessage . a2 = source - > clientMessage . a2 ;
}
if ( source - > modifierBitField & SEQUENCE_MODIFIER_FADEIN_BIT )
{
destination - > clientMessage . fadein = source - > clientMessage . fadein ;
}
if ( source - > modifierBitField & SEQUENCE_MODIFIER_FADEOUT_BIT )
{
destination - > clientMessage . fadeout = source - > clientMessage . fadeout ;
}
if ( source - > modifierBitField & SEQUENCE_MODIFIER_HOLDTIME_BIT )
{
destination - > clientMessage . holdtime = source - > clientMessage . holdtime ;
}
if ( source - > modifierBitField & SEQUENCE_MODIFIER_FXTIME_BIT )
{
destination - > clientMessage . fxtime = source - > clientMessage . fxtime ;
}
if ( source - > modifierBitField & SEQUENCE_MODIFIER_SPEAKER_BIT )
{
Z_Free ( destination - > speakerName ) ;
destination - > speakerName = copystring ( source - > speakerName ) ;
}
if ( source - > modifierBitField & SEQUENCE_MODIFIER_LISTENER_BIT )
{
Z_Free ( destination - > listenerName ) ;
destination - > listenerName = copystring ( source - > listenerName ) ;
}
if ( source - > modifierBitField & SEQUENCE_MODIFIER_TEXTCHANNEL_BIT )
{
destination - > textChannel = source - > textChannel ;
}
}
/*
= = = = = = = = = = = = =
Sequence_BakeDefaults
= = = = = = = = = = = = =
*/
void Sequence_BakeDefaults ( sequenceCommandLine_s * destination , sequenceCommandLine_s * source )
{
char * saveName , * saveMessage ;
if ( ! destination )
Con_Reportf ( S_ERROR " Attempt to bake defaults into a non-existant command. " ) ;
if ( ! source )
Con_Reportf ( S_ERROR " Attempt to bake defaults from a non-existant command. " ) ;
saveName = destination - > clientMessage . pName ;
saveMessage = destination - > clientMessage . pMessage ;
destination - > clientMessage = source - > clientMessage ;
destination - > clientMessage . pName = saveName ;
destination - > clientMessage . pMessage = saveMessage ;
destination - > textChannel = source - > textChannel ;
Z_Free ( destination - > speakerName ) ;
destination - > speakerName = copystring ( source - > speakerName ) ;
Z_Free ( destination - > listenerName ) ;
destination - > listenerName = copystring ( source - > listenerName ) ;
}
/*
= = = = = = = = = = = = =
Sequence_SkipWhitespace
= = = = = = = = = = = = =
*/
qboolean Sequence_SkipWhitespace ( void )
{
qboolean newLine = false ;
for ( ; isspace ( * g_scan ) ; g_scan + + )
{
if ( * g_scan = = ' \n ' )
{
g_lineScan = g_scan + 1 ;
g_lineNum + + ;
newLine = true ;
}
}
return newLine ;
}
/*
= = = = = = = = = = = = =
Sequence_IsNameValueChar
= = = = = = = = = = = = =
*/
qboolean Sequence_IsNameValueChar ( char ch )
{
if ( isalnum ( ch ) )
return true ;
switch ( ch )
{
case ' . ' :
case ' - ' :
case ' _ ' :
case ' / ' :
case ' \\ ' :
return true ;
}
return false ;
}
/*
= = = = = = = = = = = = =
Sequence_IsSymbol
= = = = = = = = = = = = =
*/
qboolean Sequence_IsSymbol ( char ch )
{
switch ( ch )
{
case ' " ' :
case ' # ' :
case ' $ ' :
case ' % ' :
case ' , ' :
case ' = ' :
case ' @ ' :
case ' { ' :
case ' } ' :
return true ;
}
return false ;
}
/*
= = = = = = = = = = = = =
Sequence_GetNameValueString
= = = = = = = = = = = = =
*/
size_t Sequence_GetNameValueString ( char * token , size_t len )
{
char * p ;
Sequence_SkipWhitespace ( ) ;
if ( ! Sequence_IsNameValueChar ( * g_scan ) )
{
if ( * g_scan = = ' # ' | | * g_scan = = ' $ ' )
Con_Reportf ( S_ERROR " Parsing error on line %d of %s.seq: cannot have more than one '%c' per line; '%c' must be at the beginning of the line ONLY \n " , g_lineNum , g_sequenceParseFileName , * g_scan , * g_scan ) ;
else
Con_Reportf ( S_ERROR " Parsing error on line %d of %s.seq: expected name/value, found illegal character '%c' \n " , g_lineNum , g_sequenceParseFileName , * g_scan ) ;
}
for ( p = token ; Sequence_IsNameValueChar ( * g_scan ) & & len ; p + + , g_scan + + , len - - )
{
* p = * g_scan ;
}
* p = 0 ;
return p - token ;
}
/*
= = = = = = = = = = = = =
Sequence_GetSymbol
= = = = = = = = = = = = =
*/
char Sequence_GetSymbol ( void )
{
char ch ;
Sequence_SkipWhitespace ( ) ;
ch = * g_scan ;
if ( ch )
g_scan + + ;
return ch ;
}
/*
= = = = = = = = = = = = =
Sequence_ValidateNameValueString
= = = = = = = = = = = = =
*/
void Sequence_ValidateNameValueString ( char * token )
{
char * scan ;
for ( scan = token ; * scan ; scan + + )
{
if ( ! Sequence_IsNameValueChar ( * scan ) )
Con_Reportf ( S_ERROR " Parsing error on line %d of %s.seq: name/value string \" %s \" had illegal character '%c' \n " , g_lineNum , g_sequenceParseFileName , token , * scan ) ;
}
}
/*
= = = = = = = = = = = = =
Sequence_GetToken
= = = = = = = = = = = = =
*/
size_t Sequence_GetToken ( char * token , size_t size )
{
Sequence_SkipWhitespace ( ) ;
if ( Sequence_IsNameValueChar ( * g_scan ) )
{
return Sequence_GetNameValueString ( token , size ) ;
}
if ( ! Sequence_IsSymbol ( * g_scan ) )
Con_Reportf ( S_ERROR " Parsing error on line %d of %s.seq: expected token, found '%c' instead \n " , g_lineNum , g_sequenceParseFileName , * g_scan ) ;
token [ 0 ] = * g_scan + + ;
token [ 1 ] = 0 ;
g_scan + + ;
return 1 ; // only one symbol has copied to token
}
/*
= = = = = = = = = = = = =
Sequence_GetLine
= = = = = = = = = = = = =
*/
size_t Sequence_GetLine ( char * line , int lineMaxLen )
{
int lineLen ;
char * read ;
char * write = line ;
Sequence_SkipWhitespace ( ) ;
read = Q_strchr ( g_scan , ' \n ' ) ;
if ( ! read )
Con_Reportf ( S_ERROR " Syntax Error on line %d of %s.seq: expected sentence definition or '}', found End-Of-File! \n " , g_lineNum , g_sequenceParseFileName ) ;
lineLen = read - g_scan ;
if ( lineLen > = lineMaxLen )
Con_Reportf ( S_ERROR " Syntax Error on line %d of %s.seq: line was too long (was %d chars; max is %d chars) \n " , g_lineNum , g_sequenceParseFileName , lineLen , lineMaxLen - 1 ) ;
Q_strncpy ( write , g_scan , lineLen ) ;
write [ lineLen ] = 0 ;
g_scan = read ;
return lineLen ;
}
/*
= = = = = = = = = = = = =
Sequence_StripComments
= = = = = = = = = = = = =
*/
void Sequence_StripComments ( char * buffer , int * pBufSize )
{
char * eof = buffer + * pBufSize ;
char * read = buffer ;
char * write = buffer ;
for ( ; read < eof ; )
{
if ( ! * read )
break ;
if ( * read = = ' / ' )
{
// skip one line comments //
if ( read [ 1 ] = = ' / ' )
{
read + = 2 ;
while ( * read )
{
if ( * read = = ' \n ' )
break ;
if ( * read = = ' \r ' )
break ;
read + + ;
}
continue ;
}
// skip multiline /* */
if ( read [ 1 ] = = ' * ' )
{
read + = 2 ;
while ( * read & & read [ 1 ] )
{
if ( * read = = ' * ' & & read [ 1 ] = = ' / ' )
{
read + = 2 ;
break ;
}
if ( * read = = ' \n ' | | * read = = ' \r ' )
* write + + = * read ;
read + + ;
}
continue ;
}
}
* write + + = * read + + ;
}
* write = 0 ;
}
/*
= = = = = = = = = = = = =
Sequence_ReadInt
= = = = = = = = = = = = =
*/
int Sequence_ReadInt ( void )
{
char str [ MAX_STRING ] ;
Sequence_SkipWhitespace ( ) ;
Sequence_GetNameValueString ( str , MAX_STRING ) ;
return Q_atoi ( str ) ;
}
/*
= = = = = = = = = = = = =
Sequence_ReadFloat
= = = = = = = = = = = = =
*/
float Sequence_ReadFloat ( void )
{
char str [ MAX_STRING ] ;
Sequence_SkipWhitespace ( ) ;
Sequence_GetNameValueString ( str , MAX_STRING ) ;
return Q_atof ( str ) ;
}
/*
= = = = = = = = = = = = =
Sequence_ReadFloat
= = = = = = = = = = = = =
*/
void Sequence_ReadString ( char * * dest , char * string , size_t len )
{
Sequence_SkipWhitespace ( ) ;
Sequence_GetNameValueString ( string , len ) ;
if ( dest ) * dest = copystring ( string ) ;
}
/*
= = = = = = = = = = = = =
Sequence_ReadQuotedString
= = = = = = = = = = = = =
*/
void Sequence_ReadQuotedString ( char * * dest , char * str , size_t len )
{
char * write , ch ;
Sequence_SkipWhitespace ( ) ;
ch = Sequence_GetSymbol ( ) ;
if ( ch ! = ' \" ' )
Con_Reportf ( S_ERROR " Parsing error on or before line %d of %s.seq: expected quote ( \" ), found '%c' instead \n " , g_lineNum , g_sequenceParseFileName , ch ) ;
for ( write = str ; * g_scan & & len ; write + + , g_scan + + , len - - )
{
if ( * g_scan = = ' \" ' )
break ;
if ( * g_scan = = ' \n ' )
g_lineNum + + ;
* write = * g_scan ;
}
* write = 0 ;
g_scan + + ;
if ( dest ) * dest = copystring ( str ) ;
}
/*
= = = = = = = = = = = = =
Sequence_ConfirmCarriageReturnOrSymbol
= = = = = = = = = = = = =
*/
qboolean Sequence_ConfirmCarriageReturnOrSymbol ( char symbol )
{
if ( Sequence_SkipWhitespace ( ) )
return true ;
return * g_scan = = symbol ;
}
/*
= = = = = = = = = = = = =
Sequence_IsCommandAModifier
= = = = = = = = = = = = =
*/
qboolean Sequence_IsCommandAModifier ( sequenceCommandEnum_e commandEnum )
{
int i ;
for ( i = 0 ; i < ARRAYSIZE ( g_sequenceCommandMappingTable ) ; i + + )
{
if ( g_sequenceCommandMappingTable [ i ] . commandEnum = = commandEnum )
return ( g_sequenceCommandMappingTable [ i ] . commandType = = SEQUENCE_TYPE_MODIFIER ) ;
}
Con_Reportf ( S_ERROR " Internal error caused by line %d of %s.seq: unknown command enum = %d \n " , g_lineNum , g_sequenceParseFileName , commandEnum ) ;
return false ;
}
/*
= = = = = = = = = = = = =
Sequence_ReadCommandData
= = = = = = = = = = = = =
*/
void Sequence_ReadCommandData ( sequenceCommandEnum_e commandEnum , sequenceCommandLine_s * defaults )
{
char temp [ 1024 ] ;
if ( commandEnum > = SEQUENCE_MODIFIER_EFFECT | | commandEnum < = SEQUENCE_MODIFIER_TEXTCHANNEL )
defaults - > modifierBitField | = BIT ( SEQUENCE_MODIFIER_EFFECT - SEQUENCE_COMMAND_NOOP ) ;
switch ( commandEnum )
{
case SEQUENCE_COMMAND_PAUSE :
defaults - > delay = Sequence_ReadFloat ( ) ;
break ;
case SEQUENCE_COMMAND_FIRETARGETS :
Sequence_ReadQuotedString ( & defaults - > fireTargetNames , temp , sizeof ( temp ) ) ;
break ;
case SEQUENCE_COMMAND_KILLTARGETS :
Sequence_ReadQuotedString ( & defaults - > killTargetNames , temp , sizeof ( temp ) ) ;
break ;
case SEQUENCE_COMMAND_TEXT :
Sequence_ReadQuotedString ( & defaults - > clientMessage . pMessage , temp , sizeof ( temp ) ) ;
break ;
case SEQUENCE_COMMAND_SOUND :
Sequence_ReadString ( & defaults - > soundFileName , temp , sizeof ( temp ) ) ;
break ;
case SEQUENCE_COMMAND_GOSUB :
Sequence_ReadString ( & defaults - > clientMessage . pName , temp , sizeof ( temp ) ) ;
break ;
case SEQUENCE_COMMAND_SENTENCE :
Sequence_ReadString ( & defaults - > sentenceName , temp , sizeof ( temp ) ) ;
break ;
case SEQUENCE_COMMAND_REPEAT :
defaults - > repeatCount = Sequence_ReadInt ( ) ;
break ;
case SEQUENCE_MODIFIER_EFFECT :
defaults - > clientMessage . effect = Sequence_ReadInt ( ) ;
break ;
case SEQUENCE_MODIFIER_POSITION :
defaults - > clientMessage . x = Sequence_ReadFloat ( ) ;
defaults - > clientMessage . y = Sequence_ReadFloat ( ) ;
break ;
case SEQUENCE_MODIFIER_COLOR :
defaults - > clientMessage . r1 = Sequence_ReadInt ( ) ;
defaults - > clientMessage . g1 = Sequence_ReadInt ( ) ;
defaults - > clientMessage . b1 = Sequence_ReadInt ( ) ;
defaults - > clientMessage . a1 = 255 ;
break ;
case SEQUENCE_MODIFIER_COLOR2 :
defaults - > clientMessage . r2 = Sequence_ReadInt ( ) ;
defaults - > clientMessage . g2 = Sequence_ReadInt ( ) ;
defaults - > clientMessage . b2 = Sequence_ReadInt ( ) ;
defaults - > clientMessage . a2 = 255 ;
break ;
case SEQUENCE_MODIFIER_FADEIN :
defaults - > clientMessage . fadein = Sequence_ReadFloat ( ) ;
break ;
case SEQUENCE_MODIFIER_FADEOUT :
defaults - > clientMessage . fadeout = Sequence_ReadFloat ( ) ;
break ;
case SEQUENCE_MODIFIER_HOLDTIME :
defaults - > clientMessage . holdtime = Sequence_ReadFloat ( ) ;
break ;
case SEQUENCE_MODIFIER_FXTIME :
defaults - > clientMessage . fxtime = Sequence_ReadFloat ( ) ;
break ;
case SEQUENCE_MODIFIER_SPEAKER :
Sequence_ReadString ( & defaults - > speakerName , temp , sizeof ( temp ) ) ;
break ;
case SEQUENCE_MODIFIER_LISTENER :
Sequence_ReadString ( & defaults - > listenerName , temp , sizeof ( temp ) ) ;
break ;
case SEQUENCE_MODIFIER_TEXTCHANNEL :
defaults - > textChannel = Sequence_ReadInt ( ) ;
break ;
default :
Con_Reportf ( S_ERROR " Internal error caused by line %d of %s.seq: unknown command enum = %d \n " , g_lineNum , g_sequenceParseFileName , commandEnum ) ;
}
}
/*
= = = = = = = = = = = = =
Sequence_ParseModifier
= = = = = = = = = = = = =
*/
char Sequence_ParseModifier ( sequenceCommandLine_s * defaults )
{
char modifierName [ MAX_STRING ] ;
char delimiter ;
sequenceCommandEnum_e modifierEnum ;
Sequence_GetNameValueString ( modifierName , MAX_STRING ) ;
modifierEnum = Sequence_GetCommandEnumForName ( modifierName , SEQUENCE_TYPE_MODIFIER ) ;
if ( modifierEnum = = SEQUENCE_COMMAND_ERROR )
Con_Reportf ( S_ERROR " Parsing error on line %d of %s.seq: unknown modifier \" %s \" \n " , g_lineNum , g_sequenceParseFileName , modifierName ) ;
if ( ! Sequence_IsCommandAModifier ( modifierEnum ) )
Con_Reportf ( S_ERROR " Parsing error on line %d of %s.seq: \" %s \" is a #command, not a $modifier \n " , g_lineNum , g_sequenceParseFileName , modifierName ) ;
delimiter = Sequence_GetSymbol ( ) ;
if ( delimiter ! = ' = ' )
Con_Reportf ( S_ERROR " Parsing error on or after line %d of %s.seq: after modifier \" %s \" , expected '=', found '%c' \n " , g_lineNum , g_sequenceParseFileName , modifierName , delimiter ) ;
Sequence_ReadCommandData ( modifierEnum , defaults ) ;
if ( ! Sequence_ConfirmCarriageReturnOrSymbol ( ' , ' ) )
Con_Reportf ( S_ERROR " Parsing error on line %d of %s.seq: after value(s) for modifier \" %s \" , expected ',' or End-Of-Line; found '%c' \n " , g_lineNum , g_sequenceParseFileName , modifierName , * g_scan ) ;
return Sequence_GetSymbol ( ) ;
}
/*
= = = = = = = = = = = = =
Sequence_AddCommandLineToEntry
= = = = = = = = = = = = =
*/
void Sequence_AddCommandLineToEntry ( sequenceCommandLine_s * commandLine , sequenceEntry_s * entry )
{
sequenceCommandLine_s * scan ;
if ( entry - > firstCommand )
{
for ( scan = entry - > firstCommand ; scan - > nextCommandLine ; scan = scan - > nextCommandLine ) ;
scan - > nextCommandLine = commandLine ;
}
else entry - > firstCommand = commandLine ;
commandLine - > nextCommandLine = NULL ;
}
/*
= = = = = = = = = = = = =
Sequence_ParseModifierLine
= = = = = = = = = = = = =
*/
char Sequence_ParseModifierLine ( sequenceEntry_s * entry , sequenceCommandType_e modifierType )
{
sequenceCommandLine_s * newCommandLine ;
char delimiter = ' , ' ;
while ( delimiter = = ' , ' )
{
switch ( modifierType )
{
case SEQUENCE_TYPE_COMMAND :
newCommandLine = Z_Malloc ( sizeof ( sequenceCommandLine_s ) ) ;
memset ( newCommandLine , 0 , sizeof ( sequenceCommandLine_s ) ) ;
newCommandLine - > commandType = SEQUENCE_COMMAND_MODIFIER ;
Sequence_AddCommandLineToEntry ( newCommandLine , entry ) ;
delimiter = Sequence_ParseModifier ( newCommandLine ) ;
break ;
case SEQUENCE_TYPE_MODIFIER :
delimiter = Sequence_ParseModifier ( & g_fileScopeDefaults ) ;
break ;
}
}
return delimiter ;
}
/*
= = = = = = = = = = = = =
Sequence_ParseCommand
= = = = = = = = = = = = =
*/
char Sequence_ParseCommand ( sequenceCommandLine_s * newCommandLine )
{
char commandName [ MAX_STRING ] , ch ;
sequenceCommandEnum_e commandEnum ;
sequenceCommandLine_s * modifierCommandLine ;
Sequence_GetNameValueString ( commandName , MAX_STRING ) ;
commandEnum = Sequence_GetCommandEnumForName ( commandName , SEQUENCE_TYPE_COMMAND ) ;
if ( commandEnum = = SEQUENCE_COMMAND_ERROR )
Con_Reportf ( S_ERROR " Parsing error on line %d of %s.seq: unknown command \" %s \" \n " , g_lineNum , g_sequenceParseFileName , commandName ) ;
if ( Sequence_IsCommandAModifier ( commandEnum ) )
{
modifierCommandLine = Z_Malloc ( sizeof ( sequenceCommandLine_s ) ) ;
memset ( modifierCommandLine , 0 , sizeof ( sequenceCommandLine_s ) ) ;
modifierCommandLine - > commandType = SEQUENCE_COMMAND_POSTMODIFIER ;
for ( ; newCommandLine - > nextCommandLine ; newCommandLine = newCommandLine - > nextCommandLine ) ;
newCommandLine - > nextCommandLine = modifierCommandLine ;
newCommandLine = modifierCommandLine ;
}
ch = Sequence_GetSymbol ( ) ;
if ( ch ! = ' = ' )
Con_Reportf ( S_ERROR " Parsing error on or before line %d of %s.seq: after command \" %s \" , expected '=', found '%c' \n " ,
g_lineNum , g_sequenceParseFileName , commandName , ch ) ;
Sequence_ReadCommandData ( commandEnum , newCommandLine ) ;
return Sequence_GetSymbol ( ) ;
}
/*
= = = = = = = = = = = = =
Sequence_ParseCommandLine
= = = = = = = = = = = = =
*/
char Sequence_ParseCommandLine ( sequenceEntry_s * entry )
{
char symbol ;
sequenceCommandLine_s * newCommandLine ;
newCommandLine = Z_Malloc ( sizeof ( sequenceCommandLine_s ) ) ;
memset ( newCommandLine , 0 , sizeof ( sequenceCommandLine_s ) ) ;
Sequence_ResetDefaults ( newCommandLine , & g_blockScopeDefaults ) ;
Sequence_AddCommandLineToEntry ( newCommandLine , entry ) ;
symbol = Sequence_ParseCommand ( newCommandLine ) ;
while ( symbol = = ' , ' )
{
symbol = Sequence_ParseCommand ( newCommandLine ) ;
}
return symbol ;
}
/*
= = = = = = = = = = = = =
Sequence_ParseMacro
= = = = = = = = = = = = =
*/
char Sequence_ParseMacro ( sequenceEntry_s * entry )
{
char symbol ;
sequenceCommandLine_s * newCommandLine ;
newCommandLine = Z_Malloc ( sizeof ( sequenceCommandLine_s ) ) ;
memset ( newCommandLine , 0 , sizeof ( sequenceCommandLine_s ) ) ;
Sequence_ResetDefaults ( newCommandLine , & g_blockScopeDefaults ) ;
Sequence_AddCommandLineToEntry ( newCommandLine , entry ) ;
Sequence_ReadCommandData ( SEQUENCE_COMMAND_GOSUB , newCommandLine ) ;
symbol = Sequence_GetSymbol ( ) ;
while ( symbol = = ' , ' )
{
symbol = Sequence_ParseCommand ( newCommandLine ) ;
}
return symbol ;
}
/*
= = = = = = = = = = = = =
Sequence_ParseLine
= = = = = = = = = = = = =
*/
char Sequence_ParseLine ( char start , sequenceEntry_s * entry )
{
char end = ' \0 ' ;
switch ( start )
{
case ' # ' :
end = Sequence_ParseCommandLine ( entry ) ;
break ;
case ' $ ' :
end = Sequence_ParseModifierLine ( entry , SEQUENCE_TYPE_MODIFIER ) ;
break ;
case ' @ ' :
end = Sequence_ParseMacro ( entry ) ;
break ;
default :
Con_Reportf ( S_ERROR " Parsing error on line %d of %s.seq: line must begin with either '#' (command) or '$' (modifier); found '%c' \n " , g_lineNum , g_sequenceParseFileName , start ) ;
}
return end ;
}
/*
= = = = = = = = = = = = =
Sequence_CalcEntryDuration
= = = = = = = = = = = = =
*/
float Sequence_CalcEntryDuration ( sequenceEntry_s * entry )
{
float duration ;
sequenceCommandLine_s * cmd ;
duration = 0 ;
for ( cmd = entry - > firstCommand ; cmd ; cmd = cmd - > nextCommandLine )
duration + = cmd - > delay ;
return duration ;
}
/*
= = = = = = = = = = = = =
Sequence_DoesEntryContainInfiniteLoop
= = = = = = = = = = = = =
*/
qboolean Sequence_DoesEntryContainInfiniteLoop ( sequenceEntry_s * entry )
{
sequenceCommandLine_s * cmd ;
for ( cmd = entry - > firstCommand ; cmd ; cmd = cmd - > nextCommandLine )
{
if ( cmd - > repeatCount < 0 )
return true ;
}
return false ;
}
/*
= = = = = = = = = = = = =
Sequence_IsEntrySafe
= = = = = = = = = = = = =
*/
qboolean Sequence_IsEntrySafe ( sequenceEntry_s * entry )
{
float duration ;
sequenceCommandLine_s * cmd ;
duration = 0 ;
for ( cmd = entry - > firstCommand ; cmd ; cmd = cmd - > nextCommandLine )
{
duration + = cmd - > delay ;
if ( cmd - > repeatCount < 0 )
{
if ( duration < = 0 )
return false ;
}
}
return true ;
}
/*
= = = = = = = = = = = = =
Sequence_CreateDefaultsCommand
= = = = = = = = = = = = =
*/
void Sequence_CreateDefaultsCommand ( sequenceEntry_s * entry )
{
sequenceCommandLine_s * cmd ;
cmd = Z_Malloc ( sizeof ( sequenceCommandLine_s ) ) ;
memset ( cmd , 0 , sizeof ( sequenceCommandLine_s ) ) ;
Sequence_ResetDefaults ( cmd , & g_fileScopeDefaults ) ;
cmd - > commandType = SEQUENCE_COMMAND_SETDEFAULTS ;
cmd - > modifierBitField = SEQUENCE_MODIFIER_EFFECT_BIT |
SEQUENCE_MODIFIER_POSITION_BIT |
SEQUENCE_MODIFIER_COLOR_BIT |
SEQUENCE_MODIFIER_COLOR2_BIT |
SEQUENCE_MODIFIER_FADEIN_BIT |
SEQUENCE_MODIFIER_FADEOUT_BIT |
SEQUENCE_MODIFIER_HOLDTIME_BIT |
SEQUENCE_MODIFIER_FXTIME_BIT ;
Sequence_AddCommandLineToEntry ( cmd , entry ) ;
}
/*
= = = = = = = = = = = = =
Sequence_ParseEntry
= = = = = = = = = = = = =
*/
char Sequence_ParseEntry ( void )
{
char symbol ;
char token [ MAX_STRING ] ;
sequenceEntry_s * entry ;
Sequence_GetNameValueString ( token , MAX_STRING ) ;
symbol = Sequence_GetSymbol ( ) ;
if ( symbol ! = ' { ' )
Con_Reportf ( S_ERROR " Parsing error on line %d of %s.seq: expected '{' to start a \n new entry block; found '%c' instead! " , g_lineNum , g_sequenceParseFileName , symbol ) ;
entry = Z_Malloc ( sizeof ( sequenceEntry_s ) ) ;
Sequence_ResetDefaults ( & g_blockScopeDefaults , & g_fileScopeDefaults ) ;
entry - > entryName = copystring ( token ) ;
entry - > fileName = copystring ( g_sequenceParseFileName ) ;
entry - > isGlobal = g_sequenceParseFileIsGlobal ;
entry - > firstCommand = NULL ;
Sequence_CreateDefaultsCommand ( entry ) ;
symbol = Sequence_GetSymbol ( ) ;
while ( symbol ! = ' } ' )
{
symbol = Sequence_ParseLine ( symbol , entry ) ;
}
if ( ! Sequence_IsEntrySafe ( entry ) )
Con_Reportf ( S_ERROR " Logic error in file %s.seq before line %d: execution of entry \" %%%s \" would cause an infinite loop! " , g_sequenceParseFileName , g_lineNum , entry - > entryName ) ;
entry - > nextEntry = g_sequenceList ;
g_sequenceList = entry ;
return Sequence_GetSymbol ( ) ;
}
/*
= = = = = = = = = = = = =
Sequence_FindSentenceGroup
= = = = = = = = = = = = =
*/
sentenceGroupEntry_s * Sequence_FindSentenceGroup ( const char * groupName )
{
sentenceGroupEntry_s * groupEntry ;
for ( groupEntry = g_sentenceGroupList ; groupEntry ; groupEntry = groupEntry - > nextEntry )
{
if ( ! Q_stricmp ( groupEntry - > groupName , groupName ) )
return groupEntry ;
}
return NULL ;
}
/*
= = = = = = = = = = = = =
Sequence_GetSentenceByIndex
= = = = = = = = = = = = =
*/
sentenceEntry_s * Sequence_GetSentenceByIndex ( unsigned int index )
{
sentenceEntry_s * sentenceEntry ;
sentenceGroupEntry_s * groupEntry ;
unsigned int sentenceCount = 0 ;
for ( groupEntry = g_sentenceGroupList ; groupEntry ; groupEntry = groupEntry - > nextEntry )
{
sentenceCount + = groupEntry - > numSentences ;
if ( index < sentenceCount )
{
for ( sentenceEntry = groupEntry - > firstSentence ; sentenceEntry ; sentenceEntry = sentenceEntry - > nextEntry )
{
if ( sentenceEntry - > index = = index )
return sentenceEntry ;
}
}
}
return NULL ;
}
/*
= = = = = = = = = = = = =
Sequence_PickSentence
= = = = = = = = = = = = =
*/
sentenceEntry_s * Sequence_PickSentence ( const char * groupName , int pickMethod , int * picked )
{
sentenceEntry_s * sentenceEntry ;
sentenceGroupEntry_s * groupEntry ;
unsigned int pickedIdx ;
unsigned int entryIdx ;
groupEntry = Sequence_FindSentenceGroup ( groupName ) ;
if ( groupEntry )
{
pickedIdx = COM_RandomLong ( 0 , groupEntry - > numSentences - 1 ) ;
sentenceEntry = groupEntry - > firstSentence ;
for ( entryIdx = pickedIdx ; entryIdx ; entryIdx - - )
sentenceEntry = sentenceEntry - > nextEntry ;
}
else
{
pickedIdx = 0 ;
sentenceEntry = NULL ;
}
if ( picked )
* picked = pickedIdx ;
return sentenceEntry ;
}
/*
= = = = = = = = = = = = =
Sequence_AddSentenceGroup
= = = = = = = = = = = = =
*/
sentenceGroupEntry_s * Sequence_AddSentenceGroup ( char * groupName )
{
sentenceGroupEntry_s * entry , * last ;
entry = Z_Malloc ( sizeof ( sentenceGroupEntry_s ) ) ;
entry - > numSentences = 0 ;
entry - > firstSentence = NULL ;
entry - > nextEntry = NULL ;
entry - > groupName = copystring ( groupName ) ;
if ( g_sentenceGroupList )
{
for ( last = g_sentenceGroupList ; last - > nextEntry ; last = last - > nextEntry ) ;
last - > nextEntry = entry ;
}
else
{
g_sentenceGroupList = entry ;
}
return entry ;
}
/*
= = = = = = = = = = = = =
Sequence_AddSentenceToGroup
= = = = = = = = = = = = =
*/
void Sequence_AddSentenceToGroup ( char * groupName , char * data )
{
sentenceEntry_s * entry , * last ;
sentenceGroupEntry_s * group ;
group = Sequence_FindSentenceGroup ( groupName ) ;
if ( ! group )
{
group = Sequence_AddSentenceGroup ( groupName ) ;
if ( ! group )
Con_Reportf ( S_ERROR " Unable to allocate sentence group %s at line %d in file %s.seq " , groupName , g_lineNum , g_sequenceParseFileName ) ;
}
entry = Z_Malloc ( sizeof ( sentenceEntry_s ) ) ;
entry - > nextEntry = NULL ;
entry - > data = copystring ( data ) ;
entry - > index = g_nonGlobalSentences ;
entry - > isGlobal = g_sequenceParseFileIsGlobal ;
group - > numSentences + + ;
g_nonGlobalSentences + + ;
if ( group - > firstSentence )
{
for ( last = group - > firstSentence ; last - > nextEntry ; last = last - > nextEntry ) ;
last - > nextEntry = entry ;
}
else
{
group - > firstSentence = entry ;
}
}
/*
= = = = = = = = = = = = =
Sequence_ParseSentenceLine
= = = = = = = = = = = = =
*/
qboolean Sequence_ParseSentenceLine ( void )
{
char data [ 1024 ] ;
char fullgroup [ 64 ] ;
char groupName [ 64 ] ;
char * c ;
int lastCharacterPos ;
size_t len ;
len = Sequence_GetToken ( fullgroup , sizeof ( fullgroup ) ) ;
if ( * fullgroup = = ' } ' )
return true ;
c = fullgroup + len ;
while ( ! isalpha ( * c ) & & * c ! = ' _ ' )
c - - ;
c + = 1 ;
if ( * c )
* c = 0 ;
strcpy ( groupName , fullgroup ) ;
len = Sequence_GetLine ( data , sizeof ( data ) ) ;
lastCharacterPos = len - 1 ;
if ( data [ lastCharacterPos ] = = ' \n ' | | data [ lastCharacterPos ] = = ' \r ' )
data [ lastCharacterPos ] = 0 ;
Sequence_AddSentenceToGroup ( groupName , data ) ;
return false ;
}
/*
= = = = = = = = = = = = = =
Sequence_ParseSentenceBlock
= = = = = = = = = = = = = =
*/
char Sequence_ParseSentenceBlock ( void )
{
qboolean end = false ;
char ch = Sequence_GetSymbol ( ) ;
if ( ch ! = ' { ' )
Con_Reportf ( S_ERROR " Parsing error on line %d of %s.seq: expected '{' to start a \n new sentence block; found '%c' instead! " , g_lineNum , g_sequenceParseFileName , ch ) ;
while ( ! end )
{
end = Sequence_ParseSentenceLine ( ) ;
}
return Sequence_GetSymbol ( ) ;
}
/*
= = = = = = = = = = = = = =
Sequence_ParseGlobalDataBlock
= = = = = = = = = = = = = =
*/
char Sequence_ParseGlobalDataBlock ( void )
{
char token [ MAX_STRING ] ;
Sequence_GetNameValueString ( token , MAX_STRING ) ;
if ( Q_stricmp ( token , " Sentences " ) )
Con_Reportf ( S_ERROR " Syntax error in file %s.seq on line %d: found global data block symbol '!' with unknown data type \" %s \" " , g_sequenceParseFileName , g_lineNum , token ) ;
return Sequence_ParseSentenceBlock ( ) ;
}
/*
= = = = = = = = = = = = = =
Sequence_GetEntryForName
= = = = = = = = = = = = = =
*/
sequenceEntry_s * Sequence_GetEntryForName ( const char * entryName )
{
sequenceEntry_s * scan ;
for ( scan = g_sequenceList ; scan ; scan = scan - > nextEntry )
{
if ( ! Q_stricmp ( entryName , scan - > entryName ) )
return scan ;
}
return NULL ;
}
/*
= = = = = = = = = = = = = =
Sequence_CopyCommand
= = = = = = = = = = = = = =
*/
sequenceCommandLine_s * Sequence_CopyCommand ( sequenceCommandLine_s * commandOrig )
{
sequenceCommandLine_s * commandCopy ;
commandCopy = Z_Malloc ( sizeof ( sequenceCommandLine_s ) ) ;
commandCopy - > commandType = commandOrig - > commandType ;
commandCopy - > clientMessage = commandOrig - > clientMessage ;
commandCopy - > clientMessage . pMessage = copystring ( commandOrig - > clientMessage . pMessage ) ;
commandCopy - > clientMessage . pName = copystring ( commandOrig - > clientMessage . pName ) ;
commandCopy - > speakerName = copystring ( commandOrig - > speakerName ) ;
commandCopy - > listenerName = copystring ( commandOrig - > listenerName ) ;
commandCopy - > soundFileName = copystring ( commandOrig - > soundFileName ) ;
commandCopy - > sentenceName = copystring ( commandOrig - > sentenceName ) ;
commandCopy - > fireTargetNames = copystring ( commandOrig - > fireTargetNames ) ;
commandCopy - > killTargetNames = copystring ( commandOrig - > killTargetNames ) ;
commandCopy - > delay = commandOrig - > delay ;
commandCopy - > repeatCount = commandOrig - > repeatCount ;
commandCopy - > textChannel = commandOrig - > textChannel ;
commandCopy - > modifierBitField = commandOrig - > modifierBitField ;
commandCopy - > nextCommandLine = NULL ;
return commandCopy ;
}
/*
= = = = = = = = = = = = = =
Sequence_CopyCommandList
= = = = = = = = = = = = = =
*/
sequenceCommandLine_s * Sequence_CopyCommandList ( sequenceCommandLine_s * list )
{
sequenceCommandLine_s * scan , * copy , * new , * prev ;
copy = NULL ;
prev = NULL ;
for ( scan = list ; scan ; scan = scan - > nextCommandLine )
{
if ( scan - > commandType ! = SEQUENCE_COMMAND_SETDEFAULTS )
{
new = Sequence_CopyCommand ( scan ) ;
if ( prev )
{
prev - > nextCommandLine = new ;
prev = new ;
}
else
{
prev = new ;
copy = new ;
}
}
}
return copy ;
}
/*
= = = = = = = = = = = = = =
Sequence_ExpandGosubsForEntry
= = = = = = = = = = = = = =
*/
qboolean Sequence_ExpandGosubsForEntry ( sequenceEntry_s * entry )
{
sequenceCommandLine_s * cmd , * copyList , * scan ;
sequenceEntry_s * gosubEntry ;
qboolean foundGosubs = false ;
for ( cmd = entry - > firstCommand ; cmd ; cmd = cmd - > nextCommandLine )
{
if ( ! cmd - > clientMessage . pName )
continue ;
if ( ! Q_stricmp ( cmd - > clientMessage . pName , entry - > entryName ) )
Con_Reportf ( S_ERROR " Error in %s.seq: entry \" %s \" gosubs itself! \n " , entry - > fileName , entry - > entryName ) ;
gosubEntry = Sequence_GetEntryForName ( cmd - > clientMessage . pName ) ;
if ( ! gosubEntry )
Con_Reportf ( S_ERROR " Error in %s.seq: Gosub in entry \" %s \" specified unknown entry \" %s \" \n " , entry - > fileName , entry - > entryName , cmd - > clientMessage . pName ) ;
foundGosubs = true ;
copyList = Sequence_CopyCommandList ( gosubEntry - > firstCommand ) ;
if ( copyList )
{
for ( scan = copyList - > nextCommandLine ; scan ; scan = scan - > nextCommandLine ) ;
scan - > nextCommandLine = cmd - > nextCommandLine ;
Z_Free ( cmd - > clientMessage . pName ) ;
cmd - > clientMessage . pName = NULL ;
cmd = scan ;
}
else
{
Z_Free ( cmd - > clientMessage . pName ) ;
cmd - > clientMessage . pName = NULL ;
}
}
return ! foundGosubs ;
}
/*
= = = = = = = = = = = = = =
Sequence_ExpandAllGosubs
= = = = = = = = = = = = = =
*/
void Sequence_ExpandAllGosubs ( void )
{
sequenceEntry_s * scan ;
qboolean isComplete = true ;
while ( ! isComplete )
{
for ( scan = g_sequenceList ; scan ; scan = scan - > nextEntry )
{
isComplete = Sequence_ExpandGosubsForEntry ( scan ) ;
}
}
}
/*
= = = = = = = = = = = = = =
Sequence_FlattenEntry
= = = = = = = = = = = = = =
*/
void Sequence_FlattenEntry ( sequenceEntry_s * entry )
{
sequenceCommandLine_s * cmd , * last = NULL ;
for ( cmd = entry - > firstCommand ; cmd ; cmd = cmd - > nextCommandLine )
{
switch ( cmd - > commandType )
{
case SEQUENCE_COMMAND_SETDEFAULTS :
Sequence_WriteDefaults ( cmd , & g_blockScopeDefaults ) ;
cmd - > commandType = SEQUENCE_COMMAND_NOOP ;
break ;
case SEQUENCE_COMMAND_MODIFIER :
Sequence_WriteDefaults ( cmd , & g_blockScopeDefaults ) ;
break ;
case SEQUENCE_COMMAND_POSTMODIFIER :
Sequence_WriteDefaults ( cmd , last ) ;
break ;
default :
Sequence_BakeDefaults ( cmd , & g_blockScopeDefaults ) ;
last = cmd ;
}
}
}
/*
= = = = = = = = = = = = = =
Sequence_FlattenAllEntries
= = = = = = = = = = = = = =
*/
void Sequence_FlattenAllEntries ( void )
{
sequenceEntry_s * entry ;
for ( entry = g_sequenceList ; entry ; entry = entry - > nextEntry )
Sequence_FlattenEntry ( entry ) ;
}
/*
= = = = = = = = = = = = = =
Sequence_ParseBuffer
= = = = = = = = = = = = = =
*/
void Sequence_ParseBuffer ( byte * buffer , int bufferSize )
{
char symbol ;
g_lineNum = 1 ;
g_scan = buffer ;
g_lineScan = g_scan ;
Sequence_StripComments ( buffer , & bufferSize ) ;
Sequence_ResetDefaults ( & g_fileScopeDefaults , NULL ) ;
symbol = Sequence_GetSymbol ( ) ;
while ( symbol )
{
switch ( symbol )
{
case ' $ ' :
do
symbol = Sequence_ParseModifier ( & g_fileScopeDefaults ) ;
while ( symbol = = ' , ' ) ;
break ;
case ' % ' :
symbol = Sequence_ParseEntry ( ) ;
break ;
case ' ! ' :
symbol = Sequence_ParseGlobalDataBlock ( ) ;
break ;
default :
Con_Reportf ( S_ERROR " Parsing error on line %d of %s.seq: At file scope, lines must begin with '$' (modifier) or '%%' (entry block) or '!' (sentence / global data block); found '%c' \n " , g_lineNum , g_sequenceParseFileName , symbol ) ;
}
}
Sequence_ExpandAllGosubs ( ) ;
Sequence_FlattenAllEntries ( ) ;
}
/*
= = = = = = = = = = = = = =
Sequence_ParseFile
= = = = = = = = = = = = = =
*/
void Sequence_ParseFile ( const char * fileName , qboolean isGlobal )
{
byte * buffer ;
fs_offset_t bufSize = 0 ;
Q_strcpy ( g_sequenceParseFileName , fileName ) ;
g_sequenceParseFileIsGlobal = isGlobal ;
buffer = FS_LoadFile ( va ( " sequences/%s.seq " , fileName ) , & bufSize , true ) ;
if ( ! buffer )
return ;
MsgDev ( D_INFO , " reading sequence file: %s \n " , fileName ) ;
Sequence_ParseBuffer ( buffer , bufSize ) ;
Mem_Free ( buffer ) ;
}
/*
= = = = = = = = = = = = = =
Sequence_Init
= = = = = = = = = = = = = =
*/
void Sequence_Init ( void )
{
Sequence_ParseFile ( " global " , true ) ;
}
/*
= = = = = = = = = = = = = =
SequenceGet
= = = = = = = = = = = = = =
*/
sequenceEntry_s * Sequence_Get ( const char * fileName , const char * entryName )
{
sequenceEntry_s * scan ;
for ( scan = g_sequenceList ; scan ; scan = scan - > nextEntry )
{
if ( ( ! fileName | | ! Q_stricmp ( fileName , scan - > fileName ) ) & & // a1ba: add filename check, even if originally it is ignored
! Q_stricmp ( entryName , scan - > entryName ) )
return scan ;
}
return NULL ;
}
/*
= = = = = = = = = = = = = =
Sequence_FreeCommand
= = = = = = = = = = = = = =
*/
void Sequence_FreeCommand ( sequenceCommandLine_s * kill )
{
Z_Free ( kill - > fireTargetNames ) ;
Z_Free ( kill - > speakerName ) ;
Z_Free ( kill - > listenerName ) ;
Z_Free ( kill - > soundFileName ) ;
Z_Free ( kill - > sentenceName ) ;
Z_Free ( kill - > clientMessage . pName ) ;
Z_Free ( kill - > clientMessage . pMessage ) ;
}
/*
= = = = = = = = = = = = = =
Sequence_FreeEntry
= = = = = = = = = = = = = =
*/
void Sequence_FreeEntry ( sequenceEntry_s * kill )
{
sequenceCommandLine_s * dead ;
Z_Free ( kill - > entryName ) ;
Z_Free ( kill - > fileName ) ;
for ( dead = kill - > firstCommand ; dead ; dead = dead - > nextCommandLine )
{
kill - > firstCommand = dead - > nextCommandLine ;
Sequence_FreeCommand ( dead ) ;
}
Z_Free ( kill ) ;
}
/*
= = = = = = = = = = = = = =
Sequence_FreeSentence
= = = = = = = = = = = = = =
*/
void Sequence_FreeSentence ( sentenceEntry_s * sentenceEntry )
{
Z_Free ( sentenceEntry - > data ) ;
Z_Free ( sentenceEntry ) ;
}
/*
= = = = = = = = = = = = = =
Sequence_FreeSentenceGroup
= = = = = = = = = = = = = =
*/
void Sequence_FreeSentenceGroup ( sentenceGroupEntry_s * groupEntry )
{
Z_Free ( groupEntry - > groupName ) ;
Z_Free ( groupEntry ) ;
}
/*
= = = = = = = = = = = = = =
Sequence_FreeSentenceGroupEntries
= = = = = = = = = = = = = =
*/
void Sequence_FreeSentenceGroupEntries ( sentenceGroupEntry_s * groupEntry , qboolean purgeGlobals )
{
sentenceEntry_s * sentenceEntry ;
sentenceEntry_s * deadSentence ;
sentenceEntry_s * prevSentence ;
sentenceEntry = groupEntry - > firstSentence ;
prevSentence = NULL ;
while ( sentenceEntry )
{
if ( ! sentenceEntry - > isGlobal | | purgeGlobals )
{
if ( prevSentence )
prevSentence - > nextEntry = sentenceEntry - > nextEntry ;
else
groupEntry - > firstSentence = sentenceEntry - > nextEntry ;
groupEntry - > numSentences - - ;
g_nonGlobalSentences - - ;
deadSentence = sentenceEntry ;
sentenceEntry = sentenceEntry - > nextEntry ;
Sequence_FreeSentence ( deadSentence ) ;
}
else
{
prevSentence = sentenceEntry ;
sentenceEntry = sentenceEntry - > nextEntry ;
}
}
}
/*
= = = = = = = = = = = = = =
Sequence_PurgeEntries
= = = = = = = = = = = = = =
*/
void Sequence_PurgeEntries ( qboolean purgeGlobals )
{
sequenceEntry_s * scan ;
sequenceEntry_s * dead ;
sequenceEntry_s * prev ;
sentenceGroupEntry_s * groupEntry ;
sentenceGroupEntry_s * deadGroup ;
sentenceGroupEntry_s * prevGroup ;
dead = NULL ;
prev = NULL ;
for ( scan = g_sequenceList ; scan ; )
{
if ( ! scan - > isGlobal | | purgeGlobals )
{
if ( prev )
prev - > nextEntry = scan - > nextEntry ;
else
g_sequenceList = scan - > nextEntry ;
dead = scan ;
scan = scan - > nextEntry ;
Sequence_FreeEntry ( dead ) ;
}
else
{
prev = scan ;
scan = scan - > nextEntry ;
}
}
groupEntry = g_sentenceGroupList ;
prevGroup = NULL ;
while ( groupEntry )
{
Sequence_FreeSentenceGroupEntries ( groupEntry , purgeGlobals ) ;
if ( groupEntry - > numSentences )
{
prevGroup = groupEntry ;
groupEntry = groupEntry - > nextEntry ;
}
else
{
if ( prevGroup )
prevGroup - > nextEntry = groupEntry - > nextEntry ;
else
g_sentenceGroupList = groupEntry - > nextEntry ;
deadGroup = groupEntry ;
groupEntry = groupEntry - > nextEntry ;
Sequence_FreeSentenceGroup ( deadGroup ) ;
}
}
}
/*
= = = = = = = = = = = = = =
Sequence_OnLevelLoad
= = = = = = = = = = = = = =
*/
void Sequence_OnLevelLoad ( const char * mapName )
{
Sequence_PurgeEntries ( false ) ;
Sequence_ParseFile ( mapName , false ) ;
}