mirror of
https://github.com/libretro/scummvm.git
synced 2024-12-30 14:14:43 +00:00
877474cd32
For example in the credits scroll. Clipping was already done elsewhere, so this really is just a change in how soon the line is removed from the list of text to display.
794 lines
21 KiB
C++
794 lines
21 KiB
C++
/* ScummVM - Graphic Adventure Engine
|
|
*
|
|
* ScummVM is the legal property of its developers, whose names
|
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
|
* file distributed with this source distribution.
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* of the License, or (at your option) any later version.
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*
|
|
*/
|
|
|
|
#include "common/scummsys.h"
|
|
#include "mads/game.h"
|
|
#include "mads/mads.h"
|
|
#include "mads/menu_views.h"
|
|
#include "mads/resources.h"
|
|
#include "mads/scene.h"
|
|
#include "mads/screen.h"
|
|
|
|
namespace MADS {
|
|
|
|
MenuView::MenuView(MADSEngine *vm) : FullScreenDialog(vm) {
|
|
_breakFlag = false;
|
|
_redrawFlag = true;
|
|
_palFlag = false;
|
|
}
|
|
|
|
void MenuView::show() {
|
|
Scene &scene = _vm->_game->_scene;
|
|
EventsManager &events = *_vm->_events;
|
|
_vm->_screenFade = SCREEN_FADE_FAST;
|
|
|
|
scene._spriteSlots.reset(true);
|
|
display();
|
|
|
|
events.setEventTarget(this);
|
|
events.hideCursor();
|
|
|
|
while (!_breakFlag && !_vm->shouldQuit()) {
|
|
if (_redrawFlag) {
|
|
scene._kernelMessages.update();
|
|
|
|
_vm->_game->_scene.drawElements(_vm->_game->_fx, _vm->_game->_fx);
|
|
_redrawFlag = false;
|
|
}
|
|
|
|
_vm->_events->waitForNextFrame();
|
|
_vm->_game->_fx = kTransitionNone;
|
|
doFrame();
|
|
}
|
|
|
|
events.setEventTarget(nullptr);
|
|
_vm->_sound->stop();
|
|
}
|
|
|
|
void MenuView::display() {
|
|
_vm->_palette->resetGamePalette(4, 8);
|
|
|
|
FullScreenDialog::display();
|
|
}
|
|
|
|
bool MenuView::onEvent(Common::Event &event) {
|
|
if (event.type == Common::EVENT_KEYDOWN || event.type == Common::EVENT_LBUTTONDOWN) {
|
|
_breakFlag = true;
|
|
_vm->_dialogs->_pendingDialog = DIALOG_MAIN_MENU;
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
Common::String MenuView::getResourceName() {
|
|
Common::String s(_filename);
|
|
s.toLowercase();
|
|
while (s.contains('.'))
|
|
s.deleteLastChar();
|
|
|
|
return s;
|
|
}
|
|
|
|
/*------------------------------------------------------------------------*/
|
|
|
|
char TextView::_resourceName[100];
|
|
#define TEXTVIEW_LINE_SPACING 2
|
|
#define TEXT_ANIMATION_DELAY 100
|
|
#define TV_NUM_FADE_STEPS 40
|
|
#define TV_FADE_DELAY_MILLI 50
|
|
|
|
void TextView::execute(MADSEngine *vm, const Common::String &resName) {
|
|
assert(resName.size() < 100);
|
|
Common::strlcpy(_resourceName, resName.c_str(), sizeof(_resourceName));
|
|
vm->_dialogs->_pendingDialog = DIALOG_TEXTVIEW;
|
|
}
|
|
|
|
TextView::TextView(MADSEngine *vm) : MenuView(vm) {
|
|
_animating = false;
|
|
_panSpeed = 0;
|
|
_spareScreen = nullptr;
|
|
_scrollCount = 0;
|
|
_lineY = -1;
|
|
_scrollTimeout = 0;
|
|
_panCountdown = 0;
|
|
_translationX = 0;
|
|
_screenId = -1;
|
|
|
|
_font = _vm->_font->getFont(FONT_CONVERSATION);
|
|
_vm->_palette->resetGamePalette(4, 0);
|
|
|
|
load();
|
|
}
|
|
|
|
TextView::~TextView() {
|
|
// Turn off palette cycling as well as any playing sound
|
|
Scene &scene = _vm->_game->_scene;
|
|
scene._cyclingActive = false;
|
|
_vm->_sound->stop();
|
|
}
|
|
|
|
void TextView::load() {
|
|
Common::String scriptName(_resourceName);
|
|
scriptName += ".txr";
|
|
|
|
_filename = scriptName;
|
|
if (!_script.open(scriptName))
|
|
error("Could not open resource %s", _resourceName);
|
|
|
|
processLines();
|
|
}
|
|
|
|
void TextView::processLines() {
|
|
if (_script.eos())
|
|
error("Attempted to read past end of response file");
|
|
|
|
while (!_script.eos()) {
|
|
// Read in the next line
|
|
_script.readLine(_currentLine, 79);
|
|
char *p = _currentLine + strlen(_currentLine) - 1;
|
|
if (*p == '\n')
|
|
*p = '\0';
|
|
|
|
// Commented out line, so go loop for another
|
|
if (_currentLine[0] == '#')
|
|
continue;
|
|
|
|
// Process the line
|
|
char *cStart = strchr(_currentLine, '[');
|
|
if (cStart) {
|
|
while (cStart) {
|
|
// Loop for possible multiple commands on one line
|
|
char *cEnd = strchr(_currentLine, ']');
|
|
if (!cEnd)
|
|
error("Unterminated command '%s' in response file", _currentLine);
|
|
|
|
*cEnd = '\0';
|
|
processCommand();
|
|
|
|
// Copy rest of line (if any) to start of buffer
|
|
Common::strlcpy(_currentLine, cEnd + 1, sizeof(_currentLine));
|
|
|
|
cStart = strchr(_currentLine, '[');
|
|
}
|
|
|
|
if (_currentLine[0]) {
|
|
processText();
|
|
break;
|
|
}
|
|
|
|
} else {
|
|
processText();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void TextView::processCommand() {
|
|
Scene &scene = _vm->_game->_scene;
|
|
Common::String scriptLine(_currentLine + 1);
|
|
scriptLine.toUppercase();
|
|
const char *paramP;
|
|
const char *commandStr = scriptLine.c_str();
|
|
|
|
if (!strncmp(commandStr, "BACKGROUND", 10)) {
|
|
// Set the background
|
|
paramP = commandStr + 10;
|
|
resetPalette();
|
|
int screenId = getParameter(¶mP);
|
|
|
|
SceneInfo *sceneInfo = SceneInfo::init(_vm);
|
|
sceneInfo->load(screenId, 0, "", 0, scene._depthSurface, scene._backgroundSurface);
|
|
scene._spriteSlots.fullRefresh();
|
|
_redrawFlag = true;
|
|
|
|
} else if (!strncmp(commandStr, "GO", 2)) {
|
|
_animating = true;
|
|
|
|
} else if (!strncmp(commandStr, "PAN", 3)) {
|
|
// Set panning values
|
|
paramP = commandStr + 3;
|
|
int panX = getParameter(¶mP);
|
|
int panY = getParameter(¶mP);
|
|
int panSpeed = getParameter(¶mP);
|
|
|
|
if ((panX != 0) || (panY != 0)) {
|
|
_pan = Common::Point(panX, panY);
|
|
_panSpeed = panSpeed;
|
|
}
|
|
|
|
} else if (!strncmp(commandStr, "DRIVER", 6)) {
|
|
// Set the driver to use
|
|
paramP = commandStr + 7;
|
|
|
|
if (!strncmp(paramP, "#SOUND.00", 9)) {
|
|
int driverNum = paramP[9] - '0';
|
|
_vm->_sound->init(driverNum);
|
|
}
|
|
} else if (!strncmp(commandStr, "SOUND", 5)) {
|
|
// Set sound number
|
|
paramP = commandStr + 5;
|
|
int soundId = getParameter(¶mP);
|
|
_vm->_sound->command(soundId);
|
|
|
|
} else if (!strncmp(commandStr, "COLOR", 5) && ((commandStr[5] == '0') ||
|
|
(commandStr[5] == '1'))) {
|
|
// Set the text colors
|
|
int index = commandStr[5] - '0';
|
|
paramP = commandStr + 6;
|
|
|
|
byte r = getParameter(¶mP);
|
|
byte g = getParameter(¶mP);
|
|
byte b = getParameter(¶mP);
|
|
|
|
_vm->_palette->setEntry(5 + index, r, g, b);
|
|
|
|
} else if (!strncmp(commandStr, "SPARE", 5)) {
|
|
// Sets a secondary background number that can be later switched in with a PAGE command
|
|
paramP = commandStr + 6;
|
|
int spareIndex = commandStr[5] - '0';
|
|
assert(spareIndex < 4);
|
|
int screenId = getParameter(¶mP);
|
|
|
|
// Load the spare background
|
|
SceneInfo *sceneInfo = SceneInfo::init(_vm);
|
|
sceneInfo->_width = MADS_SCREEN_WIDTH;
|
|
sceneInfo->_height = MADS_SCENE_HEIGHT;
|
|
_spareScreens[spareIndex].setSize(MADS_SCREEN_WIDTH, MADS_SCENE_HEIGHT);
|
|
sceneInfo->loadMadsV1Background(screenId, "", SCENEFLAG_TRANSLATE,
|
|
_spareScreens[spareIndex]);
|
|
delete sceneInfo;
|
|
|
|
} else if (!strncmp(commandStr, "PAGE", 4)) {
|
|
// Signals to change to a previous specified secondary background
|
|
paramP = commandStr + 4;
|
|
int spareIndex = getParameter(¶mP);
|
|
|
|
// Only allow background switches if one isn't currently in progress
|
|
if (!_spareScreen && _spareScreens[spareIndex].getPixels() != nullptr) {
|
|
_spareScreen = &_spareScreens[spareIndex];
|
|
_translationX = 0;
|
|
}
|
|
|
|
} else {
|
|
error("Unknown response command: '%s'", commandStr);
|
|
}
|
|
}
|
|
|
|
int TextView::getParameter(const char **paramP) {
|
|
if ((**paramP != '=') && (**paramP != ','))
|
|
return 0;
|
|
|
|
int result = 0;
|
|
++*paramP;
|
|
while ((**paramP >= '0') && (**paramP <= '9')) {
|
|
result = result * 10 + (**paramP - '0');
|
|
++*paramP;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
void TextView::processText() {
|
|
int xStart;
|
|
|
|
if (!strcmp(_currentLine, "***")) {
|
|
// Special signifier for end of script
|
|
_scrollCount = _font->getHeight() * 13;
|
|
_lineY = -1;
|
|
return;
|
|
}
|
|
|
|
_lineY = 0;
|
|
|
|
// Lines are always centered, except if line contains a '@', in which case the
|
|
// '@' marks the position that must be horizontally centered
|
|
char *centerP = strchr(_currentLine, '@');
|
|
if (centerP) {
|
|
*centerP = '\0';
|
|
xStart = (MADS_SCREEN_WIDTH / 2) - _font->getWidth(_currentLine);
|
|
|
|
// Delete the @ character and shift back the remainder of the string
|
|
char *p = centerP + 1;
|
|
if (*p == ' ') ++p;
|
|
strcpy(centerP, p);
|
|
|
|
} else {
|
|
int lineWidth = _font->getWidth(_currentLine);
|
|
xStart = (MADS_SCREEN_WIDTH - lineWidth) / 2;
|
|
}
|
|
|
|
// Add the new line to the list of pending lines
|
|
TextLine tl;
|
|
tl._pos = Common::Point(xStart, MADS_SCENE_HEIGHT);
|
|
tl._line = _currentLine;
|
|
tl._textDisplayIndex = -1;
|
|
_textLines.push_back(tl);
|
|
}
|
|
|
|
void TextView::display() {
|
|
FullScreenDialog::display();
|
|
}
|
|
|
|
void TextView::resetPalette() {
|
|
_vm->_palette->resetGamePalette(8, 8);
|
|
_vm->_palette->setEntry(5, 0, 63, 63);
|
|
_vm->_palette->setEntry(6, 0, 45, 45);
|
|
}
|
|
|
|
void TextView::doFrame() {
|
|
Scene &scene = _vm->_game->_scene;
|
|
if (!_animating)
|
|
return;
|
|
|
|
// Only update state if wait period has expired
|
|
uint32 currTime = g_system->getMillis();
|
|
|
|
// If a screen transition is in progress and it's time for another column, handle it
|
|
if (_spareScreen) {
|
|
byte *srcP = _spareScreen->getBasePtr(_translationX, 0);
|
|
byte *bgP = scene._backgroundSurface.getBasePtr(_translationX, 0);
|
|
byte *screenP = (byte *)_vm->_screen.getBasePtr(_translationX, 0);
|
|
|
|
for (int y = 0; y < MADS_SCENE_HEIGHT; ++y, srcP += MADS_SCREEN_WIDTH,
|
|
bgP += MADS_SCREEN_WIDTH, screenP += MADS_SCREEN_WIDTH) {
|
|
*bgP = *srcP;
|
|
*screenP = *srcP;
|
|
}
|
|
|
|
// Flag the column of the screen is modified
|
|
_vm->_screen.copyRectToScreen(Common::Rect(_translationX, 0,
|
|
_translationX + 1, MADS_SCENE_HEIGHT));
|
|
|
|
// Keep moving the column to copy to the right
|
|
if (++_translationX == MADS_SCREEN_WIDTH) {
|
|
// Surface transition is complete
|
|
_spareScreen = nullptr;
|
|
}
|
|
}
|
|
|
|
// Make sure it's time for an update
|
|
if (currTime < _scrollTimeout)
|
|
return;
|
|
_scrollTimeout = g_system->getMillis() + TEXT_ANIMATION_DELAY;
|
|
_redrawFlag = true;
|
|
|
|
// If any panning values are set, pan the background surface
|
|
if ((_pan.x != 0) || (_pan.y != 0)) {
|
|
if (_panCountdown > 0) {
|
|
--_panCountdown;
|
|
return;
|
|
}
|
|
|
|
// Handle horizontal panning
|
|
if (_pan.x != 0) {
|
|
byte *lineTemp = new byte[_pan.x];
|
|
for (int y = 0; y < MADS_SCENE_HEIGHT; ++y) {
|
|
byte *pixelsP = (byte *)scene._backgroundSurface.getBasePtr(0, y);
|
|
|
|
// Copy the first X pixels into temp buffer, move the rest of the line
|
|
// to the start of the line, and then move temp buffer pixels to end of line
|
|
Common::copy(pixelsP, pixelsP + _pan.x, lineTemp);
|
|
Common::copy(pixelsP + _pan.x, pixelsP + MADS_SCREEN_WIDTH, pixelsP);
|
|
Common::copy(lineTemp, lineTemp + _pan.x, pixelsP + MADS_SCREEN_WIDTH - _pan.x);
|
|
}
|
|
|
|
delete[] lineTemp;
|
|
}
|
|
|
|
// Handle vertical panning
|
|
if (_pan.y != 0) {
|
|
// Store the bottom Y lines into a temp buffer, move the rest of the lines down,
|
|
// and then copy the stored lines back to the top of the screen
|
|
byte *linesTemp = new byte[_pan.y * MADS_SCREEN_WIDTH];
|
|
byte *pixelsP = (byte *)scene._backgroundSurface.getBasePtr(0, MADS_SCENE_HEIGHT - _pan.y);
|
|
Common::copy(pixelsP, pixelsP + MADS_SCREEN_WIDTH * _pan.y, linesTemp);
|
|
|
|
for (int y = MADS_SCENE_HEIGHT - 1; y >= _pan.y; --y) {
|
|
byte *destP = (byte *)scene._backgroundSurface.getBasePtr(0, y);
|
|
byte *srcP = (byte *)scene._backgroundSurface.getBasePtr(0, y - _pan.y);
|
|
Common::copy(srcP, srcP + MADS_SCREEN_WIDTH, destP);
|
|
}
|
|
|
|
Common::copy(linesTemp, linesTemp + _pan.y * MADS_SCREEN_WIDTH,
|
|
(byte *)scene._backgroundSurface.getPixels());
|
|
delete[] linesTemp;
|
|
}
|
|
|
|
// Flag for a full screen refresh
|
|
scene._spriteSlots.fullRefresh();
|
|
}
|
|
|
|
// Scroll all active text lines up
|
|
for (int i = _textLines.size() - 1; i >= 0; --i) {
|
|
TextLine &tl = _textLines[i];
|
|
if (tl._textDisplayIndex != -1)
|
|
// Expire the text line that's already on-screen
|
|
scene._textDisplay.expire(tl._textDisplayIndex);
|
|
|
|
tl._pos.y--;
|
|
if (tl._pos.y + _font->getHeight() < 0) {
|
|
_textLines.remove_at(i);
|
|
} else {
|
|
tl._textDisplayIndex = scene._textDisplay.add(tl._pos.x, tl._pos.y,
|
|
0x605, -1, tl._line, _font);
|
|
}
|
|
}
|
|
|
|
if (_scrollCount > 0) {
|
|
// Handling final scrolling of text off of screen
|
|
if (--_scrollCount == 0) {
|
|
scriptDone();
|
|
return;
|
|
}
|
|
} else {
|
|
// Handling a text row
|
|
if (++_lineY == (_font->getHeight() + TEXTVIEW_LINE_SPACING))
|
|
processLines();
|
|
}
|
|
}
|
|
|
|
void TextView::scriptDone() {
|
|
_breakFlag = true;
|
|
_vm->_dialogs->_pendingDialog = DIALOG_MAIN_MENU;
|
|
}
|
|
|
|
/*------------------------------------------------------------------------*/
|
|
|
|
char AnimationView::_resourceName[100];
|
|
|
|
void AnimationView::execute(MADSEngine *vm, const Common::String &resName) {
|
|
assert(resName.size() < 100);
|
|
Common::strlcpy(_resourceName, resName.c_str(), sizeof(_resourceName));
|
|
vm->_dialogs->_pendingDialog = DIALOG_ANIMVIEW;
|
|
}
|
|
|
|
AnimationView::AnimationView(MADSEngine *vm) : MenuView(vm) {
|
|
_redrawFlag = false;
|
|
|
|
_soundDriverLoaded = false;
|
|
_previousUpdate = 0;
|
|
_screenId = -1;
|
|
_resetPalette = false;
|
|
_resyncMode = NEVER;
|
|
_v1 = 0;
|
|
_v2 = -1;
|
|
_resourceIndex = -1;
|
|
_currentAnimation = nullptr;
|
|
_sfx = 0;
|
|
_soundFlag = _bgLoadFlag = true;
|
|
_showWhiteBars = true;
|
|
_manualFrameNumber = 0;
|
|
_manualSpriteSet = nullptr;
|
|
_manualStartFrame = _manualEndFrame = 0;
|
|
_manualFrame2 = 0;
|
|
_animFrameNumber = 0;
|
|
_nextCyclingActive = false;
|
|
_sceneInfo = SceneInfo::init(_vm);
|
|
_scrollFrameCtr = 0;
|
|
|
|
load();
|
|
}
|
|
|
|
AnimationView::~AnimationView() {
|
|
// Turn off palette cycling as well as any playing sound
|
|
Scene &scene = _vm->_game->_scene;
|
|
scene._cyclingActive = false;
|
|
_vm->_sound->stop();
|
|
_vm->_audio->stop();
|
|
|
|
// Delete data
|
|
delete _currentAnimation;
|
|
delete _sceneInfo;
|
|
}
|
|
|
|
void AnimationView::load() {
|
|
Common::String resName(_resourceName);
|
|
if (!resName.hasSuffix("."))
|
|
resName += ".res";
|
|
|
|
_filename = resName;
|
|
if (!_script.open(resName))
|
|
error("Could not open resource %s", resName.c_str());
|
|
|
|
processLines();
|
|
}
|
|
|
|
void AnimationView::display() {
|
|
Scene &scene = _vm->_game->_scene;
|
|
_vm->_palette->initPalette();
|
|
Common::fill(&_vm->_palette->_cyclingPalette[0], &_vm->_palette->_cyclingPalette[PALETTE_SIZE], 0);
|
|
|
|
_vm->_palette->resetGamePalette(1, 8);
|
|
scene._spriteSlots.reset();
|
|
scene._paletteCycles.clear();
|
|
|
|
MenuView::display();
|
|
}
|
|
|
|
bool AnimationView::onEvent(Common::Event &event) {
|
|
// Wait for the Escape key or a mouse press
|
|
if (((event.type == Common::EVENT_KEYDOWN) && (event.kbd.keycode == Common::KEYCODE_ESCAPE)) ||
|
|
(event.type == Common::EVENT_LBUTTONUP)) {
|
|
scriptDone();
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void AnimationView::doFrame() {
|
|
Scene &scene = _vm->_game->_scene;
|
|
|
|
if (_resourceIndex == -1 || _currentAnimation->freeFlag()) {
|
|
if (++_resourceIndex == (int)_resources.size()) {
|
|
scriptDone();
|
|
} else {
|
|
scene._frameStartTime = 0;
|
|
loadNextResource();
|
|
}
|
|
} else if (_currentAnimation->getCurrentFrame() == 1) {
|
|
scene._cyclingActive = _nextCyclingActive;
|
|
}
|
|
|
|
if (_currentAnimation && (++_scrollFrameCtr >= _currentAnimation->_header._scrollTicks)) {
|
|
_scrollFrameCtr = 0;
|
|
scroll();
|
|
}
|
|
|
|
if (_currentAnimation) {
|
|
++scene._frameStartTime;
|
|
_currentAnimation->update();
|
|
_redrawFlag = true;
|
|
}
|
|
}
|
|
|
|
void AnimationView::loadNextResource() {
|
|
Scene &scene = _vm->_game->_scene;
|
|
Palette &palette = *_vm->_palette;
|
|
ResourceEntry &resEntry = _resources[_resourceIndex];
|
|
Common::Array<PaletteCycle> paletteCycles;
|
|
|
|
if (resEntry._bgFlag)
|
|
palette.resetGamePalette(1, 8);
|
|
|
|
palette._mainPalette[253 * 3] = palette._mainPalette[253 * 3 + 1]
|
|
= palette._mainPalette[253 * 3 + 2] = 0xb4;
|
|
palette.setPalette(&palette._mainPalette[253 * 3], 253, 1);
|
|
|
|
// Free any previous messages
|
|
scene._kernelMessages.reset();
|
|
|
|
// Handle the bars at the top/bottom
|
|
if (resEntry._showWhiteBars) {
|
|
// For animations the screen has been clipped to the middle 156 rows.
|
|
// So although it's slightly messy, bypass our screen class entirely,
|
|
// and draw the horizontal lines directly on the physiacl screen surface
|
|
Graphics::Surface *s = g_system->lockScreen();
|
|
s->hLine(0, 20, MADS_SCREEN_WIDTH, 253);
|
|
s->hLine(0, 179, MADS_SCREEN_WIDTH, 253);
|
|
g_system->unlockScreen();
|
|
}
|
|
|
|
// Load the new animation
|
|
delete _currentAnimation;
|
|
_currentAnimation = Animation::init(_vm, &scene);
|
|
int flags = ANIMFLAG_ANIMVIEW | (resEntry._bgFlag ? ANIMFLAG_LOAD_BACKGROUND : 0);
|
|
_currentAnimation->load(scene._backgroundSurface, scene._depthSurface,
|
|
resEntry._resourceName, flags, &paletteCycles, _sceneInfo);
|
|
|
|
// Signal for a screen refresh
|
|
scene._spriteSlots.fullRefresh();
|
|
|
|
// If a sound driver has been specified, then load the correct one
|
|
if (!_currentAnimation->_header._soundName.empty()) {
|
|
const char *chP = strchr(_currentAnimation->_header._soundName.c_str(), '.');
|
|
assert(chP);
|
|
|
|
// Handle both Rex naming (xxx.009) and naming in later games (e.g. xxx.ph9)
|
|
int driverNum = atoi(chP + 3);
|
|
// HACK for Dragon
|
|
if (_currentAnimation->_header._soundName == "#SOUND.DRG")
|
|
driverNum = 9;
|
|
_vm->_sound->init(driverNum);
|
|
}
|
|
|
|
// Handle any manual setup
|
|
if (_currentAnimation->_header._manualFlag) {
|
|
_manualFrameNumber = _currentAnimation->_header._spritesIndex;
|
|
_manualSpriteSet = _currentAnimation->getSpriteSet(_manualFrameNumber);
|
|
}
|
|
|
|
// Set the sound data for the animation
|
|
_vm->_sound->setEnabled(resEntry._soundFlag);
|
|
|
|
Common::String dsrName = _currentAnimation->_header._dsrName;
|
|
if (!dsrName.empty())
|
|
_vm->_audio->setSoundGroup(dsrName);
|
|
|
|
// Start the new animation
|
|
_currentAnimation->startAnimation(0);
|
|
|
|
// Handle the palette and cycling palette
|
|
scene._cyclingActive = false;
|
|
Common::copy(&palette._mainPalette[0], &palette._mainPalette[PALETTE_SIZE],
|
|
&palette._cyclingPalette[0]);
|
|
|
|
_vm->_game->_fx = (ScreenTransition)resEntry._fx;
|
|
_nextCyclingActive = paletteCycles.size() > 0;
|
|
if (!_vm->_game->_fx) {
|
|
palette.setFullPalette(palette._mainPalette);
|
|
}
|
|
|
|
scene.initPaletteAnimation(paletteCycles, _nextCyclingActive && !_vm->_game->_fx);
|
|
}
|
|
|
|
void AnimationView::scroll() {
|
|
Scene &scene = _vm->_game->_scene;
|
|
Common::Point pt = _currentAnimation->_header._scrollPosition;
|
|
|
|
if (pt.x != 0) {
|
|
scene._backgroundSurface.scrollX(pt.x);
|
|
scene._spriteSlots.fullRefresh();
|
|
}
|
|
|
|
if (pt.y != 0) {
|
|
scene._backgroundSurface.scrollY(pt.y);
|
|
scene._spriteSlots.fullRefresh();
|
|
}
|
|
}
|
|
|
|
void AnimationView::scriptDone() {
|
|
_breakFlag = true;
|
|
_vm->_dialogs->_pendingDialog = DIALOG_MAIN_MENU;
|
|
}
|
|
|
|
void AnimationView::processLines() {
|
|
if (_script.eos()) {
|
|
// end of script, end animation
|
|
scriptDone();
|
|
return;
|
|
}
|
|
|
|
while (!_script.eos()) {
|
|
// Get in next line
|
|
_currentLine.clear();
|
|
char c;
|
|
while (!_script.eos() && (c = _script.readByte()) != '\n') {
|
|
if (c != '\r' && c != '\0')
|
|
_currentLine += c;
|
|
}
|
|
|
|
// Check for comment line
|
|
if (_currentLine.hasPrefix("#"))
|
|
continue;
|
|
|
|
// Process the line
|
|
while (!_currentLine.empty()) {
|
|
if (_currentLine.hasPrefix("-")) {
|
|
_currentLine.deleteChar(0);
|
|
|
|
processCommand();
|
|
} else {
|
|
// Get resource name
|
|
Common::String resName;
|
|
while (!_currentLine.empty() && (c = _currentLine[0]) != ' ') {
|
|
_currentLine.deleteChar(0);
|
|
resName += c;
|
|
}
|
|
|
|
// Add resource into list along with any set state information
|
|
_resources.push_back(ResourceEntry(resName, _sfx, _soundFlag,
|
|
_bgLoadFlag, _showWhiteBars));
|
|
|
|
// Fx resets between resource entries
|
|
_sfx = 0;
|
|
}
|
|
|
|
// Skip any spaces
|
|
while (_currentLine.hasPrefix(" "))
|
|
_currentLine.deleteChar(0);
|
|
}
|
|
}
|
|
}
|
|
|
|
void AnimationView::processCommand() {
|
|
// Get the command character
|
|
char commandChar = toupper(_currentLine[0]);
|
|
_currentLine.deleteChar(0);
|
|
|
|
// Handle the command
|
|
switch (commandChar) {
|
|
case 'B':
|
|
_soundFlag = !_soundFlag;
|
|
break;
|
|
case 'H':
|
|
// -h[:ex] Disable EMS / XMS high memory support
|
|
if (_currentLine.hasPrefix(":"))
|
|
_currentLine.deleteChar(0);
|
|
while (_currentLine.hasPrefix("e") || _currentLine.hasPrefix("x"))
|
|
_currentLine.deleteChar(0);
|
|
break;
|
|
case 'O':
|
|
// -o:xxx Specify opening special effect
|
|
assert(_currentLine[0] == ':');
|
|
_currentLine.deleteChar(0);
|
|
_sfx = getParameter();
|
|
break;
|
|
case 'P':
|
|
// Switch to CONCAT mode, which is ignored anyway
|
|
break;
|
|
case 'R': {
|
|
// Resynch timer (always, beginning, never)
|
|
assert(_currentLine[0] == ':');
|
|
_currentLine.deleteChar(0);
|
|
|
|
char v = toupper(_currentLine[0]);
|
|
_currentLine.deleteChar(0);
|
|
if (v == 'N')
|
|
_resyncMode = NEVER;
|
|
else if (v == 'A')
|
|
_resyncMode = ALWAYS;
|
|
else if (v == 'B')
|
|
_resyncMode = BEGINNING;
|
|
else
|
|
error("Unknown parameter");
|
|
break;
|
|
}
|
|
case 'W':
|
|
// Switch white bars being visible
|
|
_showWhiteBars = !_showWhiteBars;
|
|
break;
|
|
case 'X':
|
|
// Exit after animation finishes. Ignore
|
|
break;
|
|
case 'D':
|
|
// Unimplemented and ignored in the original. Ignore as well
|
|
break;
|
|
case 'Y':
|
|
// Reset palette on startup
|
|
_resetPalette = true;
|
|
break;
|
|
default:
|
|
error("Unknown command char: '%c'", commandChar);
|
|
}
|
|
}
|
|
|
|
int AnimationView::getParameter() {
|
|
int result = 0;
|
|
|
|
while (!_currentLine.empty()) {
|
|
char c = _currentLine[0];
|
|
|
|
if (c >= '0' && c <= '9') {
|
|
_currentLine.deleteChar(0);
|
|
result = result * 10 + (c - '0');
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
} // End of namespace MADS
|