scummvm/engines/myst3/state.cpp
2012-01-13 17:51:45 +01:00

287 lines
8.0 KiB
C++

/* ResidualVM - A 3D game interpreter
*
* ResidualVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the AUTHORS
* 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.
*
*/
#include "engines/myst3/state.h"
#include "common/savefile.h"
namespace Myst3 {
GameState::GameState(Myst3Engine *vm):
_vm(vm) {
#define VAR(var, x, unk) _descriptions.setVal(var, Description(var, #x, unk));
VAR(61, LocationAge, false)
VAR(62, LocationRoom, false)
VAR(63, LocationNode, false)
VAR(64, BookSavedAge, false)
VAR(65, BookSavedRoom, false)
VAR(66, BookSavedNode, false)
VAR(67, MenuSavedAge, false)
VAR(68, MenuSavedRoom, false)
VAR(69, MenuSavedNode, false)
VAR(115, SunspotIntensity, false)
VAR(116, SunspotColor, false)
VAR(117, SunspotRadius, false)
VAR(142, MovieOverrideStartFrame, true)
VAR(143, MovieOverrideEndFrame, true)
VAR(144, MovieVolume1, true)
VAR(145, MovieVolume2, true)
VAR(146, MovieUnk146, true)
VAR(147, MovieUnk147, true)
VAR(148, MovieUnk148, true)
VAR(149, MovieConditionBit, true)
VAR(150, MoviePreloadToMemory, true)
VAR(151, MovieScriptDriven, true)
VAR(152, MovieNextFrameSetVar, true)
VAR(153, MovieNextFrameGetVar, true)
VAR(154, MovieStartFrameVar, true)
VAR(155, MovieEndFrameVar, true)
VAR(156, MovieForce2d, true)
VAR(157, MovieVolumeVar, true)
VAR(158, MovieSoundHeading, true)
VAR(159, MoviePanningStrenght, true)
VAR(160, MovieSynchronized, true)
VAR(161, MovieUnk161, true)
VAR(162, MovieUnk162, true)
VAR(163, MovieOverrideCondition, true)
VAR(164, MovieUVar, true)
VAR(165, MovieVVar, true)
VAR(166, MovieOverridePosition, true)
VAR(167, MovieOverridePosU, true)
VAR(168, MovieOverridePosV, true)
VAR(169, MovieScale, true)
VAR(170, MovieUnk170, true)
VAR(171, MovieUnk171, true)
VAR(172, MovieUnk172, true)
VAR(173, MoviePlayingVar, true)
VAR(178, MovieUnk178, true)
VAR(189, LocationNextNode, false)
VAR(190, LocationNextRoom, false)
VAR(191, LocationNextAge, false)
VAR(277, JournalAtrusState, false)
VAR(279, JournalSaavedroState, false)
VAR(280, JournalSaavedroClosed, false)
VAR(281, JournalSaavedroOpen, false)
VAR(282, JournalSaavedroLastPage, false)
VAR(283, JournalSaavedroChapter, false)
VAR(284, JournalSaavedroPageInChapter, false)
VAR(480, BookStateTomahna, false)
VAR(481, BookStateReleeshahn, false)
VAR(1337, MenuEscapePressed, false)
VAR(1338, MenuNextAction, false)
VAR(1339, MenuLoadBack, false)
VAR(1340, MenuSaveBack, false)
VAR(1341, MenuSaveAction, false)
VAR(1342, MenuOptionsBack, false)
VAR(1350, MenuSaveLoadPageLeft, false)
VAR(1351, MenuSaveLoadPageRight, false)
VAR(1352, MenuSaveLoadSelectedItem, false)
VAR(1353, MenuSaveLoadCurrentPage, false)
#undef VAR
newGame();
}
GameState::~GameState() {
}
void GameState::syncWithSaveGame(Common::Serializer &s) {
if (!s.syncVersion(kSaveVersion))
error("This savegame (v%d) is too recent (max %d) please get a newer version of Residual", s.getVersion(), kSaveVersion);
s.syncAsUint32LE(_data.gameRunning);
s.syncAsUint32LE(_data.currentFrame);
s.syncAsUint32LE(_data.dword_4C2C3C);
s.syncAsUint32LE(_data.dword_4C2C40);
s.syncAsUint32LE(_data.dword_4C2C44);
s.syncAsUint32LE(_data.dword_4C2C48);
s.syncAsUint32LE(_data.dword_4C2C4C);
s.syncAsUint32LE(_data.dword_4C2C50);
s.syncAsUint32LE(_data.dword_4C2C54);
s.syncAsUint32LE(_data.dword_4C2C58);
s.syncAsUint32LE(_data.dword_4C2C5C);
s.syncAsUint32LE(_data.dword_4C2C60);
s.syncAsUint32LE(_data.currentNodeType);
// FIXME Syncing IEE754 data is not cross platform
// Increase the savegame version and save those as integers
s.syncBytes((byte*) &_data.lookatPitch, sizeof(float));
s.syncBytes((byte*) &_data.lookatHeading, sizeof(float));
s.syncBytes((byte*) &_data.lookatFOV, sizeof(float));
s.syncBytes((byte*) &_data.pitchOffset, sizeof(float));
s.syncBytes((byte*) &_data.headingOffset, sizeof(float));
s.syncAsUint32LE(_data.limitCubeCamera);
s.syncBytes((byte*) &_data.minPitch, sizeof(float));
s.syncBytes((byte*) &_data.maxPitch, sizeof(float));
s.syncBytes((byte*) &_data.minHeading, sizeof(float));
s.syncBytes((byte*) &_data.maxHeading, sizeof(float));
s.syncAsUint32LE(_data.dword_4C2C90);
for (uint i = 0; i < 2048; i++)
s.syncAsSint32LE(_data.vars[i]);
s.syncAsUint32LE(_data.inventoryCount);
for (uint i = 0; i < 7; i++)
s.syncAsUint32LE(_data.inventoryList[i]);
for (uint i = 0; i < 256; i++)
s.syncAsByte(_data.zipDestinations[i]);
}
void GameState::newGame() {
memset(&_data, 0, sizeof(_data));
_data.version = kSaveVersion;
_data.vars[0] = 0;
_data.vars[1] = 1;
}
bool GameState::load(const Common::String &file) {
Common::InSaveFile *save = _vm->getSaveFileManager()->openForLoading(file);
Common::Serializer s = Common::Serializer(save, 0);
syncWithSaveGame(s);
delete save;
return true;
}
bool GameState::save(Common::OutSaveFile *save) {
Common::Serializer s = Common::Serializer(0, save);
syncWithSaveGame(s);
return true;
}
Common::Array<uint16> GameState::getInventory() {
Common::Array<uint16> items;
for (uint i = 0; i < _data.inventoryCount; i++)
items.push_back(_data.inventoryList[i]);
return items;
}
void GameState::updateInventory(const Common::Array<uint16> &items) {
for (uint i = 0; i < 7; i++)
_data.inventoryList[i] = 0;
for (uint i = 0; i < items.size(); i++)
_data.inventoryList[i] = items[i];
}
void GameState::checkRange(uint16 var) {
if (var < 1 || var > 2047)
error("Variable out of range %d", var);
}
int32 GameState::getVar(uint16 var) {
checkRange(var);
return _data.vars[var];
}
void GameState::setVar(uint16 var, int32 value) {
checkRange(var);
if (_descriptions.contains(var)) {
const Description &d = _descriptions.getVal(var);
if (d.unknown)
warning("A script is writing to the unimplemented engine-mapped var %d (%s)", var, d.name);
}
_data.vars[var] = value;
}
bool GameState::evaluate(int16 condition) {
uint16 unsignedCond = abs(condition);
uint16 var = unsignedCond & 2047;
int32 varValue = getVar(var);
int32 targetValue = (unsignedCond >> 11) - 1;
if (targetValue >= 0) {
if (condition >= 0)
return varValue == targetValue;
else
return varValue != targetValue;
} else {
if (condition >= 0)
return varValue != 0;
else
return varValue == 0;
}
}
int32 GameState::valueOrVarValue(int16 value) {
if (value < 0)
return getVar(-value);
return value;
}
int32 GameState::engineGet(uint16 var) {
if (!_descriptions.contains(var))
error("The engine is trying to access an undescribed var (%d)", var);
return _data.vars[var];
}
void GameState::engineSet(uint16 var, int32 value) {
if (!_descriptions.contains(var))
error("The engine is trying to access an undescribed var (%d)", var);
_data.vars[var] = value;
}
const Common::String GameState::describeVar(uint16 var) {
if (_descriptions.contains(var)) {
const Description &d = _descriptions.getVal(var);
return Common::String::format("v%s", d.name);
} else {
return Common::String::format("v%d", var);
}
}
const Common::String GameState::describeCondition(int16 condition) {
uint16 unsignedCond = abs(condition);
uint16 var = unsignedCond & 2047;
int16 value = (unsignedCond >> 11) - 1;
return Common::String::format("c[%s %s %d]",
describeVar(var).c_str(),
(condition >= 0 && value >= 0) || (condition < 0 && value < 0) ? "==" : "!=",
value >= 0 ? value : 0);
}
} /* namespace Myst3 */