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/
2016-04-03 18:18:29 +00:00
* Copyright ( c ) 2009 - 2016 , 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 */
2016-04-03 18:07:56 +00:00
# include "C4Include.h"
# include "script/C4AulDefFunc.h"
2011-03-04 12:49:41 +00:00
2016-04-03 18:07:56 +00:00
# include "script/C4AulExec.h"
# include "lib/C4Random.h"
# include "C4Version.h"
2011-03-04 12:49:41 +00:00
2016-09-16 19:15:52 +00:00
# include <regex>
2011-03-04 12:49:41 +00:00
//========================== 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 ;
}
2014-04-20 13:52:09 +00:00
C4AulDefFunc : : C4AulDefFunc ( C4PropListStatic * Parent , C4ScriptFnDef * pDef ) :
C4AulFunc ( Parent , pDef - > Identifier ) , Def ( pDef )
2012-05-20 00:39:57 +00:00
{
2014-04-20 13:52:09 +00:00
Parent - > SetPropertyByS ( Name , C4VFunction ( this ) ) ;
2012-05-20 00:39:57 +00:00
}
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
2015-12-21 22:55:03 +00:00
/* PropLists */
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 ;
}
2016-04-27 18:42:59 +00:00
static C4PropList * FnGetPrototype ( C4PropList * _this , C4PropList * p )
{
if ( ! p ) p = _this ;
if ( ! p ) throw NeedNonGlobalContext ( " GetPrototype " ) ;
return p - > GetPrototype ( ) ;
}
static void FnSetPrototype ( C4PropList * _this , C4PropList * prototype , C4PropList * p )
{
if ( ! p ) p = _this ;
if ( ! p ) throw NeedNonGlobalContext ( " GetPrototype " ) ;
p - > SetProperty ( P_Prototype , C4Value ( prototype ) ) ;
}
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-05-30 22:37:18 +00:00
C4AulParSet ParSet ;
ParSet . Copy ( & 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 ) ;
}
2014-04-20 20:05:50 +00:00
static C4String * FnGetName ( C4PropList * _this , bool truename )
{
if ( ! _this )
throw NeedNonGlobalContext ( " GetName " ) ;
else if ( truename )
return _this - > IsStatic ( ) ? _this - > IsStatic ( ) - > GetParentKeyName ( ) : nullptr ;
else
return String ( _this - > GetName ( ) ) ;
}
2015-12-21 22:55:03 +00:00
/* Effects */
static C4Value FnAddEffect ( C4PropList * _this , C4String * szEffect , C4PropList * pTarget ,
int iPrio , int iTimerInterval , C4PropList * pCmdTarget , C4Def * idCmdTarget ,
const C4Value & Val1 , const C4Value & Val2 , const C4Value & Val3 , const C4Value & Val4 )
{
// safety
if ( pTarget & & ! pTarget - > Status ) return C4Value ( ) ;
if ( ! szEffect | | ! * szEffect - > GetCStr ( ) | | ! iPrio ) return C4Value ( ) ;
// create effect
C4PropList * p = pCmdTarget ;
if ( ! p ) p = idCmdTarget ;
if ( ! p ) p = : : ScriptEngine . GetPropList ( ) ;
C4Effect * pEffect = C4Effect : : New ( pTarget , FnGetEffectsFor ( pTarget ) ,
szEffect , iPrio , iTimerInterval , p , Val1 , Val2 , Val3 , Val4 ) ;
// return effect - may be 0 if the effect has been denied by another effect
if ( ! pEffect ) return C4Value ( ) ;
return C4VPropList ( pEffect ) ;
}
2015-12-22 23:40:16 +00:00
static C4Effect * FnCreateEffect ( C4PropList * _this , C4PropList * prototype , int iPrio , int iTimerInterval ,
const C4Value & Val1 , const C4Value & Val2 , const C4Value & Val3 , const C4Value & Val4 )
{
if ( ! prototype | | ! ( prototype - > GetName ( ) [ 0 ] ) ) throw C4AulExecError ( " CreateEffect needs a prototype with a name " ) ;
if ( ! iPrio ) throw C4AulExecError ( " CreateEffect needs a nonzero priority " ) ;
// create effect
C4Effect * pEffect = C4Effect : : New ( _this , FnGetEffectsFor ( _this ) , prototype , iPrio , iTimerInterval ,
Val1 , Val2 , Val3 , Val4 ) ;
// return effect - may be 0 if the effect has been denied by another effect
return pEffect ;
}
2015-12-21 22:55:03 +00:00
static C4Effect * FnGetEffect ( C4PropList * _this , C4String * psEffectName , C4PropList * pTarget , int index , int iMaxPriority )
{
const char * szEffect = FnStringPar ( psEffectName ) ;
// get effects
C4Effect * pEffect = * FnGetEffectsFor ( pTarget ) ;
2016-11-02 23:58:02 +00:00
if ( ! pEffect ) return nullptr ;
2015-12-21 22:55:03 +00:00
// name/wildcard given: find effect by name and index
if ( szEffect & & * szEffect )
return pEffect - > Get ( szEffect , index , iMaxPriority ) ;
2016-11-02 23:58:02 +00:00
return nullptr ;
2015-12-21 22:55:03 +00:00
}
static bool FnRemoveEffect ( C4PropList * _this , C4String * psEffectName , C4PropList * pTarget , C4Effect * pEffect2 , bool fDoNoCalls )
{
// evaluate parameters
const char * szEffect = FnStringPar ( psEffectName ) ;
// if the user passed an effect, it can be used straight-away
C4Effect * pEffect = pEffect2 ;
// otherwise, the correct effect will be searched in the target's effects or in the global ones
if ( ! pEffect )
{
pEffect = * FnGetEffectsFor ( pTarget ) ;
// the object has no effects attached, nothing to look for
if ( ! pEffect ) return 0 ;
// name/wildcard given: find effect by name
if ( szEffect & & * szEffect )
pEffect = pEffect - > Get ( szEffect , 0 ) ;
}
// neither passed nor found - nothing to remove!
if ( ! pEffect ) return 0 ;
// kill it
if ( fDoNoCalls )
pEffect - > SetDead ( ) ;
else
2016-05-04 01:46:28 +00:00
pEffect - > Kill ( ) ;
2015-12-21 22:55:03 +00:00
// done, success
return true ;
}
static C4Value FnCheckEffect ( C4PropList * _this , C4String * psEffectName , C4PropList * pTarget ,
int iPrio , int iTimerInterval ,
const C4Value & Val1 , const C4Value & Val2 , const C4Value & Val3 , const C4Value & Val4 )
{
const char * szEffect = FnStringPar ( psEffectName ) ;
// safety
if ( pTarget & & ! pTarget - > Status ) return C4Value ( ) ;
if ( ! szEffect | | ! * szEffect ) return C4Value ( ) ;
// get effects
C4Effect * pEffect = * FnGetEffectsFor ( pTarget ) ;
if ( ! pEffect ) return C4Value ( ) ;
// let them check
2016-05-04 01:46:28 +00:00
C4Effect * r = pEffect - > Check ( szEffect , iPrio , iTimerInterval , Val1 , Val2 , Val3 , Val4 ) ;
2015-12-21 22:55:03 +00:00
if ( r = = ( C4Effect * ) C4Fx_Effect_Deny ) return C4VInt ( C4Fx_Effect_Deny ) ;
if ( r = = ( C4Effect * ) C4Fx_Effect_Annul ) return C4VInt ( C4Fx_Effect_Annul ) ;
return C4VPropList ( r ) ;
}
static long FnGetEffectCount ( C4PropList * _this , C4String * psEffectName , C4PropList * pTarget , long iMaxPriority )
{
// evaluate parameters
const char * szEffect = FnStringPar ( psEffectName ) ;
// get effects
C4Effect * pEffect = * FnGetEffectsFor ( pTarget ) ;
if ( ! pEffect ) return false ;
// count effects
if ( ! * szEffect ) szEffect = 0 ;
return pEffect - > GetCount ( szEffect , iMaxPriority ) ;
}
static C4Value FnEffectCall ( C4PropList * _this , C4Value * Pars )
{
// evaluate parameters
C4PropList * pTarget = Pars [ 0 ] . getPropList ( ) ;
C4Effect * pEffect = Pars [ 1 ] . getPropList ( ) ? Pars [ 1 ] . getPropList ( ) - > GetEffect ( ) : 0 ;
const char * szCallFn = FnStringPar ( Pars [ 2 ] . getStr ( ) ) ;
// safety
if ( pTarget & & ! pTarget - > Status ) return C4Value ( ) ;
if ( ! szCallFn | | ! * szCallFn ) return C4Value ( ) ;
if ( ! pEffect ) return C4Value ( ) ;
// do call
return pEffect - > DoCall ( pTarget , szCallFn , Pars [ 3 ] , Pars [ 4 ] , Pars [ 5 ] , Pars [ 6 ] , Pars [ 7 ] , Pars [ 8 ] , Pars [ 9 ] ) ;
}
2016-09-16 19:15:52 +00:00
/* Regex */
static const long
Regex_CaseInsensitive = ( 1 < < 0 ) ,
Regex_FirstOnly = ( 1 < < 1 ) ;
static std : : regex_constants : : syntax_option_type C4IntToSyntaxOption ( long flags )
{
std : : regex_constants : : syntax_option_type out = std : : regex : : ECMAScript ;
if ( flags & Regex_CaseInsensitive )
out | = std : : regex : : icase ;
return out ;
}
static std : : regex_constants : : match_flag_type C4IntToMatchFlag ( long flags )
{
std : : regex_constants : : match_flag_type out = std : : regex_constants : : match_default ;
if ( flags & Regex_FirstOnly )
out | = std : : regex_constants : : format_first_only ;
return out ;
}
static Nillable < C4String * > FnRegexReplace ( C4PropList * _this , C4String * source , C4String * regex , C4String * replacement , long flags )
{
if ( ! source | | ! regex | | ! replacement ) return C4Void ( ) ;
try
{
std : : regex re ( regex - > GetCStr ( ) , C4IntToSyntaxOption ( flags ) ) ;
std : : string out = std : : regex_replace ( source - > GetCStr ( ) , re , replacement - > GetCStr ( ) , C4IntToMatchFlag ( flags ) ) ;
return : : Strings . RegString ( out . c_str ( ) ) ;
}
catch ( const std : : regex_error & e )
{
throw C4AulExecError ( FormatString ( " RegexReplace: %s " , e . what ( ) ) . getData ( ) ) ;
}
}
static Nillable < C4ValueArray * > FnRegexSearch ( C4PropList * _this , C4String * source , C4String * regex , long flags )
{
if ( ! source | | ! regex ) return C4Void ( ) ;
try
{
std : : regex re ( regex - > GetCStr ( ) , C4IntToSyntaxOption ( flags ) ) ;
C4ValueArray * out = new C4ValueArray ( ) ;
2016-09-17 23:16:06 +00:00
const auto & data = source - > GetData ( ) ;
size_t pos = 0 ;
std : : cmatch m ;
long i = 0 ;
// std::regex_iterator would be the better way to do this, but is is broken in libc++ (see LLVM bug #21597).
2016-09-18 08:49:06 +00:00
while ( pos < = data . getLength ( ) & & std : : regex_search ( data . getData ( ) + pos , data . getData ( ) + data . getLength ( ) , m , re ) )
2016-09-16 19:15:52 +00:00
{
2016-09-17 23:16:06 +00:00
int char_pos = GetCharacterCount ( std : : string ( data . getData ( ) , pos + m . position ( ) ) . c_str ( ) ) ;
( * out ) [ i + + ] = C4VInt ( char_pos ) ;
2016-09-16 19:15:52 +00:00
if ( flags & Regex_FirstOnly ) break ;
2016-09-18 17:40:32 +00:00
pos + = m . position ( ) + std : : max < size_t > ( m . length ( ) , 1 ) ;
2016-09-16 19:15:52 +00:00
}
return out ;
}
catch ( const std : : regex_error & e )
{
throw C4AulExecError ( FormatString ( " RegexSearch: %s " , e . what ( ) ) . getData ( ) ) ;
}
}
static Nillable < C4ValueArray * > FnRegexMatch ( C4PropList * _this , C4String * source , C4String * regex , long flags )
{
if ( ! source | | ! regex ) return C4Void ( ) ;
try
{
std : : regex re ( regex - > GetCStr ( ) , C4IntToSyntaxOption ( flags ) ) ;
C4ValueArray * out = new C4ValueArray ( ) ;
2016-09-17 23:16:06 +00:00
const auto & data = source - > GetData ( ) ;
size_t pos = 0 ;
std : : cmatch m ;
2016-09-16 19:15:52 +00:00
long i = 0 ;
2016-09-18 08:49:06 +00:00
while ( pos < = data . getLength ( ) & & std : : regex_search ( data . getData ( ) + pos , data . getData ( ) + data . getLength ( ) , m , re ) )
2016-09-16 19:15:52 +00:00
{
2016-09-17 23:16:06 +00:00
C4ValueArray * match = new C4ValueArray ( m . size ( ) ) ;
2016-09-16 19:15:52 +00:00
long j = 0 ;
for ( auto sm : m )
{
( * match ) [ j + + ] = C4VString ( String ( sm . str ( ) . c_str ( ) ) ) ;
}
( * out ) [ i + + ] = C4VArray ( match ) ;
if ( flags & Regex_FirstOnly ) break ;
2016-09-18 17:40:32 +00:00
pos + = m . position ( ) + std : : max < size_t > ( m . length ( ) , 1 ) ;
2016-09-16 19:15:52 +00:00
}
return out ;
}
catch ( const std : : regex_error & e )
{
throw C4AulExecError ( FormatString ( " RegexMatch: %s " , e . what ( ) ) . getData ( ) ) ;
}
}
2016-09-18 09:10:19 +00:00
static Nillable < C4ValueArray * > FnRegexSplit ( C4PropList * _this , C4String * source , C4String * regex , long flags )
{
if ( ! source | | ! regex ) return C4Void ( ) ;
try
{
std : : regex re ( regex - > GetCStr ( ) , C4IntToSyntaxOption ( flags ) ) ;
C4ValueArray * out = new C4ValueArray ( ) ;
const auto & data = source - > GetData ( ) ;
size_t pos = 0 ;
std : : cmatch m ;
long i = 0 ;
while ( pos < = data . getLength ( ) & & std : : regex_search ( data . getData ( ) + pos , data . getData ( ) + data . getLength ( ) , m , re ) )
{
// As we're advancing by one character for zero-length matches, always
// include at least one character here.
2016-09-18 17:40:32 +00:00
std : : string substr ( data . getData ( ) + pos , std : : max < size_t > ( m . position ( ) , 1 ) ) ;
2016-09-18 09:10:19 +00:00
( * out ) [ i + + ] = C4VString ( String ( substr . c_str ( ) ) ) ;
if ( flags & Regex_FirstOnly ) break ;
2016-09-18 17:40:32 +00:00
pos + = m . position ( ) + std : : max < size_t > ( m . length ( ) , 1 ) ;
2016-09-18 09:10:19 +00:00
}
if ( pos < = data . getLength ( ) )
{
std : : string substr ( data . getData ( ) + pos , data . getLength ( ) - pos ) ;
( * out ) [ i + + ] = C4VString ( String ( substr . c_str ( ) ) ) ;
}
return out ;
}
catch ( const std : : regex_error & e )
{
throw C4AulExecError ( FormatString ( " RegexSplit: %s " , e . what ( ) ) . getData ( ) ) ;
}
}
2016-09-16 19:15:52 +00:00
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 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 ;
}
2016-01-03 01:39:11 +00:00
static void 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 ) ;
}
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
}
2016-07-31 01:43:01 +00:00
static C4String * FnStringToIdentifier ( C4PropList * _this , C4String * pString )
{
// Change an arbitrary string so that it becomes an identifier
const char * text = FnStringPar ( pString ) ;
if ( ! text ) return nullptr ;
StdStrBuf result ;
bool had_valid = false , had_invalid = false ;
const char * ptext = text , * t0 = text ;
uint32_t c = GetNextCharacter ( & text ) ;
while ( c )
{
if ( isalnum ( c ) | | c = = ' _ ' )
{
// Starting with a digit? Needs to prepend a character
if ( isdigit ( c ) & & ! had_valid )
{
result . Append ( " _ " ) ;
had_invalid = true ;
}
// Valid character: Append to result string if a modification had to be done
if ( had_invalid ) result . Append ( ptext , text - ptext ) ;
had_valid = true ;
}
else
{
// Invalid character. Make sure result is created from previous valid characters
if ( ! had_invalid )
{
result . Copy ( t0 , ptext - t0 ) ;
had_invalid = true ;
}
}
ptext = text ;
c = GetNextCharacter ( & text ) ;
}
// Make sure no empty string is returned
if ( ! had_valid ) return : : Strings . RegString ( " _ " ) ;
// Return either modified string or the original if no modifications were needed
return had_invalid ? : : Strings . RegString ( result ) : pString ;
}
2016-07-31 12:15:54 +00:00
static C4Value Fneval ( C4PropList * _this , C4String * strScript , bool dont_pass_errors )
2011-03-04 12:49:41 +00:00
{
2016-07-31 12:15:54 +00:00
return : : AulExec . DirectExec ( _this , FnStringPar ( strScript ) , " eval " , ! dont_pass_errors ) ;
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
2016-11-02 23:58:02 +00:00
pFunc = pSFunc ? pSFunc - > OwnerOverloaded : nullptr ;
2011-03-04 12:49:41 +00:00
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
{
2016-01-24 22:41:12 +00:00
AulExec . StartTrace ( ) ;
2011-03-04 12:49:41 +00:00
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
2016-01-03 19:01:37 +00:00
C4ScriptHost * pScript ;
2013-03-03 18:25:18 +00:00
if ( pDef )
2011-03-04 12:49:41 +00:00
pScript = & pDef - > Script ;
else
2016-11-02 23:58:02 +00:00
pScript = nullptr ;
2011-03-04 12:49:41 +00:00
// 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 ( ) ;
}
2016-07-13 06:12:31 +00:00
static Nillable < C4String * > FnReplaceString ( C4PropList * _this , C4String * source , C4String * from , C4String * to )
{
if ( ! from ) return source ;
if ( ! source ) return C4Void ( ) ;
const char * szto = to ? to - > GetCStr ( ) : " " ;
const char * szfrom = from - > GetCStr ( ) ;
StdStrBuf s ( source - > GetData ( ) , true ) ;
if ( s . Replace ( szfrom , szto ) )
{
return : : Strings . RegString ( s . getData ( ) ) ;
}
else
{
return source ;
}
}
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 " ) ;
2016-05-01 22:34:18 +00:00
if ( pArray - > IsFrozen ( ) ) throw C4AulExecError ( " array sort: array is readonly " ) ;
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 " ) ;
2016-05-01 22:34:18 +00:00
if ( pArray - > IsFrozen ( ) ) throw C4AulExecError ( " array sort: array is readonly " ) ;
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 " ) ;
2016-05-01 22:34:18 +00:00
if ( pArray - > IsFrozen ( ) ) throw C4AulExecError ( " array sort: array is readonly " ) ;
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
2016-11-02 23:58:02 +00:00
if ( ! data ) return false ; // write nullptr? No.
2013-12-22 22:47:40 +00:00
// write it
file - > Write ( data - > GetCStr ( ) , data - > GetData ( ) . getLength ( ) ) ;
return true ;
}
2011-03-04 12:49:41 +00:00
//=========================== C4Script Function Map ===================================
C4ScriptConstDef C4ScriptConstMap [ ] =
{
2015-12-21 22:55:03 +00:00
{ " FX_OK " , C4V_Int , C4Fx_OK } , // generic standard behaviour for all effect callbacks
{ " FX_Effect_Deny " , C4V_Int , C4Fx_Effect_Deny } , // delete effect
{ " FX_Effect_Annul " , C4V_Int , C4Fx_Effect_Annul } , // delete effect, because it has annulled a countereffect
{ " FX_Effect_AnnulDoCalls " , C4V_Int , C4Fx_Effect_AnnulCalls } , // delete effect, because it has annulled a countereffect; temp readd countereffect
{ " FX_Execute_Kill " , C4V_Int , C4Fx_Execute_Kill } , // execute callback: Remove effect now
{ " FX_Stop_Deny " , C4V_Int , C4Fx_Stop_Deny } , // deny effect removal
{ " FX_Start_Deny " , C4V_Int , C4Fx_Start_Deny } , // deny effect start
{ " FX_Call_Normal " , C4V_Int , C4FxCall_Normal } , // normal call; effect is being added or removed
{ " FX_Call_Temp " , C4V_Int , C4FxCall_Temp } , // temp call; effect is being added or removed in responce to a lower-level effect change
{ " FX_Call_TempAddForRemoval " , C4V_Int , C4FxCall_TempAddForRemoval } , // temp call; effect is being added because it had been temp removed and is now removed forever
{ " FX_Call_RemoveClear " , C4V_Int , C4FxCall_RemoveClear } , // effect is being removed because object is being removed
{ " FX_Call_RemoveDeath " , C4V_Int , C4FxCall_RemoveDeath } , // effect is being removed because object died - return -1 to avoid removal
{ " FX_Call_DmgScript " , C4V_Int , C4FxCall_DmgScript } , // damage through script call
{ " FX_Call_DmgBlast " , C4V_Int , C4FxCall_DmgBlast } , // damage through blast
{ " FX_Call_DmgFire " , C4V_Int , C4FxCall_DmgFire } , // damage through fire
{ " FX_Call_DmgChop " , C4V_Int , C4FxCall_DmgChop } , // damage through chopping
{ " FX_Call_Energy " , C4V_Int , 32 } , // bitmask for generic energy loss
{ " FX_Call_EngScript " , C4V_Int , C4FxCall_EngScript } , // energy loss through script call
{ " FX_Call_EngBlast " , C4V_Int , C4FxCall_EngBlast } , // energy loss through blast
{ " FX_Call_EngObjHit " , C4V_Int , C4FxCall_EngObjHit } , // energy loss through object hitting the living
{ " FX_Call_EngFire " , C4V_Int , C4FxCall_EngFire } , // energy loss through fire
{ " FX_Call_EngBaseRefresh " , C4V_Int , C4FxCall_EngBaseRefresh } , // energy reload in base (also by base object, but that's normally not called)
{ " FX_Call_EngAsphyxiation " , C4V_Int , C4FxCall_EngAsphyxiation } , // energy loss through asphyxiaction
{ " FX_Call_EngCorrosion " , C4V_Int , C4FxCall_EngCorrosion } , // energy loss through corrosion (acid)
{ " FX_Call_EngGetPunched " , C4V_Int , C4FxCall_EngGetPunched } , // energy loss from punch
2016-09-16 19:15:52 +00:00
{ " Regex_CaseInsensitive " , C4V_Int , Regex_CaseInsensitive } ,
{ " Regex_FirstOnly " , C4V_Int , Regex_FirstOnly } ,
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
2016-11-02 23:58:02 +00:00
{ nullptr , 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 } ,
2015-12-21 22:55:03 +00:00
{ " EffectCall " , 1 , C4V_Any , { C4V_Object , C4V_PropList , C4V_String , C4V_Any , C4V_Any , C4V_Any , C4V_Any , C4V_Any , C4V_Any , C4V_Any } , FnEffectCall } ,
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
2016-11-02 23:58:02 +00:00
{ nullptr , 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 ) ) ;
}
2016-01-03 16:14:18 +00:00
C4PropListStatic * p = pEngine - > GetPropList ( ) ;
2011-03-04 12:49:41 +00:00
// add all def script funcs
for ( C4ScriptFnDef * pDef = & C4ScriptFnMap [ 0 ] ; pDef - > Identifier ; pDef + + )
2016-01-03 16:14:18 +00:00
new C4AulDefFunc ( p , pDef ) ;
# define F(f) ::AddFunc(p, #f, Fn##f)
2012-05-18 17:41:38 +00:00
F ( Abs ) ;
F ( Min ) ;
F ( Max ) ;
F ( Sin ) ;
F ( Cos ) ;
F ( Sqrt ) ;
F ( ArcSin ) ;
F ( ArcCos ) ;
F ( BoundBy ) ;
F ( Inside ) ;
F ( Random ) ;
F ( CreateArray ) ;
F ( CreatePropList ) ;
F ( GetProperties ) ;
2012-05-18 17:44:53 +00:00
F ( GetProperty ) ;
F ( SetProperty ) ;
2016-04-27 18:42:59 +00:00
F ( GetPrototype ) ;
F ( SetPrototype ) ;
2012-05-18 17:44:53 +00:00
F ( ResetProperty ) ;
2014-04-20 20:05:50 +00:00
F ( GetName ) ;
2015-12-21 22:55:03 +00:00
F ( AddEffect ) ;
2015-12-22 23:40:16 +00:00
F ( CreateEffect ) ;
2015-12-21 22:55:03 +00:00
F ( CheckEffect ) ;
F ( RemoveEffect ) ;
F ( GetEffect ) ;
F ( GetEffectCount ) ;
2016-09-16 19:15:52 +00:00
F ( RegexReplace ) ;
F ( RegexSearch ) ;
F ( RegexMatch ) ;
2016-09-18 09:10:19 +00:00
F ( RegexSplit ) ;
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:44:53 +00:00
F ( eval ) ;
2016-07-31 01:43:01 +00:00
F ( StringToIdentifier ) ;
2012-05-18 17:41:38 +00:00
F ( GetConstantNameByValue ) ;
2016-07-13 06:12:31 +00:00
F ( ReplaceString ) ;
2011-03-04 12:49:41 +00:00
2016-01-03 16:14:18 +00:00
: : AddFunc ( p , " Translate " , C4AulExec : : FnTranslate ) ;
: : AddFunc ( p , " LogCallStack " , C4AulExec : : FnLogCallStack ) ;
2012-05-18 17:41:38 +00:00
# undef F
2011-03-04 12:49:41 +00:00
}