[Scummvm-git-logs] scummvm master -> 6640aa2274fc0e76d3af181e8bb648eea5cf8ed4
dreammaster
paulfgilbert at gmail.com
Fri Oct 16 03:40:10 UTC 2020
This automated email contains information about 2 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .
Summary:
0da4dcde56 GLK: COMPREHEND: Split opcode implementation into their own classes
6640aa2274 GLK: COMPREHEND: Starting to properly add v2 opcodes
Commit: 0da4dcde566a49e01f58b8d16b6a7c1f6ee31981
https://github.com/scummvm/scummvm/commit/0da4dcde566a49e01f58b8d16b6a7c1f6ee31981
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2020-10-15T20:39:32-07:00
Commit Message:
GLK: COMPREHEND: Split opcode implementation into their own classes
Version 2 of the engine already has at least one opcode where the
implementation slightly changed and I had to have a version check.
To make things cleaner, there are new v1 and v2 game classes that
derive from ComprehendGame, and the opcode map setup has also been
moved into them.
Currently, the V1 engine has all the opcodes implementation. I need
to start reviewing the opcode calls in v2 again, and shift stuff
that is actually unchanged to the base class shared by both 1 & 2
Changed paths:
A engines/glk/comprehend/game_opcodes.cpp
A engines/glk/comprehend/game_opcodes.h
R engines/glk/comprehend/opcode_map.cpp
R engines/glk/comprehend/opcode_map.h
engines/glk/comprehend/debugger_dumper.cpp
engines/glk/comprehend/game.cpp
engines/glk/comprehend/game.h
engines/glk/comprehend/game_cc.cpp
engines/glk/comprehend/game_cc.h
engines/glk/comprehend/game_oo.cpp
engines/glk/comprehend/game_oo.h
engines/glk/comprehend/game_tm.cpp
engines/glk/comprehend/game_tm.h
engines/glk/comprehend/game_tr.cpp
engines/glk/comprehend/game_tr.h
engines/glk/module.mk
diff --git a/engines/glk/comprehend/debugger_dumper.cpp b/engines/glk/comprehend/debugger_dumper.cpp
index bd8d6ea871..53e66182af 100644
--- a/engines/glk/comprehend/debugger_dumper.cpp
+++ b/engines/glk/comprehend/debugger_dumper.cpp
@@ -123,9 +123,6 @@ Common::String DebuggerDumper::dumpInstruction(ComprehendGame *game,
func_state->_orCount, func_state->_and,
func_state->_testResult, func_state->_elseResult);
- opcode_map = game->_opcodeMap;
- opcode = opcode_map[instr->_opcode];
-
line += Common::String::format(" [%.2x] ", instr->_opcode);
if (_opcodes.contains(opcode))
line += _opcodes[opcode];
diff --git a/engines/glk/comprehend/game.cpp b/engines/glk/comprehend/game.cpp
index 7c1238c1b4..d55a257443 100644
--- a/engines/glk/comprehend/game.cpp
+++ b/engines/glk/comprehend/game.cpp
@@ -28,35 +28,10 @@
#include "glk/comprehend/dictionary.h"
#include "glk/comprehend/draw_surface.h"
#include "glk/comprehend/game_data.h"
-#include "glk/comprehend/opcode_map.h"
namespace Glk {
namespace Comprehend {
-struct Sentence {
- Word _words[4];
- size_t _nr_words;
- byte _formattedWords[6];
- byte _specialOpcodeVal2;
-
- Sentence() {
- clear();
- }
-
- bool empty() const {
- return _nr_words == 0;
- }
-
- void clear();
-
- /**
- * Splits up the array of _words into a _formattedWords
- * array, placing the words in appropriate noun, verb, etc.
- * positions appropriately
- */
- void format();
-};
-
void Sentence::clear() {
for (uint idx = 0; idx < 4; ++idx)
_words[idx].clear();
@@ -487,24 +462,6 @@ void ComprehendGame::move_to(uint8 room) {
UPDATE_ITEM_LIST);
}
-void ComprehendGame::func_set_test_result(FunctionState *func_state, bool value) {
- if (func_state->_orCount == 0) {
- /* And */
- if (func_state->_and) {
- if (!value)
- func_state->_testResult = false;
- } else {
- func_state->_testResult = value;
- func_state->_and = true;
- }
-
- } else {
- /* Or */
- if (value)
- func_state->_testResult = value;
- }
-}
-
size_t ComprehendGame::num_objects_in_room(int room) {
size_t count = 0, i;
@@ -548,14 +505,8 @@ void ComprehendGame::move_object(Item *item, int new_room) {
void ComprehendGame::eval_instruction(FunctionState *func_state,
const Function &func, uint functionOffset, const Sentence *sentence) {
- const byte *opcode_map = _opcodeMap;
- byte verb = sentence ? sentence->_formattedWords[0] : 0;
- byte noun = sentence ? sentence->_formattedWords[2] : 0;
- Room *room;
- Item *item;
- uint16 index;
- bool test;
- uint i, count;
+ Room *room = nullptr;
+ Item *item = nullptr;
const Instruction *instr = &func[functionOffset];
room = get_room(_currentRoom);
@@ -605,518 +556,7 @@ void ComprehendGame::eval_instruction(FunctionState *func_state,
}
}
- switch (opcode_map[instr->_opcode]) {
- case OPCODE_VAR_ADD:
- _variables[instr->_operand[0]] +=
- _variables[instr->_operand[1]];
- break;
-
- case OPCODE_VAR_SUB:
- _variables[instr->_operand[0]] -=
- _variables[instr->_operand[1]];
- break;
-
- case OPCODE_VAR_INC:
- _variables[instr->_operand[0]]++;
- break;
-
- case OPCODE_VAR_DEC:
- _variables[instr->_operand[0]]--;
- break;
-
- case OPCODE_VAR_EQ1:
- func_set_test_result(func_state,
- _variables[0] ==
- _variables[instr->_operand[0]]);
- break;
-
- case OPCODE_VAR_EQ2:
- func_set_test_result(func_state,
- _variables[instr->_operand[0]] ==
- _variables[instr->_operand[1]]);
- break;
-
- case OPCODE_VAR_GT1:
- func_set_test_result(func_state,
- _variables[0] >
- _variables[instr->_operand[0]]);
- break;
-
- case OPCODE_VAR_GT2:
- func_set_test_result(func_state,
- _variables[instr->_operand[0]] >
- _variables[instr->_operand[1]]);
- break;
-
- case OPCODE_VAR_GTE1:
- func_set_test_result(func_state,
- _variables[0] >=
- _variables[instr->_operand[0]]);
- break;
-
- case OPCODE_VAR_GTE2:
- func_set_test_result(func_state,
- _variables[instr->_operand[0]] >=
- _variables[instr->_operand[1]]);
- break;
-
- case OPCODE_TURN_TICK:
- _variables[VAR_TURN_COUNT]++;
- break;
-
- case OPCODE_PRINT:
- console_println(instrStringLookup(
- instr->_operand[0], instr->_operand[1])
- .c_str());
- break;
-
- case OPCODE_TEST_NOT_ROOM_FLAG:
- func_set_test_result(func_state,
- !(room->_flags & instr->_operand[0]));
- break;
-
- case OPCODE_TEST_ROOM_FLAG:
- func_set_test_result(func_state,
- room->_flags & instr->_operand[0]);
- break;
-
- case OPCODE_NOT_IN_ROOM:
- func_set_test_result(func_state,
- _currentRoom != instr->_operand[0]);
- break;
-
- case OPCODE_IN_ROOM:
- func_set_test_result(func_state,
- _currentRoom == instr->_operand[0]);
- break;
-
- case OPCODE_MOVE_TO_ROOM:
- if (instr->_operand[0] != 0xff)
- move_to(instr->_operand[0]);
- break;
-
- case OPCODE_MOVE_DEFAULT:
- // Move in the direction dictated by the current verb
- if (verb - 1 >= NR_DIRECTIONS)
- error("Bad verb %d in move", verb);
-
- if (room->_direction[verb - 1])
- move_to(room->_direction[verb - 1]);
- else
- console_println(stringLookup(STRING_CANT_GO).c_str());
- break;
-
- case OPCODE_MOVE_DIRECTION:
- if (room->_direction[instr->_operand[0] - 1])
- move_to(room->_direction[instr->_operand[0] - 1]);
- else
- console_println(stringLookup(STRING_CANT_GO).c_str());
- break;
-
- case OPCODE_ELSE:
- func_state->_testResult = func_state->_elseResult;
- break;
-
- case OPCODE_MOVE_OBJECT_TO_CURRENT_ROOM:
- item = get_item(instr->_operand[0] - 1);
- move_object(item, _currentRoom);
- break;
-
- case OPCODE_OBJECT_IN_ROOM:
- item = get_item(instr->_operand[0] - 1);
- func_set_test_result(func_state,
- item->_room == instr->_operand[1]);
- break;
-
- case OPCODE_OBJECT_NOT_IN_ROOM:
- item = get_item(instr->_operand[0] - 1);
- func_set_test_result(func_state, !item || item->_room != _currentRoom);
- break;
-
- case OPCODE_OBJECT_CAN_TAKE:
- item = get_item(instr->_operand[0] - 1);
- func_set_test_result(func_state, item->_flags & ITEMF_CAN_TAKE);
- break;
-
- case OPCODE_CURRENT_OBJECT_NOT_IN_ROOM:
- item = get_item_by_noun(noun);
- func_set_test_result(func_state, !item || item->_room != _currentRoom);
- break;
-
- case OPCODE_MOVE_OBJECT_TO_ROOM:
- item = get_item(instr->_operand[0] - 1);
- move_object(item, instr->_operand[1]);
- break;
-
- case OPCODE_INVENTORY_FULL:
- item = get_item_by_noun(noun);
-
- if (_comprehendVersion == 1) {
- func_set_test_result(func_state,
- _variables[VAR_INVENTORY_WEIGHT] +
- (item->_flags & ITEMF_WEIGHT_MASK) >
- _variables[VAR_INVENTORY_LIMIT]);
- } else {
- weighInventory();
- func_set_test_result(func_state,
- _totalInventoryWeight + (item->_flags & ITEMF_WEIGHT_MASK) <
- _variables[VAR_INVENTORY_LIMIT]);
- }
- break;
-
- case OPCODE_DESCRIBE_CURRENT_OBJECT:
- /*
- * This opcode is only used in version 2
- * FIXME - unsure what the single operand is for.
- */
- item = get_item_by_noun(noun);
- g_comprehend->print("%s\n", stringLookup(item->_longString).c_str());
- break;
-
- case OPCODE_CURRENT_OBJECT_IN_ROOM:
- /* FIXME - use common code for these two ops */
- test = false;
-
- if (noun) {
- for (i = 0; i < _items.size(); i++) {
- Item *itemP = &_items[i];
-
- if (itemP->_word == noun && itemP->_room == instr->_operand[0]) {
- test = true;
- break;
- }
- }
- }
-
- func_set_test_result(func_state, test);
- break;
-
- case OPCODE_CURRENT_OBJECT_PRESENT:
- item = get_item_by_noun(noun);
- if (item)
- func_set_test_result(func_state,
- item->_room == _currentRoom);
- else
- func_set_test_result(func_state, false);
- break;
-
- case OPCODE_HAVE_OBJECT:
- item = get_item(instr->_operand[0] - 1);
- func_set_test_result(func_state,
- item->_room == ROOM_INVENTORY);
- break;
-
- case OPCODE_NOT_HAVE_CURRENT_OBJECT:
- item = get_item_by_noun(noun);
- func_set_test_result(func_state,
- !item || item->_room != ROOM_INVENTORY);
- break;
-
- case OPCODE_HAVE_CURRENT_OBJECT:
- item = get_item_by_noun(noun);
- func_set_test_result(func_state,
- item->_room == ROOM_INVENTORY);
- break;
-
- case OPCODE_NOT_HAVE_OBJECT:
- item = get_item(instr->_operand[0] - 1);
- func_set_test_result(func_state,
- item->_room != ROOM_INVENTORY);
- break;
-
- case OPCODE_CURRENT_OBJECT_TAKEABLE:
- item = get_item_by_noun(noun);
- if (!item)
- func_set_test_result(func_state, false);
- else
- func_set_test_result(func_state,
- (item->_flags & ITEMF_CAN_TAKE));
- break;
-
- case OPCODE_CURRENT_OBJECT_NOT_TAKEABLE:
- item = get_item_by_noun(noun);
- if (!item)
- func_set_test_result(func_state, true);
- else
- func_set_test_result(func_state,
- !(item->_flags & ITEMF_CAN_TAKE));
- break;
-
- case OPCODE_OBJECT_IS_NOWHERE:
- item = get_item(instr->_operand[0] - 1);
- func_set_test_result(func_state, item->_room == ROOM_NOWHERE);
- break;
-
- case OPCODE_CURRENT_OBJECT_IS_NOWHERE:
- item = get_item_by_noun(noun);
- func_set_test_result(func_state, item && item->_room == ROOM_NOWHERE);
- break;
-
- case OPCODE_OBJECT_IS_NOT_NOWHERE:
- item = get_item(instr->_operand[0] - 1);
- func_set_test_result(func_state, item->_room != ROOM_NOWHERE);
- break;
-
- case OPCODE_CURRENT_OBJECT_NOT_PRESENT:
- item = get_item_by_noun(noun);
- func_set_test_result(func_state, !isItemPresent(item));
- break;
-
- case OPCODE_OBJECT_NOT_PRESENT:
- item = get_item(instr->_operand[0] - 1);
- func_set_test_result(func_state, !isItemPresent(item));
- break;
-
- case OPCODE_OBJECT_PRESENT:
- item = get_item(instr->_operand[0] - 1);
- func_set_test_result(func_state,
- item->_room == _currentRoom);
- break;
-
- case OPCODE_CURRENT_OBJECT_NOT_VALID:
- func_set_test_result(func_state, !noun);
- break;
-
- case OPCODE_CURRENT_IS_OBJECT:
- func_set_test_result(func_state,
- get_item_by_noun(noun) != NULL);
- break;
-
- case OPCODE_CURRENT_NOT_OBJECT:
- func_set_test_result(func_state,
- get_item_by_noun(noun) == NULL);
- break;
-
- case OPCODE_REMOVE_OBJECT:
- item = get_item(instr->_operand[0] - 1);
- move_object(item, ROOM_NOWHERE);
- break;
-
- case OPCODE_REMOVE_CURRENT_OBJECT:
- item = get_item_by_noun(noun);
- move_object(item, ROOM_NOWHERE);
- break;
-
- case OPCODE_INVENTORY:
- count = num_objects_in_room(ROOM_INVENTORY);
- if (count == 0) {
- console_println(stringLookup(STRING_INVENTORY_EMPTY).c_str());
- break;
- }
-
- console_println(stringLookup(STRING_INVENTORY).c_str());
- for (i = 0; i < _items.size(); i++) {
- item = &_items[i];
- if (item->_room == ROOM_INVENTORY)
- g_comprehend->print("%s\n",
- stringLookup(item->_stringDesc).c_str());
- }
- break;
-
- case OPCODE_INVENTORY_ROOM:
- count = num_objects_in_room(instr->_operand[0]);
- if (count == 0) {
- console_println(stringLookup(instr->_operand[1] + 1).c_str());
- break;
- }
-
- console_println(stringLookup(instr->_operand[1]).c_str());
- for (i = 0; i < _items.size(); i++) {
- item = &_items[i];
- if (item->_room == instr->_operand[0])
- g_comprehend->print("%s\n",
- stringLookup(item->_stringDesc).c_str());
- }
- break;
-
- case OPCODE_MOVE_CURRENT_OBJECT_TO_ROOM:
- item = get_item_by_noun(noun);
- if (!item)
- error("Bad current object\n");
-
- move_object(item, instr->_operand[0]);
- break;
-
- case OPCODE_DROP_OBJECT:
- item = get_item(instr->_operand[0] - 1);
- move_object(item, _currentRoom);
- break;
-
- case OPCODE_DROP_CURRENT_OBJECT:
- item = get_item_by_noun(noun);
- if (!item)
- error("Attempt to take object failed\n");
-
- move_object(item, _currentRoom);
- break;
-
- case OPCODE_TAKE_CURRENT_OBJECT:
- item = get_item_by_noun(noun);
- if (!item)
- error("Attempt to take object failed\n");
-
- move_object(item, ROOM_INVENTORY);
- break;
-
- case OPCODE_TAKE_OBJECT:
- item = get_item(instr->_operand[0] - 1);
- move_object(item, ROOM_INVENTORY);
- break;
-
- case OPCODE_TEST_FLAG:
- func_set_test_result(func_state,
- _flags[instr->_operand[0]]);
- break;
-
- case OPCODE_TEST_NOT_FLAG:
- func_set_test_result(func_state,
- !_flags[instr->_operand[0]]);
- break;
-
- case OPCODE_CLEAR_FLAG:
- _flags[instr->_operand[0]] = false;
- break;
-
- case OPCODE_SET_FLAG:
- _flags[instr->_operand[0]] = true;
- break;
-
- case OPCODE_OR:
- if (func_state->_orCount) {
- func_state->_orCount += 2;
- } else {
- func_state->_testResult = false;
- func_state->_orCount += 3;
- }
- break;
-
- case OPCODE_SET_OBJECT_DESCRIPTION:
- item = get_item(instr->_operand[0] - 1);
- item->_stringDesc = (instr->_operand[2] << 8) | instr->_operand[1];
- break;
-
- case OPCODE_SET_OBJECT_LONG_DESCRIPTION:
- item = get_item(instr->_operand[0] - 1);
- item->_longString = (instr->_operand[2] << 8) | instr->_operand[1];
- break;
-
- case OPCODE_SET_ROOM_DESCRIPTION:
- room = get_room(instr->_operand[0]);
- switch (instr->_operand[2]) {
- case 0x80:
- room->_stringDesc = instr->_operand[1];
- break;
- case 0x81:
- room->_stringDesc = instr->_operand[1] + 0x100;
- break;
- case 0x82:
- room->_stringDesc = instr->_operand[1] + 0x200;
- break;
- default:
- error("Bad string desc %.2x:%.2x\n",
- instr->_operand[1], instr->_operand[2]);
- break;
- }
- break;
-
- case OPCODE_SET_OBJECT_GRAPHIC:
- item = get_item(instr->_operand[0] - 1);
- item->_graphic = instr->_operand[1];
- if (item->_room == _currentRoom)
- _updateFlags |= UPDATE_GRAPHICS;
- break;
-
- case OPCODE_SET_ROOM_GRAPHIC:
- room = get_room(instr->_operand[0]);
- room->_graphic = instr->_operand[1];
- if (instr->_operand[0] == _currentRoom)
- _updateFlags |= UPDATE_GRAPHICS;
- break;
-
- case OPCODE_CALL_FUNC:
- index = instr->_operand[0];
- if (instr->_operand[1] == 0x81)
- index += 256;
- if (index >= _functions.size())
- error("Bad function %.4x >= %.4x\n",
- index, _functions.size());
-
- eval_function(index, sentence);
- break;
-
- case OPCODE_TEST_FALSE:
- // The original had two opcodes mapped to the same code that does
- // a test, but ignores the result, and is always false
- func_set_test_result(func_state, false);
- break;
-
- case OPCODE_SAVE_ACTION:
- /*
- * FIXME - This saves the current verb and allows the next
- * command to use just the noun. This is used to allow
- * responses to ask the player what they meant, e.g:
- *
- * > drop
- * I don't understand what you want to drop.
- * > gun
- * Okay.
- */
- break;
-
- case OPCODE_SET_STRING_REPLACEMENT:
- _currentReplaceWord = instr->_operand[0] - 1;
- break;
-
- case OPCODE_SET_CURRENT_NOUN_STRING_REPLACEMENT:
- #if 1
- error("TODO: OPCODE_SET_CURRENT_NOUN_STRING_REPLACEMENT");
- #else
- /*
- * FIXME - Not sure what the operand is for,
- * maybe capitalisation?
- */
- if (noun && (noun->_type & WORD_TYPE_NOUN_PLURAL))
- _currentReplaceWord = 3;
- else if (noun && (noun->_type & WORD_TYPE_FEMALE))
- _currentReplaceWord = 0;
- else if (noun && (noun->_type & WORD_TYPE_MALE))
- _currentReplaceWord = 1;
- else
- _currentReplaceWord = 2;
- #endif
- break;
-
- case OPCODE_DRAW_ROOM:
- g_comprehend->drawLocationPicture(instr->_operand[0] - 1);
- break;
-
- case OPCODE_DRAW_OBJECT:
- g_comprehend->drawItemPicture(instr->_operand[0] - 1);
- break;
-
- case OPCODE_WAIT_KEY:
- console_get_key();
- break;
-
- case OPCODE_SPECIAL:
- // Game specific opcode
- handleSpecialOpcode(instr->_operand[0]);
- break;
-
- case OPCODE_MOVE_DIR:
- doMovementVerb(instr->_operand[0]);
- break;
-
- default:
- if (instr->_opcode & 0x80) {
- warning("Unhandled command opcode %.2x", instr->_opcode);
- } else {
- warning("Unhandled test opcode %.2x - returning false",
- instr->_opcode);
- func_set_test_result(func_state, false);
- }
- break;
- }
+ execute_opcode(instr, sentence, func_state, room, item);
}
void ComprehendGame::eval_function(uint functionNum, const Sentence *sentence) {
@@ -1432,13 +872,6 @@ void ComprehendGame::doMovementVerb(uint verbNum) {
console_println(_strings[0].c_str());
}
-bool ComprehendGame::isItemPresent(Item *item) const {
- return item && (
- item->_room == _currentRoom || item->_room == ROOM_INVENTORY
- || item->_room == ROOM_CONTAINER
- );
-}
-
void ComprehendGame::weighInventory() {
_totalInventoryWeight = 0;
diff --git a/engines/glk/comprehend/game.h b/engines/glk/comprehend/game.h
index d66cf82f1a..9a8e8b5d25 100644
--- a/engines/glk/comprehend/game.h
+++ b/engines/glk/comprehend/game.h
@@ -24,7 +24,6 @@
#define GLK_COMPREHEND_GAME_H
#include "glk/comprehend/game_data.h"
-#include "glk/comprehend/opcode_map.h"
#include "common/array.h"
#include "common/serializer.h"
@@ -38,17 +37,38 @@ namespace Comprehend {
struct GameStrings;
struct Sentence;
-class ComprehendGame : public GameData, public OpcodeMap {
+struct Sentence {
+ Word _words[4];
+ size_t _nr_words;
+ byte _formattedWords[6];
+ byte _specialOpcodeVal2;
+
+ Sentence() {
+ clear();
+ }
+
+ bool empty() const {
+ return _nr_words == 0;
+ }
+
+ void clear();
+
+ /**
+ * Splits up the array of _words into a _formattedWords
+ * array, placing the words in appropriate noun, verb, etc.
+ * positions appropriately
+ */
+ void format();
+};
+
+class ComprehendGame : public GameData {
private:
bool _ended;
public:
const GameStrings *_gameStrings;
private:
- Item *get_item_by_noun(byte noun);
void describe_objects_in_current_room();
- void func_set_test_result(FunctionState *func_state, bool value);
- size_t num_objects_in_room(int room);
void eval_instruction(FunctionState *func_state,
const Function &func, uint functionOffset,
const Sentence *sentence);
@@ -61,9 +81,6 @@ private:
void doBeforeTurn();
void doAfterTurn();
void read_input();
- void doMovementVerb(uint verbNum);
- bool isItemPresent(Item *item) const;
- void weighInventory();
protected:
void game_save();
@@ -72,6 +89,10 @@ protected:
_ended = true;
}
virtual bool handle_restart();
+
+ virtual void execute_opcode(const Instruction *instr, const Sentence *sentence,
+ FunctionState *func_state, Room *room, Item *&item) = 0;
+
int console_get_key();
void console_println(const char *text);
void move_object(Item *item, int new_room);
@@ -89,9 +110,13 @@ protected:
void parse_header(FileBuffer *fb) override {
GameData::parse_header(fb);
- loadOpcodes(_comprehendVersion);
}
+ Item *get_item_by_noun(byte noun);
+ void weighInventory();
+ size_t num_objects_in_room(int room);
+ void doMovementVerb(uint verbNum);
+
public:
ComprehendGame();
virtual ~ComprehendGame();
diff --git a/engines/glk/comprehend/game_cc.cpp b/engines/glk/comprehend/game_cc.cpp
index 14fdfc9de7..0bcf7169c5 100644
--- a/engines/glk/comprehend/game_cc.cpp
+++ b/engines/glk/comprehend/game_cc.cpp
@@ -29,7 +29,7 @@ namespace Comprehend {
static const GameStrings CC1_STRINGS = {0x9};
-CrimsonCrownGame::CrimsonCrownGame() : ComprehendGame(),
+CrimsonCrownGame::CrimsonCrownGame() : ComprehendGameV1(),
_diskNum(1), _newDiskNum(1) {
setupDisk(1);
}
diff --git a/engines/glk/comprehend/game_cc.h b/engines/glk/comprehend/game_cc.h
index c12a602015..5775e060dd 100644
--- a/engines/glk/comprehend/game_cc.h
+++ b/engines/glk/comprehend/game_cc.h
@@ -23,12 +23,12 @@
#ifndef GLK_COMPREHEND_GAME_CC_H
#define GLK_COMPREHEND_GAME_CC_H
-#include "glk/comprehend/game.h"
+#include "glk/comprehend/game_opcodes.h"
namespace Glk {
namespace Comprehend {
-class CrimsonCrownGame : public ComprehendGame {
+class CrimsonCrownGame : public ComprehendGameV1 {
private:
uint _diskNum;
uint _newDiskNum;
diff --git a/engines/glk/comprehend/game_oo.cpp b/engines/glk/comprehend/game_oo.cpp
index 0496bd0b05..6c565e7e86 100644
--- a/engines/glk/comprehend/game_oo.cpp
+++ b/engines/glk/comprehend/game_oo.cpp
@@ -34,7 +34,7 @@ namespace Comprehend {
#define OO_FLAG_WEARING_GOGGLES 0x1b
#define OO_FLAG_FLASHLIGHT_ON 0x27
-OOToposGame::OOToposGame() : ComprehendGame() {
+OOToposGame::OOToposGame() : ComprehendGameV2() {
_gameDataFile = "g0";
// Extra strings are (annoyingly) stored in the game binary
diff --git a/engines/glk/comprehend/game_oo.h b/engines/glk/comprehend/game_oo.h
index 3de4d24327..7d37651f64 100644
--- a/engines/glk/comprehend/game_oo.h
+++ b/engines/glk/comprehend/game_oo.h
@@ -23,12 +23,12 @@
#ifndef GLK_COMPREHEND_GAME_OO_H
#define GLK_COMPREHEND_GAME_OO_H
-#include "glk/comprehend/game.h"
+#include "glk/comprehend/game_opcodes.h"
namespace Glk {
namespace Comprehend {
-class OOToposGame : public ComprehendGame {
+class OOToposGame : public ComprehendGameV2 {
public:
OOToposGame();
~OOToposGame() override {}
diff --git a/engines/glk/comprehend/game_opcodes.cpp b/engines/glk/comprehend/game_opcodes.cpp
new file mode 100644
index 0000000000..9aae69a7eb
--- /dev/null
+++ b/engines/glk/comprehend/game_opcodes.cpp
@@ -0,0 +1,748 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers; whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License; or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful;
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not; write to the Free Software
+ * Foundation; Inc.; 51 Franklin Street; Fifth Floor; Boston; MA 02110-1301; USA.
+ *
+ */
+
+#include "glk/comprehend/game_opcodes.h"
+#include "glk/comprehend/game_data.h"
+#include "glk/comprehend/comprehend.h"
+#include "common/algorithm.h"
+#include "common/textconsole.h"
+
+namespace Glk {
+namespace Comprehend {
+
+ComprehendGameOpcodes::ComprehendGameOpcodes() {
+ Common::fill(&_opcodeMap[0], &_opcodeMap[0x100], 0);
+}
+
+void ComprehendGameOpcodes::execute_opcode(const Instruction *instr, const Sentence *sentence,
+ FunctionState *func_state, Room *room, Item *&item) {
+
+// switch (_opcodeMap[instr->_opcode]) {
+// default:
+ if (instr->_opcode & 0x80) {
+ warning("Unhandled command opcode %.2x", instr->_opcode);
+ } else {
+ warning("Unhandled test opcode %.2x - returning false",
+ instr->_opcode);
+ func_set_test_result(func_state, false);
+ }
+// break;
+// }
+}
+
+void ComprehendGameOpcodes::func_set_test_result(FunctionState *func_state, bool value) {
+ if (func_state->_orCount == 0) {
+ /* And */
+ if (func_state->_and) {
+ if (!value)
+ func_state->_testResult = false;
+ } else {
+ func_state->_testResult = value;
+ func_state->_and = true;
+ }
+
+ } else {
+ /* Or */
+ if (value)
+ func_state->_testResult = value;
+ }
+}
+
+bool ComprehendGameOpcodes::isItemPresent(Item *item) const {
+ return item && (
+ item->_room == _currentRoom || item->_room == ROOM_INVENTORY
+ || item->_room == ROOM_CONTAINER
+ );
+}
+
+/*-------------------------------------------------------*/
+
+ComprehendGameV1::ComprehendGameV1() {
+ _opcodeMap[0x01] = OPCODE_HAVE_OBJECT;
+ _opcodeMap[0x02] = OPCODE_VAR_GT2;
+ _opcodeMap[0x04] = OPCODE_OR;
+ _opcodeMap[0x05] = OPCODE_IN_ROOM;
+ _opcodeMap[0x06] = OPCODE_VAR_EQ2;
+ _opcodeMap[0x08] = OPCODE_CURRENT_OBJECT_TAKEABLE;
+ _opcodeMap[0x09] = OPCODE_OBJECT_PRESENT;
+ _opcodeMap[0x0a] = OPCODE_VAR_GTE2;
+ _opcodeMap[0x0c] = OPCODE_ELSE;
+ _opcodeMap[0x0e] = OPCODE_OBJECT_IN_ROOM;
+ _opcodeMap[0x14] = OPCODE_CURRENT_OBJECT_NOT_VALID;
+ _opcodeMap[0x18] = OPCODE_INVENTORY_FULL;
+ _opcodeMap[0x19] = OPCODE_TEST_FLAG;
+ _opcodeMap[0x1d] = OPCODE_CURRENT_OBJECT_IN_ROOM;
+ _opcodeMap[0x20] = OPCODE_HAVE_CURRENT_OBJECT;
+ _opcodeMap[0x21] = OPCODE_OBJECT_IS_NOT_NOWHERE;
+ _opcodeMap[0x24] = OPCODE_CURRENT_OBJECT_PRESENT;
+ _opcodeMap[0x25] = OPCODE_VAR_GT1;
+ _opcodeMap[0x29] = OPCODE_VAR_EQ1;
+ _opcodeMap[0x2d] = OPCODE_VAR_GTE1;
+ _opcodeMap[0x31] = OPCODE_TEST_ROOM_FLAG;
+ _opcodeMap[0x41] = OPCODE_NOT_HAVE_OBJECT;
+ _opcodeMap[0x45] = OPCODE_NOT_IN_ROOM;
+ _opcodeMap[0x48] = OPCODE_CURRENT_OBJECT_NOT_PRESENT;
+ _opcodeMap[0x49] = OPCODE_OBJECT_NOT_IN_ROOM;
+ _opcodeMap[0x4E] = OPCODE_TEST_FALSE;
+ _opcodeMap[0x50] = OPCODE_CURRENT_OBJECT_IS_NOWHERE;
+ _opcodeMap[0x59] = OPCODE_TEST_NOT_FLAG;
+ _opcodeMap[0x5D] = OPCODE_TEST_FALSE;
+ _opcodeMap[0x60] = OPCODE_NOT_HAVE_CURRENT_OBJECT;
+ _opcodeMap[0x61] = OPCODE_OBJECT_IS_NOWHERE;
+ _opcodeMap[0x64] = OPCODE_CURRENT_OBJECT_NOT_IN_ROOM;
+ _opcodeMap[0x68] = OPCODE_CURRENT_OBJECT_NOT_TAKEABLE;
+ _opcodeMap[0x71] = OPCODE_TEST_NOT_ROOM_FLAG;
+ _opcodeMap[0x80] = OPCODE_INVENTORY;
+ _opcodeMap[0x81] = OPCODE_TAKE_OBJECT;
+ _opcodeMap[0x82] = OPCODE_MOVE_OBJECT_TO_ROOM;
+ _opcodeMap[0x84] = OPCODE_SAVE_ACTION;
+ _opcodeMap[0x85] = OPCODE_MOVE_TO_ROOM;
+ _opcodeMap[0x86] = OPCODE_VAR_ADD;
+ _opcodeMap[0x87] = OPCODE_SET_ROOM_DESCRIPTION;
+ _opcodeMap[0x89] = OPCODE_MOVE_OBJECT_TO_CURRENT_ROOM;
+ _opcodeMap[0x8a] = OPCODE_VAR_SUB;
+ _opcodeMap[0x8b] = OPCODE_SET_OBJECT_DESCRIPTION;
+ _opcodeMap[0x8c] = OPCODE_MOVE_DEFAULT;
+ _opcodeMap[0x8e] = OPCODE_PRINT;
+ _opcodeMap[0x95] = OPCODE_REMOVE_OBJECT;
+ _opcodeMap[0x99] = OPCODE_SET_FLAG;
+ _opcodeMap[0x92] = OPCODE_CALL_FUNC;
+ _opcodeMap[0x98] = OPCODE_TURN_TICK;
+ _opcodeMap[0x9d] = OPCODE_CLEAR_FLAG;
+ _opcodeMap[0x9e] = OPCODE_INVENTORY_ROOM;
+ _opcodeMap[0xa0] = OPCODE_TAKE_CURRENT_OBJECT;
+ _opcodeMap[0xa1] = OPCODE_SPECIAL;
+ _opcodeMap[0xa4] = OPCODE_DROP_CURRENT_OBJECT;
+ _opcodeMap[0xa2] = OPCODE_SET_ROOM_GRAPHIC;
+ _opcodeMap[0xb0] = OPCODE_REMOVE_CURRENT_OBJECT;
+ _opcodeMap[0xb1] = OPCODE_MOVE_DIR;
+ _opcodeMap[0xb9] = OPCODE_SET_STRING_REPLACEMENT;
+ _opcodeMap[0xbd] = OPCODE_VAR_INC;
+ _opcodeMap[0xc1] = OPCODE_VAR_DEC;
+ _opcodeMap[0xc9] = OPCODE_MOVE_CURRENT_OBJECT_TO_ROOM;
+}
+
+void ComprehendGameV1::execute_opcode(const Instruction *instr, const Sentence *sentence,
+ FunctionState *func_state, Room *room, Item *&item) {
+ byte verb = sentence ? sentence->_formattedWords[0] : 0;
+ byte noun = sentence ? sentence->_formattedWords[2] : 0;
+ uint count, index;
+
+ switch (_opcodeMap[instr->_opcode]) {
+ case OPCODE_VAR_ADD:
+ _variables[instr->_operand[0]] +=
+ _variables[instr->_operand[1]];
+ break;
+
+ case OPCODE_VAR_SUB:
+ _variables[instr->_operand[0]] -=
+ _variables[instr->_operand[1]];
+ break;
+
+ case OPCODE_VAR_INC:
+ _variables[instr->_operand[0]]++;
+ break;
+
+ case OPCODE_VAR_DEC:
+ _variables[instr->_operand[0]]--;
+ break;
+
+ case OPCODE_VAR_EQ1:
+ func_set_test_result(func_state,
+ _variables[0] ==
+ _variables[instr->_operand[0]]);
+ break;
+
+ case OPCODE_VAR_EQ2:
+ func_set_test_result(func_state,
+ _variables[instr->_operand[0]] ==
+ _variables[instr->_operand[1]]);
+ break;
+
+ case OPCODE_VAR_GT1:
+ func_set_test_result(func_state,
+ _variables[0] >
+ _variables[instr->_operand[0]]);
+ break;
+
+ case OPCODE_VAR_GT2:
+ func_set_test_result(func_state,
+ _variables[instr->_operand[0]] >
+ _variables[instr->_operand[1]]);
+ break;
+
+ case OPCODE_VAR_GTE1:
+ func_set_test_result(func_state,
+ _variables[0] >=
+ _variables[instr->_operand[0]]);
+ break;
+
+ case OPCODE_VAR_GTE2:
+ func_set_test_result(func_state,
+ _variables[instr->_operand[0]] >=
+ _variables[instr->_operand[1]]);
+ break;
+
+ case OPCODE_TURN_TICK:
+ _variables[VAR_TURN_COUNT]++;
+ break;
+
+ case OPCODE_PRINT:
+ console_println(instrStringLookup(
+ instr->_operand[0], instr->_operand[1])
+ .c_str());
+ break;
+
+ case OPCODE_TEST_NOT_ROOM_FLAG:
+ func_set_test_result(func_state,
+ !(room->_flags & instr->_operand[0]));
+ break;
+
+ case OPCODE_TEST_ROOM_FLAG:
+ func_set_test_result(func_state,
+ room->_flags & instr->_operand[0]);
+ break;
+
+ case OPCODE_NOT_IN_ROOM:
+ func_set_test_result(func_state,
+ _currentRoom != instr->_operand[0]);
+ break;
+
+ case OPCODE_IN_ROOM:
+ func_set_test_result(func_state,
+ _currentRoom == instr->_operand[0]);
+ break;
+
+ case OPCODE_MOVE_TO_ROOM:
+ if (instr->_operand[0] != 0xff)
+ move_to(instr->_operand[0]);
+ break;
+
+ case OPCODE_MOVE_DEFAULT:
+ // Move in the direction dictated by the current verb
+ if (verb - 1 >= NR_DIRECTIONS)
+ error("Bad verb %d in move", verb);
+
+ if (room->_direction[verb - 1])
+ move_to(room->_direction[verb - 1]);
+ else
+ console_println(stringLookup(STRING_CANT_GO).c_str());
+ break;
+
+ case OPCODE_MOVE_DIRECTION:
+ if (room->_direction[instr->_operand[0] - 1])
+ move_to(room->_direction[instr->_operand[0] - 1]);
+ else
+ console_println(stringLookup(STRING_CANT_GO).c_str());
+ break;
+
+ case OPCODE_ELSE:
+ func_state->_testResult = func_state->_elseResult;
+ break;
+
+ case OPCODE_MOVE_OBJECT_TO_CURRENT_ROOM:
+ item = get_item(instr->_operand[0] - 1);
+ move_object(item, _currentRoom);
+ break;
+
+ case OPCODE_OBJECT_IN_ROOM:
+ item = get_item(instr->_operand[0] - 1);
+ func_set_test_result(func_state,
+ item->_room == instr->_operand[1]);
+ break;
+
+ case OPCODE_OBJECT_NOT_IN_ROOM:
+ item = get_item(instr->_operand[0] - 1);
+ func_set_test_result(func_state, !item || item->_room != _currentRoom);
+ break;
+
+ case OPCODE_OBJECT_CAN_TAKE:
+ item = get_item(instr->_operand[0] - 1);
+ func_set_test_result(func_state, item->_flags & ITEMF_CAN_TAKE);
+ break;
+
+ case OPCODE_CURRENT_OBJECT_NOT_IN_ROOM:
+ item = get_item_by_noun(noun);
+ func_set_test_result(func_state, !item || item->_room != _currentRoom);
+ break;
+
+ case OPCODE_MOVE_OBJECT_TO_ROOM:
+ item = get_item(instr->_operand[0] - 1);
+ move_object(item, instr->_operand[1]);
+ break;
+
+ case OPCODE_INVENTORY_FULL:
+ item = get_item_by_noun(noun);
+
+ func_set_test_result(func_state,
+ _variables[VAR_INVENTORY_WEIGHT] +
+ (item->_flags & ITEMF_WEIGHT_MASK) >
+ _variables[VAR_INVENTORY_LIMIT]);
+ break;
+
+ case OPCODE_DESCRIBE_CURRENT_OBJECT:
+ /*
+ * This opcode is only used in version 2
+ * FIXME - unsure what the single operand is for.
+ */
+ item = get_item_by_noun(noun);
+ g_comprehend->print("%s\n", stringLookup(item->_longString).c_str());
+ break;
+
+ case OPCODE_CURRENT_OBJECT_IN_ROOM: {
+ /* FIXME - use common code for these two ops */
+ bool test = false;
+
+ if (noun) {
+ for (uint i = 0; i < _items.size(); i++) {
+ Item *itemP = &_items[i];
+
+ if (itemP->_word == noun && itemP->_room == instr->_operand[0]) {
+ test = true;
+ break;
+ }
+ }
+ }
+
+ func_set_test_result(func_state, test);
+ break;
+ }
+
+ case OPCODE_CURRENT_OBJECT_PRESENT:
+ item = get_item_by_noun(noun);
+ if (item)
+ func_set_test_result(func_state,
+ item->_room == _currentRoom);
+ else
+ func_set_test_result(func_state, false);
+ break;
+
+ case OPCODE_HAVE_OBJECT:
+ item = get_item(instr->_operand[0] - 1);
+ func_set_test_result(func_state,
+ item->_room == ROOM_INVENTORY);
+ break;
+
+ case OPCODE_NOT_HAVE_CURRENT_OBJECT:
+ item = get_item_by_noun(noun);
+ func_set_test_result(func_state,
+ !item || item->_room != ROOM_INVENTORY);
+ break;
+
+ case OPCODE_HAVE_CURRENT_OBJECT:
+ item = get_item_by_noun(noun);
+ func_set_test_result(func_state,
+ item->_room == ROOM_INVENTORY);
+ break;
+
+ case OPCODE_NOT_HAVE_OBJECT:
+ item = get_item(instr->_operand[0] - 1);
+ func_set_test_result(func_state,
+ item->_room != ROOM_INVENTORY);
+ break;
+
+ case OPCODE_CURRENT_OBJECT_TAKEABLE:
+ item = get_item_by_noun(noun);
+ if (!item)
+ func_set_test_result(func_state, false);
+ else
+ func_set_test_result(func_state,
+ (item->_flags & ITEMF_CAN_TAKE));
+ break;
+
+ case OPCODE_CURRENT_OBJECT_NOT_TAKEABLE:
+ item = get_item_by_noun(noun);
+ if (!item)
+ func_set_test_result(func_state, true);
+ else
+ func_set_test_result(func_state,
+ !(item->_flags & ITEMF_CAN_TAKE));
+ break;
+
+ case OPCODE_OBJECT_IS_NOWHERE:
+ item = get_item(instr->_operand[0] - 1);
+ func_set_test_result(func_state, item->_room == ROOM_NOWHERE);
+ break;
+
+ case OPCODE_CURRENT_OBJECT_IS_NOWHERE:
+ item = get_item_by_noun(noun);
+ func_set_test_result(func_state, item && item->_room == ROOM_NOWHERE);
+ break;
+
+ case OPCODE_OBJECT_IS_NOT_NOWHERE:
+ item = get_item(instr->_operand[0] - 1);
+ func_set_test_result(func_state, item->_room != ROOM_NOWHERE);
+ break;
+
+ case OPCODE_CURRENT_OBJECT_NOT_PRESENT:
+ item = get_item_by_noun(noun);
+ func_set_test_result(func_state, !isItemPresent(item));
+ break;
+
+ case OPCODE_OBJECT_NOT_PRESENT:
+ item = get_item(instr->_operand[0] - 1);
+ func_set_test_result(func_state, !isItemPresent(item));
+ break;
+
+ case OPCODE_OBJECT_PRESENT:
+ item = get_item(instr->_operand[0] - 1);
+ func_set_test_result(func_state,
+ item->_room == _currentRoom);
+ break;
+
+ case OPCODE_CURRENT_OBJECT_NOT_VALID:
+ func_set_test_result(func_state, !noun);
+ break;
+
+ case OPCODE_CURRENT_IS_OBJECT:
+ func_set_test_result(func_state,
+ get_item_by_noun(noun) != NULL);
+ break;
+
+ case OPCODE_CURRENT_NOT_OBJECT:
+ func_set_test_result(func_state,
+ get_item_by_noun(noun) == NULL);
+ break;
+
+ case OPCODE_REMOVE_OBJECT:
+ item = get_item(instr->_operand[0] - 1);
+ move_object(item, ROOM_NOWHERE);
+ break;
+
+ case OPCODE_REMOVE_CURRENT_OBJECT:
+ item = get_item_by_noun(noun);
+ move_object(item, ROOM_NOWHERE);
+ break;
+
+ case OPCODE_INVENTORY:
+ count = num_objects_in_room(ROOM_INVENTORY);
+ if (count == 0) {
+ console_println(stringLookup(STRING_INVENTORY_EMPTY).c_str());
+ break;
+ }
+
+ console_println(stringLookup(STRING_INVENTORY).c_str());
+ for (uint i = 0; i < _items.size(); i++) {
+ item = &_items[i];
+ if (item->_room == ROOM_INVENTORY)
+ g_comprehend->print("%s\n",
+ stringLookup(item->_stringDesc).c_str());
+ }
+ break;
+
+ case OPCODE_INVENTORY_ROOM:
+ count = num_objects_in_room(instr->_operand[0]);
+ if (count == 0) {
+ console_println(stringLookup(instr->_operand[1] + 1).c_str());
+ break;
+ }
+
+ console_println(stringLookup(instr->_operand[1]).c_str());
+ for (uint i = 0; i < _items.size(); i++) {
+ item = &_items[i];
+ if (item->_room == instr->_operand[0])
+ g_comprehend->print("%s\n",
+ stringLookup(item->_stringDesc).c_str());
+ }
+ break;
+
+ case OPCODE_MOVE_CURRENT_OBJECT_TO_ROOM:
+ item = get_item_by_noun(noun);
+ if (!item)
+ error("Bad current object\n");
+
+ move_object(item, instr->_operand[0]);
+ break;
+
+ case OPCODE_DROP_OBJECT:
+ item = get_item(instr->_operand[0] - 1);
+ move_object(item, _currentRoom);
+ break;
+
+ case OPCODE_DROP_CURRENT_OBJECT:
+ item = get_item_by_noun(noun);
+ if (!item)
+ error("Attempt to take object failed\n");
+
+ move_object(item, _currentRoom);
+ break;
+
+ case OPCODE_TAKE_CURRENT_OBJECT:
+ item = get_item_by_noun(noun);
+ if (!item)
+ error("Attempt to take object failed\n");
+
+ move_object(item, ROOM_INVENTORY);
+ break;
+
+ case OPCODE_TAKE_OBJECT:
+ item = get_item(instr->_operand[0] - 1);
+ move_object(item, ROOM_INVENTORY);
+ break;
+
+ case OPCODE_TEST_FLAG:
+ func_set_test_result(func_state,
+ _flags[instr->_operand[0]]);
+ break;
+
+ case OPCODE_TEST_NOT_FLAG:
+ func_set_test_result(func_state,
+ !_flags[instr->_operand[0]]);
+ break;
+
+ case OPCODE_CLEAR_FLAG:
+ _flags[instr->_operand[0]] = false;
+ break;
+
+ case OPCODE_SET_FLAG:
+ _flags[instr->_operand[0]] = true;
+ break;
+
+ case OPCODE_OR:
+ if (func_state->_orCount) {
+ func_state->_orCount += 2;
+ } else {
+ func_state->_testResult = false;
+ func_state->_orCount += 3;
+ }
+ break;
+
+ case OPCODE_SET_OBJECT_DESCRIPTION:
+ item = get_item(instr->_operand[0] - 1);
+ item->_stringDesc = (instr->_operand[2] << 8) | instr->_operand[1];
+ break;
+
+ case OPCODE_SET_OBJECT_LONG_DESCRIPTION:
+ item = get_item(instr->_operand[0] - 1);
+ item->_longString = (instr->_operand[2] << 8) | instr->_operand[1];
+ break;
+
+ case OPCODE_SET_ROOM_DESCRIPTION:
+ room = get_room(instr->_operand[0]);
+ switch (instr->_operand[2]) {
+ case 0x80:
+ room->_stringDesc = instr->_operand[1];
+ break;
+ case 0x81:
+ room->_stringDesc = instr->_operand[1] + 0x100;
+ break;
+ case 0x82:
+ room->_stringDesc = instr->_operand[1] + 0x200;
+ break;
+ default:
+ error("Bad string desc %.2x:%.2x\n",
+ instr->_operand[1], instr->_operand[2]);
+ break;
+ }
+ break;
+
+ case OPCODE_SET_OBJECT_GRAPHIC:
+ item = get_item(instr->_operand[0] - 1);
+ item->_graphic = instr->_operand[1];
+ if (item->_room == _currentRoom)
+ _updateFlags |= UPDATE_GRAPHICS;
+ break;
+
+ case OPCODE_SET_ROOM_GRAPHIC:
+ room = get_room(instr->_operand[0]);
+ room->_graphic = instr->_operand[1];
+ if (instr->_operand[0] == _currentRoom)
+ _updateFlags |= UPDATE_GRAPHICS;
+ break;
+
+ case OPCODE_CALL_FUNC:
+ index = instr->_operand[0];
+ if (instr->_operand[1] == 0x81)
+ index += 256;
+ if (index >= _functions.size())
+ error("Bad function %.4x >= %.4x\n",
+ index, _functions.size());
+
+ eval_function(index, sentence);
+ break;
+
+ case OPCODE_TEST_FALSE:
+ // The original had two opcodes mapped to the same code that does
+ // a test, but ignores the result, and is always false
+ func_set_test_result(func_state, false);
+ break;
+
+ case OPCODE_SAVE_ACTION:
+ /*
+ * FIXME - This saves the current verb and allows the next
+ * command to use just the noun. This is used to allow
+ * responses to ask the player what they meant, e.g:
+ *
+ * > drop
+ * I don't understand what you want to drop.
+ * > gun
+ * Okay.
+ */
+ break;
+
+ case OPCODE_SET_STRING_REPLACEMENT:
+ _currentReplaceWord = instr->_operand[0] - 1;
+ break;
+
+ case OPCODE_SET_CURRENT_NOUN_STRING_REPLACEMENT:
+#if 1
+ error("TODO: OPCODE_SET_CURRENT_NOUN_STRING_REPLACEMENT");
+#else
+ /*
+ * FIXME - Not sure what the operand is for,
+ * maybe capitalisation?
+ */
+ if (noun && (noun->_type & WORD_TYPE_NOUN_PLURAL))
+ _currentReplaceWord = 3;
+ else if (noun && (noun->_type & WORD_TYPE_FEMALE))
+ _currentReplaceWord = 0;
+ else if (noun && (noun->_type & WORD_TYPE_MALE))
+ _currentReplaceWord = 1;
+ else
+ _currentReplaceWord = 2;
+#endif
+ break;
+
+ case OPCODE_DRAW_ROOM:
+ g_comprehend->drawLocationPicture(instr->_operand[0] - 1);
+ break;
+
+ case OPCODE_DRAW_OBJECT:
+ g_comprehend->drawItemPicture(instr->_operand[0] - 1);
+ break;
+
+ case OPCODE_WAIT_KEY:
+ console_get_key();
+ break;
+
+ case OPCODE_SPECIAL:
+ // Game specific opcode
+ handleSpecialOpcode(instr->_operand[0]);
+ break;
+
+ case OPCODE_MOVE_DIR:
+ doMovementVerb(instr->_operand[0]);
+ break;
+
+ default:
+ ComprehendGameOpcodes::execute_opcode(instr, sentence, func_state, room, item);
+ break;
+ }
+}
+
+/*-------------------------------------------------------*/
+
+ComprehendGameV2::ComprehendGameV2() {
+ _opcodeMap[0x01] = OPCODE_HAVE_OBJECT;
+ _opcodeMap[0x02] = OPCODE_VAR_GT2;
+ _opcodeMap[0x04] = OPCODE_OR;
+ _opcodeMap[0x05] = OPCODE_IN_ROOM;
+ _opcodeMap[0x06] = OPCODE_VAR_EQ2;
+ _opcodeMap[0x08] = OPCODE_CURRENT_IS_OBJECT;
+ _opcodeMap[0x09] = OPCODE_VAR_GT1;
+ _opcodeMap[0x0a] = OPCODE_VAR_GTE2;
+ _opcodeMap[0x0c] = OPCODE_ELSE;
+ _opcodeMap[0x0d] = OPCODE_VAR_EQ1;
+ _opcodeMap[0x11] = OPCODE_OBJECT_IS_NOWHERE;
+ _opcodeMap[0x14] = OPCODE_CURRENT_OBJECT_NOT_VALID;
+ _opcodeMap[0x19] = OPCODE_TEST_FLAG;
+ _opcodeMap[0x1d] = OPCODE_TEST_ROOM_FLAG;
+ _opcodeMap[0x20] = OPCODE_HAVE_CURRENT_OBJECT;
+ _opcodeMap[0x21] = OPCODE_OBJECT_PRESENT;
+ _opcodeMap[0x22] = OPCODE_OBJECT_IN_ROOM;
+ _opcodeMap[0x2d] = OPCODE_OBJECT_CAN_TAKE;
+ _opcodeMap[0x30] = OPCODE_CURRENT_OBJECT_PRESENT;
+ _opcodeMap[0x31] = OPCODE_TEST_ROOM_FLAG;
+ _opcodeMap[0x41] = OPCODE_NOT_HAVE_OBJECT;
+ _opcodeMap[0x45] = OPCODE_NOT_IN_ROOM;
+ _opcodeMap[0x48] = OPCODE_CURRENT_OBJECT_NOT_PRESENT;
+ _opcodeMap[0x43] = OPCODE_OBJECT_NOT_IN_ROOM;
+ _opcodeMap[0x51] = OPCODE_OBJECT_IS_NOWHERE;
+ _opcodeMap[0x59] = OPCODE_TEST_NOT_FLAG;
+ _opcodeMap[0x5d] = OPCODE_TEST_NOT_ROOM_FLAG;
+ _opcodeMap[0x60] = OPCODE_NOT_HAVE_CURRENT_OBJECT;
+ _opcodeMap[0x61] = OPCODE_OBJECT_NOT_PRESENT;
+ _opcodeMap[0x70] = OPCODE_CURRENT_OBJECT_NOT_PRESENT;
+ _opcodeMap[0x74] = OPCODE_CURRENT_NOT_OBJECT;
+ _opcodeMap[0x80] = OPCODE_INVENTORY;
+ _opcodeMap[0x81] = OPCODE_TAKE_OBJECT;
+ _opcodeMap[0x82] = OPCODE_MOVE_OBJECT_TO_ROOM;
+ _opcodeMap[0x84] = OPCODE_SAVE_ACTION;
+ _opcodeMap[0x85] = OPCODE_MOVE_TO_ROOM;
+ _opcodeMap[0x86] = OPCODE_VAR_ADD;
+ _opcodeMap[0x87] = OPCODE_SET_ROOM_DESCRIPTION;
+ _opcodeMap[0x89] = OPCODE_SPECIAL;
+ _opcodeMap[0x8a] = OPCODE_VAR_SUB;
+ _opcodeMap[0x8b] = OPCODE_SET_OBJECT_DESCRIPTION;
+ _opcodeMap[0x8c] = OPCODE_MOVE_DEFAULT;
+ _opcodeMap[0x8e] = OPCODE_PRINT;
+ _opcodeMap[0x8f] = OPCODE_SET_OBJECT_LONG_DESCRIPTION;
+ _opcodeMap[0x90] = OPCODE_WAIT_KEY;
+ _opcodeMap[0x92] = OPCODE_CALL_FUNC;
+ _opcodeMap[0x95] = OPCODE_REMOVE_OBJECT;
+ _opcodeMap[0x98] = OPCODE_TURN_TICK;
+ _opcodeMap[0x99] = OPCODE_SET_FLAG;
+ _opcodeMap[0x9d] = OPCODE_CLEAR_FLAG;
+ _opcodeMap[0x9e] = OPCODE_INVENTORY_ROOM;
+ _opcodeMap[0xa0] = OPCODE_TAKE_CURRENT_OBJECT;
+ _opcodeMap[0xa2] = OPCODE_SET_OBJECT_GRAPHIC;
+ _opcodeMap[0xa9] = OPCODE_INVENTORY_FULL;
+ _opcodeMap[0xb1] = OPCODE_MOVE_DIR;
+ _opcodeMap[0xb5] = OPCODE_DESCRIBE_CURRENT_OBJECT;
+ _opcodeMap[0xc1] = OPCODE_VAR_DEC;
+ _opcodeMap[0xc2] = OPCODE_SET_ROOM_GRAPHIC;
+ _opcodeMap[0xc5] = OPCODE_SET_CURRENT_NOUN_STRING_REPLACEMENT;
+ _opcodeMap[0xc6] = OPCODE_SET_OBJECT_GRAPHIC;
+ _opcodeMap[0xc9] = OPCODE_MOVE_CURRENT_OBJECT_TO_ROOM;
+ _opcodeMap[0xcd] = OPCODE_SET_STRING_REPLACEMENT;
+ _opcodeMap[0xd1] = OPCODE_MOVE_DIRECTION;
+ _opcodeMap[0xd5] = OPCODE_DRAW_ROOM;
+ _opcodeMap[0xd9] = OPCODE_DRAW_OBJECT;
+ _opcodeMap[0xdd] = OPCODE_VAR_INC;
+ _opcodeMap[0xe1] = OPCODE_MOVE_OBJECT_TO_CURRENT_ROOM;
+ _opcodeMap[0xed] = OPCODE_REMOVE_OBJECT;
+ _opcodeMap[0xf0] = OPCODE_DROP_CURRENT_OBJECT;
+ _opcodeMap[0xfc] = OPCODE_REMOVE_CURRENT_OBJECT;
+}
+
+void ComprehendGameV2::execute_opcode(const Instruction *instr, const Sentence *sentence,
+ FunctionState *func_state, Room *room, Item *&item) {
+ byte noun = sentence ? sentence->_formattedWords[2] : 0;
+
+ switch (_opcodeMap[instr->_opcode]) {
+ case OPCODE_INVENTORY_FULL:
+ item = get_item_by_noun(noun);
+
+ weighInventory();
+ func_set_test_result(func_state,
+ _totalInventoryWeight + (item->_flags & ITEMF_WEIGHT_MASK) <
+ _variables[VAR_INVENTORY_LIMIT]);
+ break;
+
+ default:
+ ComprehendGameOpcodes::execute_opcode(instr, sentence, func_state, room, item);
+ break;
+ }
+}
+
+} // namespace Comprehend
+} // namespace Glk
diff --git a/engines/glk/comprehend/game_opcodes.h b/engines/glk/comprehend/game_opcodes.h
new file mode 100644
index 0000000000..a1f25b888b
--- /dev/null
+++ b/engines/glk/comprehend/game_opcodes.h
@@ -0,0 +1,74 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef GLK_COMPREHEND_GAME_OPCODES_H
+#define GLK_COMPREHEND_GAME_OPCODES_H
+
+#include "glk/comprehend/game.h"
+
+namespace Glk {
+namespace Comprehend {
+
+/**
+ * Intermediate derived game class that handles script opcodes common to both
+ * version 1 and version 2 of the engine
+ */
+class ComprehendGameOpcodes : public ComprehendGame {
+protected:
+ byte _opcodeMap[0x100];
+
+ void execute_opcode(const Instruction *instr, const Sentence *sentence,
+ FunctionState *func_state, Room *room, Item *&item) override;
+
+ void func_set_test_result(FunctionState *func_state, bool value);
+ bool isItemPresent(Item *item) const;
+public:
+ ComprehendGameOpcodes();
+};
+
+
+/**
+ * Version 1 Comprehend game
+ */
+class ComprehendGameV1 : public ComprehendGameOpcodes {
+protected:
+ void execute_opcode(const Instruction *instr, const Sentence *sentence,
+ FunctionState *func_state, Room *room, Item *&item) override;
+public:
+ ComprehendGameV1();
+};
+
+/**
+ * Version 2 Comprehend game
+ */
+class ComprehendGameV2 : public ComprehendGameOpcodes {
+protected:
+ void execute_opcode(const Instruction *instr, const Sentence *sentence,
+ FunctionState *func_state, Room *room, Item *&item) override;
+public:
+ ComprehendGameV2();
+};
+
+} // namespace Comprehend
+} // namespace Glk
+
+#endif
diff --git a/engines/glk/comprehend/game_tm.cpp b/engines/glk/comprehend/game_tm.cpp
index 7fefaf06ea..ecc6b0cccf 100644
--- a/engines/glk/comprehend/game_tm.cpp
+++ b/engines/glk/comprehend/game_tm.cpp
@@ -28,7 +28,7 @@ namespace Comprehend {
/* FIXME - This is broken */
-TalismanGame::TalismanGame() : ComprehendGame() {
+TalismanGame::TalismanGame() : ComprehendGameV2() {
_gameDataFile = "G0";
_locationGraphicFiles.push_back("RA");
diff --git a/engines/glk/comprehend/game_tm.h b/engines/glk/comprehend/game_tm.h
index 0e1fc33038..d5be035a09 100644
--- a/engines/glk/comprehend/game_tm.h
+++ b/engines/glk/comprehend/game_tm.h
@@ -23,12 +23,12 @@
#ifndef GLK_COMPREHEND_GAME_TM_H
#define GLK_COMPREHEND_GAME_TM_H
-#include "glk/comprehend/game.h"
+#include "glk/comprehend/game_opcodes.h"
namespace Glk {
namespace Comprehend {
-class TalismanGame : public ComprehendGame {
+class TalismanGame : public ComprehendGameV2 {
public:
TalismanGame();
~TalismanGame() override {}
diff --git a/engines/glk/comprehend/game_tr.cpp b/engines/glk/comprehend/game_tr.cpp
index b4e550d1f2..117ec3700a 100644
--- a/engines/glk/comprehend/game_tr.cpp
+++ b/engines/glk/comprehend/game_tr.cpp
@@ -69,7 +69,7 @@ static const GameStrings TR_STRINGS = {
};
-TransylvaniaGame::TransylvaniaGame() : ComprehendGame(),
+TransylvaniaGame::TransylvaniaGame() : ComprehendGameV1(),
_miceReleased(false) {
_gameDataFile = "tr.gda";
diff --git a/engines/glk/comprehend/game_tr.h b/engines/glk/comprehend/game_tr.h
index 70e4a059e5..076d697aa9 100644
--- a/engines/glk/comprehend/game_tr.h
+++ b/engines/glk/comprehend/game_tr.h
@@ -23,14 +23,14 @@
#ifndef GLK_COMPREHEND_GAME_TR_H
#define GLK_COMPREHEND_GAME_TR_H
-#include "glk/comprehend/game.h"
+#include "glk/comprehend/game_opcodes.h"
namespace Glk {
namespace Comprehend {
struct TransylvaniaMonster;
-class TransylvaniaGame : public ComprehendGame {
+class TransylvaniaGame : public ComprehendGameV1 {
private:
static const TransylvaniaMonster WEREWOLF;
static const TransylvaniaMonster VAMPIRE;
diff --git a/engines/glk/comprehend/opcode_map.cpp b/engines/glk/comprehend/opcode_map.cpp
deleted file mode 100644
index 7415543c9f..0000000000
--- a/engines/glk/comprehend/opcode_map.cpp
+++ /dev/null
@@ -1,181 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers; whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License; or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful;
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not; write to the Free Software
- * Foundation; Inc.; 51 Franklin Street; Fifth Floor; Boston; MA 02110-1301; USA.
- *
- */
-
-#include "glk/comprehend/opcode_map.h"
-#include "glk/comprehend/game_data.h"
-#include "common/algorithm.h"
-#include "common/textconsole.h"
-
-namespace Glk {
-namespace Comprehend {
-
-void OpcodeMap::loadOpcodes(int version) {
- Common::fill(&_opcodeMap[0], &_opcodeMap[0x100], 0);
-
- if (version == 1)
- loadVersion1();
- else if (version == 2)
- loadVersion2();
- else
- error("Invalid version");
-}
-
-void OpcodeMap::loadVersion1() {
- _opcodeMap[0x01] = OPCODE_HAVE_OBJECT;
- _opcodeMap[0x02] = OPCODE_VAR_GT2;
- _opcodeMap[0x04] = OPCODE_OR;
- _opcodeMap[0x05] = OPCODE_IN_ROOM;
- _opcodeMap[0x06] = OPCODE_VAR_EQ2;
- _opcodeMap[0x08] = OPCODE_CURRENT_OBJECT_TAKEABLE;
- _opcodeMap[0x09] = OPCODE_OBJECT_PRESENT;
- _opcodeMap[0x0a] = OPCODE_VAR_GTE2;
- _opcodeMap[0x0c] = OPCODE_ELSE;
- _opcodeMap[0x0e] = OPCODE_OBJECT_IN_ROOM;
- _opcodeMap[0x14] = OPCODE_CURRENT_OBJECT_NOT_VALID;
- _opcodeMap[0x18] = OPCODE_INVENTORY_FULL;
- _opcodeMap[0x19] = OPCODE_TEST_FLAG;
- _opcodeMap[0x1d] = OPCODE_CURRENT_OBJECT_IN_ROOM;
- _opcodeMap[0x20] = OPCODE_HAVE_CURRENT_OBJECT;
- _opcodeMap[0x21] = OPCODE_OBJECT_IS_NOT_NOWHERE;
- _opcodeMap[0x24] = OPCODE_CURRENT_OBJECT_PRESENT;
- _opcodeMap[0x25] = OPCODE_VAR_GT1;
- _opcodeMap[0x29] = OPCODE_VAR_EQ1;
- _opcodeMap[0x2d] = OPCODE_VAR_GTE1;
- _opcodeMap[0x31] = OPCODE_TEST_ROOM_FLAG;
- _opcodeMap[0x41] = OPCODE_NOT_HAVE_OBJECT;
- _opcodeMap[0x45] = OPCODE_NOT_IN_ROOM;
- _opcodeMap[0x48] = OPCODE_CURRENT_OBJECT_NOT_PRESENT;
- _opcodeMap[0x49] = OPCODE_OBJECT_NOT_IN_ROOM;
- _opcodeMap[0x4E] = OPCODE_TEST_FALSE;
- _opcodeMap[0x50] = OPCODE_CURRENT_OBJECT_IS_NOWHERE;
- _opcodeMap[0x59] = OPCODE_TEST_NOT_FLAG;
- _opcodeMap[0x5D] = OPCODE_TEST_FALSE;
- _opcodeMap[0x60] = OPCODE_NOT_HAVE_CURRENT_OBJECT;
- _opcodeMap[0x61] = OPCODE_OBJECT_IS_NOWHERE;
- _opcodeMap[0x64] = OPCODE_CURRENT_OBJECT_NOT_IN_ROOM;
- _opcodeMap[0x68] = OPCODE_CURRENT_OBJECT_NOT_TAKEABLE;
- _opcodeMap[0x71] = OPCODE_TEST_NOT_ROOM_FLAG;
- _opcodeMap[0x80] = OPCODE_INVENTORY;
- _opcodeMap[0x81] = OPCODE_TAKE_OBJECT;
- _opcodeMap[0x82] = OPCODE_MOVE_OBJECT_TO_ROOM;
- _opcodeMap[0x84] = OPCODE_SAVE_ACTION;
- _opcodeMap[0x85] = OPCODE_MOVE_TO_ROOM;
- _opcodeMap[0x86] = OPCODE_VAR_ADD;
- _opcodeMap[0x87] = OPCODE_SET_ROOM_DESCRIPTION;
- _opcodeMap[0x89] = OPCODE_MOVE_OBJECT_TO_CURRENT_ROOM;
- _opcodeMap[0x8a] = OPCODE_VAR_SUB;
- _opcodeMap[0x8b] = OPCODE_SET_OBJECT_DESCRIPTION;
- _opcodeMap[0x8c] = OPCODE_MOVE_DEFAULT;
- _opcodeMap[0x8e] = OPCODE_PRINT;
- _opcodeMap[0x95] = OPCODE_REMOVE_OBJECT;
- _opcodeMap[0x99] = OPCODE_SET_FLAG;
- _opcodeMap[0x92] = OPCODE_CALL_FUNC;
- _opcodeMap[0x98] = OPCODE_TURN_TICK;
- _opcodeMap[0x9d] = OPCODE_CLEAR_FLAG;
- _opcodeMap[0x9e] = OPCODE_INVENTORY_ROOM;
- _opcodeMap[0xa0] = OPCODE_TAKE_CURRENT_OBJECT;
- _opcodeMap[0xa1] = OPCODE_SPECIAL;
- _opcodeMap[0xa4] = OPCODE_DROP_CURRENT_OBJECT;
- _opcodeMap[0xa2] = OPCODE_SET_ROOM_GRAPHIC;
- _opcodeMap[0xb0] = OPCODE_REMOVE_CURRENT_OBJECT;
- _opcodeMap[0xb1] = OPCODE_MOVE_DIR;
- _opcodeMap[0xb9] = OPCODE_SET_STRING_REPLACEMENT;
- _opcodeMap[0xbd] = OPCODE_VAR_INC;
- _opcodeMap[0xc1] = OPCODE_VAR_DEC;
- _opcodeMap[0xc9] = OPCODE_MOVE_CURRENT_OBJECT_TO_ROOM;
-}
-
-void OpcodeMap::loadVersion2() {
- _opcodeMap[0x01] = OPCODE_HAVE_OBJECT;
- _opcodeMap[0x02] = OPCODE_VAR_GT2;
- _opcodeMap[0x04] = OPCODE_OR;
- _opcodeMap[0x05] = OPCODE_IN_ROOM;
- _opcodeMap[0x06] = OPCODE_VAR_EQ2;
- _opcodeMap[0x08] = OPCODE_CURRENT_IS_OBJECT;
- _opcodeMap[0x09] = OPCODE_VAR_GT1;
- _opcodeMap[0x0a] = OPCODE_VAR_GTE2;
- _opcodeMap[0x0c] = OPCODE_ELSE;
- _opcodeMap[0x0d] = OPCODE_VAR_EQ1;
- _opcodeMap[0x11] = OPCODE_OBJECT_IS_NOWHERE;
- _opcodeMap[0x14] = OPCODE_CURRENT_OBJECT_NOT_VALID;
- _opcodeMap[0x19] = OPCODE_TEST_FLAG;
- _opcodeMap[0x1d] = OPCODE_TEST_ROOM_FLAG;
- _opcodeMap[0x20] = OPCODE_HAVE_CURRENT_OBJECT;
- _opcodeMap[0x21] = OPCODE_OBJECT_PRESENT;
- _opcodeMap[0x22] = OPCODE_OBJECT_IN_ROOM;
- _opcodeMap[0x2d] = OPCODE_OBJECT_CAN_TAKE;
- _opcodeMap[0x30] = OPCODE_CURRENT_OBJECT_PRESENT;
- _opcodeMap[0x31] = OPCODE_TEST_ROOM_FLAG;
- _opcodeMap[0x41] = OPCODE_NOT_HAVE_OBJECT;
- _opcodeMap[0x45] = OPCODE_NOT_IN_ROOM;
- _opcodeMap[0x48] = OPCODE_CURRENT_OBJECT_NOT_PRESENT;
- _opcodeMap[0x43] = OPCODE_OBJECT_NOT_IN_ROOM;
- _opcodeMap[0x51] = OPCODE_OBJECT_IS_NOWHERE;
- _opcodeMap[0x59] = OPCODE_TEST_NOT_FLAG;
- _opcodeMap[0x5d] = OPCODE_TEST_NOT_ROOM_FLAG;
- _opcodeMap[0x60] = OPCODE_NOT_HAVE_CURRENT_OBJECT;
- _opcodeMap[0x61] = OPCODE_OBJECT_NOT_PRESENT;
- _opcodeMap[0x70] = OPCODE_CURRENT_OBJECT_NOT_PRESENT;
- _opcodeMap[0x74] = OPCODE_CURRENT_NOT_OBJECT;
- _opcodeMap[0x80] = OPCODE_INVENTORY;
- _opcodeMap[0x81] = OPCODE_TAKE_OBJECT;
- _opcodeMap[0x82] = OPCODE_MOVE_OBJECT_TO_ROOM;
- _opcodeMap[0x84] = OPCODE_SAVE_ACTION;
- _opcodeMap[0x85] = OPCODE_MOVE_TO_ROOM;
- _opcodeMap[0x86] = OPCODE_VAR_ADD;
- _opcodeMap[0x87] = OPCODE_SET_ROOM_DESCRIPTION;
- _opcodeMap[0x89] = OPCODE_SPECIAL;
- _opcodeMap[0x8a] = OPCODE_VAR_SUB;
- _opcodeMap[0x8b] = OPCODE_SET_OBJECT_DESCRIPTION;
- _opcodeMap[0x8c] = OPCODE_MOVE_DEFAULT;
- _opcodeMap[0x8e] = OPCODE_PRINT;
- _opcodeMap[0x8f] = OPCODE_SET_OBJECT_LONG_DESCRIPTION;
- _opcodeMap[0x90] = OPCODE_WAIT_KEY;
- _opcodeMap[0x92] = OPCODE_CALL_FUNC;
- _opcodeMap[0x95] = OPCODE_REMOVE_OBJECT;
- _opcodeMap[0x98] = OPCODE_TURN_TICK;
- _opcodeMap[0x99] = OPCODE_SET_FLAG;
- _opcodeMap[0x9d] = OPCODE_CLEAR_FLAG;
- _opcodeMap[0x9e] = OPCODE_INVENTORY_ROOM;
- _opcodeMap[0xa0] = OPCODE_TAKE_CURRENT_OBJECT;
- _opcodeMap[0xa2] = OPCODE_SET_OBJECT_GRAPHIC;
- _opcodeMap[0xa9] = OPCODE_INVENTORY_FULL;
- _opcodeMap[0xb1] = OPCODE_MOVE_DIR;
- _opcodeMap[0xb5] = OPCODE_DESCRIBE_CURRENT_OBJECT;
- _opcodeMap[0xc1] = OPCODE_VAR_DEC;
- _opcodeMap[0xc2] = OPCODE_SET_ROOM_GRAPHIC;
- _opcodeMap[0xc5] = OPCODE_SET_CURRENT_NOUN_STRING_REPLACEMENT;
- _opcodeMap[0xc6] = OPCODE_SET_OBJECT_GRAPHIC;
- _opcodeMap[0xc9] = OPCODE_MOVE_CURRENT_OBJECT_TO_ROOM;
- _opcodeMap[0xcd] = OPCODE_SET_STRING_REPLACEMENT;
- _opcodeMap[0xd1] = OPCODE_MOVE_DIRECTION;
- _opcodeMap[0xd5] = OPCODE_DRAW_ROOM;
- _opcodeMap[0xd9] = OPCODE_DRAW_OBJECT;
- _opcodeMap[0xdd] = OPCODE_VAR_INC;
- _opcodeMap[0xe1] = OPCODE_MOVE_OBJECT_TO_CURRENT_ROOM;
- _opcodeMap[0xed] = OPCODE_REMOVE_OBJECT;
- _opcodeMap[0xf0] = OPCODE_DROP_CURRENT_OBJECT;
- _opcodeMap[0xfc] = OPCODE_REMOVE_CURRENT_OBJECT;
-}
-
-} // namespace Comprehend
-} // namespace Glk
diff --git a/engines/glk/comprehend/opcode_map.h b/engines/glk/comprehend/opcode_map.h
deleted file mode 100644
index 909183ddb6..0000000000
--- a/engines/glk/comprehend/opcode_map.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- */
-
-#ifndef GLK_COMPREHEND_OPCODE_MAP_H
-#define GLK_COMPREHEND_OPCODE_MAP_H
-
-#include "common/scummsys.h"
-
-namespace Glk {
-namespace Comprehend {
-
-/*
- * Version 2 of the Comprehend engine (OO-Topos) changes some of the opcode
- * numbers and adds new opcodes. This class encapsulates a table to translate
- * the opcodes used in the original games into a generic version used by the engine
- *
- * FIXME - unimplemented/unknown ocpodes:
- *
- * d5(obj): Make object visible. This will print a "you see: object" when the
- * object is in the room.
- */
-class OpcodeMap {
-public:
- byte _opcodeMap[0x100];
-
-private:
- void loadVersion1();
- void loadVersion2();
-
-public:
- void loadOpcodes(int version);
-};
-
-} // namespace Comprehend
-} // namespace Glk
-
-#endif
diff --git a/engines/glk/module.mk b/engines/glk/module.mk
index 24492c8c10..56c538c369 100644
--- a/engines/glk/module.mk
+++ b/engines/glk/module.mk
@@ -172,9 +172,9 @@ MODULE_OBJS := \
comprehend/game_cc.o \
comprehend/game_data.o \
comprehend/game_oo.o \
+ comprehend/game_opcodes.o \
comprehend/game_tm.o \
comprehend/game_tr.o \
- comprehend/opcode_map.o \
comprehend/pics.o \
glulx/accel.o \
glulx/exec.o \
Commit: 6640aa2274fc0e76d3af181e8bb648eea5cf8ed4
https://github.com/scummvm/scummvm/commit/6640aa2274fc0e76d3af181e8bb648eea5cf8ed4
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2020-10-15T20:39:33-07:00
Commit Message:
GLK: COMPREHEND: Starting to properly add v2 opcodes
Changed paths:
engines/glk/comprehend/debugger_dumper.cpp
engines/glk/comprehend/game.cpp
engines/glk/comprehend/game_data.h
engines/glk/comprehend/game_opcodes.cpp
diff --git a/engines/glk/comprehend/debugger_dumper.cpp b/engines/glk/comprehend/debugger_dumper.cpp
index 53e66182af..cb60acacb1 100644
--- a/engines/glk/comprehend/debugger_dumper.cpp
+++ b/engines/glk/comprehend/debugger_dumper.cpp
@@ -109,6 +109,7 @@ DebuggerDumper::DebuggerDumper() : _game(nullptr) {
_opcodes[OPCODE_WAIT_KEY] = "wait_key";
_opcodes[OPCODE_TEST_FALSE] = "test_false";
_opcodes[OPCODE_OBJECT_CAN_TAKE] = "object_can_take";
+ _opcodes[OPCODE_CLEAR_INVISIBLE] = "clear_invisible";
}
Common::String DebuggerDumper::dumpInstruction(ComprehendGame *game,
diff --git a/engines/glk/comprehend/game.cpp b/engines/glk/comprehend/game.cpp
index d55a257443..a6f31fa92c 100644
--- a/engines/glk/comprehend/game.cpp
+++ b/engines/glk/comprehend/game.cpp
@@ -781,8 +781,9 @@ void ComprehendGame::doBeforeTurn() {
// Run the game specific before turn bits
beforeTurn();
- // Run the each turn functions
- eval_function(0, nullptr);
+ if (_comprehendVersion == 1)
+ // Run the each turn functions
+ eval_function(0, nullptr);
update();
}
diff --git a/engines/glk/comprehend/game_data.h b/engines/glk/comprehend/game_data.h
index aebff65dbf..6f02ed2554 100644
--- a/engines/glk/comprehend/game_data.h
+++ b/engines/glk/comprehend/game_data.h
@@ -127,7 +127,8 @@ enum {
OPCODE_CAN_TAKE,
OPCODE_TOO_HEAVY,
OPCODE_NOT_MAX_WEIGHT,
- OPCODE_OBJECT_CAN_TAKE
+ OPCODE_OBJECT_CAN_TAKE,
+ OPCODE_CLEAR_INVISIBLE
};
/* Game state update flags */
diff --git a/engines/glk/comprehend/game_opcodes.cpp b/engines/glk/comprehend/game_opcodes.cpp
index 9aae69a7eb..ce8a2cfd57 100644
--- a/engines/glk/comprehend/game_opcodes.cpp
+++ b/engines/glk/comprehend/game_opcodes.cpp
@@ -34,10 +34,76 @@ ComprehendGameOpcodes::ComprehendGameOpcodes() {
}
void ComprehendGameOpcodes::execute_opcode(const Instruction *instr, const Sentence *sentence,
- FunctionState *func_state, Room *room, Item *&item) {
+ FunctionState *func_state, Room *room, Item *&item) {
+ byte verb = sentence ? sentence->_formattedWords[0] : 0;
+ byte noun = sentence ? sentence->_formattedWords[2] : 0;
+ uint index;
+
+ switch (_opcodeMap[instr->_opcode]) {
+ case OPCODE_OR:
+ if (func_state->_orCount) {
+ func_state->_orCount += 2;
+ } else {
+ func_state->_testResult = false;
+ func_state->_orCount += 3;
+ }
+ break;
+
+ case OPCODE_IN_ROOM:
+ func_set_test_result(func_state,
+ _currentRoom == instr->_operand[0]);
+ break;
+
+ case OPCODE_VAR_EQ2:
+ func_set_test_result(func_state,
+ _variables[instr->_operand[0]] ==
+ _variables[instr->_operand[1]]);
+ break;
+
+ case OPCODE_ELSE:
+ func_state->_testResult = func_state->_elseResult;
+ break;
+
+ case OPCODE_CURRENT_OBJECT_NOT_VALID:
+ func_set_test_result(func_state, !noun);
+ break;
+
+ case OPCODE_TEST_FLAG:
+ func_set_test_result(func_state,
+ _flags[instr->_operand[0]]);
+ break;
+
+ case OPCODE_SET_ROOM_DESCRIPTION:
+ room = get_room(instr->_operand[0]);
+ switch (instr->_operand[2]) {
+ case 0x80:
+ room->_stringDesc = instr->_operand[1];
+ break;
+ case 0x81:
+ room->_stringDesc = instr->_operand[1] + 0x100;
+ break;
+ case 0x82:
+ room->_stringDesc = instr->_operand[1] + 0x200;
+ break;
+ default:
+ error("Bad string desc %.2x:%.2x\n",
+ instr->_operand[1], instr->_operand[2]);
+ break;
+ }
+ break;
-// switch (_opcodeMap[instr->_opcode]) {
-// default:
+ case OPCODE_CALL_FUNC:
+ index = instr->_operand[0];
+ if (instr->_operand[1] == 0x81)
+ index += 256;
+ if (index >= _functions.size())
+ error("Bad function %.4x >= %.4x\n",
+ index, _functions.size());
+
+ eval_function(index, sentence);
+ break;
+
+ default:
if (instr->_opcode & 0x80) {
warning("Unhandled command opcode %.2x", instr->_opcode);
} else {
@@ -45,8 +111,8 @@ void ComprehendGameOpcodes::execute_opcode(const Instruction *instr, const Sente
instr->_opcode);
func_set_test_result(func_state, false);
}
-// break;
-// }
+ break;
+ }
}
void ComprehendGameOpcodes::func_set_test_result(FunctionState *func_state, bool value) {
@@ -145,7 +211,7 @@ void ComprehendGameV1::execute_opcode(const Instruction *instr, const Sentence *
FunctionState *func_state, Room *room, Item *&item) {
byte verb = sentence ? sentence->_formattedWords[0] : 0;
byte noun = sentence ? sentence->_formattedWords[2] : 0;
- uint count, index;
+ uint count;
switch (_opcodeMap[instr->_opcode]) {
case OPCODE_VAR_ADD:
@@ -172,12 +238,6 @@ void ComprehendGameV1::execute_opcode(const Instruction *instr, const Sentence *
_variables[instr->_operand[0]]);
break;
- case OPCODE_VAR_EQ2:
- func_set_test_result(func_state,
- _variables[instr->_operand[0]] ==
- _variables[instr->_operand[1]]);
- break;
-
case OPCODE_VAR_GT1:
func_set_test_result(func_state,
_variables[0] >
@@ -227,11 +287,6 @@ void ComprehendGameV1::execute_opcode(const Instruction *instr, const Sentence *
_currentRoom != instr->_operand[0]);
break;
- case OPCODE_IN_ROOM:
- func_set_test_result(func_state,
- _currentRoom == instr->_operand[0]);
- break;
-
case OPCODE_MOVE_TO_ROOM:
if (instr->_operand[0] != 0xff)
move_to(instr->_operand[0]);
@@ -255,10 +310,6 @@ void ComprehendGameV1::execute_opcode(const Instruction *instr, const Sentence *
console_println(stringLookup(STRING_CANT_GO).c_str());
break;
- case OPCODE_ELSE:
- func_state->_testResult = func_state->_elseResult;
- break;
-
case OPCODE_MOVE_OBJECT_TO_CURRENT_ROOM:
item = get_item(instr->_operand[0] - 1);
move_object(item, _currentRoom);
@@ -409,10 +460,6 @@ void ComprehendGameV1::execute_opcode(const Instruction *instr, const Sentence *
item->_room == _currentRoom);
break;
- case OPCODE_CURRENT_OBJECT_NOT_VALID:
- func_set_test_result(func_state, !noun);
- break;
-
case OPCODE_CURRENT_IS_OBJECT:
func_set_test_result(func_state,
get_item_by_noun(noun) != NULL);
@@ -499,11 +546,6 @@ void ComprehendGameV1::execute_opcode(const Instruction *instr, const Sentence *
move_object(item, ROOM_INVENTORY);
break;
- case OPCODE_TEST_FLAG:
- func_set_test_result(func_state,
- _flags[instr->_operand[0]]);
- break;
-
case OPCODE_TEST_NOT_FLAG:
func_set_test_result(func_state,
!_flags[instr->_operand[0]]);
@@ -517,15 +559,6 @@ void ComprehendGameV1::execute_opcode(const Instruction *instr, const Sentence *
_flags[instr->_operand[0]] = true;
break;
- case OPCODE_OR:
- if (func_state->_orCount) {
- func_state->_orCount += 2;
- } else {
- func_state->_testResult = false;
- func_state->_orCount += 3;
- }
- break;
-
case OPCODE_SET_OBJECT_DESCRIPTION:
item = get_item(instr->_operand[0] - 1);
item->_stringDesc = (instr->_operand[2] << 8) | instr->_operand[1];
@@ -536,25 +569,6 @@ void ComprehendGameV1::execute_opcode(const Instruction *instr, const Sentence *
item->_longString = (instr->_operand[2] << 8) | instr->_operand[1];
break;
- case OPCODE_SET_ROOM_DESCRIPTION:
- room = get_room(instr->_operand[0]);
- switch (instr->_operand[2]) {
- case 0x80:
- room->_stringDesc = instr->_operand[1];
- break;
- case 0x81:
- room->_stringDesc = instr->_operand[1] + 0x100;
- break;
- case 0x82:
- room->_stringDesc = instr->_operand[1] + 0x200;
- break;
- default:
- error("Bad string desc %.2x:%.2x\n",
- instr->_operand[1], instr->_operand[2]);
- break;
- }
- break;
-
case OPCODE_SET_OBJECT_GRAPHIC:
item = get_item(instr->_operand[0] - 1);
item->_graphic = instr->_operand[1];
@@ -569,17 +583,6 @@ void ComprehendGameV1::execute_opcode(const Instruction *instr, const Sentence *
_updateFlags |= UPDATE_GRAPHICS;
break;
- case OPCODE_CALL_FUNC:
- index = instr->_operand[0];
- if (instr->_operand[1] == 0x81)
- index += 256;
- if (index >= _functions.size())
- error("Bad function %.4x >= %.4x\n",
- index, _functions.size());
-
- eval_function(index, sentence);
- break;
-
case OPCODE_TEST_FALSE:
// The original had two opcodes mapped to the same code that does
// a test, but ignores the result, and is always false
@@ -652,19 +655,24 @@ void ComprehendGameV1::execute_opcode(const Instruction *instr, const Sentence *
/*-------------------------------------------------------*/
ComprehendGameV2::ComprehendGameV2() {
- _opcodeMap[0x01] = OPCODE_HAVE_OBJECT;
- _opcodeMap[0x02] = OPCODE_VAR_GT2;
_opcodeMap[0x04] = OPCODE_OR;
_opcodeMap[0x05] = OPCODE_IN_ROOM;
_opcodeMap[0x06] = OPCODE_VAR_EQ2;
+ _opcodeMap[0x0c] = OPCODE_ELSE;
+ _opcodeMap[0x14] = OPCODE_CURRENT_OBJECT_NOT_VALID;
+ _opcodeMap[0x19] = OPCODE_TEST_FLAG;
+ _opcodeMap[0x87] = OPCODE_SET_ROOM_DESCRIPTION;
+ _opcodeMap[0x92] = OPCODE_CALL_FUNC;
+ _opcodeMap[0xa9] = OPCODE_CLEAR_INVISIBLE;
+
+#if 0
+ _opcodeMap[0x01] = OPCODE_HAVE_OBJECT;
+ _opcodeMap[0x02] = OPCODE_VAR_GT2;
_opcodeMap[0x08] = OPCODE_CURRENT_IS_OBJECT;
_opcodeMap[0x09] = OPCODE_VAR_GT1;
_opcodeMap[0x0a] = OPCODE_VAR_GTE2;
- _opcodeMap[0x0c] = OPCODE_ELSE;
_opcodeMap[0x0d] = OPCODE_VAR_EQ1;
_opcodeMap[0x11] = OPCODE_OBJECT_IS_NOWHERE;
- _opcodeMap[0x14] = OPCODE_CURRENT_OBJECT_NOT_VALID;
- _opcodeMap[0x19] = OPCODE_TEST_FLAG;
_opcodeMap[0x1d] = OPCODE_TEST_ROOM_FLAG;
_opcodeMap[0x20] = OPCODE_HAVE_CURRENT_OBJECT;
_opcodeMap[0x21] = OPCODE_OBJECT_PRESENT;
@@ -689,7 +697,6 @@ ComprehendGameV2::ComprehendGameV2() {
_opcodeMap[0x84] = OPCODE_SAVE_ACTION;
_opcodeMap[0x85] = OPCODE_MOVE_TO_ROOM;
_opcodeMap[0x86] = OPCODE_VAR_ADD;
- _opcodeMap[0x87] = OPCODE_SET_ROOM_DESCRIPTION;
_opcodeMap[0x89] = OPCODE_SPECIAL;
_opcodeMap[0x8a] = OPCODE_VAR_SUB;
_opcodeMap[0x8b] = OPCODE_SET_OBJECT_DESCRIPTION;
@@ -697,7 +704,6 @@ ComprehendGameV2::ComprehendGameV2() {
_opcodeMap[0x8e] = OPCODE_PRINT;
_opcodeMap[0x8f] = OPCODE_SET_OBJECT_LONG_DESCRIPTION;
_opcodeMap[0x90] = OPCODE_WAIT_KEY;
- _opcodeMap[0x92] = OPCODE_CALL_FUNC;
_opcodeMap[0x95] = OPCODE_REMOVE_OBJECT;
_opcodeMap[0x98] = OPCODE_TURN_TICK;
_opcodeMap[0x99] = OPCODE_SET_FLAG;
@@ -722,13 +728,21 @@ ComprehendGameV2::ComprehendGameV2() {
_opcodeMap[0xed] = OPCODE_REMOVE_OBJECT;
_opcodeMap[0xf0] = OPCODE_DROP_CURRENT_OBJECT;
_opcodeMap[0xfc] = OPCODE_REMOVE_CURRENT_OBJECT;
+#endif
}
void ComprehendGameV2::execute_opcode(const Instruction *instr, const Sentence *sentence,
FunctionState *func_state, Room *room, Item *&item) {
byte noun = sentence ? sentence->_formattedWords[2] : 0;
- switch (_opcodeMap[instr->_opcode]) {
+ // Special pre-processing for opcodes
+ byte opcode = instr->_opcode;
+ if ((opcode & 0x30) == 0x30) {
+ // TODO: Check if getCurrentObjectRoom call in original is needed in ScummVM
+ opcode = (opcode & ~0x10) + 1;
+ }
+
+ switch (_opcodeMap[opcode]) {
case OPCODE_INVENTORY_FULL:
item = get_item_by_noun(noun);
@@ -738,6 +752,11 @@ void ComprehendGameV2::execute_opcode(const Instruction *instr, const Sentence *
_variables[VAR_INVENTORY_LIMIT]);
break;
+ case OPCODE_CLEAR_INVISIBLE:
+ item = get_item_by_noun(noun);
+ item->_flags &= ~ITEMF_INVISIBLE;
+ break;
+
default:
ComprehendGameOpcodes::execute_opcode(instr, sentence, func_state, room, item);
break;
More information about the Scummvm-git-logs
mailing list