mirror of
https://github.com/libretro/scummvm.git
synced 2025-04-02 06:41:51 +00:00
ADL: Partially implement hires5 opcodes
This commit is contained in:
parent
f29a2f31f1
commit
1f801bee43
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
|
@ -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 ®ion = getCurRegion();
|
||||
|
||||
for (uint i = 0; i < region.vars.size(); ++i)
|
||||
region.vars[i] = getVar(i);
|
||||
}
|
||||
|
||||
void AdlEngine_v4::restoreVars() {
|
||||
const Region ®ion = 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
|
||||
|
@ -63,6 +63,24 @@ protected:
|
||||
void fixupDiskOffset(byte &track, byte §or) 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;
|
||||
|
@ -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() {
|
||||
|
Loading…
x
Reference in New Issue
Block a user