FREESCAPE: implemented timed condition executions from dark (and other games)

This commit is contained in:
neuromancer 2023-03-25 09:11:21 +01:00
parent b13065da36
commit 77728fcf73
6 changed files with 44 additions and 38 deletions

View File

@ -526,7 +526,7 @@ bool FreescapeEngine::onScreenControls(Common::Point mouse) {
void FreescapeEngine::executeMovementConditions() { void FreescapeEngine::executeMovementConditions() {
// Only execute "on collision" room/global conditions // Only execute "on collision" room/global conditions
executeLocalGlobalConditions(false, true); executeLocalGlobalConditions(false, true, false);
} }
void FreescapeEngine::updateTimeVariables() { void FreescapeEngine::updateTimeVariables() {
@ -537,7 +537,7 @@ void FreescapeEngine::updateTimeVariables() {
_lastMinute = minutes; _lastMinute = minutes;
_gameStateVars[0x1e] += 1; _gameStateVars[0x1e] += 1;
_gameStateVars[0x1f] += 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
} }
} }

View File

@ -276,8 +276,8 @@ public:
Math::Vector3d _objExecutingCodeSize; Math::Vector3d _objExecutingCodeSize;
virtual void executeMovementConditions(); virtual void executeMovementConditions();
void executeObjectConditions(GeometricObject *obj, bool shot, bool collided); void executeObjectConditions(GeometricObject *obj, bool shot, bool collided);
void executeLocalGlobalConditions(bool shot, bool collided); void executeLocalGlobalConditions(bool shot, bool collided, bool timer);
void executeCode(FCLInstructionVector &code, bool shot, bool collided); void executeCode(FCLInstructionVector &code, bool shot, bool collided, bool timer);
// Instructions // Instructions
void executeIncrementVariable(FCLInstruction &instruction); void executeIncrementVariable(FCLInstruction &instruction);
@ -531,7 +531,6 @@ public:
int _lastTenSeconds; int _lastTenSeconds;
void updateTimeVariables() override; void updateTimeVariables() override;
void executeMovementConditions() override;
void drawDOSUI(Graphics::Surface *surface) override; void drawDOSUI(Graphics::Surface *surface) override;
void drawFullscreenMessage(Common::String message); void drawFullscreenMessage(Common::String message);

View File

@ -201,27 +201,20 @@ void DarkEngine::checkIfStillInArea() {
FreescapeEngine::checkIfStillInArea(); FreescapeEngine::checkIfStillInArea();
} }
void DarkEngine::executeMovementConditions() {
// Only execute "on collision" room/global conditions
if (_currentArea->getAreaFlags() == 1)
executeLocalGlobalConditions(false, true);
}
void DarkEngine::updateTimeVariables() { void DarkEngine::updateTimeVariables() {
// This function only executes "on collision" room/global conditions // This function only executes "on collision" room/global conditions
int seconds, minutes, hours; int seconds, minutes, hours;
getTimeFromCountdown(seconds, minutes, hours); getTimeFromCountdown(seconds, minutes, hours);
if (_lastTenSeconds != seconds / 10) { if (_lastTenSeconds != seconds / 10) {
_lastTenSeconds = seconds / 10; _lastTenSeconds = seconds / 10;
if (_currentArea->getAreaFlags() == 0) executeLocalGlobalConditions(false, false, true);
executeLocalGlobalConditions(false, true);
} }
if (_lastMinute != minutes) { if (_lastMinute != minutes) {
_lastMinute = minutes; _lastMinute = minutes;
_gameStateVars[0x1e] += 1; _gameStateVars[0x1e] += 1;
_gameStateVars[0x1f] += 1; _gameStateVars[0x1f] += 1;
executeLocalGlobalConditions(false, true); executeLocalGlobalConditions(false, true, false);
} }
} }

View File

