mirror of
https://github.com/libretro/scummvm.git
synced 2024-12-25 19:25:20 +00:00
0ce2ca4e00
MKID_BE relied on unspecified behavior of the C++ compiler, and as such was always a bit unsafe. The new MKTAG macro is slightly less elegant, but does no longer depend on the behavior of the compiler. Inspired by FFmpeg, which has an almost identical macro.
1309 lines
33 KiB
C++
1309 lines
33 KiB
C++
/* 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.
|
|
*
|
|
* $URL$
|
|
* $Id$
|
|
*
|
|
*/
|
|
|
|
#include "agi/preagi.h"
|
|
#include "agi/preagi_winnie.h"
|
|
#include "agi/graphics.h"
|
|
|
|
#include "graphics/cursorman.h"
|
|
|
|
#include "common/events.h"
|
|
#include "common/memstream.h"
|
|
#include "common/savefile.h"
|
|
|
|
namespace Agi {
|
|
|
|
void Winnie::parseRoomHeader(WTP_ROOM_HDR *roomHdr, byte *buffer, int len) {
|
|
int i;
|
|
|
|
Common::MemoryReadStreamEndian readS(buffer, len, _isBigEndian);
|
|
|
|
roomHdr->roomNumber = readS.readByte();
|
|
roomHdr->objId = readS.readByte();
|
|
roomHdr->ofsPic = readS.readUint16();
|
|
roomHdr->fileLen = readS.readUint16();
|
|
roomHdr->reserved0 = readS.readUint16();
|
|
|
|
for (i = 0; i < IDI_WTP_MAX_DIR; i++)
|
|
roomHdr->roomNew[i] = readS.readByte();
|
|
|
|
roomHdr->objX = readS.readByte();
|
|
roomHdr->objY = readS.readByte();
|
|
|
|
roomHdr->reserved1 = readS.readUint16();
|
|
|
|
for (i = 0; i < IDI_WTP_MAX_BLOCK; i++)
|
|
roomHdr->ofsDesc[i] = readS.readUint16();
|
|
|
|
for (i = 0; i < IDI_WTP_MAX_BLOCK; i++)
|
|
roomHdr->ofsBlock[i] = readS.readUint16();
|
|
|
|
for (i = 0; i < IDI_WTP_MAX_STR; i++)
|
|
roomHdr->ofsStr[i] = readS.readUint16();
|
|
|
|
roomHdr->reserved2 = readS.readUint32();
|
|
|
|
for (i = 0; i < IDI_WTP_MAX_BLOCK; i++)
|
|
for (byte j = 0; j < IDI_WTP_MAX_BLOCK; j++)
|
|
roomHdr->opt[i].ofsOpt[j] = readS.readUint16();
|
|
}
|
|
|
|
void Winnie::parseObjHeader(WTP_OBJ_HDR *objHdr, byte *buffer, int len) {
|
|
int i;
|
|
|
|
Common::MemoryReadStreamEndian readS(buffer, len, _isBigEndian);
|
|
|
|
objHdr->fileLen = readS.readUint16();
|
|
objHdr->objId = readS.readUint16();
|
|
|
|
for (i = 0; i < IDI_WTP_MAX_OBJ_STR_END; i++)
|
|
objHdr->ofsEndStr[i] = readS.readUint16();
|
|
|
|
for (i = 0; i < IDI_WTP_MAX_OBJ_STR; i++)
|
|
objHdr->ofsStr[i] = readS.readUint16();
|
|
|
|
objHdr->ofsPic = readS.readUint16();
|
|
}
|
|
|
|
uint32 Winnie::readRoom(int iRoom, uint8 *buffer, WTP_ROOM_HDR &roomHdr) {
|
|
char szFile[256] = {0};
|
|
|
|
if (_vm->getPlatform() == Common::kPlatformPC)
|
|
sprintf(szFile, IDS_WTP_ROOM_DOS, iRoom);
|
|
else if (_vm->getPlatform() == Common::kPlatformAmiga)
|
|
sprintf(szFile, IDS_WTP_ROOM_AMIGA, iRoom);
|
|
else if (_vm->getPlatform() == Common::kPlatformC64)
|
|
sprintf(szFile, IDS_WTP_ROOM_C64, iRoom);
|
|
else if (_vm->getPlatform() == Common::kPlatformApple2GS)
|
|
sprintf(szFile, IDS_WTP_ROOM_APPLE, iRoom);
|
|
Common::File file;
|
|
if (!file.open(szFile)) {
|
|
warning ("Could not open file \'%s\'", szFile);
|
|
return 0;
|
|
}
|
|
uint32 filelen = file.size();
|
|
if (_vm->getPlatform() == Common::kPlatformC64) { //Skip the loading address
|
|
filelen -= 2;
|
|
file.seek(2, SEEK_CUR);
|
|
}
|
|
memset(buffer, 0, sizeof(buffer));
|
|
file.read(buffer, filelen);
|
|
file.close();
|
|
|
|
parseRoomHeader(&roomHdr, buffer, filelen);
|
|
|
|
return filelen;
|
|
}
|
|
|
|
uint32 Winnie::readObj(int iObj, uint8 *buffer) {
|
|
char szFile[256] = {0};
|
|
if (_vm->getPlatform() == Common::kPlatformPC)
|
|
sprintf(szFile, IDS_WTP_OBJ_DOS, iObj);
|
|
else if (_vm->getPlatform() == Common::kPlatformAmiga)
|
|
sprintf(szFile, IDS_WTP_OBJ_AMIGA, iObj);
|
|
else if (_vm->getPlatform() == Common::kPlatformC64)
|
|
sprintf(szFile, IDS_WTP_OBJ_C64, iObj);
|
|
else if (_vm->getPlatform() == Common::kPlatformApple2GS)
|
|
sprintf(szFile, IDS_WTP_OBJ_APPLE, iObj);
|
|
Common::File file;
|
|
if (!file.open(szFile)) {
|
|
warning ("Could not open file \'%s\'", szFile);
|
|
return 0;
|
|
}
|
|
uint32 filelen = file.size();
|
|
if (_vm->getPlatform() == Common::kPlatformC64) { //Skip the loading address
|
|
filelen -= 2;
|
|
file.seek(2, SEEK_CUR);
|
|
}
|
|
memset(buffer, 0, sizeof(buffer));
|
|
file.read(buffer, filelen);
|
|
file.close();
|
|
return filelen;
|
|
}
|
|
|
|
void Winnie::randomize() {
|
|
int iObj = 0;
|
|
int iRoom = 0;
|
|
bool done;
|
|
|
|
for (int i = 0; i < IDI_WTP_MAX_OBJ_MISSING; i++) {
|
|
done = false;
|
|
|
|
while (!done) {
|
|
iObj = _vm->rnd(IDI_WTP_MAX_OBJ - 1);
|
|
done = true;
|
|
|
|
for (int j = 0; j < IDI_WTP_MAX_OBJ_MISSING; j++) {
|
|
if (_game.iUsedObj[j] == iObj) {
|
|
done = false;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
_game.iUsedObj[i] = iObj;
|
|
|
|
done = false;
|
|
while (!done) {
|
|
iRoom = _vm->rnd(IDI_WTP_MAX_ROOM_NORMAL);
|
|
done = true;
|
|
|
|
for (int j = 0; j < IDI_WTP_MAX_ROOM_OBJ; j++) {
|
|
if (_game.iObjRoom[j] == iRoom) {
|
|
done = false;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
_game.iObjRoom[iObj] = iRoom;
|
|
}
|
|
}
|
|
|
|
void Winnie::intro() {
|
|
drawPic(IDS_WTP_FILE_LOGO);
|
|
_vm->printStr(IDS_WTP_INTRO_0);
|
|
_vm->_gfx->doUpdate();
|
|
_vm->_system->updateScreen();
|
|
_vm->_system->delayMillis(0x640);
|
|
|
|
if (_vm->getPlatform() == Common::kPlatformAmiga)
|
|
_vm->_gfx->clearScreen(0);
|
|
|
|
drawPic(IDS_WTP_FILE_TITLE);
|
|
|
|
_vm->printStr(IDS_WTP_INTRO_1);
|
|
_vm->_gfx->doUpdate();
|
|
_vm->_system->updateScreen();
|
|
_vm->_system->delayMillis(0x640);
|
|
|
|
if (!playSound(IDI_WTP_SND_POOH_0))
|
|
return;
|
|
|
|
if (!playSound(IDI_WTP_SND_POOH_1))
|
|
return;
|
|
|
|
if (!playSound(IDI_WTP_SND_POOH_2))
|
|
return;
|
|
}
|
|
|
|
int Winnie::getObjInRoom(int iRoom) {
|
|
for (int iObj = 1; iObj < IDI_WTP_MAX_ROOM_OBJ; iObj++)
|
|
if (_game.iObjRoom[iObj] == iRoom)
|
|
return iObj;
|
|
return 0;
|
|
}
|
|
|
|
#define setTakeDrop() {\
|
|
if (getObjInRoom(_room))\
|
|
fCanSel[IDI_WTP_SEL_TAKE] = true;\
|
|
else\
|
|
fCanSel[IDI_WTP_SEL_TAKE] = false;\
|
|
if (_game.iObjHave)\
|
|
fCanSel[IDI_WTP_SEL_DROP] = true;\
|
|
else\
|
|
fCanSel[IDI_WTP_SEL_DROP] = false;\
|
|
}
|
|
|
|
void Winnie::setFlag(int iFlag) {
|
|
_game.fGame[iFlag] = 1;
|
|
}
|
|
|
|
void Winnie::clearFlag(int iFlag) {
|
|
_game.fGame[iFlag] = 0;
|
|
}
|
|
|
|
int Winnie::parser(int pc, int index, uint8 *buffer) {
|
|
WTP_ROOM_HDR hdr;
|
|
int startpc = pc;
|
|
int8 opcode;
|
|
int iNewRoom = 0;
|
|
|
|
int iSel, iDir, iBlock;
|
|
int fCanSel[IDI_WTP_SEL_LAST + 1];
|
|
char szMenu[121] = {0};
|
|
bool done;
|
|
int fBlock;
|
|
|
|
// extract header from buffer
|
|
parseRoomHeader(&hdr, buffer, sizeof(WTP_ROOM_HDR));
|
|
|
|
while (!_vm->shouldQuit()) {
|
|
pc = startpc;
|
|
|
|
// check if block is to be run
|
|
|
|
iBlock = *(buffer + pc++);
|
|
if (iBlock == 0)
|
|
return IDI_WTP_PAR_OK;
|
|
|
|
fBlock = *(buffer + pc++);
|
|
if (_game.fGame[iBlock] != fBlock)
|
|
return IDI_WTP_PAR_OK;
|
|
|
|
// extract text from block
|
|
|
|
opcode = *(buffer + pc);
|
|
switch (opcode) {
|
|
case 0:
|
|
case IDO_WTP_OPTION_0:
|
|
case IDO_WTP_OPTION_1:
|
|
case IDO_WTP_OPTION_2:
|
|
// clear fCanSel block
|
|
memset(fCanSel, 0, sizeof(fCanSel));
|
|
|
|
// check if NSEW directions should be displayed
|
|
if (hdr.roomNew[0])
|
|
fCanSel[IDI_WTP_SEL_NORTH] = fCanSel[IDI_WTP_SEL_SOUTH] =
|
|
fCanSel[IDI_WTP_SEL_EAST] = fCanSel[IDI_WTP_SEL_WEST] = true;
|
|
|
|
// check if object in room or player carrying one
|
|
setTakeDrop();
|
|
|
|
// check which rows have a menu option
|
|
for (iSel = 0; iSel < IDI_WTP_MAX_OPTION; iSel++) {
|
|
opcode = *(buffer + pc++);
|
|
if (opcode) {
|
|
fCanSel[opcode - IDO_WTP_OPTION_0] = true;
|
|
fCanSel[iSel + IDI_WTP_SEL_REAL_OPT_1] = opcode - 0x14;
|
|
}
|
|
}
|
|
|
|
// extract menu string
|
|
strcpy(szMenu, (char *)(buffer + pc));
|
|
_vm->XOR80(szMenu);
|
|
break;
|
|
default:
|
|
// print description
|
|
printStrWinnie((char *)(buffer + pc));
|
|
if (_vm->getSelection(kSelBackspace) == 1)
|
|
return IDI_WTP_PAR_OK;
|
|
else
|
|
return IDI_WTP_PAR_BACK;
|
|
}
|
|
|
|
// input handler
|
|
|
|
done = false;
|
|
while (!done) {
|
|
// run wind if it's time
|
|
if (_doWind)
|
|
wind();
|
|
|
|
// get menu selection
|
|
getMenuSel(szMenu, &iSel, fCanSel);
|
|
|
|
if (++_game.nMoves == IDI_WTP_MAX_MOVES_UNTIL_WIND)
|
|
_doWind = true;
|
|
|
|
if (_winnieEvent && (_room <= IDI_WTP_MAX_ROOM_TELEPORT)) {
|
|
if (!_tiggerMist) {
|
|
_tiggerMist = 1;
|
|
tigger();
|
|
} else {
|
|
_tiggerMist = 0;
|
|
mist();
|
|
}
|
|
_winnieEvent = false;
|
|
return IDI_WTP_PAR_GOTO;
|
|
}
|
|
|
|
// process selection
|
|
switch (iSel) {
|
|
case IDI_WTP_SEL_HOME:
|
|
switch (_room) {
|
|
case IDI_WTP_ROOM_HOME:
|
|
case IDI_WTP_ROOM_MIST:
|
|
case IDI_WTP_ROOM_TIGGER:
|
|
break;
|
|
default:
|
|
_room = IDI_WTP_ROOM_HOME;
|
|
return IDI_WTP_PAR_GOTO;
|
|
}
|
|
break;
|
|
case IDI_WTP_SEL_BACK:
|
|
return IDI_WTP_PAR_BACK;
|
|
case IDI_WTP_SEL_OPT_1:
|
|
case IDI_WTP_SEL_OPT_2:
|
|
case IDI_WTP_SEL_OPT_3:
|
|
done = true;
|
|
break;
|
|
case IDI_WTP_SEL_NORTH:
|
|
case IDI_WTP_SEL_SOUTH:
|
|
case IDI_WTP_SEL_EAST:
|
|
case IDI_WTP_SEL_WEST:
|
|
iDir = iSel - IDI_WTP_SEL_NORTH;
|
|
|
|
if (hdr.roomNew[iDir] == IDI_WTP_ROOM_NONE) {
|
|
_vm->printStr(IDS_WTP_CANT_GO);
|
|
_vm->getSelection(kSelAnyKey);
|
|
} else {
|
|
_room = hdr.roomNew[iDir];
|
|
return IDI_WTP_PAR_GOTO;
|
|
}
|
|
break;
|
|
case IDI_WTP_SEL_TAKE:
|
|
takeObj(_room);
|
|
setTakeDrop();
|
|
break;
|
|
case IDI_WTP_SEL_DROP:
|
|
dropObj(_room);
|
|
setTakeDrop();
|
|
break;
|
|
}
|
|
}
|
|
|
|
// jump to the script block of the selected option
|
|
pc = hdr.opt[index].ofsOpt[iSel] - _roomOffset;
|
|
|
|
opcode = *(buffer + pc);
|
|
if (!opcode) pc++;
|
|
|
|
// process script
|
|
do {
|
|
opcode = *(buffer + pc++);
|
|
switch (opcode) {
|
|
case IDO_WTP_GOTO_ROOM:
|
|
opcode = *(buffer + pc++);
|
|
iNewRoom = opcode;
|
|
break;
|
|
case IDO_WTP_PRINT_MSG:
|
|
opcode = *(buffer + pc++);
|
|
printRoomStr(_room, opcode);
|
|
_vm->getSelection(kSelAnyKey);
|
|
break;
|
|
case IDO_WTP_PRINT_STR:
|
|
opcode = *(buffer + pc++);
|
|
printRoomStr(_room, opcode);
|
|
break;
|
|
case IDO_WTP_DROP_OBJ:
|
|
opcode = *(buffer + pc++);
|
|
opcode = -1;
|
|
dropObjRnd();
|
|
break;
|
|
case IDO_WTP_FLAG_CLEAR:
|
|
opcode = *(buffer + pc++);
|
|
clearFlag(opcode);
|
|
break;
|
|
case IDO_WTP_FLAG_SET:
|
|
opcode = *(buffer + pc++);
|
|
setFlag(opcode);
|
|
break;
|
|
case IDO_WTP_GAME_OVER:
|
|
gameOver();
|
|
break;
|
|
case IDO_WTP_WALK_MIST:
|
|
_mist--;
|
|
if (!_mist) {
|
|
_room = _vm->rnd(IDI_WTP_MAX_ROOM_TELEPORT) + 1;
|
|
return IDI_WTP_PAR_GOTO;
|
|
}
|
|
break;
|
|
case IDO_WTP_PLAY_SOUND:
|
|
opcode = *(buffer + pc++);
|
|
playSound((ENUM_WTP_SOUND)opcode);
|
|
break;
|
|
case IDO_WTP_SAVE_GAME:
|
|
saveGame();
|
|
_room = IDI_WTP_ROOM_HOME;
|
|
return IDI_WTP_PAR_GOTO;
|
|
case IDO_WTP_LOAD_GAME:
|
|
loadGame();
|
|
_room = IDI_WTP_ROOM_HOME;
|
|
return IDI_WTP_PAR_GOTO;
|
|
case IDO_WTP_OWL_HELP:
|
|
opcode = *(buffer + pc++);
|
|
showOwlHelp();
|
|
break;
|
|
case IDO_WTP_GOTO_RND:
|
|
_room = _vm->rnd(IDI_WTP_MAX_ROOM_TELEPORT) + 1;
|
|
return IDI_WTP_PAR_GOTO;
|
|
default:
|
|
opcode = 0;
|
|
break;
|
|
}
|
|
} while (opcode && !_vm->shouldQuit());
|
|
|
|
if (iNewRoom) {
|
|
_room = iNewRoom;
|
|
return IDI_WTP_PAR_GOTO;
|
|
}
|
|
|
|
if (iBlock == 1)
|
|
return IDI_WTP_PAR_OK;
|
|
_vm->_gfx->doUpdate();
|
|
_vm->_system->updateScreen();
|
|
}
|
|
|
|
return IDI_WTP_PAR_OK;
|
|
}
|
|
|
|
void Winnie::keyHelp() {
|
|
playSound(IDI_WTP_SND_KEYHELP);
|
|
_vm->printStr(IDS_WTP_HELP_0);
|
|
_vm->getSelection(kSelAnyKey);
|
|
_vm->printStr(IDS_WTP_HELP_1);
|
|
_vm->getSelection(kSelAnyKey);
|
|
}
|
|
|
|
void Winnie::inventory() {
|
|
char szMissing[41] = {0};
|
|
|
|
if (_game.iObjHave)
|
|
printObjStr(_game.iObjHave, IDI_WTP_OBJ_TAKE);
|
|
else {
|
|
_vm->clearTextArea();
|
|
_vm->drawStr(IDI_WTP_ROW_MENU, IDI_WTP_COL_MENU, IDA_DEFAULT, IDS_WTP_INVENTORY_0);
|
|
}
|
|
|
|
sprintf(szMissing, IDS_WTP_INVENTORY_1, _game.nObjMiss);
|
|
_vm->drawStr(IDI_WTP_ROW_OPTION_4, IDI_WTP_COL_MENU, IDA_DEFAULT, szMissing);
|
|
_vm->_gfx->doUpdate();
|
|
_vm->_system->updateScreen(); //TODO: Move to game's main loop
|
|
_vm->getSelection(kSelAnyKey);
|
|
}
|
|
|
|
void Winnie::printObjStr(int iObj, int iStr) {
|
|
WTP_OBJ_HDR hdr;
|
|
uint8 *buffer = (uint8 *)malloc(2048);
|
|
|
|
readObj(iObj, buffer);
|
|
parseObjHeader(&hdr, buffer, sizeof(hdr));
|
|
|
|
printStrWinnie((char *)(buffer + hdr.ofsStr[iStr] - _objOffset));
|
|
free(buffer);
|
|
}
|
|
|
|
bool Winnie::isRightObj(int iRoom, int iObj, int *iCode) {
|
|
WTP_ROOM_HDR roomhdr;
|
|
WTP_OBJ_HDR objhdr;
|
|
uint8 *roomdata = (uint8 *)malloc(4096);
|
|
uint8 *objdata = (uint8 *)malloc(2048);
|
|
|
|
readRoom(iRoom, roomdata, roomhdr);
|
|
readObj(iObj, objdata);
|
|
parseObjHeader(&objhdr, objdata, sizeof(WTP_OBJ_HDR));
|
|
|
|
free(roomdata);
|
|
free(objdata);
|
|
|
|
*iCode = objhdr.objId;
|
|
|
|
if (objhdr.objId == 11) objhdr.objId = 34;
|
|
|
|
if (roomhdr.objId == objhdr.objId)
|
|
return true;
|
|
else
|
|
return false;
|
|
}
|
|
|
|
void Winnie::takeObj(int iRoom) {
|
|
if (_game.iObjHave) {
|
|
// player is already carrying an object, can't take
|
|
_vm->printStr(IDS_WTP_CANT_TAKE);
|
|
_vm->getSelection(kSelAnyKey);
|
|
} else {
|
|
// take object
|
|
int iObj = getObjInRoom(iRoom);
|
|
|
|
_game.iObjHave = iObj;
|
|
_game.iObjRoom[iObj] = 0;
|
|
|
|
_vm->printStr(IDS_WTP_OK);
|
|
playSound(IDI_WTP_SND_TAKE);
|
|
|
|
drawRoomPic();
|
|
|
|
// print object "take" string
|
|
printObjStr(_game.iObjHave, IDI_WTP_OBJ_TAKE);
|
|
_vm->getSelection(kSelAnyKey);
|
|
|
|
// HACK WARNING
|
|
if (iObj == 18) {
|
|
_game.fGame[0x0d] = 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
void Winnie::dropObj(int iRoom) {
|
|
int iCode;
|
|
|
|
if (getObjInRoom(iRoom)) {
|
|
// there already is an object in the room, can't drop
|
|
_vm->printStr(IDS_WTP_CANT_DROP);
|
|
_vm->getSelection(kSelAnyKey);
|
|
} else {
|
|
// HACK WARNING
|
|
if (_game.iObjHave == 18) {
|
|
_game.fGame[0x0d] = 0;
|
|
}
|
|
|
|
if (isRightObj(iRoom, _game.iObjHave, &iCode)) {
|
|
// object has been dropped in the right place
|
|
_vm->printStr(IDS_WTP_OK);
|
|
_vm->getSelection(kSelAnyKey);
|
|
playSound(IDI_WTP_SND_DROP_OK);
|
|
printObjStr(_game.iObjHave, IDI_WTP_OBJ_DROP);
|
|
_vm->getSelection(kSelAnyKey);
|
|
|
|
// increase amount of objects returned, decrease amount of objects missing
|
|
_game.nObjMiss--;
|
|
_game.nObjRet++;
|
|
|
|
// xor the dropped object with 0x80 to signify it has been dropped in the right place
|
|
for (int i = 0; i < IDI_WTP_MAX_OBJ_MISSING; i++) {
|
|
if (_game.iUsedObj[i] == _game.iObjHave) {
|
|
_game.iUsedObj[i] ^= 0x80;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// set flag according to dropped object's id
|
|
_game.fGame[iCode] = 1;
|
|
|
|
// player is carrying nothing
|
|
_game.iObjHave = 0;
|
|
|
|
if (!_game.nObjMiss) {
|
|
// all objects returned, tell player to find party
|
|
playSound(IDI_WTP_SND_FANFARE);
|
|
_vm->printStr(IDS_WTP_GAME_OVER_0);
|
|
_vm->getSelection(kSelAnyKey);
|
|
_vm->printStr(IDS_WTP_GAME_OVER_1);
|
|
_vm->getSelection(kSelAnyKey);
|
|
}
|
|
} else {
|
|
// drop object in the given room
|
|
_game.iObjRoom[_game.iObjHave] = iRoom;
|
|
|
|
// object has been dropped in the wrong place
|
|
_vm->printStr(IDS_WTP_WRONG_PLACE);
|
|
_vm->getSelection(kSelAnyKey);
|
|
|
|
playSound(IDI_WTP_SND_DROP);
|
|
drawRoomPic();
|
|
|
|
_vm->printStr(IDS_WTP_WRONG_PLACE);
|
|
_vm->getSelection(kSelAnyKey);
|
|
|
|
// print object description
|
|
printObjStr(_game.iObjHave, IDI_WTP_OBJ_DESC);
|
|
_vm->getSelection(kSelAnyKey);
|
|
|
|
_game.iObjHave = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
void Winnie::dropObjRnd() {
|
|
if (!_game.iObjHave)
|
|
return;
|
|
|
|
int iRoom = 0;
|
|
bool done = false;
|
|
|
|
while (!done) {
|
|
iRoom = _vm->rnd(IDI_WTP_MAX_ROOM_NORMAL);
|
|
done = true;
|
|
if (iRoom == _room)
|
|
done = false;
|
|
for (int j = 0; j < IDI_WTP_MAX_ROOM_OBJ; j++) {
|
|
if (_game.iObjRoom[j] == iRoom) {
|
|
done = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
_game.iObjRoom[_game.iObjHave] = iRoom;
|
|
_game.iObjHave = 0;
|
|
}
|
|
|
|
void Winnie::wind() {
|
|
int iRoom = 0;
|
|
bool done;
|
|
|
|
_doWind = 0;
|
|
_game.nMoves = 0;
|
|
if (!_game.nObjMiss)
|
|
return;
|
|
|
|
_vm->printStr(IDS_WTP_WIND_0);
|
|
playSound(IDI_WTP_SND_WIND_0);
|
|
_vm->getSelection(kSelAnyKey);
|
|
|
|
_vm->printStr(IDS_WTP_WIND_1);
|
|
playSound(IDI_WTP_SND_WIND_0);
|
|
_vm->getSelection(kSelAnyKey);
|
|
|
|
dropObjRnd();
|
|
|
|
// randomize positions of objects at large
|
|
for (int i = 0; i < IDI_WTP_MAX_OBJ_MISSING; i++) {
|
|
if (!(_game.iUsedObj[i] & IDI_XOR_KEY)) {
|
|
done = false;
|
|
while (!done) {
|
|
iRoom = _vm->rnd(IDI_WTP_MAX_ROOM_NORMAL);
|
|
done = true;
|
|
|
|
for (int j = 0; j < IDI_WTP_MAX_ROOM_OBJ; j++) {
|
|
if (_game.iObjRoom[j] == iRoom) {
|
|
done = false;
|
|
}
|
|
}
|
|
}
|
|
_game.iObjRoom[_game.iUsedObj[i]] = iRoom;
|
|
}
|
|
}
|
|
}
|
|
|
|
void Winnie::mist() {
|
|
// mist length in turns is (2-5)
|
|
_mist = _vm->rnd(4) + 2;
|
|
|
|
_room = IDI_WTP_ROOM_MIST;
|
|
drawRoomPic();
|
|
|
|
_vm->printStr(IDS_WTP_MIST);
|
|
}
|
|
|
|
void Winnie::tigger() {
|
|
_room = IDI_WTP_ROOM_TIGGER;
|
|
|
|
drawRoomPic();
|
|
_vm->printStr(IDS_WTP_TIGGER);
|
|
|
|
dropObjRnd();
|
|
}
|
|
|
|
void Winnie::showOwlHelp() {
|
|
if (_game.iObjHave) {
|
|
_vm->printStr(IDS_WTP_OWL_0);
|
|
_vm->getSelection(kSelAnyKey);
|
|
printObjStr(_game.iObjHave, IDI_WTP_OBJ_HELP);
|
|
_vm->getSelection(kSelAnyKey);
|
|
}
|
|
if (getObjInRoom(_room)) {
|
|
_vm->printStr(IDS_WTP_OWL_0);
|
|
_vm->getSelection(kSelAnyKey);
|
|
printObjStr(getObjInRoom(_room), IDI_WTP_OBJ_HELP);
|
|
_vm->getSelection(kSelAnyKey);
|
|
}
|
|
}
|
|
|
|
|
|
void Winnie::drawMenu(char *szMenu, int iSel, int fCanSel[]) {
|
|
int iRow = 0, iCol = 0;
|
|
|
|
_vm->clearTextArea();
|
|
_vm->drawStr(IDI_WTP_ROW_MENU, IDI_WTP_COL_MENU, IDA_DEFAULT, szMenu);
|
|
|
|
if (fCanSel[IDI_WTP_SEL_NORTH])
|
|
_vm->drawStr(IDI_WTP_ROW_OPTION_4, IDI_WTP_COL_NSEW, IDA_DEFAULT, IDS_WTP_NSEW);
|
|
if (fCanSel[IDI_WTP_SEL_TAKE])
|
|
_vm->drawStr(IDI_WTP_ROW_OPTION_4, IDI_WTP_COL_TAKE, IDA_DEFAULT, IDS_WTP_TAKE);
|
|
if (fCanSel[IDI_WTP_SEL_DROP])
|
|
_vm->drawStr(IDI_WTP_ROW_OPTION_4, IDI_WTP_COL_DROP, IDA_DEFAULT, IDS_WTP_DROP);
|
|
|
|
switch (iSel) {
|
|
case IDI_WTP_SEL_OPT_1:
|
|
case IDI_WTP_SEL_OPT_2:
|
|
case IDI_WTP_SEL_OPT_3:
|
|
iRow = IDI_WTP_ROW_OPTION_1 + iSel;
|
|
iCol = IDI_WTP_COL_OPTION;
|
|
break;
|
|
case IDI_WTP_SEL_NORTH:
|
|
iRow = IDI_WTP_ROW_OPTION_4;
|
|
iCol = IDI_WTP_COL_NORTH;
|
|
break;
|
|
case IDI_WTP_SEL_SOUTH:
|
|
iRow = IDI_WTP_ROW_OPTION_4;
|
|
iCol = IDI_WTP_COL_SOUTH;
|
|
break;
|
|
case IDI_WTP_SEL_EAST:
|
|
iRow = IDI_WTP_ROW_OPTION_4;
|
|
iCol = IDI_WTP_COL_EAST;
|
|
break;
|
|
case IDI_WTP_SEL_WEST:
|
|
iRow = IDI_WTP_ROW_OPTION_4;
|
|
iCol = IDI_WTP_COL_WEST;
|
|
break;
|
|
case IDI_WTP_SEL_TAKE:
|
|
iRow = IDI_WTP_ROW_OPTION_4;
|
|
iCol = IDI_WTP_COL_TAKE;
|
|
break;
|
|
case IDI_WTP_SEL_DROP:
|
|
iRow = IDI_WTP_ROW_OPTION_4;
|
|
iCol = IDI_WTP_COL_DROP;
|
|
break;
|
|
}
|
|
_vm->drawStr(iRow, iCol - 1, IDA_DEFAULT, ">");
|
|
_vm->_gfx->doUpdate();
|
|
_vm->_system->updateScreen(); //TODO: Move to game's main loop
|
|
}
|
|
|
|
void Winnie::incMenuSel(int *iSel, int fCanSel[]) {
|
|
do {
|
|
*iSel += 1;
|
|
if (*iSel > IDI_WTP_SEL_DROP) *iSel = IDI_WTP_SEL_OPT_1;
|
|
} while (!fCanSel[*iSel]);
|
|
}
|
|
|
|
void Winnie::decMenuSel(int *iSel, int fCanSel[]) {
|
|
do {
|
|
*iSel -= 1;
|
|
if (*iSel < IDI_WTP_SEL_OPT_1) *iSel = IDI_WTP_SEL_DROP;
|
|
} while (!fCanSel[*iSel]);
|
|
}
|
|
|
|
void Winnie::getMenuMouseSel(int *iSel, int fCanSel[], int x, int y) {
|
|
switch (y) {
|
|
case IDI_WTP_ROW_OPTION_1:
|
|
case IDI_WTP_ROW_OPTION_2:
|
|
case IDI_WTP_ROW_OPTION_3:
|
|
if (fCanSel[y - IDI_WTP_ROW_OPTION_1]) *iSel = y - IDI_WTP_ROW_OPTION_1;
|
|
break;
|
|
case IDI_WTP_ROW_OPTION_4:
|
|
if (fCanSel[IDI_WTP_SEL_NORTH] && (x > IDI_WTP_COL_NORTH - 1) && (x < 6)) *iSel = IDI_WTP_SEL_NORTH;
|
|
if (fCanSel[IDI_WTP_SEL_SOUTH] && (x > IDI_WTP_COL_SOUTH - 1) && (x < 13)) *iSel = IDI_WTP_SEL_SOUTH;
|
|
if (fCanSel[IDI_WTP_SEL_EAST] && (x > IDI_WTP_COL_EAST - 1) && (x < 19)) *iSel = IDI_WTP_SEL_EAST;
|
|
if (fCanSel[IDI_WTP_SEL_WEST] && (x > IDI_WTP_COL_WEST - 1) && (x < 25)) *iSel = IDI_WTP_SEL_WEST;
|
|
if (fCanSel[IDI_WTP_SEL_TAKE] && (x > IDI_WTP_COL_TAKE - 1) && (x < 33)) *iSel = IDI_WTP_SEL_TAKE;
|
|
if (fCanSel[IDI_WTP_SEL_DROP] && (x > IDI_WTP_COL_DROP - 1) && (x < 39)) *iSel = IDI_WTP_SEL_DROP;
|
|
break;
|
|
}
|
|
}
|
|
|
|
#define makeSel() {\
|
|
if (fCanSel[*iSel]) {\
|
|
return;\
|
|
} else {\
|
|
keyHelp();\
|
|
clrMenuSel(iSel, fCanSel);\
|
|
}\
|
|
}
|
|
|
|
void Winnie::getMenuSel(char *szMenu, int *iSel, int fCanSel[]) {
|
|
Common::Event event;
|
|
int x, y;
|
|
|
|
clrMenuSel(iSel, fCanSel);
|
|
drawMenu(szMenu, *iSel, fCanSel);
|
|
|
|
// Show the mouse cursor for the menu
|
|
CursorMan.showMouse(true);
|
|
|
|
while (!_vm->shouldQuit()) {
|
|
while (_vm->_system->getEventManager()->pollEvent(event)) {
|
|
switch (event.type) {
|
|
case Common::EVENT_RTL:
|
|
case Common::EVENT_QUIT:
|
|
return;
|
|
case Common::EVENT_MOUSEMOVE:
|
|
x = event.mouse.x / 8;
|
|
y = event.mouse.y / 8;
|
|
getMenuMouseSel(iSel, fCanSel, x, y);
|
|
|
|
// Change cursor
|
|
if (fCanSel[IDI_WTP_SEL_NORTH] && hotspotNorth.contains(event.mouse.x, event.mouse.y)) {
|
|
_vm->_gfx->setCursorPalette(true);
|
|
} else if (fCanSel[IDI_WTP_SEL_SOUTH] && hotspotSouth.contains(event.mouse.x, event.mouse.y)) {
|
|
_vm->_gfx->setCursorPalette(true);
|
|
} else if (fCanSel[IDI_WTP_SEL_WEST] && hotspotWest.contains(event.mouse.x, event.mouse.y)) {
|
|
_vm->_gfx->setCursorPalette(true);
|
|
} else if (fCanSel[IDI_WTP_SEL_EAST] && hotspotEast.contains(event.mouse.x, event.mouse.y)) {
|
|
_vm->_gfx->setCursorPalette(true);
|
|
} else {
|
|
_vm->_gfx->setCursorPalette(false);
|
|
}
|
|
|
|
break;
|
|
case Common::EVENT_LBUTTONUP:
|
|
// Click to move
|
|
if (fCanSel[IDI_WTP_SEL_NORTH] && hotspotNorth.contains(event.mouse.x, event.mouse.y)) {
|
|
*iSel = IDI_WTP_SEL_NORTH;
|
|
makeSel();
|
|
_vm->_gfx->setCursorPalette(false);
|
|
return;
|
|
} else if (fCanSel[IDI_WTP_SEL_SOUTH] && hotspotSouth.contains(event.mouse.x, event.mouse.y)) {
|
|
*iSel = IDI_WTP_SEL_SOUTH;
|
|
makeSel();
|
|
_vm->_gfx->setCursorPalette(false);
|
|
return;
|
|
} else if (fCanSel[IDI_WTP_SEL_WEST] && hotspotWest.contains(event.mouse.x, event.mouse.y)) {
|
|
*iSel = IDI_WTP_SEL_WEST;
|
|
makeSel();
|
|
_vm->_gfx->setCursorPalette(false);
|
|
return;
|
|
} else if (fCanSel[IDI_WTP_SEL_EAST] && hotspotEast.contains(event.mouse.x, event.mouse.y)) {
|
|
*iSel = IDI_WTP_SEL_EAST;
|
|
makeSel();
|
|
_vm->_gfx->setCursorPalette(false);
|
|
return;
|
|
} else {
|
|
_vm->_gfx->setCursorPalette(false);
|
|
}
|
|
|
|
switch (*iSel) {
|
|
case IDI_WTP_SEL_OPT_1:
|
|
case IDI_WTP_SEL_OPT_2:
|
|
case IDI_WTP_SEL_OPT_3:
|
|
for (int iSel2 = 0; iSel2 < IDI_WTP_MAX_OPTION; iSel2++) {
|
|
if (*iSel == (fCanSel[iSel2 + IDI_WTP_SEL_REAL_OPT_1] - 1)) {
|
|
*iSel = iSel2;
|
|
// Menu selection made, hide the mouse cursor
|
|
CursorMan.showMouse(false);
|
|
return;
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
if (fCanSel[*iSel]) {
|
|
// Menu selection made, hide the mouse cursor
|
|
CursorMan.showMouse(false);
|
|
return;
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
case Common::EVENT_RBUTTONUP:
|
|
*iSel = IDI_WTP_SEL_BACK;
|
|
// Menu selection made, hide the mouse cursor
|
|
CursorMan.showMouse(false);
|
|
return;
|
|
case Common::EVENT_WHEELUP:
|
|
decMenuSel(iSel, fCanSel);
|
|
break;
|
|
case Common::EVENT_WHEELDOWN:
|
|
incMenuSel(iSel, fCanSel);
|
|
break;
|
|
case Common::EVENT_KEYDOWN:
|
|
if (event.kbd.keycode == Common::KEYCODE_d && (event.kbd.flags & Common::KBD_CTRL) && _vm->_console) {
|
|
_vm->_console->attach();
|
|
_vm->_console->onFrame();
|
|
continue;
|
|
}
|
|
|
|
switch (event.kbd.keycode) {
|
|
case Common::KEYCODE_ESCAPE:
|
|
*iSel = IDI_WTP_SEL_HOME;
|
|
// Menu selection made, hide the mouse cursor
|
|
CursorMan.showMouse(false);
|
|
return;
|
|
case Common::KEYCODE_BACKSPACE:
|
|
*iSel = IDI_WTP_SEL_BACK;
|
|
// Menu selection made, hide the mouse cursor
|
|
CursorMan.showMouse(false);
|
|
return;
|
|
case Common::KEYCODE_c:
|
|
inventory();
|
|
break;
|
|
case Common::KEYCODE_SPACE:
|
|
case Common::KEYCODE_RIGHT:
|
|
case Common::KEYCODE_DOWN:
|
|
incMenuSel(iSel, fCanSel);
|
|
break;
|
|
case Common::KEYCODE_LEFT:
|
|
case Common::KEYCODE_UP:
|
|
decMenuSel(iSel, fCanSel);
|
|
break;
|
|
case Common::KEYCODE_1:
|
|
case Common::KEYCODE_2:
|
|
case Common::KEYCODE_3:
|
|
*iSel = event.kbd.keycode - Common::KEYCODE_1;
|
|
if (fCanSel[*iSel + IDI_WTP_SEL_REAL_OPT_1]) {
|
|
// Menu selection made, hide the mouse cursor
|
|
CursorMan.showMouse(false);
|
|
return;
|
|
} else {
|
|
keyHelp();
|
|
clrMenuSel(iSel, fCanSel);
|
|
}
|
|
break;
|
|
case Common::KEYCODE_n:
|
|
*iSel = IDI_WTP_SEL_NORTH;
|
|
makeSel();
|
|
break;
|
|
case Common::KEYCODE_s:
|
|
if (event.kbd.flags & Common::KBD_CTRL) {
|
|
_vm->flipflag(fSoundOn);
|
|
} else {
|
|
*iSel = IDI_WTP_SEL_SOUTH;
|
|
makeSel();
|
|
}
|
|
break;
|
|
case Common::KEYCODE_e:
|
|
*iSel = IDI_WTP_SEL_EAST;
|
|
makeSel();
|
|
break;
|
|
case Common::KEYCODE_w:
|
|
*iSel = IDI_WTP_SEL_WEST;
|
|
makeSel();
|
|
break;
|
|
case Common::KEYCODE_t:
|
|
*iSel = IDI_WTP_SEL_TAKE;
|
|
makeSel();
|
|
break;
|
|
case Common::KEYCODE_d:
|
|
*iSel = IDI_WTP_SEL_DROP;
|
|
makeSel();
|
|
break;
|
|
case Common::KEYCODE_RETURN:
|
|
switch (*iSel) {
|
|
case IDI_WTP_SEL_OPT_1:
|
|
case IDI_WTP_SEL_OPT_2:
|
|
case IDI_WTP_SEL_OPT_3:
|
|
for (int iSel2 = 0; iSel2 < IDI_WTP_MAX_OPTION; iSel2++) {
|
|
if (*iSel == (fCanSel[iSel2 + IDI_WTP_SEL_REAL_OPT_1] - 1)) {
|
|
*iSel = iSel2;
|
|
// Menu selection made, hide the mouse cursor
|
|
CursorMan.showMouse(false);
|
|
return;
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
if (fCanSel[*iSel]) {
|
|
// Menu selection made, hide the mouse cursor
|
|
CursorMan.showMouse(false);
|
|
return;
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
if (!event.kbd.flags) { // if the control/alt/shift keys are not pressed
|
|
keyHelp();
|
|
clrMenuSel(iSel, fCanSel);
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
drawMenu(szMenu, *iSel, fCanSel);
|
|
}
|
|
}
|
|
}
|
|
|
|
void Winnie::gameLoop() {
|
|
WTP_ROOM_HDR hdr;
|
|
uint8 *roomdata = (uint8 *)malloc(4096);
|
|
int iBlock;
|
|
|
|
phase0:
|
|
if (!_game.nObjMiss && (_room == IDI_WTP_ROOM_PICNIC))
|
|
_room = IDI_WTP_ROOM_PARTY;
|
|
|
|
readRoom(_room, roomdata, hdr);
|
|
drawRoomPic();
|
|
_vm->_gfx->doUpdate();
|
|
_vm->_system->updateScreen();
|
|
|
|
phase1:
|
|
if (getObjInRoom(_room)) {
|
|
printObjStr(getObjInRoom(_room), IDI_WTP_OBJ_DESC);
|
|
_vm->getSelection(kSelAnyKey);
|
|
}
|
|
|
|
phase2:
|
|
for (iBlock = 0; iBlock < IDI_WTP_MAX_BLOCK; iBlock++) {
|
|
if (parser(hdr.ofsDesc[iBlock] - _roomOffset, iBlock, roomdata) == IDI_WTP_PAR_BACK)
|
|
goto phase1;
|
|
}
|
|
|
|
while (!_vm->shouldQuit()) {
|
|
for (iBlock = 0; iBlock < IDI_WTP_MAX_BLOCK; iBlock++) {
|
|
switch (parser(hdr.ofsBlock[iBlock] - _roomOffset, iBlock, roomdata)) {
|
|
case IDI_WTP_PAR_GOTO:
|
|
goto phase0;
|
|
break;
|
|
case IDI_WTP_PAR_BACK:
|
|
goto phase2;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
free(roomdata);
|
|
}
|
|
|
|
void Winnie::drawPic(const char *szName) {
|
|
char szFile[256] = {0};
|
|
Common::File file;
|
|
|
|
// construct filename
|
|
if (_vm->getPlatform() != Common::kPlatformAmiga)
|
|
sprintf(szFile, "%s.pic", szName);
|
|
else
|
|
strcpy(szFile, szName);
|
|
if (!file.open(szFile)) {
|
|
warning ("Could not open file \'%s\'", szFile);
|
|
return;
|
|
}
|
|
|
|
uint8 *buffer = (uint8 *)malloc(4096);
|
|
uint32 size = file.size();
|
|
file.read(buffer, size);
|
|
file.close();
|
|
|
|
_vm->_picture->decodePicture(buffer, size, 1, IDI_WTP_PIC_WIDTH, IDI_WTP_PIC_HEIGHT);
|
|
_vm->_picture->showPic(IDI_WTP_PIC_X0, IDI_WTP_PIC_Y0, IDI_WTP_PIC_WIDTH, IDI_WTP_PIC_HEIGHT);
|
|
|
|
free(buffer);
|
|
}
|
|
|
|
void Winnie::drawObjPic(int iObj, int x0, int y0) {
|
|
if (!iObj)
|
|
return;
|
|
|
|
WTP_OBJ_HDR objhdr;
|
|
uint8 *buffer = (uint8 *)malloc(2048);
|
|
uint32 objSize = readObj(iObj, buffer);
|
|
parseObjHeader(&objhdr, buffer, sizeof(WTP_OBJ_HDR));
|
|
|
|
_vm->_picture->setOffset(x0, y0);
|
|
_vm->_picture->decodePicture(buffer + objhdr.ofsPic - _objOffset, objSize, 0, IDI_WTP_PIC_WIDTH, IDI_WTP_PIC_HEIGHT);
|
|
_vm->_picture->setOffset(0, 0);
|
|
_vm->_picture->showPic(10, 0, IDI_WTP_PIC_WIDTH, IDI_WTP_PIC_HEIGHT);
|
|
|
|
free(buffer);
|
|
}
|
|
|
|
void Winnie::drawRoomPic() {
|
|
WTP_ROOM_HDR roomhdr;
|
|
uint8 *buffer = (uint8 *)malloc(4096);
|
|
int iObj = getObjInRoom(_room);
|
|
|
|
// clear gfx screen
|
|
_vm->_gfx->clearScreen(0);
|
|
|
|
// read room picture
|
|
readRoom(_room, buffer, roomhdr);
|
|
|
|
// draw room picture
|
|
_vm->_picture->decodePicture(buffer + roomhdr.ofsPic - _roomOffset, 4096, 1, IDI_WTP_PIC_WIDTH, IDI_WTP_PIC_HEIGHT);
|
|
_vm->_picture->showPic(IDI_WTP_PIC_X0, IDI_WTP_PIC_Y0, IDI_WTP_PIC_WIDTH, IDI_WTP_PIC_HEIGHT);
|
|
|
|
// draw object picture
|
|
drawObjPic(iObj, IDI_WTP_PIC_X0 + roomhdr.objX, IDI_WTP_PIC_Y0 + roomhdr.objY);
|
|
|
|
free(buffer);
|
|
}
|
|
|
|
bool Winnie::playSound(ENUM_WTP_SOUND iSound) {
|
|
//TODO
|
|
warning ("STUB: playSound(%d)", iSound);
|
|
return 1;
|
|
}
|
|
|
|
void Winnie::clrMenuSel(int *iSel, int fCanSel[]) {
|
|
*iSel = IDI_WTP_SEL_OPT_1;
|
|
while (!fCanSel[*iSel]) {
|
|
*iSel += 1;
|
|
}
|
|
_vm->_gfx->setCursorPalette(false);
|
|
}
|
|
|
|
void Winnie::printRoomStr(int iRoom, int iStr) {
|
|
WTP_ROOM_HDR hdr;
|
|
uint8 *buffer = (uint8 *)malloc(4096);
|
|
|
|
readRoom(iRoom, buffer, hdr);
|
|
printStrWinnie((char *)(buffer + hdr.ofsStr[iStr - 1] - _roomOffset));
|
|
|
|
free(buffer);
|
|
}
|
|
|
|
void Winnie::gameOver() {
|
|
// sing the Pooh song forever
|
|
while (!_vm->shouldQuit()) {
|
|
_vm->printStr(IDS_WTP_SONG_0);
|
|
playSound(IDI_WTP_SND_POOH_0);
|
|
_vm->printStr(IDS_WTP_SONG_1);
|
|
playSound(IDI_WTP_SND_POOH_1);
|
|
_vm->printStr(IDS_WTP_SONG_2);
|
|
playSound(IDI_WTP_SND_POOH_2);
|
|
_vm->getSelection(kSelAnyKey);
|
|
}
|
|
}
|
|
|
|
void Winnie::saveGame() {
|
|
Common::OutSaveFile* outfile;
|
|
char szFile[256] = {0};
|
|
int i = 0;
|
|
|
|
sprintf(szFile, IDS_WTP_FILE_SAVEGAME);
|
|
if (!(outfile = _vm->getSaveFileMan()->openForSaving(szFile)))
|
|
return;
|
|
|
|
outfile->writeUint32BE(MKTAG('W','I','N','N')); // header
|
|
outfile->writeByte(WTP_SAVEGAME_VERSION);
|
|
|
|
outfile->writeByte(_game.fSound);
|
|
outfile->writeByte(_game.nMoves);
|
|
outfile->writeByte(_game.nObjMiss);
|
|
outfile->writeByte(_game.nObjRet);
|
|
outfile->writeByte(_game.iObjHave);
|
|
|
|
for (i = 0; i < IDI_WTP_MAX_FLAG; i++)
|
|
outfile->writeByte(_game.fGame[i]);
|
|
|
|
for (i = 0; i < IDI_WTP_MAX_OBJ_MISSING; i++)
|
|
outfile->writeByte(_game.iUsedObj[i]);
|
|
|
|
for (i = 0; i < IDI_WTP_MAX_ROOM_OBJ; i++)
|
|
outfile->writeByte(_game.iObjRoom[i]);
|
|
|
|
outfile->finalize();
|
|
|
|
if (outfile->err())
|
|
warning("Can't write file '%s'. (Disk full?)", szFile);
|
|
|
|
delete outfile;
|
|
}
|
|
|
|
void Winnie::loadGame() {
|
|
Common::InSaveFile* infile;
|
|
char szFile[256] = {0};
|
|
int saveVersion = 0;
|
|
int i = 0;
|
|
|
|
sprintf(szFile, IDS_WTP_FILE_SAVEGAME);
|
|
if (!(infile = _vm->getSaveFileMan()->openForLoading(szFile)))
|
|
return;
|
|
|
|
if (infile->readUint32BE() == MKTAG('W','I','N','N')) {
|
|
saveVersion = infile->readByte();
|
|
if (saveVersion != WTP_SAVEGAME_VERSION)
|
|
warning("Old save game version (%d, current version is %d). Will try and read anyway, but don't be surprised if bad things happen", saveVersion, WTP_SAVEGAME_VERSION);
|
|
|
|
_game.fSound = infile->readByte();
|
|
_game.nMoves = infile->readByte();
|
|
_game.nObjMiss = infile->readByte();
|
|
_game.nObjRet = infile->readByte();
|
|
_game.iObjHave = infile->readByte();
|
|
} else {
|
|
// This is probably a save from the original interpreter, throw a warning and attempt
|
|
// to read it as LE
|
|
warning("No header found in save game, assuming it came from the original interpreter");
|
|
// Note that the original saves variables as 16-bit integers, but only 8 bits are used.
|
|
// Since we read the save file data as little-endian, we skip the first byte of each
|
|
// variable
|
|
|
|
infile->seek(0); // Jump back to the beginning of the file
|
|
|
|
infile->readUint16LE(); // skip unused field
|
|
infile->readByte(); // first 8 bits of fSound
|
|
_game.fSound = infile->readByte();
|
|
infile->readByte(); // first 8 bits of nMoves
|
|
_game.nMoves = infile->readByte();
|
|
infile->readByte(); // first 8 bits of nObjMiss
|
|
_game.nObjMiss = infile->readByte();
|
|
infile->readByte(); // first 8 bits of nObjRet
|
|
_game.nObjRet = infile->readByte();
|
|
infile->readUint16LE(); // skip unused field
|
|
infile->readUint16LE(); // skip unused field
|
|
infile->readUint16LE(); // skip unused field
|
|
infile->readByte(); // first 8 bits of iObjHave
|
|
_game.iObjHave = infile->readByte();
|
|
infile->readUint16LE(); // skip unused field
|
|
infile->readUint16LE(); // skip unused field
|
|
infile->readUint16LE(); // skip unused field
|
|
}
|
|
|
|
for (i = 0; i < IDI_WTP_MAX_FLAG; i++)
|
|
_game.fGame[i] = infile->readByte();
|
|
|
|
for (i = 0; i < IDI_WTP_MAX_OBJ_MISSING; i++)
|
|
_game.iUsedObj[i] = infile->readByte();
|
|
|
|
for (i = 0; i < IDI_WTP_MAX_ROOM_OBJ; i++)
|
|
_game.iObjRoom[i] = infile->readByte();
|
|
|
|
// Note that saved games from the original interpreter have 2 more 16-bit fields here
|
|
// which are ignored
|
|
|
|
delete infile;
|
|
}
|
|
|
|
void Winnie::printStrWinnie(char *szMsg) {
|
|
if (_vm->getPlatform() != Common::kPlatformAmiga)
|
|
_vm->printStrXOR(szMsg);
|
|
else
|
|
_vm->printStr(szMsg);
|
|
}
|
|
|
|
// Console-related functions
|
|
|
|
void Winnie::debugCurRoom() {
|
|
_vm->_console->DebugPrintf("Current Room = %d\n", _room);
|
|
}
|
|
|
|
Winnie::Winnie(PreAgiEngine* vm) : _vm(vm) {
|
|
_vm->_console = new Winnie_Console(_vm, this);
|
|
}
|
|
|
|
void Winnie::init() {
|
|
memset(&_game, 0, sizeof(_game));
|
|
_game.fSound = 1;
|
|
_game.nObjMiss = IDI_WTP_MAX_OBJ_MISSING;
|
|
_game.nObjRet = 0;
|
|
_game.fGame[0] = 1;
|
|
_game.fGame[1] = 1;
|
|
_room = IDI_WTP_ROOM_HOME;
|
|
|
|
_mist = -1;
|
|
_doWind = false;
|
|
_winnieEvent = false;
|
|
|
|
if (_vm->getPlatform() != Common::kPlatformAmiga) {
|
|
_isBigEndian = false;
|
|
_roomOffset = IDI_WTP_OFS_ROOM;
|
|
_objOffset = IDI_WTP_OFS_OBJ;
|
|
} else {
|
|
_isBigEndian = true;
|
|
_roomOffset = 0;
|
|
_objOffset = 0;
|
|
}
|
|
|
|
if (_vm->getPlatform() == Common::kPlatformC64 || _vm->getPlatform() == Common::kPlatformApple2GS)
|
|
_vm->_picture->setPictureVersion(AGIPIC_C64);
|
|
|
|
hotspotNorth = Common::Rect(20, 0, (IDI_WTP_PIC_WIDTH + 10) * 2, 10);
|
|
hotspotSouth = Common::Rect(20, IDI_WTP_PIC_HEIGHT - 10, (IDI_WTP_PIC_WIDTH + 10) * 2, IDI_WTP_PIC_HEIGHT);
|
|
hotspotEast = Common::Rect(IDI_WTP_PIC_WIDTH * 2, 0, (IDI_WTP_PIC_WIDTH + 10) * 2, IDI_WTP_PIC_HEIGHT);
|
|
hotspotWest = Common::Rect(20, 0, 30, IDI_WTP_PIC_HEIGHT);
|
|
}
|
|
|
|
void Winnie::run() {
|
|
randomize();
|
|
if (_vm->getPlatform() != Common::kPlatformC64 && _vm->getPlatform() != Common::kPlatformApple2GS)
|
|
intro();
|
|
gameLoop();
|
|
}
|
|
|
|
}
|