DOOM-3-BFG

DOOM 3 BFG Edition
Log | Files | Refs

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 }