2020-05-12 11:43:24 +00:00
//-------------------------------------------------------------------------
/*
Copyright ( C ) 1996 , 2003 - 3 D Realms Entertainment
2020-05-13 14:19:39 +00:00
Copyright ( C ) 2020 - Christoph Oelckers
2020-05-12 11:43:24 +00:00
This file is part of Enhanced Duke Nukem 3 D version 1.5 - Atomic Edition
Duke Nukem 3 D 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 2
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 .
You should have received a copy of the GNU General Public License
along with this program ; if not , write to the Free Software
Foundation , Inc . , 59 Temple Place - Suite 330 , Boston , MA 02111 - 1307 , USA .
Original Source : 1996 - Todd Replogle
Prepared for public release : 03 / 21 / 2003 - Charlie Wiederhold , 3 D Realms
EDuke enhancements integrated : 04 / 13 / 2003 - Matt Saettler
Note : This source file IS NOT USED in EDuke source . It has been split
into many sub - files .
2020-07-15 11:10:18 +00:00
Modifications for JonoF ' s port by Jonathon Fowler ( jf @ jonof . id . au )
2020-05-12 11:43:24 +00:00
*/
//-------------------------------------------------------------------------
# include "ns.h"
# include <string.h>
# include "concmd.h"
# include "cmdlib.h"
2020-05-12 13:39:35 +00:00
# include "memarena.h"
# include "printf.h"
# include "filesystem.h"
2020-05-12 19:22:08 +00:00
# include "mapinfo.h"
# include "menu.h"
# include "global.h"
2020-05-13 14:16:27 +00:00
# include "m_argv.h"
2020-07-07 18:27:21 +00:00
# include "sounds.h"
2020-05-12 11:43:24 +00:00
BEGIN_DUKE_NS
2020-07-15 10:34:42 +00:00
2020-07-19 17:13:27 +00:00
//---------------------------------------------------------------------------
//
// definitions needed by the parser.
//
//---------------------------------------------------------------------------
2020-05-15 09:30:33 +00:00
2020-07-19 17:13:27 +00:00
enum labeltypes {
LABEL_ANY = - 1 ,
LABEL_DEFINE = 1 ,
LABEL_STATE = 2 ,
LABEL_ACTOR = 4 ,
LABEL_ACTION = 8 ,
LABEL_AI = 16 ,
LABEL_MOVE = 32 ,
} ;
class labelstring
{
char text [ 64 ] ;
public :
char & operator [ ] ( size_t pos )
{
return text [ pos ] ;
}
operator const char * ( ) { return text ; }
const char * GetChars ( ) { return text ; }
int compare ( const char * c ) const { return strcmp ( text , c ) ; }
int comparei ( const char * c ) const { return stricmp ( text , c ) ; }
2020-07-23 14:31:26 +00:00
labelstring & operator = ( const char * c ) { strncpy ( text , c , 64 ) ; text [ 63 ] = 0 ; return * this ; }
2020-07-19 17:13:27 +00:00
} ;
2020-05-12 11:43:24 +00:00
2020-07-07 18:27:21 +00:00
struct TempMusic
{
int levnum ;
FString music ;
} ;
2020-07-19 17:13:27 +00:00
//---------------------------------------------------------------------------
//
// the actual parser
//
//---------------------------------------------------------------------------
class ConCompiler
{
char * textptr = nullptr ;
int line_number = 0 ;
int errorcount = 0 , warningcount = 0 ; // was named 'error' and 'warning' which is too generic for public variables and may clash with other code.
int currentsourcefile = - 1 ;
unsigned parsing_actor = 0 , parsing_event = 0 ;
int parsing_state = 0 ;
int num_squigilly_brackets = 0 ;
int checking_ifelse = 0 ;
labelstring parselabel = { } ;
// This is for situations where the music gets defined before the map. Since the map records do not exist yet, we need a temporary buffer.
TArray < TempMusic > tempMusic ;
char parsebuf [ 1024 ] ;
TArray < char > parsebuffer ; // global so that the storage is persistent across calls.
void ReportError ( int error ) ;
int getkeyword ( const char * text ) ;
FString translatelabeltype ( int type ) ;
bool ispecial ( char c ) ;
void skiptoendofline ( ) ;
void skipwhitespace ( ) ;
void skipblockcomment ( ) ;
bool skipcomments ( ) ;
int keyword ( void ) ;
void getlabel ( void ) ;
void appendlabelvalue ( labeltypes type , int value ) ;
void appendlabeladdress ( labeltypes type , int offset = 0 ) ;
int transword ( void ) ;
int transnum ( int type ) ;
void checkforkeyword ( ) ;
int parsecommand ( ) ;
public :
void compilecon ( const char * filenam ) ;
void setmusic ( ) ;
int getErrorCount ( ) { return errorcount ; }
} ;
//---------------------------------------------------------------------------
//
// label data
//
//---------------------------------------------------------------------------
2020-07-07 18:27:21 +00:00
2020-07-19 17:13:27 +00:00
static const char * labeltypenames [ ] = {
" define " ,
" state " ,
" actor " ,
" action " ,
" ai " ,
" move "
} ;
struct labeldef
{
labelstring name ;
labeltypes type ;
int value ;
int compare ( const char * c ) const { return name . compare ( c ) ; }
const char * GetChars ( ) { return name . GetChars ( ) ; }
} ;
// These arrays contain the global output from the compiler.
static TArray < labeldef > labels ;
TArray < int > ScriptCode ;
2020-07-07 18:27:21 +00:00
2020-05-12 11:43:24 +00:00
//---------------------------------------------------------------------------
//
// synthesize the instruction list
//
//---------------------------------------------------------------------------
# define cmd(a) { #a, concmd_ ## a },
# define cmdx(a, b) { b, concmd_ ## a },
# define cmda(a,b) { #a, concmd_ ## b },
struct ConCommand
{
char cmd [ 20 ] ; // the longest instruction name is 'ifactornotstayput' at 17 characters so if this changes this field must be enlarged.
int instr ;
} ;
static ConCommand cmdList [ ] =
{
# include "condef.h"
} ;
# undef cmd
# undef cmdx
# undef cmda
static int cmdCmp ( const void * a , const void * b )
{
auto A = ( ConCommand * ) a ;
auto B = ( ConCommand * ) b ;
return strcmp ( A - > cmd , B - > cmd ) ;
}
void SortCommands ( )
{
qsort ( cmdList , countof ( cmdList ) , sizeof ( ConCommand ) , cmdCmp ) ;
}
2020-05-12 13:39:35 +00:00
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
enum
{
ERROR_ISAKEYWORD = 1 ,
ERROR_PARMUNDEFINED ,
WARNING_DUPLICATEDEFINITION ,
ERROR_COULDNOTFIND ,
ERROR_VARREADONLY ,
ERROR_NOTAGAMEDEF ,
ERROR_NOTAGAMEVAR ,
ERROR_OPENBRACKET ,
ERROR_CLOSEBRACKET ,
2020-05-15 20:59:13 +00:00
ERROR_NOENDSWITCH ,
2020-05-12 19:22:08 +00:00
} ;
2020-05-12 13:39:35 +00:00
2020-07-19 17:13:27 +00:00
void ConCompiler : : ReportError ( int error )
2020-05-12 13:39:35 +00:00
{
2020-07-19 17:13:27 +00:00
const char * fn = fileSystem . GetFileFullName ( currentsourcefile ) ;
switch ( error )
2020-05-12 13:39:35 +00:00
{
case ERROR_ISAKEYWORD :
Printf ( TEXTCOLOR_RED " * ERROR!(%s, line %d) Symbol '%s' is a key word. \n " ,
2020-07-15 10:34:42 +00:00
fn , line_number , parselabel . GetChars ( ) ) ;
2020-05-12 13:39:35 +00:00
break ;
case ERROR_PARMUNDEFINED :
Printf ( TEXTCOLOR_RED " * ERROR!(%s, line %d) Parameter '%s' is undefined. \n " ,
2020-07-19 17:13:27 +00:00
fn , line_number , parsebuf ) ;
2020-05-12 13:39:35 +00:00
break ;
case WARNING_DUPLICATEDEFINITION :
Printf ( TEXTCOLOR_YELLOW " * WARNING.(%s, line %d) Duplicate definition '%s' ignored. \n " ,
2020-07-15 10:34:42 +00:00
fn , line_number , parselabel . GetChars ( ) ) ;
2020-05-12 13:39:35 +00:00
break ;
case ERROR_COULDNOTFIND :
Printf ( TEXTCOLOR_RED " * ERROR!(%s, line %d) Could not find '%s'. \n " ,
2020-07-15 10:34:42 +00:00
fn , line_number , parselabel . GetChars ( ) ) ;
2020-05-12 13:39:35 +00:00
break ;
case ERROR_VARREADONLY :
Printf ( TEXTCOLOR_RED " * ERROR!(%s, line %d) Variable '%s' is read-only. \n " ,
2020-07-15 10:34:42 +00:00
fn , line_number , parselabel . GetChars ( ) ) ;
2020-05-12 13:39:35 +00:00
break ;
case ERROR_NOTAGAMEDEF :
Printf ( TEXTCOLOR_RED " * ERROR!(%s, line %d) Symbol '%s' is not a Game Definition. \n " ,
2020-07-15 10:34:42 +00:00
fn , line_number , parselabel . GetChars ( ) ) ;
2020-05-12 13:39:35 +00:00
break ;
case ERROR_NOTAGAMEVAR :
Printf ( TEXTCOLOR_RED " * ERROR! (%s, line %d) Symbol '%s' is not a defined Game Variable. \n " ,
2020-07-15 10:34:42 +00:00
fn , line_number , parselabel . GetChars ( ) ) ;
2020-05-12 13:39:35 +00:00
break ;
case ERROR_OPENBRACKET :
Printf ( TEXTCOLOR_RED " * ERROR! (%s, line %d) Found more '{' than '}' before '%s'. \n " ,
2020-07-19 17:13:27 +00:00
fn , line_number , parsebuf ) ;
2020-05-12 13:39:35 +00:00
break ;
case ERROR_CLOSEBRACKET :
2020-07-23 14:35:54 +00:00
Printf ( TEXTCOLOR_RED " * ERROR! (%s, line %d) Found more '}' than '{' before '%s'. \n " ,
2020-07-19 17:13:27 +00:00
fn , line_number , parsebuf ) ;
2020-05-12 13:39:35 +00:00
break ;
case ERROR_NOENDSWITCH :
2020-07-23 14:35:54 +00:00
Printf ( TEXTCOLOR_RED " * ERROR! (%s, line %d) Did not find endswitch before '%s'. \n " ,
2020-07-19 17:13:27 +00:00
fn , line_number , parsebuf ) ;
2020-05-12 13:39:35 +00:00
break ;
}
}
2020-05-12 11:43:24 +00:00
//---------------------------------------------------------------------------
//
// binary search for keyword
//
//---------------------------------------------------------------------------
2020-07-19 17:13:27 +00:00
int ConCompiler : : getkeyword ( const char * text )
2020-05-12 11:43:24 +00:00
{
ptrdiff_t min = 0 ;
ptrdiff_t max = countof ( cmdList ) - 1 ;
while ( min < = max )
{
int mid = ( min + max ) > > 1 ;
const int comp = strcmp ( text , cmdList [ mid ] . cmd ) ;
if ( comp = = 0 )
{
return cmdList [ mid ] . instr ;
}
else if ( comp > 0 )
{
min = mid + 1 ;
}
else
{
max = mid - 1 ;
}
}
return - 1 ;
}
2020-05-12 13:39:35 +00:00
//---------------------------------------------------------------------------
//
// label management
//
//---------------------------------------------------------------------------
2020-07-19 17:13:27 +00:00
FString ConCompiler : : translatelabeltype ( int type )
2020-07-15 10:34:42 +00:00
{
FString buf ;
for ( int i = 0 ; i < 6 ; i + + )
{
if ( ! ( type & ( 1 < < i ) ) ) continue ;
if ( buf . Len ( ) ) buf + = " or " ;
buf + = labeltypenames [ i ] ;
}
return buf ;
}
int findlabel ( const char * text , bool ignorecase = false )
2020-05-12 14:33:32 +00:00
{
2020-07-15 10:34:42 +00:00
for ( unsigned j = 0 ; j < labels . Size ( ) ; j + + )
2020-05-12 14:33:32 +00:00
{
2020-07-15 10:34:42 +00:00
if ( labels [ j ] . compare ( text ) = = 0 )
2020-05-12 14:33:32 +00:00
{
2020-05-12 21:55:33 +00:00
return j ;
2020-05-12 14:33:32 +00:00
}
}
2020-07-15 10:34:42 +00:00
if ( ignorecase )
{
for ( unsigned j = 0 ; j < labels . Size ( ) ; j + + )
{
if ( labels [ j ] . name . comparei ( text ) = = 0 )
{
return j ;
}
}
}
2020-05-12 14:33:32 +00:00
return - 1 ;
}
2020-05-12 13:39:35 +00:00
2020-07-15 10:34:42 +00:00
// This is for the 'spawn' CCMD.
int getlabelvalue ( const char * text )
{
int lnum = findlabel ( text , true ) ;
2020-07-29 18:59:32 +00:00
if ( lnum > = 0 & & labels [ lnum ] . type ! = LABEL_DEFINE ) return - 1 ;
2020-07-15 10:34:42 +00:00
return lnum < 0 ? - 1 : labels [ lnum ] . value ;
}
2020-05-12 21:19:01 +00:00
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
2020-07-19 17:13:27 +00:00
bool ConCompiler : : ispecial ( char c )
2020-05-12 21:19:01 +00:00
{
if ( c = = 0x0a )
{
line_number + + ;
return true ;
}
// oh joy - we need to skip some more characters here to allow running broken scripts.
if ( c = = ' ' | | c = = 0x0d | | c = = ' ( ' | | c = = ' ) ' | | c = = ' , ' | | c = = ' ; ' )
return true ;
return false ;
}
2020-07-19 17:13:27 +00:00
static bool isaltok ( char c )
2020-05-12 21:19:01 +00:00
{
// isalnum pukes on negative input.
return c > 0 & & ( isalnum ( c ) | | c = = ' { ' | | c = = ' } ' | | c = = ' / ' | | c = = ' * ' | | c = = ' - ' | | c = = ' _ ' | | c = = ' . ' ) ;
}
2020-05-12 11:43:24 +00:00
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
2020-07-19 17:13:27 +00:00
void ConCompiler : : skiptoendofline ( )
2020-05-12 11:43:24 +00:00
{
while ( * textptr ! = 0x0a & & * textptr ! = 0x0d & & * textptr ! = 0 )
textptr + + ;
}
2020-07-19 17:13:27 +00:00
void ConCompiler : : skipwhitespace ( )
2020-05-12 11:43:24 +00:00
{
while ( * textptr = = ' ' | | * textptr = = ' \t ' | | * textptr = = ' \r ' | | * textptr = = ' \n ' )
{
2020-05-12 13:39:35 +00:00
if ( * textptr = = ' \n ' ) line_number + + ;
2020-05-12 11:43:24 +00:00
textptr + + ;
}
}
2020-07-19 17:13:27 +00:00
void ConCompiler : : skipblockcomment ( )
2020-05-12 11:43:24 +00:00
{
2020-05-12 19:22:08 +00:00
while ( * textptr ! = ' * ' | | textptr [ 1 ] ! = ' / ' )
2020-05-12 11:43:24 +00:00
{
2020-05-12 13:39:35 +00:00
if ( * textptr = = ' \n ' ) line_number + + ;
2020-05-12 11:43:24 +00:00
if ( * textptr = = 0 ) return ; // reached the end of the file
textptr + + ;
}
2020-05-12 20:52:49 +00:00
textptr + = 2 ;
2020-05-12 11:43:24 +00:00
}
2020-07-19 17:13:27 +00:00
bool ConCompiler : : skipcomments ( )
2020-05-12 11:43:24 +00:00
{
while ( true )
{
skipwhitespace ( ) ;
if ( * textptr = = ' / ' & & textptr [ 1 ] = = ' / ' )
{
skiptoendofline ( ) ;
continue ;
}
if ( * textptr = = ' / ' & & textptr [ 1 ] = = ' * ' )
{
skipblockcomment ( ) ;
continue ;
}
// stop if we got something else
2020-05-12 21:19:01 +00:00
// this line got added to skip over a stray semicolon in RR's COOT.CON.
if ( ispecial ( * textptr ) ) textptr + + ;
2020-05-12 11:43:24 +00:00
break ;
}
return * textptr ! = 0 ;
}
2020-05-12 13:39:35 +00:00
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
2020-07-19 17:13:27 +00:00
int ConCompiler : : keyword ( void )
2020-05-12 19:22:08 +00:00
{
int i ;
const char * temptextptr ;
skipcomments ( ) ;
temptextptr = textptr ;
while ( isaltok ( * temptextptr ) = = 0 )
{
temptextptr + + ;
if ( * temptextptr = = 0 )
return 0 ;
}
i = 0 ;
while ( isaltok ( * temptextptr ) )
{
2020-07-19 17:13:27 +00:00
parsebuf [ i ] = * ( temptextptr + + ) ;
2020-05-12 19:22:08 +00:00
i + + ;
}
2020-07-19 17:13:27 +00:00
parsebuf [ i ] = 0 ;
2020-05-12 19:22:08 +00:00
2020-07-19 17:13:27 +00:00
return getkeyword ( parsebuf ) ;
2020-05-12 19:22:08 +00:00
}
2020-05-12 13:39:35 +00:00
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
2020-07-19 17:13:27 +00:00
void ConCompiler : : getlabel ( void )
2020-05-12 13:39:35 +00:00
{
2020-07-23 14:31:26 +00:00
int i ;
2020-05-12 13:39:35 +00:00
2020-05-12 19:22:08 +00:00
skipcomments ( ) ;
2020-05-12 13:39:35 +00:00
while ( isalnum ( * textptr & 0xff ) = = 0 )
{
if ( * textptr = = 0x0a ) line_number + + ;
textptr + + ;
if ( * textptr = = 0 )
return ;
}
i = 0 ;
while ( ispecial ( * textptr ) = = 0 )
2020-07-15 10:34:42 +00:00
parselabel [ i + + ] = * ( textptr + + ) ;
2020-05-12 13:39:35 +00:00
2020-07-15 10:34:42 +00:00
parselabel [ i ] = 0 ;
2020-05-12 13:39:35 +00:00
}
2020-05-12 14:55:25 +00:00
//---------------------------------------------------------------------------
//
2020-07-19 17:13:27 +00:00
// script buffer access wrappers.
2020-05-12 14:55:25 +00:00
//
//---------------------------------------------------------------------------
static void setscriptvalue ( int offset , int value )
{
2020-05-15 09:30:33 +00:00
ScriptCode [ offset ] = value ;
2020-05-12 14:55:25 +00:00
}
2020-07-19 17:13:27 +00:00
static int scriptpos ( )
2020-05-12 20:52:49 +00:00
{
2020-05-15 09:30:33 +00:00
return ScriptCode . Size ( ) ;
2020-05-12 20:52:49 +00:00
}
2020-05-12 14:55:25 +00:00
static void appendscriptvalue ( int value )
{
2020-05-15 09:30:33 +00:00
ScriptCode . Push ( value ) ;
2020-05-12 14:55:25 +00:00
}
2020-05-12 19:22:08 +00:00
static int popscriptvalue ( )
2020-05-12 14:55:25 +00:00
{
2020-05-15 09:30:33 +00:00
decltype ( ScriptCode ) : : value_type p ;
ScriptCode . Pop ( p ) ;
2020-05-12 19:22:08 +00:00
return p ;
2020-05-12 14:55:25 +00:00
}
2020-05-12 15:16:15 +00:00
2020-05-12 20:52:49 +00:00
void reservescriptspace ( int space )
{
2020-05-15 09:58:31 +00:00
for ( int i = 0 ; i < space ; i + + ) ScriptCode . Push ( 0 ) ;
2020-05-12 14:55:25 +00:00
}
2020-05-15 09:30:33 +00:00
/*
void pushlabeladdress ( )
2020-05-12 14:55:25 +00:00
{
2020-05-15 09:30:33 +00:00
labelcode . Push ( script . Size ( ) ) ;
2020-05-12 14:55:25 +00:00
}
2020-05-15 09:30:33 +00:00
*/
2020-05-12 14:55:25 +00:00
2020-07-19 17:13:27 +00:00
void ConCompiler : : appendlabelvalue ( labeltypes type , int value )
2020-05-12 19:22:08 +00:00
{
2020-07-15 10:34:42 +00:00
labels . Reserve ( 1 ) ;
labels . Last ( ) . type = type ;
labels . Last ( ) . name = parselabel ;
labels . Last ( ) . value = value ;
2020-05-12 19:22:08 +00:00
}
2020-07-19 17:13:27 +00:00
void ConCompiler : : appendlabeladdress ( labeltypes type , int offset )
2020-05-12 15:16:15 +00:00
{
2020-07-15 10:34:42 +00:00
appendlabelvalue ( type , ScriptCode . Size ( ) + offset ) ;
2020-05-12 15:16:15 +00:00
}
2020-05-12 14:55:25 +00:00
2020-05-12 13:39:35 +00:00
//---------------------------------------------------------------------------
//
2020-07-19 17:13:27 +00:00
//Returns its code #
2020-05-12 13:39:35 +00:00
//
//---------------------------------------------------------------------------
2020-07-19 17:13:27 +00:00
int ConCompiler : : transword ( void )
2020-05-12 13:39:35 +00:00
{
int i , l ;
2020-05-12 19:22:08 +00:00
skipcomments ( ) ;
2020-05-12 13:39:35 +00:00
while ( isaltok ( * textptr ) = = 0 )
{
if ( * textptr = = 0x0a ) line_number + + ;
if ( * textptr = = 0 )
return - 1 ;
textptr + + ;
}
l = 0 ;
while ( isaltok ( * ( textptr + l ) ) & & ! ( * ( textptr + l ) = = ' . ' ) )
{
if ( l < 31 )
{
2020-07-19 17:13:27 +00:00
parsebuf [ l ] = textptr [ l ] ;
2020-05-12 13:39:35 +00:00
l + + ;
}
}
2020-07-19 17:13:27 +00:00
parsebuf [ l ] = 0 ;
2020-05-12 13:39:35 +00:00
2020-07-19 17:13:27 +00:00
i = getkeyword ( parsebuf ) ;
2020-05-12 13:39:35 +00:00
if ( i > = 0 )
{
2020-05-12 14:55:25 +00:00
appendscriptvalue ( i ) ;
2020-05-12 13:39:35 +00:00
textptr + = l ;
return i ;
}
textptr + = l ;
2020-07-19 17:13:27 +00:00
const char * fn = fileSystem . GetFileFullName ( currentsourcefile ) ;
if ( parsebuf [ 0 ] = = ' { ' & & parsebuf [ 1 ] ! = 0 )
Printf ( TEXTCOLOR_RED " * ERROR!(%s, line %d) Expecting a SPACE or CR between '{' and '%s'. \n " , fn , line_number , parsebuf + 1 ) ;
else if ( parsebuf [ 0 ] = = ' } ' & & parsebuf [ 1 ] ! = 0 )
Printf ( TEXTCOLOR_RED " * ERROR!(%s, line %d) Expecting a SPACE or CR between '}' and '%s'. \n " , fn , line_number , parsebuf + 1 ) ;
else if ( parsebuf [ 0 ] = = ' / ' & & parsebuf [ 1 ] = = ' / ' & & parsebuf [ 2 ] ! = 0 )
Printf ( TEXTCOLOR_RED " * ERROR!(%s, line %d) Expecting a SPACE between '//' and '%s'. \n " , fn , line_number , parsebuf + 2 ) ;
else if ( parsebuf [ 0 ] = = ' / ' & & parsebuf [ 1 ] = = ' * ' & & parsebuf [ 2 ] ! = 0 )
Printf ( TEXTCOLOR_RED " * ERROR!(%s, line %d) Expecting a SPACE between '/*' and '%s'. \n " , fn , line_number , parsebuf + 2 ) ;
else if ( parsebuf [ 0 ] = = ' * ' & & parsebuf [ 1 ] = = ' / ' & & parsebuf [ 2 ] ! = 0 )
Printf ( TEXTCOLOR_RED " * ERROR!(%s, line %d) Expecting a SPACE between '*/' and '%s'. \n " , fn , line_number , parsebuf + 2 ) ;
2020-05-12 13:39:35 +00:00
else
2020-07-19 17:13:27 +00:00
Printf ( TEXTCOLOR_RED " * ERROR!(%s, line %d) Keyword expected, got '%s'. \n " , fn , line_number , parsebuf + 2 ) ;
2020-05-12 13:39:35 +00:00
errorcount + + ;
return - 1 ;
}
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
2020-07-19 17:13:27 +00:00
int ConCompiler : : transnum ( int type )
2020-05-12 13:39:35 +00:00
{
2020-07-15 10:34:42 +00:00
int l ;
2020-05-12 13:39:35 +00:00
while ( isaltok ( * textptr ) = = 0 )
{
if ( * textptr = = 0x0a ) line_number + + ;
textptr + + ;
if ( * textptr = = 0 )
2020-05-13 11:03:52 +00:00
return 0 ;
2020-05-12 13:39:35 +00:00
}
l = 0 ;
while ( isaltok ( * ( textptr + l ) ) )
{
if ( l < 31 )
{
2020-07-19 17:13:27 +00:00
parsebuf [ l ] = textptr [ l ] ;
2020-05-12 13:39:35 +00:00
l + + ;
}
}
2020-07-19 17:13:27 +00:00
parsebuf [ l ] = 0 ;
2020-05-12 13:39:35 +00:00
2020-07-19 17:13:27 +00:00
if ( getkeyword ( parsebuf ) > = 0 )
2020-05-12 13:39:35 +00:00
{
errorcount + + ;
ReportError ( ERROR_ISAKEYWORD ) ;
textptr + = l ;
}
2020-07-15 10:34:42 +00:00
for ( unsigned i = 0 ; i < labels . Size ( ) ; i + + )
2020-05-12 13:39:35 +00:00
{
2020-07-19 17:13:27 +00:00
if ( labels [ i ] . compare ( parsebuf ) = = 0 )
2020-05-12 13:39:35 +00:00
{
2020-07-15 10:34:42 +00:00
// Non-values can be compared with 0.
if ( labels [ i ] . type & type | | ( labels [ i ] . value = = 0 ) )
{
appendscriptvalue ( labels [ i ] . value ) ;
textptr + = l ;
return labels [ i ] . value ;
}
appendscriptvalue ( 0 ) ;
2020-05-12 13:39:35 +00:00
textptr + = l ;
2020-07-15 10:34:42 +00:00
auto el = translatelabeltype ( type ) ;
auto gl = translatelabeltype ( labels [ i ] . type ) ;
2020-07-19 17:13:27 +00:00
const char * fn = fileSystem . GetFileFullName ( currentsourcefile ) ;
2020-07-15 10:34:42 +00:00
Printf ( TEXTCOLOR_YELLOW " * WARNING.(%s, line %d) %s: Expected a '%s' label but found a '%s' label instead. \n " , fn , line_number , labels [ i ] . GetChars ( ) , el . GetChars ( ) , gl . GetChars ( ) ) ;
return - 1 ; // valid label name, but wrong type
2020-05-12 13:39:35 +00:00
}
}
if ( isdigit ( * textptr ) = = 0 & & * textptr ! = ' - ' )
{
ReportError ( ERROR_PARMUNDEFINED ) ;
errorcount + + ;
textptr + = l ;
# ifdef FOR_LATER
2020-07-19 17:13:27 +00:00
if ( GetDefID ( parsebuf ) > = 0 )
2020-05-12 13:39:35 +00:00
{
Printf ( TEXTCOLOR_ORANGE " Game Variable not expected \n " ) ;
}
# endif
2020-05-13 11:03:52 +00:00
return 0 ;
2020-05-12 13:39:35 +00:00
}
2020-05-12 14:33:32 +00:00
// Now it's getting nasty... With all of C's integer conversion functions we have to look for undefined behavior and truncation problems. This one's the least problematic approach
// that ignores octal conversion.
int64_t value ;
char * outp ;
2020-07-15 10:34:42 +00:00
bool ishex = ( textptr [ 0 ] = = ' 0 ' & & tolower ( textptr [ 1 ] ) = = ' x ' ) | | ( textptr [ 0 ] = = ' - ' & & textptr [ 1 ] = = ' 0 ' & & tolower ( textptr [ 2 ] ) = = ' x ' ) ;
if ( * textptr = = ' - ' ) value = strtoll ( textptr , & outp , ishex ? 0 : 10 ) ;
else value = strtoull ( textptr , & outp , ishex ? 0 : 10 ) ;
2020-05-12 14:33:32 +00:00
if ( * outp ! = 0 )
{
// conversion was not successful.
}
2020-05-12 14:55:25 +00:00
appendscriptvalue ( int ( value ) ) ; // truncate the parsed value to 32 bit.
2020-07-15 10:34:42 +00:00
if ( type ! = LABEL_DEFINE & & value ! = 0 )
{
2020-07-19 17:13:27 +00:00
const char * fn = fileSystem . GetFileFullName ( currentsourcefile ) ;
2020-07-15 10:34:42 +00:00
Printf ( TEXTCOLOR_YELLOW " * WARNING.(%s, line %d) Expected an identifier, got a numeric literal %d. \n " , fn , line_number , ( int ) value ) ;
}
2020-05-12 13:39:35 +00:00
textptr + = l ;
2020-05-13 11:03:52 +00:00
return int ( value ) ;
2020-05-12 13:39:35 +00:00
}
//---------------------------------------------------------------------------
//
2020-05-12 14:55:25 +00:00
// just to reduce some excessive boilerplate. This block reappeared
// endlessly in parsecommand
2020-05-12 13:39:35 +00:00
//
//---------------------------------------------------------------------------
2020-07-19 17:13:27 +00:00
void ConCompiler : : checkforkeyword ( )
2020-05-12 14:55:25 +00:00
{
2020-07-15 10:34:42 +00:00
if ( getkeyword ( parselabel ) > = 0 )
2020-05-12 14:55:25 +00:00
{
errorcount + + ;
ReportError ( ERROR_ISAKEYWORD ) ;
}
}
2020-05-12 13:39:35 +00:00
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
2020-05-12 14:55:25 +00:00
2020-07-19 17:13:27 +00:00
int ConCompiler : : parsecommand ( )
2020-05-12 13:39:35 +00:00
{
2020-07-19 17:13:27 +00:00
const char * fn = fileSystem . GetFileFullName ( currentsourcefile ) ;
2020-05-12 13:39:35 +00:00
int i , j , k ;
2020-05-12 22:29:00 +00:00
int tempscrptr ;
2020-05-12 13:39:35 +00:00
uint8_t done , temp_ifelse_check ; // , tw;
int temp_line_number ;
int temp_current_file ;
2020-05-12 14:33:32 +00:00
int lnum ;
2020-05-12 13:39:35 +00:00
2020-05-13 14:16:27 +00:00
// Do not count warnings here and allow more errors before bailing out.
if ( ( errorcount ) > 64 | | ( * textptr = = ' \0 ' ) | | ( * ( textptr + 1 ) = = ' \0 ' ) ) return 1 ;
int tw = transword ( ) ;
2020-05-12 13:39:35 +00:00
switch ( tw )
{
default :
case - 1 :
2020-05-13 14:16:27 +00:00
return 0 ; //End
2020-05-13 10:18:36 +00:00
2020-05-12 13:39:35 +00:00
case concmd_state :
if ( parsing_actor = = 0 & & parsing_state = = 0 )
{
getlabel ( ) ;
2020-05-12 14:55:25 +00:00
popscriptvalue ( ) ;
2020-07-15 10:34:42 +00:00
appendlabeladdress ( LABEL_STATE ) ;
2020-05-12 13:39:35 +00:00
parsing_state = 1 ;
return 0 ;
}
getlabel ( ) ;
2020-05-12 14:55:25 +00:00
checkforkeyword ( ) ;
2020-05-12 13:39:35 +00:00
2020-07-15 10:34:42 +00:00
lnum = findlabel ( parselabel ) ;
2020-05-12 13:39:35 +00:00
2020-05-12 14:33:32 +00:00
if ( lnum < 0 )
2020-05-12 13:39:35 +00:00
{
2020-07-15 10:34:42 +00:00
Printf ( TEXTCOLOR_RED " * ERROR!(%s, line %d) State '%s' not found. \n " , fn , line_number , parselabel . GetChars ( ) ) ;
2020-05-12 13:39:35 +00:00
errorcount + + ;
2020-07-19 17:13:27 +00:00
return 0 ;
2020-05-12 13:39:35 +00:00
}
2020-07-15 10:34:42 +00:00
appendscriptvalue ( labels [ lnum ] . value ) ;
2020-05-12 13:39:35 +00:00
return 0 ;
case concmd_ends :
if ( parsing_state = = 0 )
{
Printf ( TEXTCOLOR_RED " * ERROR!(%s, line %d) Found 'ends' with no 'state'. \n " , fn , line_number ) ;
errorcount + + ;
}
// else
{
if ( num_squigilly_brackets > 0 )
{
2020-05-12 16:44:58 +00:00
ReportError ( ERROR_OPENBRACKET ) ;
2020-05-12 13:39:35 +00:00
errorcount + + ;
}
if ( num_squigilly_brackets < 0 )
{
ReportError ( ERROR_CLOSEBRACKET ) ;
errorcount + + ;
}
parsing_state = 0 ;
}
return 0 ;
case concmd_gamevar :
2020-07-19 17:13:27 +00:00
{
2020-05-12 13:39:35 +00:00
// syntax: gamevar <var1> <initial value> <flags>
// defines var1 and sets initial value.
// flags are used to define usage
// (see top of this files for flags)
getlabel ( ) ; //GetGameVarLabel();
// Check to see it's already defined
2020-05-13 11:03:52 +00:00
popscriptvalue ( ) ;
2020-05-12 13:39:35 +00:00
2020-07-15 10:34:42 +00:00
if ( getkeyword ( parselabel ) > = 0 )
2020-05-12 13:39:35 +00:00
{
errorcount + + ;
ReportError ( ERROR_ISAKEYWORD ) ;
return 0 ;
}
2020-07-15 10:34:42 +00:00
transnum ( LABEL_DEFINE ) ; // get initial value
2020-05-13 11:03:52 +00:00
j = popscriptvalue ( ) ;
2020-05-12 13:39:35 +00:00
2020-07-15 10:34:42 +00:00
transnum ( LABEL_DEFINE ) ; // get flags
2020-05-13 11:03:52 +00:00
lnum = popscriptvalue ( ) ;
2020-07-19 17:13:27 +00:00
if ( strlen ( parselabel ) > ( MAXVARLABEL - 1 ) )
{
warningcount + + ;
2020-07-23 14:35:54 +00:00
Printf ( TEXTCOLOR_RED " * WARNING.(%s, line %d) Variable Name '%s' too int (max is %d) \n " , fn , line_number , parselabel . GetChars ( ) , MAXVARLABEL - 1 ) ;
2020-07-19 17:13:27 +00:00
return 0 ;
}
int res = AddGameVar ( parselabel , j , lnum & ( ~ ( GAMEVAR_FLAG_DEFAULT | GAMEVAR_FLAG_SECRET ) ) ) ;
if ( res < 0 )
{
errorcount + + ;
2020-07-23 14:35:54 +00:00
if ( res = = - 1 ) Printf ( TEXTCOLOR_RED " * ERROR.(%s, line %d) Duplicate game variable definition '%s'. \n " , fn , line_number , parselabel . GetChars ( ) ) ;
else if ( res = = - 2 ) Printf ( TEXTCOLOR_RED " * ERROR.(%s, line %d) '%s' maximum number of game variables exceeded. \n " , fn , line_number , parselabel . GetChars ( ) ) ;
2020-07-19 17:13:27 +00:00
return 0 ;
}
2020-05-13 11:03:52 +00:00
2020-07-19 17:13:27 +00:00
return 0 ;
}
2020-05-12 13:39:35 +00:00
case concmd_define :
getlabel ( ) ;
2020-05-12 19:22:08 +00:00
checkforkeyword ( ) ;
2020-07-15 10:34:42 +00:00
lnum = findlabel ( parselabel ) ;
2020-05-12 19:22:08 +00:00
if ( lnum > = 0 )
2020-05-12 13:39:35 +00:00
{
2020-05-12 19:22:08 +00:00
warningcount + + ;
ReportError ( WARNING_DUPLICATEDEFINITION ) ;
break ;
2020-05-12 13:39:35 +00:00
}
2020-07-15 10:34:42 +00:00
transnum ( LABEL_DEFINE ) ;
2020-05-12 19:22:08 +00:00
i = popscriptvalue ( ) ;
if ( lnum < 0 )
2020-05-12 13:39:35 +00:00
{
2020-07-15 10:34:42 +00:00
appendlabelvalue ( LABEL_DEFINE , i ) ;
2020-05-12 13:39:35 +00:00
}
2020-05-12 19:22:08 +00:00
popscriptvalue ( ) ;
2020-05-12 13:39:35 +00:00
return 0 ;
case concmd_palfrom :
for ( j = 0 ; j < 4 ; j + + )
{
if ( keyword ( ) = = - 1 )
2020-07-15 10:34:42 +00:00
transnum ( LABEL_DEFINE ) ;
2020-05-12 13:39:35 +00:00
else break ;
}
while ( j < 4 )
{
2020-05-12 14:55:25 +00:00
appendscriptvalue ( 0 ) ;
2020-05-12 13:39:35 +00:00
j + + ;
}
return 0 ;
case concmd_move :
if ( parsing_actor | | parsing_state )
{
2020-07-15 10:34:42 +00:00
transnum ( LABEL_MOVE ) ;
2020-05-12 13:39:35 +00:00
j = 0 ;
while ( keyword ( ) = = - 1 )
{
2020-07-15 10:34:42 +00:00
transnum ( LABEL_DEFINE ) ;
2020-05-15 09:30:33 +00:00
j | = popscriptvalue ( ) ;
2020-05-12 13:39:35 +00:00
}
2020-05-12 14:55:25 +00:00
appendscriptvalue ( j ) ;
2020-05-12 13:39:35 +00:00
}
else
{
2020-05-12 14:55:25 +00:00
popscriptvalue ( ) ;
2020-05-12 13:39:35 +00:00
getlabel ( ) ;
// Check to see it's already defined
2020-05-12 19:22:08 +00:00
checkforkeyword ( ) ;
2020-05-12 13:39:35 +00:00
2020-07-15 10:34:42 +00:00
for ( i = 0 ; i < ( int ) labels . Size ( ) ; i + + )
if ( labels [ i ] . compare ( parselabel ) = = 0 )
2020-05-12 13:39:35 +00:00
{
warningcount + + ;
2020-07-23 14:35:54 +00:00
Printf ( TEXTCOLOR_RED " * WARNING.(%s, line %d) Duplicate move '%s' ignored. \n " , fn , line_number , parselabel . GetChars ( ) ) ;
2020-05-12 13:39:35 +00:00
break ;
}
2020-07-15 10:34:42 +00:00
if ( i = = labels . Size ( ) )
appendlabeladdress ( LABEL_MOVE ) ;
2020-05-12 13:39:35 +00:00
for ( j = 0 ; j < 2 ; j + + )
{
if ( keyword ( ) > = 0 ) break ;
2020-07-15 10:34:42 +00:00
transnum ( LABEL_DEFINE ) ;
2020-05-12 13:39:35 +00:00
}
for ( k = j ; k < 2 ; k + + )
{
2020-05-12 14:55:25 +00:00
appendscriptvalue ( 0 ) ;
2020-05-12 13:39:35 +00:00
}
}
return 0 ;
case concmd_music :
{
2020-05-12 14:55:25 +00:00
popscriptvalue ( ) ;
2020-07-15 10:34:42 +00:00
transnum ( LABEL_DEFINE ) ; // Volume Number (0/4)
2020-05-15 09:30:33 +00:00
k = popscriptvalue ( ) - 1 ;
2020-07-07 18:27:21 +00:00
if ( k < 0 ) specialmusic . Clear ( ) ;
2020-05-12 13:39:35 +00:00
2020-07-07 18:27:21 +00:00
i = 0 ;
// get the file name...
while ( keyword ( ) = = - 1 )
2020-05-12 13:39:35 +00:00
{
2020-07-07 18:27:21 +00:00
while ( isaltok ( * textptr ) = = 0 )
2020-05-12 13:39:35 +00:00
{
2020-07-07 18:27:21 +00:00
if ( * textptr = = 0x0a ) line_number + + ;
textptr + + ;
if ( * textptr = = 0 ) break ;
}
j = 0 ;
parsebuffer . Clear ( ) ;
while ( isaltok ( * ( textptr + j ) ) )
{
parsebuffer . Push ( textptr [ j ] ) ;
j + + ;
}
parsebuffer . Push ( 0 ) ;
if ( k > = 0 )
{
tempMusic . Reserve ( 1 ) ;
tempMusic . Last ( ) . levnum = levelnum ( k , i ) ;
tempMusic . Last ( ) . music = parsebuffer . Data ( ) ;
2020-05-12 13:39:35 +00:00
}
2020-07-07 18:27:21 +00:00
else
{
specialmusic . Push ( parsebuffer . Data ( ) ) ;
}
2020-07-07 19:38:20 +00:00
textptr + = j ;
2020-07-07 18:27:21 +00:00
i + + ;
2020-05-12 13:39:35 +00:00
}
2020-07-07 18:27:21 +00:00
2020-05-12 19:22:08 +00:00
return 0 ;
2020-05-12 13:39:35 +00:00
}
case concmd_include :
{
2020-05-12 14:55:25 +00:00
popscriptvalue ( ) ;
2020-05-13 10:18:36 +00:00
skipcomments ( ) ;
parsebuffer . Clear ( ) ;
2020-05-12 13:39:35 +00:00
while ( isaltok ( * textptr ) = = 0 )
{
if ( * textptr = = 0x0a ) line_number + + ;
textptr + + ;
if ( * textptr = = 0 ) break ;
}
j = 0 ;
while ( isaltok ( * textptr ) )
{
2020-05-13 10:18:36 +00:00
parsebuffer . Push ( * ( textptr + + ) ) ;
2020-05-12 13:39:35 +00:00
j + + ;
}
2020-05-13 10:18:36 +00:00
parsebuffer . Push ( 0 ) ;
2020-05-12 13:39:35 +00:00
2020-05-13 22:04:14 +00:00
auto fni = fileSystem . FindFile ( parsebuffer . Data ( ) ) ;
if ( fni < 0 )
2020-05-12 13:39:35 +00:00
{
errorcount + + ;
2020-05-13 22:04:14 +00:00
Printf ( TEXTCOLOR_RED " * ERROR!(%s, line %d) Could not find '%s'. \n " , fn , line_number , parsebuffer . Data ( ) ) ;
2020-05-12 13:39:35 +00:00
ReportError ( ERROR_COULDNOTFIND ) ;
return 0 ;
}
2020-05-13 22:04:14 +00:00
auto data = fileSystem . GetFileData ( fni , 1 ) ;
2020-05-12 13:39:35 +00:00
2020-07-19 17:13:27 +00:00
temp_current_file = currentsourcefile ;
currentsourcefile = fni ;
2020-05-12 13:39:35 +00:00
temp_line_number = line_number ;
line_number = 1 ;
temp_ifelse_check = checking_ifelse ;
checking_ifelse = 0 ;
auto origtptr = textptr ;
textptr = ( char * ) data . Data ( ) ;
do
done = parsecommand ( ) ;
while ( done = = 0 ) ;
textptr = origtptr ;
line_number = temp_line_number ;
checking_ifelse = temp_ifelse_check ;
2020-07-19 17:13:27 +00:00
currentsourcefile = temp_current_file ;
2020-05-13 22:04:14 +00:00
if ( * textptr = = ' " ' ) textptr + + ; // needed for RR.
2020-05-12 13:39:35 +00:00
return 0 ;
}
2020-05-13 10:18:36 +00:00
2020-05-12 13:39:35 +00:00
case concmd_ai :
if ( parsing_actor | | parsing_state )
2020-07-15 10:34:42 +00:00
transnum ( LABEL_AI ) ;
2020-05-12 13:39:35 +00:00
else
{
2020-05-12 14:55:25 +00:00
popscriptvalue ( ) ;
2020-05-12 13:39:35 +00:00
getlabel ( ) ;
2020-05-12 19:22:08 +00:00
checkforkeyword ( ) ;
2020-05-12 13:39:35 +00:00
2020-07-15 10:34:42 +00:00
lnum = findlabel ( parselabel ) ;
2020-05-12 20:52:49 +00:00
if ( lnum > = 0 )
{
warningcount + + ;
2020-07-23 14:35:54 +00:00
Printf ( TEXTCOLOR_RED " * WARNING.(%s, line %d) Duplicate ai '%s' ignored. \n " , fn , line_number , parselabel . GetChars ( ) ) ;
2020-05-12 20:52:49 +00:00
}
2020-07-15 10:34:42 +00:00
else appendlabeladdress ( LABEL_AI ) ;
2020-05-12 13:39:35 +00:00
for ( j = 0 ; j < 3 ; j + + )
{
if ( keyword ( ) > = 0 ) break ;
if ( j = = 2 )
{
k = 0 ;
while ( keyword ( ) = = - 1 )
{
2020-07-15 10:34:42 +00:00
transnum ( LABEL_DEFINE ) ;
2020-05-12 19:22:08 +00:00
k | = popscriptvalue ( ) ;
2020-05-12 13:39:35 +00:00
}
2020-05-12 14:55:25 +00:00
appendscriptvalue ( k ) ;
2020-05-12 13:39:35 +00:00
return 0 ;
}
2020-07-15 10:34:42 +00:00
else transnum ( j = = 0 ? LABEL_ACTION : LABEL_MOVE ) ;
2020-05-12 13:39:35 +00:00
}
for ( k = j ; k < 3 ; k + + )
{
2020-05-12 14:55:25 +00:00
appendscriptvalue ( 0 ) ;
2020-05-12 13:39:35 +00:00
}
}
return 0 ;
case concmd_action :
if ( parsing_actor | | parsing_state )
2020-07-15 10:34:42 +00:00
transnum ( LABEL_ACTION ) ;
2020-05-12 13:39:35 +00:00
else
{
2020-05-12 14:55:25 +00:00
popscriptvalue ( ) ;
2020-05-12 13:39:35 +00:00
getlabel ( ) ;
2020-05-12 20:52:49 +00:00
checkforkeyword ( ) ;
2020-05-12 13:39:35 +00:00
2020-07-15 10:34:42 +00:00
lnum = findlabel ( parselabel ) ;
2020-05-12 20:52:49 +00:00
if ( lnum > = 0 )
2020-05-12 13:39:35 +00:00
{
2020-05-12 20:52:49 +00:00
warningcount + + ;
2020-07-23 14:35:54 +00:00
Printf ( TEXTCOLOR_RED " * WARNING.(%s, line %d) Duplicate event '%s' ignored. \n " , fn , line_number , parselabel . GetChars ( ) ) ;
2020-05-12 13:39:35 +00:00
}
2020-07-15 10:34:42 +00:00
else appendlabeladdress ( LABEL_ACTION ) ;
2020-05-12 13:39:35 +00:00
for ( j = 0 ; j < 5 ; j + + )
{
if ( keyword ( ) > = 0 ) break ;
2020-07-15 10:34:42 +00:00
transnum ( LABEL_DEFINE ) ;
2020-05-12 13:39:35 +00:00
}
for ( k = j ; k < 5 ; k + + )
{
2020-05-12 14:55:25 +00:00
appendscriptvalue ( 0 ) ;
2020-05-12 13:39:35 +00:00
}
}
return 0 ;
case concmd_actor :
2020-05-12 21:55:33 +00:00
case concmd_useractor : // merged with 'actor' because the code is identical except for the added type parameter.
2020-05-12 20:52:49 +00:00
{
2020-05-12 13:39:35 +00:00
if ( parsing_state )
{
Printf ( TEXTCOLOR_RED " * ERROR!(%s, line %d) Found 'actor' within 'state'. \n " , fn , line_number ) ;
errorcount + + ;
}
if ( parsing_actor )
{
Printf ( TEXTCOLOR_RED " * ERROR!(%s, line %d) Found 'actor' within 'actor'. \n " , fn , line_number ) ;
errorcount + + ;
}
num_squigilly_brackets = 0 ;
2020-05-12 14:55:25 +00:00
popscriptvalue ( ) ;
2020-05-12 20:52:49 +00:00
parsing_actor = scriptpos ( ) ;
2020-05-12 13:39:35 +00:00
2020-05-12 21:55:33 +00:00
if ( tw = = concmd_useractor )
{
2020-07-15 10:34:42 +00:00
transnum ( LABEL_DEFINE ) ;
2020-05-12 21:55:33 +00:00
j = popscriptvalue ( ) ;
}
2020-07-15 10:34:42 +00:00
transnum ( LABEL_DEFINE ) ;
2020-05-12 20:52:49 +00:00
lnum = popscriptvalue ( ) ;
2020-05-15 08:44:57 +00:00
actorinfo [ lnum ] . scriptaddress = parsing_actor ; // TRANSITIONAL should only store an index
2020-05-12 21:55:33 +00:00
if ( tw = = concmd_useractor )
{
if ( j & 1 )
2020-05-15 08:44:57 +00:00
actorinfo [ lnum ] . flags | = SFLAG_BADGUY ;
2020-05-12 21:55:33 +00:00
if ( j & 2 )
2020-05-15 08:44:57 +00:00
actorinfo [ lnum ] . flags | = ( SFLAG_BADGUY | SFLAG_BADGUYSTAYPUT ) ;
2020-05-12 21:55:33 +00:00
}
2020-05-12 13:39:35 +00:00
for ( j = 0 ; j < 4 ; j + + )
{
2020-05-12 20:52:49 +00:00
setscriptvalue ( parsing_actor + j , 0 ) ;
2020-05-12 13:39:35 +00:00
if ( j = = 3 )
{
j = 0 ;
while ( keyword ( ) = = - 1 )
{
2020-07-15 10:34:42 +00:00
transnum ( LABEL_DEFINE ) ;
2020-05-12 20:52:49 +00:00
j | = popscriptvalue ( ) ;
2020-05-12 13:39:35 +00:00
}
2020-05-12 14:55:25 +00:00
appendscriptvalue ( j ) ;
2020-05-12 13:39:35 +00:00
break ;
}
else
{
if ( keyword ( ) > = 0 )
{
2020-05-12 20:52:49 +00:00
reservescriptspace ( 4 - j ) ;
2020-05-12 13:39:35 +00:00
break ;
}
2020-07-15 10:34:42 +00:00
switch ( j )
{
case 0 : transnum ( LABEL_DEFINE ) ; break ;
case 1 : transnum ( LABEL_ACTION ) ; break ;
case 2 : transnum ( LABEL_MOVE | LABEL_DEFINE ) ; break ;
}
2020-05-12 21:55:33 +00:00
// This code was originally here but is a no-op, because both source and destination are the same here.
2020-05-15 08:44:57 +00:00
//*(parsing_actor + j) = *(scriptaddress - 1);
2020-05-12 13:39:35 +00:00
}
}
checking_ifelse = 0 ;
return 0 ;
2020-05-12 20:52:49 +00:00
}
2020-05-12 13:39:35 +00:00
case concmd_onevent :
if ( parsing_state )
{
Printf ( TEXTCOLOR_RED " * ERROR!(%s, line %d) Found 'onevent' within 'state'. \n " , fn , line_number ) ;
errorcount + + ;
}
if ( parsing_actor )
{
Printf ( TEXTCOLOR_RED " * ERROR!(%s, line %d) Found 'onevent' within 'actor'. \n " , fn , line_number ) ;
errorcount + + ;
}
num_squigilly_brackets = 0 ;
2020-05-12 14:55:25 +00:00
popscriptvalue ( ) ;
2020-05-13 11:30:14 +00:00
parsing_event = parsing_actor = scriptpos ( ) ;
2020-05-12 13:39:35 +00:00
2020-07-15 10:34:42 +00:00
transnum ( LABEL_DEFINE ) ;
2020-05-15 09:30:33 +00:00
j = popscriptvalue ( ) ;
2020-05-12 13:39:35 +00:00
if ( j < 0 | | j > EVENT_MAXEVENT )
{
Printf ( TEXTCOLOR_RED " * ERROR!(%s, line %d) Invalid Event ID. \n " , fn , line_number ) ;
errorcount + + ;
return 0 ;
}
apScriptGameEvent [ j ] = parsing_event ;
checking_ifelse = 0 ;
return 0 ;
2020-05-13 11:30:14 +00:00
2020-05-12 13:39:35 +00:00
2020-05-12 21:55:33 +00:00
case concmd_cstat :
2020-07-15 10:34:42 +00:00
transnum ( LABEL_DEFINE ) ;
2020-05-12 21:55:33 +00:00
#if 0
// the following checks are being performed by EDuke32 and RedNukem - not sure if this really should be done.
// DukeGDX and RedneckGDX do not perform these checks. Code pasted here for making a decision later.
2020-05-12 13:39:35 +00:00
2020-05-12 21:55:33 +00:00
i = popscriptvalue ( ) ;
if ( i = = 32767 )
2020-05-12 13:39:35 +00:00
{
2020-05-12 21:55:33 +00:00
i = 32768 ;
Printf ( TEXTCOLOR_RED " * WARNING!(%s, line %d) tried to set cstat 32767, using 32768 instead. \n " , fn , line_number ) ;
warningcount + + ;
2020-05-12 13:39:35 +00:00
}
2020-05-12 21:55:33 +00:00
else if ( ( i & 48 ) = = 48 )
2020-05-12 13:39:35 +00:00
{
2020-05-12 21:55:33 +00:00
Printf ( TEXTCOLOR_RED " * WARNING!(%s, line %d) tried to set cstat %d, using %d instead. \n " , fn , line_number , i , i ^ 48 ) ;
i ^ = 48 ;
warningcount + + ;
2020-05-12 13:39:35 +00:00
}
2020-05-12 21:55:33 +00:00
appendscriptvalue ( i ) ;
# endif
2020-05-12 13:39:35 +00:00
return 0 ;
2020-05-12 21:55:33 +00:00
case concmd_sound :
case concmd_globalsound :
case concmd_soundonce :
case concmd_stopsound :
case concmd_lotsofglass :
2020-05-12 13:39:35 +00:00
case concmd_strength :
case concmd_shoot :
case concmd_addphealth :
case concmd_spawn :
case concmd_count :
case concmd_endofgame :
case concmd_spritepal :
case concmd_cactor :
case concmd_quote :
case concmd_money :
case concmd_addkills :
case concmd_debug :
case concmd_addstrength :
case concmd_cstator :
case concmd_mail :
case concmd_paper :
case concmd_sleeptime :
case concmd_clipdist :
case concmd_isdrunk :
case concmd_iseat :
case concmd_newpic :
2020-07-15 10:34:42 +00:00
transnum ( LABEL_DEFINE ) ;
2020-05-12 13:39:35 +00:00
return 0 ;
case concmd_addammo :
case concmd_addweapon :
case concmd_sizeto :
case concmd_sizeat :
case concmd_debris :
case concmd_addinventory :
case concmd_guts :
2020-07-15 10:34:42 +00:00
transnum ( LABEL_DEFINE ) ;
transnum ( LABEL_DEFINE ) ;
2020-05-12 21:55:33 +00:00
return 0 ;
2020-05-12 13:39:35 +00:00
case concmd_hitradius :
2020-07-15 10:34:42 +00:00
transnum ( LABEL_DEFINE ) ;
transnum ( LABEL_DEFINE ) ;
transnum ( LABEL_DEFINE ) ;
transnum ( LABEL_DEFINE ) ;
transnum ( LABEL_DEFINE ) ;
2020-05-12 13:39:35 +00:00
break ;
2020-05-13 06:40:26 +00:00
2020-05-12 13:39:35 +00:00
case concmd_else :
if ( checking_ifelse )
{
checking_ifelse - - ;
2020-05-13 06:40:26 +00:00
tempscrptr = scriptpos ( ) ;
2020-05-15 09:30:33 +00:00
reservescriptspace ( 1 ) ; //Leave a spot for the fail location
2020-05-12 13:39:35 +00:00
parsecommand ( ) ;
2020-05-13 06:40:26 +00:00
setscriptvalue ( tempscrptr , scriptpos ( ) ) ;
2020-05-12 13:39:35 +00:00
}
else
{
2020-05-12 14:55:25 +00:00
popscriptvalue ( ) ;
2020-05-12 13:39:35 +00:00
warningcount + + ;
2020-05-13 06:40:26 +00:00
Printf ( TEXTCOLOR_YELLOW " * WARNING.(%s, line %d) Found 'else' with no 'if', ignored. \n " , fn , line_number ) ;
2020-05-12 13:39:35 +00:00
}
return 0 ;
case concmd_setvar :
case concmd_addvar :
// syntax: [rand|add|set]var <var1> <const1>
// sets var1 to const1
// adds const1 to var1 (const1 can be negative...)
// get the ID of the DEF
getlabel ( ) ; //GetGameVarLabel();
// Check to see if it's a keyword
2020-05-13 11:03:52 +00:00
checkforkeyword ( ) ;
2020-05-12 13:39:35 +00:00
2020-07-15 10:34:42 +00:00
i = GetDefID ( parselabel ) ;
2020-05-12 13:39:35 +00:00
if ( i < 0 )
{ // not a defined DEF
errorcount + + ;
ReportError ( ERROR_NOTAGAMEDEF ) ;
return 0 ;
}
2020-05-13 17:11:08 +00:00
if ( aGameVars [ i ] . dwFlags & GAMEVAR_FLAG_READONLY )
2020-05-12 13:39:35 +00:00
{
errorcount + + ;
ReportError ( ERROR_VARREADONLY ) ;
return 0 ;
}
2020-05-12 14:55:25 +00:00
appendscriptvalue ( i ) ; // the ID of the DEF (offset into array...)
2020-05-12 13:39:35 +00:00
2020-07-15 10:34:42 +00:00
transnum ( LABEL_DEFINE ) ; // the number to check against...
2020-05-12 13:39:35 +00:00
return 0 ;
case concmd_setvarvar :
case concmd_addvarvar :
// syntax: [add|set]varvar <var1> <var2>
// sets var1 = var2
// adds var1 and var2 with result in var1
// get the ID of the DEF
getlabel ( ) ; //GetGameVarLabel();
2020-05-13 11:03:52 +00:00
checkforkeyword ( ) ;
2020-05-12 13:39:35 +00:00
2020-07-15 10:34:42 +00:00
i = GetDefID ( parselabel ) ;
2020-05-12 13:39:35 +00:00
if ( i < 0 )
{ // not a defined DEF
errorcount + + ;
ReportError ( ERROR_NOTAGAMEDEF ) ;
return 0 ;
}
2020-05-13 17:11:08 +00:00
if ( aGameVars [ i ] . dwFlags & GAMEVAR_FLAG_READONLY )
2020-05-12 13:39:35 +00:00
{
errorcount + + ;
ReportError ( ERROR_VARREADONLY ) ;
return 0 ;
}
2020-05-12 14:55:25 +00:00
appendscriptvalue ( i ) ; // the ID of the DEF (offset into array...)
2020-05-12 13:39:35 +00:00
// get the ID of the DEF
getlabel ( ) ; //GetGameVarLabel();
2020-05-13 11:03:52 +00:00
checkforkeyword ( ) ;
2020-05-12 13:39:35 +00:00
2020-07-15 10:34:42 +00:00
i = GetDefID ( parselabel ) ;
2020-05-12 13:39:35 +00:00
if ( i < 0 )
{ // not a defined DEF
errorcount + + ;
ReportError ( ERROR_NOTAGAMEDEF ) ;
return 0 ;
}
2020-05-13 11:03:52 +00:00
2020-05-12 14:55:25 +00:00
appendscriptvalue ( i ) ; // the ID of the DEF (offset into array...)
2020-05-12 13:39:35 +00:00
return 0 ;
case concmd_ifvarvarg :
case concmd_ifvarvarl :
case concmd_ifvarvare :
// get the ID of the DEF
getlabel ( ) ; //GetGameVarLabel();
2020-05-13 11:03:52 +00:00
checkforkeyword ( ) ;
2020-05-12 13:39:35 +00:00
2020-07-15 10:34:42 +00:00
i = GetDefID ( parselabel ) ;
2020-05-12 13:39:35 +00:00
if ( i < 0 )
{ // not a defined DEF
errorcount + + ;
ReportError ( ERROR_NOTAGAMEDEF ) ;
return 0 ;
}
2020-05-12 14:55:25 +00:00
appendscriptvalue ( i ) ; // the ID of the DEF (offset into array...)
2020-05-12 13:39:35 +00:00
// get the ID of the DEF
getlabel ( ) ; //GetGameVarLabel();
2020-05-13 11:03:52 +00:00
checkforkeyword ( ) ;
2020-05-12 13:39:35 +00:00
2020-07-15 10:34:42 +00:00
i = GetDefID ( parselabel ) ;
2020-05-12 13:39:35 +00:00
if ( i < 0 )
{ // not a defined DEF
errorcount + + ;
ReportError ( ERROR_NOTAGAMEDEF ) ;
return 0 ;
}
2020-05-12 14:55:25 +00:00
appendscriptvalue ( i ) ; // the ID of the DEF (offset into array...)
2020-05-13 07:17:59 +00:00
goto if_common ;
2020-05-12 13:39:35 +00:00
case concmd_ifvarl :
case concmd_ifvarg :
case concmd_ifvare :
// get the ID of the DEF
getlabel ( ) ; //GetGameVarLabel();
2020-05-13 11:03:52 +00:00
checkforkeyword ( ) ;
2020-07-15 10:34:42 +00:00
i = GetDefID ( parselabel ) ;
2020-05-12 13:39:35 +00:00
if ( i < 0 )
{ // not a defined DEF
errorcount + + ;
ReportError ( ERROR_NOTAGAMEVAR ) ;
return 0 ;
}
2020-05-12 14:55:25 +00:00
appendscriptvalue ( i ) ; // the ID of the DEF (offset into array...)
2020-05-12 13:39:35 +00:00
2020-07-15 10:34:42 +00:00
transnum ( LABEL_DEFINE ) ; // the number to check against...
2020-05-13 07:17:59 +00:00
goto if_common ;
2020-05-12 13:39:35 +00:00
case concmd_addlogvar :
// syntax: addlogvar <var>
2020-07-19 17:13:27 +00:00
appendscriptvalue ( currentsourcefile ) ;
2020-05-12 14:55:25 +00:00
appendscriptvalue ( line_number ) ;
2020-05-12 13:39:35 +00:00
// get the ID of the DEF
getlabel ( ) ; //GetGameVarLabel();
2020-05-13 11:03:52 +00:00
checkforkeyword ( ) ;
2020-05-12 13:39:35 +00:00
2020-07-15 10:34:42 +00:00
i = GetDefID ( parselabel ) ;
2020-05-12 13:39:35 +00:00
if ( i < 0 )
{ // not a defined DEF
errorcount + + ;
ReportError ( ERROR_NOTAGAMEDEF ) ;
return 0 ;
}
2020-05-13 11:03:52 +00:00
appendscriptvalue ( i ) ;
2020-05-12 13:39:35 +00:00
return 0 ;
case concmd_addlog :
// syntax: addlog
// source file.
2020-07-19 17:13:27 +00:00
appendscriptvalue ( currentsourcefile ) ;
2020-05-12 13:39:35 +00:00
// prints the line number in the log file.
2020-05-12 14:55:25 +00:00
appendscriptvalue ( line_number ) ;
2020-05-12 13:39:35 +00:00
return 0 ;
2020-05-13 11:03:52 +00:00
2020-05-13 07:17:59 +00:00
case concmd_ifp :
j = 0 ;
do
{
2020-07-15 10:34:42 +00:00
transnum ( LABEL_DEFINE ) ;
2020-05-15 09:30:33 +00:00
j | = popscriptvalue ( ) ;
2020-05-13 07:17:59 +00:00
} while ( keyword ( ) = = - 1 ) ;
appendscriptvalue ( j ) ;
goto if_common ;
2020-05-12 13:39:35 +00:00
case concmd_ifpinventory :
2020-07-15 10:34:42 +00:00
transnum ( LABEL_DEFINE ) ;
2020-05-12 13:39:35 +00:00
case concmd_ifrnd :
case concmd_ifpdistl :
case concmd_ifpdistg :
case concmd_ifai :
case concmd_ifwasweapon :
case concmd_ifaction :
case concmd_ifactioncount :
case concmd_ifmove :
case concmd_ifcount :
case concmd_ifactor :
case concmd_ifstrength :
case concmd_ifspawnedby :
case concmd_ifgapzl :
case concmd_iffloordistl :
case concmd_ifceilingdistl :
// case 74:
case concmd_ifphealthl :
case concmd_ifspritepal :
case concmd_ifgotweaponce :
case concmd_ifangdiffl :
case concmd_ifactorhealthg :
case concmd_ifactorhealthl :
case concmd_ifsoundid :
case concmd_ifsounddist :
2020-07-15 10:34:42 +00:00
transnum ( tw = = concmd_ifai ? LABEL_AI : tw = = concmd_ifaction ? LABEL_ACTION : tw = = concmd_ifmove ? LABEL_MOVE : LABEL_DEFINE ) ;
2020-05-12 13:39:35 +00:00
case concmd_ifonwater :
case concmd_ifinwater :
case concmd_ifactornotstayput :
case concmd_ifcansee :
case concmd_ifhitweapon :
case concmd_ifsquished :
case concmd_ifdead :
case concmd_ifcanshoottarget :
case concmd_ifhitspace :
case concmd_ifoutside :
case concmd_ifmultiplayer :
case concmd_ifinspace :
case concmd_ifbulletnear :
case concmd_ifrespawn :
case concmd_ifinouterspace :
case concmd_ifnotmoving :
case concmd_ifawayfromwall :
case concmd_ifcanseetarget :
case concmd_ifnosounds :
case concmd_ifnocover :
case concmd_ifhittruck :
case concmd_iftipcow :
case concmd_ifonmud :
case concmd_ifcoop :
case concmd_ifmotofast :
case concmd_ifwind :
case concmd_ifonmoto :
case concmd_ifonboat :
case concmd_ifsizedown :
case concmd_ifplaybackon :
2020-05-12 22:29:00 +00:00
// case concmd_iffindnewspot: // RRDH
// case concmd_ifpupwind:
2020-05-12 13:39:35 +00:00
2020-05-13 07:17:59 +00:00
if_common : // this code is identical for all 'if...'instructions.
2020-07-22 20:27:51 +00:00
{
2020-05-12 22:29:00 +00:00
tempscrptr = scriptpos ( ) ;
reservescriptspace ( 1 ) ; //Leave a spot for the fail location
2020-05-12 13:39:35 +00:00
2020-05-12 22:29:00 +00:00
skipcomments ( ) ;
2020-05-12 13:39:35 +00:00
parsecommand ( ) ;
2020-05-12 22:29:00 +00:00
setscriptvalue ( tempscrptr , scriptpos ( ) ) ;
2020-07-22 20:27:51 +00:00
auto k = keyword ( ) ;
// Cannot be done - the code starts misbehaving with this check, it is especially noticeable on the soldiers in NAM.
// Unfortunately this means one less error check, but ultimately CON is too broken to begin with anyway
#if 0
if ( k = = concmd_else ) / only increment checking_ifelse if there actually is an else . Otherwise this would break the entire checking logic and render it non - functional
# endif
2020-05-13 07:17:59 +00:00
checking_ifelse + + ;
2020-05-12 13:39:35 +00:00
return 0 ;
2020-07-22 20:27:51 +00:00
}
2020-05-12 13:39:35 +00:00
case concmd_leftbrace :
num_squigilly_brackets + + ;
do
done = parsecommand ( ) ;
while ( done = = 0 ) ;
return 0 ;
case concmd_rightbrace :
num_squigilly_brackets - - ;
if ( num_squigilly_brackets < 0 )
{
Printf ( TEXTCOLOR_RED " * ERROR!(%s, line %d) Found more '}' than '{'. \n " , fn , line_number ) ;
errorcount + + ;
}
return 1 ;
case concmd_betaname :
2020-05-12 14:55:25 +00:00
popscriptvalue ( ) ;
2020-05-12 13:39:35 +00:00
// not used anywhere, just parse over it.
2020-05-13 06:40:26 +00:00
skiptoendofline ( ) ;
2020-05-12 13:39:35 +00:00
return 0 ;
case concmd_definevolumename :
2020-05-12 14:55:25 +00:00
popscriptvalue ( ) ;
2020-07-15 10:34:42 +00:00
transnum ( LABEL_DEFINE ) ;
2020-05-15 09:30:33 +00:00
j = popscriptvalue ( ) ;
2020-05-12 13:39:35 +00:00
while ( * textptr = = ' ' | | * textptr = = ' \t ' ) textptr + + ;
i = 0 ;
parsebuffer . Clear ( ) ;
while ( * textptr ! = 0x0a & & * textptr ! = 0x0d & & * textptr ! = 0 ) // JBF 20040127: end of file checked
{
parsebuffer . Push ( * textptr ) ;
textptr + + , i + + ;
}
parsebuffer . Push ( 0 ) ;
2020-05-13 06:40:26 +00:00
gVolumeNames [ j ] = FStringTable : : MakeMacro ( parsebuffer . Data ( ) , i ) ;
2020-05-12 13:39:35 +00:00
return 0 ;
case concmd_defineskillname :
2020-05-12 14:55:25 +00:00
popscriptvalue ( ) ;
2020-07-15 10:34:42 +00:00
transnum ( LABEL_DEFINE ) ;
2020-05-15 09:30:33 +00:00
j = popscriptvalue ( ) ;
2020-05-12 13:39:35 +00:00
while ( * textptr = = ' ' ) textptr + + ;
i = 0 ;
parsebuffer . Clear ( ) ;
while ( * textptr ! = 0x0a & & * textptr ! = 0x0d & & * textptr ! = 0 ) // JBF 20040127: end of file checked
{
parsebuffer . Push ( * textptr ) ;
textptr + + , i + + ;
}
parsebuffer . Push ( 0 ) ;
2020-05-13 06:40:26 +00:00
gSkillNames [ j ] = FStringTable : : MakeMacro ( parsebuffer . Data ( ) , i ) ;
2020-05-12 13:39:35 +00:00
return 0 ;
case concmd_definelevelname :
2020-07-07 18:27:21 +00:00
{
2020-05-12 14:55:25 +00:00
popscriptvalue ( ) ;
2020-07-15 10:34:42 +00:00
transnum ( LABEL_DEFINE ) ;
2020-05-15 09:30:33 +00:00
j = popscriptvalue ( ) ;
2020-07-15 10:34:42 +00:00
transnum ( LABEL_DEFINE ) ;
2020-05-15 09:30:33 +00:00
k = popscriptvalue ( ) ;
2020-05-12 13:39:35 +00:00
while ( * textptr = = ' ' ) textptr + + ;
i = 0 ;
parsebuffer . Clear ( ) ;
while ( * textptr ! = ' ' & & * textptr ! = 0x0a & & * textptr ! = 0x0d & & * textptr ! = 0 ) // JBF 20040127: end of file checked
{
parsebuffer . Push ( * textptr ) ;
textptr + + , i + + ;
}
parsebuffer . Push ( 0 ) ;
2020-07-07 18:27:21 +00:00
auto levnum = levelnum ( j , k ) ;
auto map = FindMapByLevelNum ( levnum ) ;
if ( ! map ) map = AllocateMap ( ) ;
map - > SetFileName ( parsebuffer . Data ( ) ) ;
2020-05-12 13:39:35 +00:00
while ( * textptr = = ' ' ) textptr + + ;
2020-07-07 18:27:21 +00:00
map - > parTime =
2020-05-12 13:39:35 +00:00
( ( ( * ( textptr + 0 ) - ' 0 ' ) * 10 + ( * ( textptr + 1 ) - ' 0 ' ) ) * 26 * 60 ) +
( ( ( * ( textptr + 3 ) - ' 0 ' ) * 10 + ( * ( textptr + 4 ) - ' 0 ' ) ) * 26 ) ;
textptr + = 5 ;
while ( * textptr = = ' ' ) textptr + + ;
2020-07-07 18:27:21 +00:00
map - > designerTime =
2020-05-12 13:39:35 +00:00
( ( ( * ( textptr + 0 ) - ' 0 ' ) * 10 + ( * ( textptr + 1 ) - ' 0 ' ) ) * 26 * 60 ) +
( ( ( * ( textptr + 3 ) - ' 0 ' ) * 10 + ( * ( textptr + 4 ) - ' 0 ' ) ) * 26 ) ;
2020-07-07 18:27:21 +00:00
map - > levelNumber = levnum ;
2020-07-01 18:31:29 +00:00
2020-05-12 13:39:35 +00:00
textptr + = 5 ;
while ( * textptr = = ' ' ) textptr + + ;
i = 0 ;
parsebuffer . Clear ( ) ;
while ( * textptr ! = 0x0a & & * textptr ! = 0x0d & & * textptr ! = 0 ) // JBF 20040127: end of file checked
{
parsebuffer . Push ( * textptr ) ;
textptr + + , i + + ;
}
parsebuffer . Push ( 0 ) ;
2020-07-07 18:27:21 +00:00
map - > name = parsebuffer . Data ( ) ;
2020-05-12 13:39:35 +00:00
return 0 ;
2020-07-07 18:27:21 +00:00
}
2020-05-12 13:39:35 +00:00
case concmd_definequote :
2020-05-12 14:55:25 +00:00
popscriptvalue ( ) ;
2020-07-15 10:34:42 +00:00
transnum ( LABEL_DEFINE ) ;
2020-05-15 09:30:33 +00:00
k = popscriptvalue ( ) ;
2020-05-12 13:39:35 +00:00
if ( k > = MAXQUOTES )
{
2020-07-23 14:35:54 +00:00
Printf ( TEXTCOLOR_RED " * ERROR!(%s, line %d) Quote number exceeds limit of %d. \n " , fn , line_number , MAXQUOTES ) ;
2020-05-12 13:39:35 +00:00
errorcount + + ;
}
2020-05-15 09:30:33 +00:00
2020-05-12 13:39:35 +00:00
i = 0 ;
while ( * textptr = = ' ' )
textptr + + ;
parsebuffer . Clear ( ) ;
while ( * textptr ! = 0x0a & & * textptr ! = 0x0d & & * textptr ! = 0 ) // JBF 20040127: end of file checked
{
parsebuffer . Push ( * textptr ) ;
textptr + + , i + + ;
}
parsebuffer . Push ( 0 ) ;
quoteMgr . InitializeQuote ( k , parsebuffer . Data ( ) , true ) ;
return 0 ;
case concmd_definesound :
{
2020-05-12 14:55:25 +00:00
popscriptvalue ( ) ;
2020-07-15 10:34:42 +00:00
transnum ( LABEL_DEFINE ) ;
2020-05-15 09:30:33 +00:00
k = popscriptvalue ( ) ;
2020-05-12 13:39:35 +00:00
i = 0 ;
while ( * textptr = = ' ' )
textptr + + ;
parsebuffer . Clear ( ) ;
while ( * textptr ! = ' ' & & * textptr ! = 0 ) // JBF 20040127: end of file checked
{
parsebuffer . Push ( * textptr ) ;
textptr + + , i + + ;
}
parsebuffer . Push ( 0 ) ;
2020-07-15 10:34:42 +00:00
transnum ( LABEL_DEFINE ) ;
2020-05-15 09:30:33 +00:00
int ps = popscriptvalue ( ) ;
2020-07-15 10:34:42 +00:00
transnum ( LABEL_DEFINE ) ;
2020-05-15 09:30:33 +00:00
int pe = popscriptvalue ( ) ;
2020-07-15 10:34:42 +00:00
transnum ( LABEL_DEFINE ) ;
2020-05-15 09:30:33 +00:00
int pr = popscriptvalue ( ) ;
2020-07-15 10:34:42 +00:00
transnum ( LABEL_DEFINE ) ;
2020-05-15 09:30:33 +00:00
int m = popscriptvalue ( ) ;
2020-07-15 10:34:42 +00:00
transnum ( LABEL_DEFINE ) ;
2020-05-15 09:30:33 +00:00
int vo = popscriptvalue ( ) ;
2020-05-12 13:39:35 +00:00
S_DefineSound ( k , parsebuffer . Data ( ) , ps , pe , pr , m , vo , 1.f ) ;
return 0 ;
}
2020-05-13 11:30:14 +00:00
2020-05-12 13:39:35 +00:00
case concmd_endevent :
if ( parsing_event = = 0 )
{
2020-07-23 14:35:54 +00:00
Printf ( TEXTCOLOR_RED " * ERROR!(%s, line %d) Found 'endevent' without defining 'onevent'. \n " , fn , line_number ) ;
2020-05-12 13:39:35 +00:00
errorcount + + ;
}
// else
{
if ( num_squigilly_brackets > 0 )
{
2020-07-23 14:35:54 +00:00
Printf ( TEXTCOLOR_RED " * ERROR!(%s, line %d) Found more '{' than '}' before 'endevent'. \n " , fn , line_number ) ;
2020-05-12 13:39:35 +00:00
errorcount + + ;
}
parsing_event = 0 ;
parsing_actor = 0 ;
}
return 0 ;
case concmd_enda :
if ( parsing_actor = = 0 )
{
2020-07-23 14:35:54 +00:00
Printf ( TEXTCOLOR_RED " * ERROR!(%s, line %d) Found 'enda' without defining 'actor'. \n " , fn , line_number ) ;
2020-05-12 13:39:35 +00:00
errorcount + + ;
}
// else
{
if ( num_squigilly_brackets > 0 )
{
2020-07-23 14:35:54 +00:00
Printf ( TEXTCOLOR_RED " * ERROR!(%s, line %d) Found more '{' than '}' before 'enda'. \n " , fn , line_number ) ;
2020-05-12 13:39:35 +00:00
errorcount + + ;
}
parsing_actor = 0 ;
}
return 0 ;
case concmd_break :
case concmd_fall :
case concmd_tip :
// case 21:
case concmd_killit : //KILLIT
case concmd_resetactioncount :
case concmd_pstomp :
case concmd_resetplayer :
case concmd_resetcount :
case concmd_wackplayer :
case concmd_operate :
case concmd_respawnhitag :
case concmd_getlastpal :
case concmd_pkick :
case concmd_mikesnd :
case concmd_tossweapon :
case concmd_nullop :
case concmd_destroyit :
case concmd_larrybird :
case concmd_strafeleft :
case concmd_straferight :
case concmd_slapplayer :
//case 122:
case concmd_tearitup :
case concmd_smackbubba :
case concmd_soundtagonce :
case concmd_soundtag :
case concmd_smacksprite :
case concmd_fakebubba :
case concmd_mamatrigger :
case concmd_mamaspawn :
case concmd_mamaquake :
case concmd_mamaend :
case concmd_garybanjo :
case concmd_motoloopsnd :
case concmd_rndmove :
2020-07-19 19:04:22 +00:00
//case concmd_leavetrax: // RRDH
//case concmd_leavedroppings:
//case concmd_deploybias:
2020-05-12 13:39:35 +00:00
return 0 ;
case concmd_gamestartup :
{
2020-07-19 19:04:22 +00:00
// What a mess. The only way to detect which game version we are running is to count the parsed values here.
int params [ 34 ] ; // 34 is the maximum for RRRA.
int pcount = 0 ;
for ( int i = 0 ; i < 34 ; i + + )
{
transnum ( LABEL_DEFINE ) ;
params [ pcount + + ] = popscriptvalue ( ) ;
if ( keyword ( ) ! = - 1 ) break ;
}
int pget = 0 ;
if ( ! isRR ( ) )
{
if ( pcount = = 30 ) g_gameType | = GAMEFLAG_PLUTOPAK ;
else if ( pcount = = 31 ) g_gameType | = GAMEFLAG_PLUTOPAK | GAMEFLAG_WORLDTOUR ;
else if ( pcount ! = 26 ) I_FatalError ( " Invalid CONs. Cannot detect version. gamestartup has %d entries " , pcount ) ;
}
2020-05-15 09:30:33 +00:00
popscriptvalue ( ) ;
2020-07-19 19:04:22 +00:00
auto parseone = [ & ] ( ) { return params [ pget + + ] ; } ;
2020-05-13 10:18:36 +00:00
ud . const_visibility = parseone ( ) ;
2020-05-12 13:39:35 +00:00
impact_damage = parseone ( ) ;
max_player_health = parseone ( ) ;
max_armour_amount = parseone ( ) ;
respawnactortime = parseone ( ) ;
respawnitemtime = parseone ( ) ;
dukefriction = parseone ( ) ;
2020-07-19 19:04:22 +00:00
if ( isPlutoPak ( ) | | isRR ( ) ) gc = parseone ( ) ;
2020-05-13 10:18:36 +00:00
rpgblastradius = parseone ( ) ;
pipebombblastradius = parseone ( ) ;
2020-05-12 13:39:35 +00:00
shrinkerblastradius = parseone ( ) ;
tripbombblastradius = parseone ( ) ;
morterblastradius = parseone ( ) ;
bouncemineblastradius = parseone ( ) ;
seenineblastradius = parseone ( ) ;
2020-05-13 10:18:36 +00:00
2020-05-12 13:39:35 +00:00
max_ammo_amount [ 1 ] = parseone ( ) ;
max_ammo_amount [ 2 ] = parseone ( ) ;
max_ammo_amount [ 3 ] = parseone ( ) ;
max_ammo_amount [ 4 ] = parseone ( ) ;
max_ammo_amount [ 5 ] = parseone ( ) ;
max_ammo_amount [ 6 ] = parseone ( ) ;
max_ammo_amount [ 7 ] = parseone ( ) ;
max_ammo_amount [ 8 ] = parseone ( ) ;
max_ammo_amount [ 9 ] = parseone ( ) ;
2020-07-19 19:04:22 +00:00
if ( isPlutoPak ( ) | | isRR ( ) ) max_ammo_amount [ 11 ] = parseone ( ) ;
2020-05-15 20:59:13 +00:00
if ( isRR ( ) | | isWorldTour ( ) ) max_ammo_amount [ 12 ] = parseone ( ) ;
2020-05-12 13:39:35 +00:00
camerashitable = parseone ( ) ;
numfreezebounces = parseone ( ) ;
freezerhurtowner = parseone ( ) ;
2020-07-19 19:04:22 +00:00
if ( PLUTOPAK | | isRR ( ) )
{
spriteqamount = clamp ( parseone ( ) , 0 , 1024 ) ;
lasermode = parseone ( ) ;
}
2020-05-12 13:39:35 +00:00
if ( isRRRA ( ) )
{
max_ammo_amount [ 13 ] = parseone ( ) ;
max_ammo_amount [ 14 ] = parseone ( ) ;
max_ammo_amount [ 16 ] = parseone ( ) ;
}
2020-07-19 19:04:22 +00:00
return 0 ;
2020-05-12 13:39:35 +00:00
}
}
return 0 ;
}
2020-05-13 14:16:27 +00:00
//---------------------------------------------------------------------------
//
// split in two to allow multiple CON files.
//
//---------------------------------------------------------------------------
2020-07-19 17:13:27 +00:00
void ConCompiler : : compilecon ( const char * filenam )
2020-05-13 14:16:27 +00:00
{
2020-07-19 17:13:27 +00:00
currentsourcefile = fileSystem . FindFile ( filenam ) ;
if ( currentsourcefile < 0 )
2020-05-13 14:16:27 +00:00
{
I_FatalError ( " %s: Missing con file(s). " , filenam ) ;
}
Printf ( " Compiling: '%s'. \n " , filenam ) ;
2020-07-19 17:13:27 +00:00
auto data = fileSystem . GetFileData ( currentsourcefile , 1 ) ;
2020-05-13 14:16:27 +00:00
textptr = ( char * ) data . Data ( ) ;
line_number = 1 ;
errorcount = warningcount = 0 ;
while ( parsecommand ( ) = = 0 ) ;
if ( ( errorcount ) > 64 )
Printf ( TEXTCOLOR_RED " * ERROR! Too many errors. " ) ;
else if ( warningcount | | errorcount )
Printf ( TEXTCOLOR_ORANGE " Found %d warning(s), %d error(s). \n " , warningcount , errorcount ) ;
if ( errorcount > 0 ) I_FatalError ( " Failed to compile %s " , filenam ) ;
}
2020-07-15 10:34:42 +00:00
//==========================================================================
//
// Fallback in case nothing got defined.
//
//==========================================================================
static const char * ConFile ( void )
{
if ( userConfig . DefaultCon . IsNotEmpty ( ) ) return userConfig . DefaultCon . GetChars ( ) ;
// WW2GI anf NAM special con names got introduced by EDuke32.
// Do we really need these?
if ( g_gameType & GAMEFLAG_WW2GI )
{
if ( fileSystem . FindFile ( " ww2gi.con " ) > = 0 ) return " ww2gi.con " ;
}
if ( g_gameType & GAMEFLAG_NAM )
{
if ( fileSystem . FindFile ( " nam.con " ) > = 0 ) return " nam.con " ;
if ( fileSystem . FindFile ( " napalm.con " ) > = 0 ) return " napalm.con " ;
}
if ( g_gameType & GAMEFLAG_NAPALM )
{
if ( fileSystem . FindFile ( " napalm.con " ) > = 0 ) return " napalm.con " ;
if ( fileSystem . FindFile ( " nam.con " ) > = 0 ) return " nam.con " ;
}
// This got introduced by EDuke 2.0.
if ( g_gameType & GAMEFLAG_DUKE )
{
if ( fileSystem . FindFile ( " eduke.con " ) > = 0 ) return " eduke.con " ;
}
// the other games only use game.con.
return " game.con " ;
}
2020-07-19 17:13:27 +00:00
//---------------------------------------------------------------------------
//
// process the music definitions after all map records are set up.
//
//---------------------------------------------------------------------------
void ConCompiler : : setmusic ( )
{
for ( auto & tm : tempMusic )
{
auto map = FindMapByLevelNum ( tm . levnum ) ;
if ( map ) map - > music = tm . music ;
}
tempMusic . Clear ( ) ;
}
2020-05-13 14:16:27 +00:00
//---------------------------------------------------------------------------
//
// why was this called loadefs?
//
//---------------------------------------------------------------------------
2020-07-15 10:34:42 +00:00
void loadcons ( )
2020-05-13 11:30:14 +00:00
{
2020-05-15 08:44:57 +00:00
for ( int i = 0 ; i < MAXTILES ; i + + )
{
memset ( & actorinfo [ i ] , 0 , sizeof ( actorinfo ) ) ;
}
2020-05-15 09:30:33 +00:00
ScriptCode . Clear ( ) ;
2020-07-15 10:34:42 +00:00
labels . Clear ( ) ;
2020-05-13 14:16:27 +00:00
2020-05-13 17:11:08 +00:00
SortCommands ( ) ;
2020-05-13 14:16:27 +00:00
ClearGameEvents ( ) ;
ClearGameVars ( ) ;
AddSystemVars ( ) ;
auto before = I_nsTime ( ) ;
2020-05-15 09:30:33 +00:00
ScriptCode . Push ( 0 ) ;
2020-07-19 17:13:27 +00:00
ConCompiler comp ;
comp . compilecon ( ConFile ( ) ) ; //Tokenize
2020-05-13 14:16:27 +00:00
if ( userConfig . AddCons ) for ( FString & m : * userConfig . AddCons . get ( ) )
2020-05-13 11:30:14 +00:00
{
2020-07-19 17:13:27 +00:00
comp . compilecon ( m ) ;
2020-05-13 11:30:14 +00:00
}
2020-07-15 10:34:42 +00:00
ScriptCode . ShrinkToFit ( ) ;
labels . ShrinkToFit ( ) ;
2020-05-13 14:16:27 +00:00
userConfig . AddCons . reset ( ) ;
setscriptvalue ( 0 , scriptpos ( ) ) ;
2020-05-13 11:30:14 +00:00
2020-07-19 17:13:27 +00:00
if ( comp . getErrorCount ( ) )
2020-05-13 14:16:27 +00:00
{
2020-07-15 10:34:42 +00:00
I_FatalError ( " Failed to compile CONs. " ) ;
2020-05-13 14:16:27 +00:00
}
else
2020-05-13 11:30:14 +00:00
{
2020-05-13 14:16:27 +00:00
auto after = I_nsTime ( ) ;
2020-07-15 10:34:42 +00:00
Printf ( " Compilation time:%.2f ms, Code Size:%u bytes. %u labels. %d/%d Variables. \n " , ( after - before ) / 1000000. ,
2020-05-15 09:30:33 +00:00
( ScriptCode . Size ( ) < < 2 ) - 4 ,
2020-07-15 10:34:42 +00:00
labels . Size ( ) ,
2020-05-13 14:16:27 +00:00
0 , //iGameVarCount,
MAXGAMEVARS
) ;
2020-05-13 11:30:14 +00:00
}
2020-05-13 17:11:08 +00:00
// These can only be retrieved AFTER loading the scripts.
InitGameVarPointers ( ) ;
ResetSystemDefaults ( ) ;
2020-07-07 19:38:20 +00:00
if ( isRRRA ( ) )
{
// RRRA goes directly to the second episode after E1L7 to continue the game.
int num = fileSystem . CheckNumForName ( " e1l7.map " ) ;
int file = fileSystem . GetFileContainer ( num ) ;
if ( file < = fileSystem . GetMaxIwadNum ( ) )
{
auto maprec = FindMapByName ( " e1l7 " ) ;
if ( maprec ) maprec - > nextLevel = levelnum ( 1 , 0 ) ;
}
}
else if ( isRR ( ) )
{
// RR does not define its final level and crudely hacked it into the progression. This puts it into the E2L8 slot so that the game can naturally progress there.
auto maprec1 = FindMapByLevelNum ( levelnum ( 1 , 6 ) ) ;
auto maprec2 = FindMapByLevelNum ( levelnum ( 1 , 7 ) ) ;
auto maprec3 = FindMapByName ( " endgame " ) ;
int num3 = fileSystem . CheckNumForName ( " endgame.map " ) ;
if ( maprec1 & & ! maprec2 & & ! maprec3 & & num3 > = 0 )
{
auto maprec = AllocateMap ( ) ;
maprec - > designerTime = 0 ;
maprec - > parTime = 0 ;
maprec - > SetFileName ( " endgame.map " ) ;
maprec - > SetName ( " $TXT_CLOSEENCOUNTERS " ) ;
maprec - > levelNumber = levelnum ( 1 , 7 ) ;
}
}
2020-07-19 17:13:27 +00:00
comp . setmusic ( ) ;
2020-05-13 11:30:14 +00:00
}
2020-05-12 13:39:35 +00:00
2020-05-12 11:43:24 +00:00
END_DUKE_NS