Ticket #8937: groovie2.patch
File groovie2.patch, 150.5 KB (added by , 16 years ago) |
---|
-
configure
89 89 add_engine cruise "Cinematique evo 2" no 90 90 add_engine drascula "Drascula: The Vampire Strikes Back" yes 91 91 add_engine gob "Gobli*ns" yes 92 add_engine groovie "Groovie" no 92 93 add_engine igor "Igor: Objective Uikokahonia" no 93 94 add_engine kyra "Legend of Kyrandia" yes 94 95 add_engine lure "Lure of the Temptress" yes -
engines/engines.mk
42 42 MODULES += engines/gob 43 43 endif 44 44 45 ifdef ENABLE_GROOVIE 46 DEFINES += -DENABLE_GROOVIE=$(ENABLE_GROOVIE) 47 MODULES += engines/groovie 48 endif 49 45 50 ifdef ENABLE_IGOR 46 51 DEFINES += -DENABLE_IGOR=$(ENABLE_IGOR) 47 52 MODULES += 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 28 class LzssReadStream : public Common::ReadStream { 29 private: 30 uint8 *_outLzssBufData; 31 uint32 _size; 32 uint32 _pos; 33 34 uint32 decodeLZSS(Common::ReadStream *in, uint8 lengthmask, uint8 lengthbits); 35 36 public: 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 29 namespace Groovie { 30 31 GraphicsMan::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 38 GraphicsMan::~GraphicsMan() { 39 // Free the game surfaces 40 _foreground.free(); 41 _background.free(); 42 } 43 44 void 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 80 void GraphicsMan::change() { 81 _changed = true; 82 } 83 84 void 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 100 void GraphicsMan::updateScreen(Graphics::Surface *source) { 101 _vm->_system->copyRectToScreen((byte *)source->getBasePtr(0, 0), 640, 0, 80, 640, 320); 102 change(); 103 } 104 105 bool GraphicsMan::isFading() { 106 return _fading; 107 } 108 109 void 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 127 void 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 138 void 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 31 namespace Groovie { 32 33 ROQPlayer::ROQPlayer(GroovieEngine *vm) : 34 VideoPlayer(vm) { 35 } 36 37 ROQPlayer::~ROQPlayer() { 38 } 39 40 uint16 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 57 bool 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 76 bool 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 92 bool 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 137 bool 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 169 bool 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 190 bool 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 199 int32 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 } 236 debugC(5, kGroovieDebugVideo | kGroovieDebugAll, "Should have ended at %d, and has ended at %d\n", ends, _file->pos()); 237 return true; 238 } 239 240 bool 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 284 bool 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 299 bool 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 342 bool 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 398 bool 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 35 namespace Groovie { 36 37 VDXPlayer::VDXPlayer(GroovieEngine *vm) : 38 VideoPlayer(vm), _origX(0), _origY(0), _flagOnePrev(false), 39 _fg(&_vm->_graphicsMan->_foreground), _bg(&_vm->_graphicsMan->_background) { 40 } 41 42 VDXPlayer::~VDXPlayer() { 43 //delete _audioStream; 44 } 45 46 void VDXPlayer::setOrigin(int16 x, int16 y) { 47 _origX = x; 48 _origY = y; 49 } 50 51 uint16 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 119 bool 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 180 static const uint16 vdxBlockMapLookup[] = { 181 0xc800, 0xec80, 0xfec8, 0xffec, 0xfffe, 0x3100, 0x7310, 0xf731, 0xff73, 0xfff7, 0x6c80, 0x36c8, 0x136c, 0x6310, 0xc631, 0x8c63, 182 0xf000, 0xff00, 0xfff0, 0x1111, 0x3333, 0x7777, 0x6666, 0xcccc, 0x0ff0, 0x00ff, 0xffcc, 0x0076, 0xff33, 0x0ee6, 0xccff, 0x6770, 183 0x33ff, 0x6ee0, 0x4800, 0x2480, 0x1248, 0x0024, 0x0012, 0x2100, 0x4210, 0x8421, 0x0042, 0x0084, 0xf888, 0x0044, 0x0032, 0x111f, 184 0x22e0, 0x4c00, 0x888f, 0x4470, 0x2300, 0xf111, 0x0e22, 0x00c4, 0xf33f, 0xfccf, 0xff99, 0x99ff, 0x4444, 0x2222, 0xccee, 0x7733, 185 0x00f8, 0x00f1, 0x00bb, 0x0cdd, 0x0f0f, 0x0f88, 0x13f1, 0x19b3, 0x1f80, 0x226f, 0x27ec, 0x3077, 0x3267, 0x37e4, 0x38e3, 0x3f90, 186 0x44cf, 0x4cd9, 0x4c99, 0x5555, 0x603f, 0x6077, 0x6237, 0x64c9, 0x64cd, 0x6cd9, 0x70ef, 0x0f00, 0x00f0, 0x0000, 0x4444, 0x2222 187 }; 188 189 void 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 319 void 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 404 void 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 415 void 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 442 void 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 479 void 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 491 void 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 507 void 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 32 namespace Groovie { 33 34 class GroovieEngine; 35 36 class VideoPlayer { 37 public: 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 45 protected: 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 56 private: 57 // Synchronization stuff 58 bool _begunPlaying; 59 uint16 _millisBetweenFrames; 60 uint32 _lastFrameTime; 61 62 protected: 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 39 namespace Groovie { 40 41 void 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 61 Script::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 95 Script::~Script() { 96 delete[] _code; 97 delete[] _savedCode; 98 99 delete _font; 100 delete _videoFile; 101 } 102 103 void Script::setDebugger(Debugger *debugger) { 104 _debugger = debugger; 105 } 106 107 bool 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 128 void 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 148 void 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 178 void Script::setMouseClick() { 179 _eventMouseClicked = true; 180 } 181 182 void Script::setKbdChar(uint8 c) { 183 _eventKbdChar = c; 184 } 185 186 bool Script::haveError() { 187 return _error; 188 } 189 190 void 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 204 uint8 Script::readScript8bits() { 205 uint8 data = _code[_currentInstruction]; 206 _currentInstruction++; 207 return data; 208 } 209 210 uint8 Script::readScriptVar() { 211 uint8 data = _variables[readScript8or16bits()]; 212 return data; 213 } 214 215 uint16 Script::readScript16bits() { 216 uint16 data = READ_LE_UINT16(_code + _currentInstruction); 217 _currentInstruction += 2; 218 return data; 219 } 220 221 uint32 Script::readScript32bits() { 222 uint32 data = READ_LE_UINT32(_code + _currentInstruction); 223 _currentInstruction += 4; 224 return data; 225 } 226 227 uint16 Script::readScript8or16bits() { 228 if (_firstbit) { 229 return readScript8bits(); 230 } else { 231 return readScript16bits(); 232 } 233 } 234 235 uint8 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 263 uint16 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 303 bool 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 336 void 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 346 void 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 358 void Script::o_invalid() { 359 error("Invalid opcode"); 360 } 361 362 void Script::o_nop() { 363 debugScript(1, true, "NOP"); 364 } 365 366 void Script::o_nop8() { 367 uint8 tmp = readScript8bits(); 368 debugScript(1, true, "NOP8: 0x%02X", tmp); 369 } 370 371 void Script::o_nop16() { 372 uint16 tmp = readScript16bits(); 373 debugScript(1, true, "NOP16: 0x%04X", tmp); 374 } 375 376 void Script::o_nop32() { 377 uint32 tmp = readScript32bits(); 378 debugScript(1, true, "NOP32: 0x%08X", tmp); 379 } 380 381 void Script::o_nop8or16() { 382 uint16 tmp = readScript8or16bits(); 383 debugScript(1, true, "NOP8OR16: 0x%04X", tmp); 384 } 385 386 void 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 396 void Script::o_bf9on() { // 0x03 397 debugScript(1, true, "BF9ON: bitflag 9 turned on"); 398 _bitflags |= 1 << 9; 399 } 400 401 void Script::o_palfadeout() { 402 debugScript(1, true, "PALFADEOUT"); 403 _vm->_graphicsMan->fadeOut(); 404 } 405 406 void Script::o_bf8on() { // 0x05 407 debugScript(1, true, "BF8ON: bitflag 8 turned on"); 408 _bitflags |= 1 << 8; 409 } 410 411 void Script::o_bf6on() { // 0x06 412 debugScript(1, true, "BF6ON: bitflag 6 turned on"); 413 _bitflags |= 1 << 6; 414 } 415 416 void Script::o_bf7on() { // 0x07 417 debugScript(1, true, "BF7ON: bitflag 7 turned on"); 418 _bitflags |= 1 << 7; 419 } 420 421 void Script::o_setbackgroundsong() { // 0x08 422 uint16 fileref = readScript16bits(); 423 debugScript(1, true, "SetBackgroundSong(0x%04X)", fileref); 424 _vm->_musicPlayer->setBackgroundSong(fileref); 425 } 426 427 void 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 466 bool 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 523 void Script::o_bf5on() { // 0x0A 524 debugScript(1, true, "BF5ON: bitflag 5 turned on"); 525 _bitflags |= 1 << 5; 526 } 527 528 void 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 547 void 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 568 void 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 583 void 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 593 void 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 603 void 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 613 void 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 624 void 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 670 void 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 679 void 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 688 void 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 699 void 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 716 void 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 729 void 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 737 void 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 764 void 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 781 void 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 808 void 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 819 void Script::o_inc() { 820 uint16 varnum = readScript8or16bits(); 821 822 debugScript(1, true, "INC var[0x%04X]", varnum); 823 824 _variables[varnum]++; 825 } 826 827 void Script::o_dec() { 828 uint16 varnum = readScript8or16bits(); 829 830 debugScript(1, true, "DEC var[0x%04X]", varnum); 831 832 _variables[varnum]--; 833 } 834 835 void 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 855 void 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 860 void 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 886 void 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 895 void 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 904 void 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 920 void 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 944 void Script::o_stopmidi() { 945 debugScript(1, true, "STOPMIDI (TODO)"); 946 } 947 948 void Script::o_endscript() { 949 debugScript(1, true, "END OF SCRIPT"); 950 _error = true; 951 } 952 953 void 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 963 void 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 973 void 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 983 void 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 992 void 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 1002 void 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 1010 void 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 1025 void 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 1037 void 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 1062 void Script::o_bf7off() { 1063 debugScript(1, true, "BF7OFF: bitflag 7 turned off"); 1064 _bitflags &= ~(1 << 7); 1065 } 1066 1067 void 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 1092 void 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 1113 void Script::o_restorestkpnt() { 1114 debugScript(1, true, "Restore stack pointer from saved (TODO)"); 1115 } 1116 1117 void 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 1136 void 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 1164 void 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 1222 void 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 1253 void Script::o_resetvars() { 1254 debugScript(1, true, "RESETVARS"); 1255 for (int i = 0; i < 0x100; i++) { 1256 _variables[i] = 0; 1257 } 1258 } 1259 1260 void 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 1269 void 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 1302 void 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 1314 void 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 1323 void 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 1350 void 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 1382 void Script::o_sethotspotright() { 1383 uint16 address = readScript16bits(); 1384 1385 debugScript(1, true, "SETHOTSPOTRIGHT @0x%04X", address); 1386 1387 _hotspotRightAction = address; 1388 } 1389 1390 void Script::o_sethotspotleft() { 1391 uint16 address = readScript16bits(); 1392 1393 debugScript(1, true, "SETHOTSPOTLEFT @0x%04X", address); 1394 1395 _hotspotLeftAction = address; 1396 } 1397 1398 void 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 1423 void 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 1435 void 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 1455 void 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 1463 void 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 1470 Script::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 29 namespace Groovie { 30 31 class GroovieEngine; 32 33 class GraphicsMan { 34 public: 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 51 private: 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 31 namespace Groovie { 32 33 class GroovieEngine; 34 35 struct ROQBlockHeader { 36 uint16 type; 37 uint32 size; 38 uint16 param; 39 }; 40 41 class ROQPlayer : public VideoPlayer { 42 public: 43 ROQPlayer(GroovieEngine *vm); 44 ~ROQPlayer(); 45 46 protected: 47 uint16 loadInternal(); 48 bool playFrameInternal(); 49 50 private: 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 31 namespace Groovie { 32 33 Font::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 45 Font::~Font() { 46 delete _sphinxfnt; 47 } 48 49 void 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 80 uint16 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 90 uint8 Font::letterwidth(char letter) { 91 uint16 offset = letteroffset(letter); 92 _sphinxfnt->seek(offset); 93 return _sphinxfnt->readByte(); 94 } 95 96 uint8 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 112 uint8 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 31 namespace Groovie { 32 33 class VDXPlayer : public VideoPlayer { 34 public: 35 VDXPlayer(GroovieEngine *vm); 36 ~VDXPlayer(); 37 void setOrigin(int16 x, int16 y); 38 39 protected: 40 uint16 loadInternal(); 41 bool playFrameInternal(); 42 43 private: 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 34 namespace Groovie { 35 36 class GroovieEngine; 37 38 class Script { 39 friend class Debugger; 40 41 public: 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 56 private: 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 35 namespace Groovie { 36 37 GroovieEngine::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 57 GroovieEngine::~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 67 Common::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 161 Common::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 245 bool GroovieEngine::hasFeature(EngineFeature f) const { 246 return 247 (f == kSupportsRTL) || 248 (f == kSupportsLoadingDuringRuntime); 249 } 250 251 void GroovieEngine::syncSoundSettings() { 252 _musicPlayer->setUserVolume(ConfMan.getInt("music_volume")); 253 _mixer->setVolumeForSoundType(Audio::Mixer::kPlainSoundType, ConfMan.getInt("speech_volume")); 254 } 255 256 bool GroovieEngine::canLoadGameStateCurrently() { 257 // TODO: verify the engine has been initialized 258 return true; 259 } 260 261 Common::Error GroovieEngine::loadGameState(int slot) { 262 _script.directGameLoad(slot); 263 264 // TODO: Use specific error codes 265 return Common::kNoError; 266 } 267 268 void GroovieEngine::waitForInput() { 269 _waitingForInput = true; 270 } 271 272 } // End of namespace Groovie -
engines/groovie/module.mk
1 MODULE := engines/groovie 2 3 MODULE_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 19 ifeq ($(ENABLE_GROOVIE), DYNAMIC_PLUGIN) 20 PLUGIN := 1 21 endif 22 23 # Include common rules 24 include $(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 32 namespace Groovie { 33 34 class Font { 35 public: 36 Font(OSystem *syst); 37 ~Font(); 38 void printstring(char *messagein); 39 40 private: 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 29 namespace Groovie { 30 31 // Cursor Manager 32 33 CursorMan::CursorMan(OSystem *system) : 34 _syst(system), _lastTime(0), _cursor(NULL) { 35 } 36 37 CursorMan::~CursorMan() { 38 // Delete the cursors 39 for (uint cursor = 0; cursor < _cursors.size(); cursor++) { 40 delete _cursors[cursor]; 41 } 42 } 43 44 uint8 CursorMan::getStyle() { 45 return _current; 46 } 47 48 void 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 62 void 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 77 class Cursor_t7g : public Cursor { 78 public: 79 Cursor_t7g(OSystem *system, uint8 *img, uint8 *pal); 80 81 void enable(); 82 void showFrame(uint16 frame); 83 84 private: 85 OSystem *_syst; 86 byte *_img; 87 byte *_pal; 88 }; 89 90 Cursor_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 105 void Cursor_t7g::enable() { 106 // Apply the palette 107 _syst->setCursorPalette(_pal, 0, 32); 108 } 109 110 void 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 120 static const uint16 cursorDataOffsets[NUM_IMGS] = { 121 0x0000, 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 129 const uint CursorMan_t7g::_cursorImg[NUM_STYLES] = {3, 5, 4, 3, 1, 0, 2, 6, 7, 8, 8}; 130 const uint CursorMan_t7g::_cursorPal[NUM_STYLES] = {0, 0, 0, 0, 2, 0, 1, 3, 5, 4, 6}; 131 132 CursorMan_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 163 CursorMan_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 175 byte *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 213 byte *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 227 class Cursor_v2 : public Cursor { 228 public: 229 Cursor_v2(Common::File &file); 230 231 void enable(); 232 void showFrame(uint16 frame); 233 234 private: 235 //byte *_data; 236 }; 237 238 Cursor_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 272 void Cursor_v2::enable() { 273 } 274 275 void Cursor_v2::showFrame(uint16 frame) { 276 } 277 278 279 // v2 Cursor Manager 280 281 CursorMan_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 311 CursorMan_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 30 namespace Groovie { 31 32 //#define GROOVIE_EXPERIMENTAL 33 34 static 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 54 static 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 141 static 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 161 class GroovieMetaEngine : public Common::AdvancedMetaEngine { 162 public: 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 180 bool 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 187 bool GroovieMetaEngine::hasFeature(MetaEngineFeature f) const { 188 return 189 (f == kSupportsListSaves) || 190 (f == kSupportsLoadingDuringStartup) || 191 (f == kSupportsDeleteSave); 192 //(f == kSavesSupportCreationDate) 193 } 194 195 SaveStateList 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 244 void 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 40 namespace Groovie { 41 42 class MusicPlayer; 43 44 enum 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 56 enum kEngineVersion { 57 kGroovieT7G, 58 kGroovieV2 59 }; 60 61 struct 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 68 class GroovieEngine : public Engine { 69 public: 70 GroovieEngine(OSystem *syst, GroovieGameDescription *gd); 71 ~GroovieEngine(); 72 73 protected: 74 Common::Error init(); 75 Common::Error go(); 76 77 public: 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 95 private: 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 29 namespace Groovie { 30 31 MusicPlayer::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 54 MusicPlayer::~MusicPlayer() { 55 // Unload the parser 56 unload(); 57 delete _midiParser; 58 59 // Unload the MIDI Driver 60 _driver->close(); 61 delete _driver; 62 } 63 64 void MusicPlayer::playSong(uint16 fileref) { 65 // Play the referenced file once 66 play(fileref, false); 67 } 68 69 void MusicPlayer::setBackgroundSong(uint16 fileref) { 70 _backgroundFileRef = fileref; 71 } 72 73 void 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 86 void 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 100 void 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 115 bool 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 126 bool 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 152 void MusicPlayer::unload() { 153 // Unload the parser 154 _midiParser->unloadMusic(); 155 156 // Unload the xmi file 157 delete[] _data; 158 _data = NULL; 159 } 160 161 int MusicPlayer::open() { 162 return 0; 163 } 164 165 void MusicPlayer::close() {} 166 167 void 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 181 void 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 195 void MusicPlayer::setTimerCallback(void *timer_param, Common::TimerManager::TimerProc timer_proc) { 196 _driver->setTimerCallback(timer_param, timer_proc); 197 } 198 199 uint32 MusicPlayer::getBaseTempo(void) { 200 return _driver->getBaseTempo(); 201 } 202 203 MidiChannel *MusicPlayer::allocateChannel() { 204 return _driver->allocateChannel(); 205 } 206 207 MidiChannel *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 32 namespace Groovie { 33 34 class Cursor { 35 public: 36 virtual ~Cursor() {} 37 uint16 getFrames() { return _numFrames; } 38 virtual void enable() = 0; 39 virtual void showFrame(uint16 frame) = 0; 40 41 protected: 42 uint16 _width; 43 uint16 _height; 44 uint16 _numFrames; 45 }; 46 47 class CursorMan { 48 public: 49 CursorMan(OSystem *system); 50 virtual ~CursorMan(); 51 52 virtual void animate(); 53 virtual void setStyle(uint8 newStyle); 54 virtual uint8 getStyle(); 55 56 protected: 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 69 class CursorMan_t7g : public CursorMan { 70 public: 71 CursorMan_t7g(OSystem *system); 72 ~CursorMan_t7g(); 73 74 private: 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 88 class CursorMan_v2 : public CursorMan { 89 public: 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 34 namespace Groovie { 35 36 class MusicPlayer : public MidiDriver { 37 public: 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); 46 private: 47 uint16 _userVolume; 48 uint16 _gameVolume; 49 byte _chanVolumes[0x10]; 50 void updateChanVolume(byte channel); 51 52 public: 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 63 private: 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 30 namespace Groovie { 31 32 Debugger::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 48 Debugger::~Debugger() { 49 Common::clearAllSpecialDebugLevels(); 50 } 51 52 int Debugger::getNumber(const char *arg) { 53 return strtol(arg, (char **)NULL, 0); 54 } 55 56 bool Debugger::cmd_step(int argc, const char **argv) { 57 _script->step(); 58 return true; 59 } 60 61 bool Debugger::cmd_go(int argc, const char **argv) { 62 _script->step(); 63 return false; 64 } 65 66 bool Debugger::cmd_fg(int argc, const char **argv) { 67 _vm->_graphicsMan->updateScreen(&_vm->_graphicsMan->_foreground); 68 return false; 69 } 70 71 bool Debugger::cmd_bg(int argc, const char **argv) { 72 _vm->_graphicsMan->updateScreen(&_vm->_graphicsMan->_background); 73 return false; 74 } 75 76 bool 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 85 bool 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 104 bool 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 114 bool 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 124 bool 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 134 bool 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 29 namespace Groovie { 30 31 // ResMan 32 33 Common::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 74 static 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 76 ResMan_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 87 uint16 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 129 bool 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 171 ResMan_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 201 uint16 ResMan_v2::getRef(Common::String name, Common::String scriptname) { 202 return 0; 203 } 204 205 bool 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 32 namespace Groovie { 33 34 class Script; 35 class GroovieEngine; 36 37 class Debugger : public GUI::Debugger { 38 public: 39 Debugger(GroovieEngine *vm); 40 ~Debugger(); 41 42 private: 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 31 LzssReadStream::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 42 LzssReadStream::~LzssReadStream() { 43 free(_outLzssBufData); 44 } 45 46 uint32 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 87 bool LzssReadStream::eos() const { 88 return _pos >= _size; 89 } 90 91 uint32 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 29 namespace Groovie { 30 31 VideoPlayer::VideoPlayer(GroovieEngine *vm) : 32 _vm(vm), _syst(vm->_system), _file(NULL), _audioStream(NULL) { 33 } 34 35 bool 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 52 bool 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 79 void 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 29 namespace Groovie { 30 31 struct ResInfo { 32 uint16 gjd; 33 uint32 offset; 34 uint32 size; 35 }; 36 37 class ResMan { 38 public: 39 virtual ~ResMan() {}; 40 41 Common::SeekableReadStream *open(uint16 fileRef); 42 virtual uint16 getRef(Common::String name, Common::String scriptname = "") = 0; 43 44 protected: 45 Common::Array<Common::String> _gjds; 46 virtual bool getResInfo(uint16 fileRef, ResInfo &resInfo) = 0; 47 48 uint16 _lastGjd; 49 }; 50 51 class ResMan_t7g : public ResMan { 52 public: 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 60 class ResMan_v2 : public ResMan { 61 public: 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
108 108 #if PLUGIN_ENABLED_STATIC(GOB) 109 109 LINK_PLUGIN(GOB) 110 110 #endif 111 #if PLUGIN_ENABLED_STATIC(GROOVIE) 112 LINK_PLUGIN(GROOVIE) 113 #endif 111 114 #if PLUGIN_ENABLED_STATIC(IGOR) 112 115 LINK_PLUGIN(IGOR) 113 116 #endif