mirror of
https://github.com/scummvm/gamos.git
synced 2026-05-21 05:40:53 +00:00
525 lines
14 KiB
C++
525 lines
14 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 "gamos/gamos.h"
|
|
#include "common/savefile.h"
|
|
|
|
namespace Gamos {
|
|
|
|
void GamosEngine::storeToGameScreen(int id) {
|
|
GameScreen &gs = _gameScreens[id];
|
|
gs._savedObjects.clear();
|
|
|
|
gs._savedStates = _states;
|
|
|
|
int objCount = 0;
|
|
for (int i = 0; i < _objects.size(); i++) {
|
|
const Object &obj = _objects[i];
|
|
if ((obj.flags & 3) == 3 || (obj.flags & 7) == Object::FLAG_VALID)
|
|
objCount++;
|
|
}
|
|
|
|
int idx = 0;
|
|
gs._savedObjects.resize(objCount);
|
|
for (int i = 0; i < _objects.size(); i++) {
|
|
Object &obj = _objects[i];
|
|
|
|
if (obj.isActionObject()) {
|
|
const int refObjIdx = idx;
|
|
if (obj.tgtObjectId == -1) {
|
|
gs._savedObjects[idx] = obj;
|
|
gs._savedObjects[idx].index = idx;
|
|
obj.flags = 0;
|
|
idx++;
|
|
} else {
|
|
Object &drawObj = _objects[ obj.tgtObjectId ];
|
|
gs._savedObjects[idx] = obj;
|
|
gs._savedObjects[idx].index = idx;
|
|
gs._savedObjects[idx].tgtObjectId = idx + 1;
|
|
gs._savedObjects[idx].curObjectId = idx + 1;
|
|
gs._savedObjects[idx + 1] = drawObj;
|
|
gs._savedObjects[idx + 1].index = idx + 1;
|
|
gs._savedObjects[idx + 1].actObjIndex = idx;
|
|
obj.flags = 0;
|
|
drawObj.flags = 0;
|
|
idx += 2;
|
|
}
|
|
|
|
for (int j = 0; j < _objects.size(); j++) {
|
|
Object &lobj = _objects[ j ];
|
|
if ((lobj.flags & 7) == Object::FLAG_VALID && lobj.actObjIndex == obj.index) {
|
|
gs._savedObjects[idx] = lobj;
|
|
gs._savedObjects[idx].index = idx;
|
|
gs._savedObjects[idx].actObjIndex = refObjIdx;
|
|
lobj.flags = 0;
|
|
idx++;
|
|
}
|
|
}
|
|
} else if ((obj.flags & 7) == Object::FLAG_VALID && obj.actObjIndex == -1) {
|
|
gs._savedObjects[idx] = obj;
|
|
gs._savedObjects[idx].index = idx;
|
|
obj.flags = 0;
|
|
idx++;
|
|
}
|
|
}
|
|
|
|
_objects.clear();
|
|
}
|
|
|
|
|
|
bool GamosEngine::switchToGameScreen(int id, bool doNotStore) {
|
|
if (_currentGameScreen != -1 && doNotStore == false)
|
|
storeToGameScreen(_currentGameScreen);
|
|
|
|
_currentGameScreen = id;
|
|
GameScreen &gs = _gameScreens[id];
|
|
|
|
addDirtyRect(Common::Rect(Common::Point(), _bkgSize));
|
|
|
|
_states = gs._savedStates;
|
|
|
|
for (const Object &obj : gs._savedObjects) {
|
|
Object *nobj = getFreeObject();
|
|
if (nobj->index != obj.index) {
|
|
warning("Error! nobj->index != obj.index");
|
|
return false;
|
|
}
|
|
|
|
*nobj = obj;
|
|
}
|
|
|
|
gs._savedObjects.clear();
|
|
gs._savedStates.clear();
|
|
|
|
flushDirtyRects(false);
|
|
|
|
if (doNotStore == false && !setPaletteCurrentGS())
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
Common::String GamosEngine::makeSaveName(const Common::String &main, int id, const Common::String &ext) const {
|
|
Common::String tmp = main;
|
|
tmp.toUppercase();
|
|
uint32 idx = tmp.find(".EXE");
|
|
if (idx != Common::String::npos)
|
|
tmp.erase(idx);
|
|
return Common::String::format("%s%d.%s", tmp.c_str(), id, ext.c_str());
|
|
}
|
|
|
|
|
|
bool GamosEngine::writeStateFile() {
|
|
Common::String fname = makeSaveName(getRunFile(), _saveLoadID, _stateExt);
|
|
Common::SaveFileManager *sm = _system->getSavefileManager();
|
|
|
|
if (!_isResLoadingProcess) {
|
|
if (sm->exists(fname)) {
|
|
Common::InSaveFile *rsv = sm->openForLoading(fname);
|
|
byte svdata[0x4c];
|
|
rsv->read(svdata, 0x4c);
|
|
delete rsv;
|
|
|
|
Common::OutSaveFile *osv = sm->openForSaving(fname);
|
|
osv->write(svdata, 0x4c);
|
|
|
|
writeVMData(osv, _xorSeq[0]);
|
|
writeVMData(osv, _xorSeq[1]);
|
|
|
|
osv->finalize();
|
|
delete osv;
|
|
}
|
|
} else {
|
|
_d2_fld10 = 0;
|
|
Common::OutSaveFile *osv = sm->openForSaving(fname);
|
|
|
|
writeStateData(osv);
|
|
writeVMData(osv, _xorSeq[0]);
|
|
writeVMData(osv, _xorSeq[1]);
|
|
|
|
osv->finalize();
|
|
delete osv;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool GamosEngine::loadStateFile() {
|
|
Common::String fname = makeSaveName(getRunFile(), _saveLoadID, _stateExt);
|
|
Common::SaveFileManager *sm = _system->getSavefileManager();
|
|
|
|
if (!_isResLoadingProcess) {
|
|
if (sm->exists(fname)) {
|
|
Common::SeekableReadStream *rs = sm->openForLoading(fname);
|
|
rs->seek(0x4c);
|
|
readVMData(rs, _xorSeq[0]);
|
|
readVMData(rs, _xorSeq[1]);
|
|
}
|
|
} else {
|
|
if (!sm->exists(fname))
|
|
writeStateFile();
|
|
else {
|
|
Common::SeekableReadStream *rs = sm->openForLoading(fname);
|
|
|
|
loadStateData(rs);
|
|
readVMData(rs, _xorSeq[0]);
|
|
readVMData(rs, _xorSeq[1]);
|
|
|
|
zeroVMData(_xorSeq[1]);
|
|
|
|
_isResLoadingProcess = false;
|
|
|
|
delete rs;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void GamosEngine::writeStateData(Common::SeekableWriteStream *stream) {
|
|
byte buf[4] = {0, 0, 0, 0};
|
|
memcpy(buf, _stateExt.c_str(), _stateExt.size() > 4 ? 4 : _stateExt.size());
|
|
|
|
stream->write(buf, 4); // 0
|
|
stream->writeByte(_messageProc._inputFlags); // 4
|
|
stream->writeByte(0); // 5
|
|
stream->writeByte(0); // 6
|
|
stream->writeByte(0); // 7
|
|
stream->writeSint32LE(_svModuleId); // 8
|
|
stream->writeSint32LE(_svGameScreen); // 0xc
|
|
stream->writeUint32LE(_d2_fld10); // 0x10
|
|
stream->writeByte(_enableSounds ? 1 : 0); // 0x14
|
|
stream->writeByte(_enableMidi ? 1 : 0); // 0x15
|
|
stream->writeByte(_enableInput ? 1 : 0); // 0x16
|
|
stream->writeByte(_enableMovie ? 1 : 0); // 0x17
|
|
stream->writeByte(_enableCDAudio ? 1 : 0); // 0x18
|
|
stream->writeSByte(_cdAudioTrack); // 0x19
|
|
stream->writeByte(0); // 0x1a
|
|
stream->writeByte(0); // 0x1b
|
|
stream->writeSint32LE(_scrollX); // 0x1c
|
|
stream->writeSint32LE(_scrollY); // 0x20
|
|
stream->writeSint16LE(_scrollTrackObj); // 0x24
|
|
stream->writeSint16LE(_scrollSpeed); // 0x26
|
|
stream->writeSint16LE(_scrollCutoff); // 0x28
|
|
stream->writeSint16LE(_scrollSpeedReduce); // 0x2a
|
|
stream->writeByte(_scrollBorderL); // 0x2c
|
|
stream->writeByte(_scrollBorderR); // 0x2d
|
|
stream->writeByte(_scrollBorderU); // 0x2e
|
|
stream->writeByte(_scrollBorderB); // 0x2f
|
|
stream->writeByte(_sndChannels); // 0x30
|
|
stream->writeByte(_sndVolume); // 0x31
|
|
stream->writeByte(_midiVolume); // 0x32
|
|
stream->writeByte(_svFps); // 0x33
|
|
stream->writeSint32LE(_svFrame); // 0x34
|
|
stream->writeUint32LE(_midiTrack); // 0x38
|
|
stream->writeSint32LE(_mouseCursorImgId); // 0x3c
|
|
// 0x40
|
|
for (int i = 0; i < 12; i++)
|
|
stream->writeByte(_messageProc._keyCodes[i]);
|
|
}
|
|
|
|
void GamosEngine::loadStateData(Common::SeekableReadStream *dataStream) {
|
|
_stateExt = dataStream->readString(0, 4); // FIX ME
|
|
dataStream->seek(4);
|
|
_messageProc._inputFlags = dataStream->readByte(); //4
|
|
dataStream->seek(8);
|
|
_svModuleId = dataStream->readSint32LE(); // 8
|
|
_svGameScreen = dataStream->readSint32LE(); // c
|
|
_d2_fld10 = dataStream->readUint32LE(); // x10
|
|
_enableSounds = dataStream->readByte() != 0 ? true : false; // x14
|
|
_enableMidi = dataStream->readByte() != 0 ? true : false; //x15
|
|
_enableInput = dataStream->readByte() != 0 ? true : false; // x16
|
|
_enableMovie = dataStream->readByte() != 0 ? true : false; // x17
|
|
_enableCDAudio = dataStream->readByte() != 0 ? true : false; // x18
|
|
_cdAudioTrack = dataStream->readSByte(); // x19
|
|
dataStream->seek(0x1c);
|
|
_scrollX = dataStream->readSint32LE(); // x1c
|
|
_scrollY = dataStream->readSint32LE(); // x20
|
|
_scrollTrackObj = dataStream->readSint16LE(); // x24
|
|
_scrollSpeed = dataStream->readSint16LE(); // x26
|
|
_scrollCutoff = dataStream->readSint16LE(); // x28
|
|
_scrollSpeedReduce = dataStream->readSint16LE(); // x2a
|
|
_scrollBorderL = dataStream->readByte(); // x2c
|
|
_scrollBorderR = dataStream->readByte(); // x2d
|
|
_scrollBorderU = dataStream->readByte(); // x2e
|
|
_scrollBorderB = dataStream->readByte(); // x2f
|
|
_sndChannels = dataStream->readByte(); // x30
|
|
_sndVolume = dataStream->readByte(); // x34
|
|
_midiVolume = dataStream->readByte(); // x1a
|
|
_svFps = dataStream->readByte(); // x1b
|
|
_svFrame = dataStream->readSint32LE(); // x1c
|
|
_midiTrack = dataStream->readUint32LE(); //0x38
|
|
_mouseCursorImgId = dataStream->readSint32LE(); //0x3c
|
|
|
|
for (int i = 0; i < 12; i++)
|
|
_messageProc._keyCodes[i] = dataStream->readByte();
|
|
}
|
|
|
|
|
|
void GamosEngine::writeVMData(Common::SeekableWriteStream *stream, const Common::Array<XorArg> &seq) {
|
|
for (const XorArg &xarg : seq) {
|
|
Common::Array<byte> tmp = _vm.readMemBlocks(xarg.pos, xarg.len);
|
|
|
|
//xor data in tmp
|
|
//...
|
|
|
|
// and write it
|
|
stream->write(tmp.data(), xarg.len);
|
|
}
|
|
}
|
|
|
|
void GamosEngine::readVMData(Common::SeekableReadStream *stream, const Common::Array<XorArg> &seq) {
|
|
Common::Array<byte> buf;
|
|
for (const XorArg &xarg : seq) {
|
|
if (buf.size() < xarg.len)
|
|
buf.resize(xarg.len);
|
|
stream->read(buf.data(), xarg.len);
|
|
//xor data in buf
|
|
//...
|
|
|
|
// and write it
|
|
_vm.writeMemory(xarg.pos, buf.data(), xarg.len);
|
|
}
|
|
}
|
|
|
|
void GamosEngine::zeroVMData(const Common::Array<XorArg> &seq) {
|
|
for (const XorArg &xarg : seq)
|
|
_vm.zeroMemory(xarg.pos, xarg.len);
|
|
}
|
|
|
|
|
|
|
|
|
|
bool GamosEngine::writeSaveFile(int id) {
|
|
Common::String fname = makeSaveName(getRunFile(), id, "sav");
|
|
Common::SaveFileManager *sm = _system->getSavefileManager();
|
|
|
|
Common::OutSaveFile *osv = sm->openForSaving(fname);
|
|
if (!osv)
|
|
return false;
|
|
|
|
storeToGameScreen(_currentGameScreen);
|
|
_svFps = _vm.memory().getU8(_addrFPS);
|
|
_svFrame = _vm.memory().getU32(_addrCurrentFrame);
|
|
_d2_fld10 = _countReadedBkg;
|
|
_svModuleId = _currentModuleID;
|
|
_svGameScreen = _currentGameScreen;
|
|
|
|
writeStateData(osv);
|
|
|
|
writeVMData(osv, _xorSeq[0]);
|
|
writeVMData(osv, _xorSeq[1]);
|
|
writeVMData(osv, _xorSeq[2]);
|
|
|
|
for (int i = 0; i < _gameScreens.size(); i++) {
|
|
GameScreen &scr = _gameScreens[i];
|
|
|
|
if (scr.loaded) {
|
|
osv->writeUint32LE(i);
|
|
|
|
for (int j = 0; j < scr._savedStates.size(); j++) {
|
|
const ObjState &ost = scr._savedStates[j];
|
|
osv->writeByte(ost.actid);
|
|
osv->writeByte(ost.flags);
|
|
osv->writeByte(ost.t);
|
|
}
|
|
|
|
osv->writeUint32LE(scr._savedObjects.size());
|
|
|
|
for (const Object &obj : scr._savedObjects) {
|
|
writeObjectData(osv, &obj);
|
|
}
|
|
}
|
|
}
|
|
|
|
osv->finalize();
|
|
delete osv;
|
|
|
|
switchToGameScreen(_currentGameScreen, true);
|
|
return true;
|
|
}
|
|
|
|
bool GamosEngine::loadSaveFile(int id) {
|
|
Common::String fname = makeSaveName(getRunFile(), id, "sav");
|
|
Common::SaveFileManager *sm = _system->getSavefileManager();
|
|
|
|
Common::SeekableReadStream *rs = sm->openForLoading(fname);
|
|
if (!rs)
|
|
return false;
|
|
|
|
const bool sv1 = _enableCDAudio;
|
|
const bool sv2 = _enableMovie;
|
|
const bool sv3 = _enableInput;
|
|
const bool svmdi = _enableMidi;
|
|
const bool sv4 = _enableSounds;
|
|
|
|
loadStateData(rs);
|
|
|
|
_sndVolume = _sndVolumeTarget;
|
|
_midiVolume = 0;
|
|
_enableSounds = sv4;
|
|
_enableMidi = svmdi;
|
|
_enableInput = sv3;
|
|
_enableMovie = sv2;
|
|
_enableCDAudio = sv1;
|
|
|
|
_musicPlayer.setVolume(0);
|
|
|
|
const int32 cursorImgId = _mouseCursorImgId;
|
|
const int32 svMidiTrack = _midiTrack;
|
|
const int8 cdtrack = _cdAudioTrack;
|
|
|
|
_isResLoadingProcess = true;
|
|
_isSaveLoadingProcess = true;
|
|
|
|
loadModule(_svModuleId);
|
|
|
|
readVMData(rs, _xorSeq[0]);
|
|
readVMData(rs, _xorSeq[1]);
|
|
readVMData(rs, _xorSeq[2]);
|
|
|
|
for (int i = 0; i < _countReadedBkg; i++) {
|
|
uint32 val = rs->readUint32LE();
|
|
GameScreen &scr = _gameScreens[val];
|
|
|
|
scr._savedStates.resize( _states.sizes() );
|
|
|
|
for (int j = 0; j < scr._savedStates.size(); j++) {
|
|
ObjState &st = scr._savedStates[j];
|
|
st.actid = rs->readByte();
|
|
st.flags = rs->readByte();
|
|
st.t = rs->readByte();
|
|
}
|
|
|
|
val = rs->readUint32LE();
|
|
|
|
scr._savedObjects.resize(val);
|
|
|
|
for (Object &obj : scr._savedObjects) {
|
|
loadObjectData(rs, &obj);
|
|
if (((obj.flags & Object::FLAG_HASACTION) == 0) && obj.sprId >= 0 && obj.frame >= 0 && obj.seqId >= 0) {
|
|
obj.pImg = &_sprites[obj.sprId].sequences[obj.seqId]->operator[](obj.frame);
|
|
}
|
|
}
|
|
}
|
|
|
|
delete rs;
|
|
|
|
switchToGameScreen(_svGameScreen, false);
|
|
|
|
_vm.memory().setU8(_addrFPS, _svFps);
|
|
_vm.memory().setU32(_addrCurrentFrame, _svFrame);
|
|
|
|
_isResLoadingProcess = false;
|
|
_isSaveLoadingProcess = false;
|
|
|
|
if (cdtrack != -1) {
|
|
//vmfunc_58(cdtrack);
|
|
}
|
|
|
|
if (svMidiTrack != -1)
|
|
playMidiTrack(svMidiTrack);
|
|
|
|
_midiVolume = 0;
|
|
|
|
if (cursorImgId != -1)
|
|
setCursor(cursorImgId, false);
|
|
|
|
setNeedReload();
|
|
return true;
|
|
}
|
|
|
|
void GamosEngine::writeObjectData(Common::SeekableWriteStream *stream, const Object *obj) {
|
|
stream->writeUint16LE(obj->index);
|
|
stream->writeByte(obj->flags);
|
|
stream->writeByte(obj->priority);
|
|
stream->writeSint16LE(obj->cell.x);
|
|
stream->writeSint16LE(obj->cell.y);
|
|
|
|
if (obj->flags & Object::FLAG_HASACTION) {
|
|
stream->writeByte(obj->actID);
|
|
stream->writeByte(obj->t);
|
|
stream->writeByte(obj->state.actid);
|
|
stream->writeByte(obj->state.flags);
|
|
stream->writeByte(obj->state.t);
|
|
stream->writeByte(obj->inputFlag);
|
|
stream->writeSint16LE(obj->tgtObjectId);
|
|
stream->writeSint16LE(obj->curObjectId);
|
|
stream->writeUint32LE(obj->storage.size());
|
|
stream->write(obj->storage.data(), obj->storage.size());
|
|
} else {
|
|
stream->writeSint32LE(obj->sprId);
|
|
stream->writeSint32LE(obj->seqId);
|
|
stream->writeSint16LE(obj->frame);
|
|
stream->writeSint16LE(obj->frameMax);
|
|
stream->writeSint16LE(obj->position.x);
|
|
stream->writeSint16LE(obj->position.y);
|
|
stream->writeSint16LE(obj->actObjIndex);
|
|
}
|
|
}
|
|
|
|
void GamosEngine::loadObjectData(Common::SeekableReadStream *stream, Object *obj) {
|
|
obj->index = stream->readUint16LE();
|
|
obj->flags = stream->readByte();
|
|
obj->priority = stream->readByte();
|
|
obj->cell.x = stream->readSint16LE();
|
|
obj->cell.y = stream->readSint16LE();
|
|
|
|
if (obj->flags & Object::FLAG_HASACTION) {
|
|
obj->actID = stream->readByte();
|
|
obj->t = stream->readByte();
|
|
obj->state.actid = stream->readByte();
|
|
obj->state.flags = stream->readByte();
|
|
obj->state.t = stream->readByte();
|
|
obj->inputFlag = stream->readByte();
|
|
obj->tgtObjectId = stream->readSint16LE();
|
|
obj->curObjectId = stream->readSint16LE();
|
|
|
|
uint32 storSize = stream->readUint32LE();
|
|
if (storSize) {
|
|
obj->storage.resize(storSize);
|
|
stream->read(obj->storage.data(), storSize);
|
|
} else
|
|
obj->storage.clear();
|
|
} else {
|
|
obj->sprId = stream->readSint32LE();
|
|
obj->seqId = stream->readSint32LE();
|
|
obj->frame = stream->readSint16LE();
|
|
obj->frameMax = stream->readSint16LE();
|
|
obj->position.x = stream->readSint16LE();
|
|
obj->position.y = stream->readSint16LE();
|
|
obj->actObjIndex = stream->readSint16LE();
|
|
}
|
|
}
|
|
|
|
|
|
bool GamosEngine::deleteSaveFile(int id) {
|
|
Common::String fname = makeSaveName(getRunFile(), id, "sav");
|
|
Common::SaveFileManager *sm = _system->getSavefileManager();
|
|
|
|
if ( !sm->exists(fname) )
|
|
return true;
|
|
|
|
if ( sm->removeSavefile(fname) )
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
}
|