| 407 | } |
| 408 | |
| 409 | RunScFuncResult RunScriptFunction(const RuntimeScript *script, const String &tsname, size_t numParam, const RuntimeScriptValue *params) |
| 410 | { |
| 411 | assert(script); |
| 412 | int oldRestoreCount = gameHasBeenRestored; |
| 413 | // TODO: research why this is really necessary, and refactor to avoid such hacks! |
| 414 | // First, save the current ccError state |
| 415 | // This is necessary because we might be attempting |
| 416 | // to run Script B, while Script A is still running in the |
| 417 | // background. |
| 418 | // If CallInstance here has an error, it would otherwise |
| 419 | // also abort Script A because ccError is a global variable. |
| 420 | ScriptError cachedCcError = cc_get_error(); |
| 421 | |
| 422 | const RunScFuncResult res = PrepareTextScript(script, tsname); |
| 423 | if (res != kScFnRes_Done) |
| 424 | { |
| 425 | if (res != kScFnRes_NotFound) |
| 426 | quit_with_script_error(tsname); |
| 427 | cc_error(cachedCcError); // restore cached error state |
| 428 | return res; |
| 429 | } |
| 430 | |
| 431 | // Choose a script thread. Use main thread by default if it's free |
| 432 | // (does not have any script loaded up). Otherwise, create a new dynamic |
| 433 | // callback thread and push to stack of threads. |
| 434 | ScriptThread *script_thread = scriptThreadMain.get(); |
| 435 | if (scriptThreadMain->IsBusy()) |
| 436 | { |
| 437 | script_thread = AllocateDynamicScriptThread(); |
| 438 | } |
| 439 | |
| 440 | const ScriptExecError inst_ret = scriptExecutor->Run(script_thread, |
| 441 | curExecScript->Script, tsname, params, numParam); |
| 442 | if ((inst_ret != kScExecErr_None) && (inst_ret != kScExecErr_FuncNotFound) && (inst_ret != kScExecErr_Aborted)) |
| 443 | { |
| 444 | quit_with_script_error(tsname); |
| 445 | } |
| 446 | |
| 447 | if (script_thread != scriptThreadMain.get()) |
| 448 | { |
| 449 | FreeDynamicScriptThread(script_thread); |
| 450 | } |
| 451 | |
| 452 | // FIXME: here we save the return value of the current called function, |
| 453 | // because anything scheduled for the post-script processing will be run by the same executor, |
| 454 | // and may replace "return value" field saved in a executor. |
| 455 | // That's ugly. Should revise and redesign this later. BTW, ScriptExecutor keeping |
| 456 | // last return value is also a hack, used currently only by dialogs. This should be done differently. |
| 457 | const int ret_value = scriptExecutor->GetReturnValue(); |
| 458 | PostScriptProcessing(); |
| 459 | scriptExecutor->SetReturnValue(ret_value); // restore saved ret value |
| 460 | |
| 461 | // restore cached error state |
| 462 | cc_error(cachedCcError); |
| 463 | |
| 464 | // if the game has been restored, ensure that any further scripts are not run |
| 465 | if ((oldRestoreCount != gameHasBeenRestored) && (eventClaimed == EVENT_INPROGRESS)) |
| 466 | eventClaimed = EVENT_CLAIMED; |
no test coverage detected