SWF_ScriptFunction.cpp 40 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255
  1. /*
  2. ===========================================================================
  3. Doom 3 BFG Edition GPL Source Code
  4. Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
  5. This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
  6. Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation, either version 3 of the License, or
  9. (at your option) any later version.
  10. Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
  16. In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
  17. If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
  18. ===========================================================================
  19. */
  20. #pragma hdrstop
  21. #include "../idlib/precompiled.h"
  22. idCVar swf_debug( "swf_debug", "0", CVAR_INTEGER|CVAR_ARCHIVE, "debug swf scripts. 1 shows traces/errors. 2 also shows warnings. 3 also shows disassembly. 4 shows parameters in the disassembly." );
  23. idCVar swf_debugInvoke( "swf_debugInvoke", "0", CVAR_INTEGER, "debug swf functions being called from game." );
  24. idSWFConstantPool::idSWFConstantPool() {
  25. }
  26. /*
  27. ========================
  28. idSWFConstantPool::Clear
  29. ========================
  30. */
  31. void idSWFConstantPool::Clear() {
  32. for ( int i = 0; i < pool.Num(); i++ ) {
  33. pool[i]->Release();
  34. }
  35. pool.Clear();
  36. }
  37. /*
  38. ========================
  39. idSWFConstantPool::Copy
  40. ========================
  41. */
  42. void idSWFConstantPool::Copy( const idSWFConstantPool & other ) {
  43. Clear();
  44. pool.SetNum( other.pool.Num() );
  45. for ( int i = 0; i < pool.Num(); i++ ) {
  46. pool[i] = other.pool[i];
  47. pool[i]->AddRef();
  48. }
  49. }
  50. /*
  51. ========================
  52. idSWFScriptFunction_Script::~idSWFScriptFunction_Script
  53. ========================
  54. */
  55. idSWFScriptFunction_Script::~idSWFScriptFunction_Script() {
  56. for ( int i = 0; i < scope.Num(); i++ ) {
  57. if ( verify( scope[i] ) ) {
  58. scope[i]->Release();
  59. }
  60. }
  61. if ( prototype ) {
  62. prototype->Release();
  63. }
  64. }
  65. /*
  66. ========================
  67. idSWFScriptFunction_Script::Call
  68. ========================
  69. */
  70. void idSWFScriptFunction_Script::SetScope( idList<idSWFScriptObject *> & newScope ) {
  71. assert( scope.Num() == 0 );
  72. for ( int i = 0; i < scope.Num(); i++ ) {
  73. if ( verify( scope[i] ) ) {
  74. scope[i]->Release();
  75. }
  76. }
  77. scope.Clear();
  78. scope.Append( newScope );
  79. for ( int i = 0; i < newScope.Num(); i++ ) {
  80. if ( verify( scope[i] ) ) {
  81. scope[i]->AddRef();
  82. }
  83. }
  84. }
  85. /*
  86. ========================
  87. idSWFScriptFunction_Script::Call
  88. ========================
  89. */
  90. idSWFScriptVar idSWFScriptFunction_Script::Call( idSWFScriptObject * thisObject, const idSWFParmList & parms ) {
  91. idSWFBitStream bitstream( data, length, false );
  92. // We assume scope[0] is the global scope
  93. assert( scope.Num() > 0 );
  94. if ( thisObject == NULL ) {
  95. thisObject = scope[0];
  96. }
  97. idSWFScriptObject * locals = idSWFScriptObject::Alloc();
  98. idSWFStack stack;
  99. stack.SetNum( parms.Num() + 1 );
  100. for ( int i = 0; i < parms.Num(); i++ ) {
  101. stack[ parms.Num() - i - 1 ] = parms[i];
  102. // Unfortunately at this point we don't have the function name anymore, so our warning messages aren't very detailed
  103. if ( i < parameters.Num() ) {
  104. if ( parameters[i].reg > 0 && parameters[i].reg < registers.Num() ) {
  105. registers[ parameters[i].reg ] = parms[i];
  106. }
  107. locals->Set( parameters[i].name, parms[i] );
  108. }
  109. }
  110. // Set any additional parameters to undefined
  111. for ( int i = parms.Num(); i < parameters.Num(); i++ ) {
  112. if ( parameters[i].reg > 0 && parameters[i].reg < registers.Num() ) {
  113. registers[ parameters[i].reg ].SetUndefined();
  114. }
  115. locals->Set( parameters[i].name, idSWFScriptVar() );
  116. }
  117. stack.A().SetInteger( parms.Num() );
  118. int preloadReg = 1;
  119. if ( flags & BIT( 0 ) ) {
  120. // load "this" into a register
  121. registers[ preloadReg ].SetObject( thisObject );
  122. preloadReg++;
  123. }
  124. if ( ( flags & BIT( 1 ) ) == 0 ) {
  125. // create "this"
  126. locals->Set( "this", idSWFScriptVar( thisObject ) );
  127. }
  128. if ( flags & BIT( 2 ) ) {
  129. idSWFScriptObject * arguments = idSWFScriptObject::Alloc();
  130. // load "arguments" into a register
  131. arguments->MakeArray();
  132. int numElements = parms.Num();
  133. for ( int i = 0; i < numElements; i++ ) {
  134. arguments->Set( i, parms[i] );
  135. }
  136. registers[ preloadReg ].SetObject( arguments );
  137. preloadReg++;
  138. arguments->Release();
  139. }
  140. if ( ( flags & BIT( 3 ) ) == 0 ) {
  141. idSWFScriptObject * arguments = idSWFScriptObject::Alloc();
  142. // create "arguments"
  143. arguments->MakeArray();
  144. int numElements = parms.Num();
  145. for ( int i = 0; i < numElements; i++ ) {
  146. arguments->Set( i, parms[i] );
  147. }
  148. locals->Set( "arguments", idSWFScriptVar( arguments ) );
  149. arguments->Release();
  150. }
  151. if ( flags & BIT( 4 ) ) {
  152. // load "super" into a register
  153. registers[ preloadReg ].SetObject( thisObject->GetPrototype() );
  154. preloadReg++;
  155. }
  156. if ( ( flags & BIT( 5 ) ) == 0 ) {
  157. // create "super"
  158. locals->Set( "super", idSWFScriptVar( thisObject->GetPrototype() ) );
  159. }
  160. if ( flags & BIT( 6 ) ) {
  161. // preload _root
  162. registers[ preloadReg ] = scope[0]->Get( "_root" );
  163. preloadReg++;
  164. }
  165. if ( flags & BIT( 7 ) ) {
  166. // preload _parent
  167. if ( thisObject->GetSprite() != NULL && thisObject->GetSprite()->parent != NULL ) {
  168. registers[ preloadReg ].SetObject( thisObject->GetSprite()->parent->scriptObject );
  169. } else {
  170. registers[ preloadReg ].SetNULL();
  171. }
  172. preloadReg++;
  173. }
  174. if ( flags & BIT( 8 ) ) {
  175. // load "_global" into a register
  176. registers[ preloadReg ].SetObject( scope[0] );
  177. preloadReg++;
  178. }
  179. int scopeSize = scope.Num();
  180. scope.Append( locals );
  181. locals->AddRef();
  182. idSWFScriptVar retVal = Run( thisObject, stack, bitstream );
  183. assert( scope.Num() == scopeSize + 1 );
  184. for ( int i = scopeSize; i < scope.Num(); i++ ) {
  185. if ( verify( scope[i] ) ) {
  186. scope[i]->Release();
  187. }
  188. }
  189. scope.SetNum( scopeSize );
  190. locals->Release();
  191. locals = NULL;
  192. return retVal;
  193. }
  194. /*
  195. ========================
  196. <anonymous>::Split
  197. ========================
  198. */
  199. namespace {
  200. const char * GetPropertyName( int index ) {
  201. switch ( index ) {
  202. case 0: return "_x";
  203. case 1: return "_y";
  204. case 2: return "_xscale";
  205. case 3: return "_yscale";
  206. case 4: return "_currentframe";
  207. case 5: return "_totalframes";
  208. case 6: return "_alpha";
  209. case 7: return "_visible";
  210. case 8: return "_width";
  211. case 9: return "_height";
  212. case 10: return "_rotation";
  213. case 11: return "_target";
  214. case 12: return "_framesloaded";
  215. case 13: return "_name";
  216. case 14: return "_droptarget";
  217. case 15: return "_url";
  218. case 16: return "_highquality";
  219. case 17: return "_focusrect";
  220. case 18: return "_soundbuftime";
  221. case 19: return "_quality";
  222. case 20: return "_mousex";
  223. case 21: return "_mousey";
  224. }
  225. return "";
  226. }
  227. const char *GetSwfActionName(swfAction_t code)
  228. {
  229. switch (code)
  230. {
  231. case Action_End: return "Action_End";
  232. // swf 3
  233. case Action_NextFrame: return "Action_NextFrame";
  234. case Action_PrevFrame: return "Action_PrevFrame";
  235. case Action_Play: return "Action_Play";
  236. case Action_Stop: return "Action_Stop";
  237. case Action_ToggleQuality: return "Action_ToggleQuality";
  238. case Action_StopSounds: return "Action_StopSounds";
  239. case Action_GotoFrame: return "Action_GotoFrame";
  240. case Action_GetURL: return "Action_GetURL";
  241. case Action_WaitForFrame: return "Action_WaitForFrame";
  242. case Action_SetTarget: return "Action_SetTarget";
  243. case Action_GoToLabel: return "Action_GoToLabel";
  244. // swf 4
  245. case Action_Add: return "Action_Add";
  246. case Action_Subtract: return "Action_Subtract";
  247. case Action_Multiply: return "Action_Multiply";
  248. case Action_Divide: return "Action_Divide";
  249. case Action_Equals: return "Action_Equals";
  250. case Action_Less: return "Action_Less";
  251. case Action_And: return "Action_And";
  252. case Action_Or: return "Action_Or";
  253. case Action_Not: return "Action_Not";
  254. case Action_StringEquals: return "Action_StringEquals";
  255. case Action_StringLength: return "Action_StringLength";
  256. case Action_StringExtract: return "Action_StringExtract";
  257. case Action_Pop: return "Action_Pop";
  258. case Action_ToInteger: return "Action_ToInteger";
  259. case Action_GetVariable: return "Action_GetVariable";
  260. case Action_SetVariable: return "Action_SetVariable";
  261. case Action_SetTarget2: return "Action_SetTarget2";
  262. case Action_StringAdd: return "Action_StringAdd";
  263. case Action_GetProperty: return "Action_GetProperty";
  264. case Action_SetProperty: return "Action_SetProperty";
  265. case Action_CloneSprite: return "Action_CloneSprite";
  266. case Action_RemoveSprite: return "Action_RemoveSprite";
  267. case Action_Trace: return "Action_Trace";
  268. case Action_StartDrag: return "Action_StartDrag";
  269. case Action_EndDrag: return "Action_EndDrag";
  270. case Action_StringLess: return "Action_StringLess";
  271. case Action_RandomNumber: return "Action_RandomNumber";
  272. case Action_MBStringLength: return "Action_MBStringLength";
  273. case Action_CharToAscii: return "Action_CharToAscii";
  274. case Action_AsciiToChar: return "Action_AsciiToChar";
  275. case Action_GetTime: return "Action_GetTime";
  276. case Action_MBStringExtract: return "Action_MBStringExtract";
  277. case Action_MBCharToAscii: return "Action_MBCharToAscii";
  278. case Action_MBAsciiToChar: return "Action_MBAsciiToChar";
  279. case Action_WaitForFrame2: return "Action_WaitForFrame2";
  280. case Action_Push: return "Action_Push";
  281. case Action_Jump: return "Action_Jump";
  282. case Action_GetURL2: return "Action_GetURL2";
  283. case Action_If: return "Action_If";
  284. case Action_Call: return "Action_Call";
  285. case Action_GotoFrame2: return "Action_GotoFrame2";
  286. // swf 5
  287. case Action_Delete: return "Action_Delete";
  288. case Action_Delete2: return "Action_Delete2";
  289. case Action_DefineLocal: return "Action_DefineLocal";
  290. case Action_CallFunction: return "Action_CallFunction";
  291. case Action_Return: return "Action_Return";
  292. case Action_Modulo: return "Action_Modulo";
  293. case Action_NewObject: return "Action_NewObject";
  294. case Action_DefineLocal2: return "Action_DefineLocal2";
  295. case Action_InitArray: return "Action_InitArray";
  296. case Action_InitObject: return "Action_InitObject";
  297. case Action_TypeOf: return "Action_TypeOf";
  298. case Action_TargetPath: return "Action_TargetPath";
  299. case Action_Enumerate: return "Action_Enumerate";
  300. case Action_Add2: return "Action_Add2";
  301. case Action_Less2: return "Action_Less2";
  302. case Action_Equals2: return "Action_Equals2";
  303. case Action_ToNumber: return "Action_ToNumber";
  304. case Action_ToString: return "Action_ToString";
  305. case Action_PushDuplicate: return "Action_PushDuplicate";
  306. case Action_StackSwap: return "Action_StackSwap";
  307. case Action_GetMember: return "Action_GetMember";
  308. case Action_SetMember: return "Action_SetMember";
  309. case Action_Increment: return "Action_Increment";
  310. case Action_Decrement: return "Action_Decrement";
  311. case Action_CallMethod: return "Action_CallMethod";
  312. case Action_NewMethod: return "Action_NewMethod";
  313. case Action_BitAnd: return "Action_BitAnd";
  314. case Action_BitOr: return "Action_BitOr";
  315. case Action_BitXor: return "Action_BitXor";
  316. case Action_BitLShift: return "Action_BitLShift";
  317. case Action_BitRShift: return "Action_BitRShift";
  318. case Action_BitURShift: return "Action_BitURShift";
  319. case Action_StoreRegister: return "Action_StoreRegister";
  320. case Action_ConstantPool: return "Action_ConstantPool";
  321. case Action_With: return "Action_With";
  322. case Action_DefineFunction: return "Action_DefineFunction";
  323. // swf 6
  324. case Action_InstanceOf: return "Action_InstanceOf";
  325. case Action_Enumerate2: return "Action_Enumerate2";
  326. case Action_StrictEquals: return "Action_StrictEquals";
  327. case Action_Greater: return "Action_Greater";
  328. case Action_StringGreater: return "Action_StringGreater";
  329. // swf 7
  330. case Action_Extends: return "Action_Extends";
  331. case Action_CastOp: return "Action_CastOp";
  332. case Action_ImplementsOp: return "Action_ImplementsOp";
  333. case Action_Throw: return "Action_Throw";
  334. case Action_Try: return "Action_Try";
  335. case Action_DefineFunction2: return "Action_DefineFunction2";
  336. default:
  337. return "UNKNOWN CODE";
  338. }
  339. }
  340. }
  341. /*
  342. ========================
  343. idSWFScriptFunction_Script::Run
  344. ========================
  345. */
  346. idSWFScriptVar idSWFScriptFunction_Script::Run( idSWFScriptObject * thisObject, idSWFStack & stack, idSWFBitStream & bitstream ) {
  347. static int callstackLevel = -1;
  348. idSWFSpriteInstance * thisSprite = thisObject->GetSprite();
  349. idSWFSpriteInstance * currentTarget = thisSprite;
  350. if ( currentTarget == NULL ) {
  351. thisSprite = currentTarget = defaultSprite;
  352. }
  353. callstackLevel++;
  354. while ( bitstream.Tell() < bitstream.Length() ) {
  355. swfAction_t code = (swfAction_t)bitstream.ReadU8();
  356. uint16 recordLength = 0;
  357. if ( code >= 0x80 ) {
  358. recordLength = bitstream.ReadU16();
  359. }
  360. if ( swf_debug.GetInteger() >= 3 ) {
  361. // stack[0] is always 0 so don't read it
  362. if ( swf_debug.GetInteger() >= 4 ) {
  363. for ( int i = stack.Num()-1; i >= 0 ; i-- ) {
  364. idLib::Printf(" %c: %s (%s)\n", (char)(64 + stack.Num() - i), stack[i].ToString().c_str(), stack[i].TypeOf());
  365. }
  366. for ( int i = 0; i < registers.Num(); i++ ) {
  367. if ( !registers[i].IsUndefined() ) {
  368. idLib::Printf(" R%d: %s (%s)\n", i, registers[i].ToString().c_str(), registers[i].TypeOf());
  369. }
  370. }
  371. }
  372. idLib::Printf( "SWF%d: code %s\n", callstackLevel, GetSwfActionName(code) );
  373. }
  374. switch ( code ) {
  375. case Action_Return:
  376. callstackLevel--;
  377. return stack.A();
  378. case Action_End:
  379. callstackLevel--;
  380. return idSWFScriptVar();
  381. case Action_NextFrame:
  382. if ( verify( currentTarget != NULL ) ) {
  383. currentTarget->NextFrame();
  384. } else if ( swf_debug.GetInteger() > 0 ) {
  385. idLib::Printf( "SWF: no target movie clip for nextFrame\n" );
  386. }
  387. break;
  388. case Action_PrevFrame:
  389. if ( verify( currentTarget != NULL ) ) {
  390. currentTarget->PrevFrame();
  391. } else if ( swf_debug.GetInteger() > 0 ) {
  392. idLib::Printf( "SWF: no target movie clip for prevFrame\n" );
  393. }
  394. break;
  395. case Action_Play:
  396. if ( verify( currentTarget != NULL ) ) {
  397. currentTarget->Play();
  398. } else if ( swf_debug.GetInteger() > 0 ) {
  399. idLib::Printf( "SWF: no target movie clip for play\n" );
  400. }
  401. break;
  402. case Action_Stop:
  403. if ( verify( currentTarget != NULL ) ) {
  404. currentTarget->Stop();
  405. } else if ( swf_debug.GetInteger() > 0 ) {
  406. idLib::Printf( "SWF: no target movie clip for stop\n" );
  407. }
  408. break;
  409. case Action_ToggleQuality: break;
  410. case Action_StopSounds: break;
  411. case Action_GotoFrame: {
  412. assert( recordLength == 2 );
  413. int frameNum = bitstream.ReadU16() + 1;
  414. if ( verify( currentTarget != NULL ) ) {
  415. currentTarget->RunTo( frameNum );
  416. } else if ( swf_debug.GetInteger() > 0 ) {
  417. idLib::Printf( "SWF: no target movie clip for runTo %d\n", frameNum );
  418. }
  419. break;
  420. }
  421. case Action_SetTarget: {
  422. const char * targetName = (const char *)bitstream.ReadData( recordLength );
  423. if ( verify( thisSprite != NULL ) ) {
  424. currentTarget = thisSprite->ResolveTarget( targetName );
  425. } else if ( swf_debug.GetInteger() > 0 ) {
  426. idLib::Printf( "SWF: no target movie clip for setTarget %s\n", targetName );
  427. }
  428. break;
  429. }
  430. case Action_GoToLabel: {
  431. const char * targetName = (const char *)bitstream.ReadData( recordLength );
  432. if ( verify( currentTarget != NULL ) ) {
  433. currentTarget->RunTo( currentTarget->FindFrame( targetName ) );
  434. } else if ( swf_debug.GetInteger() > 0 ) {
  435. idLib::Printf( "SWF: no target movie clip for runTo %s\n", targetName );
  436. }
  437. break;
  438. }
  439. case Action_Push: {
  440. idSWFBitStream pushstream( bitstream.ReadData( recordLength ), recordLength, false );
  441. while ( pushstream.Tell() < pushstream.Length() ) {
  442. uint8 type = pushstream.ReadU8();
  443. switch ( type ) {
  444. case 0: stack.Alloc().SetString( pushstream.ReadString() ); break;
  445. case 1: stack.Alloc().SetFloat( pushstream.ReadFloat() ); break;
  446. case 2: stack.Alloc().SetNULL(); break;
  447. case 3: stack.Alloc().SetUndefined(); break;
  448. case 4: stack.Alloc() = registers[ pushstream.ReadU8() ]; break;
  449. case 5: stack.Alloc().SetBool( pushstream.ReadU8() != 0 ); break;
  450. case 6: stack.Alloc().SetFloat( (float)pushstream.ReadDouble() ); break;
  451. case 7: stack.Alloc().SetInteger( pushstream.ReadS32() ); break;
  452. case 8: stack.Alloc().SetString( constants.Get( pushstream.ReadU8() ) ); break;
  453. case 9: stack.Alloc().SetString( constants.Get( pushstream.ReadU16() ) ); break;
  454. }
  455. }
  456. break;
  457. }
  458. case Action_Pop:
  459. stack.Pop( 1 );
  460. break;
  461. case Action_Add:
  462. stack.B().SetFloat( stack.B().ToFloat() + stack.A().ToFloat() );
  463. stack.Pop( 1 );
  464. break;
  465. case Action_Subtract:
  466. stack.B().SetFloat( stack.B().ToFloat() - stack.A().ToFloat() );
  467. stack.Pop( 1 );
  468. break;
  469. case Action_Multiply:
  470. stack.B().SetFloat( stack.B().ToFloat() * stack.A().ToFloat() );
  471. stack.Pop( 1 );
  472. break;
  473. case Action_Divide:
  474. stack.B().SetFloat( stack.B().ToFloat() / stack.A().ToFloat() );
  475. stack.Pop( 1 );
  476. break;
  477. case Action_Equals:
  478. stack.B().SetBool( stack.B().ToFloat() == stack.A().ToFloat() );
  479. stack.Pop( 1 );
  480. break;
  481. case Action_Less:
  482. stack.B().SetBool( stack.B().ToFloat() < stack.A().ToFloat() );
  483. stack.Pop( 1 );
  484. break;
  485. case Action_And:
  486. stack.B().SetBool( stack.B().ToBool() && stack.A().ToBool() );
  487. stack.Pop( 1 );
  488. break;
  489. case Action_Or:
  490. stack.B().SetBool( stack.B().ToBool() || stack.A().ToBool() );
  491. stack.Pop( 1 );
  492. break;
  493. case Action_Not:
  494. stack.A().SetBool( !stack.A().ToBool() );
  495. break;
  496. case Action_StringEquals:
  497. stack.B().SetBool( stack.B().ToString() == stack.A().ToString() );
  498. stack.Pop( 1 );
  499. break;
  500. case Action_StringLength:
  501. stack.A().SetInteger( stack.A().ToString().Length() );
  502. break;
  503. case Action_StringAdd:
  504. stack.B().SetString( stack.B().ToString() + stack.A().ToString() );
  505. stack.Pop( 1 );
  506. break;
  507. case Action_StringExtract:
  508. stack.C().SetString( stack.C().ToString().Mid( stack.B().ToInteger(), stack.A().ToInteger() ) );
  509. stack.Pop( 2 );
  510. break;
  511. case Action_StringLess:
  512. stack.B().SetBool( stack.B().ToString() < stack.A().ToString() );
  513. stack.Pop( 1 );
  514. break;
  515. case Action_StringGreater:
  516. stack.B().SetBool( stack.B().ToString() > stack.A().ToString() );
  517. stack.Pop( 1 );
  518. break;
  519. case Action_ToInteger:
  520. stack.A().SetInteger( stack.A().ToInteger() );
  521. break;
  522. case Action_CharToAscii:
  523. stack.A().SetInteger( stack.A().ToString()[0] );
  524. break;
  525. case Action_AsciiToChar:
  526. stack.A().SetString( va( "%c", stack.A().ToInteger() ) );
  527. break;
  528. case Action_Jump:
  529. bitstream.Seek( bitstream.ReadS16() );
  530. break;
  531. case Action_If: {
  532. int16 offset = bitstream.ReadS16();
  533. if ( stack.A().ToBool() ) {
  534. bitstream.Seek( offset );
  535. }
  536. stack.Pop( 1 );
  537. break;
  538. }
  539. case Action_GetVariable: {
  540. idStr variableName = stack.A().ToString();
  541. for ( int i = scope.Num() - 1; i >= 0; i-- ) {
  542. stack.A() = scope[i]->Get( variableName );
  543. if ( !stack.A().IsUndefined() ) {
  544. break;
  545. }
  546. }
  547. if ( stack.A().IsUndefined() && swf_debug.GetInteger() > 1 ) {
  548. idLib::Printf( "SWF: unknown variable %s\n", variableName.c_str() );
  549. }
  550. break;
  551. }
  552. case Action_SetVariable: {
  553. idStr variableName = stack.B().ToString();
  554. bool found = false;
  555. for ( int i = scope.Num() - 1; i >= 0; i-- ) {
  556. if ( scope[i]->HasProperty( variableName ) ) {
  557. scope[i]->Set( variableName, stack.A() );
  558. found = true;
  559. break;
  560. }
  561. }
  562. if ( !found ) {
  563. thisObject->Set( variableName, stack.A() );
  564. }
  565. stack.Pop( 2 );
  566. break;
  567. }
  568. case Action_GotoFrame2: {
  569. uint32 frameNum = 0;
  570. uint8 flags = bitstream.ReadU8();
  571. if ( flags & 2 ) {
  572. frameNum += bitstream.ReadU16();
  573. }
  574. if ( verify( thisSprite != NULL ) ) {
  575. if ( stack.A().IsString() ) {
  576. frameNum += thisSprite->FindFrame( stack.A().ToString() );
  577. } else {
  578. frameNum += (uint32)stack.A().ToInteger();
  579. }
  580. if ( ( flags & 1 ) != 0 ){
  581. thisSprite->Play();
  582. } else {
  583. thisSprite->Stop();
  584. }
  585. thisSprite->RunTo( frameNum );
  586. } else if ( swf_debug.GetInteger() > 0 ) {
  587. if ( ( flags & 1 ) != 0 ){
  588. idLib::Printf( "SWF: no target movie clip for gotoAndPlay\n" );
  589. } else {
  590. idLib::Printf( "SWF: no target movie clip for gotoAndStop\n" );
  591. }
  592. }
  593. stack.Pop( 1 );
  594. break;
  595. }
  596. case Action_GetProperty: {
  597. if ( verify( thisSprite != NULL ) ) {
  598. idSWFSpriteInstance * target = thisSprite->ResolveTarget( stack.B().ToString() );
  599. stack.B() = target->scriptObject->Get( GetPropertyName( stack.A().ToInteger() ) );
  600. } else if ( swf_debug.GetInteger() > 0 ) {
  601. idLib::Printf( "SWF: no target movie clip for getProperty\n" );
  602. }
  603. stack.Pop( 1 );
  604. break;
  605. }
  606. case Action_SetProperty: {
  607. if ( verify( thisSprite != NULL ) ) {
  608. idSWFSpriteInstance * target = thisSprite->ResolveTarget( stack.C().ToString() );
  609. target->scriptObject->Set( GetPropertyName( stack.B().ToInteger() ), stack.A() );
  610. } else if ( swf_debug.GetInteger() > 0 ) {
  611. idLib::Printf( "SWF: no target movie clip for setProperty\n" );
  612. }
  613. stack.Pop( 3 );
  614. break;
  615. }
  616. case Action_Trace:
  617. idLib::PrintfIf( swf_debug.GetInteger() > 0, "SWF Trace: %s\n", stack.A().ToString().c_str() );
  618. stack.Pop( 1 );
  619. break;
  620. case Action_GetTime:
  621. stack.Alloc().SetInteger( Sys_Milliseconds() );
  622. break;
  623. case Action_RandomNumber:
  624. assert( thisSprite && thisSprite->sprite && thisSprite->sprite->GetSWF() );
  625. stack.A().SetInteger( thisSprite->sprite->GetSWF()->GetRandom().RandomInt( stack.A().ToInteger() ) );
  626. break;
  627. case Action_CallFunction: {
  628. idStr functionName = stack.A().ToString();
  629. idSWFScriptVar function;
  630. idSWFScriptObject * object = NULL;
  631. for ( int i = scope.Num() - 1; i >= 0; i-- ) {
  632. function = scope[i]->Get( functionName );
  633. if ( !function.IsUndefined() ) {
  634. object = scope[i];
  635. break;
  636. }
  637. }
  638. stack.Pop( 1 );
  639. idSWFParmList parms;
  640. parms.SetNum( stack.A().ToInteger() );
  641. stack.Pop( 1 );
  642. for ( int i = 0; i < parms.Num(); i++ ) {
  643. parms[i] = stack.A();
  644. stack.Pop( 1 );
  645. }
  646. if ( function.IsFunction() && verify( object ) ) {
  647. stack.Alloc() = function.GetFunction()->Call( object, parms );
  648. } else {
  649. idLib::PrintfIf( swf_debug.GetInteger() > 0, "SWF: unknown function %s\n", functionName.c_str() );
  650. stack.Alloc().SetUndefined();
  651. }
  652. break;
  653. }
  654. case Action_CallMethod: {
  655. idStr functionName = stack.A().ToString();
  656. // If the top stack is undefined but there is an object, it's calling the constructor
  657. if ( functionName.IsEmpty() || stack.A().IsUndefined() || stack.A().IsNULL() ) {
  658. functionName = "__constructor__";
  659. }
  660. idSWFScriptObject * object = NULL;
  661. idSWFScriptVar function;
  662. if ( stack.B().IsObject() ) {
  663. object = stack.B().GetObject();
  664. function = object->Get( functionName );
  665. if ( !function.IsFunction() ) {
  666. idLib::PrintfIf( swf_debug.GetInteger() > 1, "SWF: unknown method %s on %s\n", functionName.c_str(), object->DefaultValue( true ).ToString().c_str() );
  667. }
  668. } else {
  669. idLib::PrintfIf( swf_debug.GetInteger() > 1, "SWF: NULL object for method %s\n", functionName.c_str() );
  670. }
  671. stack.Pop( 2 );
  672. idSWFParmList parms;
  673. parms.SetNum( stack.A().ToInteger() );
  674. stack.Pop( 1 );
  675. for ( int i = 0; i < parms.Num(); i++ ) {
  676. parms[i] = stack.A();
  677. stack.Pop( 1 );
  678. }
  679. if ( function.IsFunction() ) {
  680. stack.Alloc() = function.GetFunction()->Call( object, parms );
  681. } else {
  682. stack.Alloc().SetUndefined();
  683. }
  684. break;
  685. }
  686. case Action_ConstantPool: {
  687. constants.Clear();
  688. uint16 numConstants = bitstream.ReadU16();
  689. for ( int i = 0; i < numConstants; i++ ) {
  690. constants.Append( idSWFScriptString::Alloc( bitstream.ReadString() ) );
  691. }
  692. break;
  693. }
  694. case Action_DefineFunction: {
  695. idStr functionName = bitstream.ReadString();
  696. idSWFScriptFunction_Script * newFunction = idSWFScriptFunction_Script::Alloc();
  697. newFunction->SetScope( scope );
  698. newFunction->SetConstants( constants );
  699. newFunction->SetDefaultSprite( defaultSprite );
  700. uint16 numParms = bitstream.ReadU16();
  701. newFunction->AllocParameters( numParms );
  702. for ( int i = 0; i < numParms; i++ ) {
  703. newFunction->SetParameter( i, 0, bitstream.ReadString() );
  704. }
  705. uint16 codeSize = bitstream.ReadU16();
  706. newFunction->SetData( bitstream.ReadData( codeSize ), codeSize );
  707. if ( functionName.IsEmpty() ) {
  708. stack.Alloc().SetFunction( newFunction );
  709. } else {
  710. thisObject->Set( functionName, idSWFScriptVar( newFunction ) );
  711. }
  712. newFunction->Release();
  713. break;
  714. }
  715. case Action_DefineFunction2: {
  716. idStr functionName = bitstream.ReadString();
  717. idSWFScriptFunction_Script * newFunction = idSWFScriptFunction_Script::Alloc();
  718. newFunction->SetScope( scope );
  719. newFunction->SetConstants( constants );
  720. newFunction->SetDefaultSprite( defaultSprite );
  721. uint16 numParms = bitstream.ReadU16();
  722. // The number of registers is from 0 to 255, although valid values are 1 to 256.
  723. // There must always be at least one register for DefineFunction2, to hold "this" or "super" when required.
  724. uint8 numRegs = bitstream.ReadU8() + 1;
  725. // Note that SWF byte-ordering causes the flag bits to be reversed per-byte
  726. // from how the swf_file_format_spec_v10.pdf document describes the ordering in ActionDefineFunction2.
  727. // PreloadThisFlag is byte 0, not 7, PreloadGlobalFlag is 8, not 15.
  728. uint16 flags = bitstream.ReadU16();
  729. newFunction->AllocParameters( numParms );
  730. newFunction->AllocRegisters( numRegs );
  731. newFunction->SetFlags( flags );
  732. for ( int i = 0; i < numParms; i++ ) {
  733. uint8 reg = bitstream.ReadU8();
  734. const char * name = bitstream.ReadString();
  735. if ( reg >= numRegs ) {
  736. idLib::Warning( "SWF: Parameter %s in function %s bound to out of range register %d", name, functionName.c_str(), reg );
  737. reg = 0;
  738. }
  739. newFunction->SetParameter( i, reg, name );
  740. }
  741. uint16 codeSize = bitstream.ReadU16();
  742. newFunction->SetData( bitstream.ReadData( codeSize ), codeSize );
  743. if ( functionName.IsEmpty() ) {
  744. stack.Alloc().SetFunction( newFunction );
  745. } else {
  746. thisObject->Set( functionName, idSWFScriptVar( newFunction ) );
  747. }
  748. newFunction->Release();
  749. break;
  750. }
  751. case Action_Enumerate: {
  752. idStr variableName = stack.A().ToString();
  753. for ( int i = scope.Num() - 1; i >= 0; i-- ) {
  754. stack.A() = scope[i]->Get( variableName );
  755. if ( !stack.A().IsUndefined() ) {
  756. break;
  757. }
  758. }
  759. if ( !stack.A().IsObject() ) {
  760. stack.A().SetNULL();
  761. } else {
  762. idSWFScriptObject * object = stack.A().GetObject();
  763. object->AddRef();
  764. stack.A().SetNULL();
  765. for ( int i = 0; i < object->NumVariables(); i++ ) {
  766. stack.Alloc().SetString( object->EnumVariable( i ) );
  767. }
  768. object->Release();
  769. }
  770. break;
  771. }
  772. case Action_Enumerate2: {
  773. if ( !stack.A().IsObject() ) {
  774. stack.A().SetNULL();
  775. } else {
  776. idSWFScriptObject * object = stack.A().GetObject();
  777. object->AddRef();
  778. stack.A().SetNULL();
  779. for ( int i = 0; i < object->NumVariables(); i++ ) {
  780. stack.Alloc().SetString( object->EnumVariable( i ) );
  781. }
  782. object->Release();
  783. }
  784. break;
  785. }
  786. case Action_Equals2: {
  787. stack.B().SetBool( stack.A().AbstractEquals( stack.B() ) );
  788. stack.Pop( 1 );
  789. break;
  790. }
  791. case Action_StrictEquals: {
  792. stack.B().SetBool( stack.A().StrictEquals( stack.B() ) );
  793. stack.Pop( 1 );
  794. break;
  795. }
  796. case Action_GetMember: {
  797. if ( ( stack.B().IsUndefined() || stack.B().IsNULL() ) && swf_debug.GetInteger() > 1 ) {
  798. idLib::Printf( "SWF: tried to get member %s on an invalid object in sprite '%s'\n", stack.A().ToString().c_str(), thisSprite != NULL ? thisSprite->GetName() : "" );
  799. }
  800. if ( stack.B().IsObject() ) {
  801. idSWFScriptObject * object = stack.B().GetObject();
  802. if ( stack.A().IsNumeric() ) {
  803. stack.B() = object->Get( stack.A().ToInteger() );
  804. } else {
  805. stack.B() = object->Get( stack.A().ToString() );
  806. }
  807. if ( stack.B().IsUndefined() && swf_debug.GetInteger() > 1 ) {
  808. idLib::Printf( "SWF: unknown member %s\n", stack.A().ToString().c_str() );
  809. }
  810. } else if ( stack.B().IsString() ) {
  811. idStr propertyName = stack.A().ToString();
  812. if ( propertyName.Cmp( "length" ) == 0 ) {
  813. stack.B().SetInteger( stack.B().ToString().Length() );
  814. } else if ( propertyName.Cmp( "value" ) == 0 ) {
  815. // Do nothing
  816. } else {
  817. stack.B().SetUndefined();
  818. }
  819. } else if ( stack.B().IsFunction() ) {
  820. idStr propertyName = stack.A().ToString();
  821. if ( propertyName.Cmp( "prototype" ) == 0 ) {
  822. // if this is a function, it's a class definition function, and it just wants the prototype object
  823. // create it if it hasn't been already, and return it
  824. idSWFScriptFunction * sfs = stack.B().GetFunction();
  825. idSWFScriptObject * object = sfs->GetPrototype();
  826. if ( object == NULL ) {
  827. object = idSWFScriptObject::Alloc();
  828. // Set the __proto__ to the main Object prototype
  829. idSWFScriptVar baseObjConstructor = scope[0]->Get( "Object" );
  830. idSWFScriptFunction *baseObj = baseObjConstructor.GetFunction();
  831. object->Set( "__proto__", baseObj->GetPrototype() );
  832. sfs->SetPrototype( object );
  833. }
  834. stack.B() = idSWFScriptVar( object );
  835. } else {
  836. stack.B().SetUndefined();
  837. }
  838. } else {
  839. stack.B().SetUndefined();
  840. }
  841. stack.Pop( 1 );
  842. break;
  843. }
  844. case Action_SetMember: {
  845. if ( stack.C().IsObject() ) {
  846. idSWFScriptObject * object = stack.C().GetObject();
  847. if ( stack.B().IsNumeric() ) {
  848. object->Set( stack.B().ToInteger(), stack.A() );
  849. } else {
  850. object->Set( stack.B().ToString(), stack.A() );
  851. }
  852. }
  853. stack.Pop( 3 );
  854. break;
  855. }
  856. case Action_InitArray: {
  857. idSWFScriptObject * object = idSWFScriptObject::Alloc();
  858. object->MakeArray();
  859. int numElements = stack.A().ToInteger();
  860. stack.Pop( 1 );
  861. for ( int i = 0; i < numElements; i++ ) {
  862. object->Set( i, stack.A() );
  863. stack.Pop( 1 );
  864. }
  865. stack.Alloc().SetObject( object );
  866. object->Release();
  867. break;
  868. }
  869. case Action_InitObject: {
  870. idSWFScriptObject * object = idSWFScriptObject::Alloc();
  871. int numElements = stack.A().ToInteger();
  872. stack.Pop( 1 );
  873. for ( int i = 0; i < numElements; i++ ) {
  874. object->Set( stack.B().ToString(), stack.A() );
  875. stack.Pop( 2 );
  876. }
  877. stack.Alloc().SetObject( object );
  878. object->Release();
  879. break;
  880. }
  881. case Action_NewObject: {
  882. idSWFScriptObject * object = idSWFScriptObject::Alloc();
  883. idStr functionName = stack.A().ToString();
  884. stack.Pop( 1 );
  885. if ( functionName.Cmp( "Array" ) == 0 ) {
  886. object->MakeArray();
  887. int numElements = stack.A().ToInteger();
  888. stack.Pop( 1 );
  889. for ( int i = 0; i < numElements; i++ ) {
  890. object->Set( i, stack.A() );
  891. stack.Pop( 1 );
  892. }
  893. idSWFScriptVar baseObjConstructor = scope[0]->Get( "Object" );
  894. idSWFScriptFunction *baseObj = baseObjConstructor.GetFunction();
  895. object->Set( "__proto__", baseObj->GetPrototype() );
  896. // object prototype is not set here because it will be auto created from Object later
  897. } else {
  898. idSWFParmList parms;
  899. parms.SetNum( stack.A().ToInteger() );
  900. stack.Pop( 1 );
  901. for ( int i = 0; i < parms.Num(); i++ ) {
  902. parms[i] = stack.A();
  903. stack.Pop( 1 );
  904. }
  905. idSWFScriptVar objdef = scope[0]->Get( functionName );
  906. if ( objdef.IsFunction() ) {
  907. idSWFScriptFunction * constructorFunction = objdef.GetFunction();
  908. object->Set( "__proto__", constructorFunction->GetPrototype() );
  909. object->SetPrototype( constructorFunction->GetPrototype() );
  910. constructorFunction->Call( object, parms );
  911. } else {
  912. idLib::Warning( "SWF: Unknown class definition %s", functionName.c_str() );
  913. }
  914. }
  915. stack.Alloc().SetObject( object );
  916. object->Release();
  917. break;
  918. }
  919. case Action_Extends: {
  920. idSWFScriptFunction * superclassConstructorFunction = stack.A().GetFunction();
  921. idSWFScriptFunction *subclassConstructorFunction = stack.B().GetFunction();
  922. stack.Pop( 2 );
  923. idSWFScriptObject * scriptObject = idSWFScriptObject::Alloc();
  924. scriptObject->SetPrototype( superclassConstructorFunction->GetPrototype() );
  925. scriptObject->Set( "__proto__", idSWFScriptVar( superclassConstructorFunction->GetPrototype() ) );
  926. scriptObject->Set( "__constructor__", idSWFScriptVar( superclassConstructorFunction ) );
  927. subclassConstructorFunction->SetPrototype( scriptObject );
  928. scriptObject->Release();
  929. break;
  930. }
  931. case Action_TargetPath: {
  932. if ( !stack.A().IsObject() ) {
  933. stack.A().SetUndefined();
  934. } else {
  935. idSWFScriptObject * object = stack.A().GetObject();
  936. if ( object->GetSprite() == NULL ) {
  937. stack.A().SetUndefined();
  938. } else {
  939. idStr dotName = object->GetSprite()->name.c_str();
  940. for ( idSWFSpriteInstance * target = object->GetSprite()->parent; target != NULL; target = target->parent ) {
  941. dotName = target->name + "." + dotName;
  942. }
  943. stack.A().SetString( dotName );
  944. }
  945. }
  946. break;
  947. }
  948. case Action_With: {
  949. int withSize = bitstream.ReadU16();
  950. idSWFBitStream bitstream2( bitstream.ReadData( withSize ), withSize, false );
  951. if ( stack.A().IsObject() ) {
  952. idSWFScriptObject * withObject = stack.A().GetObject();
  953. withObject->AddRef();
  954. stack.Pop( 1 );
  955. scope.Append( withObject );
  956. Run( thisObject, stack, bitstream2 );
  957. scope.SetNum( scope.Num() - 1 );
  958. withObject->Release();
  959. } else {
  960. if ( swf_debug.GetInteger() > 0 ) {
  961. idLib::Printf( "SWF: with() invalid object specified\n" );
  962. }
  963. stack.Pop( 1 );
  964. }
  965. break;
  966. }
  967. case Action_ToNumber:
  968. stack.A().SetFloat( stack.A().ToFloat() );
  969. break;
  970. case Action_ToString:
  971. stack.A().SetString( stack.A().ToString() );
  972. break;
  973. case Action_TypeOf:
  974. stack.A().SetString( stack.A().TypeOf() );
  975. break;
  976. case Action_Add2: {
  977. if ( stack.A().IsString() || stack.B().IsString() ) {
  978. stack.B().SetString( stack.B().ToString() + stack.A().ToString() );
  979. } else {
  980. stack.B().SetFloat( stack.B().ToFloat() + stack.A().ToFloat() );
  981. }
  982. stack.Pop( 1 );
  983. break;
  984. }
  985. case Action_Less2: {
  986. if ( stack.A().IsString() && stack.B().IsString() ) {
  987. stack.B().SetBool( stack.B().ToString() < stack.A().ToString() );
  988. } else {
  989. stack.B().SetBool( stack.B().ToFloat() < stack.A().ToFloat() );
  990. }
  991. stack.Pop( 1 );
  992. break;
  993. }
  994. case Action_Greater: {
  995. if ( stack.A().IsString() && stack.B().IsString() ) {
  996. stack.B().SetBool( stack.B().ToString() > stack.A().ToString() );
  997. } else {
  998. stack.B().SetBool( stack.B().ToFloat() > stack.A().ToFloat() );
  999. }
  1000. stack.Pop( 1 );
  1001. break;
  1002. }
  1003. case Action_Modulo: {
  1004. int32 a = stack.A().ToInteger();
  1005. int32 b = stack.B().ToInteger();
  1006. if ( a == 0 ) {
  1007. stack.B().SetUndefined();
  1008. } else {
  1009. stack.B().SetInteger( b % a );
  1010. }
  1011. stack.Pop( 1 );
  1012. break;
  1013. }
  1014. case Action_BitAnd:
  1015. stack.B().SetInteger( stack.B().ToInteger() & stack.A().ToInteger() );
  1016. stack.Pop( 1 );
  1017. break;
  1018. case Action_BitLShift:
  1019. stack.B().SetInteger( stack.B().ToInteger() << stack.A().ToInteger() );
  1020. stack.Pop( 1 );
  1021. break;
  1022. case Action_BitOr:
  1023. stack.B().SetInteger( stack.B().ToInteger() | stack.A().ToInteger() );
  1024. stack.Pop( 1 );
  1025. break;
  1026. case Action_BitRShift:
  1027. stack.B().SetInteger( stack.B().ToInteger() >> stack.A().ToInteger() );
  1028. stack.Pop( 1 );
  1029. break;
  1030. case Action_BitURShift:
  1031. stack.B().SetInteger( (uint32)stack.B().ToInteger() >> stack.A().ToInteger() );
  1032. stack.Pop( 1 );
  1033. break;
  1034. case Action_BitXor:
  1035. stack.B().SetInteger( stack.B().ToInteger() ^ stack.A().ToInteger() );
  1036. stack.Pop( 1 );
  1037. break;
  1038. case Action_Decrement:
  1039. stack.A().SetFloat( stack.A().ToFloat() - 1.0f );
  1040. break;
  1041. case Action_Increment:
  1042. stack.A().SetFloat( stack.A().ToFloat() + 1.0f );
  1043. break;
  1044. case Action_PushDuplicate: {
  1045. idSWFScriptVar dup = stack.A();
  1046. stack.Alloc() = dup;
  1047. break;
  1048. }
  1049. case Action_StackSwap: {
  1050. idSWFScriptVar temp = stack.A();
  1051. stack.A() = stack.B();
  1052. stack.A() = temp;
  1053. break;
  1054. }
  1055. case Action_StoreRegister: {
  1056. uint8 registerNumber = bitstream.ReadU8();
  1057. registers[ registerNumber ] = stack.A();
  1058. break;
  1059. }
  1060. case Action_DefineLocal: {
  1061. scope[scope.Num()-1]->Set( stack.B().ToString(), stack.A() );
  1062. stack.Pop( 2 );
  1063. break;
  1064. }
  1065. case Action_DefineLocal2: {
  1066. scope[scope.Num()-1]->Set( stack.A().ToString(), idSWFScriptVar() );
  1067. stack.Pop( 1 );
  1068. break;
  1069. }
  1070. case Action_Delete: {
  1071. if ( swf_debug.GetInteger() > 0 ) {
  1072. idLib::Printf( "SWF: Delete ignored\n" );
  1073. }
  1074. // We no longer support deleting variables because the performance cost of updating the hash tables is not worth it
  1075. stack.Pop( 2 );
  1076. break;
  1077. }
  1078. case Action_Delete2: {
  1079. if ( swf_debug.GetInteger() > 0 ) {
  1080. idLib::Printf( "SWF: Delete2 ignored\n" );
  1081. }
  1082. // We no longer support deleting variables because the performance cost of updating the hash tables is not worth it
  1083. stack.Pop( 1 );
  1084. break;
  1085. }
  1086. // These are functions we just don't support because we never really needed to
  1087. case Action_CloneSprite:
  1088. case Action_RemoveSprite:
  1089. case Action_Call:
  1090. case Action_SetTarget2:
  1091. case Action_NewMethod:
  1092. default:
  1093. idLib::Warning( "SWF: Unhandled Action %s", idSWF::GetActionName( code ) );
  1094. // We have to abort here because the rest of the script is basically meaningless now
  1095. assert( false );
  1096. callstackLevel--;
  1097. return idSWFScriptVar();
  1098. }
  1099. }
  1100. callstackLevel--;
  1101. return idSWFScriptVar();
  1102. }
  1103. /*
  1104. ========================
  1105. idSWF::Invoke
  1106. ========================
  1107. */
  1108. void idSWF::Invoke( const char * functionName, const idSWFParmList & parms ) {
  1109. idSWFScriptObject * obj = mainspriteInstance->GetScriptObject();
  1110. idSWFScriptVar scriptVar = obj->Get( functionName );
  1111. if ( swf_debugInvoke.GetBool() ) {
  1112. idLib::Printf( "SWF: Invoke %s with %d parms (%s)\n", functionName, parms.Num(), GetName() );
  1113. }
  1114. if ( scriptVar.IsFunction() ) {
  1115. scriptVar.GetFunction()->Call( NULL, parms );
  1116. }
  1117. }
  1118. /*
  1119. ========================
  1120. idSWF::Invoke
  1121. ========================
  1122. */
  1123. void idSWF::Invoke( const char * functionName, const idSWFParmList & parms, idSWFScriptVar & scriptVar ) {
  1124. if ( scriptVar.IsFunction() ) {
  1125. scriptVar.GetFunction()->Call( NULL, parms );
  1126. } else {
  1127. idSWFScriptObject * obj = mainspriteInstance->GetScriptObject();
  1128. scriptVar = obj->Get( functionName );
  1129. if ( scriptVar.IsFunction() ) {
  1130. scriptVar.GetFunction()->Call( NULL, parms );
  1131. }
  1132. }
  1133. }
  1134. /*
  1135. ========================
  1136. idSWF::Invoke
  1137. ========================
  1138. */
  1139. void idSWF::Invoke( const char * functionName, const idSWFParmList & parms, bool & functionExists ) {
  1140. idSWFScriptObject * obj = mainspriteInstance->GetScriptObject();
  1141. idSWFScriptVar scriptVar = obj->Get( functionName );
  1142. if ( swf_debugInvoke.GetBool() ) {
  1143. idLib::Printf( "SWF: Invoke %s with %d parms (%s)\n", functionName, parms.Num(), GetName() );
  1144. }
  1145. if ( scriptVar.IsFunction() ) {
  1146. scriptVar.GetFunction()->Call( NULL, parms );
  1147. functionExists = true;
  1148. } else {
  1149. functionExists = false;
  1150. }
  1151. }