diff --git a/engines/freescape/freescape.cpp b/engines/freescape/freescape.cpp index 49381e47078..661a2db9dff 100644 --- a/engines/freescape/freescape.cpp +++ b/engines/freescape/freescape.cpp @@ -526,7 +526,7 @@ bool FreescapeEngine::onScreenControls(Common::Point mouse) { void FreescapeEngine::executeMovementConditions() { // Only execute "on collision" room/global conditions - executeLocalGlobalConditions(false, true); + executeLocalGlobalConditions(false, true, false); } void FreescapeEngine::updateTimeVariables() { @@ -537,7 +537,7 @@ void FreescapeEngine::updateTimeVariables() { _lastMinute = minutes; _gameStateVars[0x1e] += 1; _gameStateVars[0x1f] += 1; - executeLocalGlobalConditions(false, true); // Only execute "on collision" room/global conditions + executeLocalGlobalConditions(false, true, false); // Only execute "on collision" room/global conditions } } diff --git a/engines/freescape/freescape.h b/engines/freescape/freescape.h index 2219aaba3ec..ae3a2f8dc0b 100644 --- a/engines/freescape/freescape.h +++ b/engines/freescape/freescape.h @@ -276,8 +276,8 @@ public: Math::Vector3d _objExecutingCodeSize; virtual void executeMovementConditions(); void executeObjectConditions(GeometricObject *obj, bool shot, bool collided); - void executeLocalGlobalConditions(bool shot, bool collided); - void executeCode(FCLInstructionVector &code, bool shot, bool collided); + void executeLocalGlobalConditions(bool shot, bool collided, bool timer); + void executeCode(FCLInstructionVector &code, bool shot, bool collided, bool timer); // Instructions void executeIncrementVariable(FCLInstruction &instruction); @@ -531,7 +531,6 @@ public: int _lastTenSeconds; void updateTimeVariables() override; - void executeMovementConditions() override; void drawDOSUI(Graphics::Surface *surface) override; void drawFullscreenMessage(Common::String message); diff --git a/engines/freescape/games/dark/dark.cpp b/engines/freescape/games/dark/dark.cpp index d628c4d4ef5..1165f60243b 100644 --- a/engines/freescape/games/dark/dark.cpp +++ b/engines/freescape/games/dark/dark.cpp @@ -201,27 +201,20 @@ void DarkEngine::checkIfStillInArea() { FreescapeEngine::checkIfStillInArea(); } -void DarkEngine::executeMovementConditions() { - // Only execute "on collision" room/global conditions - if (_currentArea->getAreaFlags() == 1) - executeLocalGlobalConditions(false, true); -} - void DarkEngine::updateTimeVariables() { // This function only executes "on collision" room/global conditions int seconds, minutes, hours; getTimeFromCountdown(seconds, minutes, hours); if (_lastTenSeconds != seconds / 10) { _lastTenSeconds = seconds / 10; - if (_currentArea->getAreaFlags() == 0) - executeLocalGlobalConditions(false, true); + executeLocalGlobalConditions(false, false, true); } if (_lastMinute != minutes) { _lastMinute = minutes; _gameStateVars[0x1e] += 1; _gameStateVars[0x1f] += 1; - executeLocalGlobalConditions(false, true); + executeLocalGlobalConditions(false, true, false); } } diff --git a/engines/freescape/language/8bitDetokeniser.cpp b/engines/freescape/language/8bitDetokeniser.cpp index 06fe20c56ab..187c46f1b48 100644 --- a/engines/freescape/language/8bitDetokeniser.cpp +++ b/engines/freescape/language/8bitDetokeniser.cpp @@ -39,9 +39,8 @@ Common::String detokenise8bitCondition(Common::Array &tokenisedCondition, Common::Array::size_type sizeOfTokenisedContent = tokenisedCondition.size(); // on the 8bit platforms, all instructions have a conditional flag; - // we'll want to convert them into runs of "if shot? then" and "if collided? then", + // we'll want to convert them into runs of "if shot? then", "if collided? then" or "if timer? then", // and we'll want to start that from the top - uint8 conditionalIsShot = 0x1; FCLInstructionVector *conditionalInstructions = new FCLInstructionVector(); FCLInstruction currentInstruction; @@ -55,30 +54,42 @@ Common::String detokenise8bitCondition(Common::Array &tokenisedCondition, 0, 0, 0, 0, 0, 0, 2, 2, 1}; + detokenisedStream += Common::String::format("CONDITION FLAG: %x\n", tokenisedCondition[0]); + Token::Type newConditional; + Token::Type oldConditional; + while (bytePointer < sizeOfTokenisedContent) { // get the conditional type of the next operation - uint8 newConditionalIsShot = tokenisedCondition[bytePointer] & 0x80; + uint8 conditionalByte = tokenisedCondition[bytePointer]; + + if (conditionalByte & 0x80) + newConditional = Token::SHOTQ; + else if (conditionalByte & 0x40) + newConditional = Token::TIMERQ; + else + newConditional = Token::COLLIDEDQ; // if the conditional type has changed then end the old conditional, // if we were in one, and begin a new one - if (newConditionalIsShot != conditionalIsShot) { + if (bytePointer == 0 || newConditional != oldConditional) { + oldConditional = newConditional; FCLInstruction branch; - if (conditionalIsShot) - branch = FCLInstruction(Token::SHOTQ); - else - branch = FCLInstruction(Token::COLLIDEDQ); + branch = FCLInstruction(oldConditional); branch.setBranches(conditionalInstructions, nullptr); instructions.push_back(branch); - conditionalIsShot = newConditionalIsShot; - if (bytePointer) + if (bytePointer > 0) detokenisedStream += "ENDIF\n"; - if (conditionalIsShot) + if (oldConditional == Token::SHOTQ) detokenisedStream += "IF SHOT? THEN\n"; - else + else if (oldConditional == Token::TIMERQ) + detokenisedStream += "IF TIMER? THEN\n"; + else if (oldConditional == Token::COLLIDEDQ) detokenisedStream += "IF COLLIDED? THEN\n"; + else + error("Invalid conditional: %x", oldConditional); // Allocate the next vector of instructions conditionalInstructions = new FCLInstructionVector(); @@ -415,10 +426,7 @@ Common::String detokenise8bitCondition(Common::Array &tokenisedCondition, // conditionalInstructions->push_back(currentInstruction); FCLInstruction branch; - if (conditionalIsShot) - branch = FCLInstruction(Token::SHOTQ); - else - branch = FCLInstruction(Token::COLLIDEDQ); + branch = FCLInstruction(oldConditional); branch.setBranches(conditionalInstructions, nullptr); instructions.push_back(branch); diff --git a/engines/freescape/language/instruction.cpp b/engines/freescape/language/instruction.cpp index 2f68554d9cb..a528ec48275 100644 --- a/engines/freescape/language/instruction.cpp +++ b/engines/freescape/language/instruction.cpp @@ -72,11 +72,11 @@ void FreescapeEngine::executeObjectConditions(GeometricObject *obj, bool shot, b _firstSound = true; _objExecutingCodeSize = obj->getSize(); debugC(1, kFreescapeDebugCode, "Executing with collision flag: %s", obj->_conditionSource.c_str()); - executeCode(obj->_condition, shot, collided); + executeCode(obj->_condition, shot, collided, false); // TODO: check this last parameter } } -void FreescapeEngine::executeLocalGlobalConditions(bool shot, bool collided) { +void FreescapeEngine::executeLocalGlobalConditions(bool shot, bool collided, bool timer) { if (isCastle()) return; debugC(1, kFreescapeDebugCode, "Executing room conditions"); @@ -85,17 +85,17 @@ void FreescapeEngine::executeLocalGlobalConditions(bool shot, bool collided) { for (uint i = 0; i < conditions.size(); i++) { debugC(1, kFreescapeDebugCode, "%s", conditionSources[i].c_str()); - executeCode(conditions[i], shot, collided); + executeCode(conditions[i], shot, collided, timer); } debugC(1, kFreescapeDebugCode, "Executing global conditions (%d)", _conditions.size()); for (uint i = 0; i < _conditions.size(); i++) { debugC(1, kFreescapeDebugCode, "%s", _conditionSources[i].c_str()); - executeCode(_conditions[i], shot, collided); + executeCode(_conditions[i], shot, collided, timer); } } -void FreescapeEngine::executeCode(FCLInstructionVector &code, bool shot, bool collided) { +void FreescapeEngine::executeCode(FCLInstructionVector &code, bool shot, bool collided, bool timer) { assert(!(shot && collided)); int ip = 0; int codeSize = code.size(); @@ -109,13 +109,19 @@ void FreescapeEngine::executeCode(FCLInstructionVector &code, bool shot, bool co break; case Token::COLLIDEDQ: if (collided) - executeCode(*instruction._thenInstructions, shot, collided); + executeCode(*instruction._thenInstructions, shot, collided, timer); // else branch is always empty assert(instruction._elseInstructions == nullptr); break; case Token::SHOTQ: if (shot) - executeCode(*instruction._thenInstructions, shot, collided); + executeCode(*instruction._thenInstructions, shot, collided, timer); + // else branch is always empty + assert(instruction._elseInstructions == nullptr); + break; + case Token::TIMERQ: + if (timer) + executeCode(*instruction._thenInstructions, shot, collided, timer); // else branch is always empty assert(instruction._elseInstructions == nullptr); break; diff --git a/engines/freescape/movement.cpp b/engines/freescape/movement.cpp index c9055e80248..f914780359e 100644 --- a/engines/freescape/movement.cpp +++ b/engines/freescape/movement.cpp @@ -92,7 +92,7 @@ void FreescapeEngine::shoot() { executeObjectConditions(gobj, true, false); } - executeLocalGlobalConditions(true, false); // Only execute "on shot" room/global conditions + executeLocalGlobalConditions(true, false, false); // Only execute "on shot" room/global conditions } void FreescapeEngine::changePlayerHeight(int index) {