Implemented savegame loading/saving and sprite clipping

Fixed bug in Screen::printTextEx
Implemented opcodes:
- o1_DRAWTEXT
- o1_DRAWMENU
- o1_MENUCOUNT
- o1_SAVEGAME
- o1_LOADGAME
- o1_GAMENAME

svn-id: r31794
This commit is contained in:
Benjamin Haisch 2008-04-30 20:36:19 +00:00
parent e866aefdfd
commit 7509d66caf
4 changed files with 190 additions and 39 deletions

View file

@ -23,8 +23,10 @@
* *
*/ */
#include "common/system.h"
#include "common/endian.h" #include "common/endian.h"
#include "common/util.h" #include "common/util.h"
#include "common/savefile.h"
#include "made/database.h" #include "made/database.h"
@ -222,8 +224,7 @@ void GameDatabase::load(Common::SeekableReadStream &sourceS) {
uint32 objectsSize = sourceS.readUint32LE(); uint32 objectsSize = sourceS.readUint32LE();
_mainCodeObjectIndex = sourceS.readUint16LE(); _mainCodeObjectIndex = sourceS.readUint16LE();
debug(2, "objectIndexOffs = %08X; objectCount = %d; gameStateOffs = %08X; gameStateSize = %d; objectsOffs = %08X; objectsSize = %d\n", //debug(2, "objectIndexOffs = %08X; objectCount = %d; gameStateOffs = %08X; gameStateSize = %d; objectsOffs = %08X; objectsSize = %d\n", objectIndexOffs, objectCount, gameStateOffs, _gameStateSize, objectsOffs, objectsSize);
objectIndexOffs, objectCount, gameStateOffs, _gameStateSize, objectsOffs, objectsSize);
_gameState = new byte[_gameStateSize]; _gameState = new byte[_gameStateSize];
sourceS.seek(gameStateOffs); sourceS.seek(gameStateOffs);
@ -241,14 +242,14 @@ void GameDatabase::load(Common::SeekableReadStream &sourceS) {
// Constant objects are loaded from disk, while variable objects exist // Constant objects are loaded from disk, while variable objects exist
// in the _gameState buffer. // in the _gameState buffer.
debug(2, "obj(%04X) ofs = %08X\n", i, objectOffsets[i]); //debug(2, "obj(%04X) ofs = %08X\n", i, objectOffsets[i]);
if (objectOffsets[i] & 1) { if (objectOffsets[i] & 1) {
debug(2, "-> const %08X\n", objectsOffs + objectOffsets[i] - 1); //debug(2, "-> const %08X\n", objectsOffs + objectOffsets[i] - 1);
sourceS.seek(objectsOffs + objectOffsets[i] - 1); sourceS.seek(objectsOffs + objectOffsets[i] - 1);
obj->load(sourceS); obj->load(sourceS);
} else { } else {
debug(2, "-> var\n"); //debug(2, "-> var\n");
obj->load(_gameState + objectOffsets[i]); obj->load(_gameState + objectOffsets[i]);
} }
_objects.push_back(obj); _objects.push_back(obj);
@ -256,6 +257,79 @@ void GameDatabase::load(Common::SeekableReadStream &sourceS) {
} }
bool GameDatabase::getSavegameDescription(const char *filename, Common::String &description) {
Common::InSaveFile *in;
if (!(in = g_system->getSavefileManager()->openForLoading(filename))) {
return false;
}
char desc[64];
in->skip(4); // TODO: Verify marker 'SGAM'
in->skip(4); // TODO: Verify size
in->skip(2); // TODO: Verify version
in->read(desc, 64);
description = desc;
printf("description = %s\n", description.c_str()); fflush(stdout);
delete in;
return true;
}
int16 GameDatabase::savegame(const char *filename, const char *description, int16 version) {
Common::OutSaveFile *out;
if (!(out = g_system->getSavefileManager()->openForSaving(filename))) {
warning("Can't create file '%s', game not saved", filename);
return 6;
}
uint32 size = 4 + 4 + 2 + _gameStateSize;
char desc[64];
strncpy(desc, description, 64);
out->writeUint32BE(MKID_BE('SGAM'));
out->writeUint32LE(size);
out->writeUint16LE(version);
out->write(desc, 64);
out->write(_gameState, _gameStateSize);
delete out;
return 0;
}
int16 GameDatabase::loadgame(const char *filename, int16 version) {
Common::InSaveFile *in;
if (!(in = g_system->getSavefileManager()->openForLoading(filename))) {
warning("Can't open file '%s', game not loaded", filename);
return 1;
}
//uint32 expectedSize = 4 + 4 + 2 + _gameStateSize;
in->skip(4); // TODO: Verify marker 'SGAM'
in->skip(4); // TODO: Verify size
in->skip(2); // TODO: Verify version
in->skip(64); // skip savegame description
in->read(_gameState, _gameStateSize);
delete in;
return 0;
}
int16 GameDatabase::getVar(int16 index) { int16 GameDatabase::getVar(int16 index) {
return (int16)READ_LE_UINT16(_gameState + index * 2); return (int16)READ_LE_UINT16(_gameState + index * 2);
} }

View file

@ -30,6 +30,7 @@
#include "common/util.h" #include "common/util.h"
#include "common/file.h" #include "common/file.h"
#include "common/stream.h" #include "common/stream.h"
#include "common/str.h"
#include "made/redreader.h" #include "made/redreader.h"
@ -78,6 +79,10 @@ public:
void open(const char *filename); void open(const char *filename);
void openFromRed(const char *redFilename, const char *filename); void openFromRed(const char *redFilename, const char *filename);
bool getSavegameDescription(const char *filename, Common::String &description);
int16 savegame(const char *filename, const char *description, int16 version);
int16 loadgame(const char *filename, int16 version);
Object *getObject(int16 index) const { Object *getObject(int16 index) const {
if (index >= 1) if (index >= 1)
return _objects[index - 1]; return _objects[index - 1];

View file

@ -92,23 +92,41 @@ void Screen::clearScreen() {
_screen1->fillRect(Common::Rect(0, 0, 320, 200), 0); _screen1->fillRect(Common::Rect(0, 0, 320, 200), 0);
_screen2->fillRect(Common::Rect(0, 0, 320, 200), 0); _screen2->fillRect(Common::Rect(0, 0, 320, 200), 0);
_needPalette = true; _needPalette = true;
//_vm->_system->clearScreen();
} }
void Screen::drawSurface(Graphics::Surface *sourceSurface, int x, int y, const ClipInfo &clipInfo) { void Screen::drawSurface(Graphics::Surface *sourceSurface, int x, int y, const ClipInfo &clipInfo) {
byte *source = (byte*)sourceSurface->getBasePtr(0, 0); byte *source, *dest;
byte *dest = (byte*)clipInfo.destSurface->getBasePtr(x, y); int startX = 0;
int startY = 0;
int clipWidth = sourceSurface->w;
int clipHeight = sourceSurface->h;
// FIXME: Implement actual clipping if (x < 0) {
if (x + sourceSurface->w > clipInfo.destSurface->w || y + sourceSurface->h > clipInfo.destSurface->h) { startX = -x;
debug(2, "CLIPPING PROBLEM: x = %d; y = %d; w = %d; h = %d; x+w = %d; y+h = %d\n", clipWidth -= startX;
x, y, sourceSurface->w, sourceSurface->h, x + sourceSurface->w, y + sourceSurface->h); x = 0;
return;
} }
for (int16 yc = 0; yc < sourceSurface->h; yc++) { if (y < 0) {
for (int16 xc = 0; xc < sourceSurface->w; xc++) { startY = -y;
clipHeight -= startY;
y = 0;
}
if (x + clipWidth > clipInfo.x + clipInfo.w) {
clipWidth = clipInfo.x + clipInfo.w - x;
}
if (y + clipHeight > clipInfo.y + clipInfo.h) {
clipHeight = clipInfo.y + clipInfo.h - y;
}
source = (byte*)sourceSurface->getBasePtr(startX, startY);
dest = (byte*)clipInfo.destSurface->getBasePtr(x, y);
for (int16 yc = 0; yc < clipHeight; yc++) {
for (int16 xc = 0; xc < clipWidth; xc++) {
if (source[xc]) if (source[xc])
dest[xc] = source[xc]; dest[xc] = source[xc];
} }
@ -133,7 +151,7 @@ void Screen::setRGBPalette(byte *palRGB, int start, int count) {
} }
uint16 Screen::updateChannel(uint16 channelIndex) { uint16 Screen::updateChannel(uint16 channelIndex) {
return 0; return channelIndex;
} }
void Screen::deleteChannel(uint16 channelIndex) { void Screen::deleteChannel(uint16 channelIndex) {
@ -303,10 +321,6 @@ void Screen::drawAnimFrame(uint16 animIndex, int16 x, int16 y, int16 frameNum, u
} }
uint16 Screen::drawPic(uint16 index, int16 x, int16 y, uint16 flag1, uint16 flag2) { uint16 Screen::drawPic(uint16 index, int16 x, int16 y, uint16 flag1, uint16 flag2) {
//HACK (until clipping is implemented)
if (y > 200) y = 0;
drawFlex(index, x, y, flag1, flag2, _clipInfo1); drawFlex(index, x, y, flag1, flag2, _clipInfo1);
return 0; return 0;
} }
@ -624,7 +638,6 @@ void Screen::printText(const char *text) {
linePos = 1; linePos = 1;
x = _textRect.left; x = _textRect.left;
} else if (c == 32) { } else if (c == 32) {
// TODO: Word-wrap
int wrapPos = textPos + 1; int wrapPos = textPos + 1;
int wrapX = x + charWidth; int wrapX = x + charWidth;
while (wrapPos < textLen && text[wrapPos] != 0 && text[wrapPos] != 32 && text[wrapPos] >= 28) { while (wrapPos < textLen && text[wrapPos] != 0 && text[wrapPos] != 32 && text[wrapPos] >= 28) {
@ -682,6 +695,7 @@ void Screen::printTextEx(const char *text, int16 x, int16 y, int16 fontNum, int1
int16 oldFontNum = _currentFontNum; int16 oldFontNum = _currentFontNum;
Common::Rect oldTextRect; Common::Rect oldTextRect;
ClipInfo oldFontDrawCtx = _fontDrawCtx;
_fontDrawCtx = clipInfo; _fontDrawCtx = clipInfo;
@ -693,6 +707,7 @@ void Screen::printTextEx(const char *text, int16 x, int16 y, int16 fontNum, int1
printText(text); printText(text);
setTextRect(oldTextRect); setTextRect(oldTextRect);
setFont(oldFontNum); setFont(oldFontNum);
_fontDrawCtx = oldFontDrawCtx;
} }

View file

@ -408,9 +408,9 @@ int16 ScriptFunctionsRtz::o1_FONT(int16 argc, int16 *argv) {
} }
int16 ScriptFunctionsRtz::o1_DRAWTEXT(int16 argc, int16 *argv) { int16 ScriptFunctionsRtz::o1_DRAWTEXT(int16 argc, int16 *argv) {
warning("Unimplemented opcode: o1_DRAWTEXT");
Object *obj = _vm->_dat->getObject(argv[argc - 1]); Object *obj = _vm->_dat->getObject(argv[argc - 1]);
warning("argc = %d; drawText = %s", argc, obj->getString()); const char *text = obj->getString();
_vm->_screen->printText(text);
return 0; return 0;
} }
@ -420,7 +420,6 @@ int16 ScriptFunctionsRtz::o1_HOMETEXT(int16 argc, int16 *argv) {
} }
int16 ScriptFunctionsRtz::o1_TEXTRECT(int16 argc, int16 *argv) { int16 ScriptFunctionsRtz::o1_TEXTRECT(int16 argc, int16 *argv) {
warning("Unimplemented opcode: o1_TEXTRECT");
int16 x1 = CLIP<int16>(argv[4], 1, 318); int16 x1 = CLIP<int16>(argv[4], 1, 318);
int16 y1 = CLIP<int16>(argv[3], 1, 198); int16 y1 = CLIP<int16>(argv[3], 1, 198);
int16 x2 = CLIP<int16>(argv[2], 1, 318); int16 x2 = CLIP<int16>(argv[2], 1, 318);
@ -536,7 +535,9 @@ int16 ScriptFunctionsRtz::o1_CDPLAYSEG(int16 argc, int16 *argv) {
} }
int16 ScriptFunctionsRtz::o1_PRINTF(int16 argc, int16 *argv) { int16 ScriptFunctionsRtz::o1_PRINTF(int16 argc, int16 *argv) {
warning("Unimplemented opcode: o1_PRINTF"); Object *obj = _vm->_dat->getObject(argv[argc - 1]);
const char *text = obj->getString();
debug(4, "--> text = %s", text);
return 0; return 0;
} }
@ -556,7 +557,7 @@ int16 ScriptFunctionsRtz::o1_SNDENERGY(int16 argc, int16 *argv) {
int16 ScriptFunctionsRtz::o1_CLEARTEXT(int16 argc, int16 *argv) { int16 ScriptFunctionsRtz::o1_CLEARTEXT(int16 argc, int16 *argv) {
warning("Unimplemented opcode: o1_CLEARTEXT"); warning("Unimplemented opcode: o1_CLEARTEXT");
return 0; return 1;
} }
int16 ScriptFunctionsRtz::o1_ANIMTEXT(int16 argc, int16 *argv) { int16 ScriptFunctionsRtz::o1_ANIMTEXT(int16 argc, int16 *argv) {
@ -746,33 +747,89 @@ int16 ScriptFunctionsRtz::o1_READMENU(int16 argc, int16 *argv) {
} }
int16 ScriptFunctionsRtz::o1_DRAWMENU(int16 argc, int16 *argv) { int16 ScriptFunctionsRtz::o1_DRAWMENU(int16 argc, int16 *argv) {
warning("Unimplemented opcode: o1_DRAWMENU"); int16 menuIndex = argv[1];
int16 textIndex = argv[0];
MenuResource *menu = _vm->_res->getMenu(menuIndex);
if (menu) {
const char *text = menu->getString(textIndex);
if (text)
_vm->_screen->printText(text);
_vm->_res->freeResource(menu);
}
return 0; return 0;
} }
int16 ScriptFunctionsRtz::o1_MENUCOUNT(int16 argc, int16 *argv) { int16 ScriptFunctionsRtz::o1_MENUCOUNT(int16 argc, int16 *argv) {
warning("Unimplemented opcode: o1_MENUCOUNT"); int16 menuIndex = argv[0];
return 0; int16 count = 0;
MenuResource *menu = _vm->_res->getMenu(menuIndex);
if (menu) {
count = menu->getCount();
_vm->_res->freeResource(menu);
}
return count;
} }
int16 ScriptFunctionsRtz::o1_SAVEGAME(int16 argc, int16 *argv) { int16 ScriptFunctionsRtz::o1_SAVEGAME(int16 argc, int16 *argv) {
warning("Unimplemented opcode: o1_SAVEGAME");
return 0; int16 saveNum = argv[2];
int16 descObjectIndex = argv[1];
int16 version = argv[0];
if (saveNum > 999)
return 6;
Object *obj = _vm->_dat->getObject(descObjectIndex);
const char *description = obj->getString();
// TODO: Use better filename
char filename[256];
snprintf(filename, 256, "rtz.%03d", saveNum);
return _vm->_dat->savegame(filename, description, version);
} }
int16 ScriptFunctionsRtz::o1_LOADGAME(int16 argc, int16 *argv) { int16 ScriptFunctionsRtz::o1_LOADGAME(int16 argc, int16 *argv) {
warning("Unimplemented opcode: o1_LOADGAME");
return 0; int16 saveNum = argv[1];
int16 version = argv[0];
if (saveNum > 999)
return 1;
// TODO: Use better filename
char filename[256];
snprintf(filename, 256, "rtz.%03d", saveNum);
return _vm->_dat->loadgame(filename, version);
} }
int16 ScriptFunctionsRtz::o1_GAMENAME(int16 argc, int16 *argv) { int16 ScriptFunctionsRtz::o1_GAMENAME(int16 argc, int16 *argv) {
warning("Unimplemented opcode: o1_GAMENAME");
warning("GAMENAME: 1) %d\n", argv[2]); int16 descObjectIndex = argv[2];
warning("GAMENAME: 2) %d\n", argv[1]); int16 saveNum = argv[1];
warning("GAMENAME: 3) %d\n", argv[0]); int16 version = argv[0];
Common::String description;
if (saveNum > 999)
return 1;
// TODO: Use better filename
char filename[256];
snprintf(filename, 256, "rtz.%03d", saveNum);
Object *obj = _vm->_dat->getObject(descObjectIndex);
if (_vm->_dat->getSavegameDescription(filename, description)) {
obj->setString(description.c_str());
return 0; return 0;
} else {
obj->setString("");
return 1;
}
} }
int16 ScriptFunctionsRtz::o1_SHAKESCREEN(int16 argc, int16 *argv) { int16 ScriptFunctionsRtz::o1_SHAKESCREEN(int16 argc, int16 *argv) {