Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

714 lines
17 KiB

  1. //========== Copyright � 2008, Valve Corporation, All rights reserved. ========
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================
  6. #define WIN32_LEAN_AND_MEAN 1
  7. #pragma warning( disable:4201)
  8. #pragma comment(lib, "winmm.lib" )
  9. #include <windows.h>
  10. #include <mmsystem.h> // multimedia timer (may need winmm.lib)
  11. #include <stdio.h>
  12. #include <io.h>
  13. #include <conio.h>
  14. #include "platform.h"
  15. #include "datamap.h"
  16. #include "tier1/functors.h"
  17. #include "tier1/utlvector.h"
  18. #include "tier1/utlhash.h"
  19. #include "tier1/fmtstr.h"
  20. #include "vscript//ivscript.h"
  21. #include "gmThread.h" // game monkey script
  22. #include "gmArrayLib.h"
  23. #include "gmCall.h"
  24. #include "gmGCRoot.h"
  25. #include "gmGCRootUtil.h"
  26. #include "gmHelpers.h"
  27. #include "gmMathLib.h"
  28. #include "gmStringLib.h"
  29. #include "gmVector3Lib.h"
  30. //-----------------------------------------------------------------------------
  31. //
  32. //-----------------------------------------------------------------------------
  33. class CGCDisabler
  34. {
  35. public:
  36. CGCDisabler( gmMachine *pMachine )
  37. {
  38. m_pMachine = pMachine;
  39. m_bWasEnabled = m_pMachine->IsGCEnabled();
  40. m_pMachine->EnableGC( false );
  41. }
  42. ~CGCDisabler()
  43. {
  44. m_pMachine->EnableGC( m_bWasEnabled );
  45. }
  46. gmMachine *m_pMachine;
  47. bool m_bWasEnabled;
  48. };
  49. #define DISABLE_GC() CGCDisabler gcDisabler( this )
  50. //-----------------------------------------------------------------------------
  51. //
  52. //-----------------------------------------------------------------------------
  53. class CGameMonkeyVM : public IScriptVM,
  54. public gmMachine
  55. {
  56. public:
  57. CGameMonkeyVM()
  58. {
  59. }
  60. bool Init()
  61. {
  62. if ( !m_global )
  63. {
  64. // Must be a re-init
  65. gmMachine::Init();
  66. }
  67. s_printCallback = ScriptPrintCallback;
  68. SetDebugMode( true );
  69. AddCPPOwnedGMObject( GetGlobals() );
  70. gmBindArrayLib( this );
  71. gmBindMathLib( this );
  72. gmBindStringLib( this );
  73. gmBindVector3Lib( this );
  74. m_TypeMap.Init( 256 );
  75. return true;
  76. }
  77. void Shutdown()
  78. {
  79. // Dump run time errors to output
  80. if ( GetDebugMode() )
  81. {
  82. FlushErrorLog();
  83. }
  84. RemoveAllCPPOwnedGMObjects();
  85. ResetAndFreeMemory();
  86. m_TypeMap.Purge();
  87. }
  88. ScriptLanguage_t GetLanguage()
  89. {
  90. return SL_GAMEMONKEY;
  91. }
  92. virtual const char *GetLanguageName()
  93. {
  94. return "GameMonkey";
  95. }
  96. virtual void AddSearchPath( const char *pszSearchPath )
  97. {
  98. }
  99. bool ConnectDebugger() { return true; }
  100. void DisconnectDebugger() {}
  101. bool Frame( float simTime )
  102. {
  103. return false;
  104. }
  105. HSCRIPT CompileScript( const char *pszScript, const char *pszId )
  106. {
  107. DISABLE_GC();
  108. gmFunctionObject *pFunction = CompileStringToFunction( pszScript );
  109. if ( !pFunction )
  110. {
  111. FlushErrorLog();
  112. return NULL;
  113. }
  114. ObjectHandle_t *pObjectHandle = new ObjectHandle_t;
  115. pObjectHandle->pObject = pFunction;
  116. AddCPPOwnedGMObject( pFunction );
  117. if ( pszId )
  118. {
  119. pObjectHandle->pString = AllocStringObject( pszId );
  120. AddCPPOwnedGMObject( pObjectHandle->pString );
  121. gmTableObject *pGlobals = GetGlobals();
  122. pGlobals->Set( this, gmVariable(pObjectHandle->pString), gmVariable(pFunction) );
  123. }
  124. else
  125. {
  126. pObjectHandle->pString = NULL;
  127. }
  128. return (HSCRIPT)pObjectHandle;
  129. }
  130. void ReleaseScript( HSCRIPT hScript )
  131. {
  132. ReleaseHandle( hScript );
  133. }
  134. ScriptStatus_t Run( HSCRIPT hScript, HSCRIPT hScope = NULL, bool bWait = true )
  135. {
  136. return CGameMonkeyVM::ExecuteFunction( hScript, NULL, 0, NULL, hScope, bWait );
  137. }
  138. ScriptStatus_t Run( const char *pszScript, bool bWait = true )
  139. {
  140. Assert( bWait );
  141. int errors = ExecuteString( pszScript, NULL, bWait );
  142. // Dump compile time errors to output
  143. if(errors)
  144. {
  145. bool first = true;
  146. const char * message;
  147. while((message = GetLog().GetEntry(first)))
  148. {
  149. Msg( "%s\n", message );
  150. }
  151. GetLog().Reset();
  152. return SCRIPT_ERROR;
  153. }
  154. return SCRIPT_DONE;
  155. }
  156. ScriptStatus_t Run( HSCRIPT hScript, bool bWait )
  157. {
  158. Assert( bWait );
  159. return CGameMonkeyVM::Run( hScript, (HSCRIPT)NULL, bWait );
  160. }
  161. HSCRIPT CreateScope( const char *pszScope, HSCRIPT hParent = NULL )
  162. {
  163. Assert( pszScope );
  164. Assert( !hParent );
  165. DISABLE_GC();
  166. gmTableObject *pGlobals = GetGlobals();
  167. gmTableObject *pNewTable = AllocTableObject();
  168. ObjectHandle_t *pObjectHandle = new ObjectHandle_t;
  169. AddCPPOwnedGMObject( pNewTable );
  170. pObjectHandle->pObject = pNewTable;
  171. pObjectHandle->pString = AllocStringObject( pszScope );
  172. AddCPPOwnedGMObject( pObjectHandle->pString );
  173. pGlobals->Set( this, gmVariable(pObjectHandle->pString), gmVariable(pNewTable) );
  174. return (HSCRIPT)pObjectHandle;
  175. }
  176. void ReleaseScope( HSCRIPT hScript )
  177. {
  178. ReleaseHandle( hScript );
  179. }
  180. HSCRIPT LookupFunction( const char *pszFunction, HSCRIPT hScope = NULL )
  181. {
  182. gmTableObject *pScope;
  183. if ( !hScope )
  184. {
  185. pScope = GetGlobals();
  186. }
  187. else
  188. {
  189. ObjectHandle_t *pScopeHandle = (ObjectHandle_t *)hScope;
  190. pScope = assert_cast<gmTableObject *>(pScopeHandle->pObject);
  191. }
  192. gmVariable varFunction = pScope->Get( this, pszFunction );
  193. gmFunctionObject *pFunction = varFunction.GetFunctionObjectSafe();
  194. if ( pFunction )
  195. {
  196. ObjectHandle_t *pFunctionHandle = new ObjectHandle_t;
  197. pFunctionHandle->pObject = pFunction;
  198. pFunctionHandle->pString = NULL;
  199. AddCPPOwnedGMObject( pFunction );
  200. return (HSCRIPT)pFunctionHandle;
  201. }
  202. return NULL;
  203. }
  204. void ReleaseFunction( HSCRIPT hScript )
  205. {
  206. ReleaseHandle( hScript );
  207. }
  208. ScriptStatus_t ExecuteFunction( HSCRIPT hFunction, ScriptVariant_t *pArgs, int nArgs, ScriptVariant_t *pReturn, HSCRIPT hScope, bool bWait )
  209. {
  210. Assert( hFunction );
  211. Assert( bWait );
  212. ScriptStatus_t result = SCRIPT_ERROR;
  213. if ( pReturn )
  214. {
  215. pReturn->m_type = FIELD_VOID;
  216. }
  217. if ( hFunction )
  218. {
  219. ObjectHandle_t *pObjectHandle= (ObjectHandle_t *)hFunction;
  220. gmTableObject *pGlobals = NULL;
  221. gmTableObject *pScope;
  222. if ( hScope )
  223. {
  224. ObjectHandle_t *pScopeHandle= (ObjectHandle_t *)hScope;
  225. pScope = assert_cast<gmTableObject *>(pScopeHandle->pObject);
  226. pGlobals = GetGlobals();
  227. SetGlobals( pScope );
  228. }
  229. gmCall functionCaller;
  230. gmFunctionObject *pFunction = assert_cast<gmFunctionObject *>(pObjectHandle->pObject);
  231. if ( functionCaller.BeginFunction( this, pFunction, gmVariable::s_null, !bWait ) )
  232. {
  233. for ( int i = 0; i < nArgs; i++ )
  234. {
  235. switch ( pArgs[i].m_type )
  236. {
  237. case FIELD_FLOAT: functionCaller.AddParamFloat( pArgs[i] ); break;
  238. case FIELD_CSTRING: functionCaller.AddParamString( pArgs[i], strlen( pArgs[i].m_pszString ) ); break;
  239. case FIELD_VECTOR: Assert( 0 ); functionCaller.AddParamNull(); break;
  240. case FIELD_INTEGER: functionCaller.AddParamInt( pArgs[i] ); break;
  241. case FIELD_BOOLEAN: functionCaller.AddParamInt( pArgs[i].m_bool ); break;
  242. case FIELD_CHARACTER: { char sz[2]; sz[0] = pArgs[i].m_char; sz[1] = 0; functionCaller.AddParamString( sz, 1 ); break; }
  243. }
  244. }
  245. functionCaller.End();
  246. if ( pReturn && ( bWait || !functionCaller.GetThread() ) && functionCaller.DidReturnVariable() )
  247. {
  248. const gmVariable &ret = functionCaller.GetReturnedVariable();
  249. switch ( ret.m_type )
  250. {
  251. case GM_NULL: break;
  252. case GM_INT: *pReturn = ret.m_value.m_int; break;
  253. case GM_FLOAT: *pReturn = ret.m_value.m_float; break;
  254. case GM_STRING:
  255. {
  256. gmStringObject *pString = (gmStringObject *)ret.m_value.m_ref;
  257. int size = pString->GetLength() + 1;
  258. pReturn->m_type = FIELD_CSTRING;
  259. pReturn->m_pszString = new char[size];
  260. memcpy( (void *)pReturn->m_pszString, pString->GetString(), size );
  261. }
  262. break;
  263. default:
  264. DevMsg( "Script function returned unsupported type\n" );
  265. pReturn->m_type = FIELD_VOID;
  266. }
  267. }
  268. }
  269. if ( !FlushErrorLog() )
  270. {
  271. result = SCRIPT_DONE;
  272. }
  273. if ( hScope )
  274. {
  275. SetGlobals( pGlobals );
  276. }
  277. }
  278. return result;
  279. }
  280. gmMachine *GetMachine()
  281. {
  282. return this;
  283. }
  284. void RegisterFunction( ScriptFunctionBinding_t *pScriptFunction )
  285. {
  286. RegisterLibraryFunction( pScriptFunction->m_desc.m_pszScriptName, &TranslateCall, NULL, pScriptFunction );
  287. }
  288. bool RegisterClass( ScriptClassDesc_t *pClassDesc )
  289. {
  290. COMPILE_TIME_ASSERT( sizeof(pClassDesc) == sizeof(int) );
  291. if ( m_TypeMap.Find( (int)pClassDesc ) != m_TypeMap.InvalidHandle() )
  292. {
  293. return true;
  294. }
  295. gmType type = CreateUserType( pClassDesc->m_pszScriptName );
  296. m_TypeMap.Insert( (int)pClassDesc, type );
  297. ScriptClassDesc_t *pCurDesc = pClassDesc;
  298. CUtlVectorFixed<gmFunctionEntry, 512> functionEntries;
  299. while ( pCurDesc )
  300. {
  301. int nFunctions = pClassDesc->m_FunctionBindings.Count();
  302. functionEntries.SetSize( nFunctions );
  303. int i;
  304. for ( i = 0; i < nFunctions; i++)
  305. {
  306. functionEntries[i].m_function = &TranslateCall;
  307. functionEntries[i].m_name = pClassDesc->m_FunctionBindings[i].m_desc.m_pszFunction;
  308. functionEntries[i].m_userData = &pClassDesc->m_FunctionBindings[i];
  309. }
  310. RegisterTypeLibrary( type, functionEntries.Base(), nFunctions );
  311. pCurDesc = pCurDesc->m_pBaseDesc;
  312. }
  313. if ( pClassDesc->m_pfnConstruct )
  314. {
  315. RegisterLibraryFunction( pClassDesc->m_pszScriptName, &Construct, NULL, pClassDesc );
  316. RegisterUserCallbacks( type, NULL, &Destruct );
  317. }
  318. return true;
  319. }
  320. bool RegisterInstance( ScriptClassDesc_t *pDesc, void *pInstance, const char *pszInstance, HSCRIPT hScope = NULL )
  321. {
  322. if ( !RegisterClass( pDesc ) )
  323. {
  324. return false;
  325. }
  326. DISABLE_GC();
  327. bool bResult = true;
  328. InstanceContext_t *pInstanceContext = new InstanceContext_t;
  329. pInstanceContext->pInstance = pInstance;
  330. pInstanceContext->pClassDesc = NULL; // i.e., no destruct
  331. // @TODO: This extra hash lookup could be eliminated (as it is also done in RegisterClass above) [2/13/2008 tom]
  332. gmUserObject *pObject = AllocUserObject( pInstanceContext, m_TypeMap[m_TypeMap.Find((int)pDesc)] );
  333. AddCPPOwnedGMObject( pObject );
  334. gmTableObject *pScope;
  335. if ( hScope )
  336. {
  337. ObjectHandle_t *pScopeHandle= (ObjectHandle_t *)hScope;
  338. pScope = (gmTableObject *)pScopeHandle->pObject;
  339. }
  340. else
  341. {
  342. pScope = GetGlobals();
  343. }
  344. if ( pScope )
  345. {
  346. pScope->Set( this, pszInstance, gmVariable( pObject ) );
  347. }
  348. else
  349. {
  350. DevMsg( "Undefined script scope!\n" );
  351. bResult = false;
  352. }
  353. return bResult;
  354. }
  355. void RemoveInstance( ScriptClassDesc_t *pDesc, void *pInstance, const char *pszInstance, HSCRIPT hScope = NULL )
  356. {
  357. DISABLE_GC();
  358. gmTableObject *pScope;
  359. if ( hScope )
  360. {
  361. ObjectHandle_t *pScopeHandle= (ObjectHandle_t *)hScope;
  362. pScope = (gmTableObject *)pScopeHandle->pObject;
  363. }
  364. else
  365. {
  366. pScope = GetGlobals();
  367. }
  368. if ( pScope )
  369. {
  370. gmVariable scriptVar = pScope->Get( this, pszInstance );
  371. gmUserObject *pObject = ( !scriptVar.IsNull() ) ? scriptVar.GetUserObjectSafe( m_TypeMap[m_TypeMap.Find((int)pDesc)] ) : NULL;
  372. if ( pObject )
  373. {
  374. delete pObject->m_user;
  375. pObject->m_user = NULL;
  376. pScope->Set( this, pszInstance, gmVariable::s_null );
  377. RemoveCPPOwnedGMObject( pObject );
  378. }
  379. else
  380. {
  381. DevMsg( "Unknown instance\n" );
  382. }
  383. }
  384. else
  385. {
  386. DevMsg( "Undefined script scope!\n" );
  387. }
  388. }
  389. private:
  390. struct InstanceContext_t
  391. {
  392. void *pInstance;
  393. ScriptClassDesc_t *pClassDesc;
  394. };
  395. struct ObjectHandle_t
  396. {
  397. gmStringObject *pString;
  398. gmObject *pObject;
  399. };
  400. void ReleaseHandle( HSCRIPT hScript )
  401. {
  402. if ( hScript )
  403. {
  404. ObjectHandle_t *pObjectHandle = (ObjectHandle_t *)hScript;
  405. RemoveCPPOwnedGMObject( pObjectHandle->pObject );
  406. if ( pObjectHandle->pString )
  407. {
  408. gmTableObject *pGlobals = GetGlobals();
  409. pGlobals->Set( this, gmVariable(pObjectHandle->pString), gmVariable::s_null );
  410. RemoveCPPOwnedGMObject( pObjectHandle->pString );
  411. }
  412. delete pObjectHandle;
  413. }
  414. }
  415. static void ScriptPrintCallback(gmMachine *pMachine, const char *pString)
  416. {
  417. Msg( "%s\n", pString );
  418. }
  419. static int GM_CDECL TranslateCall( gmThread *a_thread )
  420. {
  421. const gmFunctionObject *fn = a_thread->GetFunctionObject();
  422. ScriptFunctionBinding_t *pVMScriptFunction = (ScriptFunctionBinding_t *)fn->m_cUserData;
  423. int nActualParams = a_thread->GetNumParams();
  424. int nFormalParams = pVMScriptFunction->m_desc.m_Parameters.Count();
  425. GM_CHECK_NUM_PARAMS( nFormalParams );
  426. CUtlVectorFixed<ScriptVariant_t, 14> params;
  427. ScriptVariant_t returnValue;
  428. params.SetSize( nFormalParams );
  429. int i = 0;
  430. if ( nActualParams )
  431. {
  432. int iLimit = min( nActualParams, nFormalParams );
  433. ScriptDataType_t *pCurParamType = pVMScriptFunction->m_desc.m_Parameters.Base();
  434. for ( i = 0; i < iLimit; i++, pCurParamType++ )
  435. {
  436. switch ( *pCurParamType )
  437. {
  438. case FIELD_FLOAT: params[i] = a_thread->ParamFloatOrInt( i ); break;
  439. case FIELD_CSTRING: params[i] = a_thread->ParamString( i ); break;
  440. case FIELD_VECTOR: Assert( 0 ); params[i] = (Vector *)NULL; break;
  441. case FIELD_INTEGER: params[i] = (int)a_thread->ParamFloatOrInt( i ); break;
  442. case FIELD_BOOLEAN:
  443. {
  444. int type = a_thread->ParamType(i);
  445. if ( type == GM_INT )
  446. params[i] = (bool)(a_thread->Param(i).m_value.m_int != 0 );
  447. else if ( type == GM_FLOAT )
  448. params[i] = (bool)(a_thread->Param(i).m_value.m_float != 0.0 );
  449. else
  450. params[i] = true;
  451. break;
  452. }
  453. case FIELD_CHARACTER: params[i] = a_thread->ParamString( i )[0]; break;
  454. }
  455. }
  456. }
  457. for ( ; i < nFormalParams; i++ )
  458. {
  459. COMPILE_TIME_ASSERT( sizeof(Vector *) >= sizeof(int) );
  460. params[i] = (Vector *)NULL;
  461. }
  462. InstanceContext_t *pContext;
  463. void *pObject;
  464. if ( pVMScriptFunction->m_flags & SF_MEMBER_FUNC )
  465. {
  466. pContext = (InstanceContext_t *)a_thread->ThisUser();
  467. if ( !pContext )
  468. {
  469. return GM_EXCEPTION;
  470. }
  471. pObject = pContext->pInstance;
  472. if ( !pObject )
  473. {
  474. return GM_EXCEPTION;
  475. }
  476. }
  477. else
  478. {
  479. pObject = NULL;
  480. }
  481. (*pVMScriptFunction->m_pfnBinding)( pVMScriptFunction->m_pFunction, pObject, params.Base(), params.Count(), ( pVMScriptFunction->m_desc.m_ReturnType != FIELD_VOID ) ? &returnValue : NULL );
  482. if ( pVMScriptFunction->m_desc.m_ReturnType != FIELD_VOID )
  483. {
  484. switch ( pVMScriptFunction->m_desc.m_ReturnType )
  485. {
  486. case FIELD_FLOAT: a_thread->PushFloat( returnValue ); break;
  487. case FIELD_CSTRING: Assert( 0 ); a_thread->PushNull(); break;
  488. case FIELD_VECTOR: Assert( 0 ); a_thread->PushNull(); break;
  489. case FIELD_INTEGER: a_thread->PushInt( returnValue ); break;
  490. case FIELD_BOOLEAN: a_thread->PushInt( (bool)returnValue ); break;
  491. case FIELD_CHARACTER: Assert( 0 ); a_thread->PushNull(); break;
  492. }
  493. }
  494. return GM_OK;
  495. }
  496. static int GM_CDECL Construct( gmThread *a_thread )
  497. {
  498. CGameMonkeyVM *pThis = assert_cast<CGameMonkeyVM *>(a_thread->GetMachine());
  499. const gmFunctionObject *fn = a_thread->GetFunctionObject();
  500. ScriptClassDesc_t *pClassDesc = (ScriptClassDesc_t *)fn->m_cUserData;
  501. GM_CHECK_NUM_PARAMS( 0 );
  502. InstanceContext_t *pInstanceContext = new InstanceContext_t;
  503. pInstanceContext->pInstance = pClassDesc->m_pfnConstruct();
  504. pInstanceContext->pClassDesc = pClassDesc;
  505. // @TODO: put the type in the userdata? [2/12/2008 tom]
  506. a_thread->PushNewUser( pInstanceContext, pThis->m_TypeMap[pThis->m_TypeMap.Find((int)pClassDesc)] );
  507. return GM_OK;
  508. }
  509. static void Destruct( gmMachine *pMachine, gmUserObject* pObject )
  510. {
  511. InstanceContext_t *pInstanceContext = ( InstanceContext_t *)pObject->m_user;
  512. if ( pInstanceContext && pInstanceContext->pClassDesc )
  513. {
  514. pInstanceContext->pClassDesc->m_pfnDestruct( pInstanceContext->pInstance );
  515. delete pInstanceContext;
  516. }
  517. }
  518. bool FlushErrorLog()
  519. {
  520. bool first = true;
  521. bool errors = false;
  522. const char * message;
  523. while((message = GetLog().GetEntry(first)))
  524. {
  525. Msg( "%s\n", message );
  526. errors = true;
  527. }
  528. GetLog().Reset();
  529. return errors;
  530. }
  531. CUtlHashFast<gmType, CUtlHashFastGenericHash> m_TypeMap;
  532. };
  533. IScriptVM *ScriptCreateGameMonkeyVM()
  534. {
  535. return new CGameMonkeyVM;
  536. }
  537. void ScriptDestroyGameMonkeyVM( IScriptVM *pVM )
  538. {
  539. CGameMonkeyVM *pGameMonkeyVM = assert_cast<CGameMonkeyVM *>(pVM);
  540. delete pGameMonkeyVM;
  541. }
  542. #ifdef VGM_TEST
  543. CGameMonkeyVM g_GMScriptVM;
  544. IScriptVM *pScriptVM = &g_GMScriptVM;
  545. struct Test
  546. {
  547. void Foo() { Msg( "Foo!\n");}
  548. };
  549. BEGIN_SCRIPTDESC_ROOT( Test )
  550. DEFINE_SCRIPTFUNC( Foo )
  551. END_SCRIPTDESC();
  552. Test test;
  553. //-----------------------------------------------------------------------------
  554. //
  555. //-----------------------------------------------------------------------------
  556. int main( int argc, const char **argv)
  557. {
  558. if ( argc < 2 )
  559. {
  560. printf( "No script specified" );
  561. return 1;
  562. }
  563. int key;
  564. do
  565. {
  566. pScriptVM->Init();
  567. const char *pszScript = argv[1];
  568. FILE *hFile = fopen( pszScript, "rb" );
  569. if ( !hFile )
  570. {
  571. printf( "\"%s\" not found.\n", pszScript );
  572. return 1;
  573. }
  574. int nFileLen = _filelength( _fileno( hFile ) );
  575. char *pBuf = new char[nFileLen + 1];
  576. fread( pBuf, 1, nFileLen, hFile );
  577. pBuf[nFileLen] = 0;
  578. fclose( hFile );
  579. printf( "Executing script \"%s\"\n----------------------------------------\n", pszScript );
  580. HSCRIPT hScript = pScriptVM->CompileScript( pBuf, "test" );
  581. if ( hScript )
  582. {
  583. HSCRIPT hScope = pScriptVM->CreateScope( "testScope" );
  584. pScriptVM->Run( hScript, hScope );
  585. HSCRIPT hFunction = pScriptVM->LookupFunction( "DoIt" );
  586. Assert( !hFunction );
  587. hFunction = pScriptVM->LookupFunction( "DoIt", hScope );
  588. Assert( hFunction );
  589. ScriptVariant_t ret;
  590. pScriptVM->RegisterInstance( &test, "test" );
  591. pScriptVM->Call( hFunction, hScope, true, &ret, "Har", 6.0, 99 );
  592. ret.Free();
  593. pScriptVM->ReleaseFunction( hFunction );
  594. pScriptVM->ReleaseScript( hScript );
  595. pScriptVM->ReleaseScope( hScope );
  596. }
  597. printf("Script complete. Press q to exit, enter to run again.\n");
  598. key = _getch(); // Keypress before exit
  599. pScriptVM->Shutdown();
  600. } while ( key != 'q' );
  601. return 0;
  602. }
  603. #endif