2008-04-20 14:47:37 +00:00
|
|
|
/* 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.
|
|
|
|
*
|
|
|
|
* $URL$
|
|
|
|
* $Id$
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "m4/mads_anim.h"
|
|
|
|
#include "m4/m4.h"
|
|
|
|
|
|
|
|
namespace M4 {
|
|
|
|
|
|
|
|
#define TEXTVIEW_LINE_SPACING 2
|
|
|
|
#define TEXT_ANIMATION_DELAY 100
|
|
|
|
#define TV_NUM_FADE_STEPS 40
|
|
|
|
#define TV_FADE_DELAY_MILLI 50
|
|
|
|
|
|
|
|
TextviewView::TextviewView(M4Engine *vm):
|
|
|
|
View(vm, Common::Rect(0, 0, vm->_screen->width(), vm->_screen->height())),
|
|
|
|
_bgSurface(vm->_screen->width(), MADS_SURFACE_HEIGHT),
|
|
|
|
_textSurface(vm->_screen->width(), MADS_SURFACE_HEIGHT + vm->_font->getHeight() +
|
|
|
|
TEXTVIEW_LINE_SPACING) {
|
|
|
|
|
|
|
|
_screenType = VIEWID_TEXTVIEW;
|
|
|
|
_screenFlags.layer = LAYER_BACKGROUND;
|
|
|
|
_screenFlags.visible = true;
|
|
|
|
_screenFlags.get = SCREVENT_ALL;
|
|
|
|
_callback = NULL;
|
|
|
|
_script = NULL;
|
|
|
|
_spareScreen = NULL;
|
|
|
|
_bgCurrent = NULL;
|
|
|
|
_bgSpare = NULL;
|
|
|
|
reset();
|
|
|
|
|
|
|
|
// Set up system palette colors and the two colors for text display
|
|
|
|
_vm->_palette->setMadsSystemPalette();
|
|
|
|
RGB8 palData[3];
|
|
|
|
palData[0].r = palData[0].g = palData[0].b = 0;
|
|
|
|
palData[1].r = 0; palData[1].g = palData[1].b = 252;
|
|
|
|
palData[2].r = 0; palData[2].g = palData[2].b = 180;
|
|
|
|
_vm->_palette->setPalette(&palData[0], 4, 3);
|
|
|
|
_vm->_palette->blockRange(4, 3);
|
|
|
|
|
|
|
|
_vm->_font->setColors(5, 6, 4);
|
|
|
|
|
2008-06-18 21:02:52 +00:00
|
|
|
clear();
|
|
|
|
_bgSurface.clear();
|
|
|
|
_textSurface.clear();
|
2008-04-20 14:47:37 +00:00
|
|
|
|
|
|
|
int y = (height() - MADS_SURFACE_HEIGHT) / 2;
|
|
|
|
setColor(2);
|
|
|
|
hLine(0, width() - 1, y - 2);
|
|
|
|
hLine(0, width() - 1, height() - y + 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
TextviewView::~TextviewView() {
|
|
|
|
if (_script)
|
|
|
|
_vm->res()->toss(_resourceName);
|
|
|
|
if (_spareScreen)
|
|
|
|
delete _spareScreen;
|
|
|
|
if (_bgCurrent)
|
|
|
|
delete _bgCurrent;
|
|
|
|
if (_bgSpare)
|
|
|
|
delete _bgSpare;
|
|
|
|
}
|
|
|
|
|
|
|
|
void TextviewView::reset() {
|
2008-06-18 21:02:52 +00:00
|
|
|
_bgSurface.clear();
|
|
|
|
_textSurface.clear();
|
2008-04-20 14:47:37 +00:00
|
|
|
_animating = false;
|
|
|
|
_panX = 0;
|
|
|
|
_panY = 0;
|
|
|
|
_panSpeed = 0;
|
|
|
|
_soundDriverLoaded = false;
|
|
|
|
Common::set_to(&_spareScreens[0], &_spareScreens[10], 0);
|
|
|
|
_scrollCount = 0;
|
|
|
|
_lineY = -1;
|
|
|
|
_scrollTimeout = 0;
|
|
|
|
_panCountdown = 0;
|
|
|
|
_processEvents = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void TextviewView::setScript(const char *resourceName, TextviewCallback callback) {
|
|
|
|
_callback = callback;
|
|
|
|
if (_script)
|
|
|
|
_vm->res()->toss(_resourceName);
|
|
|
|
if (_spareScreen) {
|
|
|
|
delete _spareScreen;
|
|
|
|
_spareScreen = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
reset();
|
|
|
|
|
|
|
|
strncpy(_resourceName, resourceName, 15);
|
|
|
|
_resourceName[15] = '\0';
|
|
|
|
if (!strchr(_resourceName, '.'))
|
|
|
|
strcat(_resourceName, ".txr");
|
|
|
|
|
|
|
|
_script = _vm->res()->get(_resourceName);
|
|
|
|
|
|
|
|
processLines();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool TextviewView::onEvent(M4EventType eventType, int param, int x, int y, bool &captureEvents) {
|
|
|
|
if (!_processEvents)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// Wait for the Escape key or a mouse press
|
|
|
|
if (((eventType == KEVENT_KEY) && (param == Common::KEYCODE_ESCAPE)) ||
|
|
|
|
(eventType == MEVENT_LEFT_RELEASE) || (eventType == MEVENT_RIGHT_RELEASE)) {
|
|
|
|
scriptDone();
|
|
|
|
captureEvents = false;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void TextviewView::updateState() {
|
|
|
|
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 *destP = _bgSurface.getBasePtr(_translationX, 0);
|
|
|
|
|
|
|
|
for (int y = 0; y < _bgSurface.height(); ++y, srcP += _spareScreen->width(),
|
|
|
|
destP += _bgSurface.width()) {
|
|
|
|
*destP = *srcP;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (++_translationX >= _bgSurface.width()) {
|
|
|
|
// Surface transition is complete
|
|
|
|
delete _spareScreen;
|
|
|
|
_spareScreen = NULL;
|
|
|
|
|
|
|
|
_vm->_palette->deleteRange(_bgCurrent);
|
|
|
|
delete _bgCurrent;
|
|
|
|
_bgCurrent = _bgSpare;
|
|
|
|
_bgSpare = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Make sure it's time for an update
|
|
|
|
if (currTime < _scrollTimeout)
|
|
|
|
return;
|
|
|
|
_scrollTimeout = g_system->getMillis() + TEXT_ANIMATION_DELAY;
|
|
|
|
|
|
|
|
// If any panning values are set, pan the background surface
|
|
|
|
if ((_panX != 0) || (_panY != 0)) {
|
|
|
|
if (_panCountdown > 0) {
|
|
|
|
--_panCountdown;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Handle horizontal panning
|
|
|
|
if (_panX != 0) {
|
|
|
|
byte *lineTemp = new byte[_panX];
|
|
|
|
for (int y = 0; y < _bgSurface.height(); ++y) {
|
|
|
|
byte *pixelsP = _bgSurface.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 + _panX, lineTemp);
|
|
|
|
Common::copy(pixelsP + _panX, pixelsP + _bgSurface.width(), pixelsP);
|
|
|
|
Common::copy(lineTemp, lineTemp + _panX, pixelsP + _bgSurface.width() - _panX);
|
|
|
|
}
|
|
|
|
|
|
|
|
delete[] lineTemp;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Handle vertical panning
|
|
|
|
if (_panY != 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[_panY * _bgSurface.width()];
|
|
|
|
byte *pixelsP = _bgSurface.getBasePtr(0, _bgSurface.height() - _panY);
|
|
|
|
Common::copy(pixelsP, pixelsP + _bgSurface.width() * _panY, linesTemp);
|
|
|
|
|
|
|
|
for (int y = _bgSurface.height() - 1; y >= _panY; --y) {
|
|
|
|
byte *destP = _bgSurface.getBasePtr(0, y);
|
|
|
|
byte *srcP = _bgSurface.getBasePtr(0, y - _panY);
|
|
|
|
Common::copy(srcP, srcP + _bgSurface.width(), destP);
|
|
|
|
}
|
|
|
|
|
|
|
|
Common::copy(linesTemp, linesTemp + _panY * _bgSurface.width(), (byte *)_bgSurface.pixels);
|
|
|
|
delete[] linesTemp;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Scroll the text surface up by one row
|
|
|
|
byte *pixelsP = (byte *)_textSurface.pixels;
|
|
|
|
Common::copy(pixelsP + width(), pixelsP + _textSurface.width() * _textSurface.height(), pixelsP);
|
|
|
|
pixelsP = _textSurface.getBasePtr(0, _textSurface.height() - 1);
|
|
|
|
Common::set_to(pixelsP, pixelsP + _textSurface.width(), _vm->_palette->BLACK);
|
|
|
|
|
|
|
|
if (_scrollCount > 0) {
|
|
|
|
// Handling final scrolling of text off of screen
|
|
|
|
if (--_scrollCount == 0) {
|
|
|
|
scriptDone();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// Handling a text row
|
|
|
|
if (++_lineY == (_vm->_font->getHeight() + TEXTVIEW_LINE_SPACING))
|
|
|
|
processLines();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Refresh the view
|
|
|
|
int yp = (height() - _bgSurface.height()) / 2;
|
|
|
|
_bgSurface.copyTo(this, 0, yp);
|
|
|
|
_textSurface.copyTo(this, Common::Rect(0, 0, _textSurface.width(), _bgSurface.height()),
|
|
|
|
0, yp, _vm->_palette->BLACK);
|
|
|
|
}
|
|
|
|
|
|
|
|
void TextviewView::scriptDone() {
|
|
|
|
TextviewCallback fn = _callback;
|
|
|
|
M4Engine *vm = _vm;
|
|
|
|
|
|
|
|
// Remove this view from manager and destroy it
|
|
|
|
_vm->_viewManager->deleteView(this);
|
|
|
|
|
|
|
|
if (fn)
|
|
|
|
fn(vm);
|
|
|
|
}
|
|
|
|
|
|
|
|
void TextviewView::processLines() {
|
2008-09-14 22:28:53 +00:00
|
|
|
_script->readLine_OLD(_currentLine, 79);
|
2008-04-20 14:47:37 +00:00
|
|
|
if (_script->eos())
|
|
|
|
error("Attempted to read past end of response file");
|
|
|
|
|
|
|
|
while (!_script->eos()) {
|
|
|
|
// Commented out line, so go loop for another
|
2008-09-14 22:28:53 +00:00
|
|
|
if (_currentLine[0] == '#') {
|
|
|
|
_script->readLine_OLD(_currentLine, 79);
|
2008-04-20 14:47:37 +00:00
|
|
|
continue;
|
2008-09-14 22:28:53 +00:00
|
|
|
}
|
2008-04-20 14:47:37 +00:00
|
|
|
|
|
|
|
// 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
|
|
|
|
strcpy(_currentLine, cEnd + 1);
|
|
|
|
|
|
|
|
cStart = strchr(_currentLine, '[');
|
|
|
|
}
|
|
|
|
|
|
|
|
if (_currentLine[0]) {
|
|
|
|
processText();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
processText();
|
|
|
|
break;
|
|
|
|
}
|
2008-09-14 22:28:53 +00:00
|
|
|
|
|
|
|
_script->readLine_OLD(_currentLine, 79);
|
2008-04-20 14:47:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void TextviewView::processCommand() {
|
|
|
|
char commandStr[80];
|
|
|
|
char *paramP;
|
|
|
|
strcpy(commandStr, _currentLine + 1);
|
|
|
|
str_upper(commandStr);
|
|
|
|
|
|
|
|
if (!strncmp(commandStr, "BACKGROUND", 10)) {
|
|
|
|
// Set the background
|
|
|
|
paramP = commandStr + 10;
|
|
|
|
int screenId = getParameter(¶mP);
|
|
|
|
_bgSurface.loadBackground(screenId, &_bgCurrent);
|
|
|
|
_vm->_palette->addRange(_bgCurrent);
|
|
|
|
_bgSurface.translate(_bgCurrent);
|
|
|
|
|
|
|
|
} else if (!strncmp(commandStr, "GO", 2)) {
|
|
|
|
_animating = true;
|
|
|
|
|
|
|
|
// Grab what the final palete will be
|
|
|
|
RGB8 destPalette[256];
|
|
|
|
_vm->_palette->grabPalette(destPalette, 0, 256);
|
|
|
|
|
|
|
|
// Copy the loaded background, if any, to the view surface
|
|
|
|
int yp = (height() - _bgSurface.height()) / 2;
|
|
|
|
_bgSurface.copyTo(this, 0, yp);
|
|
|
|
|
|
|
|
// Handle fade-in
|
|
|
|
_processEvents = false; // stop processing events during fade-in
|
|
|
|
_vm->_palette->fadeIn(TV_NUM_FADE_STEPS, TV_FADE_DELAY_MILLI, destPalette, 256);
|
|
|
|
_processEvents = 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)) {
|
|
|
|
_panX = panX;
|
|
|
|
_panY = panY;
|
|
|
|
_panSpeed = panSpeed;
|
|
|
|
}
|
|
|
|
|
|
|
|
} else if (!strncmp(commandStr, "DRIVER", 6)) {
|
|
|
|
// Set the driver to use
|
|
|
|
// TODO: Handling of the sound drivers
|
|
|
|
|
|
|
|
} else if (!strncmp(commandStr, "SOUND", 5)) {
|
|
|
|
// Set sound number
|
|
|
|
paramP = commandStr + 5;
|
|
|
|
//int soundId = getParameter(¶mP);
|
|
|
|
|
|
|
|
//TODO: Proper handling of the sound drivers/sounds
|
|
|
|
//if (!_soundDriverLoaded)
|
|
|
|
// error("Attempted to set sound without loading any driver\n");
|
|
|
|
|
|
|
|
} else if (!strncmp(commandStr, "COLOR", 5) && ((commandStr[5] == '0') || (commandStr[5] == '1'))) {
|
|
|
|
// Set the text colors
|
|
|
|
int index = commandStr[5] - '0';
|
|
|
|
paramP = commandStr + 6;
|
|
|
|
|
|
|
|
RGB8 palEntry;
|
|
|
|
palEntry.r = getParameter(¶mP) << 2;
|
|
|
|
palEntry.g = getParameter(¶mP) << 2;
|
|
|
|
palEntry.b = getParameter(¶mP) << 2;
|
|
|
|
_vm->_palette->setPalette(&palEntry, 5 + index, 1);
|
|
|
|
|
|
|
|
} 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';
|
|
|
|
if ((spareIndex >= 0) && (spareIndex <= 9)) {
|
|
|
|
int screenId = getParameter(¶mP);
|
|
|
|
|
|
|
|
_spareScreens[spareIndex] = screenId;
|
|
|
|
}
|
|
|
|
|
|
|
|
} 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] != 0)) {
|
|
|
|
_spareScreen = new M4Surface(width(), MADS_SURFACE_HEIGHT);
|
|
|
|
_spareScreen->loadBackground(_spareScreens[spareIndex], &_bgSpare);
|
|
|
|
_vm->_palette->addRange(_bgSpare);
|
|
|
|
_spareScreen->translate(_bgSpare);
|
|
|
|
|
|
|
|
_translationX = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
error("Unknown response command: '%s'", commandStr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int TextviewView::getParameter(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 TextviewView::processText() {
|
|
|
|
int lineWidth, xStart;
|
|
|
|
|
|
|
|
if (!strcmp(_currentLine, "***")) {
|
|
|
|
// Special signifier for end of script
|
|
|
|
_scrollCount = _vm->_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 = (width() / 2) - _vm->_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 {
|
|
|
|
lineWidth = _vm->_font->getWidth(_currentLine);
|
|
|
|
xStart = (width() - lineWidth) / 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Copy the text line onto the bottom of the textSurface surface, which will allow it
|
|
|
|
// to gradually scroll onto the screen
|
|
|
|
int yp = _textSurface.height() - _vm->_font->getHeight() - TEXTVIEW_LINE_SPACING;
|
|
|
|
_textSurface.fillRect(Common::Rect(0, yp, _textSurface.width(), _textSurface.height()),
|
|
|
|
_vm->_palette->BLACK);
|
|
|
|
_vm->_font->writeString(&_textSurface, _currentLine, xStart, yp);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------
|
|
|
|
|
|
|
|
AnimviewView::AnimviewView(M4Engine *vm):
|
|
|
|
View(vm, Common::Rect(0, 0, vm->_screen->width(), vm->_screen->height())),
|
|
|
|
_bgSurface(vm->_screen->width(), MADS_SURFACE_HEIGHT) {
|
|
|
|
|
|
|
|
_screenType = VIEWID_ANIMVIEW;
|
|
|
|
_screenFlags.layer = LAYER_BACKGROUND;
|
|
|
|
_screenFlags.visible = true;
|
|
|
|
_screenFlags.get = SCREVENT_ALL;
|
|
|
|
_callback = NULL;
|
|
|
|
_script = NULL;
|
|
|
|
_palData = NULL;
|
|
|
|
_previousUpdate = 0;
|
|
|
|
_transition = kTransitionNone;
|
|
|
|
reset();
|
|
|
|
|
|
|
|
// Set up system palette colors
|
|
|
|
_vm->_palette->setMadsSystemPalette();
|
|
|
|
|
2008-06-18 21:02:52 +00:00
|
|
|
clear();
|
|
|
|
_bgSurface.clear();
|
2008-04-20 14:47:37 +00:00
|
|
|
|
|
|
|
int y = (height() - MADS_SURFACE_HEIGHT) / 2;
|
|
|
|
setColor(2);
|
|
|
|
hLine(0, width() - 1, y - 2);
|
|
|
|
hLine(0, width() - 1, height() - y + 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
AnimviewView::~AnimviewView() {
|
|
|
|
if (_script)
|
|
|
|
_vm->res()->toss(_resourceName);
|
|
|
|
}
|
|
|
|
|
|
|
|
void AnimviewView::reset() {
|
2008-06-18 21:02:52 +00:00
|
|
|
_bgSurface.clear();
|
2008-04-20 14:47:37 +00:00
|
|
|
_soundDriverLoaded = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void AnimviewView::setScript(const char *resourceName, AnimviewCallback callback) {
|
|
|
|
_callback = callback;
|
|
|
|
if (_script)
|
|
|
|
_vm->res()->toss(_resourceName);
|
|
|
|
|
|
|
|
reset();
|
|
|
|
|
|
|
|
strncpy(_resourceName, resourceName, 15);
|
|
|
|
_resourceName[15] = '\0';
|
|
|
|
if (!strchr(_resourceName, '.'))
|
|
|
|
strcat(_resourceName, ".res");
|
|
|
|
|
|
|
|
_script = _vm->res()->get(_resourceName);
|
|
|
|
|
|
|
|
processLines();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool AnimviewView::onEvent(M4EventType eventType, int param, int x, int y, bool &captureEvents) {
|
|
|
|
// Wait for the Escape key or a mouse press
|
|
|
|
if (((eventType == KEVENT_KEY) && (param == Common::KEYCODE_ESCAPE)) ||
|
|
|
|
(eventType == MEVENT_LEFT_RELEASE) || (eventType == MEVENT_RIGHT_RELEASE)) {
|
|
|
|
scriptDone();
|
|
|
|
captureEvents = false;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void AnimviewView::updateState() {
|
|
|
|
char bgFile[10];
|
|
|
|
int bgNumber = 0;
|
|
|
|
|
|
|
|
// Only update state if wait period has expired
|
|
|
|
if (_previousUpdate > 0) {
|
|
|
|
if (g_system->getMillis() - _previousUpdate < 3000) {
|
|
|
|
return;
|
|
|
|
} else {
|
|
|
|
// time for an update
|
|
|
|
_previousUpdate = g_system->getMillis();
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
_previousUpdate = g_system->getMillis();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
strncpy(bgFile, _currentFile, 5);
|
|
|
|
bgFile[0] = bgFile[2];
|
|
|
|
bgFile[1] = bgFile[3];
|
|
|
|
bgFile[2] = bgFile[4];
|
|
|
|
bgFile[3] = '\0';
|
|
|
|
bgNumber = atoi(bgFile);
|
|
|
|
sprintf(bgFile, "rm%i.art", bgNumber);
|
|
|
|
|
|
|
|
// Not all scenes have a background. If there is one, refresh it
|
|
|
|
if (_vm->_resourceManager->resourceExists(bgFile)) {
|
|
|
|
if (_palData) {
|
|
|
|
_vm->_palette->deleteRange(_palData);
|
|
|
|
delete _palData;
|
|
|
|
}
|
|
|
|
_bgSurface.loadBackground(bgNumber, &_palData);
|
|
|
|
_vm->_palette->addRange(_palData);
|
|
|
|
_bgSurface.translate(_palData);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Grab what the final palete will be
|
|
|
|
RGB8 destPalette[256];
|
|
|
|
_vm->_palette->grabPalette(destPalette, 0, 256);
|
|
|
|
|
|
|
|
// Handle scene transition
|
|
|
|
switch (_transition) {
|
|
|
|
case kTransitionNone:
|
|
|
|
// nothing to do
|
|
|
|
break;
|
|
|
|
case kTransitionFadeIn:
|
|
|
|
case kTransitionFadeIn2:
|
|
|
|
_vm->_palette->fadeIn(TV_NUM_FADE_STEPS, TV_FADE_DELAY_MILLI, destPalette, 256);
|
|
|
|
break;
|
|
|
|
case kTransitionBoxInBottomLeft:
|
|
|
|
case kTransitionBoxInBottomRight:
|
|
|
|
case kTransitionBoxInTopLeft:
|
|
|
|
case kTransitionBoxInTopRight:
|
|
|
|
// unused
|
|
|
|
warning("Unsupported box in scene effect");
|
|
|
|
break;
|
|
|
|
case kTransitionPanLeftToRight:
|
|
|
|
// TODO
|
|
|
|
break;
|
|
|
|
case kTransitionPanRightToLeft:
|
|
|
|
// TODO
|
|
|
|
break;
|
|
|
|
case kTransitionCircleIn:
|
|
|
|
// TODO
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
// nothing to do
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Refresh the view
|
|
|
|
int yp = (height() - _bgSurface.height()) / 2;
|
|
|
|
_bgSurface.copyTo(this, 0, yp);
|
|
|
|
|
|
|
|
// Read next line
|
|
|
|
processLines();
|
|
|
|
}
|
|
|
|
|
|
|
|
void AnimviewView::scriptDone() {
|
|
|
|
AnimviewCallback fn = _callback;
|
|
|
|
M4Engine *vm = _vm;
|
|
|
|
|
|
|
|
// Remove this view from manager and destroy it
|
|
|
|
_vm->_viewManager->deleteView(this);
|
|
|
|
|
|
|
|
if (fn)
|
|
|
|
fn(vm);
|
|
|
|
}
|
|
|
|
|
|
|
|
void AnimviewView::processLines() {
|
2008-09-14 22:28:53 +00:00
|
|
|
_script->readLine_OLD(_currentLine, 79);
|
2008-04-20 14:47:37 +00:00
|
|
|
if (_script->eos()) {
|
|
|
|
// end of script, end animation
|
|
|
|
scriptDone();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (!_script->eos()) {
|
|
|
|
// 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
|
|
|
|
// Don't use strcpy() here, because if the
|
|
|
|
// rest of the line is the longer of the two
|
|
|
|
// strings, the memory areas will overlap.
|
|
|
|
memmove(_currentLine, cEnd + 1, strlen(cEnd + 1) + 1);
|
|
|
|
|
|
|
|
cStart = strchr(_currentLine, '-');
|
|
|
|
}
|
|
|
|
|
|
|
|
if (_currentLine[0]) {
|
|
|
|
sprintf(_currentFile, "%s", _currentLine);
|
|
|
|
//printf("File: %s\n", _currentLine);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
sprintf(_currentFile, "%s", _currentLine);
|
|
|
|
//printf("File: %s\n", _currentLine);
|
|
|
|
break;
|
|
|
|
}
|
2008-09-14 22:28:53 +00:00
|
|
|
|
|
|
|
_script->readLine_OLD(_currentLine, 79);
|
2008-04-20 14:47:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
Switches are: (taken from the help of the original executable)
|
|
|
|
-b Toggle background load status off/on.
|
|
|
|
-c:char Specify sound card id letter.
|
|
|
|
-g Stay in graphics mode on exit.
|
|
|
|
-h[:ex] Disable EMS/XMS high memory support.
|
|
|
|
-i Switch sound interrupts mode off/on.
|
|
|
|
-j Wait for music to finish at end.
|
|
|
|
-k Keystroke jumps to end instead of abort.
|
|
|
|
-m Operate in non-MADS mode.
|
|
|
|
-o:xxx Specify opening special effect.
|
|
|
|
-p Switch MADS path mode to CONCAT.
|
|
|
|
-r[:abn] Resynch timer (always, beginning, never).
|
|
|
|
-s:file Specify sound file.
|
|
|
|
-u[:...] Use DMA speech [optional: addr,type,irq,drq].
|
|
|
|
-w Toggle white bars off/on.
|
|
|
|
-x Exit immediately after last frame.
|
|
|
|
-y Do not clear screen initially
|
|
|
|
-z Display statistics after run.
|
|
|
|
|
|
|
|
Opening special effects are:
|
|
|
|
0: no effect
|
|
|
|
1: fade in
|
|
|
|
2: fade in (looks to be the same as 1)
|
|
|
|
3: box in from bottom left (unused)
|
|
|
|
4: box in from bottom right (unused)
|
|
|
|
5: box in from top left (unused)
|
|
|
|
6: box in from top right (unused)
|
|
|
|
7: pan in from left to right
|
|
|
|
8: pan in from right to left
|
|
|
|
9: circle in (new scene appears in a circle that expands)
|
|
|
|
|
|
|
|
Animview is ran like this from the original games:
|
|
|
|
animview.exe @resfilename -c:P,220,20 -u:220,20,07,01 -p -a:mainmenu -p
|
|
|
|
|
|
|
|
Note that the first -p is necessary to watch the animation, otherwise
|
|
|
|
the program just exits
|
|
|
|
|
|
|
|
To watch an animation within the *.res file, just run animview like this:
|
|
|
|
animview.exe -x -r:b -o:2 animfilename -p
|
|
|
|
*/
|
|
|
|
void AnimviewView::processCommand() {
|
|
|
|
char commandStr[80];
|
|
|
|
strcpy(commandStr, _currentLine + 1);
|
|
|
|
str_upper(commandStr);
|
|
|
|
char *param = commandStr;
|
|
|
|
|
|
|
|
if (!strncmp(commandStr, "X", 1)) {
|
|
|
|
//printf("X ");
|
|
|
|
} else if (!strncmp(commandStr, "W", 1)) {
|
|
|
|
//printf("W ");
|
|
|
|
} else if (!strncmp(commandStr, "R", 1)) {
|
|
|
|
param = param + 2;
|
|
|
|
//printf("R:%s ", param);
|
|
|
|
} else if (!strncmp(commandStr, "O", 1)) {
|
|
|
|
param = param + 2;
|
|
|
|
//printf("O:%i ", atoi(param));
|
|
|
|
_transition = atoi(param);
|
|
|
|
} else {
|
|
|
|
error("Unknown response command: '%s'", commandStr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|