bool LuaScriptContext::ExecuteString(const char* string) { //lua_pushcfunction(L, LuaErrorHandlerCallback); luaL_loadstring(L, string); return LuaCall(0, LUA_MULTRET); }
/** ** Call a Lua handler */ void CallHandler(unsigned int handle, int value) { lua_getglobal(Lua, "_handlers_"); lua_rawgeti(Lua, -1, handle); lua_pushnumber(Lua, value); LuaCall(1, 1); lua_pop(Lua, 1); }
static PyObject *Lua_require(PyObject *self, PyObject *args) { lua_getglobal(LuaState, "require"); if (lua_isnil(LuaState, -1)) { lua_pop(LuaState, 1); PyErr_SetString(PyExc_RuntimeError, "require is not defined"); return NULL; } return LuaCall(LuaState, args); }
/** ** Send command to ccl. ** ** @param command Zero terminated command string. ** @param exitOnError Exit if an error occurs. */ int CclCommand(const std::string &command, bool exitOnError) { int status; if (!(status = luaL_loadbuffer(Lua, command.c_str(), command.size(), command.c_str()))) { LuaCall(0, 1, exitOnError); } else { report(status, exitOnError); } return status; }
static PyObject *Lua_require(PyObject *self, PyObject *args) { lua_pushliteral(L, "require"); lua_rawget(L, LUA_GLOBALSINDEX); if (lua_isnil(L, -1)) { lua_pop(L, 1); PyErr_SetString(PyExc_RuntimeError, "require is not defined"); return NULL; } return LuaCall(L, args); }
/** ** Execute the AI Script. */ static void AiExecuteScript() { if (AiPlayer->Script.empty()) { return; } lua_getglobal(Lua, "_ai_scripts_"); lua_pushstring(Lua, AiPlayer->Script.c_str()); lua_rawget(Lua, -2); LuaCall(0, 1); lua_pop(Lua, 1); }
/** ** Initialize the trigger module. */ void InitTriggers() { // Setup default triggers // FIXME: choose the triggers for game type lua_getglobal(Lua, "_triggers_"); if (lua_isnil(Lua, -1)) { lua_getglobal(Lua, "SinglePlayerTriggers"); LuaCall(0, 1); } lua_pop(Lua, 1); }
/** ** Handle cheats ** ** @return 1 if a cheat was handled, 0 otherwise */ int HandleCheats(const std::string &input) { int ret; #if defined(DEBUG) || defined(PROF) if (input == "ai me") { if (ThisPlayer->AiEnabled) { // FIXME: UnitGoesUnderFog and UnitGoesOutOfFog change unit refs // for human players. We can't switch back to a human player or // we'll be using the wrong ref counts. #if 0 ThisPlayer->AiEnabled = false; ThisPlayer->Type = PlayerPerson; SetMessage("AI is off, Normal Player"); #else SetMessage("Cannot disable 'ai me' cheat"); #endif } else { ThisPlayer->AiEnabled = true; ThisPlayer->Type = PlayerComputer; if (!ThisPlayer->Ai) { AiInit(*ThisPlayer); } SetMessage("I'm the BORG, resistance is futile!"); } return 1; } #endif int base = lua_gettop(Lua); lua_getglobal(Lua, "HandleCheats"); if (!lua_isfunction(Lua, -1)) { DebugPrint("No HandleCheats function in lua.\n"); return 0; } lua_pushstring(Lua, input.c_str()); LuaCall(1, 0, false); if (lua_gettop(Lua) - base == 1) { ret = LuaToBoolean(Lua, -1); lua_pop(Lua, 1); } else { DebugPrint("HandleCheats must return a boolean"); ret = 0; } return ret; }
/** ** Execute a Lua function of the AI type. */ static void AiExecuteFunction(const char *field) { if (AiPlayer->AiType != NULL) { lua_getfield(Lua, LUA_GLOBALSINDEX, "AiTypes"); lua_getfield(Lua, -1, AiPlayer->AiType->Name.c_str()); lua_getfield(Lua, -1, field); if (!lua_isnil(Lua, -1)) { LuaCall(0, 1); // removes the function from the stack lua_pop(Lua, 2); // remove the tables too } else { lua_pop(Lua, 3); } } }
/** ** Check if music is finished and play the next song */ void CheckMusicFinished(bool force) { bool proceed; SDL_LockMutex(MusicFinishedMutex); proceed = MusicFinished; MusicFinished = false; SDL_UnlockMutex(MusicFinishedMutex); if ((proceed || force) && SoundEnabled() && IsMusicEnabled() && CallbackMusic) { lua_getglobal(Lua, "MusicStopped"); if (!lua_isfunction(Lua, -1)) { fprintf(stderr, "No MusicStopped function in Lua\n"); StopMusic(); } else { LuaCall(0, 1); } } }
/** ** Check trigger each game cycle. */ void TriggersEachCycle() { const int base = lua_gettop(Lua); lua_getglobal(Lua, "_triggers_"); int triggers = lua_rawlen(Lua, -1); if (Trigger >= triggers) { Trigger = 0; } if (GamePaused) { lua_pop(Lua, 1); return; } // Skip to the next trigger while (Trigger < triggers) { lua_rawgeti(Lua, -1, Trigger + 1); if (!lua_isnumber(Lua, -1)) { break; } lua_pop(Lua, 1); Trigger += 2; } if (Trigger < triggers) { int currentTrigger = Trigger; Trigger += 2; LuaCall(0, 0); // If condition is true execute action if (lua_gettop(Lua) > base + 1 && lua_toboolean(Lua, -1)) { lua_settop(Lua, base + 1); if (TriggerExecuteAction(currentTrigger + 1)) { TriggerRemoveTrigger(currentTrigger); } } lua_settop(Lua, base + 1); } lua_pop(Lua, 1); }
/** ** Execute a trigger action ** ** @param script Script to execute ** ** @return 1 if the trigger should be removed */ static int TriggerExecuteAction(int script) { const int base = lua_gettop(Lua); int ret = 0; lua_rawgeti(Lua, -1, script + 1); const int args = lua_rawlen(Lua, -1); for (int j = 0; j < args; ++j) { lua_rawgeti(Lua, -1, j + 1); LuaCall(0, 0); if (lua_gettop(Lua) > base + 1 && lua_toboolean(Lua, -1)) { ret = 1; } else { ret = 0; } lua_settop(Lua, base + 1); } lua_pop(Lua, 1); // If action returns false remove it return !ret; }
/** ** Call the lua function HandleCommandKey */ bool HandleCommandKey(int key) { int base = lua_gettop(Lua); lua_getglobal(Lua, "HandleCommandKey"); if (!lua_isfunction(Lua, -1)) { DebugPrint("No HandleCommandKey function in lua.\n"); return false; } lua_pushstring(Lua, SdlKey2Str(key)); lua_pushboolean(Lua, (KeyModifiers & ModifierControl)); lua_pushboolean(Lua, (KeyModifiers & ModifierAlt)); lua_pushboolean(Lua, (KeyModifiers & ModifierShift)); LuaCall(4, 0); if (lua_gettop(Lua) - base == 1) { bool ret = LuaToBoolean(Lua, base + 1); lua_pop(Lua, 1); return ret; } else { LuaError(Lua, "HandleCommandKey must return a boolean"); return false; } }
/** ** Load a file and execute it ** ** @param file File to load and execute ** ** @return 0 for success, else exit. */ int LuaLoadFile(const std::string &file) { int status; std::string PreviousLuaFile; std::string buf; PreviousLuaFile = CurrentLuaFile; CurrentLuaFile = file; LuaLoadBuffer(file, buf); if (buf.empty()) { return -1; } if (!(status = luaL_loadbuffer(Lua, buf.c_str(), buf.size(), file.c_str()))) { LuaCall(0, 1); } else { report(status, true); } CurrentLuaFile = PreviousLuaFile; return status; }
//Returns -1 if this thread is dead and needs to be killed int CCobThread::Tick(int deltaTime) { if (state == Sleep) { logOutput.Print("CobError: sleeping thread ticked!"); } if (state == Dead || !owner) { return -1; } state = Run; GCobEngine.SetCurThread(this); int r1, r2, r3, r4, r5, r6; vector<int> args; CCobThread *thread; execTrace.clear(); delayedAnims.clear(); //list<int>::iterator ei; vector<int>::iterator ei; #if COB_DEBUG > 0 if (COB_DEBUG_FILTER) logOutput.Print("Executing in %s (from %s)", script.scriptNames[callStack.back().functionId].c_str(), GetName().c_str()); #endif while (state == Run) { //int opcode = *(int *)&script.code[PC]; //Disabling exec trace gives about a 50% speedup on vm-intensive code //execTrace.push_back(PC); int opcode = GET_LONG_PC(); #if COB_DEBUG > 1 if (COB_DEBUG_FILTER) logOutput.Print("PC: %x opcode: %x (%s)", PC - 1, opcode, GetOpcodeName(opcode).c_str()); #endif switch(opcode) { case PUSH_CONSTANT: r1 = GET_LONG_PC(); stack.push_back(r1); break; case SLEEP: r1 = POP(); wakeTime = GCurrentTime + r1; state = Sleep; GCobEngine.AddThread(this); GCobEngine.SetCurThread(NULL); #if COB_DEBUG > 0 if (COB_DEBUG_FILTER) logOutput.Print("%s sleeping for %d ms", script.scriptNames[callStack.back().functionId].c_str(), r1); #endif return 0; case SPIN: r1 = GET_LONG_PC(); r2 = GET_LONG_PC(); r3 = POP(); //speed r4 = POP(); //accel owner->Spin(r1, r2, r3, r4); break; case STOP_SPIN: r1 = GET_LONG_PC(); r2 = GET_LONG_PC(); r3 = POP(); //decel //logOutput.Print("Stop spin of %s around %d", script.pieceNames[r1].c_str(), r2); owner->StopSpin(r1, r2, r3); break; case RETURN: retCode = POP(); if (callStack.back().returnAddr == -1) { #if COB_DEBUG > 0 if (COB_DEBUG_FILTER) logOutput.Print("%s returned %d", script.scriptNames[callStack.back().functionId].c_str(), retCode); #endif state = Dead; GCobEngine.SetCurThread(NULL); //callStack.pop_back(); //Leave values intact on stack in case caller wants to check them return -1; } PC = callStack.back().returnAddr; while (stack.size() > callStack.back().stackTop) { stack.pop_back(); } callStack.pop_back(); #if COB_DEBUG > 0 if (COB_DEBUG_FILTER) logOutput.Print("Returning to %s", script.scriptNames[callStack.back().functionId].c_str()); #endif break; case SHADE: r1 = GET_LONG_PC(); break; case DONT_SHADE: r1 = GET_LONG_PC(); break; case CACHE: r1 = GET_LONG_PC(); break; case DONT_CACHE: r1 = GET_LONG_PC(); break; case CALL: { r1 = GET_LONG_PC(); PC--; const string& name = script.scriptNames[r1]; if (name.find("lua_") == 0) { script.code[PC - 1] = LUA_CALL; LuaCall(); break; } script.code[PC - 1] = REAL_CALL; // fall through // } case REAL_CALL: r1 = GET_LONG_PC(); r2 = GET_LONG_PC(); if (script.scriptLengths[r1] == 0) { //logOutput.Print("Preventing call to zero-len script %s", script.scriptNames[r1].c_str()); break; } struct callInfo ci; ci.functionId = r1; ci.returnAddr = PC; ci.stackTop = stack.size() - r2; callStack.push_back(ci); paramCount = r2; PC = script.scriptOffsets[r1]; #if COB_DEBUG > 0 if (COB_DEBUG_FILTER) logOutput.Print("Calling %s", script.scriptNames[r1].c_str()); #endif break; case LUA_CALL: LuaCall(); break; case POP_STATIC: r1 = GET_LONG_PC(); r2 = POP(); owner->staticVars[r1] = r2; //logOutput.Print("Pop static var %d val %d", r1, r2); break; case POP_STACK: POP(); break; case START: r1 = GET_LONG_PC(); r2 = GET_LONG_PC(); if (script.scriptLengths[r1] == 0) { //logOutput.Print("Preventing start of zero-len script %s", script.scriptNames[r1].c_str()); break; } args.clear(); for (r3 = 0; r3 < r2; ++r3) { r4 = POP(); args.push_back(r4); } thread = SAFE_NEW CCobThread(script, owner); thread->Start(r1, args, true); //Seems that threads should inherit signal mask from creator thread->signalMask = signalMask; #if COB_DEBUG > 0 if (COB_DEBUG_FILTER) logOutput.Print("Starting %s %d", script.scriptNames[r1].c_str(), signalMask); #endif break; case CREATE_LOCAL_VAR: if (paramCount == 0) { stack.push_back(0); } else { paramCount--; } break; case GET_UNIT_VALUE: r1 = POP(); if ((r1 >= LUA0) && (r1 <= LUA9)) { stack.push_back(luaArgs[r1 - LUA0]); break; } ForceCommitAllAnims(); // getunitval could possibly read piece locations r1 = owner->GetUnitVal(r1, 0, 0, 0, 0); stack.push_back(r1); break; case JUMP_NOT_EQUAL: r1 = GET_LONG_PC(); r2 = POP(); if (r2 == 0) { PC = r1; } break; case JUMP: r1 = GET_LONG_PC(); //this seem to be an error in the docs.. //r2 = script.scriptOffsets[callStack.back().functionId] + r1; PC = r1; break; case POP_LOCAL_VAR: r1 = GET_LONG_PC(); r2 = POP(); stack[callStack.back().stackTop + r1] = r2; break; case PUSH_LOCAL_VAR: r1 = GET_LONG_PC(); r2 = stack[callStack.back().stackTop + r1]; stack.push_back(r2); break; case SET_LESS_OR_EQUAL: r2 = POP(); r1 = POP(); if (r1 <= r2) stack.push_back(1); else stack.push_back(0); break; case BITWISE_AND: r1 = POP(); r2 = POP(); stack.push_back(r1 & r2); break; case BITWISE_OR: //seems to want stack contents or'd, result places on stack r1 = POP(); r2 = POP(); stack.push_back(r1 | r2); break; case BITWISE_XOR: r1 = POP(); r2 = POP(); stack.push_back(r1 ^ r2); break; case BITWISE_NOT: r1 = POP(); stack.push_back(~r1); break; case EXPLODE: r1 = GET_LONG_PC(); r2 = POP(); owner->Explode(r1, r2); break; case PLAY_SOUND: r1 = GET_LONG_PC(); r2 = POP(); owner->PlayUnitSound(r1, r2); break; case PUSH_STATIC: r1 = GET_LONG_PC(); stack.push_back(owner->staticVars[r1]); //logOutput.Print("Push static %d val %d", r1, owner->staticVars[r1]); break; case SET_NOT_EQUAL: r1 = POP(); r2 = POP(); if (r1 != r2) stack.push_back(1); else stack.push_back(0); break; case SET_EQUAL: r1 = POP(); r2 = POP(); if (r1 == r2) stack.push_back(1); else stack.push_back(0); break; case SET_LESS: r2 = POP(); r1 = POP(); if (r1 < r2) stack.push_back(1); else stack.push_back(0); break; case SET_GREATER: r2 = POP(); r1 = POP(); if (r1 > r2) stack.push_back(1); else stack.push_back(0); break; case SET_GREATER_OR_EQUAL: r2 = POP(); r1 = POP(); if (r1 >= r2) stack.push_back(1); else stack.push_back(0); break; case RAND: r2 = POP(); r1 = POP(); r3 = gs->randInt() % (r2 - r1 + 1) + r1; stack.push_back(r3); break; case EMIT_SFX: r1 = POP(); r2 = GET_LONG_PC(); owner->EmitSfx(r1, r2); break; case MUL: r1 = POP(); r2 = POP(); stack.push_back(r1 * r2); break; case SIGNAL: r1 = POP(); owner->Signal(r1); break; case SET_SIGNAL_MASK: r1 = POP(); signalMask = r1; break; case TURN: r2 = POP(); r1 = POP(); r3 = GET_LONG_PC(); r4 = GET_LONG_PC(); //logOutput.Print("Turning piece %s axis %d to %d speed %d", script.pieceNames[r3].c_str(), r4, r2, r1); ForceCommitAnim(1, r3, r4); owner->Turn(r3, r4, r1, r2); break; case GET: r5 = POP(); r4 = POP(); r3 = POP(); r2 = POP(); r1 = POP(); if ((r1 >= LUA0) && (r1 <= LUA9)) { stack.push_back(luaArgs[r1 - LUA0]); break; } ForceCommitAllAnims(); r6 = owner->GetUnitVal(r1, r2, r3, r4, r5); stack.push_back(r6); break; case ADD: r2 = POP(); r1 = POP(); stack.push_back(r1 + r2); break; case SUB: r2 = POP(); r1 = POP(); r3 = r1 - r2; stack.push_back(r3); break; case DIV: r2 = POP(); r1 = POP(); if (r2 != 0) r3 = r1 / r2; else { r3 = 1000; //infinity! logOutput.Print("CobError: division by zero"); } stack.push_back(r3); break; case MOD: r2 = POP(); r1 = POP(); if (r2 != 0) stack.push_back(r1 % r2); else { stack.push_back(0); logOutput.Print("CobError: modulo division by zero"); } break; case MOVE: r1 = GET_LONG_PC(); r2 = GET_LONG_PC(); r4 = POP(); r3 = POP(); ForceCommitAnim(2, r1, r2); owner->Move(r1, r2, r3, r4); break; case MOVE_NOW:{ r1 = GET_LONG_PC(); r2 = GET_LONG_PC(); r3 = POP(); if (owner->smoothAnim) { DelayedAnim a; a.type = 2; a.piece = r1; a.axis = r2; a.dest = r3; delayedAnims.push_back(a); //logOutput.Print("Delayed move %s %d %d", owner->pieces[r1].name.c_str(), r2, r3); } else { owner->MoveNow(r1, r2, r3); } break;} case TURN_NOW:{ r1 = GET_LONG_PC(); r2 = GET_LONG_PC(); r3 = POP(); if (owner->smoothAnim) { DelayedAnim a; a.type = 1; a.piece = r1; a.axis = r2; a.dest = r3; delayedAnims.push_back(a); } else { owner->TurnNow(r1, r2, r3); } break;} case WAIT_TURN: r1 = GET_LONG_PC(); r2 = GET_LONG_PC(); //logOutput.Print("Waiting for turn on piece %s around axis %d", script.pieceNames[r1].c_str(), r2); if (owner->AddTurnListener(r1, r2, this)) { state = WaitTurn; GCobEngine.SetCurThread(NULL); return 0; } else break; case WAIT_MOVE: r1 = GET_LONG_PC(); r2 = GET_LONG_PC(); //logOutput.Print("Waiting for move on piece %s on axis %d", script.pieceNames[r1].c_str(), r2); if (owner->AddMoveListener(r1, r2, this)) { state = WaitMove; GCobEngine.SetCurThread(NULL); return 0; } break; case SET: r2 = POP(); r1 = POP(); //logOutput.Print("Setting unit value %d to %d", r1, r2); if ((r1 >= LUA0) && (r1 <= LUA9)) { luaArgs[r1 - LUA0] = r2; break; } owner->SetUnitVal(r1, r2); break; case ATTACH: r3 = POP(); r2 = POP(); r1 = POP(); owner->AttachUnit(r2, r1); break; case DROP: r1 = POP(); owner->DropUnit(r1); break; case LOGICAL_NOT: //Like bitwise, but only on values 1 and 0. r1 = POP(); if (r1 == 0) stack.push_back(1); else stack.push_back(0); break; case LOGICAL_AND: r1 = POP(); r2 = POP(); if (r1 && r2) stack.push_back(1); else stack.push_back(0); break; case LOGICAL_OR: r1 = POP(); r2 = POP(); if (r1 || r2) stack.push_back(1); else stack.push_back(0); break; case LOGICAL_XOR: r1 = POP(); r2 = POP(); if (!!r1 ^ !!r2) stack.push_back(1); else stack.push_back(0); break; case HIDE: r1 = GET_LONG_PC(); owner->SetVisibility(r1, false); //logOutput.Print("Hiding %d", r1); break; case SHOW:{ r1 = GET_LONG_PC(); int i; for (i = 0; i < COB_MaxWeapons; ++i) if (callStack.back().functionId == script.scriptIndex[COBFN_FirePrimary + i]) break; // If true, we are in a Fire-script and should show a special flare effect if (i < COB_MaxWeapons) { owner->ShowFlare(r1); } else { owner->SetVisibility(r1, true); } //logOutput.Print("Showing %d", r1); break;} default: logOutput.Print("CobError: Unknown opcode %x (in %s:%s at %x)", opcode, script.name.c_str(), script.scriptNames[callStack.back().functionId].c_str(), PC - 1); logOutput.Print("Exec trace:"); ei = execTrace.begin(); while (ei != execTrace.end()) { logOutput.Print("PC: %3x opcode: %s", *ei, GetOpcodeName(script.code[*ei]).c_str()); ei++; } state = Dead; GCobEngine.SetCurThread(NULL); return -1; break; } } GCobEngine.SetCurThread(NULL); return 0; }
static PyObject *LuaObject_call(PyObject *obj, PyObject *args) { lua_settop(LuaState, 0); lua_rawgeti(LuaState, LUA_REGISTRYINDEX, ((LuaObject*)obj)->ref); return LuaCall(LuaState, args); }
int main(int argc,char **argv){ if(argc < 2){ printf("usage testlua luafile\n"); return 0; } lua_State *L = luaL_newstate(); luaL_openlibs(L); if (luaL_dofile(L,argv[1])) { const char * error = lua_tostring(L, -1); lua_pop(L,1); printf("%s\n",error); } const char *err; printf("------makeLuaObjByStr---------\n\n"); //dynamic build a lua table and return luaRef tabRef = makeLuaObjByStr(L,"return {a=100}"); if(tabRef.L){ int a = 0; err = LuaRef_Get(tabRef,"si","a",&a); if(err) printf("%s\n",err); else{ printf("a == %d\n",a); } release_luaRef(&tabRef); } printf("------call 0 arg---------\n\n"); err = LuaCall(L,"fun0",NULL); if(err) printf("error on fun0:%s\n",err); printf("------call 2 arg(integer,str),1 ret(integer)---------\n\n"); unsigned int iret1; err = LuaCall(L,"fun1","is:i",0xfffffffff,"hello",&iret1); if(err) printf("error on fun1:%s\n",err); else printf("ret1=%u\n",iret1); printf("------call 2 arg(str),1 ret(str)---------\n\n"); char *sret1; err = LuaCall(L,"fun2","ss:s","hello","kenny",&sret1); if(err) printf("error on fun2:%s\n",err); else printf("sret1=%s\n",sret1); printf("------call 3 arg(str,str,lua str),2 ret(lua str)---------\n\n"); char *Sret1,*Sret2; size_t Lret1,Lret2; err = LuaCall(L,"fun3","ssS:SS","1","2","3",sizeof("3"),&Sret1,&Lret1,&Sret2,&Lret2); if(err) printf("error on fun3:%s\n",err); else{ printf("%s %ld\n",Sret1,Lret1); printf("%s %ld\n",Sret2,Lret2); } printf("------call 0 arg, 1 ret(luaobj)---------\n\n"); luaRef funRef; err = LuaCall(L,"fun5",":r",&funRef); if(err) printf("error on fun5:%s\n",err); int num = -1; int num2 = -1; LuaCallRefFunc(funRef,":ii",&num,&num2); printf("%d,%d\n",num,num2); printf("------call lua obj function---------\n\n"); err = LuaCall(L,"fun6",":ri",&tabRef,&num); if(err) printf("error on fun6:%s\n",err); printf("%d\n",num); err = LuaCallTabFuncS(tabRef,"hello",NULL); if(err) printf("%s\n",err); printf("------set and get luaobj field---------\n\n"); err = LuaRef_Set(tabRef,"siss","f1",99,"f2","hello haha"); if(err) printf("%s\n",err); else{ int f1; const char *f2; err = LuaRef_Get(tabRef,"siss","f1",&f1,"f2",&f2); if(err) printf("%s\n",err); else printf("get %d,%s\n",f1,f2); } err = LuaRef_Set(tabRef,"sp","f1",NULL); if(err) printf("%s\n",err); else{ err = LuaCall(L,"fun7",NULL); if(err) printf("error on fun7:%s\n",err); } printf("------iterate luaobj-------------\n\n"); lua_getglobal(L,"ttab4"); tabRef = toluaRef(L,-1); LuaTabForEach(tabRef){ const char *key = lua_tostring(L,EnumKey); const char *val = lua_tostring(L,EnumVal); printf("%s,%s\n",key,val); } printf("end\n"); return 0; }
bool CCobThread::Tick() { if (state == Sleep) { LOG_L(L_ERROR, "sleeping thread ticked!"); } if (state == Dead || owner == nullptr) { return false; } state = Run; int r1, r2, r3, r4, r5, r6; vector<int> args; vector<int>::iterator ei; //execTrace.clear(); //LOG_L(L_DEBUG, "Executing in %s (from %s)", script.scriptNames[callStack.back().functionId].c_str(), GetName().c_str()); while (state == Run) { //int opcode = *(int*)&script.code[PC]; // Disabling exec trace gives about a 50% speedup on vm-intensive code //execTrace.push_back(PC); int opcode = GET_LONG_PC(); //LOG_L(L_DEBUG, "PC: %x opcode: %x (%s)", PC - 1, opcode, GetOpcodeName(opcode).c_str()); switch(opcode) { case PUSH_CONSTANT: r1 = GET_LONG_PC(); stack.push_back(r1); break; case SLEEP: r1 = POP(); wakeTime = cobEngine->GetCurrentTime() + r1; state = Sleep; cobEngine->AddThread(this); //LOG_L(L_DEBUG, "%s sleeping for %d ms", script.scriptNames[callStack.back().functionId].c_str(), r1); return true; case SPIN: r1 = GET_LONG_PC(); r2 = GET_LONG_PC(); r3 = POP(); // speed r4 = POP(); // accel owner->Spin(r1, r2, r3, r4); break; case STOP_SPIN: r1 = GET_LONG_PC(); r2 = GET_LONG_PC(); r3 = POP(); // decel //LOG_L(L_DEBUG, "Stop spin of %s around %d", script.pieceNames[r1].c_str(), r2); owner->StopSpin(r1, r2, r3); break; case RETURN: retCode = POP(); if (callStack.back().returnAddr == -1) { //LOG_L(L_DEBUG, "%s returned %d", script.scriptNames[callStack.back().functionId].c_str(), retCode); state = Dead; //callStack.pop_back(); // Leave values intact on stack in case caller wants to check them return false; } PC = callStack.back().returnAddr; while (stack.size() > callStack.back().stackTop) { stack.pop_back(); } callStack.pop_back(); //LOG_L(L_DEBUG, "Returning to %s", owner->script->scriptNames[callStack.back().functionId].c_str()); break; case SHADE: r1 = GET_LONG_PC(); break; case DONT_SHADE: r1 = GET_LONG_PC(); break; case CACHE: r1 = GET_LONG_PC(); break; case DONT_CACHE: r1 = GET_LONG_PC(); break; case CALL: { r1 = GET_LONG_PC(); PC--; const string& name = owner->script->scriptNames[r1]; if (name.find("lua_") == 0) { owner->script->code[PC - 1] = LUA_CALL; LuaCall(); break; } owner->script->code[PC - 1] = REAL_CALL; // fall through // } case REAL_CALL: r1 = GET_LONG_PC(); r2 = GET_LONG_PC(); if (owner->script->scriptLengths[r1] == 0) { //LOG_L(L_DEBUG, "Preventing call to zero-len script %s", owner->script->scriptNames[r1].c_str()); break; } CallInfo ci; ci.functionId = r1; ci.returnAddr = PC; ci.stackTop = stack.size() - r2; callStack.push_back(ci); paramCount = r2; PC = owner->script->scriptOffsets[r1]; //LOG_L(L_DEBUG, "Calling %s", owner->script->scriptNames[r1].c_str()); break; case LUA_CALL: LuaCall(); break; case POP_STATIC: r1 = GET_LONG_PC(); r2 = POP(); owner->staticVars[r1] = r2; //LOG_L(L_DEBUG, "Pop static var %d val %d", r1, r2); break; case POP_STACK: POP(); break; case START: { r1 = GET_LONG_PC(); r2 = GET_LONG_PC(); if (owner->script->scriptLengths[r1] == 0) { //LOG_L(L_DEBUG, "Preventing start of zero-len script %s", owner->script->scriptNames[r1].c_str()); break; } args.clear(); args.reserve(r2); for (r3 = 0; r3 < r2; ++r3) { r4 = POP(); args.push_back(r4); } CCobThread* thread = new CCobThread(owner); thread->Start(r1, args, true); // Seems that threads should inherit signal mask from creator thread->signalMask = signalMask; //LOG_L(L_DEBUG, "Starting %s %d", owner->script->scriptNames[r1].c_str(), signalMask); } break; case CREATE_LOCAL_VAR: if (paramCount == 0) { stack.push_back(0); } else { paramCount--; } break; case GET_UNIT_VALUE: r1 = POP(); if ((r1 >= LUA0) && (r1 <= LUA9)) { stack.push_back(luaArgs[r1 - LUA0]); break; } r1 = owner->GetUnitVal(r1, 0, 0, 0, 0); stack.push_back(r1); break; case JUMP_NOT_EQUAL: r1 = GET_LONG_PC(); r2 = POP(); if (r2 == 0) { PC = r1; } break; case JUMP: r1 = GET_LONG_PC(); // this seem to be an error in the docs.. //r2 = owner->script->scriptOffsets[callStack.back().functionId] + r1; PC = r1; break; case POP_LOCAL_VAR: r1 = GET_LONG_PC(); r2 = POP(); stack[callStack.back().stackTop + r1] = r2; break; case PUSH_LOCAL_VAR: r1 = GET_LONG_PC(); r2 = stack[callStack.back().stackTop + r1]; stack.push_back(r2); break; case SET_LESS_OR_EQUAL: r2 = POP(); r1 = POP(); if (r1 <= r2) stack.push_back(1); else stack.push_back(0); break; case BITWISE_AND: r1 = POP(); r2 = POP(); stack.push_back(r1 & r2); break; case BITWISE_OR: // seems to want stack contents or'd, result places on stack r1 = POP(); r2 = POP(); stack.push_back(r1 | r2); break; case BITWISE_XOR: r1 = POP(); r2 = POP(); stack.push_back(r1 ^ r2); break; case BITWISE_NOT: r1 = POP(); stack.push_back(~r1); break; case EXPLODE: r1 = GET_LONG_PC(); r2 = POP(); owner->Explode(r1, r2); break; case PLAY_SOUND: r1 = GET_LONG_PC(); r2 = POP(); owner->PlayUnitSound(r1, r2); break; case PUSH_STATIC: r1 = GET_LONG_PC(); stack.push_back(owner->staticVars[r1]); //LOG_L(L_DEBUG, "Push static %d val %d", r1, owner->staticVars[r1]); break; case SET_NOT_EQUAL: r1 = POP(); r2 = POP(); if (r1 != r2) stack.push_back(1); else stack.push_back(0); break; case SET_EQUAL: r1 = POP(); r2 = POP(); if (r1 == r2) stack.push_back(1); else stack.push_back(0); break; case SET_LESS: r2 = POP(); r1 = POP(); if (r1 < r2) stack.push_back(1); else stack.push_back(0); break; case SET_GREATER: r2 = POP(); r1 = POP(); if (r1 > r2) stack.push_back(1); else stack.push_back(0); break; case SET_GREATER_OR_EQUAL: r2 = POP(); r1 = POP(); if (r1 >= r2) stack.push_back(1); else stack.push_back(0); break; case RAND: r2 = POP(); r1 = POP(); r3 = gs->randInt() % (r2 - r1 + 1) + r1; stack.push_back(r3); break; case EMIT_SFX: r1 = POP(); r2 = GET_LONG_PC(); owner->EmitSfx(r1, r2); break; case MUL: r1 = POP(); r2 = POP(); stack.push_back(r1 * r2); break; case SIGNAL: r1 = POP(); owner->Signal(r1); break; case SET_SIGNAL_MASK: r1 = POP(); signalMask = r1; break; case TURN: r2 = POP(); r1 = POP(); r3 = GET_LONG_PC(); r4 = GET_LONG_PC(); //LOG_L(L_DEBUG, "Turning piece %s axis %d to %d speed %d", owner->script->pieceNames[r3].c_str(), r4, r2, r1); owner->Turn(r3, r4, r1, r2); break; case GET: r5 = POP(); r4 = POP(); r3 = POP(); r2 = POP(); r1 = POP(); if ((r1 >= LUA0) && (r1 <= LUA9)) { stack.push_back(luaArgs[r1 - LUA0]); break; } r6 = owner->GetUnitVal(r1, r2, r3, r4, r5); stack.push_back(r6); break; case ADD: r2 = POP(); r1 = POP(); stack.push_back(r1 + r2); break; case SUB: r2 = POP(); r1 = POP(); r3 = r1 - r2; stack.push_back(r3); break; case DIV: r2 = POP(); r1 = POP(); if (r2 != 0) r3 = r1 / r2; else { r3 = 1000; // infinity! ShowError("division by zero"); } stack.push_back(r3); break; case MOD: r2 = POP(); r1 = POP(); if (r2 != 0) stack.push_back(r1 % r2); else { stack.push_back(0); ShowError("modulo division by zero"); } break; case MOVE: r1 = GET_LONG_PC(); r2 = GET_LONG_PC(); r4 = POP(); r3 = POP(); owner->Move(r1, r2, r3, r4); break; case MOVE_NOW:{ r1 = GET_LONG_PC(); r2 = GET_LONG_PC(); r3 = POP(); owner->MoveNow(r1, r2, r3); break;} case TURN_NOW:{ r1 = GET_LONG_PC(); r2 = GET_LONG_PC(); r3 = POP(); owner->TurnNow(r1, r2, r3); break;} case WAIT_TURN: r1 = GET_LONG_PC(); r2 = GET_LONG_PC(); //LOG_L(L_DEBUG, "Waiting for turn on piece %s around axis %d", owner->script->pieceNames[r1].c_str(), r2); if (owner->NeedsWait(CCobInstance::ATurn, r1, r2)) { state = WaitTurn; waitPiece = r1; waitAxis = r2; return true; } else break; case WAIT_MOVE: r1 = GET_LONG_PC(); r2 = GET_LONG_PC(); //LOG_L(L_DEBUG, "Waiting for move on piece %s on axis %d", owner->script->pieceNames[r1].c_str(), r2); if (owner->NeedsWait(CCobInstance::AMove, r1, r2)) { state = WaitMove; waitPiece = r1; waitAxis = r2; return true; } break; case SET: r2 = POP(); r1 = POP(); //LOG_L(L_DEBUG, "Setting unit value %d to %d", r1, r2); if ((r1 >= LUA0) && (r1 <= LUA9)) { luaArgs[r1 - LUA0] = r2; break; } owner->SetUnitVal(r1, r2); break; case ATTACH: r3 = POP(); r2 = POP(); r1 = POP(); owner->AttachUnit(r2, r1); break; case DROP: r1 = POP(); owner->DropUnit(r1); break; case LOGICAL_NOT: // Like bitwise, but only on values 1 and 0. r1 = POP(); if (r1 == 0) stack.push_back(1); else stack.push_back(0); break; case LOGICAL_AND: r1 = POP(); r2 = POP(); if (r1 && r2) stack.push_back(1); else stack.push_back(0); break; case LOGICAL_OR: r1 = POP(); r2 = POP(); if (r1 || r2) stack.push_back(1); else stack.push_back(0); break; case LOGICAL_XOR: r1 = POP(); r2 = POP(); if ( (!!r1) ^ (!!r2)) stack.push_back(1); else stack.push_back(0); break; case HIDE: r1 = GET_LONG_PC(); owner->SetVisibility(r1, false); //LOG_L(L_DEBUG, "Hiding %d", r1); break; case SHOW:{ r1 = GET_LONG_PC(); int i; for (i = 0; i < MAX_WEAPONS_PER_UNIT; ++i) if (callStack.back().functionId == owner->script->scriptIndex[COBFN_FirePrimary + COBFN_Weapon_Funcs * i]) break; // If true, we are in a Fire-script and should show a special flare effect if (i < MAX_WEAPONS_PER_UNIT) { owner->ShowFlare(r1); } else { owner->SetVisibility(r1, true); } //LOG_L(L_DEBUG, "Showing %d", r1); break;} default: LOG_L(L_ERROR, "Unknown opcode %x (in %s:%s at %x)", opcode, owner->script->name.c_str(), owner->script->scriptNames[callStack.back().functionId].c_str(), PC - 1); LOG_L(L_ERROR, "Exec trace:"); // ei = execTrace.begin(); // while (ei != execTrace.end()) { // LOG_L(L_ERROR, "PC: %3x opcode: %s", *ei, GetOpcodeName(owner->script->code[*ei]).c_str()); // ++ei; // } state = Dead; return false; } } return (state != Dead); // can arrive here as dead, through CCobInstance::Signal() }
void View::mouseUp(int button, double x, double y, bool shift, bool control, bool alt, bool command) { if (_scripts[ScriptOnMouseUp].L) { LuaCall(_scripts[ScriptOnMouseUp].L, _scripts[ScriptOnMouseUp].function, _luaRef, button, x, y, shift, control, alt, command); } }