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/util.h"
#include "common/savefile.h"
#include "made/database.h"
@ -222,8 +224,7 @@ void GameDatabase::load(Common::SeekableReadStream &sourceS) {
uint32 objectsSize = sourceS.readUint32LE();
_mainCodeObjectIndex = sourceS.readUint16LE();
debug(2, "objectIndexOffs = %08X; objectCount = %d; gameStateOffs = %08X; gameStateSize = %d; objectsOffs = %08X; objectsSize = %d\n",
objectIndexOffs, objectCount, gameStateOffs, _gameStateSize, objectsOffs, objectsSize);
//debug(2, "objectIndexOffs = %08X; objectCount = %d; gameStateOffs = %08X; gameStateSize = %d; objectsOffs = %08X; objectsSize = %d\n", objectIndexOffs, objectCount, gameStateOffs, _gameStateSize, objectsOffs, objectsSize);
_gameState = new byte[_gameStateSize];
sourceS.seek(gameStateOffs);
@ -241,14 +242,14 @@ void GameDatabase::load(Common::SeekableReadStream &sourceS) {
// Constant objects are loaded from disk, while variable objects exist
// 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) {
debug(2, "-> const %08X\n", objectsOffs + objectOffsets[i] - 1);
//debug(2, "-> const %08X\n", objectsOffs + objectOffsets[i] - 1);
sourceS.seek(objectsOffs + objectOffsets[i] - 1);
obj->load(sourceS);
} else {
debug(2, "-> var\n");
//debug(2, "-> var\n");
obj->load(_gameState + objectOffsets[i]);
}
_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) {
return (int16)READ_LE_UINT16(_gameState + index * 2);
}

View file

@ -30,6 +30,7 @@
#include "common/util.h"
#include "common/file.h"
#include "common/stream.h"
#include "common/str.h"
#include "made/redreader.h"
@ -78,6 +79,10 @@ public:
void open(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 {
if (index >= 1)
return _objects[index - 1];

View file

@ -92,23 +92,41 @@ void Screen::clearScreen() {
_screen1->fillRect(Common::Rect(0, 0, 320, 200), 0);
_screen2->fillRect(Common::Rect(0, 0, 320, 200), 0);
_needPalette = true;
//_vm->_system->clearScreen();
}
void Screen::drawSurface(Graphics::Surface *sourceSurface, int x, int y, const ClipInfo &clipInfo) {
byte *source = (byte*)sourceSurface->getBasePtr(0, 0);
byte *dest = (byte*)clipInfo.destSurface->getBasePtr(x, y);
byte *source, *dest;
int startX = 0;
int startY = 0;
int clipWidth = sourceSurface->w;
int clipHeight = sourceSurface->h;
// FIXME: Implement actual clipping
if (x + sourceSurface->w > clipInfo.destSurface->w || y + sourceSurface->h > clipInfo.destSurface->h) {
debug(2, "CLIPPING PROBLEM: x = %d; y = %d; w = %d; h = %d; x+w = %d; y+h = %d\n",
x, y, sourceSurface->w, sourceSurface->h, x + sourceSurface->w, y + sourceSurface->h);
return;
if (x < 0) {
startX = -x;
clipWidth -= startX;
x = 0;
}
for (int16 yc = 0; yc < sourceSurface->h; yc++) {
for (int16 xc = 0; xc < sourceSurface->w; xc++) {
if (y < 0) {
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])
dest[xc] = source[xc];
}
@ -133,7 +151,7 @@ void Screen::setRGBPalette(byte *palRGB, int start, int count) {
}
uint16 Screen::updateChannel(uint16 channelIndex) {
return 0;
return 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) {
//HACK (until clipping is implemented)
if (y > 200) y = 0;
drawFlex(index, x, y, flag1, flag2, _clipInfo1);
return 0;
}
@ -624,7 +638,6 @@ void Screen::printText(const char *text) {
linePos = 1;
x = _textRect.left;
} else if (c == 32) {
// TODO: Word-wrap
int wrapPos = textPos + 1;
int wrapX = x + charWidth;
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;
Common::Rect oldTextRect;
ClipInfo oldFontDrawCtx = _fontDrawCtx;
_fontDrawCtx = clipInfo;
@ -693,6 +707,7 @@ void Screen::printTextEx(const char *text, int16 x, int16 y, int16 fontNum, int1
printText(text);
setTextRect(oldTextRect);
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) {
warning("Unimplemented opcode: o1_DRAWTEXT");
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;
}
@ -420,7 +420,6 @@ int16 ScriptFunctionsRtz::o1_HOMETEXT(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 y1 = CLIP<int16>(argv[3], 1, 198);
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) {
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;
}
@ -556,7 +557,7 @@ int16 ScriptFunctionsRtz::o1_SNDENERGY(int16 argc, int16 *argv) {
int16 ScriptFunctionsRtz::o1_CLEARTEXT(int16 argc, int16 *argv) {
warning("Unimplemented opcode: o1_CLEARTEXT");
return 0;
return 1;
}
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) {
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;
}
int16 ScriptFunctionsRtz::o1_MENUCOUNT(int16 argc, int16 *argv) {
warning("Unimplemented opcode: o1_MENUCOUNT");
return 0;
int16 menuIndex = argv[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) {
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) {
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) {
warning("Unimplemented opcode: o1_GAMENAME");
warning("GAMENAME: 1) %d\n", argv[2]);
warning("GAMENAME: 2) %d\n", argv[1]);
warning("GAMENAME: 3) %d\n", argv[0]);
int16 descObjectIndex = argv[2];
int16 saveNum = argv[1];
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;
} else {
obj->setString("");
return 1;
}
}
int16 ScriptFunctionsRtz::o1_SHAKESCREEN(int16 argc, int16 *argv) {