mirror of
https://github.com/libretro/scummvm.git
synced 2024-12-15 14:18:37 +00:00
c122d83c0e
svn-id: r25935
519 lines
14 KiB
C++
519 lines
14 KiB
C++
/* ScummVM - Scumm Interpreter
|
|
* Copyright (C) 2006 The ScummVM project
|
|
*
|
|
* 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 "parallaction/parallaction.h"
|
|
#include "parallaction/graphics.h"
|
|
#include "parallaction/disk.h"
|
|
#include "parallaction/parser.h"
|
|
#include "parallaction/music.h"
|
|
#include "parallaction/commands.h"
|
|
#include "parallaction/zone.h"
|
|
|
|
namespace Parallaction {
|
|
|
|
void resolveLocationForwards();
|
|
void loadExternalMaskPath(char *filename);
|
|
void switchBackground(char *name);
|
|
void parseWalkNodes(Script &script, Node *list);
|
|
void freeAnimations();
|
|
|
|
Node helperNode = { NULL, NULL };
|
|
|
|
void Parallaction::parseLocation(const char *filename) {
|
|
// printf("parseLocation(%s)", filename);
|
|
debugC(1, kDebugLocation, "parseLocation('%s')", filename);
|
|
|
|
char *location_src = NULL;
|
|
|
|
uint16 _si = 1;
|
|
_vm->_graphics->_proportionalFont = false;
|
|
_vm->_graphics->setFont("topaz");
|
|
|
|
location_src = (char*)memAlloc(0x4000);
|
|
openLocation(filename, location_src);
|
|
_locationScript = new Script(location_src);
|
|
|
|
fillBuffers(*_locationScript, true);
|
|
while (scumm_stricmp(_tokens[0], "ENDLOCATION")) {
|
|
// printf("token[0] = %s", _tokens[0]);
|
|
|
|
if (!scumm_stricmp(_tokens[0], "LOCATION")) {
|
|
char *background = strchr(_tokens[1], '.');
|
|
if (background) {
|
|
background[0] = '\0';
|
|
background++;
|
|
} else
|
|
background = _tokens[1];
|
|
|
|
// WORKAROUND: the original code erroneously incremented
|
|
// _currentLocationIndex, thus producing inconsistent
|
|
// savegames. This workaround modified the following loop
|
|
// and if-statement, so the code exactly matches the one
|
|
// in Big Red Adventure.
|
|
_currentLocationIndex = -1;
|
|
uint16 _di = 0;
|
|
while (_locationNames[_di][0] != '\0') {
|
|
if (!scumm_stricmp(_locationNames[_di], filename)) {
|
|
_currentLocationIndex = _di;
|
|
}
|
|
_di++;
|
|
}
|
|
|
|
if (_currentLocationIndex == -1) {
|
|
strcpy(_locationNames[_numLocations], filename);
|
|
_currentLocationIndex = _numLocations;
|
|
|
|
_numLocations++;
|
|
_locationNames[_numLocations][0] = '\0';
|
|
_localFlags[_numLocations] = 0;
|
|
} else {
|
|
_localFlags[_currentLocationIndex] |= kFlagsVisited; // 'visited'
|
|
}
|
|
|
|
strcpy(_location, _tokens[1]);
|
|
switchBackground(background);
|
|
|
|
if (_tokens[2][0] != '\0') {
|
|
_yourself._zone.pos._position._x = atoi(_tokens[2]);
|
|
_yourself._zone.pos._position._y = atoi(_tokens[3]);
|
|
}
|
|
|
|
if (_tokens[4][0] != '\0') {
|
|
_yourself._frame = atoi(_tokens[4]);
|
|
}
|
|
}
|
|
if (!scumm_stricmp(_tokens[0], "DISK")) {
|
|
strcpy(_disk, _tokens[1]);
|
|
_archive.open(_disk);
|
|
}
|
|
if (!scumm_stricmp(_tokens[0], "LOCALFLAGS")) {
|
|
_si = 1; // _localFlagNames[0] = 'visited'
|
|
while (_tokens[_si][0] != '\0') {
|
|
_localFlagNames[_si] = (char*)memAlloc(strlen(_tokens[_si])+1);
|
|
strcpy(_localFlagNames[_si], _tokens[_si]);
|
|
_si++;
|
|
}
|
|
_localFlagNames[_si] = 0;
|
|
}
|
|
if (!scumm_stricmp(_tokens[0], "COMMANDS")) {
|
|
_locationCommands = parseCommands(*_locationScript);
|
|
}
|
|
if (!scumm_stricmp(_tokens[0], "ACOMMANDS")) {
|
|
_locationACommands = parseCommands(*_locationScript);
|
|
}
|
|
if (!scumm_stricmp(_tokens[0], "FLAGS")) {
|
|
if ((_localFlags[_currentLocationIndex] & kFlagsVisited) == 0) {
|
|
// only for 1st visit
|
|
_localFlags[_currentLocationIndex] = 0;
|
|
_si = 1;
|
|
|
|
do {
|
|
byte _al = searchTable(_tokens[_si], const_cast<const char **>(_localFlagNames));
|
|
_localFlags[_currentLocationIndex] |= 1 << (_al - 1);
|
|
|
|
_si++;
|
|
if (scumm_stricmp(_tokens[_si], "|")) break;
|
|
_si++;
|
|
} while (true);
|
|
}
|
|
}
|
|
if (!scumm_stricmp(_tokens[0], "COMMENT")) {
|
|
_locationComment = parseComment(*_locationScript);
|
|
}
|
|
if (!scumm_stricmp(_tokens[0], "ENDCOMMENT")) {
|
|
_locationEndComment = parseComment(*_locationScript);
|
|
}
|
|
if (!scumm_stricmp(_tokens[0], "ZONE")) {
|
|
parseZone(*_locationScript, &_zones, _tokens[1]);
|
|
}
|
|
if (!scumm_stricmp(_tokens[0], "NODES")) {
|
|
parseWalkNodes(*_locationScript, &_locationWalkNodes);
|
|
}
|
|
if (!scumm_stricmp(_tokens[0], "ANIMATION")) {
|
|
parseAnimation(*_locationScript, &_animations, _tokens[1]);
|
|
}
|
|
if (!scumm_stricmp(_tokens[0], "SOUND")) {
|
|
strcpy(_soundFile, _tokens[1]);
|
|
}
|
|
fillBuffers(*_locationScript, true);
|
|
}
|
|
|
|
resolveLocationForwards();
|
|
|
|
delete _locationScript;
|
|
_locationScript = NULL;
|
|
|
|
memFree(location_src);
|
|
|
|
return;
|
|
}
|
|
|
|
void resolveLocationForwards() {
|
|
// printf("resolveLocationForwards()");
|
|
// printf("# forwards: %i", _numForwards);
|
|
|
|
for (uint16 _si = 0; _forwardedCommands[_si]; _si++) {
|
|
_forwardedCommands[_si]->u._animation = findAnimation(_forwardedAnimationNames[_si]);
|
|
_forwardedCommands[_si] = NULL;
|
|
}
|
|
|
|
_numForwards = 0;
|
|
return;
|
|
}
|
|
|
|
|
|
void freeLocation() {
|
|
debugC(7, kDebugLocation, "freeLocation");
|
|
|
|
uint16 _si = 1;
|
|
while (_localFlagNames[_si] != 0) {
|
|
memFree(_localFlagNames[_si]);
|
|
_localFlagNames[_si] = NULL;
|
|
_si++;
|
|
}
|
|
debugC(7, kDebugLocation, "freeLocation: localflags names freed");
|
|
|
|
|
|
freeNodeList(_locationWalkNodes._next);
|
|
_locationWalkNodes._next = NULL;
|
|
debugC(7, kDebugLocation, "freeLocation: walk nodes freed");
|
|
|
|
helperNode._prev = helperNode._next = NULL;
|
|
freeZones(_zones._next);
|
|
freeNodeList(_zones._next);
|
|
memcpy(&_zones, &helperNode, sizeof(Node));
|
|
debugC(7, kDebugLocation, "freeLocation: zones freed");
|
|
|
|
helperNode._prev = helperNode._next = NULL;
|
|
freeZones(_animations._next);
|
|
freeAnimations();
|
|
freeNodeList(_animations._next);
|
|
memcpy(&_animations, &helperNode, sizeof(Node));
|
|
debugC(7, kDebugLocation, "freeLocation: animations freed");
|
|
|
|
if (_locationComment) {
|
|
memFree(_locationComment);
|
|
}
|
|
_locationComment = NULL;
|
|
debugC(7, kDebugLocation, "freeLocation: comments freed");
|
|
|
|
if (_locationCommands) {
|
|
freeNodeList(&_locationCommands->_node);
|
|
}
|
|
_locationCommands = NULL;
|
|
debugC(7, kDebugLocation, "freeLocation: commands freed");
|
|
|
|
if (_locationACommands) {
|
|
freeNodeList(&_locationACommands->_node);
|
|
}
|
|
_locationACommands = NULL;
|
|
debugC(7, kDebugLocation, "freeLocation: acommands freed");
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
void parseWalkNodes(Script& script, Node *list) {
|
|
|
|
fillBuffers(script, true);
|
|
while (scumm_stricmp(_tokens[0], "ENDNODES")) {
|
|
|
|
if (!scumm_stricmp(_tokens[0], "COORD")) {
|
|
|
|
WalkNode *v4 = (WalkNode*)memAlloc(sizeof(WalkNode));
|
|
v4->_x = atoi(_tokens[1]) - _yourself._cnv._width/2;
|
|
v4->_y = atoi(_tokens[2]) - _yourself._cnv._height;
|
|
|
|
addNode(list, &v4->_node);
|
|
|
|
}
|
|
|
|
fillBuffers(script, true);
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
void switchBackground(char *name) {
|
|
// printf("switchBackground(%s)", name);
|
|
|
|
byte palette[PALETTE_SIZE];
|
|
|
|
uint16 v2 = 0;
|
|
if (!scumm_stricmp(_location, "final")) {
|
|
_vm->_graphics->clearScreen(Graphics::kBitBack);
|
|
for (uint16 _si = 0; _si <= 93; ) {
|
|
palette[_si] = v2;
|
|
palette[_si+1] = v2;
|
|
palette[_si+2] = v2;
|
|
v2 += 4;
|
|
_si += 3;
|
|
}
|
|
|
|
_vm->_graphics->palUnk0(palette);
|
|
}
|
|
|
|
char dest[PATH_LEN];
|
|
strcpy(dest, _location);
|
|
strcat(dest, ".dyn");
|
|
_vm->_graphics->loadBackground(dest, Graphics::kBitBack);
|
|
_vm->_graphics->copyScreen(Graphics::kBitBack, Graphics::kBit2);
|
|
|
|
if (!scumm_stricmp(_location, name)) return;
|
|
|
|
// load external masks and paths only for certain locations
|
|
sprintf(dest, "%s.msk", name);
|
|
_vm->_graphics->loadMaskAndPath(dest);
|
|
|
|
return;
|
|
}
|
|
|
|
extern Zone *_hoverZone;
|
|
extern Job *_jDrawLabel;
|
|
extern Job *_jEraseLabel;
|
|
|
|
|
|
void Parallaction::changeLocation(char *location) {
|
|
debugC(1, kDebugLocation, "changeLocation to '%s'", location);
|
|
|
|
// printf("changeLocation('%s')", location);
|
|
if (_musicData1 != 0) {
|
|
if (!scumm_stricmp(_characterName, "dino"))
|
|
_vm->_midiPlayer->play("dino");
|
|
else if (!scumm_stricmp(_characterName, "donna"))
|
|
_vm->_midiPlayer->play("donna");
|
|
else
|
|
_vm->_midiPlayer->play("nuts");
|
|
|
|
_musicData1 = 0;
|
|
|
|
debugC(2, kDebugLocation, "changeLocation: started character specific music");
|
|
}
|
|
|
|
if (!scumm_stricmp(location, "night") || !scumm_stricmp(location, "intsushi")) {
|
|
_vm->_midiPlayer->play("soft");
|
|
|
|
debugC(2, kDebugLocation, "changeLocation: started music 'soft'");
|
|
}
|
|
|
|
if (!scumm_stricmp(location, "museo") ||
|
|
!scumm_stricmp(location, "caveau") ||
|
|
!scumm_strnicmp(location, "plaza1", 6) ||
|
|
!scumm_stricmp(location, "estgrotta") ||
|
|
!scumm_stricmp(location, "intgrottadopo") ||
|
|
!scumm_stricmp(location, "endtgz") ||
|
|
!scumm_stricmp(location, "common")) {
|
|
|
|
_vm->_midiPlayer->stop();
|
|
_musicData1 = 1;
|
|
|
|
debugC(2, kDebugLocation, "changeLocation: music stopped");
|
|
}
|
|
|
|
// WORKAROUND: this if-statement has been added to avoid crashes caused by
|
|
// execution of label jobs after a location switch. The other workaround in
|
|
// Parallaction::runGame should have been rendered useless by this one.
|
|
if (_jDrawLabel != NULL) {
|
|
removeJob(_jDrawLabel);
|
|
removeJob(_jEraseLabel);
|
|
_jDrawLabel = NULL;
|
|
_jEraseLabel = NULL;
|
|
}
|
|
|
|
|
|
_hoverZone = NULL;
|
|
if (_engineFlags & kEngineMouse) {
|
|
changeCursor( kCursorArrow );
|
|
debugC(2, kDebugLocation, "changeLocation: changed cursor");
|
|
}
|
|
|
|
strcpy(_newLocation, location);
|
|
|
|
removeNode(&_yourself._zone._node);
|
|
debugC(2, kDebugLocation, "changeLocation: removed character from the animation list");
|
|
|
|
freeLocation();
|
|
debugC(1, kDebugLocation, "changeLocation: old location free'd");
|
|
|
|
|
|
char *tmp = strchr(_newLocation, '.');
|
|
if (tmp) {
|
|
*tmp = '\0';
|
|
|
|
if (!scumm_strnicmp(tmp+1, "slide", 5)) {
|
|
char filename[200];
|
|
sprintf(filename, "%s.slide", _newLocation);
|
|
|
|
_vm->_graphics->loadBackground(filename, Graphics::kBitBack);
|
|
_vm->_graphics->palUnk0(_palette);
|
|
_vm->_graphics->copyScreen(Graphics::kBitBack, Graphics::kBitFront);
|
|
|
|
debugC(1, kDebugLocation, "changeLocation: new background set");
|
|
|
|
_vm->_graphics->_proportionalFont = false;
|
|
_vm->_graphics->setFont("slide");
|
|
|
|
uint16 _ax = strlen(_slideText[0]);
|
|
_ax <<= 3; // text width
|
|
uint16 _dx = (SCREEN_WIDTH - _ax) >> 1; // center text
|
|
_vm->_graphics->displayString(_dx, 14, _slideText[0]); // displays text on screen
|
|
|
|
waitUntilLeftClick();
|
|
|
|
debugC(2, kDebugLocation, "changeLocation: intro text shown");
|
|
|
|
tmp = strchr(tmp+1, '.');
|
|
strcpy(_newLocation, tmp+1);
|
|
tmp = strchr(_newLocation, '.');
|
|
|
|
if (tmp) {
|
|
*tmp = '\0';
|
|
changeCharacter(tmp+1);
|
|
strcpy(_characterName, tmp+1);
|
|
}
|
|
|
|
} else {
|
|
changeCharacter(tmp+1);
|
|
strcpy(_characterName, tmp+1);
|
|
}
|
|
|
|
debugC(2, kDebugLocation, "changeLocation: character changed to '%s'", _characterName);
|
|
}
|
|
|
|
addNode(&_animations, &_yourself._zone._node);
|
|
debugC(2, kDebugLocation, "changeLocation: new character added to the animation list");
|
|
|
|
strcpy(_saveData1, _newLocation);
|
|
|
|
parseLocation(_newLocation);
|
|
_vm->_graphics->copyScreen(Graphics::kBitBack, Graphics::kBit2);
|
|
debugC(1, kDebugLocation, "changeLocation: new location '%s' parsed", _newLocation);
|
|
|
|
_yourself._zone.pos._oldposition._x = -1000;
|
|
_yourself._zone.pos._oldposition._y = -1000;
|
|
|
|
_yourself.field_50 = 0;
|
|
if (_firstPosition._x != -1000) {
|
|
_yourself._zone.pos._position._x = _firstPosition._x;
|
|
_yourself._zone.pos._position._y = _firstPosition._y;
|
|
_yourself._frame = _firstFrame;
|
|
_firstPosition._y = -1000;
|
|
_firstPosition._x = -1000;
|
|
|
|
debugC(2, kDebugLocation, "changeLocation: initial position set to x: %i, y: %i, f: %i", _firstPosition._x, _firstPosition._y, _firstFrame);
|
|
}
|
|
|
|
byte palette[PALETTE_SIZE];
|
|
for (uint16 _si = 0; _si < PALETTE_SIZE; _si++) palette[_si] = 0;
|
|
_vm->_graphics->palUnk0(palette);
|
|
_vm->_graphics->copyScreen(Graphics::kBitBack, Graphics::kBitFront);
|
|
if (_locationCommands) {
|
|
runCommands(_locationCommands);
|
|
runJobs();
|
|
_vm->_graphics->swapBuffers();
|
|
runJobs();
|
|
_vm->_graphics->swapBuffers();
|
|
}
|
|
|
|
if (_locationComment) {
|
|
doLocationEnterTransition();
|
|
debugC(2, kDebugLocation, "changeLocation: shown location comment");
|
|
}
|
|
|
|
runJobs();
|
|
_vm->_graphics->swapBuffers();
|
|
|
|
_vm->_graphics->palUnk0(_palette);
|
|
if (_locationACommands) {
|
|
runCommands(_locationACommands);
|
|
debugC(1, kDebugLocation, "changeLocation: location acommands run");
|
|
}
|
|
|
|
debugC(1, kDebugLocation, "changeLocation completed");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
// displays transition before a new location
|
|
//
|
|
// clears screen (in white??)
|
|
// shows location comment (if any)
|
|
// waits for mouse click
|
|
// fades towards game palette
|
|
//
|
|
// THE FINAL PALETTE IS NOT THE SAME AS THE MAIN PALETTE!!!!!!
|
|
//
|
|
void Parallaction::doLocationEnterTransition() {
|
|
debugC(1, kDebugLocation, "doLocationEnterTransition");
|
|
|
|
byte v60[PALETTE_SIZE];
|
|
if (_localFlags[_currentLocationIndex] & kFlagsVisited) return; // visited
|
|
|
|
_vm->_graphics->buildBWPalette(v60);
|
|
_vm->_graphics->setPalette(v60);
|
|
|
|
jobRunScripts(NULL, NULL);
|
|
jobEraseAnimations(NULL, NULL);
|
|
jobDisplayAnimations(NULL, NULL);
|
|
|
|
_vm->_graphics->setFont("comic");
|
|
_vm->_graphics->swapBuffers();
|
|
_vm->_graphics->copyScreen(Graphics::kBitFront, Graphics::kBitBack);
|
|
|
|
int16 v7C, v7A;
|
|
_vm->_graphics->getStringExtent(_locationComment, 130, &v7C, &v7A);
|
|
_vm->_graphics->floodFill(0, 5, 5, 10 + v7C, 5 + v7A, Graphics::kBitFront);
|
|
_vm->_graphics->floodFill(1, 6, 6, 9 + v7C, 4 + v7A, Graphics::kBitFront);
|
|
_vm->_graphics->displayWrappedString(_locationComment, 3, 5, 130, 0);
|
|
|
|
// FIXME: ???
|
|
#if 0
|
|
do {
|
|
mouseFunc1();
|
|
} while (_mouseButtons != kMouseLeftUp);
|
|
#endif
|
|
|
|
waitUntilLeftClick();
|
|
|
|
_vm->_graphics->copyScreen(Graphics::kBitBack, Graphics::kBitFront );
|
|
|
|
// fades maximum intensity palette towards approximation of main palette
|
|
for (uint16 _si = 0; _si<6; _si++) {
|
|
waitTime( 1 );
|
|
_vm->_graphics->quickFadePalette(v60);
|
|
_vm->_graphics->setPalette(v60);
|
|
}
|
|
|
|
debugC(1, kDebugLocation, "doLocationEnterTransition completed");
|
|
|
|
return;
|
|
}
|
|
|
|
void mouseFunc1() {
|
|
// FIXME: implement this
|
|
}
|
|
|
|
} // namespace Parallaction
|