[Scummvm-git-logs] scummvm master -> 1f801bee433624e8bde214264a2d0c2359be4c13

waltervn walter at vanniftrik-it.nl
Fri Dec 16 15:35:15 CET 2016


This automated email contains information about 1 new commit which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .

Summary:
1f801bee43 ADL: Partially implement hires5 opcodes


Commit: 1f801bee433624e8bde214264a2d0c2359be4c13
    https://github.com/scummvm/scummvm/commit/1f801bee433624e8bde214264a2d0c2359be4c13
Author: Walter van Niftrik (walter at scummvm.org)
Date: 2016-12-16T15:29:38+01:00

Commit Message:
ADL: Partially implement hires5 opcodes

Changed paths:
    engines/adl/adl.cpp
    engines/adl/adl.h
    engines/adl/adl_v2.cpp
    engines/adl/adl_v4.cpp
    engines/adl/adl_v4.h
    engines/adl/hires5.cpp


diff --git a/engines/adl/adl.cpp b/engines/adl/adl.cpp
index 76f5bac..0d96cb6 100644
--- a/engines/adl/adl.cpp
+++ b/engines/adl/adl.cpp
@@ -428,6 +428,20 @@ void AdlEngine::bell(uint count) const {
 	_speaker->bell(count);
 }
 
