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 + -
显示快捷键?