2008-11-09 22:29:28 +00:00
# include "quakedef.h"
# if !defined(CLIENTONLY) || defined(CSQC_DAT) || defined(MENU_DAT)
# include "pr_common.h"
2008-11-14 20:36:46 +00:00
# include <ctype.h>
2008-11-09 22:29:28 +00:00
//fixme
# define Z_QC_TAG 2
# define PRSTR 0xa6ffb3d7
static char * cvargroup_progs = " Progs variables " ;
cvar_t pr_brokenfloatconvert = SCVAR ( " pr_brokenfloatconvert " , " 0 " ) ;
cvar_t pr_tempstringcount = SCVAR ( " pr_tempstringcount " , " " ) ; //"16");
cvar_t pr_tempstringsize = SCVAR ( " pr_tempstringsize " , " 4096 " ) ;
2008-11-18 03:10:48 +00:00
static char * strtoupper ( char * s )
2008-11-14 20:36:46 +00:00
{
char * p ;
p = s ;
while ( * p )
{
* p = toupper ( * p ) ;
p + + ;
}
return s ;
}
2008-11-18 03:10:48 +00:00
static char * strtolower ( char * s )
2008-11-14 20:36:46 +00:00
{
char * p ;
p = s ;
while ( * p )
{
* p = tolower ( * p ) ;
p + + ;
}
return s ;
}
2008-11-09 22:29:28 +00:00
void PF_Common_RegisterCvars ( void )
{
static qboolean alreadydone ;
if ( alreadydone )
return ;
alreadydone = true ;
Cvar_Register ( & pr_brokenfloatconvert , cvargroup_progs ) ;
Cvar_Register ( & pr_tempstringcount , cvargroup_progs ) ;
Cvar_Register ( & pr_tempstringsize , cvargroup_progs ) ;
}
char * Translate ( char * message ) ;
char * PF_VarString ( progfuncs_t * prinst , int first , struct globalvars_s * pr_globals )
{
# define VARSTRINGLEN 16384+8
int i ;
static char buffer [ 2 ] [ VARSTRINGLEN ] ;
static int bufnum ;
char * s , * out ;
out = buffer [ ( bufnum + + ) & 1 ] ;
out [ 0 ] = 0 ;
for ( i = first ; i < * prinst - > callargc ; i + + )
{
// if (G_INT(OFS_PARM0+i*3) < 0 || G_INT(OFS_PARM0+i*3) >= 1024*1024);
// break;
s = PR_GetStringOfs ( prinst , OFS_PARM0 + i * 3 ) ;
if ( s )
{
s = Translate ( s ) ;
if ( strlen ( out ) + strlen ( s ) + 1 > = VARSTRINGLEN )
Con_DPrintf ( " VarString (builtin call ending with strings) exceeded maximum string length of %i chars " , VARSTRINGLEN ) ;
Q_strncatz ( out , s , VARSTRINGLEN ) ;
}
}
return out ;
}
# define MAX_TEMPSTRS ((int)pr_tempstringcount.value)
# define MAXTEMPBUFFERLEN ((int)pr_tempstringsize.value)
string_t PR_TempString ( progfuncs_t * prinst , char * str )
{
char * tmp ;
if ( ! prinst - > tempstringbase )
return prinst - > TempString ( prinst , str ) ;
if ( ! str | | ! * str )
return 0 ;
if ( prinst - > tempstringnum = = MAX_TEMPSTRS )
prinst - > tempstringnum = 0 ;
tmp = prinst - > tempstringbase + ( prinst - > tempstringnum + + ) * MAXTEMPBUFFERLEN ;
Q_strncpyz ( tmp , str , MAXTEMPBUFFERLEN ) ;
return tmp - prinst - > stringtable ;
}
void PF_InitTempStrings ( progfuncs_t * prinst )
{
if ( pr_tempstringcount . value > 0 & & pr_tempstringcount . value < 2 )
pr_tempstringcount . value = 2 ;
if ( pr_tempstringsize . value < 256 )
pr_tempstringsize . value = 256 ;
pr_tempstringcount . flags | = CVAR_NOSET ;
pr_tempstringsize . flags | = CVAR_NOSET ;
if ( pr_tempstringcount . value > = 2 )
prinst - > tempstringbase = prinst - > AddString ( prinst , " " , MAXTEMPBUFFERLEN * MAX_TEMPSTRS ) ;
else
prinst - > tempstringbase = 0 ;
prinst - > tempstringnum = 0 ;
}
//#define RETURN_EDICT(pf, e) (((int *)pr_globals)[OFS_RETURN] = EDICT_TO_PROG(pf, e))
# define RETURN_SSTRING(s) (((int *)pr_globals)[OFS_RETURN] = PR_SetString(prinst, s)) //static - exe will not change it.
# define RETURN_TSTRING(s) (((int *)pr_globals)[OFS_RETURN] = PR_TempString(prinst, s)) //temp (static but cycle buffers)
# define RETURN_CSTRING(s) (((int *)pr_globals)[OFS_RETURN] = PR_SetString(prinst, s)) //semi-permanant. (hash tables?)
# define RETURN_PSTRING(s) (((int *)pr_globals)[OFS_RETURN] = PR_NewString(prinst, s, 0)) //permanant
void VARGS PR_BIError ( progfuncs_t * progfuncs , char * format , . . . )
{
va_list argptr ;
static char string [ 2048 ] ;
va_start ( argptr , format ) ;
vsnprintf ( string , sizeof ( string ) - 1 , format , argptr ) ;
va_end ( argptr ) ;
if ( developer . value )
{
struct globalvars_s * pr_globals = PR_globals ( progfuncs , PR_CURRENT ) ;
Con_Printf ( " %s \n " , string ) ;
* progfuncs - > pr_trace = 1 ;
G_INT ( OFS_RETURN ) = 0 ; //just in case it was a float and should be an ent...
G_INT ( OFS_RETURN + 1 ) = 0 ;
G_INT ( OFS_RETURN + 2 ) = 0 ;
}
else
{
PR_StackTrace ( progfuncs ) ;
PR_AbortStack ( progfuncs ) ;
progfuncs - > parms - > Abort ( " %s " , string ) ;
}
}
pbool QC_WriteFile ( char * name , void * data , int len )
{
char buffer [ 256 ] ;
sprintf ( buffer , " %s " , name ) ;
COM_WriteFile ( buffer , data , len ) ;
return true ;
}
////////////////////////////////////////////////////
//Finding
/*
//entity(string field, float match) findchainflags = #450
//chained search for float, int, and entity reference fields
void PF_findchainflags ( progfuncs_t * prinst , struct globalvars_s * pr_globals )
{
int i , f ;
int s ;
edict_t * ent , * chain ;
chain = ( edict_t * ) * prinst - > parms - > sv_edicts ;
f = G_INT ( OFS_PARM0 ) + prinst - > fieldadjust ;
s = G_FLOAT ( OFS_PARM1 ) ;
for ( i = 1 ; i < * prinst - > parms - > sv_num_edicts ; i + + )
{
ent = EDICT_NUM ( prinst , i ) ;
if ( ent - > isfree )
continue ;
if ( ! ( ( int ) ( ( float * ) ent - > v ) [ f ] & s ) )
continue ;
ent - > v - > chain = EDICT_TO_PROG ( prinst , chain ) ;
chain = ent ;
}
RETURN_EDICT ( prinst , chain ) ;
}
*/
//EXTENSION: DP_QC_FINDFLAGS
//entity(entity start, float fld, float match) findflags = #449
void PF_FindFlags ( progfuncs_t * prinst , struct globalvars_s * pr_globals )
{
int e , f ;
int s ;
edict_t * ed ;
e = G_EDICTNUM ( prinst , OFS_PARM0 ) ;
f = G_INT ( OFS_PARM1 ) + prinst - > fieldadjust ;
s = G_FLOAT ( OFS_PARM2 ) ;
for ( e + + ; e < * prinst - > parms - > sv_num_edicts ; e + + )
{
ed = EDICT_NUM ( prinst , e ) ;
if ( ed - > isfree )
continue ;
if ( ( int ) ( ( float * ) ed - > v ) [ f ] & s )
{
RETURN_EDICT ( prinst , ed ) ;
return ;
}
}
RETURN_EDICT ( prinst , * prinst - > parms - > sv_edicts ) ;
}
/*
//entity(string field, float match) findchainfloat = #403
void PF_findchainfloat ( progfuncs_t * prinst , struct globalvars_s * pr_globals )
{
int i , f ;
float s ;
edict_t * ent , * chain ;
chain = ( edict_t * ) * prinst - > parms - > sv_edicts ;
f = G_INT ( OFS_PARM0 ) + prinst - > fieldadjust ;
s = G_FLOAT ( OFS_PARM1 ) ;
for ( i = 1 ; i < * prinst - > parms - > sv_num_edicts ; i + + )
{
ent = EDICT_NUM ( prinst , i ) ;
if ( ent - > isfree )
continue ;
if ( ( ( float * ) ent - > v ) [ f ] ! = s )
continue ;
ent - > v - > chain = EDICT_TO_PROG ( prinst , chain ) ;
chain = ent ;
}
RETURN_EDICT ( prinst , chain ) ;
}
*/
/*
//entity(string field, string match) findchain = #402
//chained search for strings in entity fields
void PF_findchain ( progfuncs_t * prinst , struct globalvars_s * pr_globals )
{
int i , f ;
char * s ;
string_t t ;
edict_t * ent , * chain ;
chain = ( edict_t * ) * prinst - > parms - > sv_edicts ;
f = G_INT ( OFS_PARM0 ) + prinst - > fieldadjust ;
s = PR_GetStringOfs ( prinst , OFS_PARM1 ) ;
for ( i = 1 ; i < * prinst - > parms - > sv_num_edicts ; i + + )
{
ent = EDICT_NUM ( prinst , i ) ;
if ( ent - > isfree )
continue ;
t = * ( string_t * ) & ( ( float * ) ent - > v ) [ f ] ;
if ( ! t )
continue ;
if ( strcmp ( PR_GetString ( prinst , t ) , s ) )
continue ;
ent - > v - > chain = EDICT_TO_PROG ( prinst , chain ) ;
chain = ent ;
}
RETURN_EDICT ( prinst , chain ) ;
}
*/
//entity(entity start, float fld, float match) findfloat = #98
void PF_FindFloat ( progfuncs_t * prinst , struct globalvars_s * pr_globals )
{
int e , f ;
int s ;
edict_t * ed ;
if ( * prinst - > callargc ! = 3 ) //I can hate mvdsv if I want to.
{
PR_BIError ( prinst , " PF_FindFloat (#98): callargc != 3 \n Did you mean to set pr_imitatemvdsv to 1? " ) ;
return ;
}
e = G_EDICTNUM ( prinst , OFS_PARM0 ) ;
f = G_INT ( OFS_PARM1 ) + prinst - > fieldadjust ;
s = G_INT ( OFS_PARM2 ) ;
for ( e + + ; e < * prinst - > parms - > sv_num_edicts ; e + + )
{
ed = EDICT_NUM ( prinst , e ) ;
if ( ed - > isfree )
continue ;
if ( ( ( int * ) ed - > v ) [ f ] = = s )
{
RETURN_EDICT ( prinst , ed ) ;
return ;
}
}
RETURN_EDICT ( prinst , * prinst - > parms - > sv_edicts ) ;
}
// entity (entity start, .string field, string match) find = #5;
void PF_FindString ( progfuncs_t * prinst , struct globalvars_s * pr_globals )
{
int e ;
int f ;
char * s ;
string_t t ;
edict_t * ed ;
e = G_EDICTNUM ( prinst , OFS_PARM0 ) ;
f = G_INT ( OFS_PARM1 ) + prinst - > fieldadjust ;
s = PR_GetStringOfs ( prinst , OFS_PARM2 ) ;
if ( ! s )
{
PR_BIError ( prinst , " PF_FindString: bad search string " ) ;
return ;
}
for ( e + + ; e < * prinst - > parms - > sv_num_edicts ; e + + )
{
ed = EDICT_NUM ( prinst , e ) ;
if ( ed - > isfree )
continue ;
t = ( ( string_t * ) ed - > v ) [ f ] ;
if ( ! t )
continue ;
if ( ! strcmp ( PR_GetString ( prinst , t ) , s ) )
{
RETURN_EDICT ( prinst , ed ) ;
return ;
}
}
RETURN_EDICT ( prinst , * prinst - > parms - > sv_edicts ) ;
}
//Finding
////////////////////////////////////////////////////
//Cvars
//string(string cvarname) cvar_string
void PF_cvar_string ( progfuncs_t * prinst , struct globalvars_s * pr_globals )
{
char * str = PR_GetStringOfs ( prinst , OFS_PARM0 ) ;
cvar_t * cv = Cvar_Get ( str , " " , 0 , " QC variables " ) ;
RETURN_CSTRING ( cv - > string ) ;
}
//string(string cvarname) cvar_defstring
void PF_cvar_defstring ( progfuncs_t * prinst , struct globalvars_s * pr_globals )
{
char * str = PR_GetStringOfs ( prinst , OFS_PARM0 ) ;
cvar_t * cv = Cvar_Get ( str , " " , 0 , " QC variables " ) ;
RETURN_CSTRING ( cv - > defaultstr ) ;
}
//float(string name) cvar_type
void PF_cvar_type ( progfuncs_t * prinst , struct globalvars_s * pr_globals )
{
char * str = PR_GetStringOfs ( prinst , OFS_PARM0 ) ;
int ret = 0 ;
cvar_t * v ;
v = Cvar_FindVar ( str ) ;
if ( v )
{
ret | = 1 ; // CVAR_EXISTS
if ( v - > flags & CVAR_ARCHIVE )
ret | = 2 ; // CVAR_TYPE_SAVED
if ( v - > flags & CVAR_NOTFROMSERVER )
ret | = 4 ; // CVAR_TYPE_PRIVATE
if ( ! ( v - > flags & CVAR_USERCREATED ) )
ret | = 8 ; // CVAR_TYPE_ENGINE
//fte cvars don't support this
// ret |= 16; // CVAR_TYPE_HASDESCRIPTION
}
G_FLOAT ( OFS_RETURN ) = ret ;
}
//void(string cvarname, string newvalue) cvar
void PF_cvar_set ( progfuncs_t * prinst , struct globalvars_s * pr_globals )
{
char * var_name , * val ;
cvar_t * var ;
var_name = PR_GetStringOfs ( prinst , OFS_PARM0 ) ;
val = PR_GetStringOfs ( prinst , OFS_PARM1 ) ;
var = Cvar_Get ( var_name , val , 0 , " QC variables " ) ;
if ( ! var )
return ;
Cvar_Set ( var , val ) ;
}
void PF_cvar_setf ( progfuncs_t * prinst , struct globalvars_s * pr_globals )
{
char * var_name ;
float val ;
cvar_t * var ;
var_name = PR_GetStringOfs ( prinst , OFS_PARM0 ) ;
val = G_FLOAT ( OFS_PARM1 ) ;
var = Cvar_FindVar ( var_name ) ;
if ( ! var )
Con_Printf ( " PF_cvar_set: variable %s not found \n " , var_name ) ;
else
Cvar_SetValue ( var , val ) ;
}
//float(string name, string value) registercvar
void PF_registercvar ( progfuncs_t * prinst , struct globalvars_s * pr_globals )
{
char * name , * value ;
value = PR_GetStringOfs ( prinst , OFS_PARM0 ) ;
if ( Cvar_FindVar ( value ) )
G_FLOAT ( OFS_RETURN ) = 0 ;
else
{
name = BZ_Malloc ( strlen ( value ) + 1 ) ;
strcpy ( name , value ) ;
if ( * prinst - > callargc > 1 )
value = PR_GetStringOfs ( prinst , OFS_PARM1 ) ;
else
value = " " ;
// archive?
if ( Cvar_Get ( name , value , CVAR_USERCREATED , " QC created vars " ) )
G_FLOAT ( OFS_RETURN ) = 1 ;
else
G_FLOAT ( OFS_RETURN ) = 0 ;
}
}
//Cvars
////////////////////////////////////////////////////
//File access
# define MAX_QC_FILES 8
# define FIRST_QC_FILE_INDEX 1000
typedef struct {
char name [ 256 ] ;
char * data ;
int bufferlen ;
int len ;
int ofs ;
int accessmode ;
progfuncs_t * prinst ;
} pf_fopen_files_t ;
pf_fopen_files_t pf_fopen_files [ MAX_QC_FILES ] ;
void PF_fopen ( progfuncs_t * prinst , struct globalvars_s * pr_globals )
{
char * name = PR_GetStringOfs ( prinst , OFS_PARM0 ) ;
int fmode = G_FLOAT ( OFS_PARM1 ) ;
int i ;
for ( i = 0 ; i < MAX_QC_FILES ; i + + )
if ( ! pf_fopen_files [ i ] . data )
break ;
if ( i = = MAX_QC_FILES ) //too many already open
{
G_FLOAT ( OFS_RETURN ) = - 1 ;
return ;
}
if ( name [ 1 ] = = ' : ' | | //dos filename absolute path specified - reject.
strchr ( name , ' \\ ' ) | | * name = = ' / ' | | //absolute path was given - reject
strstr ( name , " .. " ) ) //someone tried to be cleaver.
{
G_FLOAT ( OFS_RETURN ) = - 1 ;
return ;
}
Q_strncpyz ( pf_fopen_files [ i ] . name , va ( " data/%s " , name ) , sizeof ( pf_fopen_files [ i ] . name ) ) ;
pf_fopen_files [ i ] . accessmode = fmode ;
switch ( fmode )
{
case 0 : //read
pf_fopen_files [ i ] . data = COM_LoadMallocFile ( pf_fopen_files [ i ] . name ) ;
if ( ! pf_fopen_files [ i ] . data )
{
Q_strncpyz ( pf_fopen_files [ i ] . name , name , sizeof ( pf_fopen_files [ i ] . name ) ) ;
pf_fopen_files [ i ] . data = COM_LoadMallocFile ( pf_fopen_files [ i ] . name ) ;
}
if ( pf_fopen_files [ i ] . data )
{
G_FLOAT ( OFS_RETURN ) = i + FIRST_QC_FILE_INDEX ;
pf_fopen_files [ i ] . prinst = prinst ;
}
else
G_FLOAT ( OFS_RETURN ) = - 1 ;
pf_fopen_files [ i ] . bufferlen = pf_fopen_files [ i ] . len = com_filesize ;
pf_fopen_files [ i ] . ofs = 0 ;
break ;
case 1 : //append
pf_fopen_files [ i ] . data = COM_LoadMallocFile ( pf_fopen_files [ i ] . name ) ;
pf_fopen_files [ i ] . ofs = pf_fopen_files [ i ] . bufferlen = pf_fopen_files [ i ] . len = com_filesize ;
if ( pf_fopen_files [ i ] . data )
{
G_FLOAT ( OFS_RETURN ) = i + FIRST_QC_FILE_INDEX ;
pf_fopen_files [ i ] . prinst = prinst ;
break ;
}
//file didn't exist - fall through
case 2 : //write
pf_fopen_files [ i ] . bufferlen = 8192 ;
pf_fopen_files [ i ] . data = BZ_Malloc ( pf_fopen_files [ i ] . bufferlen ) ;
pf_fopen_files [ i ] . len = 0 ;
pf_fopen_files [ i ] . ofs = 0 ;
G_FLOAT ( OFS_RETURN ) = i + FIRST_QC_FILE_INDEX ;
pf_fopen_files [ i ] . prinst = prinst ;
break ;
default : //bad
G_FLOAT ( OFS_RETURN ) = - 1 ;
break ;
}
}
void PF_fclose_i ( int fnum )
{
if ( fnum < 0 | | fnum > = MAX_QC_FILES )
{
Con_Printf ( " PF_fclose: File out of range \n " ) ;
return ; //out of range
}
if ( ! pf_fopen_files [ fnum ] . data )
{
Con_Printf ( " PF_fclose: File is not open \n " ) ;
return ; //not open
}
switch ( pf_fopen_files [ fnum ] . accessmode )
{
case 0 :
BZ_Free ( pf_fopen_files [ fnum ] . data ) ;
break ;
case 1 :
case 2 :
COM_WriteFile ( pf_fopen_files [ fnum ] . name , pf_fopen_files [ fnum ] . data , pf_fopen_files [ fnum ] . len ) ;
BZ_Free ( pf_fopen_files [ fnum ] . data ) ;
break ;
}
pf_fopen_files [ fnum ] . data = NULL ;
pf_fopen_files [ fnum ] . prinst = NULL ;
}
void PF_fclose ( progfuncs_t * prinst , struct globalvars_s * pr_globals )
{
int fnum = G_FLOAT ( OFS_PARM0 ) - FIRST_QC_FILE_INDEX ;
if ( fnum < 0 | | fnum > = MAX_QC_FILES )
{
Con_Printf ( " PF_fclose: File out of range \n " ) ;
return ; //out of range
}
if ( pf_fopen_files [ fnum ] . prinst ! = prinst )
{
Con_Printf ( " PF_fclose: File is from wrong instance \n " ) ;
return ; //this just isn't ours.
}
PF_fclose_i ( fnum ) ;
}
void PF_fgets ( progfuncs_t * prinst , struct globalvars_s * pr_globals )
{
char c , * s , * o , * max ;
int fnum = G_FLOAT ( OFS_PARM0 ) - FIRST_QC_FILE_INDEX ;
char pr_string_temp [ 4096 ] ;
* pr_string_temp = ' \0 ' ;
G_INT ( OFS_RETURN ) = 0 ; //EOF
if ( fnum < 0 | | fnum > = MAX_QC_FILES )
{
PR_BIError ( prinst , " PF_fgets: File out of range \n " ) ;
return ; //out of range
}
if ( ! pf_fopen_files [ fnum ] . data )
{
PR_BIError ( prinst , " PF_fgets: File is not open \n " ) ;
return ; //not open
}
if ( pf_fopen_files [ fnum ] . prinst ! = prinst )
{
PR_BIError ( prinst , " PF_fgets: File is from wrong instance \n " ) ;
return ; //this just isn't ours.
}
//read up to the next \n, ignoring any \rs.
o = pr_string_temp ;
max = o + MAXTEMPBUFFERLEN - 1 ;
s = pf_fopen_files [ fnum ] . data + pf_fopen_files [ fnum ] . ofs ;
while ( * s )
{
c = * s + + ;
if ( c = = ' \n ' )
break ;
if ( c = = ' \r ' )
continue ;
if ( o = = max )
break ;
* o + + = c ;
}
* o = ' \0 ' ;
pf_fopen_files [ fnum ] . ofs = s - pf_fopen_files [ fnum ] . data ;
if ( ! pr_string_temp [ 0 ] & & ! * s )
G_INT ( OFS_RETURN ) = 0 ; //EOF
else
RETURN_TSTRING ( pr_string_temp ) ;
}
void PF_fputs ( progfuncs_t * prinst , struct globalvars_s * pr_globals )
{
int fnum = G_FLOAT ( OFS_PARM0 ) - FIRST_QC_FILE_INDEX ;
char * msg = PF_VarString ( prinst , 1 , pr_globals ) ;
int len = strlen ( msg ) ;
if ( fnum < 0 | | fnum > = MAX_QC_FILES )
{
Con_Printf ( " PF_fgets: File out of range \n " ) ;
return ; //out of range
}
if ( ! pf_fopen_files [ fnum ] . data )
{
Con_Printf ( " PF_fgets: File is not open \n " ) ;
return ; //not open
}
if ( pf_fopen_files [ fnum ] . prinst ! = prinst )
{
Con_Printf ( " PF_fgets: File is from wrong instance \n " ) ;
return ; //this just isn't ours.
}
if ( pf_fopen_files [ fnum ] . bufferlen < pf_fopen_files [ fnum ] . ofs + len )
{
char * newbuf ;
pf_fopen_files [ fnum ] . bufferlen = pf_fopen_files [ fnum ] . bufferlen * 2 + len ;
newbuf = BZF_Malloc ( pf_fopen_files [ fnum ] . bufferlen ) ;
memcpy ( newbuf , pf_fopen_files [ fnum ] . data , pf_fopen_files [ fnum ] . len ) ;
BZ_Free ( pf_fopen_files [ fnum ] . data ) ;
pf_fopen_files [ fnum ] . data = newbuf ;
}
memcpy ( pf_fopen_files [ fnum ] . data + pf_fopen_files [ fnum ] . ofs , msg , len ) ;
if ( pf_fopen_files [ fnum ] . len < pf_fopen_files [ fnum ] . ofs + len )
pf_fopen_files [ fnum ] . len = pf_fopen_files [ fnum ] . ofs + len ;
pf_fopen_files [ fnum ] . ofs + = len ;
}
void PF_fcloseall ( progfuncs_t * prinst )
{
int i ;
for ( i = 0 ; i < MAX_QC_FILES ; i + + )
{
if ( pf_fopen_files [ i ] . prinst ! = prinst )
continue ;
2008-11-28 20:34:51 +00:00
Con_Printf ( " qc file %s was still open \n " , pf_fopen_files [ i ] . name ) ;
2008-11-09 22:29:28 +00:00
PF_fclose_i ( i ) ;
}
}
//DP_QC_WHICHPACK
void PF_whichpack ( progfuncs_t * prinst , struct globalvars_s * pr_globals )
{
char * srcname = PR_GetStringOfs ( prinst , OFS_PARM0 ) ;
flocation_t loc ;
if ( FS_FLocateFile ( srcname , FSLFRT_IFFOUND , & loc ) )
{
RETURN_TSTRING ( FS_WhichPackForLocation ( & loc ) ) ;
}
else
{
G_INT ( OFS_RETURN ) = 0 ; //null/empty
}
}
typedef struct prvmsearch_s {
int handle ;
progfuncs_t * fromprogs ; //share across menu/server
int entries ;
char * * names ;
int * sizes ;
struct prvmsearch_s * next ;
} prvmsearch_t ;
prvmsearch_t * prvmsearches ;
int prvm_nextsearchhandle ;
void search_close ( progfuncs_t * prinst , int handle )
{
int i ;
prvmsearch_t * prev , * s ;
prev = NULL ;
for ( s = prvmsearches ; s ; )
{
if ( s - > handle = = handle )
{ //close it down.
if ( s - > fromprogs ! = prinst )
{
Con_Printf ( " Handle wasn't valid with that progs \n " ) ;
return ;
}
if ( prev )
prev - > next = s - > next ;
else
prvmsearches = s - > next ;
for ( i = 0 ; i < s - > entries ; i + + )
{
BZ_Free ( s - > names [ i ] ) ;
}
BZ_Free ( s - > names ) ;
BZ_Free ( s - > sizes ) ;
BZ_Free ( s ) ;
return ;
}
prev = s ;
s = s - > next ;
}
}
//a progs was closed... hunt down it's searches, and warn about any searches left open.
void search_close_progs ( progfuncs_t * prinst , qboolean complain )
{
int i ;
prvmsearch_t * prev , * s ;
prev = NULL ;
for ( s = prvmsearches ; s ; )
{
if ( s - > fromprogs = = prinst )
{ //close it down.
if ( complain )
Con_Printf ( " Warning: Progs search was still active \n " ) ;
if ( prev )
prev - > next = s - > next ;
else
prvmsearches = s - > next ;
for ( i = 0 ; i < s - > entries ; i + + )
{
BZ_Free ( s - > names [ i ] ) ;
}
BZ_Free ( s - > names ) ;
BZ_Free ( s - > sizes ) ;
BZ_Free ( s ) ;
if ( prev )
s = prev - > next ;
else
s = prvmsearches ;
continue ;
}
prev = s ;
s = s - > next ;
}
if ( ! prvmsearches )
prvm_nextsearchhandle = 0 ; //might as well.
}
int search_enumerate ( char * name , int fsize , void * parm )
{
prvmsearch_t * s = parm ;
s - > names = BZ_Realloc ( s - > names , ( ( s - > entries + 64 ) & ~ 63 ) * sizeof ( char * ) ) ;
s - > sizes = BZ_Realloc ( s - > sizes , ( ( s - > entries + 64 ) & ~ 63 ) * sizeof ( int ) ) ;
s - > names [ s - > entries ] = BZ_Malloc ( strlen ( name ) + 1 ) ;
strcpy ( s - > names [ s - > entries ] , name ) ;
s - > sizes [ s - > entries ] = fsize ;
s - > entries + + ;
return true ;
}
//float search_begin(string pattern, float caseinsensitive, float quiet) = #74;
void PF_search_begin ( progfuncs_t * prinst , struct globalvars_s * pr_globals )
{ //< 0 for error, > 0 for handle.
char * pattern = PR_GetStringOfs ( prinst , OFS_PARM0 ) ;
// qboolean caseinsensative = G_FLOAT(OFS_PARM1);
// qboolean quiet = G_FLOAT(OFS_PARM2);
prvmsearch_t * s ;
s = Z_Malloc ( sizeof ( * s ) ) ;
s - > fromprogs = prinst ;
s - > handle = prvm_nextsearchhandle + + ;
COM_EnumerateFiles ( pattern , search_enumerate , s ) ;
if ( s - > entries = = 0 )
{
BZ_Free ( s ) ;
G_FLOAT ( OFS_RETURN ) = - 1 ;
return ;
}
s - > next = prvmsearches ;
prvmsearches = s ;
G_FLOAT ( OFS_RETURN ) = s - > handle ;
}
//void search_end(float handle) = #75;
void PF_search_end ( progfuncs_t * prinst , struct globalvars_s * pr_globals )
{
int handle = G_FLOAT ( OFS_PARM0 ) ;
search_close ( prinst , handle ) ;
}
//float search_getsize(float handle) = #76;
void PF_search_getsize ( progfuncs_t * prinst , struct globalvars_s * pr_globals )
{
int handle = G_FLOAT ( OFS_PARM0 ) ;
prvmsearch_t * s ;
G_FLOAT ( OFS_RETURN ) = - 1 ;
for ( s = prvmsearches ; s ; s = s - > next )
{
if ( s - > handle = = handle )
{ //close it down.
if ( s - > fromprogs ! = prinst )
{
Con_Printf ( " Handle wasn't valid with that progs \n " ) ;
return ;
}
G_FLOAT ( OFS_RETURN ) = s - > entries ;
return ;
}
}
}
//string search_getfilename(float handle, float num) = #77;
void PF_search_getfilename ( progfuncs_t * prinst , struct globalvars_s * pr_globals )
{
int handle = G_FLOAT ( OFS_PARM0 ) ;
int num = G_FLOAT ( OFS_PARM1 ) ;
prvmsearch_t * s ;
G_INT ( OFS_RETURN ) = 0 ;
for ( s = prvmsearches ; s ; s = s - > next )
{
if ( s - > handle = = handle )
{ //close it down.
if ( s - > fromprogs ! = prinst )
{
Con_Printf ( " Search handle wasn't valid with that progs \n " ) ;
return ;
}
if ( num < 0 | | num > = s - > entries )
return ;
RETURN_TSTRING ( s - > names [ num ] ) ;
return ;
}
}
Con_Printf ( " Search handle wasn't valid \n " ) ;
}
//closes filesystem type stuff for when a progs has stopped needing it.
void PR_fclose_progs ( progfuncs_t * prinst )
{
PF_fcloseall ( prinst ) ;
search_close_progs ( prinst , true ) ;
}
//File access
////////////////////////////////////////////////////
//Entities
void PF_WasFreed ( progfuncs_t * prinst , struct globalvars_s * pr_globals )
{
edict_t * ent ;
ent = ( edict_t * ) G_EDICT ( prinst , OFS_PARM0 ) ;
G_FLOAT ( OFS_RETURN ) = ent - > isfree ;
}
void PF_num_for_edict ( progfuncs_t * prinst , struct globalvars_s * pr_globals )
{
edict_t * ent ;
ent = ( edict_t * ) G_EDICT ( prinst , OFS_PARM0 ) ;
G_FLOAT ( OFS_RETURN ) = ent - > entnum ;
}
void PF_edict_for_num ( progfuncs_t * prinst , struct globalvars_s * pr_globals )
{
edict_t * ent ;
ent = ( edict_t * ) EDICT_NUM ( prinst , G_FLOAT ( OFS_PARM0 ) ) ;
RETURN_EDICT ( prinst , ent ) ;
}
//entity nextent(entity)
void PF_nextent ( progfuncs_t * prinst , struct globalvars_s * pr_globals )
{
int i ;
edict_t * ent ;
i = G_EDICTNUM ( prinst , OFS_PARM0 ) ;
while ( 1 )
{
i + + ;
if ( i = = * prinst - > parms - > sv_num_edicts )
{
RETURN_EDICT ( prinst , * prinst - > parms - > sv_edicts ) ;
return ;
}
ent = EDICT_NUM ( prinst , i ) ;
if ( ! ent - > isfree )
{
RETURN_EDICT ( prinst , ent ) ;
return ;
}
}
}
//entity() spawn
void PF_Spawn ( progfuncs_t * prinst , struct globalvars_s * pr_globals )
{
struct edict_s * ed ;
ed = ED_Alloc ( prinst ) ;
RETURN_EDICT ( prinst , ed ) ;
}
//Entities
////////////////////////////////////////////////////
//String functions
//PF_dprint
void PF_dprint ( progfuncs_t * prinst , struct globalvars_s * pr_globals )
{
Con_DPrintf ( " %s " , PF_VarString ( prinst , 0 , pr_globals ) ) ;
}
//PF_print
void PF_print ( progfuncs_t * prinst , struct globalvars_s * pr_globals )
{
Con_Printf ( " %s " , PF_VarString ( prinst , 0 , pr_globals ) ) ;
}
//FTE_STRINGS
//C style strncasecmp (compare first n characters - case insensative)
void PF_strncasecmp ( progfuncs_t * prinst , struct globalvars_s * pr_globals )
{
char * a = PR_GetStringOfs ( prinst , OFS_PARM0 ) ;
char * b = PR_GetStringOfs ( prinst , OFS_PARM1 ) ;
float len = G_FLOAT ( OFS_PARM2 ) ;
G_FLOAT ( OFS_RETURN ) = strnicmp ( a , b , len ) ;
}
//FTE_STRINGS
//C style strcasecmp (case insensative string compare)
void PF_strcasecmp ( progfuncs_t * prinst , struct globalvars_s * pr_globals )
{
char * a = PR_GetStringOfs ( prinst , OFS_PARM0 ) ;
char * b = PR_GetStringOfs ( prinst , OFS_PARM1 ) ;
G_FLOAT ( OFS_RETURN ) = stricmp ( a , b ) ;
}
//FTE_STRINGS
//C style strncmp (compare first n characters - case sensative. Note that there is no strcmp provided)
void PF_strncmp ( progfuncs_t * prinst , struct globalvars_s * pr_globals )
{
char * a = PR_GetStringOfs ( prinst , OFS_PARM0 ) ;
char * b = PR_GetStringOfs ( prinst , OFS_PARM1 ) ;
float len = G_FLOAT ( OFS_PARM2 ) ;
G_FLOAT ( OFS_RETURN ) = strncmp ( a , b , len ) ;
}
//uses qw style \key\value strings
void PF_infoget ( progfuncs_t * prinst , struct globalvars_s * pr_globals )
{
char * info = PR_GetStringOfs ( prinst , OFS_PARM0 ) ;
char * key = PR_GetStringOfs ( prinst , OFS_PARM1 ) ;
key = Info_ValueForKey ( info , key ) ;
RETURN_TSTRING ( key ) ;
}
//uses qw style \key\value strings
void PF_infoadd ( progfuncs_t * prinst , struct globalvars_s * pr_globals )
{
char * info = PR_GetStringOfs ( prinst , OFS_PARM0 ) ;
char * key = PR_GetStringOfs ( prinst , OFS_PARM1 ) ;
char * value = PF_VarString ( prinst , 2 , pr_globals ) ;
char temp [ 8192 ] ;
Q_strncpyz ( temp , info , MAXTEMPBUFFERLEN ) ;
Info_SetValueForStarKey ( temp , key , value , MAXTEMPBUFFERLEN ) ;
RETURN_TSTRING ( temp ) ;
}
//string(float pad, string str1, ...) strpad
void PF_strpad ( progfuncs_t * prinst , struct globalvars_s * pr_globals )
{
char destbuf [ 4096 ] ;
char * dest = destbuf ;
int pad = G_FLOAT ( OFS_PARM0 ) ;
char * src = PF_VarString ( prinst , 1 , pr_globals ) ;
if ( pad < 0 )
{ //pad left
pad = - pad - strlen ( src ) ;
if ( pad > = MAXTEMPBUFFERLEN )
pad = MAXTEMPBUFFERLEN - 1 ;
if ( pad < 0 )
pad = 0 ;
Q_strncpyz ( dest + pad , src , MAXTEMPBUFFERLEN - pad ) ;
while ( pad - - )
{
pad - - ;
dest [ pad ] = ' ' ;
}
}
else
{ //pad right
if ( pad > = MAXTEMPBUFFERLEN )
pad = MAXTEMPBUFFERLEN - 1 ;
pad - = strlen ( src ) ;
if ( pad < 0 )
pad = 0 ;
Q_strncpyz ( dest , src , MAXTEMPBUFFERLEN ) ;
dest + = strlen ( dest ) ;
while ( pad - - > 0 )
* dest + + = ' ' ;
* dest = ' \0 ' ;
}
RETURN_TSTRING ( destbuf ) ;
}
//part of PF_strconv
static int chrconv_number ( int i , int base , int conv )
{
i - = base ;
switch ( conv )
{
default :
case 5 :
case 6 :
case 0 :
break ;
case 1 :
base = ' 0 ' ;
break ;
case 2 :
base = ' 0 ' + 128 ;
break ;
case 3 :
base = ' 0 ' - 30 ;
break ;
case 4 :
base = ' 0 ' + 128 - 30 ;
break ;
}
return i + base ;
}
//part of PF_strconv
static int chrconv_punct ( int i , int base , int conv )
{
i - = base ;
switch ( conv )
{
default :
case 0 :
break ;
case 1 :
base = 0 ;
break ;
case 2 :
base = 128 ;
break ;
}
return i + base ;
}
//part of PF_strconv
static int chrchar_alpha ( int i , int basec , int baset , int convc , int convt , int charnum )
{
//convert case and colour seperatly...
i - = baset + basec ;
switch ( convt )
{
default :
case 0 :
break ;
case 1 :
baset = 0 ;
break ;
case 2 :
baset = 128 ;
break ;
case 5 :
case 6 :
baset = 128 * ( ( charnum & 1 ) = = ( convt - 5 ) ) ;
break ;
}
switch ( convc )
{
default :
case 0 :
break ;
case 1 :
basec = ' a ' ;
break ;
case 2 :
basec = ' A ' ;
break ;
}
return i + basec + baset ;
}
//FTE_STRINGS
//bulk convert a string. change case or colouring.
void PF_strconv ( progfuncs_t * prinst , struct globalvars_s * pr_globals )
{
int ccase = G_FLOAT ( OFS_PARM0 ) ; //0 same, 1 lower, 2 upper
int redalpha = G_FLOAT ( OFS_PARM1 ) ; //0 same, 1 white, 2 red, 5 alternate, 6 alternate-alternate
int rednum = G_FLOAT ( OFS_PARM2 ) ; //0 same, 1 white, 2 red, 3 redspecial, 4 whitespecial, 5 alternate, 6 alternate-alternate
unsigned char * string = PF_VarString ( prinst , 3 , pr_globals ) ;
int len = strlen ( string ) ;
int i ;
unsigned char resbuf [ 8192 ] ;
unsigned char * result = resbuf ;
if ( len > = MAXTEMPBUFFERLEN )
len = MAXTEMPBUFFERLEN - 1 ;
for ( i = 0 ; i < len ; i + + , string + + , result + + ) //should this be done backwards?
{
if ( * string > = ' 0 ' & & * string < = ' 9 ' ) //normal numbers...
* result = chrconv_number ( * string , ' 0 ' , rednum ) ;
else if ( * string > = ' 0 ' + 128 & & * string < = ' 9 ' + 128 )
* result = chrconv_number ( * string , ' 0 ' + 128 , rednum ) ;
else if ( * string > = ' 0 ' + 128 - 30 & & * string < = ' 9 ' + 128 - 30 )
* result = chrconv_number ( * string , ' 0 ' + 128 - 30 , rednum ) ;
else if ( * string > = ' 0 ' - 30 & & * string < = ' 9 ' - 30 )
* result = chrconv_number ( * string , ' 0 ' - 30 , rednum ) ;
else if ( * string > = ' a ' & & * string < = ' z ' ) //normal numbers...
* result = chrchar_alpha ( * string , ' a ' , 0 , ccase , redalpha , i ) ;
else if ( * string > = ' A ' & & * string < = ' Z ' ) //normal numbers...
* result = chrchar_alpha ( * string , ' A ' , 0 , ccase , redalpha , i ) ;
else if ( * string > = ' a ' + 128 & & * string < = ' z ' + 128 ) //normal numbers...
* result = chrchar_alpha ( * string , ' a ' , 128 , ccase , redalpha , i ) ;
else if ( * string > = ' A ' + 128 & & * string < = ' Z ' + 128 ) //normal numbers...
* result = chrchar_alpha ( * string , ' A ' , 128 , ccase , redalpha , i ) ;
else if ( ( * string & 127 ) < 16 | | ! redalpha ) //special chars..
* result = * string ;
else if ( * string < 128 )
* result = chrconv_punct ( * string , 0 , redalpha ) ;
else
* result = chrconv_punct ( * string , 128 , redalpha ) ;
}
* result = ' \0 ' ;
RETURN_TSTRING ( ( ( char * ) resbuf ) ) ;
}
//FTE_STRINGS
//returns a string containing one character per parameter (up to the qc max params of 8).
void PF_chr2str ( progfuncs_t * prinst , struct globalvars_s * pr_globals )
{
int i ;
char string [ 16 ] ;
for ( i = 0 ; i < * prinst - > callargc ; i + + )
string [ i ] = G_FLOAT ( OFS_PARM0 + i * 3 ) ;
string [ i ] = ' \0 ' ;
RETURN_TSTRING ( string ) ;
}
//FTE_STRINGS
//returns character at position X
void PF_str2chr ( progfuncs_t * prinst , struct globalvars_s * pr_globals )
{
char * instr = PR_GetStringOfs ( prinst , OFS_PARM0 ) ;
int ofs = ( * prinst - > callargc > 1 ) ? G_FLOAT ( OFS_PARM1 ) : 0 ;
if ( ofs < 0 )
ofs = strlen ( instr ) + ofs ;
if ( ofs & & ( ofs < 0 | | ofs > strlen ( instr ) ) )
G_FLOAT ( OFS_RETURN ) = ' \0 ' ;
else
G_FLOAT ( OFS_RETURN ) = instr [ ofs ] ;
}
//FTE_STRINGS
//strstr, without generating a new string. Use in conjunction with FRIK_FILE's substring for more similar strstr.
void PF_strstrofs ( progfuncs_t * prinst , struct globalvars_s * pr_globals )
{
char * instr = PR_GetStringOfs ( prinst , OFS_PARM0 ) ;
char * match = PR_GetStringOfs ( prinst , OFS_PARM1 ) ;
int firstofs = ( * prinst - > callargc > 2 ) ? G_FLOAT ( OFS_PARM2 ) : 0 ;
if ( firstofs & & ( firstofs < 0 | | firstofs > strlen ( instr ) ) )
{
G_FLOAT ( OFS_RETURN ) = - 1 ;
return ;
}
match = strstr ( instr + firstofs , match ) ;
if ( ! match )
G_FLOAT ( OFS_RETURN ) = - 1 ;
else
G_FLOAT ( OFS_RETURN ) = match - instr ;
}
//float(string input) stof
void PF_stof ( progfuncs_t * prinst , struct globalvars_s * pr_globals )
{
char * s ;
s = PR_GetStringOfs ( prinst , OFS_PARM0 ) ;
G_FLOAT ( OFS_RETURN ) = atof ( s ) ;
}
//tstring(float input) ftos
void PF_ftos ( progfuncs_t * prinst , struct globalvars_s * pr_globals )
{
float v ;
char pr_string_temp [ 64 ] ;
v = G_FLOAT ( OFS_PARM0 ) ;
if ( v = = ( int ) v )
sprintf ( pr_string_temp , " %d " , ( int ) v ) ;
else if ( pr_brokenfloatconvert . value )
sprintf ( pr_string_temp , " %5.1f " , v ) ;
else
Q_ftoa ( pr_string_temp , v ) ;
RETURN_TSTRING ( pr_string_temp ) ;
}
//tstring(integer input) itos
void PF_itos ( progfuncs_t * prinst , struct globalvars_s * pr_globals )
{
int v ;
char pr_string_temp [ 64 ] ;
v = G_INT ( OFS_PARM0 ) ;
sprintf ( pr_string_temp , " %d " , v ) ;
RETURN_TSTRING ( pr_string_temp ) ;
}
//int(string input) stoi
void PF_stoi ( progfuncs_t * prinst , struct globalvars_s * pr_globals )
{
char * input = PR_GetStringOfs ( prinst , OFS_PARM0 ) ;
G_INT ( OFS_RETURN ) = atoi ( input ) ;
}
//tstring(integer input) htos
void PF_htos ( progfuncs_t * prinst , struct globalvars_s * pr_globals )
{
unsigned int v ;
char pr_string_temp [ 64 ] ;
v = G_INT ( OFS_PARM0 ) ;
sprintf ( pr_string_temp , " %08x " , v ) ;
RETURN_TSTRING ( pr_string_temp ) ;
}
//int(string input) stoh
void PF_stoh ( progfuncs_t * prinst , struct globalvars_s * pr_globals )
{
char * input = PR_GetStringOfs ( prinst , OFS_PARM0 ) ;
G_INT ( OFS_RETURN ) = strtoul ( input , NULL , 16 ) ;
}
//vector(string s) stov = #117
//returns vector value from a string
void PF_stov ( progfuncs_t * prinst , struct globalvars_s * pr_globals )
{
int i ;
char * s ;
float * out ;
s = PF_VarString ( prinst , 0 , pr_globals ) ;
out = G_VECTOR ( OFS_RETURN ) ;
out [ 0 ] = out [ 1 ] = out [ 2 ] = 0 ;
if ( * s = = ' \' ' )
s + + ;
for ( i = 0 ; i < 3 ; i + + )
{
while ( * s = = ' ' | | * s = = ' \t ' )
s + + ;
out [ i ] = atof ( s ) ;
if ( ! out [ i ] & & * s ! = ' - ' & & * s ! = ' + ' & & ( * s < ' 0 ' | | * s > ' 9 ' ) )
break ; // not a number
while ( * s & & * s ! = ' ' & & * s ! = ' \t ' & & * s ! = ' \' ' )
s + + ;
if ( * s = = ' \' ' )
break ;
}
}
//tstring(vector input) vtos
void PF_vtos ( progfuncs_t * prinst , struct globalvars_s * pr_globals )
{
char pr_string_temp [ 64 ] ;
//sprintf (pr_string_temp, "'%5.1f %5.1f %5.1f'", G_VECTOR(OFS_PARM0)[0], G_VECTOR(OFS_PARM0)[1], G_VECTOR(OFS_PARM0)[2]);
sprintf ( pr_string_temp , " '%f %f %f' " , G_VECTOR ( OFS_PARM0 ) [ 0 ] , G_VECTOR ( OFS_PARM0 ) [ 1 ] , G_VECTOR ( OFS_PARM0 ) [ 2 ] ) ;
PR_TempString ( prinst , pr_string_temp ) ;
RETURN_TSTRING ( pr_string_temp ) ;
}
# pragma message("this should use something more... less hacky")
void PF_forgetstring ( progfuncs_t * prinst , struct globalvars_s * pr_globals )
{
char * s = PR_GetStringOfs ( prinst , OFS_PARM0 ) ;
s - = 8 ;
if ( ( ( int * ) s ) [ 0 ] ! = PRSTR )
{
Con_Printf ( " QC tried to free a non allocated string: " ) ;
Con_Printf ( " %s \n " , s + 8 ) ; //two prints, so that logged prints ensure the first is written.
( * prinst - > pr_trace ) = 1 ;
PR_StackTrace ( prinst ) ;
return ;
}
( ( int * ) s ) [ 0 ] = 0xabcd1234 ;
Z_TagFree ( s ) ;
}
void PF_dupstring ( progfuncs_t * prinst , struct globalvars_s * pr_globals ) //frik_file
{
char * s , * in ;
int len ;
in = PF_VarString ( prinst , 0 , pr_globals ) ;
len = strlen ( in ) + 1 ;
s = Z_TagMalloc ( len + 8 , Z_QC_TAG ) ;
( ( int * ) s ) [ 0 ] = PRSTR ;
( ( int * ) s ) [ 1 ] = len ;
strcpy ( s + 8 , in ) ;
RETURN_SSTRING ( s + 8 ) ;
}
//returns a section of a string as a tempstring
void PF_substring ( progfuncs_t * prinst , struct globalvars_s * pr_globals )
{
int i , start , length ;
char * s ;
char string [ 4096 ] ;
s = PR_GetStringOfs ( prinst , OFS_PARM0 ) ;
start = G_FLOAT ( OFS_PARM1 ) ;
length = G_FLOAT ( OFS_PARM2 ) ;
if ( start < 0 )
start = strlen ( s ) - start ;
if ( length < 0 )
length = strlen ( s ) - start + ( length + 1 ) ;
if ( start > = strlen ( s ) | | length < = 0 | | ! * s )
{
RETURN_TSTRING ( " " ) ;
return ;
}
if ( length > = MAXTEMPBUFFERLEN )
length = MAXTEMPBUFFERLEN - 1 ;
for ( i = 0 ; i < start & & * s ; i + + , s + + )
;
for ( i = 0 ; * s & & i < length ; i + + , s + + )
string [ i ] = * s ;
string [ i ] = 0 ;
RETURN_TSTRING ( string ) ;
}
//string(string str1, string str2) strcat
void PF_strcat ( progfuncs_t * prinst , struct globalvars_s * pr_globals )
{
char dest [ 4096 ] ;
char * src = PF_VarString ( prinst , 0 , pr_globals ) ;
Q_strncpyz ( dest , src , MAXTEMPBUFFERLEN ) ;
RETURN_TSTRING ( dest ) ;
}
void PF_strlen ( progfuncs_t * prinst , struct globalvars_s * pr_globals )
{
G_FLOAT ( OFS_RETURN ) = strlen ( PR_GetStringOfs ( prinst , OFS_PARM0 ) ) ;
}
//float(string input, string token) instr
void PF_instr ( progfuncs_t * prinst , struct globalvars_s * pr_globals )
{
char * sub ;
char * s1 ;
char * s2 ;
s1 = PR_GetStringOfs ( prinst , OFS_PARM0 ) ;
s2 = PF_VarString ( prinst , 1 , pr_globals ) ;
if ( ! s1 | | ! s2 )
{
PR_BIError ( prinst , " Null string in \" instr \" \n " ) ;
return ;
}
sub = strstr ( s1 , s2 ) ;
if ( sub = = NULL )
G_INT ( OFS_RETURN ) = 0 ;
else
RETURN_SSTRING ( sub ) ; //last as long as the original string
}
//string(entity ent) etos = #65
void PF_etos ( progfuncs_t * prinst , struct globalvars_s * pr_globals )
{
char s [ 64 ] ;
snprintf ( s , sizeof ( s ) , " entity %i " , G_EDICTNUM ( prinst , OFS_PARM0 ) ) ;
RETURN_TSTRING ( s ) ;
}
//DP_QC_STRINGCOLORFUNCTIONS
// #476 float(string s) strlennocol - returns how many characters are in a string, minus color codes
void PF_strlennocol ( progfuncs_t * prinst , struct globalvars_s * pr_globals )
{
char * in = PR_GetStringOfs ( prinst , OFS_PARM0 ) ;
G_FLOAT ( OFS_RETURN ) = COM_FunStringLength ( in ) ;
}
//DP_QC_STRINGCOLORFUNCTIONS
// string (string s) strdecolorize - returns the passed in string with color codes stripped
void PF_strdecolorize ( progfuncs_t * prinst , struct globalvars_s * pr_globals )
{
char * in = PR_GetStringOfs ( prinst , OFS_PARM0 ) ;
char result [ 8192 ] ;
unsigned long flagged [ 8192 ] ;
COM_ParseFunString ( in , flagged , sizeof ( flagged ) / sizeof ( flagged [ 0 ] ) ) ;
COM_DeFunString ( flagged , result , sizeof ( result ) , true ) ;
RETURN_TSTRING ( result ) ;
}
//DP_QC_STRING_CASE_FUNCTIONS
void PF_strtolower ( progfuncs_t * prinst , struct globalvars_s * pr_globals )
{
char * in = PR_GetStringOfs ( prinst , OFS_PARM0 ) ;
char result [ 8192 ] ;
Q_strncpyz ( result , in , sizeof ( result ) ) ;
2008-11-18 03:10:48 +00:00
strtolower ( result ) ;
2008-11-09 22:29:28 +00:00
RETURN_TSTRING ( result ) ;
}
//DP_QC_STRING_CASE_FUNCTIONS
void PF_strtoupper ( progfuncs_t * prinst , struct globalvars_s * pr_globals )
{
char * in = PR_GetStringOfs ( prinst , OFS_PARM0 ) ;
char result [ 8192 ] ;
Q_strncpyz ( result , in , sizeof ( result ) ) ;
2008-11-18 03:10:48 +00:00
strtoupper ( result ) ;
2008-11-09 22:29:28 +00:00
RETURN_TSTRING ( result ) ;
}
//DP_QC_STRFTIME
void PF_strftime ( progfuncs_t * prinst , struct globalvars_s * pr_globals )
{
char * in = PF_VarString ( prinst , 1 , pr_globals ) ;
char result [ 8192 ] ;
time_t ctime ;
struct tm * tm ;
ctime = time ( NULL ) ;
if ( G_FLOAT ( OFS_PARM0 ) )
tm = localtime ( & ctime ) ;
else
tm = gmtime ( & ctime ) ;
strftime ( result , sizeof ( result ) , in , tm ) ;
Q_strncpyz ( result , in , sizeof ( result ) ) ;
2008-11-18 03:10:48 +00:00
strtoupper ( result ) ;
2008-11-09 22:29:28 +00:00
RETURN_TSTRING ( result ) ;
}
//String functions
////////////////////////////////////////////////////
//515's String functions
struct strbuf {
progfuncs_t * prinst ;
char * * strings ;
int used ;
int allocated ;
} ;
# define NUMSTRINGBUFS 16
struct strbuf strbuflist [ NUMSTRINGBUFS ] ;
// #440 float() buf_create (DP_QC_STRINGBUFFERS)
void PF_buf_create ( progfuncs_t * prinst , struct globalvars_s * pr_globals )
{
int i ;
for ( i = 0 ; i < NUMSTRINGBUFS ; i + + )
{
if ( ! strbuflist [ i ] . prinst )
{
strbuflist [ i ] . prinst = prinst ;
strbuflist [ i ] . used = 0 ;
strbuflist [ i ] . allocated = 0 ;
strbuflist [ i ] . strings = NULL ;
G_FLOAT ( OFS_RETURN ) = i + 1 ;
return ;
}
}
G_FLOAT ( OFS_RETURN ) = 0 ;
}
// #441 void(float bufhandle) buf_del (DP_QC_STRINGBUFFERS)
void PF_buf_del ( progfuncs_t * prinst , struct globalvars_s * pr_globals )
{
int i ;
int bufno = G_FLOAT ( OFS_PARM0 ) - 1 ;
if ( ( unsigned int ) bufno > = NUMSTRINGBUFS )
return ;
if ( strbuflist [ bufno ] . prinst ! = prinst )
return ;
for ( i = 0 ; i < strbuflist [ bufno ] . used ; i + + )
Z_Free ( strbuflist [ bufno ] . strings [ i ] ) ;
Z_Free ( strbuflist [ bufno ] . strings ) ;
strbuflist [ bufno ] . strings = NULL ;
strbuflist [ bufno ] . used = 0 ;
strbuflist [ bufno ] . allocated = 0 ;
strbuflist [ bufno ] . prinst = NULL ;
}
// #442 float(float bufhandle) buf_getsize (DP_QC_STRINGBUFFERS)
void PF_buf_getsize ( progfuncs_t * prinst , struct globalvars_s * pr_globals )
{
int bufno = G_FLOAT ( OFS_PARM0 ) - 1 ;
if ( ( unsigned int ) bufno > = NUMSTRINGBUFS )
return ;
if ( strbuflist [ bufno ] . prinst ! = prinst )
return ;
G_FLOAT ( OFS_RETURN ) = strbuflist [ bufno ] . used ;
}
// #443 void(float bufhandle_from, float bufhandle_to) buf_copy (DP_QC_STRINGBUFFERS)
void PF_buf_copy ( progfuncs_t * prinst , struct globalvars_s * pr_globals )
{
int buffrom = G_FLOAT ( OFS_PARM0 ) - 1 ;
int bufto = G_FLOAT ( OFS_PARM1 ) - 1 ;
if ( ( unsigned int ) buffrom > = NUMSTRINGBUFS )
return ;
if ( strbuflist [ buffrom ] . prinst ! = prinst )
return ;
if ( ( unsigned int ) bufto > = NUMSTRINGBUFS )
return ;
if ( strbuflist [ bufto ] . prinst ! = prinst )
return ;
//codeme
}
// #444 void(float bufhandle, float sortpower, float backward) buf_sort (DP_QC_STRINGBUFFERS)
void PF_buf_sort ( progfuncs_t * prinst , struct globalvars_s * pr_globals )
{
int bufno = G_FLOAT ( OFS_PARM0 ) - 1 ;
int sortpower = G_FLOAT ( OFS_PARM1 ) ;
int backwards = G_FLOAT ( OFS_PARM2 ) ;
if ( ( unsigned int ) bufno > = NUMSTRINGBUFS )
return ;
if ( strbuflist [ bufno ] . prinst ! = prinst )
return ;
//codeme
}
// #445 string(float bufhandle, string glue) buf_implode (DP_QC_STRINGBUFFERS)
void PF_buf_implode ( progfuncs_t * prinst , struct globalvars_s * pr_globals )
{
int bufno = G_FLOAT ( OFS_PARM0 ) - 1 ;
char * glue = PR_GetStringOfs ( prinst , OFS_PARM1 ) ;
if ( ( unsigned int ) bufno > = NUMSTRINGBUFS )
return ;
if ( strbuflist [ bufno ] . prinst ! = prinst )
return ;
//codeme
RETURN_TSTRING ( " " ) ;
}
// #446 string(float bufhandle, float string_index) bufstr_get (DP_QC_STRINGBUFFERS)
void PF_bufstr_get ( progfuncs_t * prinst , struct globalvars_s * pr_globals )
{
int bufno = G_FLOAT ( OFS_PARM0 ) - 1 ;
int index = G_FLOAT ( OFS_PARM1 ) ;
if ( ( unsigned int ) bufno > = NUMSTRINGBUFS )
{
RETURN_CSTRING ( " " ) ;
return ;
}
if ( strbuflist [ bufno ] . prinst ! = prinst )
{
RETURN_CSTRING ( " " ) ;
return ;
}
if ( index > = strbuflist [ bufno ] . used )
{
RETURN_CSTRING ( " " ) ;
return ;
}
RETURN_TSTRING ( strbuflist [ bufno ] . strings [ index ] ) ;
}
// #447 void(float bufhandle, float string_index, string str) bufstr_set (DP_QC_STRINGBUFFERS)
void PF_bufstr_set ( progfuncs_t * prinst , struct globalvars_s * pr_globals )
{
int bufno = G_FLOAT ( OFS_PARM0 ) - 1 ;
int index = G_FLOAT ( OFS_PARM1 ) ;
char * string = PR_GetStringOfs ( prinst , OFS_PARM2 ) ;
int oldcount ;
if ( ( unsigned int ) bufno > = NUMSTRINGBUFS )
return ;
if ( strbuflist [ bufno ] . prinst ! = prinst )
return ;
if ( index > = strbuflist [ bufno ] . allocated )
{
oldcount = strbuflist [ bufno ] . allocated ;
strbuflist [ bufno ] . allocated = ( index + 256 ) ;
strbuflist [ bufno ] . strings = BZ_Realloc ( strbuflist [ bufno ] . strings , strbuflist [ bufno ] . allocated * sizeof ( char * ) ) ;
memset ( strbuflist [ bufno ] . strings + oldcount , 0 , ( strbuflist [ bufno ] . allocated - oldcount ) * sizeof ( char * ) ) ;
}
strbuflist [ bufno ] . strings [ index ] = Z_Malloc ( strlen ( string ) + 1 ) ;
strcpy ( strbuflist [ bufno ] . strings [ index ] , string ) ;
if ( index > = strbuflist [ bufno ] . used )
strbuflist [ bufno ] . used = index + 1 ;
}
// #448 float(float bufhandle, string str, float order) bufstr_add (DP_QC_STRINGBUFFERS)
void PF_bufstr_add ( progfuncs_t * prinst , struct globalvars_s * pr_globals )
{
int bufno = G_FLOAT ( OFS_PARM0 ) - 1 ;
char * string = PR_GetStringOfs ( prinst , OFS_PARM1 ) ;
int order = G_FLOAT ( OFS_PARM2 ) ;
if ( ( unsigned int ) bufno > = NUMSTRINGBUFS )
return ;
if ( strbuflist [ bufno ] . prinst ! = prinst )
return ;
//codeme
G_FLOAT ( OFS_RETURN ) = 0 ;
}
// #449 void(float bufhandle, float string_index) bufstr_free (DP_QC_STRINGBUFFERS)
void PF_bufstr_free ( progfuncs_t * prinst , struct globalvars_s * pr_globals )
{
int bufno = G_FLOAT ( OFS_PARM0 ) - 1 ;
int index = G_FLOAT ( OFS_PARM1 ) ;
if ( ( unsigned int ) bufno > = NUMSTRINGBUFS )
return ;
if ( strbuflist [ bufno ] . prinst ! = prinst )
return ;
//codeme
}
//515's String functions
////////////////////////////////////////////////////
//float(float caseinsensitive, string s, ...) crc16 = #494 (DP_QC_CRC16)
void PF_crc16 ( progfuncs_t * prinst , struct globalvars_s * pr_globals )
{
int insens = G_FLOAT ( OFS_PARM0 ) ;
char * str = PF_VarString ( prinst , 1 , pr_globals ) ;
int len = strlen ( str ) ;
if ( insens )
G_FLOAT ( OFS_RETURN ) = QCRC_Block_AsLower ( str , len ) ;
else
G_FLOAT ( OFS_RETURN ) = QCRC_Block ( str , len ) ;
}
// #510 string(string in) uri_escape = #510;
void PF_uri_escape ( progfuncs_t * prinst , struct globalvars_s * pr_globals )
{
char * s = PR_GetStringOfs ( prinst , OFS_PARM0 ) ;
RETURN_TSTRING ( s ) ;
}
// #511 string(string in) uri_unescape = #511;
void PF_uri_unescape ( progfuncs_t * prinst , struct globalvars_s * pr_globals )
{
char * s = PR_GetStringOfs ( prinst , OFS_PARM0 ) ;
RETURN_TSTRING ( s ) ;
}
////////////////////////////////////////////////////
//Console functions
void PF_ArgC ( progfuncs_t * prinst , struct globalvars_s * pr_globals ) / / 85 / / float ( ) argc ;
{
G_FLOAT ( OFS_RETURN ) = Cmd_Argc ( ) ;
}
//KRIMZON_SV_PARSECLIENTCOMMAND added these two.
void PF_Tokenize ( progfuncs_t * prinst , struct globalvars_s * pr_globals ) / / 84 / / void ( string str ) tokanize ;
{
Cmd_TokenizeString ( PR_GetStringOfs ( prinst , OFS_PARM0 ) , false , true ) ;
G_FLOAT ( OFS_RETURN ) = Cmd_Argc ( ) ;
}
void PF_tokenizebyseparator ( progfuncs_t * prinst , struct globalvars_s * pr_globals )
{
Cmd_TokenizePunctation ( PR_GetStringOfs ( prinst , OFS_PARM0 ) , PR_GetStringOfs ( prinst , OFS_PARM1 ) ) ;
G_FLOAT ( OFS_RETURN ) = Cmd_Argc ( ) ;
}
void PF_ArgV ( progfuncs_t * prinst , struct globalvars_s * pr_globals ) / / 86 / / string ( float num ) argv ;
{
int i = G_FLOAT ( OFS_PARM0 ) ;
if ( i < 0 )
{
PR_BIError ( prinst , " pr_argv with i < 0 " ) ;
G_INT ( OFS_RETURN ) = 0 ;
return ;
}
RETURN_TSTRING ( Cmd_Argv ( i ) ) ;
}
//Console functions
////////////////////////////////////////////////////
//Maths functions
void PF_random ( progfuncs_t * prinst , struct globalvars_s * pr_globals )
{
float num ;
num = ( rand ( ) & 0x7fff ) / ( ( float ) 0x7fff ) ;
G_FLOAT ( OFS_RETURN ) = num ;
}
//float(float number, float quantity) bitshift = #218;
void PF_bitshift ( progfuncs_t * prinst , struct globalvars_s * pr_globals )
{
int bitmask ;
int shift ;
bitmask = G_FLOAT ( OFS_PARM0 ) ;
shift = G_FLOAT ( OFS_PARM1 ) ;
if ( shift < 0 )
bitmask > > = shift ;
else
bitmask < < = shift ;
G_FLOAT ( OFS_RETURN ) = bitmask ;
}
//float(float a, floats) min = #94
void PF_min ( progfuncs_t * prinst , struct globalvars_s * pr_globals )
{
int i ;
float f ;
if ( * prinst - > callargc = = 2 )
{
G_FLOAT ( OFS_RETURN ) = min ( G_FLOAT ( OFS_PARM0 ) , G_FLOAT ( OFS_PARM1 ) ) ;
}
else if ( * prinst - > callargc > = 3 )
{
f = G_FLOAT ( OFS_PARM0 ) ;
for ( i = 1 ; i < * prinst - > callargc ; i + + )
{
if ( G_FLOAT ( ( OFS_PARM0 + i * 3 ) ) < f )
f = G_FLOAT ( ( OFS_PARM0 + i * 3 ) ) ;
}
G_FLOAT ( OFS_RETURN ) = f ;
}
else
PR_BIError ( prinst , " PF_min: must supply at least 2 floats \n " ) ;
}
//float(float a, floats) max = #95
void PF_max ( progfuncs_t * prinst , struct globalvars_s * pr_globals )
{
int i ;
float f ;
if ( * prinst - > callargc = = 2 )
{
G_FLOAT ( OFS_RETURN ) = max ( G_FLOAT ( OFS_PARM0 ) , G_FLOAT ( OFS_PARM1 ) ) ;
}
else if ( * prinst - > callargc > = 3 )
{
f = G_FLOAT ( OFS_PARM0 ) ;
for ( i = 1 ; i < * prinst - > callargc ; i + + ) {
if ( G_FLOAT ( ( OFS_PARM0 + i * 3 ) ) > f )
f = G_FLOAT ( ( OFS_PARM0 + i * 3 ) ) ;
}
G_FLOAT ( OFS_RETURN ) = f ;
}
else
{
PR_BIError ( prinst , " PF_min: must supply at least 2 floats \n " ) ;
}
}
//float(float minimum, float val, float maximum) bound = #96
void PF_bound ( progfuncs_t * prinst , struct globalvars_s * pr_globals )
{
if ( G_FLOAT ( OFS_PARM1 ) > G_FLOAT ( OFS_PARM2 ) )
G_FLOAT ( OFS_RETURN ) = G_FLOAT ( OFS_PARM2 ) ;
else if ( G_FLOAT ( OFS_PARM1 ) < G_FLOAT ( OFS_PARM0 ) )
G_FLOAT ( OFS_RETURN ) = G_FLOAT ( OFS_PARM0 ) ;
else
G_FLOAT ( OFS_RETURN ) = G_FLOAT ( OFS_PARM1 ) ;
}
void PF_Sin ( progfuncs_t * prinst , struct globalvars_s * pr_globals )
{
G_FLOAT ( OFS_RETURN ) = sin ( G_FLOAT ( OFS_PARM0 ) ) ;
}
void PF_Cos ( progfuncs_t * prinst , struct globalvars_s * pr_globals )
{
G_FLOAT ( OFS_RETURN ) = cos ( G_FLOAT ( OFS_PARM0 ) ) ;
}
void PF_Sqrt ( progfuncs_t * prinst , struct globalvars_s * pr_globals )
{
G_FLOAT ( OFS_RETURN ) = sqrt ( G_FLOAT ( OFS_PARM0 ) ) ;
}
void PF_pow ( progfuncs_t * prinst , struct globalvars_s * pr_globals )
{
G_FLOAT ( OFS_RETURN ) = pow ( G_FLOAT ( OFS_PARM0 ) , G_FLOAT ( OFS_PARM1 ) ) ;
}
void PF_asin ( progfuncs_t * prinst , struct globalvars_s * pr_globals )
{
G_FLOAT ( OFS_RETURN ) = asin ( G_FLOAT ( OFS_PARM0 ) ) ;
}
void PF_acos ( progfuncs_t * prinst , struct globalvars_s * pr_globals )
{
G_FLOAT ( OFS_RETURN ) = acos ( G_FLOAT ( OFS_PARM0 ) ) ;
}
void PF_atan ( progfuncs_t * prinst , struct globalvars_s * pr_globals )
{
G_FLOAT ( OFS_RETURN ) = atan ( G_FLOAT ( OFS_PARM0 ) ) ;
}
void PF_atan2 ( progfuncs_t * prinst , struct globalvars_s * pr_globals )
{
G_FLOAT ( OFS_RETURN ) = atan2 ( G_FLOAT ( OFS_PARM0 ) , G_FLOAT ( OFS_PARM1 ) ) ;
}
void PF_tan ( progfuncs_t * prinst , struct globalvars_s * pr_globals )
{
G_FLOAT ( OFS_RETURN ) = tan ( G_FLOAT ( OFS_PARM0 ) ) ;
}
void PF_fabs ( progfuncs_t * prinst , struct globalvars_s * pr_globals )
{
float v ;
v = G_FLOAT ( OFS_PARM0 ) ;
G_FLOAT ( OFS_RETURN ) = fabs ( v ) ;
}
void PF_rint ( progfuncs_t * prinst , struct globalvars_s * pr_globals )
{
float f ;
f = G_FLOAT ( OFS_PARM0 ) ;
if ( f > 0 )
G_FLOAT ( OFS_RETURN ) = ( int ) ( f + 0.5 ) ;
else
G_FLOAT ( OFS_RETURN ) = ( int ) ( f - 0.5 ) ;
}
void PF_floor ( progfuncs_t * prinst , struct globalvars_s * pr_globals )
{
G_FLOAT ( OFS_RETURN ) = floor ( G_FLOAT ( OFS_PARM0 ) ) ;
}
void PF_ceil ( progfuncs_t * prinst , struct globalvars_s * pr_globals )
{
G_FLOAT ( OFS_RETURN ) = ceil ( G_FLOAT ( OFS_PARM0 ) ) ;
}
//Maths functions
////////////////////////////////////////////////////
//Vector functions
//vector() randomvec = #91
void PF_randomvector ( progfuncs_t * prinst , struct globalvars_s * pr_globals )
{
vec3_t temp ;
do
{
temp [ 0 ] = ( rand ( ) & 32767 ) * ( 2.0 / 32767.0 ) - 1.0 ;
temp [ 1 ] = ( rand ( ) & 32767 ) * ( 2.0 / 32767.0 ) - 1.0 ;
temp [ 2 ] = ( rand ( ) & 32767 ) * ( 2.0 / 32767.0 ) - 1.0 ;
} while ( DotProduct ( temp , temp ) > = 1 ) ;
VectorCopy ( temp , G_VECTOR ( OFS_RETURN ) ) ;
}
//float vectoyaw(vector)
void PF_vectoyaw ( progfuncs_t * prinst , struct globalvars_s * pr_globals )
{
float * value1 ;
float yaw ;
value1 = G_VECTOR ( OFS_PARM0 ) ;
if ( value1 [ 1 ] = = 0 & & value1 [ 0 ] = = 0 )
yaw = 0 ;
else
{
yaw = ( int ) ( atan2 ( value1 [ 1 ] , value1 [ 0 ] ) * 180 / M_PI ) ;
if ( yaw < 0 )
yaw + = 360 ;
}
G_FLOAT ( OFS_RETURN ) = yaw ;
}
//float(vector) vlen
void PF_vlen ( progfuncs_t * prinst , struct globalvars_s * pr_globals )
{
float * value1 ;
float newv ;
value1 = G_VECTOR ( OFS_PARM0 ) ;
newv = value1 [ 0 ] * value1 [ 0 ] + value1 [ 1 ] * value1 [ 1 ] + value1 [ 2 ] * value1 [ 2 ] ;
newv = sqrt ( newv ) ;
G_FLOAT ( OFS_RETURN ) = newv ;
}
//vector vectoangles(vector)
void PF_vectoangles ( progfuncs_t * prinst , struct globalvars_s * pr_globals )
{
float * value1 , * up ;
float yaw , pitch , roll ;
value1 = G_VECTOR ( OFS_PARM0 ) ;
if ( * prinst - > callargc > = 2 )
up = G_VECTOR ( OFS_PARM1 ) ;
else
up = NULL ;
if ( value1 [ 1 ] = = 0 & & value1 [ 0 ] = = 0 )
{
yaw = 0 ;
if ( value1 [ 2 ] > 0 )
{
pitch = 90 ;
yaw = up ? atan2 ( - up [ 1 ] , - up [ 0 ] ) : 0 ;
}
else
{
pitch = 270 ;
yaw = up ? atan2 ( up [ 1 ] , up [ 0 ] ) : 0 ;
}
roll = 0 ;
}
else
{
yaw = atan2 ( value1 [ 1 ] , value1 [ 0 ] ) ;
pitch = atan2 ( value1 [ 2 ] , sqrt ( value1 [ 0 ] * value1 [ 0 ] + value1 [ 1 ] * value1 [ 1 ] ) ) ;
if ( up )
{
vec_t cp = cos ( pitch ) , sp = sin ( pitch ) ;
vec_t cy = cos ( yaw ) , sy = sin ( yaw ) ;
vec3_t tleft , tup ;
tleft [ 0 ] = - sy ;
tleft [ 1 ] = cy ;
tleft [ 2 ] = 0 ;
tup [ 0 ] = sp * cy ;
tup [ 1 ] = sp * sy ;
tup [ 2 ] = cp ;
roll = - atan2 ( DotProduct ( up , tleft ) , DotProduct ( up , tup ) ) ;
}
else
roll = 0 ;
}
pitch * = 180 / M_PI ;
yaw * = 180 / M_PI ;
roll * = 180 / M_PI ;
if ( pitch < 0 )
pitch + = 360 ;
if ( yaw < 0 )
yaw + = 360 ;
if ( roll < 0 )
roll + = 360 ;
G_FLOAT ( OFS_RETURN + 0 ) = pitch ;
G_FLOAT ( OFS_RETURN + 1 ) = yaw ;
G_FLOAT ( OFS_RETURN + 2 ) = roll ;
}
//vector normalize(vector)
void PF_normalize ( progfuncs_t * prinst , struct globalvars_s * pr_globals )
{
float * value1 ;
vec3_t newvalue ;
float newf ;
value1 = G_VECTOR ( OFS_PARM0 ) ;
newf = value1 [ 0 ] * value1 [ 0 ] + value1 [ 1 ] * value1 [ 1 ] + value1 [ 2 ] * value1 [ 2 ] ;
newf = sqrt ( newf ) ;
if ( newf = = 0 )
newvalue [ 0 ] = newvalue [ 1 ] = newvalue [ 2 ] = 0 ;
else
{
newf = 1 / newf ;
newvalue [ 0 ] = value1 [ 0 ] * newf ;
newvalue [ 1 ] = value1 [ 1 ] * newf ;
newvalue [ 2 ] = value1 [ 2 ] * newf ;
}
VectorCopy ( newvalue , G_VECTOR ( OFS_RETURN ) ) ;
}
//Vector functions
////////////////////////////////////////////////////
//Progs internals
void PF_Abort ( progfuncs_t * prinst , struct globalvars_s * pr_globals )
{
prinst - > AbortStack ( prinst ) ;
}
//this func calls a function in annother progs
//it works in the same way as the above func, except that it calls by reference to a function, as opposed to by it's name
//used for entity function variables - not actually needed anymore
void PF_externrefcall ( progfuncs_t * prinst , struct globalvars_s * pr_globals )
{
int progsnum ;
func_t f ;
progsnum = G_PROG ( OFS_PARM0 ) ;
f = G_INT ( OFS_PARM1 ) ;
( * prinst - > pr_trace ) + + ; //continue debugging.
PR_ExecuteProgram ( prinst , f ) ;
}
void PF_externset ( progfuncs_t * prinst , struct globalvars_s * pr_globals ) //set a value in annother progs
{
int n = G_PROG ( OFS_PARM0 ) ;
int v = G_INT ( OFS_PARM1 ) ;
char * varname = PF_VarString ( prinst , 2 , pr_globals ) ;
eval_t * var ;
var = prinst - > FindGlobal ( prinst , varname , n ) ;
if ( var )
var - > _int = v ;
}
void PF_externvalue ( progfuncs_t * prinst , struct globalvars_s * pr_globals ) //return a value in annother progs
{
int n = G_PROG ( OFS_PARM0 ) ;
char * varname = PF_VarString ( prinst , 1 , pr_globals ) ;
eval_t * var ;
var = prinst - > FindGlobal ( prinst , varname , n ) ;
if ( var )
{
G_INT ( OFS_RETURN + 0 ) = ( ( int * ) & var - > _int ) [ 0 ] ;
G_INT ( OFS_RETURN + 1 ) = ( ( int * ) & var - > _int ) [ 1 ] ;
G_INT ( OFS_RETURN + 2 ) = ( ( int * ) & var - > _int ) [ 2 ] ;
}
else
G_INT ( OFS_RETURN ) = 0 ;
}
void PF_externcall ( progfuncs_t * prinst , struct globalvars_s * pr_globals ) //this func calls a function in annother progs (by name)
{
int progsnum ;
char * funcname ;
int i ;
string_t failedst = G_INT ( OFS_PARM1 ) ;
func_t f ;
progsnum = G_PROG ( OFS_PARM0 ) ;
funcname = PR_GetStringOfs ( prinst , OFS_PARM1 ) ;
f = PR_FindFunction ( prinst , funcname , progsnum ) ;
if ( f )
{
for ( i = OFS_PARM0 ; i < OFS_PARM5 ; i + = 3 )
VectorCopy ( G_VECTOR ( i + ( 2 * 3 ) ) , G_VECTOR ( i ) ) ;
( * prinst - > pr_trace ) + + ; //continue debugging
PR_ExecuteProgram ( prinst , f ) ;
}
else if ( ! f )
{
f = PR_FindFunction ( prinst , " MissingFunc " , progsnum ) ;
if ( ! f )
{
PR_BIError ( prinst , " Couldn't find function %s " , funcname ) ;
return ;
}
for ( i = OFS_PARM0 ; i < OFS_PARM6 ; i + = 3 )
VectorCopy ( G_VECTOR ( i + ( 1 * 3 ) ) , G_VECTOR ( i ) ) ;
G_INT ( OFS_PARM0 ) = failedst ;
( * prinst - > pr_trace ) + + ; //continue debugging
PR_ExecuteProgram ( prinst , f ) ;
}
}
/*
pr_csqc . obj : error LNK2001 : unresolved external symbol _ PR_BIError
*/
void PF_traceon ( progfuncs_t * prinst , struct globalvars_s * pr_globals )
{
( * prinst - > pr_trace ) = true ;
}
void PF_traceoff ( progfuncs_t * prinst , struct globalvars_s * pr_globals )
{
( * prinst - > pr_trace ) = false ;
}
void PF_coredump ( progfuncs_t * prinst , struct globalvars_s * pr_globals )
{
int size = 1024 * 1024 * 8 ;
char * buffer = BZ_Malloc ( size ) ;
prinst - > save_ents ( prinst , buffer , & size , 3 ) ;
COM_WriteFile ( " core.txt " , buffer , size ) ;
BZ_Free ( buffer ) ;
}
void PF_eprint ( progfuncs_t * prinst , struct globalvars_s * pr_globals )
{
int size = 1024 * 1024 ;
char * buffer = BZ_Malloc ( size ) ;
char * buf ;
buf = prinst - > saveent ( prinst , buffer , & size , G_EDICT ( prinst , OFS_PARM0 ) ) ;
Con_Printf ( " Entity %i: \n %s \n " , G_EDICTNUM ( prinst , OFS_PARM0 ) , buf ) ;
BZ_Free ( buffer ) ;
}
void PF_break ( progfuncs_t * prinst , struct globalvars_s * pr_globals )
{
# ifdef SERVERONLY //new break code
char * s ;
//I would like some sort of network activity here,
//but I don't want to mess up the sequence and stuff
//It should be possible, but would mean that I would
//need to alter the client, or rewrite a bit of the server..
if ( pr_globals )
Con_TPrintf ( STL_BREAKSTATEMENT ) ;
else if ( developer . value ! = 2 )
return ; //non developers cann't step.
for ( ; ; )
{
s = Sys_ConsoleInput ( ) ;
if ( s )
{
if ( ! * s )
break ;
else
Con_Printf ( " %s \n " , svprogfuncs - > EvaluateDebugString ( svprogfuncs , s ) ) ;
}
}
# elif defined(TEXTEDITOR)
( * prinst - > pr_trace ) + + ;
# else //old break code
Con_Printf ( " break statement \n " ) ;
* ( int * ) - 4 = 0 ; // dump to debugger
// PR_RunError ("break statement");
# endif
}
void PF_error ( progfuncs_t * prinst , struct globalvars_s * pr_globals )
{
char * s ;
s = PF_VarString ( prinst , 0 , pr_globals ) ;
/* Con_Printf ("======SERVER ERROR in %s:\n%s\n", PR_GetString(pr_xfunction->s_name) ,s);
ed = PROG_TO_EDICT ( pr_global_struct - > self ) ;
ED_Print ( ed ) ;
*/
PR_StackTrace ( prinst ) ;
Con_Printf ( " %s \n " , s ) ;
if ( developer . value )
{
// SV_Error ("Program error: %s", s);
PF_break ( prinst , pr_globals ) ;
( * prinst - > pr_trace ) = 2 ;
}
else
{
PR_AbortStack ( prinst ) ;
PR_BIError ( prinst , " Program error: %s " , s ) ;
}
}
//Progs internals
////////////////////////////////////////////////////
//System
//Sends text over to the client's execution buffer
void PF_localcmd ( progfuncs_t * prinst , struct globalvars_s * pr_globals )
{
char * str ;
str = PF_VarString ( prinst , 0 , pr_globals ) ;
if ( ! strcmp ( str , " host_framerate 0 \n " ) )
Cbuf_AddText ( " sv_mintic 0 \n " , RESTRICT_INSECURE ) ; //hmm... do this better...
else
Cbuf_AddText ( str , RESTRICT_INSECURE ) ;
}
/*
pr_csqc . obj : error LNK2001 : unresolved external symbol _PF_findchainflags
pr_csqc . obj : error LNK2001 : unresolved external symbol _PF_findchainfloat
pr_csqc . obj : error LNK2001 : unresolved external symbol _PF_findchain
pr_csqc . obj : error LNK2001 : unresolved external symbol _PF_cl_getkeybind
pr_csqc . obj : error LNK2001 : unresolved external symbol _PF_cl_stringtokeynum
pr_csqc . obj : error LNK2001 : unresolved external symbol _PF_cl_keynumtostring
pr_csqc . obj : error LNK2001 : unresolved external symbol _PF_CL_drawresetcliparea
pr_csqc . obj : error LNK2001 : unresolved external symbol _PF_CL_drawsetcliparea
pr_csqc . obj : error LNK2001 : unresolved external symbol _PF_CL_drawfill
pr_csqc . obj : error LNK2001 : unresolved external symbol _PF_CL_drawpic
pr_csqc . obj : error LNK2001 : unresolved external symbol _PF_CL_drawstring
pr_csqc . obj : error LNK2001 : unresolved external symbol _PF_CL_drawcharacter
pr_csqc . obj : error LNK2001 : unresolved external symbol _PF_CL_free_pic
pr_csqc . obj : error LNK2001 : unresolved external symbol _PF_CL_drawgetimagesize
pr_csqc . obj : error LNK2001 : unresolved external symbol _PF_CL_precache_pic
pr_csqc . obj : error LNK2001 : unresolved external symbol _PF_CL_is_cached_pic
pr_csqc . obj : error LNK2001 : unresolved external symbol _PF_CL_drawline
pr_csqc . obj : error LNK2001 : unresolved external symbol _checkfteextensionsv
pr_csqc . obj : error LNK2001 : unresolved external symbol _checkextension
pr_csqc . obj : error LNK2001 : unresolved external symbol _QCEditor
pr_csqc . obj : error LNK2001 : unresolved external symbol _PR_CB_Free
pr_csqc . obj : error LNK2001 : unresolved external symbol _PR_CB_Malloc
pr_csqc . obj : error LNK2001 : unresolved external symbol _QC_WriteFile
pr_csqc . obj : error LNK2001 : unresolved external symbol _MP_TranslateFTEtoDPCodes
*/
lh_extension_t QSG_Extensions [ ] = {
//as a special hack, the first 32 entries are PEXT features.
//some of these are overkill yes, but they are all derived from the fteextensions flags and document the underlaying protocol available.
//(which is why there are two lists of extensions here)
//note: not all of these are actually supported. This list mearly reflects the values of the PEXT_ constants.
//Check protocol.h to make sure that the related PEXT is enabled. The engine will only accept if they are actually supported.
{ " FTE_PEXT_SETVIEW " } , //nq setview works.
{ " DP_ENT_SCALE " } , //entities may be rescaled
{ " FTE_PEXT_LIGHTSTYLECOL " } , //lightstyles may have colours.
{ " DP_ENT_ALPHA " } , //transparent entites
{ " FTE_PEXT_VIEW2 " } , //secondary view.
{ " FTE_PEXT_BULLETENS " } , //bulleten boards (scrolling text on walls)
2008-11-28 20:34:51 +00:00
{ " FTE_PEXT_ACURATETIMINGS " } , //allows full interpolation
{ " FTE_PEXT_SOUNDDBL " } , //twice the sound indexes
2008-11-09 22:29:28 +00:00
{ " FTE_PEXT_FATNESS " } , //entities may be expanded along their vertex normals
{ " DP_HALFLIFE_MAP " } , //entitiy can visit a hl bsp
{ " FTE_PEXT_TE_BULLET " } , //additional particle effect. Like TE_SPIKE and TE_SUPERSPIKE
{ " FTE_PEXT_HULLSIZE " } , //means we can tell a client to go to crouching hull
2008-11-28 20:34:51 +00:00
{ " FTE_PEXT_MODELDBL " } , //max of 512 models/sounds
2008-11-09 22:29:28 +00:00
{ " FTE_PEXT_ENTITYDBL " } , //max of 1024 ents
{ " FTE_PEXT_ENTITYDBL2 " } , //max of 2048 ents
{ " FTE_PEXT_ORIGINDBL " } , //-8k to +8k map size.
{ " FTE_PEXT_VWEAP " } ,
{ " FTE_PEXT_Q2BSP " } , //supports q2 maps. No bugs are apparent.
{ " FTE_PEXT_Q3BSP " } , //quake3 bsp support. dp probably has an equivelent, but this is queryable per client.
{ " DP_ENT_COLORMOD " } ,
{ NULL } , //splitscreen - not queryable.
{ " FTE_HEXEN2 " } , //client can use hexen2 maps. server can use hexen2 progs
{ " FTE_PEXT_SPAWNSTATIC " } , //means that static entities can have alpha/scale and anything else the engine supports on normal ents. (Added for >256 models, while still being compatible - previous system failed with -1 skins)
{ " FTE_PEXT_CUSTOMTENTS " , 2 , NULL , { " RegisterTempEnt " , " CustomTempEnt " } } ,
{ " FTE_PEXT_256PACKETENTITIES " } , //client is able to receive unlimited packet entities (server caps itself to 256 to prevent insanity).
{ " FTE_PEXT_64PLAYERS " } ,
{ " TEI_SHOWLMP2 " , 6 , NULL , { " showpic " , " hidepic " , " movepic " , " changepic " , " showpicent " , " hidepicent " } } , //telejano doesn't actually export the moveent/changeent (we don't want to either cos it would stop frik_file stuff being autoregistered)
{ " DP_GFX_QUAKE3MODELTAGS " , 1 , NULL , { " setattachment " } } ,
{ " FTE_PK3DOWNLOADS " } ,
{ " PEXT_CHUNKEDDOWNLOADS " } ,
{ " EXT_CSQC_SHARED " } , //this is a separate extension because it requires protocol modifications. note: this is also the extension that extends the allowed stats.
{ NULL } ,
//{"EXT_CSQC"}, //this is the base csqc extension. I'm not sure what needs to be separate and what does not.
//{"EXT_CSQC_DELTAS"},//this is a separate extension because a: its slower thus optional. b: the feature may be banned in a league due to cheat protection.
//the rest are generic extensions
{ " ??TOMAZ_STRINGS " , 6 , NULL , { " tq_zone " , " tq_unzone " , " tq_strcat " , " tq_substring " , " tq_stof " , " tq_stov " } } ,
{ " ??TOMAZ_FILE " , 4 , NULL , { " tq_fopen " , " tq_fclose " , " tq_fgets " , " tq_fputs " } } ,
{ " ??MVDSV_BUILTINS " , 21 , NULL , { " executecommand " , " mvdtokenize " , " mvdargc " , " mvdargv " ,
" teamfield " , " substr " , " mvdstrcat " , " mvdstrlen " , " str2byte " ,
" str2short " , " mvdnewstr " , " mvdfreestr " , " conprint " , " readcmd " ,
" mvdstrcpy " , " strstr " , " mvdstrncpy " , " log " , " redirectcmd " ,
" mvdcalltimeofday " , " forcedemoframe " } } ,
//end of mvdsv
// Tomaz - QuakeC File System End
{ " BX_COLOREDTEXT " } ,
{ " DP_CON_SET " } ,
# ifndef SERVERONLY
{ " DP_CON_SETA " } , //because the server doesn't write configs.
# endif
{ " DP_EF_BLUE " } , //hah!! This is QuakeWorld!!!
{ " DP_EF_FULLBRIGHT " } , //Rerouted to hexen2 support.
{ " DP_EF_NODRAW " } , //implemented by sending it with no modelindex
{ " DP_EF_RED " } ,
{ " DP_ENT_COLORMOD " } ,
{ " DP_ENT_EXTERIORMODELTOCLIENT " } ,
//only in dp6 currently {"DP_ENT_GLOW"},
{ " DP_ENT_VIEWMODEL " } ,
{ " DP_GECKO_SUPPORT " , 7 , NULL , { " gecko_create " , " gecko_destroy " , " gecko_navigate " , " gecko_keyevent " , " gecko_mousemove " , " gecko_resize " , " gecko_get_texture_extent " } } ,
{ " DP_GFX_QUAKE3MODELTAGS " } ,
{ " DP_GFX_SKINFILES " } ,
{ " DP_GFX_SKYBOX " } , //according to the spec. :)
{ " DP_HALFLIFE_MAP_CVAR " } ,
//to an extend {"DP_HALFLIFE_SPRITE"},
{ " DP_INPUTBUTTONS " } ,
{ " DP_LITSUPPORT " } ,
{ " DP_MONSTERWALK " } ,
{ " DP_MOVETYPEBOUNCEMISSILE " } , //I added the code for hexen2 support.
{ " DP_MOVETYPEFOLLOW " } ,
{ " DP_QC_ASINACOSATANATAN2TAN " , 5 , NULL , { " asin " , " acos " , " atan " , " atan2 " , " tan " } } ,
{ " DP_QC_CHANGEPITCH " , 1 , NULL , { " changepitch " } } ,
{ " DP_QC_COPYENTITY " , 1 , NULL , { " copyentity " } } ,
{ " DP_QC_CRC16 " , 1 , NULL , { " crc16 " } } ,
{ " DP_QC_CVAR_DEFSTRING " , 1 , NULL , { " cvar_defstring " } } ,
{ " DP_QC_CVAR_STRING " , 1 , NULL , { " dp_cvar_string " } } , //448 builtin.
{ " DP_QC_CVAR_TYPE " , 1 , NULL , { " cvar_type " } } ,
{ " DP_QC_EDICT_NUM " , 1 , NULL , { " edict_num " } } ,
{ " DP_QC_ENTITYDATA " , 5 , NULL , { " numentityfields " , " entityfieldname " , " entityfieldtype " , " getentityfieldstring " , " putentityfieldstring " } } ,
{ " DP_QC_ETOS " , 1 , NULL , { " etos " } } ,
{ " DP_QC_FINDCHAIN " , 1 , NULL , { " findchain " } } ,
{ " DP_QC_FINDCHAINFLOAT " , 1 , NULL , { " findchainfloat " } } ,
{ " DP_QC_FINDFLAGS " , 1 , NULL , { " findflags " } } ,
{ " DP_QC_FINDCHAINFLAGS " , 1 , NULL , { " findchainflags " } } ,
{ " DP_QC_FINDFLOAT " , 1 , NULL , { " findfloat " } } ,
{ " DP_QC_FS_SEARCH " , 4 , NULL , { " search_begin " , " search_end " , " search_getsize " , " search_getfilename " } } ,
{ " DP_QC_GETSURFACEPOINTATTRIBUTE " , 1 , NULL , { " getsurfacepointattribute " } } ,
{ " DP_QC_MINMAXBOUND " , 3 , NULL , { " min " , " max " , " bound " } } ,
{ " DP_QC_MULTIPLETEMPSTRINGS " } ,
{ " DP_QC_RANDOMVEC " , 1 , NULL , { " randomvec " } } ,
{ " DP_QC_SINCOSSQRTPOW " , 4 , NULL , { " sin " , " cos " , " sqrt " , " pow " } } ,
{ " DP_QC_STRFTIME " , 1 , NULL , { " strftime " } } ,
{ " DP_QC_STRING_CASE_FUNCTIONS " , 2 , NULL , { " strtolower " , " strtoupper " } } ,
{ " DP_QC_STRINGBUFFERS " , 10 , NULL , { " buf_create " , " buf_del " , " buf_getsize " , " buf_copy " , " buf_sort " , " buf_implode " , " bufstr_get " , " bufstr_set " , " bufstr_add " , " bufstr_free " } } ,
{ " DP_QC_STRINGCOLORFUNCTIONS " , 2 , NULL , { " strlennocol " , " strdecolorize " } } ,
{ " DP_QC_STRREPLACE " , 2 , NULL , { " strreplace " , " strireplace " } } ,
{ " DP_QC_TOKENIZEBYSEPARATOR " , 1 , NULL , { " tokenizebyseparator " } } ,
{ " DP_QC_TRACEBOX " , 1 , NULL , { " tracebox " } } ,
{ " DP_QC_TRACETOSS " } ,
{ " DP_QC_TRACE_MOVETYPE_HITMODEL " } ,
{ " DP_QC_TRACE_MOVETYPE_WORLDONLY " } ,
{ " DP_QC_TRACE_MOVETYPES " } , //this one is just a lame excuse to add annother extension...
{ " DP_QC_UNLIMITEDTEMPSTRINGS " } ,
{ " DP_QC_URI_ESCAPE " , 2 , NULL , { " uri_escape " , " uri_unescape " } } ,
{ " DP_QC_URI_GET " , 1 , NULL , { " uri_get " } } ,
{ " DP_QC_VECTOANGLES_WITH_ROLL " } ,
{ " DP_QC_VECTORVECTORS " , 1 , NULL , { " vectorvectors " } } ,
{ " DP_QC_WHICHPACK " , 1 , NULL , { " whichpack " } } ,
{ " DP_QUAKE2_MODEL " } ,
{ " DP_QUAKE2_SPRITE " } ,
{ " DP_QUAKE3_MODEL " } ,
{ " DP_REGISTERCVAR " , 1 , NULL , { " registercvar " } } ,
{ " DP_SND_STEREOWAV " } ,
{ " DP_SND_OGGVORBIS " } ,
{ " DP_SOLIDCORPSE " } ,
{ " DP_SPRITE32 " } , //hmm... is it legal to advertise this one?
{ " DP_SV_BOTCLIENT " , 2 , NULL , { " spawnclient " , " clienttype " } } ,
{ " DP_SV_CLIENTCOLORS " } ,
{ " DP_SV_CLIENTNAME " } ,
{ " DP_SV_DRAWONLYTOCLIENT " } ,
{ " DP_SV_DROPCLIENT " , 1 , NULL , { " dropclient " } } ,
{ " DP_SV_EFFECT " , 1 , NULL , { " effect " } } ,
{ " DP_SV_EXTERIORMODELFORCLIENT " } ,
{ " DP_SV_NODRAWTOCLIENT " } , //I prefer my older system. Guess I might as well remove that older system at some point.
{ " DP_SV_PLAYERPHYSICS " } ,
{ " DP_SV_POINTSOUND " , 1 , NULL , { " pointsound " } } ,
{ " DP_SV_PRECACHEANYTIME " } ,
{ " DP_SV_SETCOLOR " } ,
{ " DP_SV_SPAWNFUNC_PREFIX " } ,
{ " DP_SV_WRITEPICTURE " , 1 , NULL , { " WritePicture " } } ,
{ " DP_SV_WRITEUNTERMINATEDSTRING " , 1 , NULL , { " WriteUnterminatedString " } } ,
{ " DP_TE_BLOOD " , 1 , NULL , { " te_blood " } } ,
{ " DP_TE_BLOODSHOWER " , 1 , NULL , { " te_bloodshower " } } ,
{ " DP_TE_CUSTOMFLASH " , 1 , NULL , { " te_customflash " } } ,
{ " DP_TE_EXPLOSIONRGB " } ,
{ " DP_TE_FLAMEJET " , 1 , NULL , { " te_flamejet " } } ,
{ " DP_TE_PARTICLECUBE " , 1 , NULL , { " te_particlecube " } } ,
//particlerain
//particlesnow
{ " DP_TE_PLASMABURN " , 1 , NULL , { " te_plasmaburn " } } ,
{ " DP_TE_QUADEFFECTS1 " } ,
{ " DP_TE_SMALLFLASH " , 1 , NULL , { " te_smallflash " } } ,
{ " DP_TE_SPARK " , 1 , NULL , { " te_spark " } } ,
{ " DP_TE_STANDARDEFFECTBUILTINS " , 14 , NULL , { " te_gunshot " , " te_spike " , " te_superspike " , " te_explosion " , " te_tarexplosion " , " te_wizspike " , " te_knightspike " , " te_lavasplash " , " te_teleport " , " te_explosion2 " , " te_lightning1 " , " te_lightning2 " , " te_lightning3 " , " te_beam " } } ,
{ " DP_VIEWZOOM " } ,
{ " EXT_BITSHIFT " , 1 , NULL , { " bitshift " } } ,
{ " EXT_DIMENSION_VISIBILITY " } ,
{ " EXT_DIMENSION_PHYSICS " } ,
{ " EXT_DIMENSION_GHOST " } ,
{ " FRIK_FILE " , 11 , NULL , { " stof " , " fopen " , " fclose " , " fgets " , " fputs " , " strlen " , " strcat " , " substring " , " stov " , " strzone " , " strunzone " } } ,
{ " FTE_CALLTIMEOFDAY " , 1 , NULL , { " calltimeofday " } } ,
{ " FTE_CSQC_HALFLIFE_MODELS " } , //hl-specific skeletal model control
//implementme {"FTE_CSQC_BASEFRAME"}, //control for all skeletal models
{ " FTE_ENT_UNIQUESPAWNID " } ,
{ " FTE_EXTENDEDTEXTCODES " } ,
{ " FTE_FORCEINFOKEY " , 1 , NULL , { " forceinfokey " } } ,
{ " FTE_GFX_QUAKE3SHADERS " } ,
{ " FTE_ISBACKBUFFERED " , 1 , NULL , { " isbackbuffered " } } ,
# ifndef NOMEDIA
{ " FTE_MEDIA_AVI " } , //playfilm supports avi files.
{ " FTE_MEDIA_CIN " } , //playfilm command supports q2 cin files.
{ " FTE_MEDIA_ROQ " } , //playfilm command supports q3 roq files
# endif
{ " FTE_MULTIPROGS " } , //multiprogs functions are available.
{ " FTE_MULTITHREADED " , 3 , NULL , { " sleep " , " fork " , " abort " } } ,
{ " FTE_MVD_PLAYBACK " } ,
# ifdef SVCHAT
{ " FTE_NPCCHAT " , 1 , NULL , { " chat " } } , //server looks at chat files. It automagically branches through calling qc functions as requested.
# endif
{ " FTE_QC_CHECKPVS " , 1 , NULL , { " checkpvs " } } ,
{ " FTE_QC_MATCHCLIENTNAME " , 1 , NULL , { " matchclientname " } } ,
{ " FTE_QC_PAUSED " } ,
{ " FTE_QC_SENDPACKET " , 1 , NULL , { " sendpacket " } } ,
{ " FTE_QC_TRACETRIGGER " } ,
{ " FTE_SOLID_LADDER " } , //part of a worthy hl implementation. Allows a simple trigger to remove effects of gravity (solid 20)
# ifdef SQL
// serverside SQL functions for managing an SQL database connection
{ " FTE_SQL " , 9 , NULL , { " sqlconnect " , " sqldisconnect " , " sqlopenquery " , " sqlclosequery " , " sqlreadfield " , " sqlerror " , " sqlescape " , " sqlversion " ,
" sqlreadfloat " } } ,
# endif
//eperimental advanced strings functions.
//reuses the FRIK_FILE builtins (with substring extension)
{ " FTE_STRINGS " , 16 , NULL , { " stof " , " strlen " , " strcat " , " substring " , " stov " , " strzone " , " strunzone " ,
" strstrofs " , " str2chr " , " chr2str " , " strconv " , " infoadd " , " infoget " , " strncmp " , " strcasecmp " , " strncasecmp " } } ,
{ " FTE_SV_REENTER " } ,
{ " FTE_TE_STANDARDEFFECTBUILTINS " , 14 , NULL , { " te_gunshot " , " te_spike " , " te_superspike " , " te_explosion " , " te_tarexplosion " , " te_wizspike " , " te_knightspike " , " te_lavasplash " ,
" te_teleport " , " te_lightning1 " , " te_lightning2 " , " te_lightning3 " , " te_lightningblood " , " te_bloodqw " } } ,
{ " KRIMZON_SV_PARSECLIENTCOMMAND " , 3 , NULL , { " clientcommand " , " tokenize " , " argv " } } , //very very similar to the mvdsv system.
{ " NEH_CMD_PLAY2 " } ,
{ " NEH_RESTOREGAME " } ,
//{"PRYDON_CLIENTCURSOR"},
{ " QSG_CVARSTRING " , 1 , NULL , { " qsg_cvar_string " } } ,
{ " QW_ENGINE " , 3 , NULL , { " infokey " , " stof " , " logfrag " } } , //warning: interpretation of .skin on players can be dodgy, as can some other QW features that differ from NQ.
{ " QWE_MVD_RECORD " } , //Quakeworld extended get the credit for this one. (mvdsv)
{ " TEI_MD3_MODEL " } ,
// {"TQ_RAILTRAIL"}, //treat this as the ZQ style railtrails which the client already supports, okay so the preparse stuff needs strengthening.
{ " ZQ_MOVETYPE_FLY " } ,
{ " ZQ_MOVETYPE_NOCLIP " } ,
{ " ZQ_MOVETYPE_NONE " } ,
// {"ZQ_QC_PARTICLE"}, //particle builtin works in QW ( we don't mimic ZQ fully though)
{ " ZQ_QC_STRINGS " , 7 , NULL , { " stof " , " strlen " , " strcat " , " substring " , " stov " , " strzone " , " strunzone " } } //a trimmed down FRIK_FILE.
} ;
unsigned int QSG_Extensions_count = sizeof ( QSG_Extensions ) / sizeof ( QSG_Extensions [ 0 ] ) ;
# endif