cobthread.cpp
来自「这是整套横扫千军3D版游戏的源码」· C++ 代码 · 共 968 行 · 第 1/2 页
CPP
968 行
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;
}
// Shows an errormessage which includes the current state of the script interpreter
void CCobThread::ShowError(const string& msg)
{
static int spamPrevention = 100;
if (spamPrevention < 0) return;
--spamPrevention;
if (callStack.size() == 0)
logOutput.Print("CobError: %s outside script execution (?)", msg.c_str());
else
logOutput.Print("CobError: %s (in %s:%s at %x)", msg.c_str(), script.name.c_str(), script.scriptNames[callStack.back().functionId].c_str(), PC - 1);
}
string CCobThread::GetOpcodeName(int opcode)
{
switch (opcode) {
case MOVE: return "move";
case TURN: return "turn";
case SPIN: return "spin";
case STOP_SPIN: return "stop-spin";
case SHOW: return "show";
case HIDE: return "hide";
case CACHE: return "cache";
case DONT_CACHE: return "dont-cache";
case TURN_NOW: return "turn-now";
case MOVE_NOW: return "move-now";
case SHADE: return "shade";
case DONT_SHADE: return "dont-shade";
case EMIT_SFX: return "sfx";
case WAIT_TURN: return "wait-for-turn";
case WAIT_MOVE: return "wait-for-move";
case SLEEP: return "sleep";
case PUSH_CONSTANT: return "pushc";
case PUSH_LOCAL_VAR: return "pushl";
case PUSH_STATIC: return "pushs";
case CREATE_LOCAL_VAR: return "clv";
case POP_LOCAL_VAR: return "popl";
case POP_STATIC: return "pops";
case POP_STACK: return "pop-stack";
case ADD: return "add";
case SUB: return "sub";
case MUL: return "mul";
case DIV: return "div";
case MOD: return "mod";
case BITWISE_AND: return "and";
case BITWISE_OR: return "or";
case BITWISE_XOR: return "xor";
case BITWISE_NOT: return "not";
case RAND: return "rand";
case GET_UNIT_VALUE: return "getuv";
case GET: return "get";
case SET_LESS: return "setl";
case SET_LESS_OR_EQUAL: return "setle";
case SET_GREATER: return "setg";
case SET_GREATER_OR_EQUAL: return "setge";
case SET_EQUAL: return "sete";
case SET_NOT_EQUAL: return "setne";
case LOGICAL_AND: return "land";
case LOGICAL_OR: return "lor";
case LOGICAL_XOR: return "lxor";
case LOGICAL_NOT: return "neg";
case START: return "start";
case CALL: return "call";
case REAL_CALL: return "call";
case LUA_CALL: return "lua_call";
case JUMP: return "jmp";
case RETURN: return "return";
case JUMP_NOT_EQUAL: return "jne";
case SIGNAL: return "signal";
case SET_SIGNAL_MASK: return "mask";
case EXPLODE: return "explode";
case PLAY_SOUND: return "play-sound";
case SET: return "set";
case ATTACH: return "attach";
case DROP: return "drop";
}
return "unknown";
}
void CCobThread::DependentDied(CObject* o)
{
if(o==owner)
owner=0;
}
void CCobThread::CommitAnims(int deltaTime)
{
for (vector<DelayedAnim>::iterator anim = delayedAnims.begin(); anim != delayedAnims.end(); ++anim) {
//Only consider smoothing when the thread is sleeping for a short while, but not too short
int delta = wakeTime - GCurrentTime;
bool smooth = (state == Sleep) && (delta < 300) && (delta > deltaTime);
// logOutput.Print("Commiting %s type %d %d", owner->pieces[anim->piece].name.c_str(), smooth, anim->dest);
switch (anim->type) {
case 1:
if (smooth)
owner->TurnSmooth(anim->piece, anim->axis, anim->dest, delta, deltaTime);
else
owner->TurnNow(anim->piece, anim->axis, anim->dest);
break;
case 2:
if (smooth)
owner->MoveSmooth(anim->piece, anim->axis, anim->dest, delta, deltaTime);
else
owner->MoveNow(anim->piece, anim->axis, anim->dest);
break;
}
}
delayedAnims.clear();
}
void CCobThread::ForceCommitAnim(int type, int piece, int axis)
{
for (vector<DelayedAnim>::iterator anim = delayedAnims.begin(); anim != delayedAnims.end(); ++anim) {
if ((anim->type == type) && (anim->piece == piece) && (anim->axis == axis)) {
switch (type) {
case 1:
owner->TurnNow(piece, axis, anim->dest);
break;
case 2:
owner->MoveNow(piece, axis, anim->dest);
break;
}
//Remove it so it does not interfere later
delayedAnims.erase(anim);
return;
}
}
}
void CCobThread::ForceCommitAllAnims()
{
for (vector<DelayedAnim>::iterator anim = delayedAnims.begin(); anim != delayedAnims.end(); ++anim) {
switch (anim->type) {
case 1:
owner->TurnNow(anim->piece, anim->axis, anim->dest);
break;
case 2:
owner->MoveNow(anim->piece, anim->axis, anim->dest);
break;
}
}
delayedAnims.clear();
}
/******************************************************************************/
void CCobThread::LuaCall()
{
const int r1 = GET_LONG_PC(); // script id
const int r2 = GET_LONG_PC(); // arg count
// setup the parameter array
const int size = (int)stack.size();
const int argCount = min(r2, MAX_LUA_COB_ARGS);
const int start = max(0, size - r2);
const int end = min(size, start + argCount);
int a = 0;
for (int i = start; i < end; i++) {
luaArgs[a] = stack[i];
a++;
}
if (r2 >= size) {
stack.clear();
} else {
stack.resize(size - r2);
}
if (!luaCob) {
luaArgs[0] = 0; // failure
return;
}
// check script index validity
if ((r1 < 0) || (r1 >= script.luaScripts.size())) {
luaArgs[0] = 0; // failure
return;
}
const LuaHashString& hs = script.luaScripts[r1];
#if COB_DEBUG > 0
if (COB_DEBUG_FILTER) {
logOutput.Print("Calling LuaCob %s", hs.GetString().c_str());
}
#endif
int argsCount = argCount;
luaCob->CallFunction(hs, owner->GetUnit(), argsCount, luaArgs);
retCode = luaArgs[0];
}
/******************************************************************************/
/******************************************************************************/
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?