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