Files
scummvm-cursorfix/engines/nancy/action/miscrecords.cpp
2026-02-02 04:50:13 +01:00

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