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() {
// 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
}
}

View File

@ -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);

View File

@ -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);
}
}

View File

@ -39,9 +39,8 @@ Common::String detokenise8bitCondition(Common::Array<uint8> &tokenisedCondition,
Common::Array<uint8>::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<uint8> &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<uint8> &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);

View File

@ -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;

View File

@ -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) {