diff options
Diffstat (limited to 'engines/chewy')
-rw-r--r-- | engines/chewy/console.cpp | 23 | ||||
-rw-r--r-- | engines/chewy/console.h | 3 | ||||
-rw-r--r-- | engines/chewy/cursor.cpp | 29 | ||||
-rw-r--r-- | engines/chewy/cursor.h | 9 | ||||
-rw-r--r-- | engines/chewy/events.cpp | 2 | ||||
-rw-r--r-- | engines/chewy/graphics.cpp | 47 | ||||
-rw-r--r-- | engines/chewy/graphics.h | 7 | ||||
-rw-r--r-- | engines/chewy/scene.cpp | 207 | ||||
-rw-r--r-- | engines/chewy/scene.h | 1 | ||||
-rw-r--r-- | engines/chewy/text.cpp | 10 |
10 files changed, 277 insertions, 61 deletions
diff --git a/engines/chewy/console.cpp b/engines/chewy/console.cpp index 6fbd99278f..65c4a681d6 100644 --- a/engines/chewy/console.cpp +++ b/engines/chewy/console.cpp @@ -35,7 +35,8 @@ namespace Chewy { Console::Console(ChewyEngine *vm) : GUI::Debugger(), _vm(vm) { registerCmd("dump", WRAP_METHOD(Console, Cmd_Dump)); registerCmd("dump_bg", WRAP_METHOD(Console, Cmd_DumpBg)); - registerCmd("draw", WRAP_METHOD(Console, Cmd_Draw)); + registerCmd("draw_image", WRAP_METHOD(Console, Cmd_DrawImage)); + registerCmd("draw_sprite", WRAP_METHOD(Console, Cmd_DrawSprite)); registerCmd("play_sound", WRAP_METHOD(Console, Cmd_PlaySound)); registerCmd("play_speech", WRAP_METHOD(Console, Cmd_PlaySpeech)); registerCmd("play_music", WRAP_METHOD(Console, Cmd_PlayMusic)); @@ -104,9 +105,9 @@ bool Console::Cmd_DumpBg(int argc, const char **argv) { } -bool Console::Cmd_Draw(int argc, const char **argv) { +bool Console::Cmd_DrawImage(int argc, const char **argv) { if (argc < 3) { - debugPrintf("Usage: draw <file> <resource number>\n"); + debugPrintf("Usage: draw_image <file> <resource number>\n"); return true; } @@ -118,6 +119,22 @@ bool Console::Cmd_Draw(int argc, const char **argv) { return false; } +bool Console::Cmd_DrawSprite(int argc, const char **argv) { + if (argc < 3) { + debugPrintf("Usage: draw_sprite <file> <resource number> [x] [y]\n"); + return true; + } + + Common::String filename = argv[1]; + int spriteNum = atoi(argv[2]); + int x = (argc < 4) ? 0 : atoi(argv[3]); + int y = (argc < 5) ? 0 : atoi(argv[4]); + + _vm->_graphics->drawSprite(filename, spriteNum, x, y); + + return false; +} + bool Console::Cmd_PlaySound(int argc, const char **argv) { if (argc < 2) { debugPrintf("Usage: play_sound <number>\n"); diff --git a/engines/chewy/console.h b/engines/chewy/console.h index ae2be15f30..2ceb1df4e6 100644 --- a/engines/chewy/console.h +++ b/engines/chewy/console.h @@ -39,7 +39,8 @@ private: bool Cmd_Dump(int argc, const char **argv); bool Cmd_DumpBg(int argc, const char **argv); - bool Cmd_Draw(int argc, const char **argv); + bool Cmd_DrawImage(int argc, const char **argv); + bool Cmd_DrawSprite(int argc, const char **argv); bool Cmd_PlaySound(int argc, const char **argv); bool Cmd_PlaySpeech(int argc, const char **argv); bool Cmd_PlayMusic(int argc, const char **argv); diff --git a/engines/chewy/cursor.cpp b/engines/chewy/cursor.cpp index 4795221e44..54496ef848 100644 --- a/engines/chewy/cursor.cpp +++ b/engines/chewy/cursor.cpp @@ -63,6 +63,35 @@ Cursor::~Cursor() { delete _cursorSprites; } +// TODO: This may need to be refactored, since in the original the user +// selects the cursor to use from a pop-up menu +CurrentCursor Cursor::getCurrentCursor() const { + switch (_curCursor) { + case 0: + case 1: + case 2: + case 3: + return kWalk; + case 4: + case 5: + case 6: + case 7: + return kUse; + case 13: + case 14: + case 15: + case 16: + return kLook; + case 17: + case 18: + case 19: + case 20: + return kTalk; + default: + return kOther; + } +} + void Cursor::setCursor(uint num, bool newCursor) { TAFChunk *cursor = _cursorSprites->getSprite(num); if (newCursor) diff --git a/engines/chewy/cursor.h b/engines/chewy/cursor.h index de5a707ca6..bb39abb463 100644 --- a/engines/chewy/cursor.h +++ b/engines/chewy/cursor.h @@ -30,6 +30,14 @@ namespace Chewy { class SpriteResource; class Font; +enum CurrentCursor { + kWalk, + kLook, + kUse, + kTalk, + kOther +}; + class Cursor { public: Cursor(); @@ -40,6 +48,7 @@ public: void hideCursor(); void animateCursor(); void nextCursor(); + CurrentCursor getCurrentCursor() const; private: uint _curCursor; diff --git a/engines/chewy/events.cpp b/engines/chewy/events.cpp index 3da9da2803..532b1acce7 100644 --- a/engines/chewy/events.cpp +++ b/engines/chewy/events.cpp @@ -55,6 +55,8 @@ void Events::processEvents() { default: break; } + } else if (_event.type == Common::EVENT_LBUTTONUP) { + _vm->_scene->mouseClick(_event.mouse); } else if (_event.type == Common::EVENT_RBUTTONUP) { _vm->_cursor->nextCursor(); } else if (_event.type == Common::EVENT_MOUSEMOVE) { diff --git a/engines/chewy/graphics.cpp b/engines/chewy/graphics.cpp index 54a731fd3a..2f7c28ad6c 100644 --- a/engines/chewy/graphics.cpp +++ b/engines/chewy/graphics.cpp @@ -34,12 +34,17 @@ namespace Chewy { +#define DESC_WIDTH 80 +#define DESC_HEIGHT 8 + Graphics::Graphics(ChewyEngine *vm) : _vm(vm) { _font = nullptr; + _descSurface.create(DESC_WIDTH, DESC_HEIGHT, ::Graphics::PixelFormat::createFormatCLUT8()); } Graphics::~Graphics() { delete _font; + _descSurface.free(); } void Graphics::drawSprite(Common::String filename, int spriteNum, uint x, uint y) { @@ -67,6 +72,15 @@ void Graphics::drawImage(Common::String filename, int imageNum) { delete res; } +void Graphics::drawRect(Common::Rect r, byte color) { + ::Graphics::Surface *screen = g_system->lockScreen(); + screen->drawLine(r.left, r.top, r.right, r.top, color); + screen->drawLine(r.right, r.top, r.right, r.bottom, color); + screen->drawLine(r.left, r.bottom, r.right, r.bottom, color); + screen->drawLine(r.left, r.top, r.left, r.bottom, color); + g_system->unlockScreen(); +} + void Graphics::loadFont(Common::String filename) { _font = new Font(filename); } @@ -75,10 +89,12 @@ void Graphics::drawTransparent(uint16 x, uint16 y, byte *data, uint16 width, uin ::Graphics::Surface *screen = g_system->lockScreen(); for (uint curX = 0; curX < width; curX++) { for (uint curY = 0; curY < height; curY++) { - byte *src = data + (curY * width) + curX; - byte *dst = (byte *)screen->getBasePtr(curX + x, curY + y); - if (*src != transparentColor) - *dst = *src; + if (curX + x < 320 && curY + y < 200) { + byte *src = data + (curY * width) + curX; + byte *dst = (byte *)screen->getBasePtr(curX + x, curY + y); + if (*src != transparentColor) + *dst = *src; + } } } g_system->unlockScreen(); @@ -145,4 +161,27 @@ void Graphics::playVideo(uint num) { delete cfoDecoder; } +void Graphics::setDescSurface(Common::Point pos) { + _descPos = pos; + + if (pos.x < 0) + return; + + ::Graphics::Surface *s = g_system->lockScreen(); + Common::Rect r = Common::Rect(pos.x, pos.y, pos.x + _descSurface.w, pos.y + _descSurface.h); + r.clip(Common::Rect(0, 0, 320, 200)); + _descSurface.copyRectToSurface(*s, 0, 0, r); + g_system->unlockScreen(); +} + +void Graphics::restoreDescSurface() { + if (_descPos.x < 0) + return; + + Common::Rect r = Common::Rect(_descPos.x, _descPos.y, _descPos.x + _descSurface.w, _descPos.y + _descSurface.h); + r.clip(Common::Rect(0, 0, 320, 200)); + g_system->copyRectToScreen(_descSurface.getPixels(), _descSurface.pitch, _descPos.x, _descPos.y, r.width(), r.height()); + _descPos = Common::Point(-1, -1); +} + } // End of namespace Chewy diff --git a/engines/chewy/graphics.h b/engines/chewy/graphics.h index a260311df5..09865711df 100644 --- a/engines/chewy/graphics.h +++ b/engines/chewy/graphics.h @@ -24,6 +24,8 @@ #define CHEWY_GRAPHICS_H #include "chewy/chewy.h" +#include "common/rect.h" +#include "graphics/surface.h" namespace Chewy { @@ -37,15 +39,20 @@ public: void drawImage(Common::String filename, int imageNum); void drawSprite(Common::String filename, int spriteNum, uint x, uint y); + void drawRect(Common::Rect r, byte color); void playVideo(uint num); void loadFont(Common::String filename); void drawText(Common::String text, uint x, uint y); + void setDescSurface(Common::Point pos); + void restoreDescSurface(); private: void drawTransparent(uint16 x, uint16 y, byte *data, uint16 width, uint16 height, byte transparentColor); ChewyEngine *_vm; Font *_font; + Common::Point _descPos; + ::Graphics::Surface _descSurface; }; } // End of namespace Chewy diff --git a/engines/chewy/scene.cpp b/engines/chewy/scene.cpp index 0f12219078..df8dd66148 100644 --- a/engines/chewy/scene.cpp +++ b/engines/chewy/scene.cpp @@ -30,6 +30,7 @@ #include "chewy/graphics.h" #include "chewy/scene.h" #include "chewy/resource.h" +#include "chewy/sound.h" #include "chewy/text.h" #include "chewy/video/cfo_decoder.h" @@ -37,12 +38,28 @@ namespace Chewy { #define MAX_DETAILS 32 #define MAX_HOTSPOTS 50 +#define MAX_AUTOMOVE 20 +#define MAX_SOUNDS 3 // Animated details - scene animations struct AnimatedDetails { - uint16 x; - uint16 y; - // 66 bytes animated details - TODO + int16 x; + int16 y; + byte startFlag; // 0: no animation + byte repeat; + int16 startSprite; + int16 endSprite; + int16 spriteCount; + uint16 delay; + uint16 delayCount; + uint16 reverse; // 0: play normally, 1: play in reverse + uint16 timerStart; // seconds until detail is started (0: no timer) + uint16 zIndex; + byte loadFlag; // 0: load animation in memory immediately, 1: load animation in memory when it is played + byte zoom; + // 2 * 3 * 7 = 42 bytes sound data - TODO + byte showOneFrame; // show a sprite, 0: none, 1: before animation, 2: after animation + byte currentFrame; }; // Static details - scene sprites and props @@ -50,20 +67,18 @@ struct StaticDetails { int16 x; int16 y; int16 spriteNum; - uint16 z; + uint16 zIndex; byte hide; // 1 byte dummy }; -struct SceneInfo { - uint16 staticDetailsCount; - uint16 animatedDetailsCount; - uint32 spritePtr; - AnimatedDetails animatedDetails[MAX_DETAILS]; - StaticDetails staticDetails[MAX_DETAILS]; - Common::Rect hotspot[MAX_HOTSPOTS]; - uint16 hotspotDescRes[MAX_HOTSPOTS]; - Common::String hotspotDesc[MAX_HOTSPOTS]; +struct Hotspot { + Common::Rect rect; + uint16 resource; + Common::String desc; +}; + +struct RoomInfo { byte roomNum; byte picNum; byte autoMoveCount; @@ -71,13 +86,37 @@ struct SceneInfo { Common::String tafName; // 14 bytes byte zoomFactor; // 1 byte dummy - // 6 * 20 = 120 bytes automove coordinates - TODO - // MAX_DETAILS * 3 * 2 = 192 bytes voc - TODO - // MAX_DETAILS * 3 = 96 bytes samples - TODO +}; + +struct AutoMove { + int16 x; + int16 y; + byte spriteNum; // sprite number to draw when the end point is reached + // 1 byte dummy +}; + +struct HotspotSpeech { + int16 look; + int16 use; + int16 talk; +}; + +struct SceneInfo { + uint16 staticDetailsCount; + uint16 animatedDetailsCount; + uint32 spritePtr; + AnimatedDetails animatedDetails[MAX_DETAILS]; + StaticDetails staticDetails[MAX_DETAILS]; + Hotspot hotspot[MAX_HOTSPOTS]; + RoomInfo roomInfo; + AutoMove autoMove[MAX_AUTOMOVE]; + HotspotSpeech hotspotSpeech[MAX_DETAILS]; + byte hotspotSound[MAX_DETAILS][MAX_SOUNDS]; }; Scene::Scene(ChewyEngine *vm) : _vm(vm) { _sceneInfo = new SceneInfo(); + _vm->_graphics->setDescSurface(Common::Point(-1, -1)); } Scene::~Scene() { @@ -97,8 +136,8 @@ void Scene::draw() { // Background _vm->_graphics->drawImage("episode1.tgp", _curScene); - // Static details - for (uint16 i = 0; i < MAX_HOTSPOTS; i++) { + for (uint16 i = 0; i < MAX_DETAILS; i++) { + // Static details StaticDetails s = _sceneInfo->staticDetails[i]; if (s.spriteNum >= 0 && s.x >= 0 && s.y >= 0 && !s.hide) _vm->_graphics->drawSprite(Common::String::format("det%d.taf", _curScene), s.spriteNum, s.x, s.y); @@ -107,23 +146,54 @@ void Scene::draw() { // TODO: These are all hardcoded for now _vm->_graphics->drawSprite("det1.taf", 0, 200, 100); _vm->_graphics->loadFont("6x8.tff"); - _vm->_graphics->drawText("This is a test", 200, 80); + //_vm->_graphics->drawText("This is a test", 200, 80); + + _vm->_graphics->setDescSurface(Common::Point(-1, -1)); } void Scene::updateMouse(Common::Point coords) { - // Animated details - // TODO: handle these + _vm->_graphics->restoreDescSurface(); // Static details for (uint16 i = 0; i < MAX_HOTSPOTS; i++) { - if (_sceneInfo->hotspot[i].contains(coords)) { - // TODO: Draw hotspot description on screen - debug("Coords %d, %d: '%s'", coords.x, coords.y, _sceneInfo->hotspotDesc[i].c_str()); + //_vm->_graphics->drawRect(_sceneInfo->hotspot[i].rect, 0); // debug + if (_sceneInfo->hotspot[i].rect.contains(coords) && _sceneInfo->hotspot[i].resource < kATSTextMax) { + if (coords.y >= 8) { + _vm->_graphics->setDescSurface(Common::Point(coords.x, coords.y - 8)); + _vm->_graphics->drawText(_sceneInfo->hotspot[i].desc, coords.x, coords.y - 8); + } break; } } } +void Scene::mouseClick(Common::Point coords) { + // Static details + for (uint16 i = 0; i < MAX_HOTSPOTS; i++) { + //_vm->_graphics->drawRect(_sceneInfo->hotspot[i].rect, 0); // debug + if (_sceneInfo->hotspot[i].rect.contains(coords)) { + int sample = -1; + + switch (_vm->_cursor->getCurrentCursor()) { + case kLook: + sample = _sceneInfo->hotspotSpeech[i].look; + break; + case kUse: + sample = _sceneInfo->hotspotSpeech[i].use; + break; + case kTalk: + sample = _sceneInfo->hotspotSpeech[i].talk; + break; + default: + break; + } + + if (sample >= 0) + _vm->_sound->playSpeech(sample); + } + } +} + void Scene::loadSceneInfo() { const uint32 sceneInfoSize = 3784; const uint32 headerRDI = MKTAG('R', 'D', 'I', '\0'); @@ -148,9 +218,23 @@ void Scene::loadSceneInfo() { // Animated details for (int i = 0; i < MAX_DETAILS; i++) { - _sceneInfo->animatedDetails[i].x = indexFile.readUint16LE(); - _sceneInfo->animatedDetails[i].y = indexFile.readUint16LE(); - indexFile.skip(66); // animated details info - TODO: read these + _sceneInfo->animatedDetails[i].x = indexFile.readSint16LE(); + _sceneInfo->animatedDetails[i].y = indexFile.readSint16LE(); + _sceneInfo->animatedDetails[i].startFlag = indexFile.readByte(); + _sceneInfo->animatedDetails[i].repeat = indexFile.readByte(); + _sceneInfo->animatedDetails[i].startSprite = indexFile.readSint16LE(); + _sceneInfo->animatedDetails[i].endSprite = indexFile.readSint16LE(); + _sceneInfo->animatedDetails[i].spriteCount = indexFile.readSint16LE(); + _sceneInfo->animatedDetails[i].delay = indexFile.readUint16LE(); + _sceneInfo->animatedDetails[i].delayCount = indexFile.readUint16LE(); + _sceneInfo->animatedDetails[i].reverse = indexFile.readUint16LE(); + _sceneInfo->animatedDetails[i].timerStart = indexFile.readUint16LE(); + _sceneInfo->animatedDetails[i].zIndex = indexFile.readUint16LE(); + _sceneInfo->animatedDetails[i].loadFlag = indexFile.readByte(); + _sceneInfo->animatedDetails[i].zoom = indexFile.readByte(); + indexFile.skip(42); // 2 * 3 * 7 = 42 bytes sound data - TODO + _sceneInfo->animatedDetails[i].showOneFrame = indexFile.readUint16LE(); + _sceneInfo->animatedDetails[i].currentFrame = indexFile.readUint16LE(); } // Static details @@ -158,49 +242,70 @@ void Scene::loadSceneInfo() { _sceneInfo->staticDetails[i].x = indexFile.readSint16LE(); _sceneInfo->staticDetails[i].y = indexFile.readSint16LE(); _sceneInfo->staticDetails[i].spriteNum = indexFile.readSint16LE(); - _sceneInfo->staticDetails[i].z = indexFile.readUint16LE(); + _sceneInfo->staticDetails[i].zIndex = indexFile.readUint16LE(); _sceneInfo->staticDetails[i].hide = indexFile.readByte(); indexFile.readByte(); // padding } // Hotspots for (int i = 0; i < MAX_HOTSPOTS; i++) { - _sceneInfo->hotspot[i].left = indexFile.readUint16LE(); - _sceneInfo->hotspot[i].top = indexFile.readUint16LE(); - _sceneInfo->hotspot[i].right = indexFile.readUint16LE(); - _sceneInfo->hotspot[i].bottom = indexFile.readUint16LE(); - if (!_sceneInfo->hotspot[i].isValidRect()) + _sceneInfo->hotspot[i].rect.left = indexFile.readUint16LE(); + _sceneInfo->hotspot[i].rect.top = indexFile.readUint16LE(); + _sceneInfo->hotspot[i].rect.right = indexFile.readUint16LE(); + _sceneInfo->hotspot[i].rect.bottom = indexFile.readUint16LE(); + if (!_sceneInfo->hotspot[i].rect.isValidRect()) warning("Hotspot %d has an invalid rect", i); } // Hotspot descriptions for (int i = 0; i < MAX_HOTSPOTS; i++) { - _sceneInfo->hotspotDescRes[i] = indexFile.readUint16LE(); - - if (_sceneInfo->hotspotDescRes[i] < 12) { - // TODO: Hotspot description IDs are off... investigate why - _sceneInfo->hotspotDesc[i] = text->getText(_curScene + kADSTextMax, _sceneInfo->hotspotDescRes[i])->text; - } else { - // TODO: Handle these types of hotspot descriptions - warning("Hotspot %d has an invalid description resource (%d)", i, _sceneInfo->hotspotDescRes[i]); - _sceneInfo->hotspotDesc[i] = Common::String::format("Hotspot %d", _sceneInfo->hotspotDescRes[i]); + _sceneInfo->hotspot[i].resource = indexFile.readUint16LE() + 4; + _sceneInfo->hotspot[i].desc = ""; + + if (_sceneInfo->hotspot[i].resource < kATSTextMax) { + TextEntry *entry = text->getText(_curScene + kADSTextMax, _sceneInfo->hotspot[i].resource); + if (entry) + _sceneInfo->hotspot[i].desc = entry->text; } } - _sceneInfo->roomNum = indexFile.readByte(); - _sceneInfo->picNum = indexFile.readByte(); - _sceneInfo->autoMoveCount = indexFile.readByte(); - _sceneInfo->loadTaf = indexFile.readByte(); + // Room info + _sceneInfo->roomInfo.roomNum = indexFile.readByte(); + _sceneInfo->roomInfo.picNum = indexFile.readByte(); + _sceneInfo->roomInfo.autoMoveCount = indexFile.readByte(); + _sceneInfo->roomInfo.loadTaf = indexFile.readByte(); + _sceneInfo->roomInfo.tafName = ""; for (int i = 0; i < 14; i++) - _sceneInfo->tafName += indexFile.readByte(); + _sceneInfo->roomInfo.tafName += indexFile.readByte(); - _sceneInfo->zoomFactor = indexFile.readByte(); + _sceneInfo->roomInfo.zoomFactor = indexFile.readByte(); indexFile.readByte(); // padding - // 6 * 20 = 120 bytes automove coordinates - TODO: read these - // MAX_DETAILS * 3 * 2 = 192 bytes voc - TODO: read these - // MAX_DETAILS * 3 = 96 bytes samples - TODO: read these + for (int i = 0; i < MAX_AUTOMOVE; i++) { + _sceneInfo->autoMove[i].x = indexFile.readSint16LE(); + _sceneInfo->autoMove[i].y = indexFile.readSint16LE(); + _sceneInfo->autoMove[i].spriteNum = indexFile.readByte(); + indexFile.readByte(); // padding + if (i > _sceneInfo->roomInfo.autoMoveCount && !(_sceneInfo->autoMove[i].x <= 0 || _sceneInfo->autoMove[i].y <= 0)) + warning("Auto move %d should be unused, but it isn't (max auto move items are %d)", i, _sceneInfo->roomInfo.autoMoveCount); + } + + for (int i = 0; i < MAX_DETAILS; i++) { + // FIXME: These are all wrong... investigate why + _sceneInfo->hotspotSpeech[i].look = indexFile.readSint16LE(); + _sceneInfo->hotspotSpeech[i].use = indexFile.readSint16LE(); + _sceneInfo->hotspotSpeech[i].talk = indexFile.readSint16LE(); + } + + for (int i = 0; i < MAX_DETAILS; i++) { + _sceneInfo->hotspotSound[i][0] = indexFile.readSint16LE(); + _sceneInfo->hotspotSound[i][1] = indexFile.readSint16LE(); + _sceneInfo->hotspotSound[i][2] = indexFile.readSint16LE(); + } + + // TODO: We seem to be missing a chunk of data (186 bytes) from the end of + // the room info structure delete text; indexFile.close(); diff --git a/engines/chewy/scene.h b/engines/chewy/scene.h index c5b87ac7ae..bcbbf6761e 100644 --- a/engines/chewy/scene.h +++ b/engines/chewy/scene.h @@ -37,6 +37,7 @@ public: void change(uint scene); void draw(); void updateMouse(Common::Point coords); + void mouseClick(Common::Point coords); uint getCurScene() const { return _curScene; } diff --git a/engines/chewy/text.cpp b/engines/chewy/text.cpp index cf0fb041a7..095b74b290 100644 --- a/engines/chewy/text.cpp +++ b/engines/chewy/text.cpp @@ -112,8 +112,14 @@ TextEntry *Text::getText(uint dialogNum, uint entryNum) { } } while (*ptr); - if (*(ptr + 1) != kEndText || *(ptr + 2) != kEndChunk) - error("Invalid text resource - %d, %d", dialogNum, entryNum); + if (*(ptr + 1) != kEndText || *(ptr + 2) != kEndChunk) { + warning("Invalid text resource - %d, %d", dialogNum, entryNum); + + delete[] data; + delete d; + + return nullptr; + } if (!isText) ptr += 3; // 0, kEndText, kEndChunk |