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 .
*/
//-------------------------------------------------------------------------
# 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-05-12 11:43:24 +00:00
BEGIN_DUKE_NS
// parser state: todo: turn into a class
char * textptr ;
2020-05-12 13:39:35 +00:00
char * label ;
int line_number ;
int labelcnt ;
int errorcount , warningcount ; // was named 'error' and 'warning' which is too generic for public variables and may clash with other code.
int g_currentSourceFile ;
2020-05-15 08:44:57 +00:00
uint32_t parsing_actor , parsing_event ;
2020-05-12 14:33:32 +00:00
int parsing_state ;
2020-05-12 16:44:58 +00:00
int num_squigilly_brackets ;
2020-05-12 20:52:49 +00:00
int checking_ifelse ;
2020-05-12 14:33:32 +00:00
2020-05-12 13:39:35 +00:00
//G_EXTERN char tempbuf[MAXSECTORS << 1], buf[1024]; todo - move to compile state. tempbuf gets used nearly everywhere as scratchpad memory.
extern char tempbuf [ ] ;
extern int * labelcode ;
2020-05-15 09:30:33 +00:00
2020-05-15 09:36:46 +00:00
TArray < int > ScriptCode ;
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
void ReportError ( int iError )
{
const char * fn = fileSystem . GetFileFullName ( g_currentSourceFile ) ;
switch ( iError )
{
case ERROR_ISAKEYWORD :
Printf ( TEXTCOLOR_RED " * ERROR!(%s, line %d) Symbol '%s' is a key word. \n " ,
fn , line_number , label + ( labelcnt < < 6 ) ) ;
break ;
case ERROR_PARMUNDEFINED :
Printf ( TEXTCOLOR_RED " * ERROR!(%s, line %d) Parameter '%s' is undefined. \n " ,
fn , line_number , tempbuf ) ;
break ;
case WARNING_DUPLICATEDEFINITION :
Printf ( TEXTCOLOR_YELLOW " * WARNING.(%s, line %d) Duplicate definition '%s' ignored. \n " ,
fn , line_number , label + ( labelcnt < < 6 ) ) ;
break ;
case ERROR_COULDNOTFIND :
Printf ( TEXTCOLOR_RED " * ERROR!(%s, line %d) Could not find '%s'. \n " ,
fn , line_number , label + ( labelcnt < < 6 ) ) ;
break ;
case ERROR_VARREADONLY :
Printf ( TEXTCOLOR_RED " * ERROR!(%s, line %d) Variable '%s' is read-only. \n " ,
fn , line_number , label + ( labelcnt < < 6 ) ) ;
break ;
case ERROR_NOTAGAMEDEF :
Printf ( TEXTCOLOR_RED " * ERROR!(%s, line %d) Symbol '%s' is not a Game Definition. \n " ,
fn , line_number , label + ( labelcnt < < 6 ) ) ;
break ;
case ERROR_NOTAGAMEVAR :
Printf ( TEXTCOLOR_RED " * ERROR! (%s, line %d) Symbol '%s' is not a defined Game Variable. \n " ,
fn , line_number , label + ( labelcnt < < 6 ) ) ;
break ;
case ERROR_OPENBRACKET :
Printf ( TEXTCOLOR_RED " * ERROR! (%s, line %d) Found more '{' than '}' before '%s'. \n " ,
fn , line_number , tempbuf ) ;
break ;
case ERROR_CLOSEBRACKET :
Printf ( TEXTCOLOR_RED " * ERROR!(%s, line %d) Found more '}' than '{' before '%s'. \n " ,
fn , line_number , tempbuf ) ;
break ;
case ERROR_NOENDSWITCH :
Printf ( TEXTCOLOR_RED " * ERROR!%s(%s, line %d) Did not find endswitch before '%s'. \n " ,
fn , line_number , tempbuf ) ;
break ;
}
}
2020-05-12 11:43:24 +00:00
//---------------------------------------------------------------------------
//
// binary search for keyword
//
//---------------------------------------------------------------------------
int getkeyword ( const char * text )
{
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-05-12 14:33:32 +00:00
int findlabel ( const char * text )
{
for ( int j = 0 ; j < labelcnt ; j + + )
{
if ( strcmp ( label + ( j < < 6 ) , text ) = = 0 )
{
2020-05-12 21:55:33 +00:00
return j ;
2020-05-12 14:33:32 +00:00
}
}
return - 1 ;
}
2020-05-12 13:39:35 +00:00
2020-05-12 21:19:01 +00:00
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
bool ispecial ( char c )
{
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 ;
}
bool isaltok ( char c )
{
// 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
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
void skiptoendofline ( )
{
while ( * textptr ! = 0x0a & & * textptr ! = 0x0d & & * textptr ! = 0 )
textptr + + ;
}
void skipwhitespace ( )
{
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 + + ;
}
}
void skipblockcomment ( )
{
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
}
bool skipcomments ( )
{
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-05-12 19:22:08 +00:00
int keyword ( void )
{
int i ;
const char * temptextptr ;
skipcomments ( ) ;
temptextptr = textptr ;
while ( isaltok ( * temptextptr ) = = 0 )
{
temptextptr + + ;
if ( * temptextptr = = 0 )
return 0 ;
}
i = 0 ;
while ( isaltok ( * temptextptr ) )
{
tempbuf [ i ] = * ( temptextptr + + ) ;
i + + ;
}
tempbuf [ i ] = 0 ;
return getkeyword ( tempbuf ) ;
}
2020-05-12 13:39:35 +00:00
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
void getlabel ( void )
{
long i ;
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 )
label [ ( labelcnt < < 6 ) + i + + ] = * ( textptr + + ) ;
label [ ( labelcnt < < 6 ) + i ] = 0 ;
}
2020-05-12 14:55:25 +00:00
//---------------------------------------------------------------------------
//
// script buffer access wrappers. These are here to reduce the affected code
// when the time comes to refactor the buffer into a dynamic array.
//
//---------------------------------------------------------------------------
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-05-12 20:52:49 +00:00
int scriptpos ( )
{
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-05-12 20:52:49 +00:00
2020-05-12 19:22:08 +00:00
void appendlabeladdress ( int offset = 0 )
{
2020-05-15 09:30:33 +00:00
labelcode [ labelcnt + + ] = ScriptCode . Size ( ) + offset ;
2020-05-12 19:22:08 +00:00
labelcnt + + ;
}
void appendlabelvalue ( int value )
2020-05-12 15:16:15 +00:00
{
2020-05-12 19:22:08 +00:00
labelcode [ labelcnt + + ] = value ;
2020-05-12 15:16:15 +00:00
labelcnt + + ;
}
2020-05-12 14:55:25 +00:00
2020-05-12 13:39:35 +00:00
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
int transword ( void ) //Returns its code #
{
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 )
{
tempbuf [ l ] = textptr [ l ] ;
l + + ;
}
}
tempbuf [ l ] = 0 ;
i = getkeyword ( tempbuf ) ;
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 ;
const char * fn = fileSystem . GetFileFullName ( g_currentSourceFile ) ;
if ( tempbuf [ 0 ] = = ' { ' & & tempbuf [ 1 ] ! = 0 )
Printf ( TEXTCOLOR_RED " * ERROR!(%s, line %d) Expecting a SPACE or CR between '{' and '%s'. \n " , fn , line_number , tempbuf + 1 ) ;
else if ( tempbuf [ 0 ] = = ' } ' & & tempbuf [ 1 ] ! = 0 )
Printf ( TEXTCOLOR_RED " * ERROR!(%s, line %d) Expecting a SPACE or CR between '}' and '%s'. \n " , fn , line_number , tempbuf + 1 ) ;
else if ( tempbuf [ 0 ] = = ' / ' & & tempbuf [ 1 ] = = ' / ' & & tempbuf [ 2 ] ! = 0 )
Printf ( TEXTCOLOR_RED " * ERROR!(%s, line %d) Expecting a SPACE between '//' and '%s'. \n " , fn , line_number , tempbuf + 2 ) ;
else if ( tempbuf [ 0 ] = = ' / ' & & tempbuf [ 1 ] = = ' * ' & & tempbuf [ 2 ] ! = 0 )
Printf ( TEXTCOLOR_RED " * ERROR!(%s, line %d) Expecting a SPACE between '/*' and '%s'. \n " , fn , line_number , tempbuf + 2 ) ;
else if ( tempbuf [ 0 ] = = ' * ' & & tempbuf [ 1 ] = = ' / ' & & tempbuf [ 2 ] ! = 0 )
Printf ( TEXTCOLOR_RED " * ERROR!(%s, line %d) Expecting a SPACE between '*/' and '%s'. \n " , fn , line_number , tempbuf + 2 ) ;
else
Printf ( TEXTCOLOR_RED " * ERROR!(%s, line %d) Keyword expected, got '%s'. \n " , fn , line_number , tempbuf + 2 ) ;
errorcount + + ;
return - 1 ;
}
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
2020-05-13 11:03:52 +00:00
int transnum ( void )
2020-05-12 13:39:35 +00:00
{
int i , l ;
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 )
{
tempbuf [ l ] = textptr [ l ] ;
l + + ;
}
}
tempbuf [ l ] = 0 ;
if ( getkeyword ( tempbuf ) > = 0 )
{
errorcount + + ;
ReportError ( ERROR_ISAKEYWORD ) ;
textptr + = l ;
}
for ( i = 0 ; i < labelcnt ; i + + )
{
if ( strcmp ( tempbuf , label + ( i < < 6 ) ) = = 0 )
{
2020-05-12 14:55:25 +00:00
appendscriptvalue ( labelcode [ i ] ) ;
2020-05-12 13:39:35 +00:00
textptr + = l ;
2020-05-13 11:03:52 +00:00
return labelcode [ i ] ;
2020-05-12 13:39:35 +00:00
}
}
if ( isdigit ( * textptr ) = = 0 & & * textptr ! = ' - ' )
{
ReportError ( ERROR_PARMUNDEFINED ) ;
errorcount + + ;
textptr + = l ;
# ifdef FOR_LATER
if ( GetDefID ( tempbuf ) > = 0 )
{
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 ;
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 ? 16 : 10 ) ;
else value = strtoull ( textptr , & outp , ishex ? 16 : 10 ) ;
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-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-05-12 14:55:25 +00:00
void checkforkeyword ( )
{
if ( getkeyword ( label + ( labelcnt < < 6 ) ) > = 0 )
{
errorcount + + ;
ReportError ( ERROR_ISAKEYWORD ) ;
}
}
2020-05-12 13:39:35 +00:00
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
2020-05-12 14:55:25 +00:00
2020-05-12 13:39:35 +00:00
static TArray < char > parsebuffer ; // global so that the storage is persistent across calls.
2020-05-13 14:16:27 +00:00
int parsecommand ( )
2020-05-12 13:39:35 +00:00
{
const char * fn = fileSystem . GetFileFullName ( g_currentSourceFile ) ;
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-05-12 19:22:08 +00:00
appendlabeladdress ( ) ;
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-05-12 16:44:58 +00:00
lnum = findlabel ( label + ( labelcnt < < 6 ) ) ;
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
{
Printf ( TEXTCOLOR_RED " * ERROR!(%s, line %d) State '%s' not found. \n " , fn , line_number , label + ( labelcnt < < 6 ) ) ;
errorcount + + ;
}
2020-05-12 15:16:15 +00:00
appendscriptvalue ( labelcode [ lnum ] ) ;
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 :
// 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
if ( getkeyword ( label + ( labelcnt < < 6 ) ) > = 0 )
{
errorcount + + ;
ReportError ( ERROR_ISAKEYWORD ) ;
return 0 ;
}
transnum ( ) ; // get initial value
2020-05-13 11:03:52 +00:00
j = popscriptvalue ( ) ;
2020-05-12 13:39:35 +00:00
transnum ( ) ; // get flags
2020-05-13 11:03:52 +00:00
lnum = popscriptvalue ( ) ;
AddGameVar ( label + ( labelcnt < < 6 ) , j , lnum & ( ~ ( GAMEVAR_FLAG_DEFAULT | GAMEVAR_FLAG_SECRET ) ) ) ;
2020-05-12 13:39:35 +00:00
return 0 ;
2020-05-13 11:03:52 +00:00
2020-05-12 13:39:35 +00:00
case concmd_define :
getlabel ( ) ;
2020-05-12 19:22:08 +00:00
checkforkeyword ( ) ;
lnum = findlabel ( label + ( labelcnt < < 6 ) ) ;
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
}
transnum ( ) ;
2020-05-12 19:22:08 +00:00
i = popscriptvalue ( ) ;
if ( lnum < 0 )
2020-05-12 13:39:35 +00:00
{
2020-05-12 19:22:08 +00:00
appendlabelvalue ( 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 )
transnum ( ) ;
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 )
{
transnum ( ) ;
j = 0 ;
while ( keyword ( ) = = - 1 )
{
transnum ( ) ;
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
for ( i = 0 ; i < labelcnt ; i + + )
if ( strcmp ( label + ( labelcnt < < 6 ) , label + ( i < < 6 ) ) = = 0 )
{
warningcount + + ;
Printf ( TEXTCOLOR_RED " * WARNING.(%s, line %d) Duplicate move '%s' ignored. \n " , fn , line_number , label + ( labelcnt < < 6 ) ) ;
break ;
}
if ( i = = labelcnt )
2020-05-12 19:22:08 +00:00
appendlabeladdress ( ) ;
2020-05-12 13:39:35 +00:00
for ( j = 0 ; j < 2 ; j + + )
{
if ( keyword ( ) > = 0 ) break ;
transnum ( ) ;
}
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-05-12 13:39:35 +00:00
transnum ( ) ; // Volume Number (0/4)
2020-05-15 09:30:33 +00:00
k = popscriptvalue ( ) - 1 ;
2020-05-12 13:39:35 +00:00
if ( k = = - 1 ) k = MAXVOLUMES ;
if ( k > = 0 ) // if it's background music
{
i = 0 ;
// get the file name...
while ( keyword ( ) = = - 1 )
{
while ( isaltok ( * textptr ) = = 0 )
{
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 ) ;
mapList [ ( MAXLEVELS * k ) + i ] . music = parsebuffer . Data ( ) ;
textptr + = j ;
if ( i > MAXLEVELS ) break ;
i + + ;
}
}
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
temp_current_file = g_currentSourceFile ;
2020-05-13 22:04:14 +00:00
g_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 ;
g_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 )
transnum ( ) ;
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-05-12 20:52:49 +00:00
lnum = findlabel ( label + ( labelcnt < < 6 ) ) ;
if ( lnum > = 0 )
{
warningcount + + ;
Printf ( TEXTCOLOR_RED " * WARNING.(%s, line %d) Duplicate ai '%s' ignored. \n " , fn , line_number , label + ( labelcnt < < 6 ) ) ;
}
else appendlabeladdress ( ) ;
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 )
{
transnum ( ) ;
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 ;
}
else transnum ( ) ;
}
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 )
transnum ( ) ;
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-05-12 20:52:49 +00:00
lnum = findlabel ( label + ( labelcnt < < 6 ) ) ;
if ( lnum > = 0 )
2020-05-12 13:39:35 +00:00
{
2020-05-12 20:52:49 +00:00
warningcount + + ;
Printf ( TEXTCOLOR_RED " * WARNING.(%s, line %d) Duplicate event '%s' ignored. \n " , fn , line_number , label + ( labelcnt < < 6 ) ) ;
2020-05-12 13:39:35 +00:00
}
2020-05-12 20:52:49 +00:00
else appendlabeladdress ( ) ;
2020-05-12 13:39:35 +00:00
for ( j = 0 ; j < 5 ; j + + )
{
if ( keyword ( ) > = 0 ) break ;
transnum ( ) ;
}
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 )
{
transnum ( ) ;
j = popscriptvalue ( ) ;
}
2020-05-12 13:39:35 +00:00
transnum ( ) ;
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 )
{
transnum ( ) ;
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 ;
}
transnum ( ) ;
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
transnum ( ) ;
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 :
transnum ( ) ;
#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 :
transnum ( ) ;
return 0 ;
case concmd_addammo :
case concmd_addweapon :
case concmd_sizeto :
case concmd_sizeat :
case concmd_debris :
case concmd_addinventory :
case concmd_guts :
transnum ( ) ;
transnum ( ) ;
2020-05-12 21:55:33 +00:00
return 0 ;
2020-05-12 13:39:35 +00:00
case concmd_hitradius :
transnum ( ) ;
transnum ( ) ;
transnum ( ) ;
transnum ( ) ;
transnum ( ) ;
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
i = GetDefID ( label + ( labelcnt < < 6 ) ) ;
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
transnum ( ) ; // the number to check against...
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
i = GetDefID ( label + ( labelcnt < < 6 ) ) ;
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
i = GetDefID ( label + ( labelcnt < < 6 ) ) ;
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
i = GetDefID ( label + ( labelcnt < < 6 ) ) ;
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
i = GetDefID ( label + ( labelcnt < < 6 ) ) ;
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-05-12 13:39:35 +00:00
i = GetDefID ( label + ( labelcnt < < 6 ) ) ;
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
transnum ( ) ; // 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-05-13 11:03:52 +00:00
appendscriptvalue ( g_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
i = GetDefID ( label + ( labelcnt < < 6 ) ) ;
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-05-12 14:55:25 +00:00
appendscriptvalue ( g_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
{
transnum ( ) ;
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 :
transnum ( ) ;
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 :
transnum ( ) ;
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-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-05-13 07:17:59 +00:00
if ( keyword ( ) = = 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
checking_ifelse + + ;
2020-05-12 13:39:35 +00:00
return 0 ;
2020-05-13 07:17:59 +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-05-12 13:39:35 +00:00
transnum ( ) ;
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-05-12 13:39:35 +00:00
transnum ( ) ;
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-05-12 14:55:25 +00:00
popscriptvalue ( ) ;
2020-05-12 13:39:35 +00:00
transnum ( ) ;
2020-05-15 09:30:33 +00:00
j = popscriptvalue ( ) ;
2020-05-12 13:39:35 +00:00
transnum ( ) ;
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-05-13 06:40:26 +00:00
mapList [ j * MAXLEVELS + k ] . SetFileName ( parsebuffer . Data ( ) ) ;
2020-05-12 13:39:35 +00:00
while ( * textptr = = ' ' ) textptr + + ;
mapList [ j * MAXLEVELS + k ] . parTime =
( ( ( * ( textptr + 0 ) - ' 0 ' ) * 10 + ( * ( textptr + 1 ) - ' 0 ' ) ) * 26 * 60 ) +
( ( ( * ( textptr + 3 ) - ' 0 ' ) * 10 + ( * ( textptr + 4 ) - ' 0 ' ) ) * 26 ) ;
textptr + = 5 ;
while ( * textptr = = ' ' ) textptr + + ;
mapList [ j * MAXLEVELS + k ] . designerTime =
( ( ( * ( textptr + 0 ) - ' 0 ' ) * 10 + ( * ( textptr + 1 ) - ' 0 ' ) ) * 26 * 60 ) +
( ( ( * ( textptr + 3 ) - ' 0 ' ) * 10 + ( * ( textptr + 4 ) - ' 0 ' ) ) * 26 ) ;
2020-07-01 18:31:29 +00:00
mapList [ j * MAXLEVELS + k ] . levelNumber = k + j * 100 ;
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 ) ;
mapList [ j * MAXLEVELS + k ] . name = parsebuffer . Data ( ) ;
return 0 ;
case concmd_definequote :
2020-05-12 14:55:25 +00:00
popscriptvalue ( ) ;
2020-05-12 13:39:35 +00:00
transnum ( ) ;
2020-05-15 09:30:33 +00:00
k = popscriptvalue ( ) ;
2020-05-12 13:39:35 +00:00
if ( k > = MAXQUOTES )
{
Printf ( TEXTCOLOR_RED " * ERROR!(%s, line %d) Quote number exceeds limit of %d. \n " , line_number , MAXQUOTES ) ;
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-05-12 13:39:35 +00:00
transnum ( ) ;
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 ) ;
transnum ( ) ;
2020-05-15 09:30:33 +00:00
int ps = popscriptvalue ( ) ;
2020-05-12 13:39:35 +00:00
transnum ( ) ;
2020-05-15 09:30:33 +00:00
int pe = popscriptvalue ( ) ;
2020-05-12 13:39:35 +00:00
transnum ( ) ;
2020-05-15 09:30:33 +00:00
int pr = popscriptvalue ( ) ;
2020-05-12 13:39:35 +00:00
transnum ( ) ;
2020-05-15 09:30:33 +00:00
int m = popscriptvalue ( ) ;
2020-05-12 13:39:35 +00:00
transnum ( ) ;
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 )
{
Printf ( TEXTCOLOR_RED " * ERROR!(%s, line %d) Found 'endevent' without defining 'onevent'. \n " , line_number ) ;
errorcount + + ;
}
// else
{
if ( num_squigilly_brackets > 0 )
{
Printf ( TEXTCOLOR_RED " * ERROR!(%s, line %d) Found more '{' than '}' before 'endevent'. \n " , line_number ) ;
errorcount + + ;
}
parsing_event = 0 ;
parsing_actor = 0 ;
}
return 0 ;
case concmd_enda :
if ( parsing_actor = = 0 )
{
Printf ( TEXTCOLOR_RED " * ERROR!(%s, line %d) Found 'enda' without defining 'actor'. \n " , line_number ) ;
errorcount + + ;
}
// else
{
if ( num_squigilly_brackets > 0 )
{
Printf ( TEXTCOLOR_RED " * ERROR!(%s, line %d) Found more '{' than '}' before 'enda'. \n " , line_number ) ;
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-05-13 06:50:13 +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-05-15 09:30:33 +00:00
popscriptvalue ( ) ;
2020-05-13 10:18:36 +00:00
auto parseone = [ ] ( ) { transnum ( ) ; return popscriptvalue ( ) ; } ;
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 ( ) ;
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-05-13 10:18:36 +00:00
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 ( ) ;
spriteqamount = clamp ( parseone ( ) , 0 , 1024 ) ;
lasermode = parseone ( ) ;
if ( isRRRA ( ) )
{
max_ammo_amount [ 13 ] = parseone ( ) ;
max_ammo_amount [ 14 ] = parseone ( ) ;
max_ammo_amount [ 16 ] = parseone ( ) ;
}
}
return 0 ;
}
return 0 ;
}
2020-05-13 14:16:27 +00:00
//---------------------------------------------------------------------------
//
// split in two to allow multiple CON files.
//
//---------------------------------------------------------------------------
void compilecon ( const char * filenam )
{
g_currentSourceFile = fileSystem . FindFile ( filenam ) ;
if ( g_currentSourceFile < 0 )
{
I_FatalError ( " %s: Missing con file(s). " , filenam ) ;
}
Printf ( " Compiling: '%s'. \n " , filenam ) ;
auto data = fileSystem . GetFileData ( g_currentSourceFile , 1 ) ;
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 ) ;
}
//---------------------------------------------------------------------------
//
// why was this called loadefs?
//
//---------------------------------------------------------------------------
void loadcons ( const char * filenam )
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-05-15 08:44:57 +00:00
2020-05-13 14:16:27 +00:00
labelcnt = 0 ;
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-05-13 14:16:27 +00:00
compilecon ( filenam ) ; //Tokenize
if ( userConfig . AddCons ) for ( FString & m : * userConfig . AddCons . get ( ) )
2020-05-13 11:30:14 +00:00
{
2020-05-13 14:16:27 +00:00
compilecon ( filenam ) ;
2020-05-13 11:30:14 +00:00
}
2020-05-13 14:16:27 +00:00
userConfig . AddCons . reset ( ) ;
setscriptvalue ( 0 , scriptpos ( ) ) ;
2020-05-13 11:30:14 +00:00
2020-05-13 14:16:27 +00:00
if ( errorcount )
{
I_FatalError ( " \n Error in %s. " , filenam ) ;
}
else
2020-05-13 11:30:14 +00:00
{
2020-05-13 14:16:27 +00:00
auto after = I_nsTime ( ) ;
Printf ( " Compilation time:%.2f ms, Code Size:%d bytes. %d labels. %d/%d Variables. \n " , ( after - before ) / 1000000. ,
2020-05-15 09:30:33 +00:00
( ScriptCode . Size ( ) < < 2 ) - 4 ,
2020-05-13 14:16:27 +00:00
labelcnt ,
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-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