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 */
22
23 #include "common/scummsys.h"
24 #include "mads/game.h"
25 #include "mads/mads.h"
26 #include "mads/menu_views.h"
27 #include "mads/resources.h"
28 #include "mads/scene.h"
29 #include "mads/screen.h"
30
31 namespace MADS {
32
MenuView(MADSEngine * vm)33 MenuView::MenuView(MADSEngine *vm) : FullScreenDialog(vm) {
34 _breakFlag = false;
35 _redrawFlag = true;
36 _palFlag = false;
37 }
38
show()39 void MenuView::show() {
40 Scene &scene = _vm->_game->_scene;
41 EventsManager &events = *_vm->_events;
42 _vm->_screenFade = SCREEN_FADE_FAST;
43
44 scene._spriteSlots.reset(true);
45 display();
46
47 events.setEventTarget(this);
48 events.hideCursor();
49
50 while (!_breakFlag && !_vm->shouldQuit()) {
51 if (_redrawFlag) {
52 scene._kernelMessages.update();
53
54 _vm->_game->_scene.drawElements(_vm->_game->_fx, _vm->_game->_fx);
55 _redrawFlag = false;
56 }
57
58 _vm->_events->waitForNextFrame();
59 _vm->_game->_fx = kTransitionNone;
60 doFrame();
61 }
62
63 events.setEventTarget(nullptr);
64 _vm->_sound->stop();
65 }
66
display()67 void MenuView::display() {
68 _vm->_palette->resetGamePalette(4, 8);
69
70 FullScreenDialog::display();
71 }
72
onEvent(Common::Event & event)73 bool MenuView::onEvent(Common::Event &event) {
74 if (event.type == Common::EVENT_KEYDOWN || event.type == Common::EVENT_LBUTTONDOWN) {
75 _breakFlag = true;
76 _vm->_dialogs->_pendingDialog = DIALOG_MAIN_MENU;
77 return true;
78 }
79
80 return false;
81 }
82
getResourceName()83 Common::String MenuView::getResourceName() {
84 Common::String s(_filename);
85 s.toLowercase();
86 while (s.contains('.'))
87 s.deleteLastChar();
88
89 return s;
90 }
91
92 /*------------------------------------------------------------------------*/
93
94 char TextView::_resourceName[100];
95 #define TEXTVIEW_LINE_SPACING 2
96 #define TEXT_ANIMATION_DELAY 100
97 #define TV_NUM_FADE_STEPS 40
98 #define TV_FADE_DELAY_MILLI 50
99
execute(MADSEngine * vm,const Common::String & resName)100 void TextView::execute(MADSEngine *vm, const Common::String &resName) {
101 assert(resName.size() < 100);
102 Common::strlcpy(_resourceName, resName.c_str(), sizeof(_resourceName));
103 vm->_dialogs->_pendingDialog = DIALOG_TEXTVIEW;
104 }
105
TextView(MADSEngine * vm)106 TextView::TextView(MADSEngine *vm) : MenuView(vm) {
107 _animating = false;
108 _panSpeed = 0;
109 _spareScreen = nullptr;
110 _scrollCount = 0;
111 _lineY = -1;
112 _scrollTimeout = 0;
113 _panCountdown = 0;
114 _translationX = 0;
115 _screenId = -1;
116
117 _font = _vm->_font->getFont(FONT_CONVERSATION);
118 _vm->_palette->resetGamePalette(4, 0);
119
120 load();
121 }
122
~TextView()123 TextView::~TextView() {
124 // Turn off palette cycling as well as any playing sound
125 Scene &scene = _vm->_game->_scene;
126 scene._cyclingActive = false;
127 _vm->_sound->stop();
128 }
129
load()130 void TextView::load() {
131 Common::String scriptName(_resourceName);
132 scriptName += ".txr";
133
134 _filename = scriptName;
135 if (!_script.open(scriptName))
136 error("Could not open resource %s", _resourceName);
137
138 processLines();
139 }
140
processLines()141 void TextView::processLines() {
142 if (_script.eos())
143 error("Attempted to read past end of response file");
144
145 while (!_script.eos()) {
146 // Read in the next line
147 _script.readLine(_currentLine, 79);
148 char *p = _currentLine + strlen(_currentLine) - 1;
149 if (*p == '\n')
150 *p = '\0';
151
152 // Commented out line, so go loop for another
153 if (_currentLine[0] == '#')
154 continue;
155
156 // Process the line
157 char *cStart = strchr(_currentLine, '[');
158 if (cStart) {
159 while (cStart) {
160 // Loop for possible multiple commands on one line
161 char *cEnd = strchr(_currentLine, ']');
162 if (!cEnd)
163 error("Unterminated command '%s' in response file", _currentLine);
164
165 *cEnd = '\0';
166 processCommand();
167
168 // Copy rest of line (if any) to start of buffer
169 Common::strlcpy(_currentLine, cEnd + 1, sizeof(_currentLine));
170
171 cStart = strchr(_currentLine, '[');
172 }
173
174 if (_currentLine[0]) {
175 processText();
176 break;
177 }
178
179 } else {
180 processText();
181 break;
182 }
183 }
184 }
185
processCommand()186 void TextView::processCommand() {
187 Scene &scene = _vm->_game->_scene;
188 Common::String scriptLine(_currentLine + 1);
189 scriptLine.toUppercase();
190 const char *paramP;
191 const char *commandStr = scriptLine.c_str();
192
193 if (!strncmp(commandStr, "BACKGROUND", 10)) {
194 // Set the background
195 paramP = commandStr + 10;
196 resetPalette();
197 int screenId = getParameter(¶mP);
198
199 SceneInfo *sceneInfo = SceneInfo::init(_vm);
200 sceneInfo->load(screenId, 0, "", 0, scene._depthSurface, scene._backgroundSurface);
201 scene._spriteSlots.fullRefresh();
202 _redrawFlag = true;
203
204 } else if (!strncmp(commandStr, "GO", 2)) {
205 _animating = true;
206
207 } else if (!strncmp(commandStr, "PAN", 3)) {
208 // Set panning values
209 paramP = commandStr + 3;
210 int panX = getParameter(¶mP);
211 int panY = getParameter(¶mP);
212 int panSpeed = getParameter(¶mP);
213
214 if ((panX != 0) || (panY != 0)) {
215 _pan = Common::Point(panX, panY);
216 _panSpeed = panSpeed;
217 }
218
219 } else if (!strncmp(commandStr, "DRIVER", 6)) {
220 // Set the driver to use
221 paramP = commandStr + 7;
222
223 if (!strncmp(paramP, "#SOUND.00", 9)) {
224 int driverNum = paramP[9] - '0';
225 _vm->_sound->init(driverNum);
226 }
227 } else if (!strncmp(commandStr, "SOUND", 5)) {
228 // Set sound number
229 paramP = commandStr + 5;
230 int soundId = getParameter(¶mP);
231 _vm->_sound->command(soundId);
232
233 } else if (!strncmp(commandStr, "COLOR", 5) && ((commandStr[5] == '0') ||
234 (commandStr[5] == '1'))) {
235 // Set the text colors
236 int index = commandStr[5] - '0';
237 paramP = commandStr + 6;
238
239 byte r = getParameter(¶mP);
240 byte g = getParameter(¶mP);
241 byte b = getParameter(¶mP);
242
243 _vm->_palette->setEntry(5 + index, r, g, b);
244
245 } else if (!strncmp(commandStr, "SPARE", 5)) {
246 // Sets a secondary background number that can be later switched in with a PAGE command
247 paramP = commandStr + 6;
248 int spareIndex = commandStr[5] - '0';
249 assert(spareIndex < 4);
250 int screenId = getParameter(¶mP);
251
252 // Load the spare background
253 SceneInfo *sceneInfo = SceneInfo::init(_vm);
254 sceneInfo->_width = MADS_SCREEN_WIDTH;
255 sceneInfo->_height = MADS_SCENE_HEIGHT;
256 _spareScreens[spareIndex].create(MADS_SCREEN_WIDTH, MADS_SCENE_HEIGHT);
257
258 sceneInfo->loadMadsV1Background(screenId, "", SCENEFLAG_TRANSLATE,
259 _spareScreens[spareIndex]);
260 delete sceneInfo;
261
262 } else if (!strncmp(commandStr, "PAGE", 4)) {
263 // Signals to change to a previous specified secondary background
264 paramP = commandStr + 4;
265 int spareIndex = getParameter(¶mP);
266
267 // Only allow background switches if one isn't currently in progress
268 if (!_spareScreen && _spareScreens[spareIndex].getPixels() != nullptr) {
269 _spareScreen = &_spareScreens[spareIndex];
270 _translationX = 0;
271 }
272
273 } else {
274 error("Unknown response command: '%s'", commandStr);
275 }
276 }
277
getParameter(const char ** paramP)278 int TextView::getParameter(const char **paramP) {
279 if ((**paramP != '=') && (**paramP != ','))
280 return 0;
281
282 int result = 0;
283 ++*paramP;
284 while ((**paramP >= '0') && (**paramP <= '9')) {
285 result = result * 10 + (**paramP - '0');
286 ++*paramP;
287 }
288
289 return result;
290 }
291
processText()292 void TextView::processText() {
293 int xStart;
294
295 if (!strcmp(_currentLine, "***")) {
296 // Special signifier for end of script
297 _scrollCount = _font->getHeight() * 13;
298 _lineY = -1;
299 return;
300 }
301
302 _lineY = 0;
303
304 // Lines are always centered, except if line contains a '@', in which case the
305 // '@' marks the position that must be horizontally centered
306 char *centerP = strchr(_currentLine, '@');
307 if (centerP) {
308 *centerP = '\0';
309 xStart = (MADS_SCREEN_WIDTH / 2) - _font->getWidth(_currentLine);
310
311 // Delete the @ character and shift back the remainder of the string
312 char *p = centerP + 1;
313 if (*p == ' ') ++p;
314 strcpy(centerP, p);
315
316 } else {
317 int lineWidth = _font->getWidth(_currentLine);
318 xStart = (MADS_SCREEN_WIDTH - lineWidth) / 2;
319 }
320
321 // Add the new line to the list of pending lines
322 TextLine tl;
323 tl._pos = Common::Point(xStart, MADS_SCENE_HEIGHT);
324 tl._line = _currentLine;
325 tl._textDisplayIndex = -1;
326 _textLines.push_back(tl);
327 }
328
display()329 void TextView::display() {
330 FullScreenDialog::display();
331 }
332
resetPalette()333 void TextView::resetPalette() {
334 _vm->_palette->resetGamePalette(8, 8);
335 _vm->_palette->setEntry(5, 0, 63, 63);
336 _vm->_palette->setEntry(6, 0, 45, 45);
337 }
338
doFrame()339 void TextView::doFrame() {
340 Scene &scene = _vm->_game->_scene;
341 if (!_animating)
342 return;
343
344 // Only update state if wait period has expired
345 uint32 currTime = g_system->getMillis();
346
347 // If a screen transition is in progress and it's time for another column, handle it
348 if (_spareScreen) {
349 const byte *srcP = (const byte *)_spareScreen->getBasePtr(_translationX, 0);
350 byte *bgP = (byte *)scene._backgroundSurface.getBasePtr(_translationX, 0);
351
352 Graphics::Surface dest = _vm->_screen->getSubArea(Common::Rect(_translationX, 0, _translationX + 1, 0));
353 byte *screenP = (byte *)dest.getBasePtr(0, 0);
354
355 for (int y = 0; y < MADS_SCENE_HEIGHT; ++y, srcP += MADS_SCREEN_WIDTH,
356 bgP += MADS_SCREEN_WIDTH, screenP += MADS_SCREEN_WIDTH) {
357 *bgP = *srcP;
358 *screenP = *srcP;
359 }
360
361 // Keep moving the column to copy to the right
362 if (++_translationX == MADS_SCREEN_WIDTH) {
363 // Surface transition is complete
364 _spareScreen = nullptr;
365 }
366 }
367
368 // Make sure it's time for an update
369 if (currTime < _scrollTimeout)
370 return;
371 _scrollTimeout = g_system->getMillis() + TEXT_ANIMATION_DELAY;
372 _redrawFlag = true;
373
374 // If any panning values are set, pan the background surface
375 if ((_pan.x != 0) || (_pan.y != 0)) {
376 if (_panCountdown > 0) {
377 --_panCountdown;
378 return;
379 }
380
381 // Handle horizontal panning
382 if (_pan.x != 0) {
383 byte *lineTemp = new byte[_pan.x];
384 for (int y = 0; y < MADS_SCENE_HEIGHT; ++y) {
385 byte *pixelsP = (byte *)scene._backgroundSurface.getBasePtr(0, y);
386
387 // Copy the first X pixels into temp buffer, move the rest of the line
388 // to the start of the line, and then move temp buffer pixels to end of line
389 Common::copy(pixelsP, pixelsP + _pan.x, lineTemp);
390 Common::copy(pixelsP + _pan.x, pixelsP + MADS_SCREEN_WIDTH, pixelsP);
391 Common::copy(lineTemp, lineTemp + _pan.x, pixelsP + MADS_SCREEN_WIDTH - _pan.x);
392 }
393
394 delete[] lineTemp;
395 }
396
397 // Handle vertical panning
398 if (_pan.y != 0) {
399 // Store the bottom Y lines into a temp buffer, move the rest of the lines down,
400 // and then copy the stored lines back to the top of the screen
401 byte *linesTemp = new byte[_pan.y * MADS_SCREEN_WIDTH];
402 byte *pixelsP = (byte *)scene._backgroundSurface.getBasePtr(0, MADS_SCENE_HEIGHT - _pan.y);
403 Common::copy(pixelsP, pixelsP + MADS_SCREEN_WIDTH * _pan.y, linesTemp);
404
405 for (int y = MADS_SCENE_HEIGHT - 1; y >= _pan.y; --y) {
406 byte *destP = (byte *)scene._backgroundSurface.getBasePtr(0, y);
407 byte *srcP = (byte *)scene._backgroundSurface.getBasePtr(0, y - _pan.y);
408 Common::copy(srcP, srcP + MADS_SCREEN_WIDTH, destP);
409 }
410
411 Common::copy(linesTemp, linesTemp + _pan.y * MADS_SCREEN_WIDTH,
412 (byte *)scene._backgroundSurface.getPixels());
413 delete[] linesTemp;
414 }
415
416 // Flag for a full screen refresh
417 scene._spriteSlots.fullRefresh();
418 }
419
420 // Scroll all active text lines up
421 for (int i = _textLines.size() - 1; i >= 0; --i) {
422 TextLine &tl = _textLines[i];
423 if (tl._textDisplayIndex != -1)
424 // Expire the text line that's already on-screen
425 scene._textDisplay.expire(tl._textDisplayIndex);
426
427 tl._pos.y--;
428 if (tl._pos.y + _font->getHeight() < 0) {
429 _textLines.remove_at(i);
430 } else {
431 tl._textDisplayIndex = scene._textDisplay.add(tl._pos.x, tl._pos.y,
432 0x605, -1, tl._line, _font);
433 }
434 }
435
436 if (_scrollCount > 0) {
437 // Handling final scrolling of text off of screen
438 if (--_scrollCount == 0) {
439 scriptDone();
440 return;
441 }
442 } else {
443 // Handling a text row
444 if (++_lineY == (_font->getHeight() + TEXTVIEW_LINE_SPACING))
445 processLines();
446 }
447 }
448
scriptDone()449 void TextView::scriptDone() {
450 _breakFlag = true;
451 _vm->_dialogs->_pendingDialog = DIALOG_MAIN_MENU;
452 }
453
454 /*------------------------------------------------------------------------*/
455
456 char AnimationView::_resourceName[100];
457
execute(MADSEngine * vm,const Common::String & resName)458 void AnimationView::execute(MADSEngine *vm, const Common::String &resName) {
459 assert(resName.size() < 100);
460 Common::strlcpy(_resourceName, resName.c_str(), sizeof(_resourceName));
461 vm->_dialogs->_pendingDialog = DIALOG_ANIMVIEW;
462 }
463
AnimationView(MADSEngine * vm)464 AnimationView::AnimationView(MADSEngine *vm) : MenuView(vm) {
465 _redrawFlag = false;
466
467 _soundDriverLoaded = false;
468 _previousUpdate = 0;
469 _screenId = -1;
470 _resetPalette = false;
471 _resyncMode = NEVER;
472 _v1 = 0;
473 _v2 = -1;
474 _resourceIndex = -1;
475 _currentAnimation = nullptr;
476 _sfx = 0;
477 _soundFlag = _bgLoadFlag = true;
478 _showWhiteBars = true;
479 _manualFrameNumber = 0;
480 _manualSpriteSet = nullptr;
481 _manualStartFrame = _manualEndFrame = 0;
482 _manualFrame2 = 0;
483 _animFrameNumber = 0;
484 _nextCyclingActive = false;
485 _sceneInfo = SceneInfo::init(_vm);
486 _scrollFrameCtr = 0;
487
488 load();
489 }
490
~AnimationView()491 AnimationView::~AnimationView() {
492 // Turn off palette cycling as well as any playing sound
493 Scene &scene = _vm->_game->_scene;
494 scene._cyclingActive = false;
495 _vm->_sound->stop();
496 _vm->_audio->stop();
497
498 // Delete data
499 delete _currentAnimation;
500 delete _sceneInfo;
501 }
502
load()503 void AnimationView::load() {
504 Common::String resName(_resourceName);
505 if (!resName.hasSuffix("."))
506 resName += ".res";
507
508 _filename = resName;
509 if (!_script.open(resName))
510 error("Could not open resource %s", resName.c_str());
511
512 processLines();
513 }
514
display()515 void AnimationView::display() {
516 Scene &scene = _vm->_game->_scene;
517 _vm->_palette->initPalette();
518 Common::fill(&_vm->_palette->_cyclingPalette[0], &_vm->_palette->_cyclingPalette[PALETTE_SIZE], 0);
519
520 _vm->_palette->resetGamePalette(1, 8);
521 scene._spriteSlots.reset();
522 scene._paletteCycles.clear();
523
524 MenuView::display();
525 }
526
onEvent(Common::Event & event)527 bool AnimationView::onEvent(Common::Event &event) {
528 // Wait for the Escape key or a mouse press
529 if (((event.type == Common::EVENT_KEYDOWN) && (event.kbd.keycode == Common::KEYCODE_ESCAPE)) ||
530 (event.type == Common::EVENT_LBUTTONUP)) {
531 scriptDone();
532 return true;
533 }
534
535 return false;
536 }
537
doFrame()538 void AnimationView::doFrame() {
539 Scene &scene = _vm->_game->_scene;
540
541 if (_resourceIndex == -1 || _currentAnimation->freeFlag()) {
542 if (++_resourceIndex == (int)_resources.size()) {
543 scriptDone();
544 } else {
545 scene._frameStartTime = 0;
546 scene._spriteSlots.clear();
547 loadNextResource();
548 }
549 } else if (_currentAnimation->getCurrentFrame() == 1) {
550 scene._cyclingActive = _nextCyclingActive;
551 }
552
553 if (_currentAnimation && (++_scrollFrameCtr >= _currentAnimation->_header._scrollTicks)) {
554 _scrollFrameCtr = 0;
555 scroll();
556 }
557
558 if (_currentAnimation) {
559 ++scene._frameStartTime;
560 _currentAnimation->update();
561 _redrawFlag = true;
562
563 if (_currentAnimation->freeFlag())
564 // We don't want the sprites removed after the last animation frame
565 scene._spriteSlots.clear();
566 }
567 }
568
loadNextResource()569 void AnimationView::loadNextResource() {
570 Scene &scene = _vm->_game->_scene;
571 Palette &palette = *_vm->_palette;
572 Screen &screen = *_vm->_screen;
573 ResourceEntry &resEntry = _resources[_resourceIndex];
574 Common::Array<PaletteCycle> paletteCycles;
575
576 if (resEntry._bgFlag)
577 palette.resetGamePalette(1, 8);
578
579 palette._mainPalette[253 * 3] = palette._mainPalette[253 * 3 + 1]
580 = palette._mainPalette[253 * 3 + 2] = 0xb4;
581 palette.setPalette(&palette._mainPalette[253 * 3], 253, 1);
582
583 // Free any previous messages
584 scene._kernelMessages.reset();
585
586 // Handle the bars at the top/bottom
587 if (resEntry._showWhiteBars) {
588 // For animations the screen has been clipped to the middle 156 rows.
589 // So although it's slightly messy, temporarily reset clip bounds
590 // so we can redraw the white lines
591 Common::Rect clipBounds = screen.getClipBounds();
592 screen.resetClipBounds();
593
594 screen.hLine(0, 20, MADS_SCREEN_WIDTH, 253);
595 screen.hLine(0, 179, MADS_SCREEN_WIDTH, 253);
596
597 screen.setClipBounds(clipBounds);
598 }
599
600 // Load the new animation
601 delete _currentAnimation;
602 _currentAnimation = Animation::init(_vm, &scene);
603 int flags = ANIMFLAG_ANIMVIEW | (resEntry._bgFlag ? ANIMFLAG_LOAD_BACKGROUND : 0);
604 _currentAnimation->load(scene._backgroundSurface, scene._depthSurface,
605 resEntry._resourceName, flags, &paletteCycles, _sceneInfo);
606
607 // Signal for a screen refresh
608 scene._spriteSlots.fullRefresh();
609
610 // If a sound driver has been specified, then load the correct one
611 if (!_currentAnimation->_header._soundName.empty()) {
612 const char *chP = strchr(_currentAnimation->_header._soundName.c_str(), '.');
613 assert(chP);
614
615 // Handle both Rex naming (xxx.009) and naming in later games (e.g. xxx.ph9)
616 int driverNum = atoi(chP + 3);
617 // HACK for Dragon
618 if (_currentAnimation->_header._soundName == "#SOUND.DRG")
619 driverNum = 9;
620 _vm->_sound->init(driverNum);
621 }
622
623 // Handle any manual setup
624 if (_currentAnimation->_header._manualFlag) {
625 _manualFrameNumber = _currentAnimation->_header._spritesIndex;
626 _manualSpriteSet = _currentAnimation->getSpriteSet(_manualFrameNumber);
627 }
628
629 // Set the sound data for the animation
630 _vm->_sound->setEnabled(resEntry._soundFlag);
631
632 Common::String dsrName = _currentAnimation->_header._dsrName;
633 if (!dsrName.empty())
634 _vm->_audio->setSoundGroup(dsrName);
635
636 // Start the new animation
637 _currentAnimation->startAnimation(0);
638
639 // Handle the palette and cycling palette
640 scene._cyclingActive = false;
641 Common::copy(&palette._mainPalette[0], &palette._mainPalette[PALETTE_SIZE],
642 &palette._cyclingPalette[0]);
643
644 _vm->_game->_fx = (ScreenTransition)resEntry._fx;
645 _nextCyclingActive = paletteCycles.size() > 0;
646 if (!_vm->_game->_fx) {
647 palette.setFullPalette(palette._mainPalette);
648 }
649
650 scene.initPaletteAnimation(paletteCycles, _nextCyclingActive && !_vm->_game->_fx);
651 }
652
scroll()653 void AnimationView::scroll() {
654 Scene &scene = _vm->_game->_scene;
655 Common::Point pt = _currentAnimation->_header._scrollPosition;
656
657 if (pt.x != 0) {
658 scene._backgroundSurface.scrollX(pt.x);
659 scene._spriteSlots.fullRefresh();
660 }
661
662 if (pt.y != 0) {
663 scene._backgroundSurface.scrollY(pt.y);
664 scene._spriteSlots.fullRefresh();
665 }
666 }
667
scriptDone()668 void AnimationView::scriptDone() {
669 _breakFlag = true;
670 _vm->_dialogs->_pendingDialog = DIALOG_MAIN_MENU;
671 }
672
processLines()673 void AnimationView::processLines() {
674 if (_script.eos()) {
675 // end of script, end animation
676 scriptDone();
677 return;
678 }
679
680 while (!_script.eos()) {
681 // Get in next line
682 _currentLine.clear();
683 char c;
684 while (!_script.eos() && (c = _script.readByte()) != '\n') {
685 if (c != '\r' && c != '\0')
686 _currentLine += c;
687 }
688
689 // Check for comment line
690 if (_currentLine.hasPrefix("#"))
691 continue;
692
693 // Process the line
694 while (!_currentLine.empty()) {
695 if (_currentLine.hasPrefix("-")) {
696 _currentLine.deleteChar(0);
697
698 processCommand();
699 } else {
700 // Get resource name
701 Common::String resName;
702 while (!_currentLine.empty() && (c = _currentLine[0]) != ' ') {
703 _currentLine.deleteChar(0);
704 resName += c;
705 }
706
707 // Add resource into list along with any set state information
708 _resources.push_back(ResourceEntry(resName, _sfx, _soundFlag,
709 _bgLoadFlag, _showWhiteBars));
710
711 // Fx resets between resource entries
712 _sfx = 0;
713 }
714
715 // Skip any spaces
716 while (_currentLine.hasPrefix(" "))
717 _currentLine.deleteChar(0);
718 }
719 }
720 }
721
processCommand()722 void AnimationView::processCommand() {
723 // Get the command character
724 char commandChar = toupper(_currentLine[0]);
725 _currentLine.deleteChar(0);
726
727 // Handle the command
728 switch (commandChar) {
729 case 'B':
730 _soundFlag = !_soundFlag;
731 break;
732 case 'H':
733 // -h[:ex] Disable EMS / XMS high memory support
734 if (_currentLine.hasPrefix(":"))
735 _currentLine.deleteChar(0);
736 while (_currentLine.hasPrefix("e") || _currentLine.hasPrefix("x"))
737 _currentLine.deleteChar(0);
738 break;
739 case 'O':
740 // -o:xxx Specify opening special effect
741 assert(_currentLine[0] == ':');
742 _currentLine.deleteChar(0);
743 _sfx = getParameter();
744 break;
745 case 'P':
746 // Switch to CONCAT mode, which is ignored anyway
747 break;
748 case 'R': {
749 // Resynch timer (always, beginning, never)
750 assert(_currentLine[0] == ':');
751 _currentLine.deleteChar(0);
752
753 char v = toupper(_currentLine[0]);
754 _currentLine.deleteChar(0);
755 if (v == 'N')
756 _resyncMode = NEVER;
757 else if (v == 'A')
758 _resyncMode = ALWAYS;
759 else if (v == 'B')
760 _resyncMode = BEGINNING;
761 else
762 error("Unknown parameter");
763 break;
764 }
765 case 'W':
766 // Switch white bars being visible
767 _showWhiteBars = !_showWhiteBars;
768 break;
769 case 'X':
770 // Exit after animation finishes. Ignore
771 break;
772 case 'D':
773 // Unimplemented and ignored in the original. Ignore as well
774 break;
775 case 'Y':
776 // Reset palette on startup
777 _resetPalette = true;
778 break;
779 default:
780 error("Unknown command char: '%c'", commandChar);
781 }
782 }
783
getParameter()784 int AnimationView::getParameter() {
785 int result = 0;
786
787 while (!_currentLine.empty()) {
788 char c = _currentLine[0];
789
790 if (c >= '0' && c <= '9') {
791 _currentLine.deleteChar(0);
792 result = result * 10 + (c - '0');
793 } else {
794 break;
795 }
796 }
797
798 return result;
799 }
800
checkResource(const Common::String & resourceName)801 void AnimationView::checkResource(const Common::String &resourceName) {
802 //bool hasSuffix = false;
803
804 }
805
scanResourceIndex(const Common::String & resourceName)806 int AnimationView::scanResourceIndex(const Common::String &resourceName) {
807 int foundIndex = -1;
808
809 if (_v1) {
810 const char *chP = strchr(resourceName.c_str(), '\\');
811 if (!chP) {
812 chP = strchr(resourceName.c_str(), '*');
813 }
814
815 Common::String resName = chP ? Common::String(chP + 1) : resourceName;
816
817 if (_v2 != 3) {
818 assert(_resIndex.size() == 0);
819 }
820
821 // Scan for the resource name
822 for (uint resIndex = 0; resIndex < _resIndex.size(); ++resIndex) {
823 ResIndexEntry &resEntry = _resIndex[resIndex];
824 if (resEntry._resourceName.compareToIgnoreCase(resourceName)) {
825 foundIndex = resIndex;
826 break;
827 }
828 }
829 }
830
831 if (foundIndex >= 0) {
832 // TODO
833 }
834 return -1;
835 }
836
837 } // End of namespace MADS
838