// Assign the result to the appropriate _result variable void Expression::getResult(byte operation, int32 value, byte *type) { if (type != 0) *type = operation; switch (operation) { case OP_NOT: if (type != 0) *type ^= 1; break; case OP_LOAD_IMM_INT16: _resultInt = value; break; case OP_LOAD_IMM_STR: if ((char *)decodePtr(value) != _resultStr) strcpy(_resultStr, (char *)decodePtr(value)); break; case OP_LOAD_VAR_INT32: case OP_LOAD_VAR_INT32_AS_INT16: break; default: _resultInt = 0; if (type != 0) *type = OP_LOAD_IMM_INT16; break; } }
void Expression::simpleArithmetic1(StackFrame &stackFrame) { switch (stackFrame.opers[-1]) { case OP_ADD: if (stackFrame.opers[-2] == OP_LOAD_IMM_STR) { if ((char *)decodePtr(stackFrame.values[-2]) != _resultStr) { strcpy(_resultStr, (char *)decodePtr(stackFrame.values[-2])); stackFrame.values[-2] = encodePtr((byte *)_resultStr, kResStr); } strcat(_resultStr, (char *)decodePtr(stackFrame.values[0])); stackFrame.pop(2); } break; case OP_MUL: stackFrame.values[-2] *= stackFrame.values[0]; stackFrame.pop(2); break; case OP_DIV: stackFrame.values[-2] /= stackFrame.values[0]; stackFrame.pop(2); break; case OP_MOD: stackFrame.values[-2] %= stackFrame.values[0]; stackFrame.pop(2); break; case OP_BITAND: stackFrame.values[-2] &= stackFrame.values[0]; stackFrame.pop(2); break; } }
int Expression::cmpHelper(const StackFrame &stackFrame) { byte type = stackFrame.opers[-3]; int cmpTemp = 0; if (type == OP_LOAD_IMM_INT16) { cmpTemp = (int)stackFrame.values[-3] - (int)stackFrame.values[-1]; } else if (type == OP_LOAD_IMM_STR) { if ((char *)decodePtr(stackFrame.values[-3]) != _resultStr) { strcpy(_resultStr, (char *)decodePtr(stackFrame.values[-3])); stackFrame.values[-3] = encodePtr((byte *)_resultStr, kResStr); } cmpTemp = strcmp(_resultStr, (char *)decodePtr(stackFrame.values[-1])); } return cmpTemp; }
void Logic::formText(int32 *params) { // params 0 pointer to ob_graphic // 1 pointer to ob_speech // 2 pointer to ob_logic // 3 pointer to ob_mega // 4 encoded text number // 5 wav res id // 6 anim res id // 7 pointer to anim table // 8 animation mode 0 lip synced, // 1 just straight animation // There should always be a text line, as all text is derived from it. // If there is none, that's bad... if (!params[S_TEXT]) { warning("No text line for speech wav %d", params[S_WAV]); return; } ObjectSpeech obSpeech(decodePtr(params[S_OB_SPEECH])); // Establish the max width allowed for this text sprite. uint32 textWidth = obSpeech.getWidth(); if (!textWidth) textWidth = 400; // Pull out the text line, and make the sprite and text block uint32 text_res = params[S_TEXT] / SIZE; uint32 local_text = params[S_TEXT] & 0xffff; byte *text = _vm->fetchTextLine(_vm->_resman->openResource(text_res), local_text); // 'text + 2' to skip the first 2 bytes which form the line reference // number _speechTextBlocNo = _vm->_fontRenderer->buildNewBloc( text + 2, _textX, _textY, textWidth, obSpeech.getPen(), RDSPR_TRANS | RDSPR_DISPLAYALIGN, _vm->_speechFontId, POSITION_AT_CENTRE_OF_BASE); _vm->_resman->closeResource(text_res); // Set speech duration, in case not using a wav. _speechTime = strlen((char *)text) + 30; }
void Logic::locateTalker(int32 *params) { // params: 0 pointer to ob_graphic // 1 pointer to ob_speech // 2 pointer to ob_logic // 3 pointer to ob_mega // 4 encoded text number // 5 wav res id // 6 anim res id // 7 pointer to anim table // 8 animation mode 0 lip synced, // 1 just straight animation if (!_animId) { // There is no animation. Assume it's voice-over text, and put // it at the bottom of the screen. _textX = 320; _textY = 400; return; } byte *file = _vm->_resman->openResource(_animId); // '0' means 1st frame CdtEntry cdt_entry; FrameHeader frame_head; cdt_entry.read(_vm->fetchCdtEntry(file, 0)); frame_head.read(_vm->fetchFrameHeader(file, 0)); // Note: This part of the code is quite similar to registerFrame(). if (cdt_entry.frameType & FRAME_OFFSET) { // The frame has offsets, i.e. it's a scalable mega frame ObjectMega obMega(decodePtr(params[S_OB_MEGA])); uint16 scale = obMega.calcScale(); // Calc suitable centre point above the head, based on scaled // height // just use 'feet_x' as centre _textX = obMega.getFeetX(); // Add scaled y-offset to feet_y coord to get top of sprite _textY = obMega.getFeetY() + (cdt_entry.y * scale) / 256; } else { // It's a non-scaling anim - calc suitable centre point above // the head, based on scaled width // x-coord + half of width _textX = cdt_entry.x + frame_head.width / 2; _textY = cdt_entry.y; } _vm->_resman->closeResource(_animId); // Leave space above their head _textY -= GAP_ABOVE_HEAD; // Adjust the text coords for RDSPR_DISPLAYALIGN ScreenInfo *screenInfo = _vm->_screen->getScreenInfo(); _textX -= screenInfo->scroll_offset_x; _textY -= screenInfo->scroll_offset_y; }
// Complex arithmetics with brackets bool Expression::complexArithmetic(Stack &stack, StackFrame &stackFrame, int16 brackStart) { switch (stackFrame.opers[-2]) { case OP_ADD: if (stack.opers[brackStart] == OP_LOAD_IMM_INT16) { stack.values[brackStart] += stackFrame.values[-1]; } else if (stack.opers[brackStart] == OP_LOAD_IMM_STR) { if ((char *)decodePtr(stack.values[brackStart]) != _resultStr) { strcpy(_resultStr, (char *)decodePtr(stack.values[brackStart])); stack.values[brackStart] = encodePtr((byte *)_resultStr, kResStr); } strcat(_resultStr, (char *)decodePtr(stackFrame.values[-1])); } stackFrame.pop(2); break; case OP_SUB: stack.values[brackStart] -= stackFrame.values[-1]; stackFrame.pop(2); break; case OP_BITOR: stack.values[brackStart] |= stackFrame.values[-1]; stackFrame.pop(2); break; case OP_MUL: stackFrame.values[-3] *= stackFrame.values[-1]; stackFrame.pop(2); break; case OP_DIV: stackFrame.values[-3] /= stackFrame.values[-1]; stackFrame.pop(2); break; case OP_MOD: stackFrame.values[-3] %= stackFrame.values[-1]; stackFrame.pop(2); break; case OP_BITAND: stackFrame.values[-3] &= stackFrame.values[-1]; stackFrame.pop(2); break; case OP_OR: // (x OR false) == x // (x OR true) == true if (stackFrame.opers[-3] == GOB_FALSE) stackFrame.opers[-3] = stackFrame.opers[-1]; stackFrame.pop(2); break; case OP_AND: // (x AND false) == false // (x AND true) == x if (stackFrame.opers[-3] == GOB_TRUE) stackFrame.opers[-3] = stackFrame.opers[-1]; stackFrame.pop(2); break; case OP_LESS: stackFrame.opers[-3] = (cmpHelper(stackFrame) < 0) ? GOB_TRUE : GOB_FALSE; stackFrame.pop(2); break; case OP_LEQ: stackFrame.opers[-3] = (cmpHelper(stackFrame) <= 0) ? GOB_TRUE : GOB_FALSE; stackFrame.pop(2); break; case OP_GREATER: stackFrame.opers[-3] = (cmpHelper(stackFrame) > 0) ? GOB_TRUE : GOB_FALSE; stackFrame.pop(2); break; case OP_GEQ: stackFrame.opers[-3] = (cmpHelper(stackFrame) >= 0) ? GOB_TRUE : GOB_FALSE; stackFrame.pop(2); break; case OP_EQ: stackFrame.opers[-3] = (cmpHelper(stackFrame) == 0) ? GOB_TRUE : GOB_FALSE; stackFrame.pop(2); break; case OP_NEQ: stackFrame.opers[-3] = (cmpHelper(stackFrame) != 0) ? GOB_TRUE : GOB_FALSE; stackFrame.pop(2); break; default: return true; } return false; }
int16 Expression::parseExpr(byte stopToken, byte *type) { Stack stack; StackFrame stackFrame(stack); byte operation; int16 brackStart; uint32 varBase; while (true) { getVarBase(varBase); stackFrame.push(); operation = _vm->_game->_script->readByte(); if ((operation >= OP_ARRAY_INT8) && (operation <= OP_FUNC)) { loadValue(operation, varBase, stackFrame); if ((stackFrame.pos > 0) && ((stackFrame.opers[-1] == OP_NEG) || (stackFrame.opers[-1] == OP_NOT))) { stackFrame.pop(); if (*stackFrame.opers == OP_NEG) { *stackFrame.opers = OP_LOAD_IMM_INT16; stackFrame.values[0] = -stackFrame.values[1]; } else *stackFrame.opers = (stackFrame.opers[1] == GOB_FALSE) ? GOB_TRUE : GOB_FALSE; } if (stackFrame.pos <= 0) continue; simpleArithmetic1(stackFrame); continue; } // (op >= OP_ARRAY_INT8) && (op <= OP_FUNC) if ((operation == stopToken) || (operation == OP_OR) || (operation == OP_AND) || (operation == OP_END_EXPR)) { while (stackFrame.pos >= 2) { if ((stackFrame.opers[-2] == OP_BEGIN_EXPR) && ((operation == OP_END_EXPR) || (operation == stopToken))) { stackFrame.opers[-2] = stackFrame.opers[-1]; if ((stackFrame.opers[-2] == OP_LOAD_IMM_INT16) || (stackFrame.opers[-2] == OP_LOAD_IMM_STR)) stackFrame.values[-2] = stackFrame.values[-1]; stackFrame.pop(); simpleArithmetic2(stackFrame); if (operation != stopToken) break; } // if ((stackFrame.opers[-2] == OP_BEGIN_EXPR) && ...) for (brackStart = (stackFrame.pos - 2); (brackStart > 0) && (stack.opers[brackStart] < OP_OR) && (stack.opers[brackStart] != OP_BEGIN_EXPR); brackStart--) ; if ((stack.opers[brackStart] >= OP_OR) || (stack.opers[brackStart] == OP_BEGIN_EXPR)) brackStart++; if (complexArithmetic(stack, stackFrame, brackStart)) break; } // while (stackFrame.pos >= 2) if ((operation == OP_OR) || (operation == OP_AND)) { if (stackFrame.opers[-1] == OP_LOAD_IMM_INT16) { if (stackFrame.values[-1] != 0) stackFrame.opers[-1] = GOB_TRUE; else stackFrame.opers[-1] = GOB_FALSE; } if (((operation == OP_OR) && (stackFrame.opers[-1] == GOB_TRUE)) || ((operation == OP_AND) && (stackFrame.opers[-1] == GOB_FALSE))) { if ((stackFrame.pos > 1) && (stackFrame.opers[-2] == OP_BEGIN_EXPR)) { skipExpr(OP_END_EXPR); stackFrame.opers[-2] = stackFrame.opers[-1]; stackFrame.pop(2); } else { skipExpr(stopToken); } operation = _vm->_game->_script->peekByte(-1); if ((stackFrame.pos > 0) && (stackFrame.opers[-1] == OP_NOT)) { if (stackFrame.opers[0] == GOB_FALSE) stackFrame.opers[-1] = GOB_TRUE; else stackFrame.opers[-1] = GOB_FALSE; stackFrame.pop(); } } else stackFrame.opers[0] = operation; } else stackFrame.pop(); if (operation != stopToken) continue; getResult(stack.opers[0], stack.values[0], type); return 0; } // (operation == stopToken) || (operation == OP_OR) || (operation == OP_AND) || (operation == OP_END_EXPR) if ((operation < OP_NEG) || (operation > OP_NOT)) { if ((operation < OP_LESS) || (operation > OP_NEQ)) continue; if (stackFrame.pos > 2) { if (stackFrame.opers[-2] == OP_ADD) { if (stackFrame.opers[-3] == OP_LOAD_IMM_INT16) { stackFrame.values[-3] += stackFrame.values[-1]; } else if (stackFrame.opers[-3] == OP_LOAD_IMM_STR) { if ((char *)decodePtr(stackFrame.values[-3]) != _resultStr) { strcpy(_resultStr, (char *)decodePtr(stackFrame.values[-3])); stackFrame.values[-3] = encodePtr((byte *)_resultStr, kResStr); } strcat(_resultStr, (char *)decodePtr(stackFrame.values[-1])); } stackFrame.pop(2); } else if (stackFrame.opers[-2] == OP_SUB) { stackFrame.values[-3] -= stackFrame.values[-1]; stackFrame.pop(2); } else if (stackFrame.opers[-2] == OP_BITOR) { stackFrame.values[-3] |= stackFrame.values[-1]; stackFrame.pop(2); } } } *stackFrame.opers = operation; } }