2011-03-04 12:49:41 +00:00
/*
* OpenClonk , http : //www.openclonk.org
*
2013-12-17 20:01:09 +00:00
* Copyright ( c ) 1998 - 2000 , Matthes Bender
* Copyright ( c ) 2001 - 2009 , RedWolf Design GmbH , http : //www.clonk.de/
* Copyright ( c ) 2009 - 2013 , The OpenClonk Team and contributors
2011-03-04 12:49:41 +00:00
*
2013-12-17 20:01:09 +00:00
* Distributed under the terms of the ISC license ; see accompanying file
* " COPYING " for details .
2011-03-04 12:49:41 +00:00
*
2013-12-17 20:01:09 +00:00
* " Clonk " is a registered trademark of Matthes Bender , used with permission .
* See accompanying file " TRADEMARK " for details .
2011-03-04 12:49:41 +00:00
*
2013-12-17 20:01:09 +00:00
* To redistribute this file separately , substitute the full license texts
* for the above references .
2011-03-04 12:49:41 +00:00
*/
/* Functions mapped by C4Script */
# include <C4Include.h>
# include <C4AulDefFunc.h>
# include <C4AulExec.h>
# include <C4Random.h>
# include <C4Version.h>
//========================== Some Support Functions =======================================
2012-05-19 16:34:17 +00:00
StdStrBuf FnStringFormat ( C4PropList * _this , C4String * szFormatPar , C4Value * Pars , int ParCount )
2011-03-04 12:49:41 +00:00
{
int cPar = 0 ;
StdStrBuf StringBuf ( " " , false ) ;
2012-05-19 16:34:17 +00:00
const char * cpFormat = FnStringPar ( szFormatPar ) ;
2011-03-04 12:49:41 +00:00
const char * cpType ;
2012-05-19 16:34:17 +00:00
char szField [ 20 ] ;
2011-03-04 12:49:41 +00:00
while ( * cpFormat )
{
// Copy normal stuff
while ( * cpFormat & & ( * cpFormat ! = ' % ' ) )
StringBuf . AppendChar ( * cpFormat + + ) ;
// Field
if ( * cpFormat = = ' % ' )
{
// Scan field type
2014-02-17 22:10:50 +00:00
for ( cpType = cpFormat + 1 ; * cpType & & ( * cpType = = ' + ' | | * cpType = = ' - ' | | * cpType = = ' . ' | | * cpType = = ' # ' | | * cpType = = ' ' | | Inside ( * cpType , ' 0 ' , ' 9 ' ) ) ; cpType + + ) { }
2011-03-04 12:49:41 +00:00
// Copy field
2015-11-15 12:53:01 +00:00
SCopy ( cpFormat , szField , std : : min < unsigned int > ( sizeof szField - 1 , cpType - cpFormat + 1 ) ) ;
2011-03-04 12:49:41 +00:00
// Insert field by type
switch ( * cpType )
{
// number
2011-03-09 23:26:31 +00:00
case ' d ' : case ' x ' : case ' X ' :
2011-03-04 12:49:41 +00:00
{
2015-12-07 14:15:49 +00:00
if ( cPar > = ParCount ) throw C4AulExecError ( " format placeholder without parameter " ) ;
2012-05-19 16:34:17 +00:00
StringBuf . AppendFormat ( szField , Pars [ cPar + + ] . getInt ( ) ) ;
2011-03-04 12:49:41 +00:00
cpFormat + = SLen ( szField ) ;
break ;
}
2011-03-09 23:26:31 +00:00
// character
case ' c ' :
{
2015-12-07 14:15:49 +00:00
if ( cPar > = ParCount ) throw C4AulExecError ( " format placeholder without parameter " ) ;
2012-05-19 16:34:17 +00:00
StringBuf . AppendCharacter ( Pars [ cPar + + ] . getInt ( ) ) ;
2011-03-09 23:26:31 +00:00
cpFormat + = SLen ( szField ) ;
break ;
}
2011-03-04 12:49:41 +00:00
// C4ID
case ' i ' :
// C4Value
case ' v ' :
{
2015-12-07 14:15:49 +00:00
if ( cPar > = ParCount ) throw C4AulExecError ( " format placeholder without parameter " ) ;
2012-05-19 16:34:17 +00:00
StringBuf . Append ( static_cast < const StdStrBuf & > ( Pars [ cPar + + ] . GetDataString ( 10 ) ) ) ;
2011-03-04 12:49:41 +00:00
cpFormat + = SLen ( szField ) ;
break ;
}
// String
case ' s ' :
{
// get string
2015-12-07 14:15:49 +00:00
if ( cPar > = ParCount ) throw C4AulExecError ( " format placeholder without parameter " ) ;
2011-03-04 12:49:41 +00:00
const char * szStr = " (null) " ;
2012-05-19 16:34:17 +00:00
if ( Pars [ cPar ] . GetData ( ) )
2011-03-04 12:49:41 +00:00
{
2012-05-19 16:34:17 +00:00
C4String * pStr = Pars [ cPar ] . getStr ( ) ;
2015-12-07 14:15:49 +00:00
if ( ! pStr ) throw C4AulExecError ( " string format placeholder without string " ) ;
2011-03-04 12:49:41 +00:00
szStr = pStr - > GetCStr ( ) ;
}
2012-05-19 16:34:17 +00:00
+ + cPar ;
2011-03-04 12:49:41 +00:00
StringBuf . AppendFormat ( szField , szStr ) ;
cpFormat + = SLen ( szField ) ;
break ;
}
case ' % ' :
StringBuf . AppendChar ( ' % ' ) ;
cpFormat + = SLen ( szField ) ;
break ;
// Undefined / Empty
default :
StringBuf . AppendChar ( ' % ' ) ;
cpFormat + + ;
break ;
}
}
}
return StringBuf ;
}
bool C4ValueToMatrix ( C4Value & value , StdMeshMatrix * matrix )
{
const C4ValueArray * array = value . getArray ( ) ;
if ( ! array ) return false ;
return C4ValueToMatrix ( * array , matrix ) ;
}
bool C4ValueToMatrix ( const C4ValueArray & array , StdMeshMatrix * matrix )
{
if ( array . GetSize ( ) ! = 12 ) return false ;
StdMeshMatrix & trans = * matrix ;
trans ( 0 , 0 ) = array [ 0 ] . getInt ( ) / 1000.0f ;
trans ( 0 , 1 ) = array [ 1 ] . getInt ( ) / 1000.0f ;
trans ( 0 , 2 ) = array [ 2 ] . getInt ( ) / 1000.0f ;
trans ( 0 , 3 ) = array [ 3 ] . getInt ( ) / 1000.0f ;
trans ( 1 , 0 ) = array [ 4 ] . getInt ( ) / 1000.0f ;
trans ( 1 , 1 ) = array [ 5 ] . getInt ( ) / 1000.0f ;
trans ( 1 , 2 ) = array [ 6 ] . getInt ( ) / 1000.0f ;
trans ( 1 , 3 ) = array [ 7 ] . getInt ( ) / 1000.0f ;
trans ( 2 , 0 ) = array [ 8 ] . getInt ( ) / 1000.0f ;
trans ( 2 , 1 ) = array [ 9 ] . getInt ( ) / 1000.0f ;
trans ( 2 , 2 ) = array [ 10 ] . getInt ( ) / 1000.0f ;
trans ( 2 , 3 ) = array [ 11 ] . getInt ( ) / 1000.0f ;
return true ;
}
2012-05-20 00:39:57 +00:00
C4AulDefFunc : : C4AulDefFunc ( C4AulScript * pOwner , C4ScriptFnDef * pDef ) :
C4AulFunc ( pOwner , pDef - > Identifier ) , Def ( pDef )
{
Owner - > GetPropList ( ) - > SetPropertyByS ( Name , C4VFunction ( this ) ) ;
}
C4AulDefFunc : : ~ C4AulDefFunc ( )
{
}
C4Value C4AulDefFunc : : Exec ( C4PropList * p , C4Value pPars [ ] , bool fPassErrors )
{
assert ( Def - > FunctionC4V ) ;
return Def - > FunctionC4V ( p , pPars ) ;
}
2011-03-04 12:49:41 +00:00
//=============================== C4Script Functions ====================================
2013-07-07 13:54:35 +00:00
# define MAKE_AND_RETURN_ARRAY(values) do { \
C4ValueArray * matrix = new C4ValueArray ( sizeof ( values ) / sizeof ( * values ) ) ; \
2015-01-02 19:55:48 +00:00
for ( size_t i = 0 ; i < sizeof ( values ) / sizeof ( * values ) ; + + i ) \
2013-07-07 13:54:35 +00:00
( * matrix ) [ i ] = C4VInt ( values [ i ] ) ; \
return matrix ; \
} while ( 0 )
static C4ValueArray * FnTrans_Identity ( C4PropList * _this )
{
long values [ ] =
{
1000 , 0 , 0 , 0 ,
0 , 1000 , 0 , 0 ,
0 , 0 , 1000 , 0
} ;
MAKE_AND_RETURN_ARRAY ( values ) ;
}
static C4ValueArray * FnTrans_Translate ( C4PropList * _this , long dx , long dy , long dz )
{
long values [ ] =
{
1000 , 0 , 0 , dx ,
0 , 1000 , 0 , dy ,
0 , 0 , 1000 , dz
} ;
MAKE_AND_RETURN_ARRAY ( values ) ;
}
static C4ValueArray * FnTrans_Scale ( C4PropList * _this , long sx , long sy , long sz )
{
if ( sy = = 0 & & sz = = 0 )
sy = sz = sx ;
long values [ ] =
{
sx , 0 , 0 , 0 ,
0 , sy , 0 , 0 ,
0 , 0 , sz , 0
} ;
MAKE_AND_RETURN_ARRAY ( values ) ;
}
static C4ValueArray * FnTrans_Rotate ( C4PropList * _this , long angle , long rx , long ry , long rz )
{
long c = fixtoi ( Cos ( itofix ( angle , 1 ) ) , 1000 ) ;
long s = fixtoi ( Sin ( itofix ( angle , 1 ) ) , 1000 ) ;
long sqrt_val = rx * rx + ry * ry + rz * rz ;
long n = long ( sqrt ( double ( sqrt_val ) ) ) ;
if ( n * n < sqrt_val ) n + + ;
else if ( n * n > sqrt_val ) n - - ;
rx = ( 1000 * rx ) / n ;
ry = ( 1000 * ry ) / n ;
rz = ( 1000 * rz ) / n ;
long values [ ] =
{
rx * rx * ( 1000 - c ) / 1000000 + c , rx * ry * ( 1000 - c ) / 1000000 - rz * s / 1000 , rx * rz * ( 1000 - c ) / 1000000 + ry * s / 1000 , 0 ,
ry * rx * ( 1000 - c ) / 1000000 + rz * s / 1000 , ry * ry * ( 1000 - c ) / 1000000 + c , ry * rz * ( 1000 - c ) / 1000000 - rx * s / 1000 , 0 ,
rz * rx * ( 1000 - c ) / 1000000 - ry * s / 1000 , ry * rz * ( 1000 - c ) / 1000000 + rx * s / 1000 , rz * rz * ( 1000 - c ) / 1000000 + c , 0
} ;
MAKE_AND_RETURN_ARRAY ( values ) ;
}
static C4Value FnTrans_Mul ( C4PropList * _this , C4Value * pars )
{
const int32_t matrixSize = 12 ;
long values [ ] =
{
0 , 0 , 0 , 0 ,
0 , 0 , 0 , 0 ,
0 , 0 , 0 , 0
} ;
// Read all parameters
bool first = true ;
for ( int32_t i = 0 ; i < C4AUL_MAX_Par ; i + + )
{
C4Value Data = * ( pars + + ) ;
// No data given?
if ( ! Data ) break ;
C4ValueArray * factorArray = Data . getArray ( ) ;
if ( ! factorArray | | factorArray - > GetSize ( ) ! = matrixSize ) continue ;
if ( first )
{
first = false ;
for ( int32_t c = 0 ; c < matrixSize ; + + c )
values [ c ] = ( * factorArray ) [ c ] . getInt ( ) ;
continue ;
}
// multiply current matrix with new one
long values_rhs [ matrixSize ] , values_result [ matrixSize ] ;
for ( int32_t c = 0 ; c < matrixSize ; + + c )
values_rhs [ c ] = ( * factorArray ) [ c ] . getInt ( ) ;
// matrix multiplication
values_result [ 0 ] = values [ 0 ] * values_rhs [ 0 ] / 1000 + values [ 1 ] * values_rhs [ 4 ] / 1000 + values [ 2 ] * values_rhs [ 8 ] / 1000 ;
values_result [ 1 ] = values [ 0 ] * values_rhs [ 1 ] / 1000 + values [ 1 ] * values_rhs [ 5 ] / 1000 + values [ 2 ] * values_rhs [ 9 ] / 1000 ;
values_result [ 2 ] = values [ 0 ] * values_rhs [ 2 ] / 1000 + values [ 1 ] * values_rhs [ 6 ] / 1000 + values [ 2 ] * values_rhs [ 10 ] / 1000 ;
values_result [ 3 ] = values [ 0 ] * values_rhs [ 3 ] / 1000 + values [ 1 ] * values_rhs [ 7 ] / 1000 + values [ 2 ] * values_rhs [ 11 ] / 1000 + values [ 3 ] ;
values_result [ 4 ] = values [ 4 ] * values_rhs [ 0 ] / 1000 + values [ 5 ] * values_rhs [ 4 ] / 1000 + values [ 6 ] * values_rhs [ 8 ] / 1000 ;
values_result [ 5 ] = values [ 4 ] * values_rhs [ 1 ] / 1000 + values [ 5 ] * values_rhs [ 5 ] / 1000 + values [ 6 ] * values_rhs [ 9 ] / 1000 ;
values_result [ 6 ] = values [ 4 ] * values_rhs [ 2 ] / 1000 + values [ 5 ] * values_rhs [ 6 ] / 1000 + values [ 6 ] * values_rhs [ 10 ] / 1000 ;
values_result [ 7 ] = values [ 4 ] * values_rhs [ 3 ] / 1000 + values [ 5 ] * values_rhs [ 7 ] / 1000 + values [ 6 ] * values_rhs [ 11 ] / 1000 + values [ 7 ] ;
values_result [ 8 ] = values [ 8 ] * values_rhs [ 0 ] / 1000 + values [ 9 ] * values_rhs [ 4 ] / 1000 + values [ 10 ] * values_rhs [ 8 ] / 1000 ;
values_result [ 9 ] = values [ 8 ] * values_rhs [ 1 ] / 1000 + values [ 9 ] * values_rhs [ 5 ] / 1000 + values [ 10 ] * values_rhs [ 9 ] / 1000 ;
values_result [ 10 ] = values [ 8 ] * values_rhs [ 2 ] / 1000 + values [ 9 ] * values_rhs [ 6 ] / 1000 + values [ 10 ] * values_rhs [ 10 ] / 1000 ;
values_result [ 11 ] = values [ 8 ] * values_rhs [ 3 ] / 1000 + values [ 9 ] * values_rhs [ 7 ] / 1000 + values [ 10 ] * values_rhs [ 11 ] / 1000 + values [ 11 ] ;
for ( int32_t c = 0 ; c < matrixSize ; + + c )
values [ c ] = values_result [ c ] ;
}
// unlike in the other Trans_*-functions, we have to put the array into a C4Value manually here
C4ValueArray * matrix = new C4ValueArray ( sizeof ( values ) / sizeof ( * values ) ) ;
2015-01-02 19:55:48 +00:00
for ( size_t i = 0 ; i < sizeof ( values ) / sizeof ( * values ) ; + + i )
2013-07-07 13:54:35 +00:00
( * matrix ) [ i ] = C4VInt ( values [ i ] ) ;
return C4VArray ( matrix ) ;
}
# undef MAKE_AND_RETURN_ARRAY
2012-05-15 01:03:47 +00:00
static C4PropList * FnCreatePropList ( C4PropList * _this , C4PropList * prototype )
2011-03-04 12:49:41 +00:00
{
return C4PropList : : New ( prototype ) ;
}
2012-05-18 17:44:53 +00:00
static C4Value FnGetProperty ( C4PropList * _this , C4String * key , C4PropList * pObj )
2011-03-04 12:49:41 +00:00
{
2012-05-18 17:44:53 +00:00
if ( ! pObj ) pObj = _this ;
2011-03-04 12:49:41 +00:00
if ( ! pObj ) return C4VNull ;
if ( ! key ) return C4VNull ;
C4Value r ;
pObj - > GetPropertyByS ( key , & r ) ;
return r ;
}
2012-05-18 17:44:53 +00:00
static bool FnSetProperty ( C4PropList * _this , C4String * key , const C4Value & to , C4PropList * pObj )
2011-03-04 12:49:41 +00:00
{
2012-05-18 17:44:53 +00:00
if ( ! pObj ) pObj = _this ;
if ( ! pObj ) return false ;
if ( ! key ) return false ;
2011-03-04 12:49:41 +00:00
if ( pObj - > IsFrozen ( ) )
2015-12-07 14:15:49 +00:00
throw C4AulExecError ( " proplist write: proplist is readonly " ) ;
2012-05-18 17:44:53 +00:00
pObj - > SetPropertyByS ( key , to ) ;
return true ;
2011-03-04 12:49:41 +00:00
}
2012-05-18 17:44:53 +00:00
static bool FnResetProperty ( C4PropList * _this , C4String * key , C4PropList * pObj )
2011-03-04 12:49:41 +00:00
{
2012-05-18 17:44:53 +00:00
if ( ! pObj ) pObj = _this ;
if ( ! pObj ) return false ;
if ( ! key ) return false ;
if ( ! pObj - > HasProperty ( key ) ) return false ;
2011-03-04 12:49:41 +00:00
if ( pObj - > IsFrozen ( ) )
2015-12-07 14:15:49 +00:00
throw C4AulExecError ( " proplist write: proplist is readonly " ) ;
2011-03-04 12:49:41 +00:00
pObj - > ResetProperty ( key ) ;
2012-05-18 17:44:53 +00:00
return true ;
2011-03-04 12:49:41 +00:00
}
2012-05-25 23:32:43 +00:00
static C4ValueArray * FnGetProperties ( C4PropList * _this , C4PropList * p )
{
if ( ! p ) p = _this ;
2015-12-07 14:15:49 +00:00
if ( ! p ) throw NeedNonGlobalContext ( " GetProperties " ) ;
2012-05-25 23:32:43 +00:00
C4ValueArray * r = p - > GetProperties ( ) ;
r - > SortStrings ( ) ;
return r ;
}
2012-08-19 15:34:53 +00:00
static C4Value FnCall ( C4PropList * _this , C4Value * Pars )
{
2013-01-31 21:38:16 +00:00
if ( ! _this ) _this = : : ScriptEngine . GetPropList ( ) ;
2014-04-17 15:20:46 +00:00
C4AulParSet ParSet ( & Pars [ 1 ] , C4AUL_MAX_Par - 1 ) ;
2012-08-19 15:34:53 +00:00
C4AulFunc * fn = Pars [ 0 ] . getFunction ( ) ;
2012-12-29 23:59:50 +00:00
C4String * name ;
2012-08-19 15:34:53 +00:00
if ( ! fn )
2012-12-29 23:59:50 +00:00
{
name = Pars [ 0 ] . getStr ( ) ;
2013-01-31 21:38:16 +00:00
if ( name ) fn = _this - > GetFunc ( name ) ;
2012-12-29 23:59:50 +00:00
}
2012-08-19 15:34:53 +00:00
if ( ! fn )
{
2012-12-29 23:59:50 +00:00
const char * s = FnStringPar ( name ) ;
2012-08-19 15:34:53 +00:00
if ( s [ 0 ] = = ' ~ ' )
{
fn = _this - > GetFunc ( & s [ 1 ] ) ;
if ( ! fn )
return C4Value ( ) ;
}
}
if ( ! fn )
2015-12-07 14:15:49 +00:00
throw C4AulExecError ( FormatString ( " Call: no function %s " , Pars [ 0 ] . GetDataString ( ) . getData ( ) ) . getData ( ) ) ;
2012-08-19 15:34:53 +00:00
return fn - > Exec ( _this , & ParSet , true ) ;
}
2012-05-19 16:34:17 +00:00
static C4Value FnLog ( C4PropList * _this , C4Value * Pars )
2011-03-04 12:49:41 +00:00
{
2012-05-19 16:34:17 +00:00
Log ( FnStringFormat ( _this , Pars [ 0 ] . getStr ( ) , & Pars [ 1 ] , 9 ) . getData ( ) ) ;
2011-03-04 12:49:41 +00:00
return C4VBool ( true ) ;
}
2012-05-19 16:34:17 +00:00
static C4Value FnDebugLog ( C4PropList * _this , C4Value * Pars )
2011-03-04 12:49:41 +00:00
{
2012-05-19 16:34:17 +00:00
DebugLog ( FnStringFormat ( _this , Pars [ 0 ] . getStr ( ) , & Pars [ 1 ] , 9 ) . getData ( ) ) ;
2011-03-04 12:49:41 +00:00
return C4VBool ( true ) ;
}
2012-05-19 16:34:17 +00:00
static C4Value FnFormat ( C4PropList * _this , C4Value * Pars )
2011-03-04 12:49:41 +00:00
{
2012-05-19 16:34:17 +00:00
return C4VString ( FnStringFormat ( _this , Pars [ 0 ] . getStr ( ) , & Pars [ 1 ] , 9 ) ) ;
2011-03-04 12:49:41 +00:00
}
2012-05-15 01:03:47 +00:00
static long FnAbs ( C4PropList * _this , long iVal )
2011-03-04 12:49:41 +00:00
{
return Abs ( iVal ) ;
}
2012-05-15 01:03:47 +00:00
static long FnSin ( C4PropList * _this , long iAngle , long iRadius , long iPrec )
2011-03-04 12:49:41 +00:00
{
if ( ! iPrec ) iPrec = 1 ;
// Precalculate the modulo operation so the C4Fixed argument to Sin does not overflow
iAngle % = 360 * iPrec ;
// Let itofix and fixtoi handle the division and multiplication because that can handle higher ranges
return fixtoi ( Sin ( itofix ( iAngle , iPrec ) ) , iRadius ) ;
}
2012-05-15 01:03:47 +00:00
static long FnCos ( C4PropList * _this , long iAngle , long iRadius , long iPrec )
2011-03-04 12:49:41 +00:00
{
if ( ! iPrec ) iPrec = 1 ;
iAngle % = 360 * iPrec ;
return fixtoi ( Cos ( itofix ( iAngle , iPrec ) ) , iRadius ) ;
}
2012-05-15 01:03:47 +00:00
static long FnSqrt ( C4PropList * _this , long iValue )
2011-03-04 12:49:41 +00:00
{
if ( iValue < 0 ) return 0 ;
long iSqrt = long ( sqrt ( double ( iValue ) ) ) ;
if ( iSqrt * iSqrt < iValue ) iSqrt + + ;
if ( iSqrt * iSqrt > iValue ) iSqrt - - ;
return iSqrt ;
}
2012-05-15 01:03:47 +00:00
static long FnAngle ( C4PropList * _this , long iX1 , long iY1 , long iX2 , long iY2 , long iPrec )
2011-03-04 12:49:41 +00:00
{
long iAngle ;
// Standard prec
if ( ! iPrec ) iPrec = 1 ;
long dx = iX2 - iX1 , dy = iY2 - iY1 ;
if ( ! dx )
{
if ( dy > 0 ) return 180 * iPrec ;
else return 0 ;
}
if ( ! dy )
{
if ( dx > 0 ) return 90 * iPrec ;
else return 270 * iPrec ;
}
iAngle = static_cast < long > ( 180.0 * iPrec * atan2 ( static_cast < double > ( Abs ( dy ) ) , static_cast < double > ( Abs ( dx ) ) ) / M_PI ) ;
if ( iX2 > iX1 )
{
if ( iY2 < iY1 ) iAngle = ( 90 * iPrec ) - iAngle ;
else iAngle = ( 90 * iPrec ) + iAngle ;
}
else
{
if ( iY2 < iY1 ) iAngle = ( 270 * iPrec ) + iAngle ;
else iAngle = ( 270 * iPrec ) - iAngle ;
}
return iAngle ;
}
2012-05-15 01:03:47 +00:00
static long FnArcSin ( C4PropList * _this , long iVal , long iRadius )
2011-03-04 12:49:41 +00:00
{
// safety
if ( ! iRadius ) return 0 ;
if ( iVal > iRadius ) return 0 ;
// calc arcsin
double f1 = iVal ;
f1 = asin ( f1 / iRadius ) * 180.0 / M_PI ;
// return rounded angle
return ( long ) floor ( f1 + 0.5 ) ;
}
2012-05-15 01:03:47 +00:00
static long FnArcCos ( C4PropList * _this , long iVal , long iRadius )
2011-03-04 12:49:41 +00:00
{
// safety
if ( ! iRadius ) return 0 ;
if ( iVal > iRadius ) return 0 ;
// calc arccos
double f1 = iVal ;
f1 = acos ( f1 / iRadius ) * 180.0 / M_PI ;
// return rounded angle
return ( long ) floor ( f1 + 0.5 ) ;
}
2016-01-23 12:45:22 +00:00
static std : : pair < Nillable < int32_t > , Nillable < int32_t > > minmax ( const char * func , const C4Value & a_val , const Nillable < int32_t > & b_opt )
2011-03-04 12:49:41 +00:00
{
2016-01-23 12:45:22 +00:00
if ( a_val . CheckConversion ( C4V_Int ) )
{
int32_t a = a_val . getInt ( ) ;
int32_t b = b_opt ;
if ( a > b )
std : : swap ( a , b ) ;
return std : : make_pair ( a , b ) ;
}
else if ( a_val . CheckConversion ( C4V_Array ) )
{
const C4ValueArray * a = a_val . getArray ( ) ;
if ( a - > GetSize ( ) = = 0 )
return std : : make_pair ( nullptr , nullptr ) ;
if ( ! a - > GetItem ( 0 ) . CheckConversion ( C4V_Int ) )
{
throw C4AulExecError ( FormatString ( " %s: argument 1 must be int or array-of-int, but element %d of array is of type %s " , func , 0 , a - > GetItem ( 0 ) . GetTypeName ( ) ) . getData ( ) ) ;
}
int32_t min , max ;
min = max = a - > GetItem ( 0 ) . getInt ( ) ;
for ( int32_t i = 1 ; i < a - > GetSize ( ) ; + + i )
{
if ( ! a - > GetItem ( i ) . CheckConversion ( C4V_Int ) )
{
throw C4AulExecError ( FormatString ( " %s: argument 1 must be int or array-of-int, but element %d of array is of type %s " , func , i , a - > GetItem ( i ) . GetTypeName ( ) ) . getData ( ) ) ;
}
int32_t value = a - > GetItem ( i ) . getInt ( ) ;
min = std : : min ( min , value ) ;
max = std : : max ( max , value ) ;
}
return std : : make_pair ( min , max ) ;
}
else
{
throw C4AulExecError ( FormatString ( " %s: argument 1 must be int or array-of-int, but is of type %s " , func , a_val . GetTypeName ( ) ) . getData ( ) ) ;
}
}
static Nillable < int32_t > FnMin ( C4PropList * _this , const C4Value & a , Nillable < int32_t > b )
{
return minmax ( " Min " , a , b ) . first ;
2011-03-04 12:49:41 +00:00
}
2016-01-23 12:45:22 +00:00
static Nillable < int32_t > FnMax ( C4PropList * _this , const C4Value & a , Nillable < int32_t > b )
2011-03-04 12:49:41 +00:00
{
2016-01-23 12:45:22 +00:00
return minmax ( " Max " , a , b ) . second ;
2011-03-04 12:49:41 +00:00
}
2012-05-15 01:03:47 +00:00
static long FnDistance ( C4PropList * _this , long iX1 , long iY1 , long iX2 , long iY2 )
2011-03-04 12:49:41 +00:00
{
return Distance ( iX1 , iY1 , iX2 , iY2 ) ;
}
2012-05-15 01:03:47 +00:00
static long FnBoundBy ( C4PropList * _this , long iVal , long iRange1 , long iRange2 )
2011-03-04 12:49:41 +00:00
{
2015-02-12 22:05:55 +00:00
return Clamp ( iVal , iRange1 , iRange2 ) ;
2011-03-04 12:49:41 +00:00
}
2012-05-15 01:03:47 +00:00
static bool FnInside ( C4PropList * _this , long iVal , long iRange1 , long iRange2 )
2011-03-04 12:49:41 +00:00
{
return Inside ( iVal , iRange1 , iRange2 ) ;
}
2012-05-15 01:03:47 +00:00
static long FnRandom ( C4PropList * _this , long iRange )
2011-03-04 12:49:41 +00:00
{
return Random ( iRange ) ;
}
2012-05-15 01:03:47 +00:00
static long FnAsyncRandom ( C4PropList * _this , long iRange )
2011-03-04 12:49:41 +00:00
{
return SafeRandom ( iRange ) ;
}
2012-05-15 01:03:47 +00:00
static int FnGetType ( C4PropList * _this , const C4Value & Value )
2011-03-04 12:49:41 +00:00
{
2011-09-26 18:22:31 +00:00
// dynamic types
2012-04-13 16:38:30 +00:00
if ( Value . CheckConversion ( C4V_Object ) ) return C4V_Object ;
2011-09-24 16:37:28 +00:00
if ( Value . CheckConversion ( C4V_Def ) ) return C4V_Def ;
if ( Value . CheckConversion ( C4V_Effect ) ) return C4V_Effect ;
2011-09-26 18:22:31 +00:00
// static types
return Value . GetType ( ) ;
2011-03-04 12:49:41 +00:00
}
2012-05-15 01:03:47 +00:00
static C4ValueArray * FnCreateArray ( C4PropList * _this , int iSize )
2011-03-04 12:49:41 +00:00
{
return new C4ValueArray ( iSize ) ;
}
2012-05-18 17:44:53 +00:00
static int FnGetLength ( C4PropList * _this , const C4Value & Par )
2011-03-04 12:49:41 +00:00
{
// support GetLength() etc.
2012-05-18 17:44:53 +00:00
C4ValueArray * pArray = Par . getArray ( ) ;
2011-03-04 12:49:41 +00:00
if ( pArray )
2012-05-18 17:44:53 +00:00
return pArray - > GetSize ( ) ;
C4String * pStr = Par . getStr ( ) ;
2011-03-04 12:49:41 +00:00
if ( pStr )
2012-05-18 17:44:53 +00:00
return GetCharacterCount ( pStr - > GetData ( ) . getData ( ) ) ;
2015-12-07 14:15:49 +00:00
throw C4AulExecError ( " GetLength: parameter 0 cannot be converted to string or array " ) ;
2011-03-04 12:49:41 +00:00
}
2012-05-18 17:44:53 +00:00
static int FnGetIndexOf ( C4PropList * _this , C4ValueArray * pArray , const C4Value & Needle )
2011-03-04 12:49:41 +00:00
{
// find first occurance of first parameter in array
2012-02-25 20:57:39 +00:00
// support GetIndexOf(0, x)
2012-05-18 17:44:53 +00:00
if ( ! pArray ) return - 1 ;
2011-03-04 12:49:41 +00:00
int32_t iSize = pArray - > GetSize ( ) ;
2012-05-18 17:44:53 +00:00
for ( int32_t i = 0 ; i < iSize ; + + i )
2014-04-19 20:33:31 +00:00
if ( Needle . IsIdenticalTo ( pArray - > GetItem ( i ) ) )
2011-03-04 12:49:41 +00:00
// element found
2012-05-18 17:44:53 +00:00
return i ;
2011-03-04 12:49:41 +00:00
// element not found
2012-05-18 17:44:53 +00:00
return - 1 ;
2011-03-04 12:49:41 +00:00
}
2014-04-19 20:33:31 +00:00
static bool FnDeepEqual ( C4PropList * _this , const C4Value & v1 , const C4Value & v2 )
{
// return if v1==v2 with deep comparison on arrays and proplists
return v1 = = v2 ;
}
2012-05-15 01:03:47 +00:00
static C4Void FnSetLength ( C4PropList * _this , C4ValueArray * pArray , int iNewSize )
2011-03-04 12:49:41 +00:00
{
// safety
if ( iNewSize < 0 | | iNewSize > C4ValueArray : : MaxSize )
2015-12-07 14:15:49 +00:00
throw C4AulExecError ( FormatString ( " SetLength: invalid array size (%d) " , iNewSize).getData()) ;
2011-03-04 12:49:41 +00:00
// set new size
pArray - > SetSize ( iNewSize ) ;
return C4Void ( ) ;
}
2012-05-15 01:03:47 +00:00
static Nillable < long > FnGetChar ( C4PropList * _this , C4String * pString , long iIndex )
2011-03-04 12:49:41 +00:00
{
const char * szText = FnStringPar ( pString ) ;
2011-07-30 23:32:02 +00:00
if ( ! szText ) return C4Void ( ) ;
2011-03-09 23:26:31 +00:00
// C4Strings are UTF-8 encoded, so decode to get the indicated character
uint32_t c = GetNextCharacter ( & szText ) ;
for ( int i = 0 ; i < iIndex ; + + i )
{
c = GetNextCharacter ( & szText ) ;
2011-07-30 23:32:02 +00:00
if ( ! c ) return C4Void ( ) ;
2011-03-09 23:26:31 +00:00
}
return c ;
2011-03-04 12:49:41 +00:00
}
2012-05-18 17:44:53 +00:00
static C4Value Fneval ( C4PropList * _this , C4String * strScript )
2011-03-04 12:49:41 +00:00
{
// execute script in the same object
2012-05-15 01:03:47 +00:00
if ( Object ( _this ) )
2012-05-18 17:44:53 +00:00
return Object ( _this ) - > Def - > Script . DirectExec ( Object ( _this ) , FnStringPar ( strScript ) , " eval " , true ) ;
2012-05-15 01:03:47 +00:00
else if ( _this & & _this - > GetDef ( ) )
2012-05-18 17:44:53 +00:00
return _this - > GetDef ( ) - > Script . DirectExec ( 0 , FnStringPar ( strScript ) , " eval " , true ) ;
2011-03-04 12:49:41 +00:00
else
2012-05-18 17:44:53 +00:00
return : : GameScript . DirectExec ( 0 , FnStringPar ( strScript ) , " eval " , true ) ;
2011-03-04 12:49:41 +00:00
}
2012-05-15 01:03:47 +00:00
static bool FnLocateFunc ( C4PropList * _this , C4String * funcname , C4PropList * p )
2011-03-04 12:49:41 +00:00
{
// safety
if ( ! funcname | | ! funcname - > GetCStr ( ) )
{
Log ( " No func name " ) ;
return false ;
}
2012-05-15 01:03:47 +00:00
if ( ! p ) p = _this ;
2011-03-04 12:49:41 +00:00
// get function by name
2011-10-15 00:27:02 +00:00
C4AulFunc * pFunc = p - > GetFunc ( funcname ) ;
2011-03-04 12:49:41 +00:00
if ( ! pFunc )
{
LogF ( " Func %s not found " , funcname - > GetCStr ( ) ) ;
}
else
{
const char * szPrefix = " " ;
while ( pFunc )
{
C4AulScriptFunc * pSFunc = pFunc - > SFunc ( ) ;
if ( ! pSFunc )
{
2011-10-13 22:40:55 +00:00
LogF ( " %s%s (engine) " , szPrefix , pFunc - > GetName ( ) ) ;
2011-03-04 12:49:41 +00:00
}
else if ( ! pSFunc - > pOrgScript )
{
2011-10-13 22:40:55 +00:00
LogF ( " %s%s (no owner) " , szPrefix , pSFunc - > GetName ( ) ) ;
2011-03-04 12:49:41 +00:00
}
else
{
int32_t iLine = SGetLine ( pSFunc - > pOrgScript - > GetScript ( ) , pSFunc - > Script ) ;
2011-10-13 22:40:55 +00:00
LogF ( " %s%s (%s:%d) " , szPrefix , pFunc - > GetName ( ) , pSFunc - > pOrgScript - > ScriptName . getData ( ) , ( int ) iLine ) ;
2011-03-04 12:49:41 +00:00
}
// next func in overload chain
pFunc = pSFunc ? pSFunc - > OwnerOverloaded : NULL ;
szPrefix = " overloads " ;
}
}
return true ;
}
2012-05-15 01:03:47 +00:00
static long FnModulateColor ( C4PropList * _this , long iClr1 , long iClr2 )
2011-03-04 12:49:41 +00:00
{
DWORD dwClr1 = iClr1 ;
DWORD dwClr2 = iClr2 ;
// default color
if ( ! dwClr1 ) dwClr1 = 0xffffff ;
// get alpha
long iA1 = dwClr1 > > 24 , iA2 = dwClr2 > > 24 ;
// modulate color values; mod alpha upwards
DWORD r = ( ( ( dwClr1 & 0xff ) * ( dwClr2 & 0xff ) ) > > 8 ) | // blue
( ( ( dwClr1 > > 8 & 0xff ) * ( dwClr2 > > 8 & 0xff ) ) & 0xff00 ) | // green
( ( ( dwClr1 > > 16 & 0xff ) * ( dwClr2 > > 8 & 0xff00 ) ) & 0xff0000 ) | // red
2015-11-15 12:53:01 +00:00
( std : : min < long > ( iA1 + iA2 - ( ( iA1 * iA2 ) > > 8 ) , 255 ) < < 24 ) ; // alpha
2011-03-04 12:49:41 +00:00
return r ;
}
2012-05-15 01:03:47 +00:00
static long FnWildcardMatch ( C4PropList * _this , C4String * psString , C4String * psWildcard )
2011-03-04 12:49:41 +00:00
{
return SWildcardMatchEx ( FnStringPar ( psString ) , FnStringPar ( psWildcard ) ) ;
}
2012-05-15 01:03:47 +00:00
static bool FnFatalError ( C4PropList * _this , C4String * pErrorMsg )
2011-03-04 12:49:41 +00:00
{
2015-12-07 14:15:49 +00:00
throw C4AulExecError ( FormatString ( " script: %s " , pErrorMsg ? pErrorMsg - > GetCStr ( ) : " (no error) " ) . getData ( ) ) ;
2011-03-04 12:49:41 +00:00
}
2012-05-15 01:03:47 +00:00
static bool FnStartCallTrace ( C4PropList * _this )
2011-03-04 12:49:41 +00:00
{
extern void C4AulStartTrace ( ) ;
C4AulStartTrace ( ) ;
return true ;
}
2013-03-03 18:25:18 +00:00
static bool FnStartScriptProfiler ( C4PropList * _this , C4Def * pDef )
2011-03-04 12:49:41 +00:00
{
// get script to profile
C4AulScript * pScript ;
2013-03-03 18:25:18 +00:00
if ( pDef )
2011-03-04 12:49:41 +00:00
pScript = & pDef - > Script ;
else
pScript = & : : ScriptEngine ;
// profile it
C4AulProfiler : : StartProfiling ( pScript ) ;
return true ;
}
2012-05-15 01:03:47 +00:00
static bool FnStopScriptProfiler ( C4PropList * _this )
2011-03-04 12:49:41 +00:00
{
C4AulProfiler : : StopProfiling ( ) ;
return true ;
}
2012-05-15 01:03:47 +00:00
static Nillable < C4String * > FnGetConstantNameByValue ( C4PropList * _this , int value , Nillable < C4String * > name_prefix , int idx )
2011-03-04 12:49:41 +00:00
{
C4String * name_prefix_s = name_prefix ;
// find a constant that has the specified value and prefix
for ( int32_t i = 0 ; i < : : ScriptEngine . GlobalConsts . GetAnzItems ( ) ; + + i )
{
if ( : : ScriptEngine . GlobalConsts [ i ] . getInt ( ) = = value )
{
const char * const_name = : : ScriptEngine . GlobalConstNames . GetItemUnsafe ( i ) ;
if ( ! name_prefix_s | | SEqual2 ( const_name , name_prefix_s - > GetCStr ( ) ) )
if ( ! idx - - )
// indexed constant found. return name minus prefix
return String ( const_name + ( name_prefix_s ? name_prefix_s - > GetData ( ) . getLength ( ) : 0 ) ) ;
}
}
// nothing found (at index)
return C4Void ( ) ;
}
2012-12-17 15:41:39 +00:00
static bool FnSortArray ( C4PropList * _this , C4ValueArray * pArray , bool descending )
{
2015-12-07 14:15:49 +00:00
if ( ! pArray ) throw C4AulExecError ( " SortArray: no array given " ) ;
2012-12-17 15:41:39 +00:00
// sort array by its members
pArray - > Sort ( descending ) ;
return true ;
}
static bool FnSortArrayByProperty ( C4PropList * _this , C4ValueArray * pArray , C4String * prop_name , bool descending )
{
2015-12-07 14:15:49 +00:00
if ( ! pArray ) throw C4AulExecError ( " SortArrayByProperty: no array given " ) ;
if ( ! prop_name ) throw C4AulExecError ( " SortArrayByProperty: no property name given " ) ;
2012-12-17 15:41:39 +00:00
// sort array by property
2015-12-07 14:15:49 +00:00
if ( ! pArray - > SortByProperty ( prop_name , descending ) ) throw C4AulExecError ( " SortArrayByProperty: not all array elements are proplists " ) ;
2012-12-17 15:41:39 +00:00
return true ;
}
static bool FnSortArrayByArrayElement ( C4PropList * _this , C4ValueArray * pArray , int32_t element_index , bool descending )
{
2015-12-07 14:15:49 +00:00
if ( ! pArray ) throw C4AulExecError ( " SortArrayByArrayElement: no array given " ) ;
if ( element_index < 0 ) throw C4AulExecError ( " SortArrayByArrayElement: element index must be >=0 " ) ;
2012-12-17 15:41:39 +00:00
// sort array by array element
2015-12-07 14:15:49 +00:00
if ( ! pArray - > SortByArrayElement ( element_index , descending ) ) throw C4AulExecError ( " SortArrayByArrayElement: not all array elements are arrays of sufficient length " ) ;
2012-12-17 15:41:39 +00:00
return true ;
}
2013-12-22 22:47:40 +00:00
static bool FnFileWrite ( C4PropList * _this , int32_t file_handle , C4String * data )
{
// resolve file handle to user file
C4AulUserFile * file = : : ScriptEngine . GetUserFile ( file_handle ) ;
2015-12-07 14:15:49 +00:00
if ( ! file ) throw C4AulExecError ( " FileWrite: invalid file handle " ) ;
2013-12-22 22:47:40 +00:00
// prepare string to write
if ( ! data ) return false ; // write NULL? No.
// write it
file - > Write ( data - > GetCStr ( ) , data - > GetData ( ) . getLength ( ) ) ;
return true ;
}
2011-03-04 12:49:41 +00:00
//=========================== C4Script Function Map ===================================
C4ScriptConstDef C4ScriptConstMap [ ] =
{
2011-09-26 18:22:31 +00:00
{ " C4V_Nil " , C4V_Int , C4V_Nil } ,
{ " C4V_Int " , C4V_Int , C4V_Int } ,
{ " C4V_Bool " , C4V_Int , C4V_Bool } ,
{ " C4V_C4Object " , C4V_Int , C4V_Object } ,
2011-09-24 16:37:28 +00:00
{ " C4V_Effect " , C4V_Int , C4V_Effect } ,
{ " C4V_Def " , C4V_Int , C4V_Def } ,
2011-09-26 18:22:31 +00:00
{ " C4V_String " , C4V_Int , C4V_String } ,
{ " C4V_Array " , C4V_Int , C4V_Array } ,
2011-09-24 23:20:18 +00:00
{ " C4V_Function " , C4V_Int , C4V_Function } ,
2011-09-26 18:22:31 +00:00
{ " C4V_PropList " , C4V_Int , C4V_PropList } ,
2011-03-04 12:49:41 +00:00
2011-09-26 18:22:31 +00:00
{ " C4X_Ver1 " , C4V_Int , C4XVER1 } ,
{ " C4X_Ver2 " , C4V_Int , C4XVER2 } ,
2011-03-04 12:49:41 +00:00
2011-05-09 12:37:28 +00:00
{ NULL , C4V_Nil , 0 }
2011-03-04 12:49:41 +00:00
} ;
C4ScriptFnDef C4ScriptFnMap [ ] =
{
2012-08-19 15:34:53 +00:00
{ " Call " , 1 , C4V_Any , { C4V_Any , C4V_Any , C4V_Any , C4V_Any , C4V_Any , C4V_Any , C4V_Any , C4V_Any , C4V_Any , C4V_Any } , FnCall } ,
2012-05-20 00:39:57 +00:00
{ " Log " , 1 , C4V_Bool , { C4V_String , C4V_Any , C4V_Any , C4V_Any , C4V_Any , C4V_Any , C4V_Any , C4V_Any , C4V_Any , C4V_Any } , FnLog } ,
{ " DebugLog " , 1 , C4V_Bool , { C4V_String , C4V_Any , C4V_Any , C4V_Any , C4V_Any , C4V_Any , C4V_Any , C4V_Any , C4V_Any , C4V_Any } , FnDebugLog } ,
{ " Format " , 1 , C4V_String , { C4V_String , C4V_Any , C4V_Any , C4V_Any , C4V_Any , C4V_Any , C4V_Any , C4V_Any , C4V_Any , C4V_Any } , FnFormat } ,
2013-07-07 13:54:35 +00:00
{ " Trans_Mul " , 1 , C4V_Array , { C4V_Array , C4V_Any , C4V_Any , C4V_Any , C4V_Any , C4V_Any , C4V_Any , C4V_Any , C4V_Any , C4V_Any } , FnTrans_Mul } ,
2011-03-04 12:49:41 +00:00
2012-05-20 00:39:57 +00:00
{ NULL , 0 , C4V_Nil , { C4V_Nil , C4V_Nil , C4V_Nil , C4V_Nil , C4V_Nil , C4V_Nil , C4V_Nil , C4V_Nil , C4V_Nil , C4V_Nil } , 0 }
2011-03-04 12:49:41 +00:00
} ;
void InitCoreFunctionMap ( C4AulScriptEngine * pEngine )
{
// add all def constants (all Int)
for ( C4ScriptConstDef * pCDef = & C4ScriptConstMap [ 0 ] ; pCDef - > Identifier ; pCDef + + )
{
assert ( pCDef - > ValType = = C4V_Int ) ; // only int supported currently
pEngine - > RegisterGlobalConstant ( pCDef - > Identifier , C4VInt ( pCDef - > Data ) ) ;
}
// add all def script funcs
for ( C4ScriptFnDef * pDef = & C4ScriptFnMap [ 0 ] ; pDef - > Identifier ; pDef + + )
2012-05-20 00:39:57 +00:00
new C4AulDefFunc ( pEngine , pDef ) ;
2012-05-18 17:41:38 +00:00
# define F(f) AddFunc(pEngine, #f, Fn##f)
F ( Abs ) ;
F ( Min ) ;
F ( Max ) ;
F ( Sin ) ;
F ( Cos ) ;
F ( Sqrt ) ;
F ( ArcSin ) ;
F ( ArcCos ) ;
F ( BoundBy ) ;
F ( Inside ) ;
F ( Random ) ;
F ( AsyncRandom ) ;
F ( CreateArray ) ;
F ( CreatePropList ) ;
F ( GetProperties ) ;
2012-05-18 17:44:53 +00:00
F ( GetProperty ) ;
F ( SetProperty ) ;
F ( ResetProperty ) ;
2012-05-18 17:41:38 +00:00
F ( Distance ) ;
F ( Angle ) ;
F ( GetChar ) ;
F ( GetType ) ;
F ( ModulateColor ) ;
F ( WildcardMatch ) ;
2012-05-18 17:44:53 +00:00
F ( GetLength ) ;
2012-05-18 17:41:38 +00:00
F ( SetLength ) ;
2012-05-18 17:44:53 +00:00
F ( GetIndexOf ) ;
2014-04-19 20:33:31 +00:00
F ( DeepEqual ) ;
2012-05-18 17:41:38 +00:00
F ( FatalError ) ;
F ( StartCallTrace ) ;
F ( StartScriptProfiler ) ;
F ( StopScriptProfiler ) ;
2012-12-17 15:41:39 +00:00
F ( SortArray ) ;
F ( SortArrayByProperty ) ;
F ( SortArrayByArrayElement ) ;
2013-07-07 13:54:35 +00:00
F ( Trans_Identity ) ;
F ( Trans_Translate ) ;
F ( Trans_Scale ) ;
F ( Trans_Rotate ) ;
2012-05-18 17:41:38 +00:00
F ( LocateFunc ) ;
2013-12-22 22:47:40 +00:00
F ( FileWrite ) ;
2012-05-18 17:41:38 +00:00
2012-05-18 17:44:53 +00:00
F ( eval ) ;
2012-05-18 17:41:38 +00:00
F ( GetConstantNameByValue ) ;
2011-03-04 12:49:41 +00:00
2012-04-28 19:32:29 +00:00
AddFunc ( pEngine , " Translate " , C4AulExec : : FnTranslate ) ;
2014-01-04 13:22:41 +00:00
AddFunc ( pEngine , " LogCallStack " , C4AulExec : : FnLogCallStack ) ;
2012-05-18 17:41:38 +00:00
# undef F
2011-03-04 12:49:41 +00:00
}