346 lines
8.7 KiB
C++
346 lines
8.7 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 3 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, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
*/
|
|
|
|
#include "engines/nancy/nancy.h"
|
|
#include "engines/nancy/sound.h"
|
|
#include "engines/nancy/resource.h"
|
|
#include "engines/nancy/util.h"
|
|
|
|
#include "engines/nancy/action/miscrecords.h"
|
|
|
|
#include "engines/nancy/state/scene.h"
|
|
|
|
#include "common/events.h"
|
|
#include "common/config-manager.h"
|
|
|
|
namespace Nancy {
|
|
namespace Action {
|
|
|
|
void PaletteThisScene::readData(Common::SeekableReadStream &stream) {
|
|
_paletteID = stream.readByte();
|
|
_unknownEnum = stream.readByte();
|
|
_paletteStart = stream.readUint16LE();
|
|
_paletteSize = stream.readUint16LE();
|
|
}
|
|
|
|
void PaletteThisScene::execute() {
|
|
NancySceneState.getSceneInfo().paletteID = _paletteID;
|
|
const State::Scene::SceneSummary &ssum = NancySceneState.getSceneSummary();
|
|
|
|
if (_unknownEnum > 1 && _unknownEnum < 3) {
|
|
// Not sure what the difference is between the 3 types
|
|
NancySceneState.getViewport().setPalette(ssum.palettes[_paletteID], _paletteStart, _paletteSize);
|
|
} else {
|
|
NancySceneState.getViewport().setPalette(ssum.palettes[_paletteID]);
|
|
}
|
|
|
|
finishExecution();
|
|
}
|
|
|
|
void PaletteNextScene::readData(Common::SeekableReadStream &stream) {
|
|
// Structure is the same as PaletteThisScene, but the original engine only uses the palette ID
|
|
_paletteID = stream.readByte();
|
|
stream.skip(5);
|
|
}
|
|
|
|
void PaletteNextScene::execute() {
|
|
NancySceneState.getNextSceneInfo().paletteID = _paletteID;
|
|
_isDone = true;
|
|
}
|
|
|
|
void LightningOn::readData(Common::SeekableReadStream &stream) {
|
|
_distance = stream.readSint16LE();
|
|
_pulseTime = stream.readUint16LE();
|
|
_rgbPercent = stream.readSint16LE();
|
|
stream.skip(4);
|
|
}
|
|
|
|
void SpecialEffect::readData(Common::SeekableReadStream &stream) {
|
|
if (g_nancy->getGameType() <= kGameTypeNancy6) {
|
|
_type = stream.readByte();
|
|
_fadeToBlackTime = stream.readUint16LE();
|
|
_frameTime = stream.readUint16LE();
|
|
} else {
|
|
_type = stream.readByte();
|
|
_totalTime = stream.readUint16LE();
|
|
_fadeToBlackTime = stream.readUint16LE();
|
|
readRect(stream, _rect);
|
|
}
|
|
}
|
|
|
|
void SpecialEffect::execute() {
|
|
if (g_nancy->getGameType() <= kGameTypeNancy6) {
|
|
NancySceneState.specialEffect(_type, _fadeToBlackTime, _frameTime);
|
|
} else {
|
|
NancySceneState.specialEffect(_type, _totalTime, _fadeToBlackTime, _rect);
|
|
}
|
|
|
|
_isDone = true;
|
|
}
|
|
|
|
void LightningOn::execute() {
|
|
NancySceneState.beginLightning(_distance, _pulseTime, _rgbPercent);
|
|
_isDone = true;
|
|
}
|
|
|
|
void TextBoxWrite::readData(Common::SeekableReadStream &stream) {
|
|
int16 size = stream.readSint16LE();
|
|
|
|
if (size > 10000) {
|
|
error("Action Record atTextboxWrite has too many text box chars: %d", size);
|
|
}
|
|
|
|
if (size == -1) {
|
|
Common::String stringID;
|
|
readFilename(stream, stringID);
|
|
|
|
const CVTX *autotext = (const CVTX *)g_nancy->getEngineData("AUTOTEXT");
|
|
assert(autotext);
|
|
|
|
_text = autotext->texts[stringID];
|
|
} else {
|
|
char *buf = new char[size];
|
|
stream.read(buf, size);
|
|
buf[size - 1] = '\0';
|
|
|
|
assembleTextLine(buf, _text, size);
|
|
|
|
delete[] buf;
|
|
}
|
|
}
|
|
|
|
void TextBoxWrite::execute() {
|
|
auto &tb = NancySceneState.getTextbox();
|
|
tb.clear();
|
|
tb.addTextLine(_text);
|
|
tb.setVisible(true);
|
|
finishExecution();
|
|
}
|
|
|
|
void TextboxClear::readData(Common::SeekableReadStream &stream) {
|
|
stream.skip(1);
|
|
}
|
|
|
|
void TextboxClear::execute() {
|
|
NancySceneState.getTextbox().clear();
|
|
finishExecution();
|
|
}
|
|
|
|
void BumpPlayerClock::readData(Common::SeekableReadStream &stream) {
|
|
_relative = stream.readByte();
|
|
_hours = stream.readUint16LE();
|
|
_minutes = stream.readUint16LE();
|
|
}
|
|
|
|
void BumpPlayerClock::execute() {
|
|
NancySceneState.setPlayerTime(_hours * 3600000 + _minutes * 60000, _relative);
|
|
finishExecution();
|
|
}
|
|
|
|
void SaveContinueGame::readData(Common::SeekableReadStream &stream) {
|
|
stream.skip(1);
|
|
}
|
|
|
|
void SaveContinueGame::execute() {
|
|
g_nancy->secondChance();
|
|
_isDone = true;
|
|
}
|
|
|
|
void TurnOffMainRendering::readData(Common::SeekableReadStream &stream) {
|
|
stream.skip(1);
|
|
}
|
|
|
|
void TurnOnMainRendering::readData(Common::SeekableReadStream &stream) {
|
|
stream.skip(1);
|
|
}
|
|
|
|
void ResetAndStartTimer::readData(Common::SeekableReadStream &stream) {
|
|
stream.skip(1);
|
|
}
|
|
|
|
void ResetAndStartTimer::execute() {
|
|
NancySceneState.resetAndStartTimer();
|
|
_isDone = true;
|
|
}
|
|
|
|
void StopTimer::readData(Common::SeekableReadStream &stream) {
|
|
stream.skip(1);
|
|
}
|
|
|
|
void StopTimer::execute() {
|
|
NancySceneState.stopTimer();
|
|
_isDone = true;
|
|
}
|
|
|
|
void GotoMenu::readData(Common::SeekableReadStream &stream) {
|
|
stream.skip(1);
|
|
}
|
|
|
|
void GotoMenu::execute() {
|
|
//NancySceneState.setDestroyOnExit();
|
|
g_nancy->setState(NancyState::kMainMenu);
|
|
|
|
_isDone = true;
|
|
}
|
|
|
|
void LoseGame::readData(Common::SeekableReadStream &stream) {
|
|
stream.skip(1);
|
|
}
|
|
|
|
void LoseGame::execute() {
|
|
g_nancy->_sound->stopAndUnloadSceneSpecificSounds();
|
|
NancySceneState.setDestroyOnExit();
|
|
|
|
if (!ConfMan.hasKey("original_menus") || ConfMan.getBool("original_menus")) {
|
|
g_nancy->setState(NancyState::kMainMenu);
|
|
} else {
|
|
Common::Event ev;
|
|
ev.type = Common::EVENT_RETURN_TO_LAUNCHER;
|
|
g_system->getEventManager()->pushEvent(ev);
|
|
}
|
|
|
|
_isDone = true;
|
|
}
|
|
|
|
void PushScene::readData(Common::SeekableReadStream &stream) {
|
|
stream.skip(1);
|
|
}
|
|
|
|
void PushScene::execute() {
|
|
NancySceneState.pushScene();
|
|
_isDone = true;
|
|
}
|
|
|
|
void PopScene::readData(Common::SeekableReadStream &stream) {
|
|
stream.skip(1);
|
|
}
|
|
|
|
void PopScene::execute() {
|
|
NancySceneState.popScene();
|
|
_isDone = true;
|
|
}
|
|
|
|
void WinGame::readData(Common::SeekableReadStream &stream) {
|
|
stream.skip(1);
|
|
}
|
|
|
|
void WinGame::execute() {
|
|
// Set ConfMan value that will stay persistent across future playthroughs.
|
|
// Default value in original is StillWorkingOnIt, but we just don't set it instead.
|
|
ConfMan.set("PlayerWonTheGame", "AcedTheGame", ConfMan.getActiveDomainName());
|
|
ConfMan.flushToDisk();
|
|
|
|
g_nancy->_sound->stopAndUnloadSceneSpecificSounds();
|
|
NancySceneState.setDestroyOnExit();
|
|
g_nancy->setState(NancyState::kCredits, NancyState::kMainMenu);
|
|
|
|
_isDone = true;
|
|
}
|
|
|
|
void HintSystem::readData(Common::SeekableReadStream &stream) {
|
|
_characterID = stream.readByte();
|
|
_genericSound.readNormal(stream);
|
|
}
|
|
|
|
void HintSystem::execute() {
|
|
switch (_state) {
|
|
case kBegin: {
|
|
uint16 difficulty = NancySceneState.getDifficulty();
|
|
selectHint();
|
|
_genericSound.name = selectedHint->soundIDs[difficulty];
|
|
|
|
NancySceneState.getTextbox().clear();
|
|
NancySceneState.getTextbox().addTextLine(g_nancy->getStaticData().hintTexts[selectedHint->textID * 3 + difficulty]);
|
|
|
|
g_nancy->_sound->loadSound(_genericSound);
|
|
g_nancy->_sound->playSound(_genericSound);
|
|
_state = kRun;
|
|
break;
|
|
}
|
|
case kRun:
|
|
if (!g_nancy->_sound->isSoundPlaying(_genericSound)) {
|
|
g_nancy->_sound->stopSound(_genericSound);
|
|
_state = kActionTrigger;
|
|
} else {
|
|
break;
|
|
}
|
|
|
|
// fall through
|
|
case kActionTrigger:
|
|
NancySceneState.useHint(_characterID, _hintID);
|
|
NancySceneState.getTextbox().clear();
|
|
|
|
NancySceneState.changeScene(selectedHint->sceneChange);
|
|
|
|
_isDone = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
void HintSystem::selectHint() {
|
|
if (NancySceneState.getHintsRemaining() == 0) {
|
|
selectedHint = &g_nancy->getStaticData().hints[_characterID][0];
|
|
}
|
|
|
|
// Start from 1 since the first hint is always the "I give up" option
|
|
for (uint i = 1; i < g_nancy->getStaticData().hints[_characterID].size(); ++i) {
|
|
const auto &hint = g_nancy->getStaticData().hints[_characterID][i];
|
|
|
|
bool isSatisfied = true;
|
|
|
|
for (const auto &cond : hint.conditions) {
|
|
switch (cond.type) {
|
|
case (byte)StaticDataConditionType::kEvent :
|
|
if (!NancySceneState.getEventFlag(cond.label, cond.flag)) {
|
|
isSatisfied = false;
|
|
}
|
|
|
|
break;
|
|
case (byte)StaticDataConditionType::kInventory :
|
|
if (NancySceneState.hasItem(cond.label) != cond.flag) {
|
|
isSatisfied = false;
|
|
}
|
|
|
|
break;
|
|
case (byte)StaticDataConditionType::kDifficulty :
|
|
if ( (NancySceneState.getDifficulty() != cond.label && cond.flag != 0) ||
|
|
(NancySceneState.getDifficulty() == cond.label && cond.flag == 0) ) {
|
|
isSatisfied = false;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
if (!isSatisfied) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (isSatisfied) {
|
|
selectedHint = &hint;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
} // End of namespace Action
|
|
} // End of namespace Nancy
|