diff options
author | Nicola Mettifogo | 2007-08-24 20:14:51 +0000 |
---|---|---|
committer | Nicola Mettifogo | 2007-08-24 20:14:51 +0000 |
commit | 37cdd1c69ad4a1750c3041d5cceeed676da9061f (patch) | |
tree | dfd19d7e1b667e16d319c5e599907c61ba16e18e /engines/parallaction/parallaction.cpp | |
parent | 2bfc4466df238fea2162466cca06de88c773e6c5 (diff) | |
download | scummvm-rg350-37cdd1c69ad4a1750c3041d5cceeed676da9061f.tar.gz scummvm-rg350-37cdd1c69ad4a1750c3041d5cceeed676da9061f.tar.bz2 scummvm-rg350-37cdd1c69ad4a1750c3041d5cceeed676da9061f.zip |
First step in restructuring engine code:
- code has been consolidated in fewer files
- new table-driven parsers/execution
- some functions has been pushed down the engine hierarchy
- Parallaction_br now inherits from Parallaction_ns
svn-id: r28711
Diffstat (limited to 'engines/parallaction/parallaction.cpp')
-rw-r--r-- | engines/parallaction/parallaction.cpp | 584 |
1 files changed, 422 insertions, 162 deletions
diff --git a/engines/parallaction/parallaction.cpp b/engines/parallaction/parallaction.cpp index af0a34e409..dedcddb8c7 100644 --- a/engines/parallaction/parallaction.cpp +++ b/engines/parallaction/parallaction.cpp @@ -53,7 +53,6 @@ char _saveData1[30] = { '\0' }; uint16 _language = 0; char _slideText[2][40]; uint32 _engineFlags = 0; -Zone *_activeZone = NULL; uint16 _score = 1; @@ -128,11 +127,9 @@ Parallaction::~Parallaction() { delete _globalTable; delete _callableNames; - delete _commandsNames; - delete _instructionNames; + delete _zoneTypeNames; delete _zoneFlagNames; - delete _locationStmt; _animations.remove(&_char._ani); @@ -168,6 +165,7 @@ int Parallaction::init() { _backgroundInfo = 0; _pathBuffer = 0; + _activeZone = 0; _screenSize = _screenWidth * _screenHeight; @@ -178,8 +176,6 @@ int Parallaction::init() { memset(_locationNames, 0, 120*32); - initOpcodes(); - initInventory(); // needs to be pushed into subclass _animations.push_front(&_char._ani); @@ -840,7 +836,7 @@ void Table::addData(const char* s) { } -int Table::lookup(const char* s) { +uint16 Table::lookup(const char* s) { for (uint16 i = 0; i < _used; i++) { if (!scumm_stricmp(_data[i], s)) return i + 1; @@ -849,14 +845,12 @@ int Table::lookup(const char* s) { return notFound; } -void Parallaction::pushParserTables(const Opcode* opcodes, Table *statements) { - +void Parallaction::pushParserTables(OpcodeSet *opcodes, Table *statements) { _opcodes.push(_currentOpcodes); _statements.push(_currentStatements); _currentOpcodes = opcodes; _currentStatements = statements; - } void Parallaction::popParserTables() { @@ -870,161 +864,427 @@ void Parallaction::parseStatement() { assert(_currentOpcodes != 0); _lookup = _currentStatements->lookup(_tokens[0]); - (this->*(_currentOpcodes[_lookup]))(); + (*(*_currentOpcodes)[_lookup])(); +} + + + + +Animation *Parallaction::findAnimation(const char *name) { + + for (AnimationList::iterator it = _animations.begin(); it != _animations.end(); it++) + if (!scumm_stricmp((*it)->_label._text, name)) return *it; + + return NULL; +} + +void Parallaction::freeAnimations() { + _animations.clear(); + return; +} + +int compareAnimationZ(const AnimationPointer &a1, const AnimationPointer &a2) { + if (a1->_z == a2->_z) return 0; + return (a1->_z < a2->_z ? -1 : 1); +} + +void Parallaction::sortAnimations() { + _char._ani._z = _char._ani.height() + _char._ani._top; + _animations.sort(compareAnimationZ); + return; +} + + +void Parallaction::allocateLocationSlot(const char *name) { + // 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], name)) { + _currentLocationIndex = _di; + } + _di++; + } + + if (_di == 120) + error("No more location slots available. Please report this immediately to ScummVM team."); + + if (_currentLocationIndex == -1) { + strcpy(_locationNames[_numLocations], name); + _currentLocationIndex = _numLocations; + + _numLocations++; + _locationNames[_numLocations][0] = '\0'; + _localFlags[_numLocations] = 0; + } else { + _localFlags[_currentLocationIndex] |= kFlagsVisited; // 'visited' + } +} + + + +void Parallaction::freeLocation() { + debugC(7, kDebugLocation, "freeLocation"); + + _soundMan->stopSfx(0); + _soundMan->stopSfx(1); + _soundMan->stopSfx(2); + _soundMan->stopSfx(3); + + if (_localFlagNames) + delete _localFlagNames; + + // HACK: prevents leakage. A routine like this + // should allocate memory at all, though. + if ((_engineFlags & kEngineQuit) == 0) { + _localFlagNames = new Table(120); + _localFlagNames->addData("visited"); + } + + _location._walkNodes.clear(); + + freeZones(); + freeAnimations(); + + if (_location._comment) { + free(_location._comment); + } + _location._comment = NULL; + + _location._commands.clear(); + _location._aCommands.clear(); + + return; +} + + + + +void Parallaction::freeBackground() { + + if (!_backgroundInfo) + return; + + _backgroundInfo->bg.free(); + _backgroundInfo->mask.free(); + _backgroundInfo->path.free(); + + _pathBuffer = 0; + +} + +void Parallaction::setBackground(const char* name, const char* mask, const char* path) { + + _disk->loadScenery(*_backgroundInfo, name, mask, path); + + _gfx->setPalette(_backgroundInfo->palette); + _gfx->_palette.clone(_backgroundInfo->palette); + _gfx->setBackground(&_backgroundInfo->bg); + + if (_backgroundInfo->mask.data) + _gfx->setMask(&_backgroundInfo->mask); + + if (_backgroundInfo->path.data) + _pathBuffer = &_backgroundInfo->path; + + return; +} + +void Parallaction::showLocationComment(const char *text, bool end) { + + _gfx->setFont(_dialogueFont); + + int16 w, h; + _gfx->getStringExtent(const_cast<char*>(text), 130, &w, &h); + + Common::Rect r(w + (end ? 5 : 10), h + 5); + r.moveTo(5, 5); + + _gfx->floodFill(Gfx::kBitFront, r, 0); + r.grow(-2); + _gfx->floodFill(Gfx::kBitFront, r, 1); + _gfx->displayWrappedString(const_cast<char*>(text), 3, 5, 0, 130); + + _gfx->updateScreen(); + + return; +} + +void Parallaction::switchBackground(const char* background, const char* mask) { +// printf("switchBackground(%s)", name); + + Palette pal; + + uint16 v2 = 0; + if (!scumm_stricmp(background, "final")) { + _gfx->clearScreen(Gfx::kBitBack); + for (uint16 _si = 0; _si <= 32; _si++) { + pal.setEntry(_si, v2, v2, v2); + v2 += 4; + } + + g_system->delayMillis(20); + _gfx->setPalette(pal); + _gfx->updateScreen(); + } + + setBackground(background, mask, mask); + + return; +} + +extern Zone *_hoverZone; +extern Job *_jDrawLabel; +extern Job *_jEraseLabel; + +void Parallaction::showSlide(const char *name) { + + BackgroundInfo info; + + _disk->loadSlide(info, name); + + // TODO: avoid using screen buffers for displaying slides. Using a generic buffer + // allows for positioning of graphics as needed by Big Red Adventure. + // The main problem lies with menu, which relies on multiple buffers, mainly because + // it is crappy code. + _gfx->setBackground(&info.bg); + _gfx->setPalette(info.palette); + _gfx->copyScreen(Gfx::kBitBack, Gfx::kBitFront); + + info.bg.free(); + info.mask.free(); + info.path.free(); + + return; +} + +/* + changeLocation handles transitions between locations, and is able to display slides + between one and the other. The input parameter 'location' exists in some flavours: + + 1 - [S].slide.[L]{.[C]} + 2 - [L]{.[C]} + + where: + + [S] is the slide to be shown + [L] is the location to switch to (immediately in case 2, or right after slide [S] in case 1) + [C] is the character to be selected, and is optional + + The routine tells one form from the other by searching for the '.slide.' + + NOTE: there exists one script in which [L] is not used in the case 1, but its use + is commented out, and would definitely crash the current implementation. +*/ +void Parallaction::changeLocation(char *location) { + debugC(1, kDebugLocation, "changeLocation(%s)", location); + + _soundMan->playLocationMusic(location); + + // 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 & kEngineBlockInput) { + changeCursor( kCursorArrow ); + } + + _animations.remove(&_char._ani); + + freeLocation(); + char buf[100]; + strcpy(buf, location); + + Common::StringList list; + char *tok = strtok(location, "."); + while (tok) { + list.push_back(tok); + tok = strtok(NULL, "."); + } + + if (list.size() < 1 || list.size() > 4) + error("changeLocation: ill-formed location string '%s'", location); + + if (list.size() > 1) { + if (list[1] == "slide") { + showSlide(list[0].c_str()); + _gfx->setFont(_menuFont); + _gfx->displayCenteredString(14, _slideText[0]); // displays text on screen + _gfx->updateScreen(); + waitUntilLeftClick(); + + list.remove_at(0); // removes slide name + list.remove_at(0); // removes 'slide' + } + + // list is now only [L].{[C]} (see above comment) + if (list.size() == 2) { + changeCharacter(list[1].c_str()); + strcpy(_characterName, list[1].c_str()); + } + } + + _animations.push_front(&_char._ani); + + strcpy(_saveData1, list[0].c_str()); + parseLocation(list[0].c_str()); + + _char._ani._oldPos.x = -1000; + _char._ani._oldPos.y = -1000; + + _char._ani.field_50 = 0; + if (_location._startPosition.x != -1000) { + _char._ani._left = _location._startPosition.x; + _char._ani._top = _location._startPosition.y; + _char._ani._frame = _location._startFrame; + _location._startPosition.y = -1000; + _location._startPosition.x = -1000; + } + + + _gfx->copyScreen(Gfx::kBitBack, Gfx::kBitFront); + _gfx->copyScreen(Gfx::kBitBack, Gfx::kBit2); + _gfx->setBlackPalette(); + _gfx->updateScreen(); + + if (_location._commands.size() > 0) { + runCommands(_location._commands); + runJobs(); + _gfx->swapBuffers(); + runJobs(); + _gfx->swapBuffers(); + } + + if (_location._comment) { + doLocationEnterTransition(); + } + + runJobs(); + _gfx->swapBuffers(); + + _gfx->setPalette(_gfx->_palette); + if (_location._aCommands.size() > 0) { + runCommands(_location._aCommands); + } + + if (_hasLocationSound) + _soundMan->playSfx(_locationSound, 0, true); + + debugC(1, kDebugLocation, "changeLocation() done"); + + return; + } -void Parallaction::initOpcodes() { - - static const Opcode op0[] = { - INSTRUCTION_PARSER(defLocal), // invalid opcode -> local definition - INSTRUCTION_PARSER(animation), // on - INSTRUCTION_PARSER(animation), // off - INSTRUCTION_PARSER(x), - INSTRUCTION_PARSER(y), - INSTRUCTION_PARSER(z), - INSTRUCTION_PARSER(f), - INSTRUCTION_PARSER(loop), - INSTRUCTION_PARSER(null), // endloop - INSTRUCTION_PARSER(null), // show - INSTRUCTION_PARSER(inc), - INSTRUCTION_PARSER(inc), // dec - INSTRUCTION_PARSER(set), - INSTRUCTION_PARSER(put), - INSTRUCTION_PARSER(call), - INSTRUCTION_PARSER(null), // wait - INSTRUCTION_PARSER(animation), // start - INSTRUCTION_PARSER(sound), - INSTRUCTION_PARSER(move) - }; - - _instructionParsers = op0; - - - static const Opcode op1[] = { - INSTRUCTION_OPCODE(invalid), - INSTRUCTION_OPCODE(on), - INSTRUCTION_OPCODE(off), - INSTRUCTION_OPCODE(set), // x - INSTRUCTION_OPCODE(set), // y - INSTRUCTION_OPCODE(set), // z - INSTRUCTION_OPCODE(set), // f - INSTRUCTION_OPCODE(loop), - INSTRUCTION_OPCODE(endloop), - INSTRUCTION_OPCODE(null), - INSTRUCTION_OPCODE(inc), - INSTRUCTION_OPCODE(inc), // dec - INSTRUCTION_OPCODE(set), - INSTRUCTION_OPCODE(put), - INSTRUCTION_OPCODE(call), - INSTRUCTION_OPCODE(wait), - INSTRUCTION_OPCODE(start), - INSTRUCTION_OPCODE(sound), - INSTRUCTION_OPCODE(move), - INSTRUCTION_OPCODE(end) - }; - - _vm->_instructionOpcodes = op1; - - static const Opcode op2[] = { - COMMAND_PARSER(invalid), - COMMAND_PARSER(flags), // set - COMMAND_PARSER(flags), // clear - COMMAND_PARSER(animation), // start - COMMAND_PARSER(zone), // speak - COMMAND_PARSER(zone), // get - COMMAND_PARSER(location), // location - COMMAND_PARSER(zone), // open - COMMAND_PARSER(zone), // close - COMMAND_PARSER(zone), // on - COMMAND_PARSER(zone), // off - COMMAND_PARSER(call), // call - COMMAND_PARSER(flags), // toggle - COMMAND_PARSER(drop), // drop - COMMAND_PARSER(null), // quit - COMMAND_PARSER(move), // move - COMMAND_PARSER(animation), // stop - COMMAND_PARSER(endcommands), // endcommands - COMMAND_PARSER(endcommands) // endzone - }; - - _commandParsers = op2; - - static const Opcode op3[] = { - COMMAND_OPCODE(invalid), - COMMAND_OPCODE(set), - COMMAND_OPCODE(clear), - COMMAND_OPCODE(start), - COMMAND_OPCODE(speak), - COMMAND_OPCODE(get), - COMMAND_OPCODE(location), - COMMAND_OPCODE(open), - COMMAND_OPCODE(close), - COMMAND_OPCODE(on), - COMMAND_OPCODE(off), - COMMAND_OPCODE(call), - COMMAND_OPCODE(toggle), - COMMAND_OPCODE(drop), - COMMAND_OPCODE(quit), - COMMAND_OPCODE(move), - COMMAND_OPCODE(stop) - }; - - _commandOpcodes = op3; - - - static const Opcode op4[] = { - LOCATION_PARSER(invalid), - LOCATION_PARSER(endlocation), - LOCATION_PARSER(location), - LOCATION_PARSER(disk), - LOCATION_PARSER(nodes), - LOCATION_PARSER(zone), - LOCATION_PARSER(animation), - LOCATION_PARSER(localflags), - LOCATION_PARSER(commands), - LOCATION_PARSER(acommands), - LOCATION_PARSER(flags), - LOCATION_PARSER(comment), - LOCATION_PARSER(endcomment), - LOCATION_PARSER(sound), - LOCATION_PARSER(music), - LOCATION_PARSER(redundant) // for redundant endanimation - }; - - _locationParsers = op4; - - - static const Opcode op5[] = { - ZONE_PARSER(invalid), - ZONE_PARSER(limits), - ZONE_PARSER(moveto), - ZONE_PARSER(type), - ZONE_PARSER(commands), - ZONE_PARSER(label), - ZONE_PARSER(flags), - ZONE_PARSER(endzone) - }; - - _locationZoneParsers = op5; - - static const Opcode op6[] = { - ANIM_PARSER(invalid), - ANIM_PARSER(script), - ANIM_PARSER(commands), - ANIM_PARSER(type), - ANIM_PARSER(label), - ANIM_PARSER(flags), - ANIM_PARSER(file), - ANIM_PARSER(position), - ANIM_PARSER(moveto), - ANIM_PARSER(endanimation) - }; - - _locationAnimParsers = op6; - - _currentOpcodes = 0; - _currentStatements = 0; +// displays transition before a new location +// +// clears screen (in white??) +// shows location comment (if any) +// waits for mouse click +// fades towards game palette +// +void Parallaction::doLocationEnterTransition() { + debugC(1, kDebugLocation, "doLocationEnterTransition"); + + if (_localFlags[_currentLocationIndex] & kFlagsVisited) { + debugC(3, kDebugLocation, "skipping location transition"); + return; // visited + } + + Palette pal(_gfx->_palette); + pal.makeGrayscale(); + _gfx->setPalette(pal); + + jobRunScripts(NULL, NULL); + jobEraseAnimations(NULL, NULL); + jobDisplayAnimations(NULL, NULL); + + _gfx->swapBuffers(); + _gfx->copyScreen(Gfx::kBitFront, Gfx::kBitBack); + + showLocationComment(_location._comment, false); + waitUntilLeftClick(); + + _gfx->copyScreen(Gfx::kBitBack, Gfx::kBitFront ); + + // fades maximum intensity palette towards approximation of main palette + for (uint16 _si = 0; _si<6; _si++) { + pal.fadeTo(_gfx->_palette, 4); + _gfx->setPalette(pal); + waitTime( 1 ); + _gfx->updateScreen(); + } + debugC(1, kDebugLocation, "doLocationEnterTransition completed"); + + return; +} + + + +Zone *Parallaction::findZone(const char *name) { + + for (ZoneList::iterator it = _zones.begin(); it != _zones.end(); it++) { + if (!scumm_stricmp((*it)->_label._text, name)) return *it; + } + + return findAnimation(name); } + +void Parallaction::freeZones() { + debugC(1, kDebugLocation, "freeZones: kEngineQuit = %i", _engineFlags & kEngineQuit); + + ZoneList::iterator it = _zones.begin(); + + while ( it != _zones.end() ) { + + Zone* z = *it; + + // WORKAROUND: this huge condition is needed because we made TypeData a collection of structs + // instead of an union. So, merge->_obj1 and get->_icon were just aliases in the original engine, + // but we need to check it separately here. The same workaround is applied in hitZone. + if (((z->_top == -1) || + ((z->_left == -2) && ( + (((z->_type & 0xFFFF) == kZoneMerge) && ((isItemInInventory(MAKE_INVENTORY_ID(z->u.merge->_obj1)) != 0) || (isItemInInventory(MAKE_INVENTORY_ID(z->u.merge->_obj2)) != 0))) || + (((z->_type & 0xFFFF) == kZoneGet) && ((isItemInInventory(MAKE_INVENTORY_ID(z->u.get->_icon)) != 0))) + ))) && + ((_engineFlags & kEngineQuit) == 0)) { + + debugC(1, kDebugLocation, "freeZones preserving zone '%s'", z->_label._text); + + it++; + + } else + + it = _zones.erase(it); + + } + + return; +} + + + + + + + + + + + + } // namespace Parallaction |