@ -39,9 +39,8 @@ Common::String detokenise8bitCondition(Common::Array<uint8> &tokenisedCondition,
Common::Array<uint8>::size_type sizeOfTokenisedContent = tokenisedCondition.size(); Common::Array<uint8>::size_type sizeOfTokenisedContent = tokenisedCondition.size();
// on the 8bit platforms, all instructions have a conditional flag; // 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 // and we'll want to start that from the top
uint8 conditionalIsShot = 0x1;
FCLInstructionVector *conditionalInstructions = new FCLInstructionVector(); FCLInstructionVector *conditionalInstructions = new FCLInstructionVector();
FCLInstruction currentInstruction; FCLInstruction currentInstruction;
@ -55,30 +54,42 @@ Common::String detokenise8bitCondition(Common::Array<uint8> &tokenisedCondition,
0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0, 2, 2,
1}; 1};
detokenisedStream += Common::String::format("CONDITION FLAG: %x\n", tokenisedCondition[0]);
Token::Type newConditional;
Token::Type oldConditional;
while (bytePointer < sizeOfTokenisedContent) { while (bytePointer < sizeOfTokenisedContent) {
// get the conditional type of the next operation // 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 the conditional type has changed then end the old conditional,
// if we were in one, and begin a new one // if we were in one, and begin a new one
if (newConditionalIsShot != conditionalIsShot) { if (bytePointer == 0 || newConditional != oldConditional) {
oldConditional = newConditional;
FCLInstruction branch; FCLInstruction branch;
if (conditionalIsShot) branch = FCLInstruction(oldConditional);
branch = FCLInstruction(Token::SHOTQ);
else
branch = FCLInstruction(Token::COLLIDEDQ);
branch.setBranches(conditionalInstructions, nullptr); branch.setBranches(conditionalInstructions, nullptr);
instructions.push_back(branch); instructions.push_back(branch);
conditionalIsShot = newConditionalIsShot; if (bytePointer > 0)
if (bytePointer)
detokenisedStream += "ENDIF\n"; detokenisedStream += "ENDIF\n";
if (conditionalIsShot) if (oldConditional == Token::SHOTQ)
detokenisedStream += "IF SHOT? THEN\n"; 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"; detokenisedStream += "IF COLLIDED? THEN\n";
else
error("Invalid conditional: %x", oldConditional);
// Allocate the next vector of instructions // Allocate the next vector of instructions
conditionalInstructions = new FCLInstructionVector(); conditionalInstructions = new FCLInstructionVector();
@ -415,10 +426,7 @@ Common::String detokenise8bitCondition(Common::Array<uint8> &tokenisedCondition,
// conditionalInstructions->push_back(currentInstruction); // conditionalInstructions->push_back(currentInstruction);
FCLInstruction branch; FCLInstruction branch;
if (conditionalIsShot) branch = FCLInstruction(oldConditional);
branch = FCLInstruction(Token::SHOTQ);
else
branch = FCLInstruction(Token::COLLIDEDQ);
branch.setBranches(conditionalInstructions, nullptr); branch.setBranches(conditionalInstructions, nullptr);
instructions.push_back(branch); instructions.push_back(branch);

View File

@ -72,11 +72,11 @@ void FreescapeEngine::executeObjectConditions(GeometricObject *obj, bool shot, b
_firstSound = true; _firstSound = true;
_objExecutingCodeSize = obj->getSize(); _objExecutingCodeSize = obj->getSize();
debugC(1, kFreescapeDebugCode, "Executing with collision flag: %s", obj->_conditionSource.c_str()); 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()) if (isCastle())
return; return;
debugC(1, kFreescapeDebugCode, "Executing room conditions"); 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++) { for (uint i = 0; i < conditions.size(); i++) {
debugC(1, kFreescapeDebugCode, "%s", conditionSources[i].c_str()); 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()); debugC(1, kFreescapeDebugCode, "Executing global conditions (%d)", _conditions.size());
for (uint i = 0; i < _conditions.size(); i++) { for (uint i = 0; i < _conditions.size(); i++) {
debugC(1, kFreescapeDebugCode, "%s", _conditionSources[i].c_str()); 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)); assert(!(shot && collided));
int ip = 0; int ip = 0;
int codeSize = code.size(); int codeSize = code.size();
@ -109,13 +109,19 @@ void FreescapeEngine::executeCode(FCLInstructionVector &code, bool shot, bool co
break; break;
case Token::COLLIDEDQ: case Token::COLLIDEDQ:
if (collided) if (collided)
executeCode(*instruction._thenInstructions, shot, collided); executeCode(*instruction._thenInstructions, shot, collided, timer);
// else branch is always empty // else branch is always empty
assert(instruction._elseInstructions == nullptr); assert(instruction._elseInstructions == nullptr);
break; break;
case Token::SHOTQ: case Token::SHOTQ:
if (shot) 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 // else branch is always empty
assert(instruction._elseInstructions == nullptr); assert(instruction._elseInstructions == nullptr);
break; break;

View File

@ -92,7 +92,7 @@ void FreescapeEngine::shoot() {
executeObjectConditions(gobj, true, false); 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) { void FreescapeEngine::changePlayerHeight(int index) {