Implemented basic saving and loading. Use Ctrl+(0-9) to save, and

Alt+(0-9) to load. Also extended the FastMode functionality to cover
the main game, hit Ctrl-F to speed animations and chats. Set '.' to skip
Brandon's chats, removed a redundant showMouse() and hideMouse() pair,
and simplified some screen updating code.

svn-id: r19773
This commit is contained in:
Oystein Eftevaag 2005-12-10 17:51:40 +00:00
parent 7b556aaafe
commit d6e9396166
3 changed files with 195 additions and 23 deletions

View file

@ -30,6 +30,7 @@
#include "common/file.h"
#include "common/system.h"
#include "common/md5.h"
#include "common/savefile.h"
#include "sound/mixer.h"
#include "sound/mididrv.h"
@ -264,6 +265,8 @@ int KyraEngine::init(GameDetector &detector) {
_midi->hasNativeMT32(native_mt32);
_midi->setVolume(255);
_saveFileMan = _system->getSavefileManager();
assert(_saveFileMan);
_res = new Resource(this);
assert(_res);
_screen = new Screen(this, _system);
@ -370,6 +373,7 @@ KyraEngine::~KyraEngine() {
delete _screen;
delete _res;
delete _midi;
delete _saveFileMan;
delete _seq;
delete _scriptInterpreter;
@ -511,6 +515,8 @@ void KyraEngine::startup() {
void KyraEngine::delay(uint32 amount) {
OSystem::Event event;
char saveLoadSlot[20];
uint32 start = _system->getMillis();
do {
while (_system->pollEvent(event)) {
@ -520,6 +526,15 @@ void KyraEngine::delay(uint32 amount) {
_quitFlag = true;
} else if (event.kbd.keycode == 'd' && !_debugger->isAttached()) {
_debugger->attach();
} else if (event.kbd.keycode >= '0' && event.kbd.keycode <= '9' &&
(event.kbd.flags == OSystem::KBD_CTRL || event.kbd.flags == OSystem::KBD_ALT)) {
sprintf(saveLoadSlot, "KYRA1.00%i", event.kbd.keycode - '0');
if (event.kbd.flags == OSystem::KBD_CTRL)
saveGame(saveLoadSlot, saveLoadSlot);
else
loadGame(saveLoadSlot);
} else if (event.kbd.flags == OSystem::KBD_CTRL && event.kbd.keycode == 'f') {
_fastMode = !_fastMode;
}
break;
case OSystem::EVENT_MOUSEMOVE:
@ -556,7 +571,7 @@ void KyraEngine::delay(uint32 amount) {
if (amount > 0) {
_system->delayMillis((amount > 10) ? 10 : amount);
}
} while (_system->getMillis() < start + amount);
} while (!_fastMode && _system->getMillis() < start + amount);
}
void KyraEngine::mainLoop() {
@ -1971,9 +1986,7 @@ void KyraEngine::initSceneObjectList(int brandonAlive) {
restoreAllObjectBackgrounds();
preserveAnyChangedBackgrounds();
prepDrawAllObjects();
_screen->hideMouse();
initSceneScreen(brandonAlive);
_screen->showMouse();
copyChangedObjectsForward(0);
}
@ -2255,7 +2268,7 @@ void KyraEngine::waitForChatToFinish(int16 chatDuration, char *chatStr, uint8 ch
while (_system->pollEvent(event)) {
switch (event.type) {
case OSystem::EVENT_KEYDOWN:
if (event.kbd.keycode == 0x20 || event.kbd.keycode == 0xC6)
if (event.kbd.keycode == '.')
runLoop = false;
break;
case OSystem::EVENT_QUIT:
@ -2268,6 +2281,9 @@ void KyraEngine::waitForChatToFinish(int16 chatDuration, char *chatStr, uint8 ch
}
}
if (_fastMode)
runLoop = false;
delayTime = (loopStart + _gameSpeed) - _system->getMillis();
if (delayTime > 0)
_system->delayMillis(delayTime);
@ -2285,6 +2301,7 @@ void KyraEngine::endCharacterChat(int8 charNum, int16 convoInitialized) {
if (charNum > 4 && charNum < 11) {
//TODO: weird _game_inventory stuff here
warning("STUB: endCharacterChat() for high charnums");
}
if (convoInitialized != 0) {
@ -2364,6 +2381,7 @@ int KyraEngine::initCharacterChat(int8 charNum) {
if (charNum > 4 && charNum < 11) {
// TODO: Fill in weird _game_inventory stuff here
warning("STUB: initCharacterChat() for high charnums");
}
flagAllObjectsForRefresh();
@ -3377,7 +3395,6 @@ void KyraEngine::prepDrawAllObjects() {
void KyraEngine::copyChangedObjectsForward(int refreshFlag) {
debug(9, "copyChangedObjectsForward(%d)", refreshFlag);
AnimObject *curObject = _objectQueue;
bool changed = false;
while (curObject) {
if (curObject->active) {
@ -3402,13 +3419,15 @@ void KyraEngine::copyChangedObjectsForward(int refreshFlag) {
_screen->copyRegion(xpos, ypos, xpos, ypos, width, height, 2, 0, Screen::CR_CLIPPED);
curObject->refreshFlag = 0;
changed = true;
_updateScreen = true;
}
}
curObject = curObject->nextAnimObject;
}
if (changed)
if (_updateScreen) {
_screen->updateScreen();
_updateScreen = false;
}
}
void KyraEngine::updateAllObjectShapes() {
@ -4941,4 +4960,156 @@ void KyraEngine::runNpcScript(int func) {
}
}
#pragma mark -
#pragma mark - Saving/loading
#pragma mark -
void KyraEngine::loadGame(const char *fileName) {
debug(9, "loadGame('%s')", fileName);
Common::InSaveFile *in;
if (!(in = _saveFileMan->openForLoading(fileName))) {
warning("Can't open file '%s', game not loaded", fileName);
return;
}
if (in->readByte() != 1) {
warning("Savegame is not the right version");
delete in;
return;
}
char saveName[31];
in->read(saveName, 31);
for (int i = 0; i < 11; i++) {
_characterList[i].sceneId = in->readUint16BE();
_characterList[i].height = in->readByte();
_characterList[i].facing = in->readByte();
_characterList[i].currentAnimFrame = in->readUint16BE();
_characterList[i].unk6 = in->readUint32BE();
in->read(_characterList[i].inventoryItems, 10);
_characterList[i].x1 = in->readSint16BE();
_characterList[i].y1 = in->readSint16BE();
_characterList[i].x2 = in->readSint16BE();
_characterList[i].y1 = in->readSint16BE();
_characterList[i].field_20 = in->readUint16BE();
_characterList[i].field_23 = in->readUint16BE();
}
_marbleVaseItem = in->readSint16BE();
_itemInHand = in->readByte();
for (int i = 0; i < 32; i++) {
_timers[i].countdown = in->readSint32BE();
_timers[i].nextRun = in->readUint32BE();
}
_timerNextRun = 0;
in->read(_flagsTable, sizeof(_flagsTable));
for (int i = 0; i < _roomTableSize; ++i) {
for (int item = 0; item < 12; ++item) {
_roomTable[i].itemsTable[item] = 0xFF;
_roomTable[i].itemsXPos[item] = 0xFFFF;
_roomTable[i].itemsYPos[item] = 0xFF;
_roomTable[i].unkField3[item] = 0;
}
}
uint16 sceneId;
uint8 itemCount;
while (!in->eos()) {
sceneId = in->readUint16BE();
if (sceneId == 0xffff)
break;
itemCount = in->readByte();
for (int i = 0; i < itemCount; i++) {
_roomTable[sceneId].itemsTable[i] = in->readByte();
_roomTable[sceneId].itemsXPos[i] = in->readUint16BE();
_roomTable[sceneId].itemsYPos[i] = in->readUint16BE();
_roomTable[sceneId].unkField3[i] = in->readUint32BE();
}
}
createMouseItem(_itemInHand);
enterNewScene(_currentCharacter->sceneId, _currentCharacter->facing, 0, 0, 1);
if (in->ioFailed())
error("Load failed.");
else
debug(1, "Loaded savegame '%s.'", saveName);
delete in;
}
void KyraEngine::saveGame(const char *fileName, const char *saveName) {
debug(9, "saveGame('%s', '%s')", fileName, saveName);
Common::OutSaveFile *out;
if (!(out = _saveFileMan->openForSaving(fileName))) {
warning("Can't create file '%s', game not saved", fileName);
return;
}
// Savegame version
out->writeByte(1);
out->write(saveName, 31);
for (int i = 0; i < 11; i++) {
out->writeUint16BE(_characterList[i].sceneId);
out->writeByte(_characterList[i].height);
out->writeByte(_characterList[i].facing);
out->writeUint16BE(_characterList[i].currentAnimFrame);
out->writeUint32BE(_characterList[i].unk6);
out->write(_characterList[i].inventoryItems, 10);
out->writeSint16BE(_characterList[i].x1);
out->writeSint16BE(_characterList[i].y1);
out->writeSint16BE(_characterList[i].x2);
out->writeSint16BE(_characterList[i].y1);
out->writeUint16BE(_characterList[i].field_20);
out->writeUint16BE(_characterList[i].field_23);
}
out->writeSint16BE(_marbleVaseItem);
out->writeByte(_itemInHand);
for (int i = 0; i < 32; i++) {
out->writeSint32BE(_timers[i].countdown);
out->writeUint32BE(_timers[i].nextRun);
}
out->write(_flagsTable, sizeof(_flagsTable));
uint8 itemCount;
for (int i = 0; i < _roomTableSize; i++) {
itemCount = countItemsInScene(i);
if (itemCount > 0) {
out->writeUint16BE(i);
out->writeByte(itemCount);
for (int a = 0; a < 12; a++) {
if (_roomTable[i].itemsTable[a] != 0xff) {
out->writeByte(_roomTable[i].itemsTable[a]);
out->writeUint16BE(_roomTable[i].itemsXPos[a]);
out->writeUint16BE(_roomTable[i].itemsYPos[a]);
out->writeUint32BE(_roomTable[i].unkField3[a]);
}
}
}
}
out->flush();
// check for errors
if (out->ioFailed())
warning("Can't write file '%s'. (Disk full?)", fileName);
else
debug(1, "Saved game '%s.'", saveName);
delete out;
}
} // End of namespace Kyra

View file

@ -228,6 +228,9 @@ public:
int16 fetchAnimWidth(const uint8 *shape, int16 mult);
int16 fetchAnimHeight(const uint8 *shape, int16 mult);
void saveGame(const char *fileName, const char *saveName);
void loadGame(const char *fileName);
int mouseX() { return _mouseX; }
int mouseY() { return _mouseY; }
@ -570,9 +573,10 @@ protected:
uint16 _tickLength;
uint32 _features;
int _mouseX, _mouseY;
int _itemInHand;
int8 _itemInHand;
int _mouseState;
bool _handleInput;
bool _updateScreen;
WSAMovieV1 *_wsaObjects[10];
uint16 _entranceMouseCursorTracks[8];
@ -648,6 +652,7 @@ protected:
Sprites *_sprites;
ScriptHelper *_scriptInterpreter;
Debugger *_debugger;
Common::SaveFileManager *_saveFileMan;
ScriptState *_scriptMain;

View file

@ -314,10 +314,8 @@ int KyraEngine::cmd_characterSays(ScriptState *script) {
if (_features & GF_TALKIE) {
debug(3, "cmd_characterSays(0x%X) (%d, '%s', %d, %d)", script, stackPos(0), stackPosString(1), stackPos(2), stackPos(3));
while (snd_voicePlaying()) {
_sprites->updateSceneAnims();
updateAllObjectShapes();
_system->delayMillis(10);
while (snd_voicePlaying() && !_fastMode) {
delay(10);
}
snd_playVoiceFile(stackPos(0));
characterSays(stackPosString(1), stackPos(2), stackPos(3));
@ -667,7 +665,7 @@ int KyraEngine::cmd_runWSAFromBeginningToEnd(ScriptState *script) {
_sprites->updateSceneAnims();
updateAllObjectShapes();
}
_screen->updateScreen();
_updateScreen = true;
}
_screen->showMouse();
@ -685,7 +683,7 @@ int KyraEngine::cmd_displayWSAFrame(ScriptState *script) {
_screen->hideMouse();
wsa_play(_wsaObjects[wsaIndex], frame, xpos, ypos, 0);
delay(waitTime * _tickLength);
_screen->updateScreen();
_updateScreen = true;
_screen->showMouse();
return 0;
}
@ -779,10 +777,8 @@ int KyraEngine::cmd_loadPageFromDisk(ScriptState *script) {
int KyraEngine::cmd_customPrintTalkString(ScriptState *script) {
if (_features & GF_TALKIE) {
debug(3, "cmd_customPrintTalkString(0x%X) ('%s', %d, %d, %d)", script, stackPosString(1), stackPos(2), stackPos(3), stackPos(4) & 0xFF);
while (snd_voicePlaying()) {
_sprites->updateSceneAnims();
updateAllObjectShapes();
_system->delayMillis(10);
while (snd_voicePlaying() && !_fastMode) {
delay(10);
}
snd_playVoiceFile(stackPos(0));
printTalkTextMessage(stackPosString(1), stackPos(2), stackPos(3), stackPos(4) & 0xFF, 0, 2);
@ -790,7 +786,7 @@ int KyraEngine::cmd_customPrintTalkString(ScriptState *script) {
debug(3, "cmd_customPrintTalkString(0x%X) ('%s', %d, %d, %d)", script, stackPosString(0), stackPos(1), stackPos(2), stackPos(3) & 0xFF);
printTalkTextMessage(stackPosString(0), stackPos(1), stackPos(2), stackPos(3) & 0xFF, 0, 2);
}
_updateScreen = true;
return 0;
}
@ -907,7 +903,7 @@ int KyraEngine::cmd_displayWSASequentialFrames(ScriptState *script) {
while (endFrame >= frame) {
wsa_play(_wsaObjects[wsaIndex], frame, xpos, ypos, 0);
delay(waitTime * _tickLength);
_screen->updateScreen();
_updateScreen = true;
++frame;
}
} else {
@ -915,7 +911,7 @@ int KyraEngine::cmd_displayWSASequentialFrames(ScriptState *script) {
while (startFrame <= frame) {
wsa_play(_wsaObjects[wsaIndex], frame, xpos, ypos, 0);
delay(waitTime * _tickLength);
_screen->updateScreen();
_updateScreen = true;
--frame;
}
}