Ticket #8937: groovie2.patch

File groovie2.patch, 150.5 KB (added by spookypeanut, 16 years ago)

updated patch

  • configure

     
    8989add_engine cruise "Cinematique evo 2" no
    9090add_engine drascula "Drascula: The Vampire Strikes Back" yes
    9191add_engine gob "Gobli*ns" yes
     92add_engine groovie "Groovie" no
    9293add_engine igor "Igor: Objective Uikokahonia" no
    9394add_engine kyra "Legend of Kyrandia" yes
    9495add_engine lure "Lure of the Temptress" yes
  • engines/engines.mk

     
    4242MODULES += engines/gob
    4343endif
    4444
     45ifdef ENABLE_GROOVIE
     46DEFINES += -DENABLE_GROOVIE=$(ENABLE_GROOVIE)
     47MODULES += engines/groovie
     48endif
     49
    4550ifdef ENABLE_IGOR
    4651DEFINES += -DENABLE_IGOR=$(ENABLE_IGOR)
    4752MODULES += engines/igor
  • engines/groovie/lzss.h

     
     1/* ScummVM - Graphic Adventure Engine
     2 *
     3 * ScummVM is the legal property of its developers, whose names
     4 * are too numerous to list here. Please refer to the COPYRIGHT
     5 * file distributed with this source distribution.
     6 *
     7 * This program is free software; you can redistribute it and/or
     8 * modify it under the terms of the GNU General Public License
     9 * as published by the Free Software Foundation; either version 2
     10 * of the License, or (at your option) any later version.
     11
     12 * This program is distributed in the hope that it will be useful,
     13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15 * GNU General Public License for more details.
     16
     17 * You should have received a copy of the GNU General Public License
     18 * along with this program; if not, write to the Free Software
     19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
     20 *
     21 * $URL$
     22 * $Id$
     23 *
     24 */
     25
     26#include "common/stream.h"
     27
     28class LzssReadStream : public Common::ReadStream {
     29private:
     30        uint8 *_outLzssBufData;
     31        uint32 _size;
     32        uint32 _pos;
     33
     34        uint32 decodeLZSS(Common::ReadStream *in, uint8 lengthmask, uint8 lengthbits);
     35
     36public:
     37        LzssReadStream(Common::ReadStream *indata, uint8 lengthmask, uint8 lengthbits);
     38        ~LzssReadStream();
     39
     40        bool eos() const;
     41        uint32 read(void *buf, uint32 size);
     42};
  • engines/groovie/graphics.cpp

     
     1/* ScummVM - Graphic Adventure Engine
     2 *
     3 * ScummVM is the legal property of its developers, whose names
     4 * are too numerous to list here. Please refer to the COPYRIGHT
     5 * file distributed with this source distribution.
     6 *
     7 * This program is free software; you can redistribute it and/or
     8 * modify it under the terms of the GNU General Public License
     9 * as published by the Free Software Foundation; either version 2
     10 * of the License, or (at your option) any later version.
     11
     12 * This program is distributed in the hope that it will be useful,
     13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15 * GNU General Public License for more details.
     16
     17 * You should have received a copy of the GNU General Public License
     18 * along with this program; if not, write to the Free Software
     19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
     20 *
     21 * $URL$
     22 * $Id$
     23 *
     24 */
     25
     26#include "groovie/groovie.h"
     27#include "groovie/graphics.h"
     28
     29namespace Groovie {
     30
     31GraphicsMan::GraphicsMan(GroovieEngine *vm) :
     32        _vm(vm), _changed(false), _fading(0) {
     33        // Create the game surfaces
     34        _foreground.create(640, 320, 1);
     35        _background.create(640, 320, 1);
     36}
     37
     38GraphicsMan::~GraphicsMan() {
     39        // Free the game surfaces
     40        _foreground.free();
     41        _background.free();
     42}
     43
     44void GraphicsMan::update() {
     45        if (_fading) {
     46                // Set the start time
     47                uint32 time = _vm->_system->getMillis() - _fadeStartTime;
     48
     49                // Scale the time
     50                int step = time / 4;
     51                if (step > 256) {
     52                        step = 256;
     53                }
     54
     55                if (_fading == 1) {
     56                        // Apply the fade in
     57                        applyFading(step);
     58                } else if (_fading == 2) {
     59                        // Apply the fade out
     60                        applyFading(256 - step);
     61
     62                        // Clear the buffer when ending the fade out
     63                        if (step == 256)
     64                                _foreground.fillRect(Common::Rect::Rect(640, 320), 0);
     65                }
     66
     67                // Check for the end
     68                if (step == 256) {
     69                        _fading = 0;
     70                }
     71        }
     72
     73        // Update the screen if needed and reset the status
     74        if (_changed) {
     75                _vm->_system->updateScreen();
     76                _changed = false;
     77        }
     78}
     79
     80void GraphicsMan::change() {
     81        _changed = true;
     82}
     83
     84void GraphicsMan::mergeFgAndBg() {
     85        uint32 i;
     86        byte *countf, *countb;
     87
     88        countf = (byte *)_foreground.getBasePtr(0, 0);
     89        countb = (byte *)_background.getBasePtr(0, 0);
     90        for (i = 640 * 320; i; i--) {
     91                if (255 == *(countf)) {
     92                        *(countf) = *(countb);
     93                }
     94                countf++;
     95                countb++;
     96        }
     97}
     98
     99
     100void GraphicsMan::updateScreen(Graphics::Surface *source) {
     101        _vm->_system->copyRectToScreen((byte *)source->getBasePtr(0, 0), 640, 0, 80, 640, 320);
     102        change();
     103}
     104
     105bool GraphicsMan::isFading() {
     106        return _fading;
     107}
     108
     109void GraphicsMan::fadeIn(byte *pal) {
     110        // Set the start time
     111        _fadeStartTime = _vm->_system->getMillis();
     112
     113        // Copy the target palette
     114        for (int i = 0; i < 256; i++) {
     115                _paletteFull[(i * 4) + 0] = pal[(i * 3) + 0];
     116                _paletteFull[(i * 4) + 1] = pal[(i * 3) + 1];
     117                _paletteFull[(i * 4) + 2] = pal[(i * 3) + 2];
     118        }
     119
     120        // Apply a black palette right now
     121        applyFading(0);
     122
     123        // Set the current fading
     124        _fading = 1;
     125}
     126
     127void GraphicsMan::fadeOut() {
     128        // Set the start time
     129        _fadeStartTime = _vm->_system->getMillis();
     130
     131        // Get the current palette
     132        _vm->_system->grabPalette(_paletteFull, 0, 256);
     133
     134        // Set the current fading
     135        _fading = 2;
     136}
     137
     138void GraphicsMan::applyFading(int step) {
     139        // Calculate the fade factor for the given step
     140        int factorR = 256 - (256 - step) * 1;
     141        int factorGB = 256 - (256 - step) * 2;
     142
     143        if (factorR <= 0) factorR = 0;
     144        if (factorGB <= 0) factorGB = 0;
     145
     146        // Calculate the new palette
     147        byte newpal[256 * 4];
     148        for (int i = 0; i < 256; i++) {
     149                newpal[(i * 4) + 0] = (_paletteFull[(i * 4) + 0] * factorR) / 256;
     150                newpal[(i * 4) + 1] = (_paletteFull[(i * 4) + 1] * factorGB) / 256;
     151                newpal[(i * 4) + 2] = (_paletteFull[(i * 4) + 2] * factorGB) / 256;
     152        }
     153
     154        // Set the screen palette
     155        _vm->_system->setPalette(newpal, 0, 256);
     156
     157        // Request a screen update
     158        change();
     159}
     160
     161} // End of Groovie namespace
  • engines/groovie/roq.cpp

     
     1/* ScummVM - Graphic Adventure Engine
     2 *
     3 * ScummVM is the legal property of its developers, whose names
     4 * are too numerous to list here. Please refer to the COPYRIGHT
     5 * file distributed with this source distribution.
     6 *
     7 * This program is free software; you can redistribute it and/or
     8 * modify it under the terms of the GNU General Public License
     9 * as published by the Free Software Foundation; either version 2
     10 * of the License, or (at your option) any later version.
     11
     12 * This program is distributed in the hope that it will be useful,
     13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15 * GNU General Public License for more details.
     16
     17 * You should have received a copy of the GNU General Public License
     18 * along with this program; if not, write to the Free Software
     19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
     20 *
     21 * $URL$
     22 * $Id$
     23 *
     24 */
     25
     26#include "groovie/groovie.h"
     27#include "groovie/roq.h"
     28
     29#include "sound/mixer.h"
     30
     31namespace Groovie {
     32
     33ROQPlayer::ROQPlayer(GroovieEngine *vm) :
     34        VideoPlayer(vm) {
     35}
     36
     37ROQPlayer::~ROQPlayer() {
     38}
     39
     40uint16 ROQPlayer::loadInternal() {
     41        // Begin reading the file
     42        debugC(1, kGroovieDebugVideo | kGroovieDebugAll, "Groovie::ROQ: Loading video");
     43
     44        // Read the file header
     45        ROQBlockHeader blockHeader;
     46        if (!readBlockHeader(blockHeader)) {
     47                return 0;
     48        }
     49        if (blockHeader.type != 0x1084 || blockHeader.size != 0 || blockHeader.param != 0) {
     50                return 0;
     51        }
     52
     53        // Hardcoded FPS
     54        return 25;
     55}
     56
     57bool ROQPlayer::playFrameInternal() {
     58        debugC(5, kGroovieDebugVideo | kGroovieDebugAll, "Groovie::ROQ: Playing frame");
     59
     60        // Process the needed blocks until the next video frame
     61        bool endframe = false;
     62        while (!endframe && !_file->eos()) {
     63                endframe = processBlock();
     64        }
     65
     66        // Wait until the current frame can be shown
     67        waitFrame();
     68
     69        // Update the screen
     70        _syst->updateScreen();
     71
     72        // Return whether the video has ended
     73        return _file->eos();
     74}
     75
     76bool ROQPlayer::readBlockHeader(ROQBlockHeader &blockHeader) {
     77        if (_file->eos()) {
     78                return false;
     79        } else {
     80                blockHeader.type = _file->readUint16LE();
     81                blockHeader.size = _file->readUint32LE();
     82                blockHeader.param = _file->readUint16LE();
     83
     84                debugC(10, kGroovieDebugVideo | kGroovieDebugAll, "Groovie::ROQ: Block type = 0x%02X", blockHeader.type);
     85                debugC(10, kGroovieDebugVideo | kGroovieDebugAll, "Groovie::ROQ: Block size = 0x%08X", blockHeader.size);
     86                debugC(10, kGroovieDebugVideo | kGroovieDebugAll, "Groovie::ROQ: Block param = 0x%04X", blockHeader.param);
     87
     88                return true;
     89        }
     90}
     91
     92bool ROQPlayer::processBlock() {
     93        // Read the header of the block
     94        ROQBlockHeader blockHeader;
     95        if (!readBlockHeader(blockHeader)) {
     96                return true;
     97        }
     98
     99        bool ok = true;
     100        bool endframe = false;
     101        switch (blockHeader.type) {
     102        case 0x1001: // Video info
     103                ok = processBlockInfo(blockHeader);
     104                break;
     105        case 0x1002: // Quad codebook definition
     106                ok = processBlockQuadCodebook(blockHeader);
     107                break;
     108        case 0x1011: // Quad vector quantised video frame
     109                ok = processBlockQuadVector(blockHeader);
     110                endframe = true;
     111                break;
     112        case 0x1012: // Still image (JPEG)
     113                ok = processBlockStill(blockHeader);
     114                endframe = true;
     115                break;
     116        case 0x1013: // Hang
     117                //warning("Groovie::ROQ: Hang block (skipped)");
     118                break;
     119        case 0x1020: // Mono sound samples
     120                ok = processBlockSoundMono(blockHeader);
     121                break;
     122        case 0x1021: // Stereo sound samples
     123                ok = processBlockSoundStereo(blockHeader);
     124                break;
     125        case 0x1030: // Audio container
     126                ok = processBlockAudioContainer(blockHeader);
     127                break;
     128        default:
     129                error("Groovie::ROQ: Unknown block type: 0x%04X", blockHeader.type);
     130                ok = false;
     131        }
     132
     133        // End the frame when the graphics have been modified or when there's an error
     134        return endframe || !ok;
     135}
     136
     137bool ROQPlayer::processBlockInfo(ROQBlockHeader &blockHeader) {
     138        debugC(5, kGroovieDebugVideo | kGroovieDebugAll, "Groovie::ROQ: Processing info block");
     139
     140        // Verify the block header
     141        if (blockHeader.type != 0x1001 || blockHeader.size != 8 || blockHeader.param != 0) {
     142                return false;
     143        }
     144
     145        uint16 tmp;
     146        tmp = _file->readUint16LE();
     147        debugC(5, kGroovieDebugVideo | kGroovieDebugAll, "w = %d\n", tmp);
     148        if (tmp != 640) {
     149                return false;
     150        }
     151        tmp = _file->readUint16LE();
     152        debugC(5, kGroovieDebugVideo | kGroovieDebugAll, "h = %d\n", tmp);
     153        if (tmp != 320) {
     154                return false;
     155        }
     156        tmp = _file->readUint16LE();
     157        debugC(5, kGroovieDebugVideo | kGroovieDebugAll, "unk1 = %d\n", tmp);
     158        if (tmp != 8) {
     159                return false;
     160        }
     161        tmp = _file->readUint16LE();
     162        debugC(5, kGroovieDebugVideo | kGroovieDebugAll, "unk2 = %d\n", tmp);
     163        if (tmp != 4) {
     164                return false;
     165        }
     166        return true;
     167}
     168
     169bool ROQPlayer::processBlockQuadCodebook(ROQBlockHeader &blockHeader) {
     170        debugC(5, kGroovieDebugVideo | kGroovieDebugAll, "Groovie::ROQ: Processing quad codebook block");
     171
     172        // Get the number of 2x2 pixel blocks
     173        _num2blocks = blockHeader.param >> 8;
     174        if (_num2blocks == 0) {
     175                _num2blocks = 256;
     176        }
     177
     178        // Get the number of 4x4 pixel blocks
     179        _num4blocks = blockHeader.param & 0xFF;
     180        if (_num4blocks == 0 && (blockHeader.size > (uint32)_num2blocks * 6)) {
     181                _num4blocks = 256;
     182        }
     183
     184        _file->skip(_num2blocks * 6);
     185        _file->skip(_num4blocks * 4);
     186
     187        return true;
     188}
     189
     190bool ROQPlayer::processBlockQuadVector(ROQBlockHeader &blockHeader) {
     191        debugC(5, kGroovieDebugVideo | kGroovieDebugAll, "Groovie::ROQ: Processing quad vector block");
     192        _file->skip(blockHeader.size);
     193        return true;
     194
     195        // Get the mean motion vectors
     196        //byte Mx = blockHeader.param >> 8;
     197        //byte My = blockHeader.param & 0xFF;
     198
     199int32 ends =_file->pos() + blockHeader.size;
     200        int numblocks = (640 / 8) * (320 / 8);
     201        for (int j = 0; j < numblocks && ends > _file->pos(); j++) {
     202                debugC(5, kGroovieDebugVideo | kGroovieDebugAll, "doing block %d/%d\n", j, numblocks);
     203                uint16 codingType = _file->readUint16LE();
     204                for (int i = 0; i < 8; i++) {
     205                        switch (codingType >> 14) {
     206                        case 0: // MOT: Skip block
     207                                //printf("coding type 0\n");
     208                                break;
     209                        case 1: { // FCC: Copy an existing block
     210                                //printf("coding type 1\n");
     211                                byte argument;
     212                                argument = _file->readByte();
     213                                //byte Dx = Mx + (argument >> 4);
     214                                //byte Dy = My + (argument & 0x0F);
     215                                // Dx = X + 8 - (argument >> 4) - Mx
     216                                // Dy = Y + 8 - (argument & 0x0F) - My
     217                                break;
     218                        }
     219                        case 2: { // SLD: Quad vector quantisation
     220                                //printf("coding type 2\n");
     221                                byte argument = _file->readByte();
     222                                if (argument > _num4blocks) {
     223                                        //error("invalid 4x4 block %d of %d", argument, _num4blocks);
     224                                }
     225                                // Upsample the 4x4 pixel block
     226                                break;
     227                        }
     228                        case 3: // CCC:
     229                                //printf("coding type 3:\n");
     230                                processBlockQuadVectorSub(blockHeader);
     231                                break;
     232                        }
     233                        codingType <<= 2;
     234                }
     235        }
     236debugC(5, kGroovieDebugVideo | kGroovieDebugAll, "Should have ended at %d, and has ended at %d\n", ends, _file->pos());
     237        return true;
     238}
     239
     240bool ROQPlayer::processBlockQuadVectorSub(ROQBlockHeader &blockHeader) {
     241        debugC(5, kGroovieDebugVideo | kGroovieDebugAll, "Groovie::ROQ: Processing quad vector sub block");
     242
     243        // Get the mean motion vectors
     244        //byte Mx = blockHeader.param >> 8;
     245        //byte My = blockHeader.param & 0xFF;
     246
     247        uint16 codingType = _file->readUint16LE();
     248        for (int i = 0; i < 4; i++) {
     249                switch (codingType >> 14) {
     250                case 0: // MOT: Skip block
     251                        //printf("coding type 0\n");
     252                        break;
     253                case 1: { // FCC: Copy an existing block
     254                        //printf("coding type 1\n");
     255                        byte argument;
     256                        argument = _file->readByte();
     257                        //byte Dx = Mx + (argument >> 4);
     258                        //byte Dy = My + (argument & 0x0F);
     259                        // Dx = X + 8 - (argument >> 4) - Mx
     260                        // Dy = Y + 8 - (argument & 0x0F) - My
     261                        break;
     262                }
     263                case 2: { // SLD: Quad vector quantisation
     264                        //printf("coding type 2\n");
     265                        byte argument = _file->readByte();
     266                        if (argument > _num2blocks) {
     267                                //error("invalid 2x2 block: %d of %d", argument, _num2blocks);
     268                        }
     269                        break;
     270                }
     271                case 3:
     272                        //printf("coding type 3\n");
     273                        _file->readByte();
     274                        _file->readByte();
     275                        _file->readByte();
     276                        _file->readByte();
     277                        break;
     278                }
     279                codingType <<= 2;
     280        }
     281        return true;
     282}
     283
     284bool ROQPlayer::processBlockStill(ROQBlockHeader &blockHeader) {
     285        debugC(5, kGroovieDebugVideo | kGroovieDebugAll, "Groovie::ROQ: Processing still (JPEG) block");
     286        //Common::ReadStream *jpegData = new Common::SubReadStream(_file, blockHeader.size);
     287        //Graphics::JPEG jpegFrame;
     288        //jpegFrame.read(jpegData);
     289        /*
     290        Common::File save;
     291        save.open("dump.jpg", Common::File::kFileWriteMode);
     292        save.write(data, blockHeader.size);
     293        save.close();
     294        */
     295        error("JPEG!");
     296        return true;
     297}
     298
     299bool ROQPlayer::processBlockSoundMono(ROQBlockHeader &blockHeader) {
     300        debugC(5, kGroovieDebugVideo | kGroovieDebugAll, "Groovie::ROQ: Processing mono sound block");
     301
     302        // Verify the block header
     303        if (blockHeader.type != 0x1020) {
     304                return false;
     305        }
     306
     307        // Initialize the audio stream if needed
     308        if (!_audioStream) {
     309                byte flags = Audio::Mixer::FLAG_16BITS | Audio::Mixer::FLAG_AUTOFREE;
     310#ifdef SCUMM_LITTLE_ENDIAN
     311                flags |= Audio::Mixer::FLAG_LITTLE_ENDIAN;
     312#endif
     313                _audioStream = Audio::makeAppendableAudioStream(22050, flags);
     314                Audio::SoundHandle sound_handle;
     315                ::g_engine->_mixer->playInputStream(Audio::Mixer::kPlainSoundType, &sound_handle, _audioStream);
     316        }
     317
     318        // Create the audio buffer
     319        int16 *buffer = new int16[blockHeader.size];
     320
     321        // Initialize the prediction with the block parameter
     322        int16 prediction = blockHeader.param ^ 0x8000;
     323
     324        // Process the data
     325        for (uint16 i = 0; i < blockHeader.size; i++) {
     326                int16 data = _file->readByte();
     327                if (data < 0x80) {
     328                        prediction += data * data;
     329                } else {
     330                        data -= 0x80;
     331                        prediction -= data * data;
     332                }
     333                buffer[i] = prediction;
     334        }
     335
     336        // Queue the read buffer
     337        _audioStream->queueBuffer((byte *)buffer, blockHeader.size * 2);
     338
     339        return true;
     340}
     341
     342bool ROQPlayer::processBlockSoundStereo(ROQBlockHeader &blockHeader) {
     343        debugC(5, kGroovieDebugVideo | kGroovieDebugAll, "Groovie::ROQ: Processing stereo sound block");
     344
     345        // Verify the block header
     346        if (blockHeader.type != 0x1021) {
     347                return false;
     348        }
     349
     350        // Initialize the audio stream if needed
     351        if (!_audioStream) {
     352                byte flags = Audio::Mixer::FLAG_16BITS | Audio::Mixer::FLAG_AUTOFREE | Audio::Mixer::FLAG_STEREO;
     353#ifdef SCUMM_LITTLE_ENDIAN
     354                flags |= Audio::Mixer::FLAG_LITTLE_ENDIAN;
     355#endif
     356                _audioStream = Audio::makeAppendableAudioStream(22050, flags);
     357                Audio::SoundHandle sound_handle;
     358                ::g_engine->_mixer->playInputStream(Audio::Mixer::kPlainSoundType, &sound_handle, _audioStream);
     359        }
     360
     361        // Create the audio buffer
     362        int16 *buffer = new int16[blockHeader.size];
     363
     364        // Initialize the prediction with the block parameter
     365        int16 predictionLeft = (blockHeader.param & 0xFF00) ^ 0x8000;
     366        int16 predictionRight = (blockHeader.param << 8) ^ 0x8000;
     367        bool left = true;
     368
     369        // Process the data
     370        for (uint16 i = 0; i < blockHeader.size; i++) {
     371                int16 data = _file->readByte();
     372                if (left) {
     373                        if (data < 0x80) {
     374                                predictionLeft += data * data;
     375                        } else {
     376                                data -= 0x80;
     377                                predictionLeft -= data * data;
     378                        }
     379                        buffer[i] = predictionLeft;
     380                } else {
     381                        if (data < 0x80) {
     382                                predictionRight += data * data;
     383                        } else {
     384                                data -= 0x80;
     385                                predictionRight -= data * data;
     386                        }
     387                        buffer[i] = predictionRight;
     388                }
     389                left = !left;
     390        }
     391
     392        // Queue the read buffer
     393        _audioStream->queueBuffer((byte *)buffer, blockHeader.size * 2);
     394
     395        return true;
     396}
     397
     398bool ROQPlayer::processBlockAudioContainer(ROQBlockHeader &blockHeader) {
     399        debugC(5, kGroovieDebugVideo | kGroovieDebugAll, "Groovie::ROQ: Processing audio container block: 0x%04X", blockHeader.param);
     400        return true;
     401}
     402
     403} // End of Groovie namespace
  • engines/groovie/vdx.cpp

     
     1/* ScummVM - Graphic Adventure Engine
     2 *
     3 * ScummVM is the legal property of its developers, whose names
     4 * are too numerous to list here. Please refer to the COPYRIGHT
     5 * file distributed with this source distribution.
     6 *
     7 * This program is free software; you can redistribute it and/or
     8 * modify it under the terms of the GNU General Public License
     9 * as published by the Free Software Foundation; either version 2
     10 * of the License, or (at your option) any later version.
     11
     12 * This program is distributed in the hope that it will be useful,
     13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15 * GNU General Public License for more details.
     16
     17 * You should have received a copy of the GNU General Public License
     18 * along with this program; if not, write to the Free Software
     19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
     20 *
     21 * $URL$
     22 * $Id$
     23 *
     24 */
     25
     26#include "groovie/groovie.h"
     27#include "groovie/lzss.h"
     28#include "groovie/vdx.h"
     29
     30#include "sound/mixer.h"
     31
     32#define TILE_SIZE 4             // Size of each tile on the image: only ever seen 4 so far
     33#define VDX_IDENT 0x9267        // 37479
     34
     35namespace Groovie {
     36
     37VDXPlayer::VDXPlayer(GroovieEngine *vm) :
     38        VideoPlayer(vm), _origX(0), _origY(0), _flagOnePrev(false),
     39        _fg(&_vm->_graphicsMan->_foreground), _bg(&_vm->_graphicsMan->_background) {
     40}
     41
     42VDXPlayer::~VDXPlayer() {
     43        //delete _audioStream;
     44}
     45
     46void VDXPlayer::setOrigin(int16 x, int16 y) {
     47        _origX = x;
     48        _origY = y;
     49}
     50
     51uint16 VDXPlayer::loadInternal() {
     52        uint32 engine_level = kGroovieDebugVideo | kGroovieDebugAll;
     53        if ((gDebugLevel == 11) || (Common::getEnabledSpecialDebugLevels() & engine_level)) {
     54                int8 i;
     55                debugN(1, "Groovie::VDX: New VDX: bitflags are ");
     56                for (i = 11; i >= 0; i--) {
     57                        debugN(1, "%d", _flags & (1 << i)? 1 : 0);
     58                        if (i % 4 == 0) {
     59                                debugN(1, " ");
     60                        }
     61                }
     62                debug(1, " ");
     63        }
     64        // Flags:
     65        // - 1 Puzzle piece? Skip palette, don't redraw full screen, draw still to b/ack buffer
     66        // - 2 Transparent colour is 0xFF
     67        // - 5 Skip still chunks
     68        // - 7
     69        // - 8 Just show the first frame
     70        // - 9 Start a palette fade in
     71        _flagZero =             ((_flags & (1 << 0)) != 0);
     72        _flagOne =              ((_flags & (1 << 1)) != 0);
     73        _flag2Byte =            (_flags & (1 << 2)) ? 0xFF : 0x00;
     74        _flagThree =            ((_flags & (1 << 3)) != 0);
     75        _flagFour =             ((_flags & (1 << 4)) != 0);
     76        _flagFive =             ((_flags & (1 << 5)) != 0);
     77        _flagSix =              ((_flags & (1 << 6)) != 0);
     78        _flagSeven =            ((_flags & (1 << 7)) != 0);
     79        _flagEight =            ((_flags & (1 << 8)) != 0);
     80        _flagNine =             ((_flags & (1 << 9)) != 0);
     81
     82        if (_flagOnePrev && !_flagOne && !_flagEight) {
     83                _flagSeven = true;
     84        }
     85
     86        // Save _flagOne for the next video
     87        _flagOnePrev = _flagOne;
     88
     89        //_flagTransparent =    _flagOne;
     90        _flagFirstFrame =       _flagEight;
     91        //_flagSkipPalette =    _flagSeven;
     92        _flagSkipPalette =      false;
     93        //_flagSkipStill =      _flagFive || _flagSeven;
     94        //_flagUpdateStill =    _flagNine || _flagSix;
     95
     96        // Begin reading the file
     97        debugC(1, kGroovieDebugVideo | kGroovieDebugAll, "Groovie::VDX: Playing video");
     98
     99        if (_file->readUint16LE() != VDX_IDENT) {
     100                error("Groovie::VDX: This does not appear to be a 7th guest vxd file");
     101                return 0;
     102        } else {
     103                debugC(5, kGroovieDebugVideo | kGroovieDebugAll, "Groovie::VDX: VDX file identified correctly");
     104        }
     105
     106        uint16 tmp;
     107
     108        // Skip unknown data: 6 bytes, ref Martine
     109        tmp = _file->readUint16LE();
     110        debugC(2, kGroovieDebugVideo | kGroovieDebugUnknown | kGroovieDebugAll, "Groovie::VDX: Martine1 = 0x%04X", tmp);
     111        tmp = _file->readUint16LE();
     112        debugC(2, kGroovieDebugVideo | kGroovieDebugUnknown | kGroovieDebugAll, "Groovie::VDX: Martine2 = 0x%04X", tmp);
     113        tmp = _file->readUint16LE();
     114        debugC(2, kGroovieDebugVideo | kGroovieDebugUnknown | kGroovieDebugAll, "Groovie::VDX: Martine3 (FPS?) = %d", tmp);
     115
     116        return tmp;
     117}
     118
     119bool VDXPlayer::playFrameInternal() {
     120        byte currRes = 0x80;
     121        while (!_file->eos() && currRes == 0x80) {
     122                currRes = _file->readByte();
     123
     124                // Skip unknown data: 1 byte, ref Edward
     125                byte tmp = _file->readByte();
     126                debugC(5, kGroovieDebugVideo | kGroovieDebugUnknown | kGroovieDebugAll, "Groovie::VDX: Edward = 0x%04X", tmp);
     127
     128                uint32 compSize = _file->readUint32LE();
     129                uint8 lengthmask = _file->readByte();
     130                uint8 lengthbits = _file->readByte();
     131
     132                // Read the chunk data and decompress if needed
     133                Common::ReadStream *vdxData = new Common::SubReadStream(_file, compSize);
     134                if (lengthmask && lengthbits) {
     135                        Common::ReadStream *decompData = new LzssReadStream(vdxData, lengthmask, lengthbits);
     136                        delete vdxData;
     137                        vdxData = decompData;
     138                }
     139
     140                // Use the current chunk
     141                switch (currRes) {
     142                        case 0x00:
     143                                debugC(6, kGroovieDebugVideo | kGroovieDebugAll, "Groovie::VDX: Replay frame");
     144                                break;
     145                        case 0x20:
     146                                debugC(5, kGroovieDebugVideo | kGroovieDebugAll, "Groovie::VDX: Still frame");
     147                                getStill(vdxData);
     148                                break;
     149                        case 0x25:
     150                                debugC(5, kGroovieDebugVideo | kGroovieDebugAll, "Groovie::VDX: Animation frame");
     151                                getDelta(vdxData);
     152                                break;
     153                        case 0x80:
     154                                debugC(5, kGroovieDebugVideo | kGroovieDebugAll, "Groovie::VDX: Sound resource");
     155                                chunkSound(vdxData);
     156                                break;
     157                        default:
     158                                error("Groovie::VDX: Invalid resource type: %d", currRes);
     159                }
     160                delete vdxData;
     161        }
     162
     163        // Wait until the current frame can be shown
     164        waitFrame();
     165
     166        // TODO: Move it to a better place
     167        // Update the screen
     168        if (currRes == 0x25) {
     169                //if (_flagSeven) {
     170                        //_vm->_graphicsMan->mergeFgAndBg();
     171                //}
     172                _vm->_graphicsMan->updateScreen(_bg);
     173        }
     174
     175        // Report the end of the video if we reached the end of the file or if we
     176        // just wanted to play one frame.
     177        return _file->eos() || _flagFirstFrame;
     178}
     179
     180static const uint16 vdxBlockMapLookup[] = {
     1810xc800, 0xec80, 0xfec8, 0xffec, 0xfffe, 0x3100, 0x7310, 0xf731, 0xff73, 0xfff7, 0x6c80, 0x36c8, 0x136c, 0x6310, 0xc631, 0x8c63,
     1820xf000, 0xff00, 0xfff0, 0x1111, 0x3333, 0x7777, 0x6666, 0xcccc, 0x0ff0, 0x00ff, 0xffcc, 0x0076, 0xff33, 0x0ee6, 0xccff, 0x6770,
     1830x33ff, 0x6ee0, 0x4800, 0x2480, 0x1248, 0x0024, 0x0012, 0x2100, 0x4210, 0x8421, 0x0042, 0x0084, 0xf888, 0x0044, 0x0032, 0x111f,
     1840x22e0, 0x4c00, 0x888f, 0x4470, 0x2300, 0xf111, 0x0e22, 0x00c4, 0xf33f, 0xfccf, 0xff99, 0x99ff, 0x4444, 0x2222, 0xccee, 0x7733,
     1850x00f8, 0x00f1, 0x00bb, 0x0cdd, 0x0f0f, 0x0f88, 0x13f1, 0x19b3, 0x1f80, 0x226f, 0x27ec, 0x3077, 0x3267, 0x37e4, 0x38e3, 0x3f90,
     1860x44cf, 0x4cd9, 0x4c99, 0x5555, 0x603f, 0x6077, 0x6237, 0x64c9, 0x64cd, 0x6cd9, 0x70ef, 0x0f00, 0x00f0, 0x0000, 0x4444, 0x2222
     187};
     188
     189void VDXPlayer::getDelta(Common::ReadStream *in) {
     190        uint16 j, k, l;
     191        uint32 offset;
     192        uint8 currOpCode, param1, param2, param3;
     193
     194        // Get the size of the local palette
     195        j = in->readUint16LE();
     196
     197        // Load the palette if it isn't empty
     198        if (j) {
     199                uint16 palBitField[16];
     200                int flag = 1, palIndex;
     201
     202                // Load the bit field
     203                for (l = 0; l < 16; l++) {
     204                        palBitField[l] = in->readUint16LE();
     205                }
     206
     207                // Load the actual palette
     208                for (l = 0; l < 16; l++) {
     209                        flag = 1 << 15;
     210                        for (j = 0; j < 16; j++) {
     211                                palIndex = (l * 16) + j;
     212
     213                                if (flag & palBitField[l]) {
     214                                        for (k = 0; k < 3; k++) {
     215                                                _palBuf[(palIndex * 3) + k] = in->readByte();
     216                                        }
     217                                }
     218                                flag = flag >> 1;
     219                        }
     220                }
     221
     222                // Apply the palette
     223                if (!_flagSix && !_flagSeven) {
     224                        setPalette(_palBuf);
     225                }
     226        }
     227        currOpCode = in->readByte();
     228
     229        /* j now becomes the current block line we're dealing with */
     230        j = 0;
     231        offset = 0;
     232        while (!in->eos()) {
     233                byte colours[16];
     234                if (currOpCode < 0x60) {
     235                        param1 = in->readByte();
     236                        param2 = in->readByte();
     237                        expandColourMap(colours, vdxBlockMapLookup[currOpCode], param1, param2);
     238                        decodeBlockDelta(offset, colours, 640);
     239                        offset += TILE_SIZE;
     240                } else if (currOpCode > 0x7f) {
     241                        param1 = in->readByte();
     242                        param2 = in->readByte();
     243                        param3 = in->readByte();
     244                        expandColourMap(colours, (param1 << 8) + currOpCode, param2, param3);
     245                        decodeBlockDelta(offset, colours, 640);
     246                        offset += TILE_SIZE;
     247                } else switch (currOpCode) {
     248                        case 0x60: /* Fill tile with the 16 colours given as parameters */
     249                                for (l = 0; l < 16; l++) {
     250                                        colours[l] = in->readByte();
     251                                }
     252                                decodeBlockDelta(offset, colours, 640);
     253                                offset += TILE_SIZE;
     254                                break;
     255                        case 0x61: /* Skip to the end of this line, next block is start of next */
     256                                /* Note this is used at the end of EVERY line */
     257                                j++;
     258                                offset = j * TILE_SIZE * 640;
     259                                break;
     260                        case 0x62:
     261                        case 0x63:
     262                        case 0x64:
     263                        case 0x65:
     264                        case 0x66:
     265                        case 0x67:
     266                        case 0x68:
     267                        case 0x69:
     268                        case 0x6a:
     269                        case 0x6b: /* Skip next param1 blocks (within line) */
     270                                offset += (currOpCode - 0x62) * TILE_SIZE;
     271                                break;
     272                        case 0x6c:
     273                        case 0x6d:
     274                        case 0x6e:
     275                        case 0x6f:
     276                        case 0x70:
     277                        case 0x71:
     278                        case 0x72:
     279                        case 0x73:
     280                        case 0x74:
     281                        case 0x75: /* Next param1 blocks are filled with colour param2 */
     282                                param1 = currOpCode - 0x6b;
     283                                param2 = in->readByte();
     284                                for (l = 0; l < 16; l++) {
     285                                        colours[l] = param2;
     286                                }
     287                                for (k = 0; k < param1; k++) {
     288                                        decodeBlockDelta(offset, colours, 640);
     289                                        offset += TILE_SIZE;
     290                                }
     291                                break;
     292                        case 0x76:
     293                        case 0x77:
     294                        case 0x78:
     295                        case 0x79:
     296                        case 0x7a:
     297                        case 0x7b:
     298                        case 0x7c:
     299                        case 0x7d:
     300                        case 0x7e:
     301                        case 0x7f: /* Next bytes contain colours to fill the next param1 blocks in the current line*/
     302                                param1 = currOpCode - 0x75;
     303                                for (k = 0; k < param1; k++) {
     304                                        param2 = in->readByte();
     305                                        for (l = 0; l < 16; l++) {
     306                                                colours[l] = param2;
     307                                        }
     308                                        decodeBlockDelta(offset, colours, 640);
     309                                        offset += TILE_SIZE;
     310                                }
     311                                break;
     312                        default:
     313                                error("Groovie::VDX: Broken somehow");
     314                }
     315                currOpCode = in->readByte();
     316        }
     317}
     318
     319void VDXPlayer::getStill(Common::ReadStream *in) {
     320        uint16 numXTiles = in->readUint16LE();
     321        debugC(5, kGroovieDebugVideo | kGroovieDebugAll, "Groovie::VDX: numXTiles=%d", numXTiles);
     322        uint16 numYTiles = in->readUint16LE();
     323        debugC(5, kGroovieDebugVideo | kGroovieDebugAll, "Groovie::VDX: numYTiles=%d", numYTiles);
     324
     325        // It's skipped in the original:
     326        uint16 colourDepth = in->readUint16LE();
     327        debugC(5, kGroovieDebugVideo | kGroovieDebugAll, "Groovie::VDX: colourDepth=%d", colourDepth);
     328
     329        uint16 imageWidth = TILE_SIZE * numXTiles;
     330
     331        uint8 mask = 0;
     332        byte *buf;
     333        if (_flagOne) {
     334                // Paint to the foreground
     335                buf = (byte *)_fg->getBasePtr(0, 0);
     336                if (_flag2Byte) {
     337                        mask = 0xff;
     338                } else {
     339                        mask = 0;
     340                }
     341
     342                // TODO: Verify this is the right procedure. Couldn't find it on the
     343                // disassembly, but it's required to work properly
     344                _flagFirstFrame = true;
     345        } else {
     346                // Paint to the background
     347                buf = (byte *)_bg->getBasePtr(0, 0);
     348        }
     349
     350        // Read the palette
     351        in->read(_palBuf, 3 * 256);
     352
     353        if (_flagSeven) {
     354                _flagFive = true;
     355        }
     356
     357        // Skip the frame when flag 5 is set, unless flag 1 is set
     358        if (!_flagFive || _flagOne) {
     359
     360                byte colours[16];
     361                for (uint16 j = 0; j < numYTiles; j++) {
     362                        for (uint16 i = 0; i < numXTiles; i++) { /* Tile number */
     363                                uint8 colour1 = in->readByte();
     364                                uint8 colour0 = in->readByte();
     365                                uint16 colourMap = in->readUint16LE();
     366                                expandColourMap(colours, colourMap, colour1, colour0);
     367                                decodeBlockStill(buf + j * TILE_SIZE * imageWidth + i * TILE_SIZE, colours, 640, mask);
     368                        }
     369                }
     370
     371                // Apply the palette
     372                if (_flagNine) {
     373                        // Flag 9 starts a fade in
     374                        fadeIn(_palBuf);
     375                } else {
     376                        if (!_flagOne && !_flagSeven) {
     377                                // Actually apply the palette
     378                                setPalette(_palBuf);
     379                        }
     380                }
     381
     382                if (!_flagOne) {
     383                        _vm->_graphicsMan->updateScreen(_bg);
     384                }
     385                /*
     386                if (_flagSix) {
     387                        if (_flagOne) {
     388                                _vm->_graphicsMan->updateScreen(_fg);
     389                        } else {
     390                                _vm->_graphicsMan->updateScreen(_bg);
     391                        }
     392                        _flagSix = 0;
     393                }
     394                */
     395        } else {
     396                // Skip the remaining data
     397                debugC(10, kGroovieDebugVideo | kGroovieDebugAll, "Groovie::VDX: Skipping still frame");
     398                while (!in->eos()) {
     399                        in->readByte();
     400                }
     401        }
     402}
     403
     404void VDXPlayer::expandColourMap(byte *out, uint16 colourMap, uint8 colour1, uint8 colour0) {
     405        int flag = 1 << 15;
     406        for (int i = 0; i < 16; i++) {
     407                // Set the corresponding colour
     408                out[i] = (colourMap & flag) ? colour1 : colour0;
     409
     410                // Update the flag to test the next colour
     411                flag >>= 1;
     412        }
     413}
     414
     415void VDXPlayer::decodeBlockStill(byte *buf, byte *colours, uint16 imageWidth, uint8 mask) {
     416        for (int y = 0; y < TILE_SIZE; y++) {
     417                for (int x = 0; x < TILE_SIZE; x++) {
     418                        if (_flagOne) {
     419                                // 0xff pixels don't modify the buffer
     420                                if (*colours != 0xff) {
     421                                        // Write the colour
     422                                        *buf = *colours | mask;
     423                                        // Note: if the mask is 0, it paints the image
     424                                        // else, it paints the image's mask using 0xff
     425                                }
     426                        } else {
     427                                *buf = *colours;
     428                        }
     429
     430                        // Point to the next colour
     431                        colours++;
     432
     433                        // Point to the next pixel
     434                        buf++;
     435                }
     436
     437                // Point to the start of the next line
     438                buf += imageWidth - TILE_SIZE;
     439        }
     440}
     441
     442void VDXPlayer::decodeBlockDelta(uint32 offset, byte *colours, uint16 imageWidth) {
     443        byte *fgBuf = (byte *)_fg->getBasePtr(0, 0) + offset;
     444        //byte *bgBuf = (byte *)_bg->getBasePtr(0, 0) + offset;
     445
     446        byte *dest;
     447        // TODO: Verify just the else block is required
     448        //if (_flagOne) {
     449                // Paint to the foreground
     450                //dest = (byte *)_fg->getBasePtr(0, 0) + offset;
     451        //} else {
     452                dest = (byte *)_bg->getBasePtr(0, 0) + offset;
     453        //}
     454
     455        int32 off = _origX + _origY * imageWidth;
     456        for (int y = 0; y < TILE_SIZE; y++) {
     457                for (int x = 0; x < TILE_SIZE; x++) {
     458                        if (_flagSeven) {
     459                                if (fgBuf[off] != 0xff) {
     460                                        if (*colours == 0xff) {
     461                                                dest[off] = fgBuf[off];
     462                                        } else {
     463                                                dest[off] = *colours;
     464                                        }
     465                                }
     466                        } else {
     467                                // Paint directly
     468                                dest[off] = *colours;
     469                        }
     470                        colours++;
     471                        off++;
     472                }
     473
     474                // Prepare the offset of the next line
     475                off += imageWidth - TILE_SIZE;
     476        }
     477}
     478
     479void VDXPlayer::chunkSound(Common::ReadStream *in) {
     480        if (!_audioStream) {
     481                _audioStream = Audio::makeAppendableAudioStream(22050, Audio::Mixer::FLAG_UNSIGNED | Audio::Mixer::FLAG_AUTOFREE);
     482                Audio::SoundHandle sound_handle;
     483                ::g_engine->_mixer->playInputStream(Audio::Mixer::kPlainSoundType, &sound_handle, _audioStream);
     484        }
     485
     486        byte *data = new byte[60000];
     487        int chunksize = in->read(data, 60000);
     488        _audioStream->queueBuffer(data, chunksize);
     489}
     490
     491void VDXPlayer::fadeIn(uint8 *targetpal) {
     492        // Don't do anything if we're asked to skip palette changes
     493        if (_flagSkipPalette)
     494                return;
     495
     496        // TODO: Is it required? If so, move to an appropiate place
     497        // Copy the foreground to the background
     498        memcpy((byte *)_vm->_graphicsMan->_foreground.getBasePtr(0, 0), (byte *)_vm->_graphicsMan->_background.getBasePtr(0, 0), 640 * 320);
     499
     500        // Start a fadein
     501        _vm->_graphicsMan->fadeIn(targetpal);
     502
     503        // Show the background
     504        _vm->_graphicsMan->updateScreen(_bg);
     505}
     506
     507void VDXPlayer::setPalette(uint8 *palette) {
     508        if (_flagSkipPalette)
     509                return;
     510
     511        uint8 palBuf[4 * 256];
     512        debugC(7, kGroovieDebugVideo | kGroovieDebugAll, "Groovie::VDX: Setting palette");
     513        for (int i = 0; i < 256; i++) {
     514                palBuf[(i * 4) + 0] = palette[(i * 3) + 0];
     515                palBuf[(i * 4) + 1] = palette[(i * 3) + 1];
     516                palBuf[(i * 4) + 2] = palette[(i * 3) + 2];
     517                palBuf[(i * 4) + 3] = 0;
     518        }
     519        _syst->setPalette(palBuf, 0, 256);
     520}
     521
     522} // End of Groovie namespace
  • engines/groovie/player.h

     
     1/* ScummVM - Graphic Adventure Engine
     2 *
     3 * ScummVM is the legal property of its developers, whose names
     4 * are too numerous to list here. Please refer to the COPYRIGHT
     5 * file distributed with this source distribution.
     6 *
     7 * This program is free software; you can redistribute it and/or
     8 * modify it under the terms of the GNU General Public License
     9 * as published by the Free Software Foundation; either version 2
     10 * of the License, or (at your option) any later version.
     11
     12 * This program is distributed in the hope that it will be useful,
     13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15 * GNU General Public License for more details.
     16
     17 * You should have received a copy of the GNU General Public License
     18 * along with this program; if not, write to the Free Software
     19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
     20 *
     21 * $URL$
     22 * $Id$
     23 *
     24 */
     25
     26#ifndef GROOVIE_PLAYER_H
     27#define GROOVIE_PLAYER_H
     28
     29#include "common/system.h"
     30#include "sound/audiostream.h"
     31
     32namespace Groovie {
     33
     34class GroovieEngine;
     35
     36class VideoPlayer {
     37public:
     38        VideoPlayer(GroovieEngine *vm);
     39        virtual ~VideoPlayer() {}
     40
     41        bool load(Common::SeekableReadStream *file, uint16 flags);
     42        bool playFrame();
     43        virtual void setOrigin(int16 x, int16 y) {};
     44
     45protected:
     46        // To be implemented by subclasses
     47        virtual uint16 loadInternal() = 0;
     48        virtual bool playFrameInternal() = 0;
     49
     50        GroovieEngine *_vm;
     51        OSystem *_syst;
     52        Common::SeekableReadStream *_file;
     53        uint16 _flags;
     54        Audio::AppendableAudioStream *_audioStream;
     55
     56private:
     57        // Synchronization stuff
     58        bool _begunPlaying;
     59        uint16 _millisBetweenFrames;
     60        uint32 _lastFrameTime;
     61
     62protected:
     63        void waitFrame();
     64};
     65
     66} // End of Groovie namespace
     67
     68#endif // GROOVIE_PLAYER_H
  • engines/groovie/script.cpp

     
     1/* ScummVM - Graphic Adventure Engine
     2 *
     3 * ScummVM is the legal property of its developers, whose names
     4 * are too numerous to list here. Please refer to the COPYRIGHT
     5 * file distributed with this source distribution.
     6 *
     7 * This program is free software; you can redistribute it and/or
     8 * modify it under the terms of the GNU General Public License
     9 * as published by the Free Software Foundation; either version 2
     10 * of the License, or (at your option) any later version.
     11
     12 * This program is distributed in the hope that it will be useful,
     13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15 * GNU General Public License for more details.
     16
     17 * You should have received a copy of the GNU General Public License
     18 * along with this program; if not, write to the Free Software
     19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
     20 *
     21 * $URL$
     22 * $Id$
     23 *
     24 */
     25
     26#include "groovie/debug.h"
     27#include "groovie/music.h"
     28#include "groovie/script.h"
     29#include "groovie/groovie.h"
     30
     31#include "common/config-manager.h"
     32#include "common/endian.h"
     33#include "common/events.h"
     34#include "common/savefile.h"
     35#include "sound/audiocd.h"
     36
     37#define NUM_OPCODES 90
     38
     39namespace Groovie {
     40
     41void debugScript(int level, bool nl, const char *s, ...) {
     42        char buf[STRINGBUFLEN];
     43        va_list va;
     44
     45        uint32 engine_level = kGroovieDebugScript | kGroovieDebugAll;
     46
     47        if (gDebugLevel != 11)
     48                if (!(Common::getEnabledSpecialDebugLevels() & engine_level))
     49                        return;
     50
     51        va_start(va, s);
     52        vsnprintf(buf, STRINGBUFLEN, s, va);
     53        va_end(va);
     54
     55        if (nl)
     56                debug(level, buf);
     57        else
     58                debugN(level, buf);
     59}
     60
     61Script::Script(GroovieEngine *vm) :
     62        _code(NULL), _savedCode(NULL), _stacktop(0),
     63        _debugger(NULL), _error(false), _vm(vm),
     64        _videoFile(NULL), _videoRef(0), _font(NULL) {
     65        // Initialize the random source
     66        _vm->_system->getEventManager()->registerRandomSource(_random, "GroovieScripts");
     67
     68        // Prepare the variables
     69        _bitflags = 0;
     70        for (int i = 0; i < 0x400; i++) {
     71                _variables[i] = 0;
     72        }
     73
     74        // Initialize the music type variable
     75        int midiDriver = MidiDriver::detectMusicDriver(MDT_MIDI | MDT_ADLIB | MDT_PREFER_MIDI);
     76        if (midiDriver == MD_ADLIB) {
     77                // MIDI through AdLib
     78                _variables[0x100] = 0;
     79        } else  if ((midiDriver == MD_MT32) || ConfMan.getBool("native_mt32")) {
     80                // MT-32
     81                _variables[0x100] = 2;
     82        } else {
     83                // GM
     84                _variables[0x100] = 1;
     85        }
     86
     87        _hotspotTopAction = 0;
     88        _hotspotBottomAction = 0;
     89        _hotspotRightAction = 0;
     90        _hotspotLeftAction = 0;
     91        _hotspotCursorOldX = 1000;
     92        _hotspotCursorOldY = 1000;
     93}
     94
     95Script::~Script() {
     96        delete[] _code;
     97        delete[] _savedCode;
     98
     99        delete _font;
     100        delete _videoFile;
     101}
     102
     103void Script::setDebugger(Debugger *debugger) {
     104        _debugger = debugger;
     105}
     106
     107bool Script::loadScript(Common::String filename) {
     108        // Try to open the script file
     109        Common::File scriptfile;
     110        if (!scriptfile.open(filename)) {
     111                return false;
     112        }
     113
     114        // Save the script filename
     115        _scriptFile = filename;
     116
     117        // Load the code
     118        _code = new byte[0x10000];
     119        scriptfile.read(_code, 0x10000);
     120        scriptfile.close();
     121
     122        // Initialize the script
     123        _currentInstruction = 0;
     124
     125        return true;
     126}
     127
     128void Script::directGameLoad(int slot) {
     129        // Reject invalid slots
     130        if (slot < 0 || slot > 9) {
     131                return;
     132        }
     133
     134        // TODO: Return to the main script, likely reusing most of o_returnscript()
     135
     136        // HACK: We set variable 0x19 to the slot to load, and set the current
     137        // instruction to the one that actually loads the saved game specified
     138        // in that variable. This will change in other versions of the game and
     139        // in other games.
     140        _variables[0x19] = slot;
     141        _currentInstruction = 0x287;
     142
     143        // TODO: We'll probably need to start by running the beginning of the
     144        // script to let it do the soundcard initialization and then do the
     145        // actual loading.
     146}
     147
     148void Script::step() {
     149        // Reset the error status
     150        _error = false;
     151
     152        // Prepare the base debug string
     153        char debugstring[10];
     154        sprintf(debugstring, "@0x%04X: ", _currentInstruction);
     155        _debugString = _scriptFile + debugstring;
     156
     157        // Get the current opcode
     158        byte opcode = readScript8bits();
     159        _firstbit = ((opcode & 0x80) != 0);
     160        opcode = opcode & 0x7F;
     161
     162        // Show the opcode debug string
     163        sprintf(debugstring, "op 0x%02X: ", opcode);
     164        _debugString += debugstring;
     165        debugScript(1, false, _debugString.c_str());
     166
     167        // Detect invalid opcodes
     168        if (opcode >= NUM_OPCODES) {
     169                o_invalid();
     170                return;
     171        }
     172
     173        // Execute the current opcode
     174        OpcodeFunc op = _opcodes[opcode];
     175        (this->*op)();
     176}
     177
     178void Script::setMouseClick() {
     179        _eventMouseClicked = true;
     180}
     181
     182void Script::setKbdChar(uint8 c) {
     183        _eventKbdChar = c;
     184}
     185
     186bool Script::haveError() {
     187        return _error;
     188}
     189
     190void Script::error(const char *msg) {
     191        // Prepend the debugging info to the error
     192        Common::String msg2 = _debugString + msg;
     193
     194        // Print the error message
     195        ::error("ERROR: %s\n", msg2.c_str());
     196
     197        // Show it in the debugger
     198        _debugger->attach(msg2.c_str());
     199
     200        // Set the error state
     201        _error = true;
     202}
     203
     204uint8 Script::readScript8bits() {
     205        uint8 data = _code[_currentInstruction];
     206        _currentInstruction++;
     207        return data;
     208}
     209
     210uint8 Script::readScriptVar() {
     211        uint8 data = _variables[readScript8or16bits()];
     212        return data;
     213}
     214
     215uint16 Script::readScript16bits() {
     216        uint16 data = READ_LE_UINT16(_code + _currentInstruction);
     217        _currentInstruction += 2;
     218        return data;
     219}
     220
     221uint32 Script::readScript32bits() {
     222        uint32 data = READ_LE_UINT32(_code + _currentInstruction);
     223        _currentInstruction += 4;
     224        return data;
     225}
     226
     227uint16 Script::readScript8or16bits() {
     228        if (_firstbit) {
     229                return readScript8bits();
     230        } else {
     231                return readScript16bits();
     232        }
     233}
     234
     235uint8 Script::readScriptChar(bool allow7C, bool limitVal, bool limitVar) {
     236        uint8 result;
     237        uint8 data = readScript8bits();
     238
     239        if (limitVal) {
     240                data &= 0x7F;
     241        }
     242
     243        if (allow7C && (data == 0x7C)) {
     244                // Index a bidimensional array
     245                uint8 parta, partb;
     246                parta = readScriptChar(false, false, false);
     247                partb = readScriptChar(false, true, true);
     248                result = _variables[0x0A * parta + partb + 0x19];
     249        } else if (data == 0x23) {
     250                // Index an array
     251                data = readScript8bits();
     252                if (limitVar) {
     253                        data &= 0x7F;
     254                }
     255                result = _variables[data - 0x61];
     256        } else {
     257                // Immediate value
     258                result = data - 0x30;
     259        }
     260        return result;
     261}
     262
     263uint16 Script::getVideoRefString() {
     264        Common::String str;
     265        byte c;
     266
     267        while ((c = readScript8bits())) {
     268                switch (c) {
     269                case 0x23:
     270                        c = readScript8bits();
     271                        c = _variables[c - 0x61] + 0x30;
     272                        if (c >= 0x41 && c <= 0x5A) {
     273                                c += 0x20;
     274                        }
     275                        break;
     276                case 0x7C:
     277                        uint8 parta, partb;
     278                        parta = readScriptChar(false, false, false);
     279                        partb = readScriptChar(false, false, false);
     280                        c = _variables[0x0A * parta + partb + 0x19] + 0x30;
     281                        break;
     282                default:
     283                        if (c >= 0x41 && c <= 0x5A) {
     284                                c += 0x20;
     285                        }
     286                }
     287                // Append the current character at the end of the string
     288                str += c;
     289        }
     290
     291        // Add a trailing dot
     292        str += 0x2E;
     293
     294        debugScript(0, false, "%s", str.c_str());
     295
     296        // Extract the script name.
     297        Common::String scriptname(_scriptFile.c_str(), _scriptFile.size() - 4);
     298
     299        // Get the fileref of the resource
     300        return _vm->_resMan->getRef(str, scriptname);
     301}
     302
     303bool Script::hotspot(Common::Rect rect, uint16 address, uint8 cursor) {
     304        // Test if the current mouse position is contained in the specified rectangle
     305        Common::Point mousepos = _vm->_system->getEventManager()->getMousePos();
     306        bool contained = rect.contains(mousepos);
     307
     308        // Show hotspots when debugging
     309        if (Common::getEnabledSpecialDebugLevels() & (kGroovieDebugHotspots | kGroovieDebugAll)) {
     310                rect.translate(0, -80);
     311                _vm->_graphicsMan->_foreground.frameRect(rect, 250);
     312                _vm->_system->copyRectToScreen((byte*)_vm->_graphicsMan->_foreground.getBasePtr(0, 0), 640, 0, 80, 640, 320);
     313                _vm->_system->updateScreen();
     314        }
     315
     316        // If there's an already planned action, do nothing
     317        if (_inputAction != -1) {
     318                return false;
     319        }
     320
     321        if (contained) {
     322                // Change the mouse cursor
     323                if (_newCursorStyle == 5) {
     324                        _newCursorStyle = cursor;
     325                }
     326
     327                // If clicked with the mouse, jump to the specified address
     328                if (_mouseClicked) {
     329                        _inputAction = address;
     330                }
     331        }
     332
     333        return contained;
     334}
     335
     336void Script::loadgame(uint slot) {
     337        Common::String filename = ConfMan.getActiveDomainName() + ".00" + ('0' + slot);
     338        Common::InSaveFile *file = _vm->_system->getSavefileManager()->openForLoading(filename.c_str());
     339
     340        // Loading the variables. It is endian safe because they're byte variables
     341        file->read(_variables, 0x400);
     342
     343        delete file;
     344}
     345
     346void Script::savegame(uint slot) {
     347        Common::String filename = ConfMan.getActiveDomainName() + ".00" + ('0' + slot);
     348        Common::OutSaveFile *file = _vm->_system->getSavefileManager()->openForSaving(filename.c_str());
     349
     350        // Saving the variables. It is endian safe because they're byte variables
     351        file->write(_variables, 0x400);
     352
     353        delete file;
     354}
     355
     356// OPCODES
     357
     358void Script::o_invalid() {
     359        error("Invalid opcode");
     360}
     361
     362void Script::o_nop() {
     363        debugScript(1, true, "NOP");
     364}
     365
     366void Script::o_nop8() {
     367        uint8 tmp = readScript8bits();
     368        debugScript(1, true, "NOP8: 0x%02X", tmp);
     369}
     370
     371void Script::o_nop16() {
     372        uint16 tmp = readScript16bits();
     373        debugScript(1, true, "NOP16: 0x%04X", tmp);
     374}
     375
     376void Script::o_nop32() {
     377        uint32 tmp = readScript32bits();
     378        debugScript(1, true, "NOP32: 0x%08X", tmp);
     379}
     380
     381void Script::o_nop8or16() {
     382        uint16 tmp = readScript8or16bits();
     383        debugScript(1, true, "NOP8OR16: 0x%04X", tmp);
     384}
     385
     386void Script::o_playsong() {                     // 0x02
     387        uint16 fileref = readScript16bits();
     388        debugScript(1, true, "PlaySong(0x%04X): Play xmidi file", fileref);
     389        if (fileref == 0x4C17) {
     390                warning("this song is special somehow");
     391                // don't save the reference?
     392        }
     393        _vm->_musicPlayer->playSong(fileref);
     394}
     395
     396void Script::o_bf9on() {                        // 0x03
     397        debugScript(1, true, "BF9ON: bitflag 9 turned on");
     398        _bitflags |= 1 << 9;
     399}
     400
     401void Script::o_palfadeout() {
     402        debugScript(1, true, "PALFADEOUT");
     403        _vm->_graphicsMan->fadeOut();
     404}
     405
     406void Script::o_bf8on() {                        // 0x05
     407        debugScript(1, true, "BF8ON: bitflag 8 turned on");
     408        _bitflags |= 1 << 8;
     409}
     410
     411void Script::o_bf6on() {                        // 0x06
     412        debugScript(1, true, "BF6ON: bitflag 6 turned on");
     413        _bitflags |= 1 << 6;
     414}
     415
     416void Script::o_bf7on() {                        // 0x07
     417        debugScript(1, true, "BF7ON: bitflag 7 turned on");
     418        _bitflags |= 1 << 7;
     419}
     420
     421void Script::o_setbackgroundsong() {                    // 0x08
     422        uint16 fileref = readScript16bits();
     423        debugScript(1, true, "SetBackgroundSong(0x%04X)", fileref);
     424        _vm->_musicPlayer->setBackgroundSong(fileref);
     425}
     426
     427void Script::o_videofromref() {                 // 0x09
     428        uint16 fileref = readScript16bits();
     429
     430        // Show the debug information just when starting the playback
     431        if (fileref != _videoRef) {
     432                debugScript(1, false, "VIDEOFROMREF(0x%04X) (Not fully imp): Play video file from ref", fileref);
     433                debugC(5, kGroovieDebugVideo | kGroovieDebugAll, "Playing video 0x%04X via 0x09", fileref);
     434        }
     435        switch (fileref) {
     436        case 0x1C03:    // Trilobyte logo
     437        case 0x1C04:    // Virgin logo
     438        case 0x1C05:    // Credits
     439                if (fileref != _videoRef) {
     440                        debugScript(1, true, "Use external file if available");
     441                }
     442                break;
     443               
     444        case 0x400D:    // floating objects in music room
     445        case 0x5060:    // a sound from gamwav?
     446        case 0x5098:    // a sound from gamwav?
     447        case 0x2402:    // House becomes book in intro?
     448        case 0x1426:    // Turn to face front in hall: played after intro
     449        case 0x206D:    // Cards on table puzzle (bedroom)
     450        case 0x2001:    // Coins on table puzzle (bedroom)
     451                if (fileref != _videoRef) {
     452                        debugScript(1, false, " (This video is special somehow!)");
     453                        warning("(This video (0x%04X) is special somehow!)", fileref);
     454                }
     455        }
     456        if (fileref != _videoRef) {
     457                debugScript(1, true, "");
     458        }
     459        // Play the video
     460        if (!playvideofromref(fileref)) {
     461                // Move _currentInstruction back
     462                _currentInstruction -= 3;
     463        }
     464}
     465
     466bool Script::playvideofromref(uint16 fileref) {
     467        // It isn't the current video, open it
     468        if (fileref != _videoRef) {
     469
     470                // Debug bitflags
     471                debugScript(1, false, "Play video 0x%04X (bitflags:", fileref);
     472                for (int i = 10; i >= 0; i--) {
     473                        debugScript(1, false, "%d", _bitflags & (1 << i)? 1 : 0);
     474                }
     475                debugScript(1, true, ")");
     476
     477                // Close the previous video file
     478                if (_videoFile) {
     479                        _videoRef = 0;
     480                        delete _videoFile;
     481                }
     482
     483                // Try to open the new file
     484                _videoFile = _vm->_resMan->open(fileref);
     485
     486                if (_videoFile) {
     487                        _videoRef = fileref;
     488                        _vm->_videoPlayer->load(_videoFile, _bitflags);
     489                } else {
     490                        error("Couldn't open file");
     491                        return true;
     492                }
     493
     494                _bitflags = 0;
     495        }
     496
     497        // Video available, play one frame
     498        if (_videoFile) {
     499                bool endVideo = _vm->_videoPlayer->playFrame();
     500
     501                if (endVideo) {
     502                        // Close the file
     503                        delete _videoFile;
     504                        _videoFile = NULL;
     505                        _videoRef = 0;
     506
     507                        // Clear the input events while playing the video
     508                        _eventMouseClicked = false;
     509                        _eventKbdChar = 0;
     510
     511                        // Newline
     512                        debugScript(1, true, "");
     513                }
     514
     515                // Let the caller know if the video has ended
     516                return endVideo;
     517        }
     518
     519        // If the file is closed, finish the playback
     520        return true;
     521}
     522
     523void Script::o_bf5on() {                        // 0x0A
     524        debugScript(1, true, "BF5ON: bitflag 5 turned on");
     525        _bitflags |= 1 << 5;
     526}
     527
     528void Script::o_inputloopstart() {
     529        debugScript(5, true, "Input loop start");
     530
     531        // Reset the input action and the mouse cursor
     532        _inputAction = -1;
     533        _newCursorStyle = 5;
     534
     535        // Save the input loop address
     536        _inputLoopAddress = _currentInstruction - 1;
     537
     538        // Save the current mouse state for the whole loop
     539        _mouseClicked = _eventMouseClicked;
     540        _eventMouseClicked = false;
     541
     542        // Save the current pressed character for the whole loop
     543        _kbdChar = _eventKbdChar;
     544        _eventKbdChar = 0;
     545}
     546
     547void Script::o_keyboardaction() {
     548        uint8 val = readScript8bits();
     549        uint16 address = readScript16bits();
     550
     551        debugScript(5, true, "Test key == 0x%02X @0x%04X", val, address);
     552
     553        // If there's an already planned action, do nothing
     554        if (_inputAction != -1) {
     555                return;
     556        }
     557
     558        // Check the typed key
     559        if (_kbdChar == val) {
     560                // Exit the input loop
     561                _inputLoopAddress = 0;
     562
     563                // Save the action address
     564                _inputAction = address;
     565        }
     566}
     567
     568void Script::o_hotspot_rect() {
     569        uint16 left = readScript16bits();
     570        uint16 top = readScript16bits();
     571        uint16 right = readScript16bits();
     572        uint16 bottom = readScript16bits();
     573        uint16 address = readScript16bits();
     574        uint8 cursor = readScript8bits();
     575
     576        debugScript(5, true, "HOTSPOT-RECT(%d,%d,%d,%d) @0x%04X cursor=%d", left, top, right, bottom, address, cursor);
     577
     578        // Mark the specified rectangle
     579        Common::Rect rect(left, top, right, bottom);
     580        hotspot(rect, address, cursor);
     581}
     582
     583void Script::o_hotspot_left() {
     584        uint16 address = readScript16bits();
     585
     586        debugScript(5, true, "HOTSPOT-LEFT @0x%04X", address);
     587
     588        // Mark the leftmost 100 pixels of the game area
     589        Common::Rect rect(0, 80, 100, 400);
     590        hotspot(rect, address, 1);
     591}
     592
     593void Script::o_hotspot_right() {
     594        uint16 address = readScript16bits();
     595
     596        debugScript(5, true, "HOTSPOT-RIGHT @0x%04X", address);
     597
     598        // Mark the rightmost 100 pixels of the game area
     599        Common::Rect rect(540, 80, 640, 400);
     600        hotspot(rect, address, 2);
     601}
     602
     603void Script::o_hotspot_center() {
     604        uint16 address = readScript16bits();
     605
     606        debugScript(5, true, "HOTSPOT-CENTER @0x%04X", address);
     607
     608        // Mark the centremost 240 pixels of the game area
     609        Common::Rect rect(200, 80, 440, 400);
     610        hotspot(rect, address, 0);
     611}
     612
     613void Script::o_hotspot_current() {
     614       uint16 address = readScript16bits();
     615
     616       debugScript(5, true, "HOTSPOT-CURRENT @0x%04X", address);
     617
     618       // The original interpreter doesn't check the position, so accept the
     619       // whole screen
     620       Common::Rect rect(0, 0, 640, 480);
     621       hotspot(rect, address, 0);
     622}
     623
     624void Script::o_inputloopend() {
     625        debugScript(5, true, "Input loop end");
     626
     627        // Handle the predefined hotspots
     628        if (_hotspotTopAction) {
     629                Common::Rect rect(0, 0, 640, 80);
     630                hotspot(rect, _hotspotTopAction, _hotspotTopCursor);
     631        }
     632        if (_hotspotBottomAction) {
     633                Common::Rect rect(0, 400, 640, 480);
     634                hotspot(rect, _hotspotBottomAction, _hotspotBottomCursor);
     635        }
     636        if (_hotspotRightAction) {
     637                Common::Rect rect(560, 0, 640, 480);
     638                hotspot(rect, _hotspotRightAction, 2);
     639        }
     640        if (_hotspotLeftAction) {
     641                Common::Rect rect(0, 0, 80, 480);
     642                hotspot(rect, _hotspotLeftAction, 1);
     643        }
     644
     645        // Actually execute the planned action
     646        if (_inputAction != -1) {
     647                // Jump to the planned address
     648                _currentInstruction = _inputAction;
     649
     650                // Exit the input loop
     651                _inputLoopAddress = 0;
     652                _vm->_system->showMouse(false);
     653        }
     654
     655        // Nothing to do
     656        if (_inputLoopAddress) {
     657                if (_newCursorStyle != _vm->_cursorMan->getStyle()) {
     658                        _vm->_cursorMan->setStyle(_newCursorStyle);
     659                }
     660                _vm->_system->showMouse(true);
     661
     662                // Go back to the begining of the loop
     663                _currentInstruction = _inputLoopAddress;
     664
     665                // There's nothing to do until we get some input
     666                _vm->waitForInput();
     667        }
     668}
     669
     670void Script::o_random() {
     671        uint16 varnum = readScript8or16bits();
     672        uint8 maxnum = readScript8bits();
     673
     674        debugScript(1, true, "RANDOM: var[0x%04X] = rand(%d)", varnum, maxnum);
     675
     676        _variables[varnum] = _random.getRandomNumber(maxnum);
     677}
     678
     679void Script::o_jmp() {
     680        uint16 address = readScript16bits();
     681       
     682        debugScript(1, true, "JMP @0x%04X", address);
     683
     684        // Set the current address
     685        _currentInstruction = address;
     686}
     687
     688void Script::o_loadstring() {
     689        uint16 varnum = readScript8or16bits();
     690       
     691        debugScript(1, false, "LOADSTRING var[0x%04X..] =", varnum);
     692        do {
     693                _variables[varnum++] = readScriptChar(true, true, true);
     694                debugScript(1, false, " 0x%02X", _variables[varnum - 1]);
     695        } while (!(_code[_currentInstruction - 1] & 0x80));
     696        debugScript(1, true, "");
     697}
     698
     699void Script::o_ret() {
     700        uint8 val = readScript8bits();
     701       
     702        debugScript(1, true, "RET %d", val);
     703
     704        // Set the return value
     705        _variables[0x102] = val;
     706
     707        // Get the return address
     708        if (_stacktop > 0) {
     709                _stacktop--;
     710                _currentInstruction = _stack[_stacktop];
     711        } else {
     712                error("Return: Stack is empty");
     713        }
     714}
     715
     716void Script::o_call() {
     717        uint16 address = readScript16bits();
     718       
     719        debugScript(1, true, "CALL @0x%04X", address);
     720
     721        // Save return address in the call stack
     722        _stack[_stacktop] = _currentInstruction;
     723        _stacktop++;
     724
     725        // Change the current instruction
     726        _currentInstruction = address;
     727}
     728
     729void Script::o_sleep() {
     730        uint16 time = readScript16bits();
     731       
     732        debugScript(1, true, "SLEEP 0x%04X", time);
     733
     734        _vm->_system->delayMillis(time * 3);
     735}
     736
     737void Script::o_strcmpnejmp() {                  // 0x1A
     738        uint16 varnum = readScript8or16bits();
     739        uint8 val;
     740        uint8 result = 1;
     741
     742        debugScript(1, false, "STRCMP-NEJMP: var[0x%04X..],", varnum);
     743
     744        do {
     745                val = readScriptChar(true, true, true);
     746
     747                if (_variables[varnum] != val) {
     748                        result = 0;
     749                }
     750                varnum++;
     751                debugScript(1, false, " 0x%02X", val);
     752
     753        } while (!(_code[_currentInstruction - 1] & 0x80));
     754
     755        uint16 address = readScript16bits();
     756        if (!result) {
     757                debugScript(1, true, " jumping to @0x%04X", address);
     758                _currentInstruction = address;
     759        } else {
     760                debugScript(1, true, " not jumping");
     761        }
     762}
     763
     764void Script::o_xor_obfuscate() {
     765        uint16 varnum = readScript8or16bits();
     766
     767        debugScript(1, false, "XOR OBFUSCATE: var[0x%04X..] = ", varnum);
     768        do {
     769                uint8 val = readScript8bits();
     770                _firstbit = ((val & 0x80) != 0);
     771                val &= 0x4F;
     772
     773                _variables[varnum] ^= val;
     774                debugScript(1, false, "%c", _variables[varnum]);
     775
     776                varnum++;
     777        } while (!_firstbit);
     778        debugScript(1, true, "");
     779}
     780
     781void Script::o_vdxtransition() {                // 0x1C
     782        uint16 fileref = readScript16bits();
     783
     784        // Show the debug information just when starting the playback
     785        if (fileref != _videoRef) {
     786                debugScript(1, true, "VDX transition fileref = 0x%04X", fileref);
     787                debugC(1, kGroovieDebugVideo | kGroovieDebugAll, "Playing video 0x%04X with transition", fileref);
     788        }
     789
     790        // Set bit 1
     791        _bitflags |= 1 << 1;
     792
     793        // Clear bit 7
     794        _bitflags &= ~(1 << 7);
     795
     796        // Set bit 2 if _firstbit
     797        if (_firstbit) {
     798                _bitflags |= 1 << 2;
     799        }
     800
     801        // Play the video
     802        if (!playvideofromref(fileref)) {
     803                // Move _currentInstruction back
     804                _currentInstruction -= 3;
     805        }
     806}
     807
     808void Script::o_swap() {
     809        uint16 varnum1 = readScript8or16bits();
     810        uint16 varnum2 = readScript16bits();
     811       
     812        debugScript(1, true, "SWAP var[0x%04X] <-> var[0x%04X]", varnum1, varnum2);
     813
     814        uint8 tmp = _variables[varnum1];
     815        _variables[varnum1] = _variables[varnum2];
     816        _variables[varnum2] = tmp;
     817}
     818
     819void Script::o_inc() {
     820        uint16 varnum = readScript8or16bits();
     821       
     822        debugScript(1, true, "INC var[0x%04X]", varnum);
     823
     824        _variables[varnum]++;
     825}
     826
     827void Script::o_dec() {
     828        uint16 varnum = readScript8or16bits();
     829       
     830        debugScript(1, true, "DEC var[0x%04X]", varnum);
     831
     832        _variables[varnum]--;
     833}
     834
     835void Script::o_strcmpnejmp_var() {                      // 0x21
     836        uint16 data = readScriptVar();
     837       
     838        if (data > 9) {
     839                data -= 7;
     840        }
     841        data = _variables[data + 0x19];
     842        bool stringsmatch = 1;
     843        do {
     844                if (_variables[data++] != readScriptChar(true, true, true)) {
     845                        stringsmatch = 0;
     846                }       
     847        } while (!(_code[_currentInstruction - 1] & 0x80));
     848
     849        uint16 offset = readScript16bits();
     850        if (!stringsmatch) {
     851                _currentInstruction = offset;
     852        }
     853}
     854
     855void Script::o_copybgtofg() {                   // 0x22
     856        debugScript(1, true, "COPY_BG_TO_FG");
     857        memcpy(_vm->_graphicsMan->_foreground.getBasePtr(0, 0), _vm->_graphicsMan->_background.getBasePtr(0, 0), 640 * 320);
     858}
     859
     860void Script::o_strcmpeqjmp() {                  // 0x23
     861        uint16 varnum = readScript8or16bits();
     862        uint8 val;
     863        uint8 result = 1;
     864       
     865        debugScript(1, false, "STRCMP-EQJMP: var[0x%04X..],", varnum);
     866        do {
     867                val = readScriptChar(true, true, true);
     868
     869                if (_variables[varnum] != val) {
     870                        result = 0;
     871                }
     872                varnum++;
     873                debugScript(1, false, " 0x%02X", val);
     874
     875        } while (!(_code[_currentInstruction - 1] & 0x80));
     876
     877        uint16 address = readScript16bits();
     878        if (result) {
     879                debugScript(1, true, " jumping to @0x%04X", address);
     880                _currentInstruction = address;
     881        } else {
     882                debugScript(1, true, " not jumping");
     883        }
     884}
     885
     886void Script::o_mov() {
     887        uint16 varnum1 = readScript8or16bits();
     888        uint16 varnum2 = readScript16bits();
     889
     890        debugScript(1, true, "MOV var[0x%04X] = var[0x%04X]", varnum1, varnum2);
     891
     892        _variables[varnum1] = _variables[varnum2];
     893}
     894
     895void Script::o_add() {
     896        uint16 varnum1 = readScript8or16bits();
     897        uint16 varnum2 = readScript16bits();
     898       
     899        debugScript(1, true, "ADD var[0x%04X] += var[0x%04X]", varnum1, varnum2);
     900
     901        _variables[varnum1] += _variables[varnum2];
     902}
     903
     904void Script::o_videofromstring1() {
     905        uint16 instStart = _currentInstruction;
     906        uint16 fileref = getVideoRefString();
     907
     908        // Show the debug information just when starting the playback
     909        if (fileref != _videoRef) {
     910                debugScript(0, true, "VIDEOFROMSTRING1 0x%04X", fileref);
     911        }
     912
     913        // Play the video
     914        if (!playvideofromref(fileref)) {
     915                // Move _currentInstruction back
     916                _currentInstruction = instStart - 1;
     917        }
     918}
     919
     920void Script::o_videofromstring2() {
     921        uint16 instStart = _currentInstruction;
     922        uint16 fileref = getVideoRefString();
     923
     924        // Show the debug information just when starting the playback
     925        if (fileref != _videoRef) {
     926                debugScript(0, true, "VIDEOFROMSTRING2 0x%04X", fileref);
     927        }
     928
     929        // Set bit 1
     930        _bitflags |= 1 << 1;
     931
     932        // Set bit 2 if _firstbit
     933        if (_firstbit) {
     934                _bitflags |= 1 << 2;
     935        }
     936
     937        // Play the video
     938        if (!playvideofromref(fileref)) {
     939                // Move _currentInstruction back
     940                _currentInstruction = instStart - 1;
     941        }
     942}
     943
     944void Script::o_stopmidi() {
     945        debugScript(1, true, "STOPMIDI (TODO)");
     946}
     947
     948void Script::o_endscript() {
     949        debugScript(1, true, "END OF SCRIPT");
     950        _error = true;
     951}
     952
     953void Script::o_sethotspottop() {
     954        uint16 address = readScript16bits();
     955        uint8 cursor = readScript8bits();
     956       
     957        debugScript(5, true, "SETHOTSPOTTOP @0x%04X cursor=%d", address, cursor);
     958
     959        _hotspotTopAction = address;
     960        _hotspotTopCursor = cursor;
     961}
     962
     963void Script::o_sethotspotbottom() {
     964        uint16 address = readScript16bits();
     965        uint8 cursor = readScript8bits();
     966       
     967        debugScript(5, true, "SETHOTSPOTBOTTOM @0x%04X cursor=%d", address, cursor);
     968
     969        _hotspotBottomAction = address;
     970        _hotspotBottomCursor = cursor;
     971}
     972
     973void Script::o_loadgame() {
     974        uint16 varnum = readScript8or16bits();
     975        uint8 slot = _variables[varnum];
     976       
     977        debugScript(1, true, "LOADGAME var[0x%04X] -> slot=%d (TODO)", varnum, slot);
     978
     979        loadgame(slot);
     980        _vm->_system->clearScreen();
     981}
     982
     983void Script::o_savegame() {
     984        uint16 varnum = readScript8or16bits();
     985        uint8 slot = _variables[varnum];
     986       
     987        debugScript(1, true, "SAVEGAME var[0x%04X] -> slot=%d (TODO)", varnum, slot);
     988
     989        savegame(slot);
     990}
     991
     992void Script::o_hotspotbottom_4() {      //0x30
     993        uint16 address = readScript16bits();
     994       
     995        debugScript(5, true, "HOTSPOT-BOTTOM @0x%04X", address);
     996
     997        // Mark the 80 pixels under the game area
     998        Common::Rect rect(0, 400, 640, 480);
     999        hotspot(rect, address, 4);
     1000}
     1001
     1002void Script::o_midivolume() {
     1003        uint16 arg1 = readScript16bits();
     1004        uint16 arg2 = readScript16bits();
     1005       
     1006        debugScript(1, true, "MIDI volume: %d %d", arg1, arg2);
     1007        _vm->_musicPlayer->setGameVolume(arg1, arg2);
     1008}
     1009
     1010void Script::o_jne() {
     1011        int16 varnum1 = readScript8or16bits();
     1012        uint16 varnum2 = readScript16bits();
     1013        uint16 address = readScript16bits();
     1014       
     1015        debugScript(1, false, "JNE: var[var[0x%04X] - 0x31] != var[0x%04X] @0x%04X", varnum1, varnum2, address);
     1016
     1017        if (_variables[_variables[varnum1] - 0x31] != _variables[varnum2]) {
     1018                _currentInstruction = address;
     1019                debugScript(1, true, " jumping to @0x%04X", address);
     1020        } else {
     1021                debugScript(1, true, " not jumping");
     1022        }
     1023}
     1024
     1025void Script::o_loadstringvar() {
     1026        uint16 varnum = readScript8or16bits();
     1027       
     1028        varnum = _variables[varnum] - 0x31;
     1029        debugScript(1, false, "LOADSTRINGVAR var[0x%04X..] =", varnum);
     1030        do {
     1031                _variables[varnum++] = readScriptChar(true, true, true);
     1032                debugScript(1, false, " 0x%02X", _variables[varnum - 1]);
     1033        } while (!(_code[_currentInstruction - 1] & 0x80));
     1034        debugScript(1, true, "");
     1035}
     1036
     1037void Script::o_chargreatjmp() {
     1038        uint16 varnum = readScript8or16bits();
     1039        uint8 val;
     1040        uint8 result = 0;
     1041
     1042        debugScript(1, false, "CHARGREAT-JMP: var[0x%04X..],", varnum);
     1043        do {
     1044                val = readScriptChar(true, true, true);
     1045
     1046                if (val < _variables[varnum]) {
     1047                        result = 1;
     1048                }
     1049                varnum++;
     1050                debugScript(1, false, " 0x%02X", val);
     1051        } while (!(_code[_currentInstruction - 1] & 0x80));
     1052
     1053        uint16 address = readScript16bits();
     1054        if (result) {
     1055                debugScript(1, true, " jumping to @0x%04X", address);
     1056                _currentInstruction = address;
     1057        } else {
     1058                debugScript(1, true, " not jumping");
     1059        }
     1060}
     1061
     1062void Script::o_bf7off() {
     1063        debugScript(1, true, "BF7OFF: bitflag 7 turned off");
     1064        _bitflags &= ~(1 << 7);
     1065}
     1066
     1067void Script::o_charlessjmp() {
     1068        uint16 varnum = readScript8or16bits();
     1069        uint8 val;
     1070        uint8 result = 0;
     1071
     1072        debugScript(1, false, "CHARLESS-JMP: var[0x%04X..],", varnum);
     1073        do {
     1074                val = readScriptChar(true, true, true);
     1075
     1076                if (val > _variables[varnum]) {
     1077                        result = 1;
     1078                }
     1079                varnum++;
     1080                debugScript(1, false, " 0x%02X", val);
     1081        } while (!(_code[_currentInstruction - 1] & 0x80));
     1082
     1083        uint16 address = readScript16bits();
     1084        if (result) {
     1085                debugScript(1, true, " jumping to @0x%04X", address);
     1086                _currentInstruction = address;
     1087        } else {
     1088                debugScript(1, true, " not jumping");
     1089        }
     1090}
     1091
     1092void Script::o_copyrecttobg() { // 0x37
     1093        uint16 left = readScript16bits();
     1094        uint16 top = readScript16bits();
     1095        uint16 right = readScript16bits();
     1096        uint16 bottom = readScript16bits();
     1097        uint16 i, width = right - left, height = bottom - top;
     1098        uint32 offset = 0;
     1099        byte *fg, *bg;
     1100
     1101        debugScript(1, true, "COPYRECT((%d,%d)->(%d,%d))", left, top, right, bottom);
     1102
     1103        fg = (byte *)_vm->_graphicsMan->_foreground.getBasePtr(left, top - 80);
     1104        bg = (byte *)_vm->_graphicsMan->_background.getBasePtr(left, top - 80);
     1105        for (i = 0; i < height; i++) {
     1106                memcpy(bg + offset, fg + offset, width);
     1107                offset += 640;
     1108        }
     1109        _vm->_system->copyRectToScreen((byte *)_vm->_graphicsMan->_background.getBasePtr(left, top - 80), 640, left, top, width, height);
     1110        _vm->_graphicsMan->change();
     1111}
     1112
     1113void Script::o_restorestkpnt() {
     1114        debugScript(1, true, "Restore stack pointer from saved (TODO)");
     1115}
     1116
     1117void Script::o_obscureswap() {
     1118        uint16 var1, var2, tmp;
     1119
     1120        debugScript(1, true, "OBSCSWAP");
     1121
     1122        // Read the first variable
     1123        var1 = readScriptChar(false, true, true) * 10;
     1124        var1 += readScriptChar(false, true, true) + 0x19;
     1125
     1126        // Read the second variable
     1127        var2 = readScriptChar(false, true, true) * 10;
     1128        var2 += readScriptChar(false, true, true) + 0x19;
     1129
     1130        // Swap the values
     1131        tmp = _variables[var1];
     1132        _variables[var1] = _variables[var2];
     1133        _variables[var2] = tmp;
     1134}
     1135
     1136void Script::o_printstring() {
     1137        char stringstorage[15], newchar;
     1138        uint8 counter = 0;
     1139
     1140        debugScript(1, true, "PRINTSTRING");
     1141
     1142        memset(stringstorage, 0, 15);
     1143        do {
     1144                newchar = readScriptChar(true, true, true) + 0x30;
     1145                if (newchar < 0x30 || newchar > 0x39) {         // If character is invalid, chuck a space in
     1146                        if (newchar < 0x41 || newchar > 0x7A) {
     1147                                newchar = 0x20;
     1148                        }
     1149                }
     1150
     1151                stringstorage[counter] = newchar;
     1152                counter++;
     1153        } while (!(_code[_currentInstruction - 1] & 0x80));
     1154
     1155        stringstorage[counter] = 0;
     1156
     1157        // Load the font if required
     1158        if (!_font) {
     1159                _font = new Font(_vm->_system);
     1160        }
     1161        _font->printstring(stringstorage);
     1162}
     1163
     1164void Script::o_hotspot_slot() {
     1165        uint16 slot = readScript8bits();
     1166        uint16 left = readScript16bits();
     1167        uint16 top = readScript16bits();
     1168        uint16 right = readScript16bits();
     1169        uint16 bottom = readScript16bits();
     1170        uint16 address = readScript16bits();
     1171        uint16 cursor = readScript8bits();
     1172
     1173        debugScript(1, true, "HOTSPOT-SLOT %d (%d,%d,%d,%d) @0x%04X cursor=%d (TODO)", slot, left, top, right, bottom, address, cursor);
     1174
     1175        Common::Rect rect(left, top, right, bottom);
     1176        if (hotspot(rect, address, cursor)) {
     1177                char savename[15];
     1178
     1179                Common::String filename = ConfMan.getActiveDomainName() + ".00" + ('0' + slot);
     1180                Common::StringList files = _vm->_system->getSavefileManager()->listSavefiles(filename.c_str());
     1181                if (!files.empty()) {
     1182                        Common::InSaveFile *file = _vm->_system->getSavefileManager()->openForLoading(filename.c_str());
     1183                        if (file) {
     1184                                uint8 i;
     1185                                char temp;
     1186
     1187                                for (i = 0; i < 15; i++) {
     1188                                        file->read(&temp, 1);
     1189                                        savename[i] = temp + 0x30;
     1190                                }
     1191
     1192                                delete file;
     1193                        } else {
     1194                                strcpy(savename, "ERROR");
     1195                        }
     1196                } else {
     1197                        strcpy(savename, "E M P T Y");
     1198                }
     1199
     1200                // Load the font if required
     1201                if (!_font) {
     1202                        _font = new Font(_vm->_system);
     1203                }
     1204                _font->printstring(savename);
     1205        } else {
     1206                Common::Point mousepos = _vm->_system->getEventManager()->getMousePos();
     1207                if (_hotspotCursorOldX != mousepos.x || _hotspotCursorOldY != mousepos.y ) {
     1208                        Common::Rect topbar(640, 80);
     1209
     1210                        Graphics::Surface *gamescreen;
     1211                        gamescreen = _vm->_system->lockScreen();
     1212
     1213                        gamescreen->fillRect(topbar, 0);       
     1214
     1215                        _vm->_system->unlockScreen();
     1216                        _hotspotCursorOldX = mousepos.x;
     1217                        _hotspotCursorOldY = mousepos.y;
     1218                }
     1219        }
     1220}
     1221
     1222void Script::o_checkvalidsaves() {
     1223        debugScript(1, true, "CHECKVALIDSAVES");
     1224
     1225        // Reset the array of valid saves
     1226        for (int i = 0; i < 10; i++) {
     1227                _variables[i] = 0;
     1228        }
     1229
     1230        // Get the list of savefiles
     1231        Common::String pattern = ConfMan.getActiveDomainName() + ".00?";
     1232        Common::StringList savefiles = _vm->_system->getSavefileManager()->listSavefiles(pattern.c_str());
     1233
     1234        // Mark the existing savefiles as valid
     1235        uint count = 0;
     1236        Common::StringList::iterator it = savefiles.begin();
     1237        while (it != savefiles.end()) {
     1238                int8 n = it->lastChar() - '0';
     1239                if (n >= 0 && n <= 9) {
     1240                        // TODO: Check the contents of the file?
     1241                        debugScript(2, true, "  Found valid savegame: %s", it->c_str());
     1242                        _variables[n] = 1;
     1243                        count++;
     1244                }
     1245                it++;
     1246        }
     1247
     1248        // Save the number of valid saves
     1249        _variables[0x104] = count;
     1250        debugScript(1, true, "  Found %d valid savegames", count);
     1251}
     1252
     1253void Script::o_resetvars() {
     1254        debugScript(1, true, "RESETVARS");
     1255        for (int i = 0; i < 0x100; i++) {
     1256                _variables[i] = 0;
     1257        }
     1258}
     1259
     1260void Script::o_mod() {
     1261        uint16 varnum = readScript8or16bits();
     1262        uint8 val = readScript8bits();
     1263
     1264        debugScript(1, true, "MOD var[0x%04X] %%= %d", varnum, val);
     1265
     1266        _variables[varnum] %= val;
     1267}
     1268
     1269void Script::o_loadscript() {
     1270        Common::String filename;
     1271        char c;
     1272
     1273        while ((c = readScript8bits())) {
     1274                filename += c;
     1275        }
     1276        debugScript(1, true, "LOADSCRIPT %s", filename.c_str());
     1277
     1278        // Just 1 level of sub-scripts are allowed
     1279        if (_savedCode) {
     1280                error("Tried to load a level 2 sub-script");
     1281        }
     1282
     1283        // Save the current code
     1284        _savedCode = _code;
     1285        _savedInstruction = _currentInstruction;
     1286
     1287        // Save the filename of the current script
     1288        _savedScriptFile = _scriptFile;
     1289
     1290        // Load the sub-script
     1291        if (!loadScript(filename)) {
     1292                error("Couldn't load sub-script");
     1293        }
     1294
     1295        // Save the current stack top
     1296        _savedStacktop = _stacktop;
     1297
     1298        // Save the variables
     1299        memcpy(_savedVariables, _variables + 0x107, 0x180);
     1300}
     1301
     1302void Script::o_setvideoorigin() {
     1303        // Read the two offset arguments
     1304        int16 origX = readScript16bits();
     1305        int16 origY = readScript16bits();
     1306       
     1307        // Set bitflag 7
     1308        _bitflags |= 1 << 7;
     1309
     1310        debugScript(1, true, "SetVideoOrigin(0x%04X,0x%04X) (%d, %d)", origX, origY, origX, origY);
     1311        _vm->_videoPlayer->setOrigin(origX, origY);
     1312}
     1313
     1314void Script::o_sub() {
     1315        uint16 varnum1 = readScript8or16bits();
     1316        uint16 varnum2 = readScript16bits();
     1317
     1318        debugScript(1, true, "SUB var[0x%04X] -= var[0x%04X]", varnum1, varnum2);
     1319
     1320        _variables[varnum1] -= _variables[varnum2];
     1321}
     1322
     1323void Script::o_othello() {
     1324        uint16 arg = readScript8bits();
     1325        byte *scriptBoard = &_variables[0x19];
     1326        byte board[7][7];
     1327
     1328        debugScript(1, true, "OTHELLO var[0x%02X]", arg);
     1329
     1330        // Arguments used by the original implementation: (2, arg, scriptBoard)
     1331        for (int y = 0; y < 7; y++) {
     1332                for (int x = 0; x < 7; x++) {
     1333                        board[x][y] = 0;
     1334                        if (*scriptBoard == 0x32) board[x][y] = 1;
     1335                        if (*scriptBoard == 0x42) board[x][y] = 2;
     1336                        scriptBoard++;
     1337                        debugScript(1, false, "%d", board[x][y]);
     1338                }
     1339                debugScript(1, false, "\n");
     1340        }
     1341
     1342        // Set the movement origin
     1343        _variables[0] = 6; // y
     1344        _variables[1] = 0; // x
     1345        // Set the movement destination
     1346        _variables[2] = 6;
     1347        _variables[3] = 1;
     1348}
     1349
     1350void Script::o_returnscript() {
     1351        uint8 val = readScript8bits();
     1352
     1353        debugScript(1, true, "RETURNSCRIPT @0x%02X", val);
     1354
     1355        // Are we returning from a sub-script?
     1356        if (!_savedCode) {
     1357                error("Tried to return from the main script");
     1358        }
     1359
     1360        // Set the return value
     1361        _variables[0x102] = val;
     1362
     1363        // Restore the code
     1364        delete[] _code;
     1365        _code = _savedCode;
     1366        _savedCode = NULL;
     1367        _currentInstruction = _savedInstruction;
     1368
     1369        // Restore the stack
     1370        _stacktop = _savedStacktop;
     1371
     1372        // Restore the variables
     1373        memcpy(_variables + 0x107, _savedVariables, 0x180);
     1374
     1375        // Restore the filename of the script
     1376        _scriptFile = _savedScriptFile;
     1377
     1378        //TODO: reset script flags and previous video's flag1?
     1379        _vm->_videoPlayer->setOrigin(0, 0);
     1380}
     1381
     1382void Script::o_sethotspotright() {
     1383        uint16 address = readScript16bits();
     1384
     1385        debugScript(1, true, "SETHOTSPOTRIGHT @0x%04X", address);
     1386
     1387        _hotspotRightAction = address;
     1388}
     1389
     1390void Script::o_sethotspotleft() {
     1391        uint16 address = readScript16bits();
     1392
     1393        debugScript(1, true, "SETHOTSPOTLEFT @0x%04X", address);
     1394
     1395        _hotspotLeftAction = address;
     1396}
     1397
     1398void Script::o_getcd() {
     1399        debugScript(1, true, "GETCD");
     1400
     1401        // By default set it to no CD available
     1402        int8 cd = -1;
     1403
     1404        // Try to open one file from each CD
     1405        Common::File cdfile;
     1406        if (cdfile.open("b.gjd")) {
     1407                cdfile.close();
     1408                cd = 1;
     1409        }
     1410        if (cdfile.open("at.gjd")) {
     1411                cdfile.close();
     1412                if (cd == 1) {
     1413                        // Both CDs are available
     1414                        cd = 0;
     1415                } else {
     1416                        cd = 2;
     1417                }
     1418        }
     1419
     1420        _variables[0x106] = cd;
     1421}
     1422
     1423void Script::o_opcode4D() {
     1424        // TODO: play alternative vie logo, then playcd
     1425        uint8 val = readScript8bits();
     1426       
     1427        debugScript(1, true, "PLAYCD? %d", val);
     1428
     1429        if (val == 2) {
     1430                AudioCD.play(1, 1, 0, 0);
     1431        }
     1432
     1433}
     1434
     1435void Script::o_hotspot_outrect() {
     1436        uint16 left = readScript16bits();
     1437        uint16 top = readScript16bits();
     1438        uint16 right = readScript16bits();
     1439        uint16 bottom = readScript16bits();
     1440        uint16 address = readScript16bits();
     1441       
     1442        debugScript(1, true, "HOTSPOT-OUTRECT(%d,%d,%d,%d) @0x%04X (TODO)", left, top, right, bottom, address);
     1443
     1444        // Test if the current mouse position is outside the specified rectangle
     1445        Common::Rect rect(left, top, right, bottom);
     1446        Common::Point mousepos = _vm->_system->getEventManager()->getMousePos();
     1447        bool contained = rect.contains(mousepos);
     1448
     1449        if (!contained) {
     1450                error("hotspot-outrect unimplemented!");
     1451                // TODO: what to do with address?
     1452        }
     1453}
     1454
     1455void Script::o_stub56() {
     1456        uint32 val1 = readScript32bits();
     1457        uint8 val2 = readScript8bits();
     1458        uint8 val3 = readScript8bits();
     1459       
     1460        debugScript(1, true, "STUB56: 0x%08X 0x%02X 0x%02X", val1, val2, val3);
     1461}
     1462
     1463void Script::o_stub59() {
     1464        uint16 val1 = readScript8or16bits();
     1465        uint8 val2 = readScript8bits();
     1466       
     1467        debugScript(1, true, "STUB59: 0x%04X 0x%02X", val1, val2);
     1468}
     1469
     1470Script::OpcodeFunc Script::_opcodes[NUM_OPCODES] = {
     1471        &Script::o_nop, // 0x00
     1472        &Script::o_nop,
     1473        &Script::o_playsong,
     1474        &Script::o_bf9on,
     1475        &Script::o_palfadeout, // 0x04
     1476        &Script::o_bf8on,
     1477        &Script::o_bf6on,
     1478        &Script::o_bf7on,
     1479        &Script::o_setbackgroundsong, // 0x08
     1480        &Script::o_videofromref,
     1481        &Script::o_bf5on,
     1482        &Script::o_inputloopstart,
     1483        &Script::o_keyboardaction, // 0x0C
     1484        &Script::o_hotspot_rect,
     1485        &Script::o_hotspot_left,
     1486        &Script::o_hotspot_right,
     1487        &Script::o_hotspot_center, // 0x10
     1488        &Script::o_hotspot_center,
     1489        &Script::o_hotspot_current,
     1490        &Script::o_inputloopend,
     1491        &Script::o_random, // 0x14
     1492        &Script::o_jmp,
     1493        &Script::o_loadstring,
     1494        &Script::o_ret,
     1495        &Script::o_call, // 0x18
     1496        &Script::o_sleep,
     1497        &Script::o_strcmpnejmp,
     1498        &Script::o_xor_obfuscate,
     1499        &Script::o_vdxtransition, // 0x1C
     1500        &Script::o_swap,
     1501        &Script::o_nop8,
     1502        &Script::o_inc,
     1503        &Script::o_dec, // 0x20
     1504        &Script::o_strcmpnejmp_var,
     1505        &Script::o_copybgtofg,
     1506        &Script::o_strcmpeqjmp,
     1507        &Script::o_mov, // 0x24
     1508        &Script::o_add,
     1509        &Script::o_videofromstring1, // Reads a string and then does stuff: used by book in library
     1510        &Script::o_videofromstring2, // play vdx file from string, after setting 1 (and 2 if firstbit)
     1511        &Script::o_nop16, // 0x28
     1512        &Script::o_stopmidi,
     1513        &Script::o_endscript,
     1514        &Script::o_nop,
     1515        &Script::o_sethotspottop, // 0x2C
     1516        &Script::o_sethotspotbottom,
     1517        &Script::o_loadgame,
     1518        &Script::o_savegame,
     1519        &Script::o_hotspotbottom_4, // 0x30
     1520        &Script::o_midivolume,
     1521        &Script::o_jne,
     1522        &Script::o_loadstringvar,
     1523        &Script::o_chargreatjmp, // 0x34
     1524        &Script::o_bf7off,
     1525        &Script::o_charlessjmp,
     1526        &Script::o_copyrecttobg,
     1527        &Script::o_restorestkpnt, // 0x38
     1528        &Script::o_obscureswap,
     1529        &Script::o_printstring,
     1530        &Script::o_hotspot_slot,
     1531        &Script::o_checkvalidsaves, // 0x3C
     1532        &Script::o_resetvars,
     1533        &Script::o_mod,
     1534        &Script::o_loadscript,
     1535        &Script::o_setvideoorigin, // 0x40
     1536        &Script::o_sub,
     1537        &Script::o_othello,
     1538        &Script::o_returnscript,
     1539        &Script::o_sethotspotright, // 0x44
     1540        &Script::o_sethotspotleft,
     1541        &Script::o_nop,
     1542        &Script::o_nop,
     1543        &Script::o_nop8, // 0x48
     1544        &Script::o_nop,
     1545        &Script::o_nop16,
     1546        &Script::o_nop8,
     1547        &Script::o_getcd, // 0x4C
     1548        &Script::o_opcode4D,
     1549        &Script::o_nop16,
     1550        &Script::o_nop16,
     1551        &Script::o_nop16, // 0x50
     1552        &Script::o_nop16,
     1553        //&Script::o_nop8,
     1554        &Script::o_invalid,             // Do loads with game area, maybe draw dirty areas?
     1555        &Script::o_hotspot_outrect,
     1556        &Script::o_nop, // 0x54
     1557        &Script::o_nop16,
     1558        &Script::o_stub56,
     1559        //&Script::o_nop32,
     1560        &Script::o_invalid,             // completely unimplemented, plays vdx in some way
     1561        //&Script::o_nop, // 0x58
     1562        &Script::o_invalid, // 0x58     // like above, but plays from string not ref
     1563        &Script::o_stub59
     1564};
     1565
     1566} // End of Groovie namespace
  • engines/groovie/graphics.h

     
     1/* ScummVM - Graphic Adventure Engine
     2 *
     3 * ScummVM is the legal property of its developers, whose names
     4 * are too numerous to list here. Please refer to the COPYRIGHT
     5 * file distributed with this source distribution.
     6 *
     7 * This program is free software; you can redistribute it and/or
     8 * modify it under the terms of the GNU General Public License
     9 * as published by the Free Software Foundation; either version 2
     10 * of the License, or (at your option) any later version.
     11
     12 * This program is distributed in the hope that it will be useful,
     13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15 * GNU General Public License for more details.
     16
     17 * You should have received a copy of the GNU General Public License
     18 * along with this program; if not, write to the Free Software
     19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
     20 *
     21 * $URL$
     22 * $Id$
     23 *
     24 */
     25
     26#ifndef GROOVIE_GRAPHICS_H
     27#define GROOVIE_GRAPHICS_H
     28
     29namespace Groovie {
     30
     31class GroovieEngine;
     32
     33class GraphicsMan {
     34public:
     35        GraphicsMan(GroovieEngine *vm);
     36        ~GraphicsMan();
     37
     38        // Buffers
     39        void update();
     40        void change();
     41        void mergeFgAndBg();
     42        void updateScreen(Graphics::Surface *source);
     43        Graphics::Surface _foreground;  // The main surface that most things are drawn to
     44        Graphics::Surface _background;  // Used occasionally, mostly (only?) in puzzles
     45
     46        // Palette fading
     47        bool isFading();
     48        void fadeIn(byte *pal);
     49        void fadeOut();
     50
     51private:
     52        GroovieEngine *_vm;
     53
     54        bool _changed;
     55
     56        // Palette fading
     57        void applyFading(int step);
     58        int _fading;
     59        byte _paletteFull[256 * 4];
     60        uint32 _fadeStartTime;
     61};
     62
     63} // End of Groovie namespace
     64
     65#endif // GROOVIE_GRAPHICS_H
  • engines/groovie/roq.h

     
     1/* ScummVM - Graphic Adventure Engine
     2 *
     3 * ScummVM is the legal property of its developers, whose names
     4 * are too numerous to list here. Please refer to the COPYRIGHT
     5 * file distributed with this source distribution.
     6 *
     7 * This program is free software; you can redistribute it and/or
     8 * modify it under the terms of the GNU General Public License
     9 * as published by the Free Software Foundation; either version 2
     10 * of the License, or (at your option) any later version.
     11
     12 * This program is distributed in the hope that it will be useful,
     13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15 * GNU General Public License for more details.
     16
     17 * You should have received a copy of the GNU General Public License
     18 * along with this program; if not, write to the Free Software
     19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
     20 *
     21 * $URL$
     22 * $Id$
     23 *
     24 */
     25
     26#ifndef GROOVIE_ROQ_H
     27#define GROOVIE_ROQ_H
     28
     29#include "groovie/player.h"
     30
     31namespace Groovie {
     32
     33class GroovieEngine;
     34
     35struct ROQBlockHeader {
     36        uint16 type;
     37        uint32 size;
     38        uint16 param;
     39};
     40
     41class ROQPlayer : public VideoPlayer {
     42public:
     43        ROQPlayer(GroovieEngine *vm);
     44        ~ROQPlayer();
     45
     46protected:
     47        uint16 loadInternal();
     48        bool playFrameInternal();
     49
     50private:
     51        bool readBlockHeader(ROQBlockHeader &blockHeader);
     52
     53        bool processBlock();
     54        bool processBlockInfo(ROQBlockHeader &blockHeader);
     55        bool processBlockQuadCodebook(ROQBlockHeader &blockHeader);
     56        bool processBlockQuadVector(ROQBlockHeader &blockHeader);
     57        bool processBlockQuadVectorSub(ROQBlockHeader &blockHeader);
     58        bool processBlockStill(ROQBlockHeader &blockHeader);
     59        bool processBlockSoundMono(ROQBlockHeader &blockHeader);
     60        bool processBlockSoundStereo(ROQBlockHeader &blockHeader);
     61        bool processBlockAudioContainer(ROQBlockHeader &blockHeader);
     62
     63        uint16 _num2blocks;
     64        uint16 _num4blocks;
     65};
     66
     67} // End of Groovie namespace
     68
     69#endif // GROOVIE_ROQ_H
  • engines/groovie/font.cpp

     
     1/* ScummVM - Graphic Adventure Engine
     2 *
     3 * ScummVM is the legal property of its developers, whose names
     4 * are too numerous to list here. Please refer to the COPYRIGHT
     5 * file distributed with this source distribution.
     6 *
     7 * This program is free software; you can redistribute it and/or
     8 * modify it under the terms of the GNU General Public License
     9 * as published by the Free Software Foundation; either version 2
     10 * of the License, or (at your option) any later version.
     11
     12 * This program is distributed in the hope that it will be useful,
     13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15 * GNU General Public License for more details.
     16
     17 * You should have received a copy of the GNU General Public License
     18 * along with this program; if not, write to the Free Software
     19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
     20 *
     21 * $URL$
     22 * $Id$
     23 *
     24 */
     25
     26#include "common/file.h"
     27#include "graphics/surface.h"
     28
     29#include "groovie/font.h"
     30
     31namespace Groovie {
     32
     33Font::Font(OSystem *syst) :
     34        _syst(syst), _sphinxfnt(NULL) {
     35
     36        Common::File fontfile;
     37        if (!fontfile.open("sphinx.fnt")) {
     38                error("Groovie::Font: Couldn't open sphinx.fnt");
     39        }
     40        uint16 fontfilesize = fontfile.size();
     41        _sphinxfnt = fontfile.readStream(fontfilesize);
     42        fontfile.close();
     43}
     44
     45Font::~Font() {
     46        delete _sphinxfnt;
     47}
     48
     49void Font::printstring(char *messagein) {
     50        uint16 totalwidth = 0, currxoffset, i;
     51
     52        char message[15];
     53        memset(message, 0, 15);
     54
     55        // Clear the top bar
     56        Common::Rect topbar(640, 80);
     57        Graphics::Surface *gamescreen;
     58        gamescreen = _syst->lockScreen();
     59        gamescreen->fillRect(topbar, 0);       
     60        _syst->unlockScreen();
     61
     62        for (i = 0; i < 14; i++) {
     63                char chartocopy = messagein[i];
     64                if (chartocopy <= 0x00 || chartocopy == 0x24) {
     65                        break;
     66                }
     67                message[i] = chartocopy;
     68        }
     69        Common::rtrim(message);
     70        for (i = 0; i < strlen(message); i++) {
     71                totalwidth += letterwidth(message[i]);
     72        }
     73        currxoffset = (640 - totalwidth) / 2;
     74        char *currpos = message;
     75        while (*(currpos) != 0) {
     76                currxoffset += printletter(*(currpos++), currxoffset);
     77        }
     78}
     79
     80uint16 Font::letteroffset(char letter) {
     81        uint16 offset;
     82        offset = letter;
     83        _sphinxfnt->seek(offset);
     84        offset = _sphinxfnt->readByte() * 2 + 128;
     85        _sphinxfnt->seek(offset);
     86        offset = _sphinxfnt->readUint16LE();
     87        return offset;
     88}
     89
     90uint8 Font::letterwidth(char letter) {
     91        uint16 offset = letteroffset(letter);
     92        _sphinxfnt->seek(offset);
     93        return _sphinxfnt->readByte();
     94}
     95
     96uint8 Font::letterheight(char letter) {
     97        uint16 offset, width, julia, data, counter = 0;
     98        offset = letteroffset(letter);
     99        _sphinxfnt->seek(offset);
     100        width = _sphinxfnt->readByte();
     101        julia = _sphinxfnt->readByte();
     102        data = _sphinxfnt->readByte();
     103        while (data != 0xFF) {
     104                data = _sphinxfnt->readByte();
     105                counter++;
     106        }
     107        if (counter % width != 0) assert("font file corrupt");
     108        return counter / width;
     109}
     110
     111
     112uint8 Font::printletter(char letter, uint16 xoffset) {
     113        uint16 offset, width, height, julia;
     114        offset = letteroffset(letter);
     115        height = letterheight(letter);
     116        _sphinxfnt->seek(offset);
     117        width = _sphinxfnt->readByte();
     118        julia = _sphinxfnt->readByte();
     119
     120        byte *data = new byte[width * height];
     121        _sphinxfnt->read(data, width * height);
     122        _syst->copyRectToScreen(data, width, xoffset, 16, width, height);
     123        delete data;
     124       
     125        return width;
     126}
     127
     128} // End of Groovie namespace
  • engines/groovie/vdx.h

     
     1/* ScummVM - Graphic Adventure Engine
     2 *
     3 * ScummVM is the legal property of its developers, whose names
     4 * are too numerous to list here. Please refer to the COPYRIGHT
     5 * file distributed with this source distribution.
     6 *
     7 * This program is free software; you can redistribute it and/or
     8 * modify it under the terms of the GNU General Public License
     9 * as published by the Free Software Foundation; either version 2
     10 * of the License, or (at your option) any later version.
     11
     12 * This program is distributed in the hope that it will be useful,
     13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15 * GNU General Public License for more details.
     16
     17 * You should have received a copy of the GNU General Public License
     18 * along with this program; if not, write to the Free Software
     19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
     20 *
     21 * $URL$
     22 * $Id$
     23 *
     24 */
     25
     26#ifndef GROOVIE_VDX_H
     27#define GROOVIE_VDX_H
     28
     29#include "groovie/player.h"
     30
     31namespace Groovie {
     32
     33class VDXPlayer : public VideoPlayer {
     34public:
     35        VDXPlayer(GroovieEngine *vm);
     36        ~VDXPlayer();
     37        void setOrigin(int16 x, int16 y);
     38
     39protected:
     40        uint16 loadInternal();
     41        bool playFrameInternal();
     42
     43private:
     44        Graphics::Surface *_fg, *_bg;
     45        uint8 _palBuf[3 * 256];
     46
     47        // Origin
     48        int16 _origX, _origY;
     49
     50        // Video flags
     51        bool _flagZero;
     52        bool _flagOne;
     53        bool _flagOnePrev;
     54        byte _flag2Byte;
     55        bool _flagThree;
     56        bool _flagFour;
     57        bool _flagFive;
     58        bool _flagSix;
     59        bool _flagSeven;
     60        bool _flagEight;
     61        bool _flagNine;
     62
     63        bool _flagSkipStill;
     64        bool _flagSkipPalette;
     65        bool _flagFirstFrame;
     66        bool _flagTransparent;
     67        bool _flagUpdateStill;
     68
     69        void getStill(Common::ReadStream *in);
     70        void getDelta(Common::ReadStream *in);
     71        void expandColourMap(byte *out, uint16 colourMap, uint8 colour1, uint8 colour0);
     72        void decodeBlockStill(byte *buf, byte *colours, uint16 imageWidth, uint8 mask);
     73        void decodeBlockDelta(uint32 offset, byte *colours, uint16 imageWidth);
     74        void chunkSound(Common::ReadStream *in);
     75        void setPalette(uint8 *palette);
     76        void fadeIn(uint8 *palette);
     77};
     78
     79} // End of Groovie namespace
     80
     81#endif // GROOVIE_VDX_H
  • engines/groovie/script.h

     
     1/* ScummVM - Graphic Adventure Engine
     2 *
     3 * ScummVM is the legal property of its developers, whose names
     4 * are too numerous to list here. Please refer to the COPYRIGHT
     5 * file distributed with this source distribution.
     6 *
     7 * This program is free software; you can redistribute it and/or
     8 * modify it under the terms of the GNU General Public License
     9 * as published by the Free Software Foundation; either version 2
     10 * of the License, or (at your option) any later version.
     11
     12 * This program is distributed in the hope that it will be useful,
     13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15 * GNU General Public License for more details.
     16
     17 * You should have received a copy of the GNU General Public License
     18 * along with this program; if not, write to the Free Software
     19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
     20 *
     21 * $URL$
     22 * $Id$
     23 *
     24 */
     25
     26#ifndef GROOVIE_SCRIPT_H
     27#define GROOVIE_SCRIPT_H
     28
     29#include "common/file.h"
     30#include "common/rect.h"
     31
     32#include "groovie/font.h"
     33
     34namespace Groovie {
     35
     36class GroovieEngine;
     37
     38class Script {
     39        friend class Debugger;
     40
     41public:
     42        Script(GroovieEngine *vm);
     43        ~Script();
     44
     45        void setDebugger(Debugger *debugger);
     46
     47        bool loadScript(Common::String scriptfile);
     48        void directGameLoad(int slot);
     49        void step();
     50
     51        void setMouseClick();
     52        void setKbdChar(uint8 c);
     53
     54        bool haveError();
     55
     56private:
     57        GroovieEngine *_vm;
     58
     59        Common::RandomSource _random;
     60
     61        bool _firstbit;
     62
     63        // Script filename (for debugging purposes)
     64        Common::String _scriptFile;
     65        Common::String _savedScriptFile;
     66
     67        // Code
     68        byte *_code;
     69        uint16 _currentInstruction;
     70        byte *_savedCode;
     71        uint16 _savedInstruction;
     72
     73        // Variables
     74        byte _variables[0x400];
     75        byte _savedVariables[0x180];
     76
     77        // Stack
     78        uint16 _stack[0x20];
     79        uint8 _stacktop;
     80        uint8 _savedStacktop;
     81
     82        // Input
     83        bool _mouseClicked;
     84        bool _eventMouseClicked;
     85        uint8 _kbdChar;
     86        uint8 _eventKbdChar;
     87        uint16 _inputLoopAddress;
     88        int16 _inputAction;
     89        uint8 _newCursorStyle;
     90        uint16 _hotspotTopAction;
     91        uint16 _hotspotTopCursor;
     92        uint16 _hotspotBottomAction;
     93        uint16 _hotspotBottomCursor;
     94        uint16 _hotspotRightAction;
     95        uint16 _hotspotLeftAction;
     96        uint16 _hotspotCursorOldX;
     97        uint16 _hotspotCursorOldY;
     98
     99        // Video
     100        Font *_font;
     101        Common::SeekableReadStream *_videoFile;
     102        uint16 _videoRef;
     103        uint16 _bitflags;
     104
     105        // Debugging
     106        Debugger *_debugger;
     107        Common::String _debugString;
     108        void error(const char *msg);
     109        bool _error;
     110
     111        // Helper functions
     112        uint8 readScript8bits();
     113        uint16 readScript16bits();
     114        uint32 readScript32bits();
     115        uint16 readScript8or16bits();
     116        uint8 readScriptChar(bool allow7C, bool limitVal, bool limitVar);
     117        uint8 readScriptVar();
     118        uint16 getVideoRefString();
     119
     120        bool hotspot(Common::Rect rect, uint16 addr, uint8 cursor);
     121
     122        void loadgame(uint slot);
     123        void savegame(uint slot);
     124        bool playvideofromref(uint16 fileref);
     125
     126        // Opcodes
     127        typedef void (Script::*OpcodeFunc)();
     128        static OpcodeFunc _opcodes[];
     129
     130        void o_invalid();
     131
     132        void o_nop();
     133        void o_nop8();
     134        void o_nop16();
     135        void o_nop32();
     136        void o_nop8or16();
     137
     138        void o_playsong();
     139        void o_bf9on();
     140        void o_palfadeout();
     141        void o_bf8on();
     142        void o_bf6on();
     143        void o_bf7on();
     144        void o_setbackgroundsong();
     145        void o_videofromref();
     146        void o_bf5on();
     147        void o_inputloopstart();
     148        void o_keyboardaction();
     149        void o_hotspot_rect();
     150        void o_hotspot_left();
     151        void o_hotspot_right();
     152        void o_hotspot_center();
     153        void o_hotspot_current();
     154        void o_inputloopend();
     155        void o_random();
     156        void o_jmp();
     157        void o_loadstring();
     158        void o_ret();
     159        void o_call();
     160        void o_sleep();
     161        void o_strcmpnejmp_var();
     162        void o_copybgtofg();
     163        void o_strcmpnejmp();
     164        void o_xor_obfuscate();
     165        void o_vdxtransition();
     166        void o_swap();
     167        void o_inc();
     168        void o_dec();
     169        void o_strcmpeqjmp();
     170        void o_mov();
     171        void o_add();
     172        void o_videofromstring1();
     173        void o_videofromstring2();
     174        void o_stopmidi();
     175        void o_endscript();
     176        void o_sethotspottop();
     177        void o_sethotspotbottom();
     178        void o_loadgame();
     179        void o_savegame();
     180        void o_hotspotbottom_4();
     181        void o_midivolume();
     182        void o_jne();
     183        void o_loadstringvar();
     184        void o_chargreatjmp();
     185        void o_bf7off();
     186        void o_charlessjmp();
     187        void o_copyrecttobg();
     188        void o_restorestkpnt();
     189        void o_obscureswap();
     190        void o_printstring();
     191        void o_hotspot_slot();
     192        void o_checkvalidsaves();
     193        void o_resetvars();
     194        void o_mod();
     195        void o_loadscript();
     196        void o_setvideoorigin();
     197        void o_sub();
     198        void o_othello();
     199        void o_returnscript();
     200        void o_sethotspotright();
     201        void o_sethotspotleft();
     202        void o_getcd();
     203        void o_opcode4D();
     204        void o_hotspot_outrect();
     205        void o_stub56();
     206        void o_stub59();
     207};
     208
     209} // End of Groovie namespace
     210
     211#endif // GROOVIE_SCRIPT_H
  • engines/groovie/groovie.cpp

     
     1/* ScummVM - Graphic Adventure Engine
     2 *
     3 * ScummVM is the legal property of its developers, whose names
     4 * are too numerous to list here. Please refer to the COPYRIGHT
     5 * file distributed with this source distribution.
     6 *
     7 * This program is free software; you can redistribute it and/or
     8 * modify it under the terms of the GNU General Public License
     9 * as published by the Free Software Foundation; either version 2
     10 * of the License, or (at your option) any later version.
     11
     12 * This program is distributed in the hope that it will be useful,
     13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15 * GNU General Public License for more details.
     16
     17 * You should have received a copy of the GNU General Public License
     18 * along with this program; if not, write to the Free Software
     19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
     20 *
     21 * $URL$
     22 * $Id$
     23 *
     24 */
     25
     26#include "common/config-manager.h"
     27#include "common/events.h"
     28#include "sound/mixer.h"
     29
     30#include "groovie/groovie.h"
     31#include "groovie/music.h"
     32#include "groovie/roq.h"
     33#include "groovie/vdx.h"
     34
     35namespace Groovie {
     36
     37GroovieEngine::GroovieEngine(OSystem *syst, GroovieGameDescription *gd) :
     38        Engine(syst), _gameDescription(gd), _debugger(NULL), _script(this),
     39        _resMan(NULL), _cursorMan(NULL), _videoPlayer(NULL), _musicPlayer(NULL),
     40        _graphicsMan(NULL), _waitingForInput(false) {
     41
     42        // Adding the default directories
     43        Common::File::addDefaultDirectory(_gameDataDir.getChild("groovie"));
     44        Common::File::addDefaultDirectory(_gameDataDir.getChild("media"));
     45        Common::File::addDefaultDirectory(_gameDataDir.getChild("system"));
     46
     47        // Initialize the custom debug levels
     48        Common::addSpecialDebugLevel(kGroovieDebugAll, "All", "Debug everything");
     49        Common::addSpecialDebugLevel(kGroovieDebugVideo, "Video", "Debug video and audio playback");
     50        Common::addSpecialDebugLevel(kGroovieDebugResource, "Resource", "Debug resouce management");
     51        Common::addSpecialDebugLevel(kGroovieDebugScript, "Script", "Debug the scripts");
     52        Common::addSpecialDebugLevel(kGroovieDebugUnknown, "Unknown", "Report values of unknown data in files");
     53        Common::addSpecialDebugLevel(kGroovieDebugHotspots, "Hotspots", "Show the hotspots");
     54        Common::addSpecialDebugLevel(kGroovieDebugCursor, "Cursor", "Debug cursor decompression / switching");
     55}
     56
     57GroovieEngine::~GroovieEngine() {
     58        // Delete the remaining objects
     59        delete _debugger;
     60        delete _resMan;
     61        delete _cursorMan;
     62        delete _videoPlayer;
     63        delete _musicPlayer;
     64        delete _graphicsMan;
     65}
     66
     67Common::Error GroovieEngine::init() {
     68        // Initialize the graphics
     69        _system->beginGFXTransaction();
     70        initCommonGFX(true);
     71        _system->initSize(640, 480);
     72        _system->endGFXTransaction();
     73
     74        // Create debugger. It requires GFX to be initialized
     75        _debugger = new Debugger(this);
     76        _script.setDebugger(_debugger);
     77
     78        // Create the graphics manager
     79        _graphicsMan = new GraphicsMan(this);
     80
     81        // Create the resource and cursor managers and the video player
     82        switch (_gameDescription->version) {
     83        case kGroovieT7G:
     84                _resMan = new ResMan_t7g();
     85                _cursorMan = new CursorMan_t7g(_system);
     86                _videoPlayer = new VDXPlayer(this);
     87                break;
     88        case kGroovieV2:
     89                _resMan = new ResMan_v2();
     90                _cursorMan = new CursorMan_v2(_system);
     91                _videoPlayer = new ROQPlayer(this);
     92                break;
     93        }
     94
     95        // Create the music player
     96        _musicPlayer = new MusicPlayer(this);
     97
     98        // Load volume levels
     99        syncSoundSettings();
     100
     101        // Get the name of the main script
     102        Common::String filename = _gameDescription->desc.filesDescriptions[0].fileName;
     103        if (_gameDescription->version == kGroovieT7G) {
     104                // Run The 7th Guest's demo if requested
     105                if (ConfMan.hasKey("demo_mode") && ConfMan.getBool("demo_mode")) {
     106                        filename = Common::String("demo.grv");
     107                }
     108        } else if (_gameDescription->version == kGroovieV2) {
     109                // Open the disk index
     110                Common::File disk;
     111                if (!disk.open(filename)) {
     112                        error("Couldn't open %s", filename.c_str());
     113                        return Common::kNoGameDataFoundError;
     114                }
     115
     116                // Search the entry
     117                bool found = false;
     118                int index = 0;
     119                while (!found && !disk.eos()) {
     120                        Common::String line = disk.readLine();
     121                        if (line.hasPrefix("title: ")) {
     122                                // A new entry
     123                                index++;
     124                        } else if (line.hasPrefix("boot: ") && index == _gameDescription->indexEntry) {
     125                                // It's the boot of the entry were looking for,
     126                                // get the script filename
     127                                filename = line.c_str() + 6;
     128                                found = true;
     129                        }
     130                }
     131
     132                // Couldn't find the entry
     133                if (!found) {
     134                        error("Couldn't find entry %d in %s", _gameDescription->indexEntry, filename.c_str());
     135                        return Common::kUnknownError;
     136                }
     137        }
     138       
     139        // Check the script file extension
     140        if (!filename.hasSuffix(".grv")) {
     141                error("%s isn't a valid script filename", filename.c_str());
     142                return Common::kUnknownError;
     143        }
     144
     145        // Load the script
     146        if (!_script.loadScript(filename)) {
     147                error("Couldn't load the script file %s", filename.c_str());
     148                return Common::kUnknownError;
     149        }
     150
     151        // Should I load a saved game?
     152        if (ConfMan.hasKey("save_slot")) {
     153                // Get the requested slot
     154                int slot = ConfMan.getInt("save_slot");
     155                _script.directGameLoad(slot);
     156        }
     157
     158        return Common::kNoError;
     159}
     160
     161Common::Error GroovieEngine::go() {
     162        // Check that the game files and the audio tracks aren't together run from
     163        // the same cd
     164       
     165        checkCD();
     166
     167        // Initialize the CD
     168        int cd_num = ConfMan.getInt("cdrom");
     169        if (cd_num >= 0)
     170                _system->openCD(cd_num);
     171
     172        while (!shouldQuit()) {
     173                // Show the debugger if required
     174                if (_debugger->isAttached()) {
     175                        _debugger->onFrame();
     176                }
     177
     178                // If there's still a script error after debugging, end the execution
     179                if (_script.haveError()) {
     180                        quitGame();
     181                        break;
     182                }
     183
     184                // Handle input
     185                Common::Event ev;
     186                while (_eventMan->pollEvent(ev)) {
     187                        switch (ev.type) {
     188                        case Common::EVENT_KEYDOWN:
     189                                // CTRL-D: Attach the debugger
     190                                if ((ev.kbd.flags & Common::KBD_CTRL) && ev.kbd.keycode == Common::KEYCODE_d)
     191                                        _debugger->attach();
     192
     193                                // Send the event to the scripts
     194                                _script.setKbdChar(ev.kbd.ascii);
     195
     196                                // Continue the script execution to handle the key
     197                                _waitingForInput = false;
     198                                break;
     199
     200                        case Common::EVENT_MOUSEMOVE:
     201                                // Continue the script execution, the mouse
     202                                // pointer may fall inside a hotspot now
     203                                _waitingForInput = false;
     204                                break;
     205
     206                        case Common::EVENT_LBUTTONDOWN:
     207                                // Send the event to the scripts
     208                                _script.setMouseClick();
     209
     210                                // Continue the script execution to handle
     211                                // the click
     212                                _waitingForInput = false;
     213                                break;
     214
     215                        case Common::EVENT_QUIT:
     216                                quitGame();
     217                                break;
     218
     219                        default:
     220                                break;
     221                        }
     222                }
     223
     224                if (_waitingForInput) {
     225                        // Still waiting for input, just update the mouse and wait a bit more
     226                        _cursorMan->animate();
     227                        _system->updateScreen();
     228                        _system->delayMillis(50);
     229                } else if (_graphicsMan->isFading()) {
     230                        // We're waiting for a fading to end, let the CPU rest
     231                        // for a while and continue
     232                        _system->delayMillis(30);
     233                } else {
     234                        // Everything's fine, execute another script step
     235                        _script.step();
     236                }
     237
     238                // Update the screen if required
     239                _graphicsMan->update();
     240        }
     241
     242        return Common::kNoError;
     243}
     244
     245bool GroovieEngine::hasFeature(EngineFeature f) const {
     246        return
     247                (f == kSupportsRTL) ||
     248                (f == kSupportsLoadingDuringRuntime);
     249}
     250
     251void GroovieEngine::syncSoundSettings() {
     252        _musicPlayer->setUserVolume(ConfMan.getInt("music_volume"));
     253        _mixer->setVolumeForSoundType(Audio::Mixer::kPlainSoundType, ConfMan.getInt("speech_volume"));
     254}
     255
     256bool GroovieEngine::canLoadGameStateCurrently() {
     257        // TODO: verify the engine has been initialized
     258        return true;
     259}
     260
     261Common::Error GroovieEngine::loadGameState(int slot) {
     262        _script.directGameLoad(slot);
     263
     264        // TODO: Use specific error codes
     265        return Common::kNoError;
     266}
     267
     268void GroovieEngine::waitForInput() {
     269        _waitingForInput = true;
     270}
     271
     272} // End of namespace Groovie
  • engines/groovie/module.mk

     
     1MODULE := engines/groovie
     2
     3MODULE_OBJS := \
     4        cursor.o \
     5        debug.o \
     6        detection.o \
     7        font.o \
     8        graphics.o \
     9        groovie.o \
     10        lzss.o \
     11        music.o \
     12        player.o \
     13        resource.o \
     14        roq.o \
     15        script.o \
     16        vdx.o
     17
     18# This module can be built as a plugin
     19ifeq ($(ENABLE_GROOVIE), DYNAMIC_PLUGIN)
     20PLUGIN := 1
     21endif
     22
     23# Include common rules
     24include $(srcdir)/rules.mk
  • engines/groovie/font.h

     
     1/* ScummVM - Graphic Adventure Engine
     2 *
     3 * ScummVM is the legal property of its developers, whose names
     4 * are too numerous to list here. Please refer to the COPYRIGHT
     5 * file distributed with this source distribution.
     6 *
     7 * This program is free software; you can redistribute it and/or
     8 * modify it under the terms of the GNU General Public License
     9 * as published by the Free Software Foundation; either version 2
     10 * of the License, or (at your option) any later version.
     11
     12 * This program is distributed in the hope that it will be useful,
     13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15 * GNU General Public License for more details.
     16
     17 * You should have received a copy of the GNU General Public License
     18 * along with this program; if not, write to the Free Software
     19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
     20 *
     21 * $URL$
     22 * $Id$
     23 *
     24 */
     25
     26#ifndef GROOVIE_FONT_H
     27#define GROOVIE_FONT_H
     28
     29#include "common/stream.h"
     30#include "common/system.h"
     31
     32namespace Groovie {
     33
     34class Font {
     35public:
     36        Font(OSystem *syst);
     37        ~Font();
     38        void printstring(char *messagein);
     39
     40private:
     41        OSystem *_syst;
     42        Common::MemoryReadStream *_sphinxfnt;
     43
     44        uint16 letteroffset(char letter);
     45        uint8 letterwidth(char letter);
     46        uint8 letterheight(char letter);
     47        uint8 printletter(char letter, uint16 xoffset);
     48};
     49
     50} // End of Groovie namespace
     51
     52#endif // GROOVIE_FONT_H
  • engines/groovie/cursor.cpp

     
     1/* ScummVM - Graphic Adventure Engine
     2 *
     3 * ScummVM is the legal property of its developers, whose names
     4 * are too numerous to list here. Please refer to the COPYRIGHT
     5 * file distributed with this source distribution.
     6 *
     7 * This program is free software; you can redistribute it and/or
     8 * modify it under the terms of the GNU General Public License
     9 * as published by the Free Software Foundation; either version 2
     10 * of the License, or (at your option) any later version.
     11
     12 * This program is distributed in the hope that it will be useful,
     13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15 * GNU General Public License for more details.
     16
     17 * You should have received a copy of the GNU General Public License
     18 * along with this program; if not, write to the Free Software
     19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
     20 *
     21 * $URL$
     22 * $Id$
     23 *
     24 */
     25
     26#include "groovie/cursor.h"
     27#include "groovie/groovie.h"
     28
     29namespace Groovie {
     30
     31// Cursor Manager
     32
     33CursorMan::CursorMan(OSystem *system) :
     34        _syst(system), _lastTime(0), _cursor(NULL) {
     35}
     36
     37CursorMan::~CursorMan() {
     38        // Delete the cursors
     39        for (uint cursor = 0; cursor < _cursors.size(); cursor++) {
     40                delete _cursors[cursor];
     41        }
     42}
     43
     44uint8 CursorMan::getStyle() {
     45        return _current;
     46}
     47
     48void CursorMan::setStyle(uint8 newStyle) {
     49        // Reset the animation
     50        _lastFrame = 254;
     51        _lastTime = 1;
     52
     53        // Save the new cursor
     54        _current = newStyle;
     55        _cursor = _cursors[newStyle];
     56
     57        // Show the first frame
     58        _cursor->enable();
     59        animate();
     60}
     61
     62void CursorMan::animate() {
     63        if (_lastTime) {
     64                int newTime = _syst->getMillis();
     65                if (_lastTime - newTime >= 75) {
     66                        _lastFrame++;
     67                        _lastFrame %= _cursor->getFrames();
     68                        _cursor->showFrame(_lastFrame);
     69                        _lastTime = _syst->getMillis();
     70                }
     71        }
     72}
     73
     74
     75// t7g Cursor
     76
     77class Cursor_t7g : public Cursor {
     78public:
     79        Cursor_t7g(OSystem *system, uint8 *img, uint8 *pal);
     80
     81        void enable();
     82        void showFrame(uint16 frame);
     83
     84private:
     85        OSystem *_syst;
     86        byte *_img;
     87        byte *_pal;
     88};
     89
     90Cursor_t7g::Cursor_t7g(OSystem *system, uint8 *img, uint8 *pal) :
     91        _syst(system), _pal(pal) {
     92
     93        _width = img[0];
     94        _height = img[1];
     95        _numFrames = img[2];
     96        uint8 elinor1 = img[3];
     97        uint8 elinor2 = img[4];
     98
     99        _img = img + 5;
     100
     101        debugC(1, kGroovieDebugCursor | kGroovieDebugAll, "Groovie::Cursor: width: %d, height: %d, frames:%d", _width, _height, _numFrames);
     102        debugC(1, kGroovieDebugCursor | kGroovieDebugUnknown | kGroovieDebugAll, "Groovie::Cursor: elinor: 0x%02X (%d), 0x%02X (%d)", elinor1, elinor1, elinor2, elinor2);
     103}
     104
     105void Cursor_t7g::enable() {
     106        // Apply the palette
     107        _syst->setCursorPalette(_pal, 0, 32);
     108}
     109
     110void Cursor_t7g::showFrame(uint16 frame) {
     111        // Set the mouse cursor
     112        int offset = _width * _height * frame;
     113        _syst->setMouseCursor((const byte *)_img + offset, _width, _height, _width >> 1, _height >> 1, 0);
     114}
     115
     116
     117// t7g Cursor Manager
     118
     119#define NUM_IMGS 9
     120static const uint16 cursorDataOffsets[NUM_IMGS] = {
     1210x0000, 0x182f, 0x3b6d, 0x50cc, 0x6e79, 0x825d, 0x96d7, 0xa455, 0xa776
     122};
     123
     124#define NUM_PALS 7
     125//Pals: 0xb794, 0xb7f4, 0xb854, 0xb8b4, 0xb914, 0xb974, 0xb9d4
     126
     127#define NUM_STYLES 11
     128// pyramid is cursor 8, eyes are 9 & 10
     129const uint CursorMan_t7g::_cursorImg[NUM_STYLES] = {3, 5, 4, 3, 1, 0, 2, 6, 7, 8, 8};
     130const uint CursorMan_t7g::_cursorPal[NUM_STYLES] = {0, 0, 0, 0, 2, 0, 1, 3, 5, 4, 6};
     131
     132CursorMan_t7g::CursorMan_t7g(OSystem *system) :
     133        CursorMan(system) {
     134
     135        // Open the cursors file
     136        Common::File robgjd;
     137        if (!robgjd.open("rob.gjd")) {
     138                error("Groovie::Cursor: Couldn't open rob.gjd");
     139                return;
     140        }
     141
     142        // Load the images
     143        for (uint imgnum = 0; imgnum < NUM_IMGS; imgnum++) {
     144                robgjd.seek(cursorDataOffsets[imgnum]);
     145                _images.push_back(loadImage(robgjd));
     146        }
     147
     148        // Load the palettes
     149        robgjd.seek(-0x60 * NUM_PALS, SEEK_END);
     150        for (uint palnum = 0; palnum < NUM_PALS; palnum++) {
     151                _palettes.push_back(loadPalette(robgjd));
     152        }
     153
     154        // Build the cursors
     155        for (uint cursor = 0; cursor < NUM_STYLES; cursor++) {
     156                Cursor *s = new Cursor_t7g(_syst, _images[_cursorImg[cursor]], _palettes[_cursorPal[cursor]]);
     157                _cursors.push_back(s);
     158        }
     159
     160        robgjd.close();
     161}
     162
     163CursorMan_t7g::~CursorMan_t7g() {
     164        // Delete the images
     165        for (uint img = 0; img < _images.size(); img++) {
     166                delete[] _images[img];
     167        }
     168
     169        // Delete the palettes
     170        for (uint pal = 0; pal < _palettes.size(); pal++) {
     171                delete[] _palettes[pal];
     172        }
     173}
     174
     175byte *CursorMan_t7g::loadImage(Common::File &file) {
     176        uint16 decompbytes = 0, offset, i, length;
     177        uint8 flagbyte, lengthmask = 0x0F, offsetlen, var_8;
     178        byte *cursorStorage = new byte[65536];
     179        uint8 *runningcursor = cursorStorage;
     180
     181        bool finished = false;
     182        while (!(finished || file.eos())) {
     183                flagbyte = file.readByte();
     184                for (i = 1; i <= 8; i++) {
     185                        if (!file.eos()) {
     186                                if (flagbyte & 1) {
     187                                        *(runningcursor++) = file.readByte();
     188                                        decompbytes++;
     189                                } else {
     190                                        var_8 = file.readByte();
     191                                        offsetlen = file.readByte();
     192                                        if (var_8 == 0 && offsetlen == 0) {
     193                                                finished = true;
     194                                                break;
     195                                        }
     196                                        length = (offsetlen & lengthmask) + 3;
     197                                        offsetlen >>= 4;
     198                                        offset = (offsetlen << 8) + var_8;
     199                                        decompbytes += length;
     200
     201                                        for (; length > 0; length--, runningcursor++) {
     202                                                *(runningcursor) = *(runningcursor - offset);
     203                                        }
     204                                }
     205                                flagbyte = flagbyte >> 1;
     206                        }
     207                }
     208        }
     209
     210        return cursorStorage;
     211}
     212
     213byte *CursorMan_t7g::loadPalette(Common::File &file) {
     214        byte *palette = new byte[4 * 32];
     215        for (uint8 colournum = 0; colournum < 32; colournum++) {
     216                palette[colournum * 4 + 0] = file.readByte();
     217                palette[colournum * 4 + 1] = file.readByte();
     218                palette[colournum * 4 + 2] = file.readByte();
     219                palette[colournum * 4 + 3] = 0;
     220        }
     221        return palette;
     222}
     223
     224
     225// v2 Cursor
     226
     227class Cursor_v2 : public Cursor {
     228public:
     229        Cursor_v2(Common::File &file);
     230
     231        void enable();
     232        void showFrame(uint16 frame);
     233
     234private:
     235        //byte *_data;
     236};
     237
     238Cursor_v2::Cursor_v2(Common::File &file) {
     239        _numFrames = file.readUint16LE();
     240        _width = file.readUint16LE();
     241        _height = file.readUint16LE();
     242
     243        debugC(1, kGroovieDebugCursor | kGroovieDebugAll, "Groovie::Cursor: width: %d, height: %d, frames:%d", _width, _height, _numFrames);
     244
     245        uint16 tmp16 = file.readUint16LE();
     246        debugC(5, kGroovieDebugCursor | kGroovieDebugAll, "hotspot x?: %d\n", tmp16);
     247        tmp16 = file.readUint16LE();
     248        debugC(5, kGroovieDebugCursor | kGroovieDebugAll, "hotspot y?: %d\n", tmp16);
     249        int loop2count = file.readUint16LE();
     250        debugC(5, kGroovieDebugCursor | kGroovieDebugAll, "loop2count?: %d\n", loop2count);
     251        for (int l = 0; l < loop2count; l++) {
     252                tmp16 = file.readUint16LE();
     253                debugC(5, kGroovieDebugCursor | kGroovieDebugAll, "loop2a: %d\n", tmp16);
     254                tmp16 = file.readUint16LE();
     255                debugC(5, kGroovieDebugCursor | kGroovieDebugAll, "loop2b: %d\n", tmp16);
     256        }
     257
     258        file.seek(0x20 * 3, SEEK_CUR);
     259
     260        for (int f = 0; f < _numFrames; f++) {
     261                uint32 tmp32 = file.readUint32LE();
     262                debugC(5, kGroovieDebugCursor | kGroovieDebugAll, "loop3: %d\n", tmp32);
     263
     264                //file.seek(tmp32, SEEK_CUR);
     265                byte *data = new byte[tmp32];
     266                file.read(data, tmp32);
     267                //Common::hexdump(data, tmp32);
     268                delete[] data;
     269        }
     270}
     271
     272void Cursor_v2::enable() {
     273}
     274
     275void Cursor_v2::showFrame(uint16 frame) {
     276}
     277
     278
     279// v2 Cursor Manager
     280
     281CursorMan_v2::CursorMan_v2(OSystem *system) :
     282        CursorMan(system) {
     283
     284        // Open the icons file
     285        Common::File iconsFile;
     286        if (!iconsFile.open("icons.ph")) {
     287                error("Groovie::Cursor: Couldn't open icons.ph");
     288                return;
     289        }
     290
     291        // Verify the signature
     292        uint32 tmp32 = iconsFile.readUint32LE();
     293        uint16 tmp16 = iconsFile.readUint16LE();
     294        if (tmp32 != 0x6e6f6369 || tmp16 != 1) {
     295                error("Groovie::Cursor: icons.ph signature failed: %04X %d", tmp32, tmp16);
     296                return;
     297        }
     298
     299        // Read the number of icons
     300        uint16 nicons = iconsFile.readUint16LE();
     301
     302        // Read the icons
     303        for (int i = 0; i < nicons; i++) {
     304                Cursor *s = new Cursor_v2(iconsFile);
     305                _cursors.push_back(s);
     306        }
     307
     308        iconsFile.close();
     309}
     310
     311CursorMan_v2::~CursorMan_v2() {
     312}
     313
     314} // End of Groovie namespace
  • engines/groovie/detection.cpp

     
     1/* ScummVM - Graphic Adventure Engine
     2 *
     3 * ScummVM is the legal property of its developers, whose names
     4 * are too numerous to list here. Please refer to the COPYRIGHT
     5 * file distributed with this source distribution.
     6 *
     7 * This program is free software; you can redistribute it and/or
     8 * modify it under the terms of the GNU General Public License
     9 * as published by the Free Software Foundation; either version 2
     10 * of the License, or (at your option) any later version.
     11
     12 * This program is distributed in the hope that it will be useful,
     13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15 * GNU General Public License for more details.
     16
     17 * You should have received a copy of the GNU General Public License
     18 * along with this program; if not, write to the Free Software
     19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
     20 *
     21 * $URL: https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/trunk/engines/groovie/detection.cpp $
     22 * $Id: detection.cpp 28132 2007-07-17 22:29:09Z aquadran $
     23 *
     24 */
     25
     26#include "common/savefile.h"
     27
     28#include "groovie/groovie.h"
     29
     30namespace Groovie {
     31
     32//#define GROOVIE_EXPERIMENTAL
     33
     34static const PlainGameDescriptor groovieGames[] = {
     35        // Games
     36        {"t7g", "The 7th Guest"},
     37
     38#ifdef GROOVIE_EXPERIMENTAL
     39        {"11h", "The 11th Hour: The sequel to The 7th Guest"},
     40        {"clandestiny", "Clandestiny"},
     41        {"unclehenry", "Uncle Henry's Playhouse"},
     42        {"tlc", "Tender Loving Care"},
     43
     44        // Extras
     45        {"making11h", "The Making of The 11th Hour"},
     46        {"clantrailer", "Clandestiny Trailer"},
     47#endif
     48
     49        // Unknown
     50        {"groovie", "Groovie engine game"},
     51        {0, 0}
     52};
     53
     54static const GroovieGameDescription gameDescriptions[] = {
     55
     56        // The 7th Guest DOS English
     57        {
     58                {
     59                        "t7g", "",
     60                        AD_ENTRY1s("script.grv", "d1b8033b40aa67c076039881eccce90d", 16659),
     61                        Common::EN_ANY, Common::kPlatformPC, Common::ADGF_NO_FLAGS
     62                },
     63                kGroovieT7G, 0
     64        },
     65
     66        // The 7th Guest Mac English
     67        {
     68                {
     69                        "t7g", "",
     70                        AD_ENTRY1s("script.grv", "6e30b54b1f3bc2262cdcf7961db2ae67", 17191),
     71                        Common::EN_ANY, Common::kPlatformMacintosh, Common::ADGF_NO_FLAGS
     72                },
     73                kGroovieT7G, 0
     74        },
     75
     76#ifdef GROOVIE_EXPERIMENTAL
     77        // The 11th Hour DOS English
     78        {
     79                {
     80                        "11h", "",
     81                        AD_ENTRY1s("disk.1", "5c0428cd3659fc7bbcd0aa16485ed5da", 227),
     82                        Common::EN_ANY, Common::kPlatformPC, Common::ADGF_NO_FLAGS
     83                },
     84                kGroovieV2, 1
     85        },
     86
     87        // The Making of The 11th Hour DOS English
     88        {
     89                {
     90                        "making11h", "",
     91                        AD_ENTRY1s("disk.1", "5c0428cd3659fc7bbcd0aa16485ed5da", 227),
     92                        Common::EN_ANY, Common::kPlatformPC, Common::ADGF_NO_FLAGS
     93                },
     94                kGroovieV2, 2
     95        },
     96
     97        // Clandestiny Trailer DOS English
     98        {
     99                {
     100                        "clantrailer", "",
     101                        AD_ENTRY1s("disk.1", "5c0428cd3659fc7bbcd0aa16485ed5da", 227),
     102                        Common::EN_ANY, Common::kPlatformPC, Common::ADGF_NO_FLAGS
     103                },
     104                kGroovieV2, 3
     105        },
     106
     107        // Clandestiny DOS English
     108        {
     109                {
     110                        "clandestiny", "",
     111                        AD_ENTRY1s("disk.1", "f79fc1515174540fef6a34132efc4c53", 76),
     112                        Common::EN_ANY, Common::kPlatformPC, Common::ADGF_NO_FLAGS
     113                },
     114                kGroovieV2, 1
     115        },
     116
     117        // Uncle Henry's Playhouse PC English
     118        {
     119                {
     120                        "unclehenry", "",
     121                        AD_ENTRY1s("disk.1", "0e1b1d3cecc4fc7efa62a968844d1f7a", 72),
     122                        Common::EN_ANY, Common::kPlatformPC, Common::ADGF_NO_FLAGS
     123                },
     124                kGroovieV2, 1
     125        },
     126
     127        // Tender Loving Care PC English
     128        {
     129                {
     130                        "tlc", "",
     131                        AD_ENTRY1s("disk.1", "32a1afa68478f1f9d2b25eeea427f2e3", 84),
     132                        Common::EN_ANY, Common::kPlatformPC, Common::ADGF_NO_FLAGS
     133                },
     134                kGroovieV2, 1
     135        },
     136#endif
     137
     138        {AD_TABLE_END_MARKER, kGroovieT7G, 0}
     139};
     140
     141static const Common::ADParams detectionParams = {
     142        // Pointer to ADGameDescription or its superset structure
     143        (const byte *)gameDescriptions,
     144        // Size of that superset structure
     145        sizeof(GroovieGameDescription),
     146        // Number of bytes to compute MD5 sum for
     147        5000,
     148        // List of all engine targets
     149        groovieGames,
     150        // Structure for autoupgrading obsolete targets
     151        0,
     152        // Name of single gameid (optional)
     153        0,
     154        // List of files for file-based fallback detection (optional)
     155        0,
     156        // Flags
     157        0
     158};
     159
     160
     161class GroovieMetaEngine : public Common::AdvancedMetaEngine {
     162public:
     163        GroovieMetaEngine() : Common::AdvancedMetaEngine(detectionParams) {}
     164
     165        const char *getName() const {
     166                return "Groovie Engine";
     167        }
     168
     169        const char *getCopyright() const {
     170                return "Groovie Engine (C) 1990-1996 Trilobyte";
     171        }
     172
     173        bool createInstance(OSystem *syst, Engine **engine, const Common::ADGameDescription *gd) const;
     174
     175        bool hasFeature(MetaEngineFeature f) const;
     176        SaveStateList listSaves(const char *target) const;
     177        void removeSaveState(const char *target, int slot) const;
     178};
     179
     180bool GroovieMetaEngine::createInstance(OSystem *syst, Engine **engine, const Common::ADGameDescription *gd) const {
     181        if (gd) {
     182                *engine = new GroovieEngine(syst, (GroovieGameDescription *)gd);
     183        }
     184        return gd != 0;
     185}
     186
     187bool GroovieMetaEngine::hasFeature(MetaEngineFeature f) const {
     188        return
     189                (f == kSupportsListSaves) ||
     190                (f == kSupportsLoadingDuringStartup) ||
     191                (f == kSupportsDeleteSave);
     192                //(f == kSavesSupportCreationDate)
     193}
     194
     195SaveStateList GroovieMetaEngine::listSaves(const char *target) const {
     196        Common::SaveFileManager *sfm = g_system->getSavefileManager();
     197        SaveStateList list;
     198
     199        // Get the list of savefiles
     200        Common::String pattern = Common::String(target) + ".00?";
     201        Common::StringList savefiles = sfm->listSavefiles(pattern.c_str());
     202
     203        // Sort the list of filenames
     204        sort(savefiles.begin(), savefiles.end());
     205
     206        // Fill the information for the existing savegames
     207        Common::StringList::iterator it = savefiles.begin();
     208        while (it != savefiles.end()) {
     209                int slot = it->lastChar() - '0';
     210                if (slot >= 0 && slot <= 9) {
     211                        Common::InSaveFile *file = sfm->openForLoading(it->c_str());
     212
     213                        // Read the savegame description
     214                        Common::String description;
     215                        unsigned char c = 1;
     216                        for (int i = 0; (c != 0) && (i < 15); i++) {
     217                                c = file->readByte();
     218                                switch (c) {
     219                                case 0:
     220                                        break;
     221                                case 16: // @
     222                                        c = ' ';
     223                                        break;
     224                                case 244: // $
     225                                        c = 0;
     226                                        break;
     227                                default:
     228                                        c += 0x30;
     229                                }
     230                                if (c != 0) {
     231                                        description += c;
     232                                }
     233                        }
     234                        delete file;
     235
     236                        list.push_back(SaveStateDescriptor(slot, description));
     237                }
     238                it++;
     239        }
     240
     241        return list;
     242}
     243
     244void GroovieMetaEngine::removeSaveState(const char *target, int slot) const {
     245        if (slot < 0 || slot > 9) {
     246                // Invalid slot, do nothing
     247                return;
     248        }
     249
     250        char extension[6];
     251        snprintf(extension, sizeof(extension), ".00%01d", slot);
     252
     253        Common::String filename = target;
     254        filename += extension;
     255
     256        g_system->getSavefileManager()->removeSavefile(filename.c_str());
     257}
     258
     259} // End of namespace Groovie
     260
     261#if PLUGIN_ENABLED_DYNAMIC(GROOVIE)
     262        REGISTER_PLUGIN_DYNAMIC(GROOVIE, PLUGIN_TYPE_ENGINE, Groovie::GroovieMetaEngine);
     263#else
     264        REGISTER_PLUGIN_STATIC(GROOVIE, PLUGIN_TYPE_ENGINE, Groovie::GroovieMetaEngine);
     265#endif
  • engines/groovie/groovie.h

     
     1/* ScummVM - Graphic Adventure Engine
     2 *
     3 * ScummVM is the legal property of its developers, whose names
     4 * are too numerous to list here. Please refer to the COPYRIGHT
     5 * file distributed with this source distribution.
     6 *
     7 * This program is free software; you can redistribute it and/or
     8 * modify it under the terms of the GNU General Public License
     9 * as published by the Free Software Foundation; either version 2
     10 * of the License, or (at your option) any later version.
     11
     12 * This program is distributed in the hope that it will be useful,
     13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15 * GNU General Public License for more details.
     16
     17 * You should have received a copy of the GNU General Public License
     18 * along with this program; if not, write to the Free Software
     19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
     20 *
     21 * $URL$
     22 * $Id$
     23 *
     24 */
     25
     26#ifndef GROOVIE_H
     27#define GROOVIE_H
     28
     29#include "common/advancedDetector.h"
     30#include "engines/engine.h"
     31#include "graphics/surface.h"
     32
     33#include "groovie/cursor.h"
     34#include "groovie/debug.h"
     35#include "groovie/graphics.h"
     36#include "groovie/player.h"
     37#include "groovie/resource.h"
     38#include "groovie/script.h"
     39
     40namespace Groovie {
     41
     42class MusicPlayer;
     43
     44enum kDebugLevels {
     45        kGroovieDebugAll = 1 << 0,
     46        kGroovieDebugVideo = 1 << 1,
     47        kGroovieDebugResource = 1 << 2,
     48        kGroovieDebugScript = 1 << 3,
     49        kGroovieDebugUnknown = 1 << 4,
     50        kGroovieDebugHotspots = 1 << 5,
     51        kGroovieDebugCursor = 1 << 6,
     52        kGroovieDebugMIDI = 1 << 7
     53                // the current limitation is 32 debug levels (1 << 31 is the last one)
     54};
     55
     56enum kEngineVersion {
     57        kGroovieT7G,
     58        kGroovieV2
     59};
     60
     61struct GroovieGameDescription {
     62        Common::ADGameDescription desc;
     63
     64        kEngineVersion version; // Version of the engine
     65        int indexEntry; // The index of the entry in disk.1 for V2 games
     66};
     67
     68class GroovieEngine : public Engine {
     69public:
     70        GroovieEngine(OSystem *syst, GroovieGameDescription *gd);
     71        ~GroovieEngine();
     72
     73protected:
     74        Common::Error init();
     75        Common::Error go();
     76
     77public:
     78        bool hasFeature(EngineFeature f) const;
     79
     80        bool canLoadGameStateCurrently();
     81        Common::Error loadGameState(int slot);
     82        void syncSoundSettings();
     83
     84        Debugger *getDebugger() { return _debugger; }
     85
     86        void waitForInput();
     87
     88        Script _script;
     89        ResMan *_resMan;
     90        CursorMan *_cursorMan;
     91        VideoPlayer *_videoPlayer;
     92        MusicPlayer *_musicPlayer;
     93        GraphicsMan *_graphicsMan;
     94
     95private:
     96        GroovieGameDescription *_gameDescription;
     97        Debugger *_debugger;
     98        bool _waitingForInput;
     99};
     100
     101} // End of namespace Groovie
     102
     103#endif // GROOVIE_H
  • engines/groovie/music.cpp

     
     1/* ScummVM - Graphic Adventure Engine
     2 *
     3 * ScummVM is the legal property of its developers, whose names
     4 * are too numerous to list here. Please refer to the COPYRIGHT
     5 * file distributed with this source distribution.
     6 *
     7 * This program is free software; you can redistribute it and/or
     8 * modify it under the terms of the GNU General Public License
     9 * as published by the Free Software Foundation; either version 2
     10 * of the License, or (at your option) any later version.
     11
     12 * This program is distributed in the hope that it will be useful,
     13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15 * GNU General Public License for more details.
     16
     17 * You should have received a copy of the GNU General Public License
     18 * along with this program; if not, write to the Free Software
     19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
     20 *
     21 * $URL$
     22 * $Id$
     23 *
     24 */
     25
     26#include "groovie/music.h"
     27#include "groovie/resource.h"
     28
     29namespace Groovie {
     30
     31MusicPlayer::MusicPlayer(GroovieEngine *vm) :
     32        _vm(vm), _midiParser(NULL), _data(NULL), _driver(NULL),
     33        _backgroundFileRef(0) {
     34        // Create the parser
     35        _midiParser = MidiParser::createParser_XMIDI();
     36
     37        // Create the driver
     38        int driver = detectMusicDriver(MDT_MIDI | MDT_ADLIB | MDT_PREFER_MIDI);
     39        _driver = createMidi(driver);
     40        _driver->open();
     41
     42        // Initialize the channel volumes
     43        for (int i = 0; i < 0x10; i++) {
     44                _chanVolumes[i] = 0x7F;
     45        }
     46
     47        // Set the parser's driver
     48        _midiParser->setMidiDriver(this);
     49
     50        // Set the timer rate
     51        _midiParser->setTimerRate(_driver->getBaseTempo());
     52}
     53
     54MusicPlayer::~MusicPlayer() {
     55        // Unload the parser
     56        unload();
     57        delete _midiParser;
     58
     59        // Unload the MIDI Driver
     60        _driver->close();
     61        delete _driver;
     62}
     63
     64void MusicPlayer::playSong(uint16 fileref) {
     65        // Play the referenced file once
     66        play(fileref, false);
     67}
     68
     69void MusicPlayer::setBackgroundSong(uint16 fileref) {
     70        _backgroundFileRef = fileref;
     71}
     72
     73void MusicPlayer::setUserVolume(uint16 volume) {
     74        // Save the new user volume
     75        _userVolume = volume;
     76        if (_userVolume > 0x100) _userVolume = 0x100;
     77
     78        // Apply it to all the channels
     79        for (int i = 0; i < 0x10; i++) {
     80                updateChanVolume(i);
     81        }
     82        //FIXME: AdlibPercussionChannel::controlChange() is empty
     83        //(can't set the volume for the percusion channel)
     84}
     85
     86void MusicPlayer::setGameVolume(uint16 volume, uint16 time) {
     87        //TODO: Implement volume fading
     88        debugC(5, kGroovieDebugMIDI | kGroovieDebugAll, "setting game volume: %d, %d\n", volume, time);
     89
     90        // Save the new game volume
     91        _gameVolume = volume;
     92        if (_gameVolume > 100) _gameVolume = 100;
     93
     94        // Apply it to all the channels
     95        for (int i = 0; i < 0x10; i++) {
     96                updateChanVolume(i);
     97        }
     98}
     99
     100void MusicPlayer::updateChanVolume(byte channel) {
     101        // Generate a MIDI Control change message for the volume
     102        uint32 b = 0x7B0;
     103
     104        // Specify the channel
     105        b |= (channel & 0xF);
     106
     107        // Scale by the user and game volumes
     108        uint32 val = (_chanVolumes[channel] * _userVolume * _gameVolume) / 0x100 / 100;
     109        val &= 0x7F;
     110
     111        // Send it to the driver
     112        _driver->send(b | (val << 16));
     113}
     114
     115bool MusicPlayer::play(uint16 fileref, bool loop) {
     116        // Unload the previous song
     117        unload();
     118
     119        // Set the looping option
     120        _midiParser->property(MidiParser::mpAutoLoop, loop);
     121
     122        // Load the new file
     123        return load(fileref);
     124}
     125
     126bool MusicPlayer::load(uint16 fileref) {
     127        // Open the song resource
     128        Common::SeekableReadStream *xmidiFile = _vm->_resMan->open(fileref);
     129        if (!xmidiFile) {
     130                error("Groovie::Music: Couldn't resource 0x%04X", fileref);
     131                return false;
     132        }
     133
     134        // Read the whole file to memory
     135        int length = xmidiFile->size();
     136        _data = new byte[length];
     137        xmidiFile->read(_data, length);
     138        delete xmidiFile;
     139
     140        // Start parsing the data
     141        if (!_midiParser->loadMusic(_data, length)) {
     142                error("Groovie::Music: Invalid XMI file");
     143                return false;
     144        }
     145
     146        // Activate the timer source
     147        _driver->setTimerCallback(_midiParser, MidiParser::timerCallback);
     148
     149        return true;
     150}
     151
     152void MusicPlayer::unload() {
     153        // Unload the parser
     154        _midiParser->unloadMusic();
     155
     156        // Unload the xmi file
     157        delete[] _data;
     158        _data = NULL;
     159}
     160
     161int MusicPlayer::open() {
     162        return 0;
     163}
     164
     165void MusicPlayer::close() {}
     166
     167void MusicPlayer::send(uint32 b) {
     168        if ((b & 0xFFF0) == 0x07B0) { // Volume change
     169                // Save the specific channel volume
     170                byte chan = b & 0xF;
     171                _chanVolumes[chan] = (b >> 16) & 0x7F;
     172
     173                // Send the updated value
     174                updateChanVolume(chan);
     175
     176                return;
     177        }
     178        _driver->send(b);
     179}
     180
     181void MusicPlayer::metaEvent(byte type, byte *data, uint16 length) {
     182        switch (type) {
     183        case 0x2F:
     184                // End of Track, play the background song
     185                if (_backgroundFileRef) {
     186                        play(_backgroundFileRef, true);
     187                }
     188                break;
     189        default:
     190                _driver->metaEvent(type, data, length);
     191                break;
     192        }
     193}
     194
     195void MusicPlayer::setTimerCallback(void *timer_param, Common::TimerManager::TimerProc timer_proc) {
     196        _driver->setTimerCallback(timer_param, timer_proc);
     197}
     198
     199uint32 MusicPlayer::getBaseTempo(void) {
     200        return _driver->getBaseTempo();
     201}
     202
     203MidiChannel *MusicPlayer::allocateChannel() {
     204        return _driver->allocateChannel();
     205}
     206
     207MidiChannel *MusicPlayer::getPercussionChannel() {
     208        return _driver->getPercussionChannel();
     209}
     210
     211} // End of Groovie namespace
  • engines/groovie/cursor.h

     
     1/* ScummVM - Graphic Adventure Engine
     2 *
     3 * ScummVM is the legal property of its developers, whose names
     4 * are too numerous to list here. Please refer to the COPYRIGHT
     5 * file distributed with this source distribution.
     6 *
     7 * This program is free software; you can redistribute it and/or
     8 * modify it under the terms of the GNU General Public License
     9 * as published by the Free Software Foundation; either version 2
     10 * of the License, or (at your option) any later version.
     11
     12 * This program is distributed in the hope that it will be useful,
     13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15 * GNU General Public License for more details.
     16
     17 * You should have received a copy of the GNU General Public License
     18 * along with this program; if not, write to the Free Software
     19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
     20 *
     21 * $URL$
     22 * $Id$
     23 *
     24 */
     25
     26#ifndef GROOVIE_CURSOR_H
     27#define GROOVIE_CURSOR_H
     28
     29#include "common/system.h"
     30#include "common/file.h"
     31
     32namespace Groovie {
     33
     34class Cursor {
     35public:
     36        virtual ~Cursor() {}
     37        uint16 getFrames() { return _numFrames; }
     38        virtual void enable() = 0;
     39        virtual void showFrame(uint16 frame) = 0;
     40
     41protected:
     42        uint16 _width;
     43        uint16 _height;
     44        uint16 _numFrames;
     45};
     46
     47class CursorMan {
     48public:
     49        CursorMan(OSystem *system);
     50        virtual ~CursorMan();
     51
     52        virtual void animate();
     53        virtual void setStyle(uint8 newStyle);
     54        virtual uint8 getStyle();
     55
     56protected:
     57        OSystem *_syst;
     58
     59        // Animation variables
     60        uint8 _lastFrame;
     61        uint32 _lastTime;
     62
     63        // Styles
     64        Common::Array<Cursor *> _cursors;
     65        uint8 _current;
     66        Cursor *_cursor;
     67};
     68
     69class CursorMan_t7g : public CursorMan {
     70public:
     71        CursorMan_t7g(OSystem *system);
     72        ~CursorMan_t7g();
     73
     74private:
     75        // Styles data
     76        static const uint _cursorImg[];
     77        static const uint _cursorPal[];
     78
     79        // Cursors data
     80        Common::Array<byte *> _images;
     81        Common::Array<byte *> _palettes;
     82
     83        // Loading functions
     84        byte *loadImage(Common::File &file);
     85        byte *loadPalette(Common::File &file);
     86};
     87
     88class CursorMan_v2 : public CursorMan {
     89public:
     90        CursorMan_v2(OSystem *system);
     91        ~CursorMan_v2();
     92};
     93
     94} // End of Groovie namespace
     95
     96#endif // GROOVIE_CURSOR_H
  • engines/groovie/music.h

     
     1/* ScummVM - Graphic Adventure Engine
     2 *
     3 * ScummVM is the legal property of its developers, whose names
     4 * are too numerous to list here. Please refer to the COPYRIGHT
     5 * file distributed with this source distribution.
     6 *
     7 * This program is free software; you can redistribute it and/or
     8 * modify it under the terms of the GNU General Public License
     9 * as published by the Free Software Foundation; either version 2
     10 * of the License, or (at your option) any later version.
     11
     12 * This program is distributed in the hope that it will be useful,
     13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15 * GNU General Public License for more details.
     16
     17 * You should have received a copy of the GNU General Public License
     18 * along with this program; if not, write to the Free Software
     19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
     20 *
     21 * $URL$
     22 * $Id$
     23 *
     24 */
     25
     26#ifndef GROOVIE_MUSIC_H
     27#define GROOVIE_MUSIC_H
     28
     29#include "groovie/groovie.h"
     30
     31#include "sound/mididrv.h"
     32#include "sound/midiparser.h"
     33
     34namespace Groovie {
     35
     36class MusicPlayer : public MidiDriver {
     37public:
     38        MusicPlayer(GroovieEngine *vm);
     39        ~MusicPlayer();
     40        void playSong(uint16 fileref);
     41        void setBackgroundSong(uint16 fileref);
     42
     43        // Volume
     44        void setUserVolume(uint16 volume);
     45        void setGameVolume(uint16 volume, uint16 time);
     46private:
     47        uint16 _userVolume;
     48        uint16 _gameVolume;
     49        byte _chanVolumes[0x10];
     50        void updateChanVolume(byte channel);
     51
     52public:
     53        // MidiDriver interface
     54        int open();
     55        void close();
     56        void send(uint32 b);
     57        void metaEvent(byte type, byte *data, uint16 length);
     58        void setTimerCallback(void *timer_param, Common::TimerManager::TimerProc timer_proc);
     59        uint32 getBaseTempo(void);
     60        MidiChannel *allocateChannel();
     61        MidiChannel *getPercussionChannel();
     62
     63private:
     64        GroovieEngine *_vm;
     65        byte *_data;
     66        MidiParser *_midiParser;
     67        MidiDriver *_driver;
     68
     69        uint16 _backgroundFileRef;
     70
     71        bool play(uint16 fileref, bool loop);
     72        bool load(uint16 fileref);
     73        void unload();
     74};
     75
     76} // End of Groovie namespace
     77
     78#endif // GROOVIE_MUSIC_H
  • engines/groovie/debug.cpp

     
     1/* ScummVM - Graphic Adventure Engine
     2 *
     3 * ScummVM is the legal property of its developers, whose names
     4 * are too numerous to list here. Please refer to the COPYRIGHT
     5 * file distributed with this source distribution.
     6 *
     7 * This program is free software; you can redistribute it and/or
     8 * modify it under the terms of the GNU General Public License
     9 * as published by the Free Software Foundation; either version 2
     10 * of the License, or (at your option) any later version.
     11
     12 * This program is distributed in the hope that it will be useful,
     13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15 * GNU General Public License for more details.
     16
     17 * You should have received a copy of the GNU General Public License
     18 * along with this program; if not, write to the Free Software
     19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
     20 *
     21 * $URL$
     22 * $Id$
     23 *
     24 */
     25
     26#include "groovie/debug.h"
     27#include "groovie/script.h"
     28#include "groovie/groovie.h"
     29
     30namespace Groovie {
     31
     32Debugger::Debugger(GroovieEngine *vm) :
     33        _vm (vm), _script(&_vm->_script), _syst(_vm->_system) {
     34
     35        // Register the debugger comands
     36        DCmd_Register("step", WRAP_METHOD(Debugger, cmd_step));
     37        DCmd_Register("go", WRAP_METHOD(Debugger, cmd_go));
     38        DCmd_Register("pc", WRAP_METHOD(Debugger, cmd_pc));
     39        DCmd_Register("fg", WRAP_METHOD(Debugger, cmd_fg));
     40        DCmd_Register("bg", WRAP_METHOD(Debugger, cmd_bg));
     41        DCmd_Register("mem", WRAP_METHOD(Debugger, cmd_mem));
     42        DCmd_Register("load", WRAP_METHOD(Debugger, cmd_loadgame));
     43        DCmd_Register("save", WRAP_METHOD(Debugger, cmd_savegame));
     44        DCmd_Register("playref", WRAP_METHOD(Debugger, cmd_playref));
     45        DCmd_Register("dumppal", WRAP_METHOD(Debugger, cmd_dumppal));
     46}
     47
     48Debugger::~Debugger() {
     49        Common::clearAllSpecialDebugLevels();
     50}
     51
     52int Debugger::getNumber(const char *arg) {
     53        return strtol(arg, (char **)NULL, 0);
     54}
     55
     56bool Debugger::cmd_step(int argc, const char **argv) {
     57        _script->step();
     58        return true;
     59}
     60
     61bool Debugger::cmd_go(int argc, const char **argv) {
     62        _script->step();
     63        return false;
     64}
     65
     66bool Debugger::cmd_fg(int argc, const char **argv) {
     67        _vm->_graphicsMan->updateScreen(&_vm->_graphicsMan->_foreground);
     68        return false;
     69}
     70
     71bool Debugger::cmd_bg(int argc, const char **argv) {
     72        _vm->_graphicsMan->updateScreen(&_vm->_graphicsMan->_background);
     73        return false;
     74}
     75
     76bool Debugger::cmd_pc(int argc, const char **argv) {
     77        if (argc == 2) {
     78                int val = getNumber(argv[1]);
     79                _script->_currentInstruction = val;
     80        }
     81        DebugPrintf("pc = 0x%04X\n", _script->_currentInstruction);
     82        return true;
     83}
     84
     85bool Debugger::cmd_mem(int argc, const char **argv) {
     86        if (argc >= 2) {
     87                int pos = getNumber(argv[1]);
     88                uint8 val;
     89                if (argc >= 3) {
     90                        // Set
     91                        val = getNumber(argv[2]);
     92                        _script->_variables[pos] = val;
     93                } else {
     94                        // Get
     95                        val = _script->_variables[pos];
     96                }
     97                DebugPrintf("mem[0x%04X] = 0x%02X\n", pos, val);
     98        } else {
     99                DebugPrintf("Syntax: mem <addr> [<val>]\n");
     100        }
     101        return true;
     102}
     103
     104bool Debugger::cmd_loadgame(int argc, const char **argv) {
     105        if (argc == 2) {
     106                int slot = getNumber(argv[1]);
     107                _script->loadgame(slot);
     108        } else {
     109                DebugPrintf("Syntax: load <slot>\n");
     110        }
     111        return true;
     112}
     113
     114bool Debugger::cmd_savegame(int argc, const char **argv) {
     115        if (argc == 2) {
     116                int slot = getNumber(argv[1]);
     117                _script->savegame(slot);
     118        } else {
     119                DebugPrintf("Syntax: save <slot>\n");
     120        }
     121        return true;
     122}
     123
     124bool Debugger::cmd_playref(int argc, const char **argv) {
     125        if (argc == 2) {
     126                int ref = getNumber(argv[1]);
     127                _script->playvideofromref(ref);
     128        } else {
     129                DebugPrintf("Syntax: playref <videorefnum>\n");
     130        }
     131        return true;
     132}
     133
     134bool Debugger::cmd_dumppal(int argc, const char **argv) {
     135        uint16 i;
     136        byte palettedump[256 * 4];
     137        _syst->grabPalette(palettedump, 0, 256);
     138
     139        for (i = 0; i < 256; i++) {
     140                DebugPrintf("%3d: %3d,%3d,%3d,%3d\n", i, palettedump[(i * 4)], palettedump[(i * 4) + 1], palettedump[(i * 4) + 2], palettedump[(i * 4) + 3]);
     141        }
     142        return true;
     143}
     144
     145} // End of Groovie namespace
  • engines/groovie/resource.cpp

     
     1/* ScummVM - Graphic Adventure Engine
     2 *
     3 * ScummVM is the legal property of its developers, whose names
     4 * are too numerous to list here. Please refer to the COPYRIGHT
     5 * file distributed with this source distribution.
     6 *
     7 * This program is free software; you can redistribute it and/or
     8 * modify it under the terms of the GNU General Public License
     9 * as published by the Free Software Foundation; either version 2
     10 * of the License, or (at your option) any later version.
     11
     12 * This program is distributed in the hope that it will be useful,
     13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15 * GNU General Public License for more details.
     16
     17 * You should have received a copy of the GNU General Public License
     18 * along with this program; if not, write to the Free Software
     19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
     20 *
     21 * $URL$
     22 * $Id$
     23 *
     24 */
     25
     26#include "groovie/groovie.h"
     27#include "groovie/resource.h"
     28
     29namespace Groovie {
     30
     31// ResMan
     32
     33Common::SeekableReadStream *ResMan::open(uint16 fileRef) {
     34        // Get the information about the resource
     35        ResInfo resInfo;
     36        if (!getResInfo(fileRef, resInfo)) {
     37                return NULL;
     38        }
     39
     40        // Do we know the name of the required GJD?
     41        if (resInfo.gjd >= _gjds.size()) {
     42                error("Groovie::Resource: Unknown GJD %d", resInfo.gjd);
     43                return NULL;
     44        }
     45
     46        debugC(1, kGroovieDebugResource | kGroovieDebugAll, "Groovie::Resource: Opening resource 0x%04X (%s, %d, %d)", fileRef, _gjds[resInfo.gjd].c_str(), resInfo.offset, resInfo.size);
     47
     48        // Does it exist?
     49        if (!Common::File::exists(_gjds[resInfo.gjd])) {
     50                error("Groovie::Resource: %s not found", _gjds[resInfo.gjd].c_str());
     51                return NULL;
     52        }
     53
     54        // Open the pack file
     55        Common::File *gjdFile = new Common::File();
     56        if (!gjdFile->open(_gjds[resInfo.gjd].c_str())) {
     57                delete gjdFile;
     58                error("Groovie::Resource: Couldn't open %s", _gjds[resInfo.gjd].c_str());
     59                return NULL;
     60        }
     61
     62        // Save the used gjd file (except xmi and gamwav)
     63        if (resInfo.gjd < 19) {
     64                _lastGjd = resInfo.gjd;
     65        }
     66
     67        // Returning the resource substream
     68        return new Common::SeekableSubReadStream(gjdFile, resInfo.offset, resInfo.offset + resInfo.size, true);
     69}
     70
     71
     72// ResMan_t7g
     73
     74static const char t7g_gjds[][0x15] = {"at", "b", "ch", "d", "dr", "fh", "ga", "hdisk", "htbd", "intro", "jhek", "k", "la", "li", "mb", "mc", "mu", "n", "p", "xmi", "gamwav"};
     75
     76ResMan_t7g::ResMan_t7g() {
     77        for (int i = 0; i < 0x15; i++) {
     78                // Prepare the filename
     79                Common::String filename = t7g_gjds[i];
     80                filename += ".gjd";
     81
     82                // Append it to the list of GJD files
     83                _gjds.push_back(filename);
     84        }
     85}
     86
     87uint16 ResMan_t7g::getRef(Common::String name, Common::String scriptname) {
     88        // Get the name of the RL file
     89        Common::String rlFileName(t7g_gjds[_lastGjd]);
     90        rlFileName += ".rl";
     91
     92        // Open the RL file
     93        Common::File rlFile;
     94        if (!rlFile.open(rlFileName)) {
     95                error("Groovie::Resource: Couldn't open %s", rlFileName.c_str());
     96                return false;
     97        }
     98
     99        uint16 resNum;
     100        bool found = false;
     101        for (resNum = 0; !found && !rlFile.ioFailed(); resNum++) {
     102                // Read the resource name
     103                char readname[12];
     104                rlFile.read(readname, 12);
     105
     106                // Test whether it's the resource we're searching
     107                Common::String resname(readname, 12);
     108                if (resname.hasPrefix(name.c_str())) {
     109                        debugC(2, kGroovieDebugResource | kGroovieDebugAll, "Groovie::Resource: Resource %12s matches %s", readname, name.c_str());
     110                        found = true;
     111                }
     112
     113                // Skip the rest of resource information
     114                rlFile.read(readname, 8);
     115        }
     116
     117        // Close the RL file
     118        rlFile.close();
     119
     120        // Verify we really found the resource
     121        if (!found) {
     122                error("Groovie::Resource: Couldn't find resource %s in %s", name.c_str(), rlFileName.c_str());
     123                return (uint16)-1;
     124        }
     125
     126        return (_lastGjd << 10) | (resNum - 1);
     127}
     128
     129bool ResMan_t7g::getResInfo(uint16 fileRef, ResInfo &resInfo) {
     130        // Calculate the GJD and the resource number
     131        resInfo.gjd = fileRef >> 10;
     132        uint16 resNum = fileRef & 0x3FF;
     133
     134        // Get the name of the RL file
     135        Common::String rlFileName(t7g_gjds[resInfo.gjd]);
     136        rlFileName += ".rl";
     137
     138        // Open the RL file
     139        Common::File rlFile;
     140        if (!rlFile.open(rlFileName)) {
     141                error("Groovie::Resource: Couldn't open %s", rlFileName.c_str());
     142                return false;
     143        }
     144
     145        // Seek to the position of the desired resource
     146        rlFile.seek(resNum * 20);
     147        if (rlFile.eos()) {
     148                rlFile.close();
     149                error("Groovie::Resource: Invalid resource number: 0x%04X (%s)", resNum, rlFileName.c_str());
     150                return false;
     151        }
     152
     153        // Read the resource name (just for debugging purposes)
     154        char resname[12];
     155        rlFile.read(resname, 12);
     156        debugC(2, kGroovieDebugResource | kGroovieDebugAll, "Groovie::Resource: Resource name: %12s", resname);
     157
     158        // Read the resource information
     159        resInfo.offset = rlFile.readUint32LE();
     160        resInfo.size = rlFile.readUint32LE();
     161
     162        // Close the resource RL file
     163        rlFile.close();
     164
     165        return true;
     166}
     167
     168
     169// ResMan_v2
     170
     171ResMan_v2::ResMan_v2() {
     172        Common::File indexfile;
     173
     174        // Open the GJD index file
     175        if (!indexfile.open("gjd.gjd")) {
     176                error("Groovie::Resource: Couldn't open gjd.gjd");
     177                return;
     178        }
     179
     180        Common::String line = indexfile.readLine();
     181        while (!indexfile.eos() && !line.empty()) {
     182                // Get the name before the space
     183                Common::String filename;
     184                for (const char *cur = line.c_str(); *cur != ' '; cur++) {
     185                        filename += *cur;
     186                }
     187
     188                // Append it to the list of GJD files
     189                if (!filename.empty()) {
     190                        _gjds.push_back(filename);
     191                }
     192
     193                // Read the next line
     194                line = indexfile.readLine();
     195        }
     196
     197        // Close the GJD index file
     198        indexfile.close();
     199}
     200
     201uint16 ResMan_v2::getRef(Common::String name, Common::String scriptname) {
     202        return 0;
     203}
     204
     205bool ResMan_v2::getResInfo(uint16 fileRef, ResInfo &resInfo) {
     206        // Open the RL file
     207        Common::File rlFile;
     208        if (!rlFile.open("dir.rl")) {
     209                error("Groovie::Resource: Couldn't open dir.rl");
     210                return false;
     211        }
     212
     213        // Seek to the position of the desired resource
     214        rlFile.seek(fileRef * 32);
     215        if (rlFile.eos()) {
     216                rlFile.close();
     217                error("Groovie::Resource: Invalid resource number: 0x%04X", fileRef);
     218                return false;
     219        }
     220
     221        // Read the resource information
     222        rlFile.readUint32LE(); // Unknown
     223        resInfo.offset = rlFile.readUint32LE();
     224        resInfo.size = rlFile.readUint32LE();
     225        resInfo.gjd = rlFile.readUint16LE();
     226
     227        // Read the resource name (just for debugging purposes)
     228        char resname[12];
     229        rlFile.read(resname, 12);
     230        debugC(2, kGroovieDebugResource | kGroovieDebugAll, "Groovie::Resource: Resource name: %12s", resname);
     231
     232        // 6 padding bytes? (it looks like they're always 0)
     233
     234        // Close the resource RL file
     235        rlFile.close();
     236
     237        return true;
     238}
     239
     240} // End of Groovie namespace
  • engines/groovie/debug.h

     
     1/* ScummVM - Graphic Adventure Engine
     2 *
     3 * ScummVM is the legal property of its developers, whose names
     4 * are too numerous to list here. Please refer to the COPYRIGHT
     5 * file distributed with this source distribution.
     6 *
     7 * This program is free software; you can redistribute it and/or
     8 * modify it under the terms of the GNU General Public License
     9 * as published by the Free Software Foundation; either version 2
     10 * of the License, or (at your option) any later version.
     11
     12 * This program is distributed in the hope that it will be useful,
     13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15 * GNU General Public License for more details.
     16
     17 * You should have received a copy of the GNU General Public License
     18 * along with this program; if not, write to the Free Software
     19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
     20 *
     21 * $URL$
     22 * $Id$
     23 *
     24 */
     25
     26#ifndef GROOVIE_DEBUG_H
     27#define GROOVIE_DEBUG_H
     28
     29#include "gui/debugger.h"
     30#include "engines/engine.h"
     31
     32namespace Groovie {
     33
     34class Script;
     35class GroovieEngine;
     36
     37class Debugger : public GUI::Debugger {
     38public:
     39        Debugger(GroovieEngine *vm);
     40        ~Debugger();
     41
     42private:
     43        GroovieEngine *_vm;
     44        Script *_script;
     45        OSystem *_syst;
     46
     47        int getNumber(const char *arg);
     48
     49        bool cmd_step(int argc, const char **argv);
     50        bool cmd_go(int argc, const char **argv);
     51        bool cmd_pc(int argc, const char **argv);
     52        bool cmd_bg(int argc, const char **argv);
     53        bool cmd_fg(int argc, const char **argv);
     54        bool cmd_mem(int argc, const char **argv);
     55        bool cmd_loadgame(int argc, const char **argv);
     56        bool cmd_savegame(int argc, const char **argv);
     57        bool cmd_playref(int argc, const char **argv);
     58        bool cmd_dumppal(int argc, const char **argv);
     59};
     60
     61} // End of Groovie namespace
     62
     63#endif // GROOVIE_DEBUG_H
  • engines/groovie/lzss.cpp

     
     1/* ScummVM - Graphic Adventure Engine
     2 *
     3 * ScummVM is the legal property of its developers, whose names
     4 * are too numerous to list here. Please refer to the COPYRIGHT
     5 * file distributed with this source distribution.
     6 *
     7 * This program is free software; you can redistribute it and/or
     8 * modify it under the terms of the GNU General Public License
     9 * as published by the Free Software Foundation; either version 2
     10 * of the License, or (at your option) any later version.
     11
     12 * This program is distributed in the hope that it will be useful,
     13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15 * GNU General Public License for more details.
     16
     17 * You should have received a copy of the GNU General Public License
     18 * along with this program; if not, write to the Free Software
     19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
     20 *
     21 * $URL$
     22 * $Id$
     23 *
     24 */
     25
     26#include "groovie/lzss.h"
     27
     28#define OUT_BUFF_SIZE 131072
     29#define COMP_THRESH 3 // Compression not attempted if string to be compressed is less than 3 long
     30
     31LzssReadStream::LzssReadStream(Common::ReadStream *indata, uint8 lengthmask, uint8 lengthbits) {
     32        /*
     33        TODO: Nasty hack. Make a buffer bigger than I'll ever need... probably.
     34        What should *really* happen is I should define a whole new type of stream
     35        that gets lzss decompressed on the fly
     36        */
     37        _outLzssBufData = (uint8 *)malloc(OUT_BUFF_SIZE);
     38        _size = decodeLZSS(indata, lengthmask, lengthbits);
     39        _pos = 0;
     40}
     41
     42LzssReadStream::~LzssReadStream() {
     43        free(_outLzssBufData);
     44}
     45
     46uint32 LzssReadStream::decodeLZSS(Common::ReadStream *in, uint8 lengthmask, uint8 lengthbits) {
     47        uint32 N = 1 << (16 - lengthbits); /* History buffer size */
     48        byte *histbuff = new byte[N]; /* History buffer */
     49        memset(histbuff, 0, N);
     50        uint32 outstreampos = 0;
     51        uint32 bufpos = 0;
     52
     53        while (!in->eos()) {
     54                byte flagbyte = in->readByte();
     55                for (uint32 i = 1; i <= 8; i++) {
     56                        if (!in->eos()) {
     57                                if ((flagbyte & 1) == 0) {
     58                                        uint32 offsetlen = in->readUint16LE();
     59                                        if (offsetlen == 0) {
     60                                                break;
     61                                        }
     62                                        uint32 length = (offsetlen & lengthmask) + COMP_THRESH;
     63                                        uint32 offset = (bufpos - (offsetlen >> lengthbits)) & (N - 1);
     64                                        for (uint32 j = 0; j < length; j++) {
     65                                                byte tempa = histbuff[(offset + j) & (N - 1)];
     66                                                _outLzssBufData[outstreampos++] = tempa;
     67                                                histbuff[bufpos] = tempa;
     68                                                bufpos = (bufpos + 1) & (N - 1);
     69                                        }
     70                                } else {
     71                                        byte tempa = in->readByte();
     72                                        if (in->eos()) {
     73                                                break;
     74                                        }
     75                                        _outLzssBufData[outstreampos++] = tempa;
     76                                        histbuff[bufpos] = tempa;
     77                                        bufpos = (bufpos + 1) & (N - 1);
     78                                }
     79                                flagbyte = flagbyte >> 1;
     80                        }
     81                }
     82        }
     83        delete[] histbuff;
     84        return outstreampos;
     85}
     86
     87bool LzssReadStream::eos() const {
     88        return _pos >= _size;
     89}
     90
     91uint32 LzssReadStream::read(void *buf, uint32 size) {
     92        if (size > _size - _pos)
     93                size = _size - _pos;
     94
     95        memcpy(buf, &_outLzssBufData[_pos], size);
     96        _pos += size;
     97
     98        return size;
     99}
  • engines/groovie/player.cpp

     
     1/* ScummVM - Graphic Adventure Engine
     2 *
     3 * ScummVM is the legal property of its developers, whose names
     4 * are too numerous to list here. Please refer to the COPYRIGHT
     5 * file distributed with this source distribution.
     6 *
     7 * This program is free software; you can redistribute it and/or
     8 * modify it under the terms of the GNU General Public License
     9 * as published by the Free Software Foundation; either version 2
     10 * of the License, or (at your option) any later version.
     11
     12 * This program is distributed in the hope that it will be useful,
     13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15 * GNU General Public License for more details.
     16
     17 * You should have received a copy of the GNU General Public License
     18 * along with this program; if not, write to the Free Software
     19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
     20 *
     21 * $URL$
     22 * $Id$
     23 *
     24 */
     25
     26#include "groovie/groovie.h"
     27#include "groovie/player.h"
     28
     29namespace Groovie {
     30
     31VideoPlayer::VideoPlayer(GroovieEngine *vm) :
     32        _vm(vm), _syst(vm->_system), _file(NULL), _audioStream(NULL) {
     33}
     34
     35bool VideoPlayer::load(Common::SeekableReadStream *file, uint16 flags) {
     36        _file = file;
     37        _flags = flags;
     38        _audioStream = NULL;
     39
     40        uint16 fps = loadInternal();
     41
     42        if (fps != 0) {
     43                _millisBetweenFrames = 1000 / fps;
     44                _begunPlaying = false;
     45                return true;
     46        } else {
     47                _file = NULL;
     48                return false;
     49        }
     50}
     51
     52bool VideoPlayer::playFrame() {
     53        bool end = true;
     54
     55        // Process the next frame while the file is open
     56        if (_file) {
     57                end = playFrameInternal();
     58        }
     59
     60        // The file has been completely processed
     61        if (end) {
     62                _file = NULL;
     63
     64                // Wait for pending audio
     65                if (_audioStream) {
     66                        if (_audioStream->endOfData()) {
     67                                // Mark the audio stream as finished (no more data will be appended)
     68                                _audioStream->finish();
     69                        } else {
     70                                // Don't end if there's still audio playing
     71                                end = false;
     72                        }
     73                }
     74        }
     75
     76        return end;
     77}
     78
     79void VideoPlayer::waitFrame() {
     80        uint32 currTime = _syst->getMillis();
     81        if (!_begunPlaying) {
     82                _begunPlaying = true;
     83                _lastFrameTime = currTime;
     84        } else {
     85                uint32 millisDiff = currTime - _lastFrameTime;
     86                if (millisDiff < _millisBetweenFrames) {
     87                        debugC(7, kGroovieDebugVideo | kGroovieDebugAll, "Groovie::Player: Delaying %d (currTime=%d, _lastFrameTime=%d, millisDiff=%d, _millisBetweenFrame=%d)",
     88                                        _millisBetweenFrames - millisDiff, currTime, _lastFrameTime, millisDiff, _millisBetweenFrames);
     89                        _syst->delayMillis(_millisBetweenFrames - millisDiff);
     90                        currTime = _syst->getMillis();
     91                        debugC(7, kGroovieDebugVideo | kGroovieDebugAll, "Groovie::Player: Finished delay at %d", currTime);
     92                }
     93                debugC(6, kGroovieDebugVideo | kGroovieDebugAll, "Groovie::Player: Frame displayed at %d (%f FPS)", currTime, 1000.0 / (currTime - _lastFrameTime));
     94                _lastFrameTime = currTime;
     95        }
     96}
     97
     98} // End of Groovie namespace
  • engines/groovie/resource.h

     
     1/* ScummVM - Graphic Adventure Engine
     2 *
     3 * ScummVM is the legal property of its developers, whose names
     4 * are too numerous to list here. Please refer to the COPYRIGHT
     5 * file distributed with this source distribution.
     6 *
     7 * This program is free software; you can redistribute it and/or
     8 * modify it under the terms of the GNU General Public License
     9 * as published by the Free Software Foundation; either version 2
     10 * of the License, or (at your option) any later version.
     11
     12 * This program is distributed in the hope that it will be useful,
     13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15 * GNU General Public License for more details.
     16
     17 * You should have received a copy of the GNU General Public License
     18 * along with this program; if not, write to the Free Software
     19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
     20 *
     21 * $URL$
     22 * $Id$
     23 *
     24 */
     25
     26#ifndef GROOVIE_RESOURCE_H
     27#define GROOVIE_RESOURCE_H
     28
     29namespace Groovie {
     30
     31struct ResInfo {
     32        uint16 gjd;
     33        uint32 offset;
     34        uint32 size;
     35};
     36
     37class ResMan {
     38public:
     39        virtual ~ResMan() {};
     40
     41        Common::SeekableReadStream *open(uint16 fileRef);
     42        virtual uint16 getRef(Common::String name, Common::String scriptname = "") = 0;
     43
     44protected:
     45        Common::Array<Common::String> _gjds;
     46        virtual bool getResInfo(uint16 fileRef, ResInfo &resInfo) = 0;
     47
     48        uint16 _lastGjd;
     49};
     50
     51class ResMan_t7g : public ResMan {
     52public:
     53        ResMan_t7g();
     54        ~ResMan_t7g() {};
     55
     56        uint16 getRef(Common::String name, Common::String scriptname);
     57        bool getResInfo(uint16 fileRef, ResInfo &resInfo);
     58};
     59
     60class ResMan_v2 : public ResMan {
     61public:
     62        ResMan_v2();
     63        ~ResMan_v2() {};
     64
     65        uint16 getRef(Common::String name, Common::String scriptname);
     66        bool getResInfo(uint16 fileRef, ResInfo &resInfo);
     67};
     68
     69} // End of Groovie namespace
     70
     71#endif // GROOVIE_RESOURCE_H
  • base/plugins.cpp

     
    108108                #if PLUGIN_ENABLED_STATIC(GOB)
    109109                LINK_PLUGIN(GOB)
    110110                #endif
     111                #if PLUGIN_ENABLED_STATIC(GROOVIE)
     112                LINK_PLUGIN(GROOVIE)
     113                #endif
    111114                #if PLUGIN_ENABLED_STATIC(IGOR)
    112115                LINK_PLUGIN(IGOR)
    113116                #endif