FREESCAPE: refactored conditional handling to make it work with castle

This commit is contained in:
neuromancer 2023-04-30 14:04:28 +02:00
parent fc0b1480c1
commit c4a0d162fb
5 changed files with 55 additions and 44 deletions

View File

@ -281,6 +281,7 @@ public:
void executeCode(FCLInstructionVector &code, bool shot, bool collided, bool timer); void executeCode(FCLInstructionVector &code, bool shot, bool collided, bool timer);
// Instructions // Instructions
bool checkConditional(FCLInstruction &instruction, bool shot, bool collided, bool timer, bool activated);
bool checkIfGreaterOrEqual(FCLInstruction &instruction); bool checkIfGreaterOrEqual(FCLInstruction &instruction);
void executeIncrementVariable(FCLInstruction &instruction); void executeIncrementVariable(FCLInstruction &instruction);
void executeDecrementVariable(FCLInstruction &instruction); void executeDecrementVariable(FCLInstruction &instruction);

View File

@ -33,7 +33,7 @@ uint8 k8bitMaxVariable = 64;
uint8 k8bitMaxShield = 64; uint8 k8bitMaxShield = 64;
uint8 k8bitMaxEnergy = 64; uint8 k8bitMaxEnergy = 64;
Common::String detokenise8bitCondition(Common::Array<uint8> &tokenisedCondition, FCLInstructionVector &instructions, bool enableActivated) { Common::String detokenise8bitCondition(Common::Array<uint8> &tokenisedCondition, FCLInstructionVector &instructions, bool multipleConditionals) {
Common::String detokenisedStream; Common::String detokenisedStream;
Common::Array<uint8>::size_type bytePointer = 0; Common::Array<uint8>::size_type bytePointer = 0;
Common::Array<uint8>::size_type sizeOfTokenisedContent = tokenisedCondition.size(); Common::Array<uint8>::size_type sizeOfTokenisedContent = tokenisedCondition.size();
@ -56,28 +56,30 @@ Common::String detokenise8bitCondition(Common::Array<uint8> &tokenisedCondition,
if (sizeOfTokenisedContent > 0) if (sizeOfTokenisedContent > 0)
detokenisedStream += Common::String::format("CONDITION FLAG: %x\n", tokenisedCondition[0]); detokenisedStream += Common::String::format("CONDITION FLAG: %x\n", tokenisedCondition[0]);
Token::Type newConditional = Token::UNKNOWN; uint16 newConditional = 0;
Token::Type oldConditional = Token::UNKNOWN; uint16 oldConditional = 0;
while (bytePointer < sizeOfTokenisedContent) { while (bytePointer < sizeOfTokenisedContent) {
// get the conditional type of the next operation // get the conditional type of the next operation
uint8 conditionalByte = tokenisedCondition[bytePointer]; uint8 conditionalByte = tokenisedCondition[bytePointer] & 0xc0;
//detokenisedStream += Common::String::format("CONDITION FLAG: %x\n", conditionalByte);
newConditional = 0;
if ((conditionalByte & 0xc0) && enableActivated) { if (conditionalByte == 0x40)
newConditional = Token::ACTIVATEDQ; newConditional = kConditionalTimeout;
} else if (conditionalByte & 0x80) else if (conditionalByte == 0x80)
newConditional = Token::SHOTQ; newConditional = kConditionalShot;
else if (conditionalByte & 0x40) else if (conditionalByte == 0xc0)
newConditional = Token::TIMERQ; newConditional = kConditionalActivated;
else else
newConditional = Token::COLLIDEDQ; newConditional = kConditionalCollided;
// 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 (bytePointer == 0 || newConditional != oldConditional) { if (bytePointer == 0 || newConditional != oldConditional) {
oldConditional = newConditional; oldConditional = newConditional;
FCLInstruction branch; FCLInstruction branch;
branch = FCLInstruction(oldConditional); branch = FCLInstruction(Token::CONDITIONAL);
if (bytePointer > 0) { if (bytePointer > 0) {
detokenisedStream += "ENDIF\n"; detokenisedStream += "ENDIF\n";
@ -86,18 +88,23 @@ Common::String detokenise8bitCondition(Common::Array<uint8> &tokenisedCondition,
} }
branch.setBranches(conditionalInstructions, nullptr); branch.setBranches(conditionalInstructions, nullptr);
branch.setSource(oldConditional); // conditional flag
instructions.push_back(branch); instructions.push_back(branch);
if (oldConditional == Token::SHOTQ) detokenisedStream += "IF ";
detokenisedStream += "IF SHOT? THEN\n";
else if (oldConditional == Token::TIMERQ) if (oldConditional & kConditionalShot)
detokenisedStream += "IF TIMER? THEN\n"; detokenisedStream += "SHOT? ";
else if (oldConditional == Token::COLLIDEDQ) else if (oldConditional & kConditionalTimeout)
detokenisedStream += "IF COLLIDED? THEN\n"; detokenisedStream += "TIMER? ";
else if (oldConditional == Token::ACTIVATEDQ) else if (oldConditional & kConditionalCollided)
detokenisedStream += "IF ACTIVATED? THEN\n"; detokenisedStream += "COLLIDED? ";
else if (oldConditional & kConditionalActivated)
detokenisedStream += "ACTIVATED? ";
else else
error("Invalid conditional: %x", oldConditional); error("Invalid conditional: %x", oldConditional);
detokenisedStream += "THEN\n";
} }
// get the actual operation // get the actual operation

View File

@ -36,6 +36,13 @@ enum {
k8bitVariableEnergyDrillerJet = 57 k8bitVariableEnergyDrillerJet = 57
}; };
enum {
kConditionalShot = 1 << 0,
kConditionalTimeout = 1 << 1,
kConditionalCollided = 1 << 2,
kConditionalActivated = 1 << 3,
};
extern uint8 k8bitMaxVariable; extern uint8 k8bitMaxVariable;
extern uint8 k8bitMaxShield; extern uint8 k8bitMaxShield;
extern uint8 k8bitMaxEnergy; extern uint8 k8bitMaxEnergy;

View File

@ -148,31 +148,13 @@ void FreescapeEngine::executeCode(FCLInstructionVector &code, bool shot, bool co
debugC(1, kFreescapeDebugCode, "Executing NOP at ip: %d", ip); debugC(1, kFreescapeDebugCode, "Executing NOP at ip: %d", ip);
break; break;
case Token::ACTIVATEDQ: case Token::CONDITIONAL:
if (shot) // TODO: implement interaction if (checkConditional(instruction, shot, collided, timer, false)) // TODO: implement interaction
executeCode(*instruction._thenInstructions, shot, collided, 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;
case Token::COLLIDEDQ:
if (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, 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;
case Token::VARNOTEQ: case Token::VARNOTEQ:
if (executeEndIfNotEqual(instruction)) if (executeEndIfNotEqual(instruction))
ip = codeSize; ip = codeSize;
@ -355,6 +337,23 @@ bool FreescapeEngine::executeEndIfVisibilityIsEqual(FCLInstruction &instruction)
return (obj->isInvisible() == (value != 0)); return (obj->isInvisible() == (value != 0));
} }
bool FreescapeEngine::checkConditional(FCLInstruction &instruction, bool shot, bool collided, bool timer, bool activated) {
uint16 conditional = instruction._source;
bool result = false;
if (conditional & kConditionalShot)
result |= shot;
if (conditional & kConditionalTimeout)
result |= timer;
if (conditional & kConditionalCollided)
result |= collided;
if (conditional & kConditionalActivated)
result |= activated;
debugC(1, kFreescapeDebugCode, "Check if conditional %x is true: %d!", conditional, result);
return result;
}
bool FreescapeEngine::checkIfGreaterOrEqual(FCLInstruction &instruction) { bool FreescapeEngine::checkIfGreaterOrEqual(FCLInstruction &instruction) {
uint16 variable = instruction._source; uint16 variable = instruction._source;
uint16 value = instruction._destination; uint16 value = instruction._destination;

View File

@ -30,12 +30,11 @@ namespace Freescape {
struct Token { struct Token {
public: public:
enum Type { enum Type {
ACTIVATEDQ,
ADDVAR, ADDVAR,
AGAIN, AGAIN,
AND, AND,
ANDV, ANDV,
COLLIDEDQ, CONDITIONAL,
DELAY, DELAY,
DESTROY, DESTROY,
DESTROYEDQ, DESTROYEDQ,
@ -67,7 +66,6 @@ public:
SCREEN, SCREEN,
SOUND, SOUND,
SETVAR, SETVAR,
SHOTQ,
START, START,
STARTANIM, STARTANIM,
STOPANIM, STOPANIM,
@ -75,7 +73,6 @@ public:
SUBVAR, SUBVAR,
SYNCSND, SYNCSND,
THEN, THEN,
TIMERQ,
TOGVIS, TOGVIS,
TRIGANIM, TRIGANIM,
UPDATEI, UPDATEI,