+const Region &AdlEngine::getRegion(uint i) const {
+	if (i < 1 || i > _state.regions.size())
+		error("Region %i out of range [1, %i]", i, _state.regions.size());
+
+	return _state.regions[i - 1];
+}
+
+Region &AdlEngine::getRegion(uint i) {
+	if (i < 1 || i > _state.regions.size())
+		error("Region %i out of range [1, %i]", i, _state.regions.size());
+
+	return _state.regions[i - 1];
+}
+
 const Room &AdlEngine::getRoom(uint i) const {
 	if (i < 1 || i > _state.rooms.size())
 		error("Room %i out of range [1, %i]", i, _state.rooms.size());
@@ -442,6 +456,14 @@ Room &AdlEngine::getRoom(uint i) {
 	return _state.rooms[i - 1];
 }
 
+const Region &AdlEngine::getCurRegion() const {
+	return getRegion(_state.region);
+}
+
+Region &AdlEngine::getCurRegion() {
+	return getRegion(_state.region);
+}
+
 const Room &AdlEngine::getCurRoom() const {
 	return getRoom(_state.room);
 }
diff --git a/engines/adl/adl.h b/engines/adl/adl.h
index 06be0e0..a825200 100644
--- a/engines/adl/adl.h
+++ b/engines/adl/adl.h
@@ -143,6 +143,7 @@ enum {
 struct Item {
 	byte id;
 	byte noun;
+	byte region;
 	byte room;
 	byte picture;
 	bool isLineArt;
@@ -175,14 +176,14 @@ struct State {
 	Common::List<Item> items;
 	Common::Array<byte> vars;
 
-	byte region;
+	byte region, prevRegion;
 	byte room;
 	byte curPicture;
 	uint16 moves;
 	bool isDark;
 	Time time;
 
-	State() : region(0), room(1), curPicture(0), moves(1), isDark(false) { }
+	State() : region(0), prevRegion(0), room(1), curPicture(0), moves(1), isDark(false) { }
 };
 
 typedef Common::List<Command> Commands;
@@ -300,8 +301,12 @@ protected:
 	void bell(uint count = 1) const;
 
 	// Game state functions
+	const Region &getRegion(uint i) const;
+	Region &getRegion(uint i);
 	const Room &getRoom(uint i) const;
 	Room &getRoom(uint i);
+	const Region &getCurRegion() const;
+	Region &getCurRegion();
 	const Room &getCurRoom() const;
 	Room &getCurRoom();
 	const Item &getItem(uint i) const;
@@ -309,7 +314,7 @@ protected:
 	byte getVar(uint i) const;
 	void setVar(uint i, byte value);
 	virtual void takeItem(byte noun);
-	void dropItem(byte noun);
+	virtual void dropItem(byte noun);
 	bool matchCommand(ScriptEnv &env) const;
 	void doActions(ScriptEnv &env);
 	bool doOneCommand(const Commands &commands, byte verb, byte noun);
diff --git a/engines/adl/adl_v2.cpp b/engines/adl/adl_v2.cpp
index 45810d6..b34d4c9 100644
--- a/engines/adl/adl_v2.cpp
+++ b/engines/adl/adl_v2.cpp
@@ -372,7 +372,7 @@ void AdlEngine_v2::loadItems(Common::ReadStream &stream) {
 		item.noun = stream.readByte();
 		item.room = stream.readByte();
 		item.picture = stream.readByte();
-		item.isLineArt = stream.readByte(); // Disk number in later games
+		item.region = stream.readByte();
 		item.position.x = stream.readByte();
 		item.position.y = stream.readByte();
 		item.state = stream.readByte();
diff --git a/engines/adl/adl_v4.cpp b/engines/adl/adl_v4.cpp
index 00a393f..6dfee80 100644
--- a/engines/adl/adl_v4.cpp
+++ b/engines/adl/adl_v4.cpp
@@ -195,13 +195,14 @@ void AdlEngine_v4::loadRegion(byte region) {
 			break;
 		}
 		case 0x7b00:
-			// Global commands
-			readCommands(*stream, _globalCommands);
-			break;
-		case 0x9500:
+			// TODO: hires6 has global and room lists swapped
 			// Room commands
 			readCommands(*stream, _roomCommands);
 			break;
+		case 0x9500:
+			// Global commands
+			readCommands(*stream, _globalCommands);
+			break;
 		default:
 			error("Unknown data block found (addr %04x; size %04x)", addr, size);
 		}
@@ -216,6 +217,8 @@ void AdlEngine_v4::loadRegion(byte region) {
 			}
 		}
 	}
+
+	restoreVars();
 }
 
 void AdlEngine_v4::loadItemPicIndex(Common::ReadStream &stream, uint items) {
@@ -225,4 +228,205 @@ void AdlEngine_v4::loadItemPicIndex(Common::ReadStream &stream, uint items) {
 		error("Error reading item index");
 }
 
+void AdlEngine_v4::backupRoomState(byte room) {
+	RoomState &backup = getCurRegion().rooms[room - 1];
+
+	backup.isFirstTime = getRoom(room).isFirstTime;
+	backup.picture = getRoom(room).picture;
+}
+
+void AdlEngine_v4::restoreRoomState(byte room) {
+	const RoomState &backup = getCurRegion().rooms[room - 1];
+
+	getRoom(room).isFirstTime = backup.isFirstTime;
+	getRoom(room).picture = backup.picture;
+}
+
+void AdlEngine_v4::backupVars() {
+	Region &region = getCurRegion();
+
+	for (uint i = 0; i < region.vars.size(); ++i)
+		region.vars[i] = getVar(i);
+}
+
+void AdlEngine_v4::restoreVars() {
+	const Region &region = getCurRegion();
+
+	for (uint i = 0; i < region.vars.size(); ++i)
+		setVar(i, region.vars[i]);
+}
+
+void AdlEngine_v4::switchRegion(byte region) {
+	backupVars();
+	backupRoomState(_state.room);
+	_state.prevRegion = _state.region;
+	_state.region = region;
+	loadRegion(region);
+	_state.room = 1;
+	_picOnScreen = _roomOnScreen = 0;
+}
+
+// TODO: Merge this into v2?
+void AdlEngine_v4::takeItem(byte noun) {
+	Common::List<Item>::iterator item;
+
+	for (item = _state.items.begin(); item != _state.items.end(); ++item) {
+		if (item->noun != noun || item->room != _state.room || item->region != _state.region)
+			continue;
+
+		if (item->state == IDI_ITEM_DOESNT_MOVE) {
+			printMessage(_messageIds.itemDoesntMove);
+			return;
+		}
+
+		if (item->state == IDI_ITEM_DROPPED) {
+			item->room = IDI_ANY;
+			_itemRemoved = true;
+			return;
+		}
+
+		Common::Array<byte>::const_iterator pic;
+		for (pic = item->roomPictures.begin(); pic != item->roomPictures.end(); ++pic) {
+			if (*pic == getCurRoom().curPicture || *pic == IDI_ANY) {
+				if (!isInventoryFull()) {
+					item->room = IDI_ANY;
+					_itemRemoved = true;
+					item->state = IDI_ITEM_DROPPED;
+				}
+				return;
+			}
+		}
+	}
+
+	printMessage(_messageIds.itemNotHere);
+}
+
+// TODO: Merge this into v2?
+void AdlEngine_v4::dropItem(byte noun) {
+	Common::List<Item>::iterator item;
+
+	for (item = _state.items.begin(); item != _state.items.end(); ++item) {
+		if (item->noun != noun || item->room != IDI_ANY)
+			continue;
+
+		item->room = _state.room;
+		item->region = _state.region;
+		item->state = IDI_ITEM_DROPPED;
+		return;
+	}
+
+	printMessage(_messageIds.dontUnderstand);
+}
+
+int AdlEngine_v4::o4_isItemInRoom(ScriptEnv &e) {
+	OP_DEBUG_2("\t&& GET_ITEM_ROOM(%s) == %s", itemStr(e.arg(1)).c_str(), itemRoomStr(e.arg(2)).c_str());
+
+	const Item &item = getItem(e.arg(1));
+
+	if (e.arg(2) != IDI_ANY && item.region != _state.region)
+		return -1;
+
+	if (item.room == roomArg(e.arg(2)))
+		return 2;
+
+	return -1;
+}
+
+int AdlEngine_v4::o4_isVarGT(ScriptEnv &e) {
+	OP_DEBUG_2("\t&& VARS[%d] > %d", e.arg(1), e.arg(2));
+
+	if (getVar(e.arg(1)) > e.arg(2))
+		return 2;
+
+	return -1;
+}
+
+int AdlEngine_v4::o4_moveItem(ScriptEnv &e) {
+	o2_moveItem(e);
+	getItem(e.arg(1)).region = _state.region;
+	return 2;
+}
+
+int AdlEngine_v4::o4_setRoom(ScriptEnv &e) {
+	OP_DEBUG_1("\tROOM = %d", e.arg(1));
+
+	getCurRoom().curPicture = getCurRoom().picture;
+	getCurRoom().isFirstTime = false;
+	backupRoomState(_state.room);
+	_state.room = e.arg(1);
+	restoreRoomState(_state.room);
+	return 1;
+}
+
+int AdlEngine_v4::o4_setRegionToPrev(ScriptEnv &e) {
+	OP_DEBUG_0("\tREGION = PREV_REGION");
+
+	switchRegion(_state.prevRegion);
+	// Long jump
+	_isRestarting = true;
+	return -1;
+}
+
+int AdlEngine_v4::o4_moveAllItems(ScriptEnv &e) {
+	OP_DEBUG_2("\tMOVE_ALL_ITEMS(%s, %s)", itemRoomStr(e.arg(1)).c_str(), itemRoomStr(e.arg(2)).c_str());
+
+	byte room1 = roomArg(e.arg(1));
+
+	if (room1 == _state.room)
+		_picOnScreen = 0;
+
+	byte room2 = roomArg(e.arg(2));
+
+	Common::List<Item>::iterator item;
+
+	for (item = _state.items.begin(); item != _state.items.end(); ++item) {
+		if (room1 != item->room)
+			continue;
+
+		if (room1 != IDI_ANY) {
+			if (_state.region != item->region)
+				continue;
+			if (room2 == IDI_ANY) {
+				if (isInventoryFull())
+					break;
+				if (item->state == IDI_ITEM_DOESNT_MOVE)
+					continue;
+			}
+		}
+
+		item->room = room2;
+		item->region = _state.region;
+
+		if (room1 == IDI_ANY)
+			item->state = IDI_ITEM_DROPPED;
+	}
+
+	return 2;
+}
+
+int AdlEngine_v4::o4_setRegion(ScriptEnv &e) {
+	OP_DEBUG_1("\tREGION = %d", e.arg(1));
+
+	switchRegion(e.arg(1));
+	// Long jump
+	_isRestarting = true;
+	return -1;
+}
+
+int AdlEngine_v4::o4_setRegionRoom(ScriptEnv &e) {
+	OP_DEBUG_2("\tSET_REGION_ROOM(%d, %d)", e.arg(1), e.arg(2));
+
+	switchRegion(e.arg(1));
+	_state.room = e.arg(2);
+	// Long jump
+	_isRestarting = true;
+	return -1;
+}
+
+int AdlEngine_v4::o4_setRoomPic(ScriptEnv &e) {
+	o1_setRoomPic(e);
+	backupRoomState(e.arg(1));
+	return 2;
+}
+
 } // End of namespace Adl
