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);
// Instructions
bool checkConditional(FCLInstruction &instruction, bool shot, bool collided, bool timer, bool activated);
bool checkIfGreaterOrEqual(FCLInstruction &instruction);
void executeIncrementVariable(FCLInstruction &instruction);
void executeDecrementVariable(FCLInstruction &instruction);

View File

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

View File

@ -36,6 +36,13 @@ enum {
k8bitVariableEnergyDrillerJet = 57
};
enum {
kConditionalShot = 1 << 0,
kConditionalTimeout = 1 << 1,
kConditionalCollided = 1 << 2,
kConditionalActivated = 1 << 3,
};
extern uint8 k8bitMaxVariable;
extern uint8 k8bitMaxShield;
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);
break;
case Token::ACTIVATEDQ:
if (shot) // TODO: implement interaction
case Token::CONDITIONAL:
if (checkConditional(instruction, shot, collided, timer, false)) // TODO: implement interaction
executeCode(*instruction._thenInstructions, shot, collided, timer);
// else branch is always empty
assert(instruction._elseInstructions == nullptr);
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:
if (executeEndIfNotEqual(instruction))
ip = codeSize;
@ -355,6 +337,23 @@ bool FreescapeEngine::executeEndIfVisibilityIsEqual(FCLInstruction &instruction)
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) {
uint16 variable = instruction._source;
uint16 value = instruction._destination;

View File

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