diff --git a/engines/adl/adl_v4.h b/engines/adl/adl_v4.h
index 2a5ceb4..8516e40 100644
--- a/engines/adl/adl_v4.h
+++ b/engines/adl/adl_v4.h
@@ -63,6 +63,24 @@ protected:
 	void fixupDiskOffset(byte &track, byte &sector) const;
 	void loadRegion(byte region);
 	void loadItemPicIndex(Common::ReadStream &stream, uint items);
+	void backupRoomState(byte room);
+	void restoreRoomState(byte room);
+	void backupVars();
+	void restoreVars();
+	void switchRegion(byte region);
+	virtual bool isInventoryFull() { return false; }
+	virtual void takeItem(byte noun);
+	virtual void dropItem(byte noun);
+
+	int o4_isItemInRoom(ScriptEnv &e);
+	int o4_isVarGT(ScriptEnv &e);
+	int o4_moveItem(ScriptEnv &e);
+	int o4_setRoom(ScriptEnv &e);
+	int o4_setRegionToPrev(ScriptEnv &e);
+	int o4_moveAllItems(ScriptEnv &e);
+	int o4_setRegion(ScriptEnv &e);
+	int o4_setRegionRoom(ScriptEnv &e);
+	int o4_setRoomPic(ScriptEnv &e);
 
 	byte _currentVolume;
 	Common::Array<RegionLocation> _regionLocations;
diff --git a/engines/adl/hires5.cpp b/engines/adl/hires5.cpp
index d33fd8a..f298cec 100644
--- a/engines/adl/hires5.cpp
+++ b/engines/adl/hires5.cpp
@@ -41,14 +41,159 @@ public:
 
 private:
 	// AdlEngine
+	void setupOpcodeTables();
 	void runIntro();
 	void init();
 	void initGameState();
 
+	// AdlEngine_v4
+	bool isInventoryFull();
+
+	int o_checkItemTimeLimits(ScriptEnv &e);
+	int o_startAnimation(ScriptEnv &e);
+	int o_winGame(ScriptEnv &e);
+
 	static const uint kRegions = 41;
 	static const uint kItems = 69;
+
+	Common::Array<byte> _itemTimeLimits;
+	Common::String _itemTimeLimitMsg;
+
+	struct {
+		Common::String itemTimeLimit;
+		Common::String carryingTooMuch;
+	} _gameStrings;
 };
 
+typedef Common::Functor1Mem<ScriptEnv &, int, HiRes5Engine> OpcodeH5;
+#define SetOpcodeTable(x) table = &x;
+#define Opcode(x) table->push_back(new OpcodeH5(this, &HiRes5Engine::x))
+#define OpcodeUnImpl() table->push_back(new OpcodeH5(this, 0))
+
+void HiRes5Engine::setupOpcodeTables() {
+	Common::Array<const Opcode *> *table = 0;
+
+	SetOpcodeTable(_condOpcodes);
+	// 0x00
+	OpcodeUnImpl();
+	Opcode(o2_isFirstTime);
+	Opcode(o2_isRandomGT);
+	Opcode(o4_isItemInRoom);
+	// 0x04
+	Opcode(o3_isNounNotInRoom);
+	Opcode(o1_isMovesGT);
+	Opcode(o1_isVarEQ);
+	Opcode(o2_isCarryingSomething);
+	// 0x08
+	Opcode(o4_isVarGT);
+	Opcode(o1_isCurPicEQ);
+	OpcodeUnImpl();
+
+	SetOpcodeTable(_actOpcodes);
+	// 0x00
+	OpcodeUnImpl();
+	Opcode(o1_varAdd);
+	Opcode(o1_varSub);
+	Opcode(o1_varSet);
+	// 0x04
+	Opcode(o1_listInv);
+	Opcode(o4_moveItem);
+	Opcode(o4_setRoom);
+	Opcode(o2_setCurPic);
+	// 0x08
+	Opcode(o2_setPic);
+	Opcode(o1_printMsg);
+	Opcode(o4_setRegionToPrev);
+	Opcode(o_checkItemTimeLimits);
+	// 0x0c
+	Opcode(o4_moveAllItems);
+	Opcode(o1_quit);
+	Opcode(o4_setRegion);
+	Opcode(o2_save); // TODO
+	// 0x10
+	Opcode(o2_restore); // TODO
+	Opcode(o1_restart); // TODO
+	Opcode(o4_setRegionRoom);
+	Opcode(o_startAnimation);
+	// 0x14
+	Opcode(o1_resetPic);
+	Opcode(o1_goDirection<IDI_DIR_NORTH>);
+	Opcode(o1_goDirection<IDI_DIR_SOUTH>);
+	Opcode(o1_goDirection<IDI_DIR_EAST>);
+	// 0x18
+	Opcode(o1_goDirection<IDI_DIR_WEST>);
+	Opcode(o1_goDirection<IDI_DIR_UP>);
+	Opcode(o1_goDirection<IDI_DIR_DOWN>);
+	Opcode(o1_takeItem);
+	// 0x1c
+	Opcode(o1_dropItem);
+	Opcode(o4_setRoomPic);
+	Opcode(o_winGame);
+	OpcodeUnImpl();
+	// 0x20
+	Opcode(o2_initDisk);
+}
+
+bool HiRes5Engine::isInventoryFull() {
+	Common::List<Item>::const_iterator item;
+	byte weight = 0;
+
+	for (item = _state.items.begin(); item != _state.items.end(); ++item) {
+		if (item->room == IDI_ANY)
+			weight += item->description;
+	}
+
+	if (weight >= 100) {
+		printString(_gameStrings.carryingTooMuch);
+		inputString();
+		return true;
+	}
+
+	return false;
+}
+
+int HiRes5Engine::o_checkItemTimeLimits(ScriptEnv &e) {
+	OP_DEBUG_1("\tCHECK_ITEM_TIME_LIMITS(VARS[%d])", e.arg(1));
+
+	bool lostAnItem = false;
+	Common::List<Item>::iterator item;
+
+	for (item = _state.items.begin(); item != _state.items.end(); ++item) {
+		const byte room = item->room;
+		const byte region = item->region;
+
+		if (room == IDI_ANY || room == IDI_CUR_ROOM || (room == _state.room && region == _state.region)) {
+			if (getVar(e.arg(1)) < _itemTimeLimits[item->id - 1]) {
+				item->room = IDI_VOID_ROOM;
+				lostAnItem = true;
+			}
+		}
+	}
+
+	if (lostAnItem) {
+		printString(_gameStrings.itemTimeLimit);
+		inputString();
+	}
+
+	return 1;
+}
+
+int HiRes5Engine::o_startAnimation(ScriptEnv &e) {
+	OP_DEBUG_0("\tSTART_ANIMATION()");
+
+	// TODO: sets a flag that triggers an animation
+
+	return 0;
+}
+
+int HiRes5Engine::o_winGame(ScriptEnv &e) {
+	OP_DEBUG_0("\tWIN_GAME()");
+
+	// TODO: draws room and plays music
+
+	return o1_quit(e);
+}
+
 void HiRes5Engine::runIntro() {
 	insertDisk(2);
 
@@ -114,8 +259,18 @@ void HiRes5Engine::init() {
 	stream.reset(_disk->createReadStream(0xb, 0xa, 0x05, 1));
 	loadItemPicIndex(*stream, kItems);
 
+	stream.reset(_disk->createReadStream(0x7, 0x8, 0x01));
+	for (uint i = 0; i < kItems; ++i)
+		_itemTimeLimits.push_back(stream->readByte());
+
 	if (stream->eos() || stream->err())
-		error("Error reading item index");
+		error("Failed to read item time limits");
+
+	stream.reset(_disk->createReadStream(0x8, 0x2, 0x2d));
+	_gameStrings.itemTimeLimit = readString(*stream);
+
+	stream.reset(_disk->createReadStream(0x8, 0x7, 0x02));
+	_gameStrings.carryingTooMuch = readString(*stream);
 }
 
 void HiRes5Engine::initGameState() {





More information about the Scummvm-git-logs mailing list