void KyraRpgEngine::releaseTempData() { for (int i = 0; i < 29; i++) { if (_lvlTempData[i]) { delete[] _lvlTempData[i]->wallsXorData; delete[] _lvlTempData[i]->flags; releaseMonsterTempData(_lvlTempData[i]); releaseFlyingObjectTempData(_lvlTempData[i]); releaseWallOfForceTempData(_lvlTempData[i]); delete _lvlTempData[i]; _lvlTempData[i] = 0; } } }
void KyraRpgEngine::generateTempData() { int l = _currentLevel - 1; if (_lvlTempData[l]) { delete[] _lvlTempData[l]->wallsXorData; delete[] _lvlTempData[l]->flags; releaseMonsterTempData(_lvlTempData[l]); releaseFlyingObjectTempData(_lvlTempData[l]); releaseWallOfForceTempData(_lvlTempData[l]); delete _lvlTempData[l]; } _lvlTempData[l] = new LevelTempData; _lvlTempData[l]->wallsXorData = new uint8[4096]; _lvlTempData[l]->flags = new uint16[1024]; const uint8 *p = getBlockFileData(_currentLevel); uint16 len = READ_LE_UINT16(p + 4); p += 6; memset(_lvlTempData[l]->wallsXorData, 0, 4096); memset(_lvlTempData[l]->flags, 0, 1024 * sizeof(uint16)); uint8 *d = _lvlTempData[l]->wallsXorData; uint16 *df = _lvlTempData[l]->flags; for (int i = 0; i < 1024; i++) { for (int ii = 0; ii < 4; ii++) *d++ = p[i * len + ii] ^ _levelBlockProperties[i].walls[ii]; *df++ = _levelBlockProperties[i].flags; } _lvlTempData[l]->monsters = generateMonsterTempData(_lvlTempData[l]); _lvlTempData[l]->flyingObjects = generateFlyingObjectTempData(_lvlTempData[l]); _lvlTempData[l]->wallsOfForce = generateWallOfForceTempData(_lvlTempData[l]); _hasTempDataFlags |= (1 << l); }
Common::Error EoBCoreEngine::loadGameState(int slot) { // Special slot id -1 for EOB1 party transfer const char *fileName = (slot == -1) ? _savegameFilename.c_str() : getSavegameFilename(slot); SaveHeader header; Common::InSaveFile *saveFile = openSaveForReading(fileName, header, (slot != -1)); if (!saveFile) return Common::Error(Common::kReadingFailed); Common::SeekableSubReadStreamEndian in(saveFile, saveFile->pos(), saveFile->size(), !header.originalSave, DisposeAfterUse::YES); _loading = true; if (slot != -1) _screen->fadeToBlack(10); for (int i = 0; i < 6; i++) { EoBCharacter *c = &_characters[i]; c->id = in.readByte(); c->flags = in.readByte(); in.read(c->name, 11); c->strengthCur = in.readSByte(); c->strengthMax = in.readSByte(); c->strengthExtCur = in.readSByte(); c->strengthExtMax = in.readSByte(); c->intelligenceCur = in.readSByte(); c->intelligenceMax = in.readSByte(); c->wisdomCur = in.readSByte(); c->wisdomMax = in.readSByte(); c->dexterityCur = in.readSByte(); c->dexterityMax = in.readSByte(); c->constitutionCur = in.readSByte(); c->constitutionMax = in.readSByte(); c->charismaCur = in.readSByte(); c->charismaMax = in.readSByte(); c->hitPointsCur = in.readSint16BE(); c->hitPointsMax = in.readSint16BE(); c->armorClass = in.readSByte(); c->disabledSlots = in.readByte(); c->raceSex = in.readByte(); c->cClass = in.readByte(); c->alignment = in.readByte(); c->portrait = in.readSByte(); if (slot == -1 && c->portrait < 0) c->portrait = -c->portrait + 43; c->food = in.readByte(); in.read(c->level, 3); for (int ii = 0; ii < 3; ii++) c->experience[ii] = in.readUint32BE(); delete[] c->faceShape; c->faceShape = 0; in.read(c->mageSpells, 80); in.read(c->clericSpells, 80); c->mageSpellsAvailableFlags = in.readUint32BE(); for (int ii = 0; ii < 27; ii++) c->inventory[ii] = in.readSint16BE(); uint32 ct = _system->getMillis(); for (int ii = 0; ii < 10; ii++) { c->timers[ii] = in.readUint32BE(); if (c->timers[ii]) c->timers[ii] += ct; } in.read(c->events, 10); in.read(c->effectsRemainder, 4); c->effectFlags = in.readUint32BE(); c->damageTaken = in.readByte(); in.read(c->slotStatus, 5); } setupCharacterTimers(); _screen->loadShapeSetBitmap("CHARGENA", 3, 3); for (int i = 0; i < 6; i++) { EoBCharacter *c = &_characters[i]; if (!c->flags || c->portrait < 0) continue; c->faceShape = _screen->encodeShape((c->portrait % 10) << 2, (c->portrait / 10) << 5, 4, 32, true); } _screen->loadShapeSetBitmap(_flags.gameID == GI_EOB2 ? "OUTPORTS" : "OUTTAKE", 3, 3); for (int i = 0; i < 6; i++) { EoBCharacter *c = &_characters[i]; if (!c->flags || c->portrait >= 0) continue; c->faceShape = _screen->encodeShape((-(c->portrait + 1)) << 2, _flags.gameID == GI_EOB2 ? 0 : 160, 4, 32, true); } _screen->_curPage = 0; if (slot == -1) { // Skip all settings which aren't necessary for party transfer. // Jump directly to the items list. in.skip(108); } else { _currentLevel = in.readByte(); _currentSub = in.readSByte(); _currentBlock = in.readUint16BE(); _currentDirection = in.readUint16BE(); _itemInHand = in.readSint16BE(); _hasTempDataFlags = in.readUint32BE(); _partyEffectFlags = in.readUint32BE(); _updateFlags = in.readUint16BE(); _compassDirection = in.readUint16BE(); _currentControlMode = in.readUint16BE(); _updateCharNum = in.readUint16BE(); _openBookSpellLevel = in.readSByte(); _openBookSpellSelectedItem = in.readSByte(); _openBookSpellListOffset = in.readSByte(); _openBookChar = in.readByte(); _openBookType = in.readByte(); _openBookCharBackup = in.readByte(); _openBookTypeBackup = in.readByte(); _activeSpellCharId = in.readByte(); _activeSpellCharacterPos = in.readByte(); _activeSpell = in.readByte(); _returnAfterSpellCallback = in.readByte() ? true : false; _inf->loadState(in); } for (int i = 0; i < 600; i++) { EoBItem *t = &_items[i]; t->nameUnid = in.readByte(); t->nameId = in.readByte(); t->flags = in.readByte(); t->icon = in.readSByte(); t->type = in.readSByte(); t->pos = in.readSByte(); t->block = in.readSint16BE(); t->next = in.readSint16BE(); t->prev = in.readSint16BE(); t->level = in.readByte(); t->value = in.readSByte(); } // No more data needed for party transfer if (slot == -1) { _loading = false; return Common::kNoError; } for (int i = 51; i < 65; i++) { EoBItemType *t = &_itemTypes[i]; t->invFlags = in.readUint16BE(); t->handFlags = in.readUint16BE(); t->armorClass = in.readSByte(); t->allowedClasses = in.readSByte(); t->requiredHands = in.readSByte(); t->dmgNumDiceS = in.readSByte(); t->dmgNumPipsS = in.readSByte(); t->dmgIncS = in.readSByte(); t->dmgNumDiceL = in.readSByte(); t->dmgNumPipsL = in.readSByte(); t->dmgIncL = in.readSByte(); t->unk1 = in.readByte(); t->extraProperties = in.readUint16BE(); } for (int i = 0; i < 18; i++) { if (!(_hasTempDataFlags & (1 << i))) continue; if (_lvlTempData[i]) { delete[] _lvlTempData[i]->wallsXorData; delete[] _lvlTempData[i]->flags; releaseMonsterTempData(_lvlTempData[i]); releaseFlyingObjectTempData(_lvlTempData[i]); releaseWallOfForceTempData(_lvlTempData[i]); delete _lvlTempData[i]; } _lvlTempData[i] = new LevelTempData; LevelTempData *l = _lvlTempData[i]; l->wallsXorData = new uint8[4096]; l->flags = new uint16[1024]; EoBMonsterInPlay *lm = new EoBMonsterInPlay[30]; l->monsters = lm; EoBFlyingObject *lf = new EoBFlyingObject[_numFlyingObjects]; l->flyingObjects = lf; WallOfForce *lw = new WallOfForce[5]; l->wallsOfForce = lw; in.read(l->wallsXorData, 4096); for (int ii = 0; ii < 1024; ii++) l->flags[ii] = in.readByte(); for (int ii = 0; ii < 30; ii++) { EoBMonsterInPlay *m = &lm[ii]; m->type = in.readByte(); m->unit = in.readByte(); m->block = in.readUint16BE(); m->pos = in.readByte(); m->dir = in.readSByte(); m->animStep = in.readByte(); m->shpIndex = in.readByte(); m->mode = in.readSByte(); m->f_9 = in.readSByte(); m->curAttackFrame = in.readSByte(); m->spellStatusLeft = in.readSByte(); m->hitPointsMax = in.readSint16BE(); m->hitPointsCur = in.readSint16BE(); m->dest = in.readUint16BE(); m->randItem = in.readUint16BE(); m->fixedItem = in.readUint16BE(); m->flags = in.readByte(); m->idleAnimState = in.readByte(); m->curRemoteWeapon = in.readByte(); m->numRemoteAttacks = in.readByte(); m->palette = in.readSByte(); m->directionChanged = in.readByte(); m->stepsTillRemoteAttack = in.readByte(); m->sub = in.readByte(); } for (int ii = 0; ii < _numFlyingObjects; ii++) { EoBFlyingObject *m = &lf[ii]; m->enable = in.readByte(); m->objectType = in.readByte(); m->attackerId = in.readSint16BE(); m->item = in.readSint16BE(); m->curBlock = in.readUint16BE(); m->u2 = in.readUint16BE(); m->u1 = in.readByte(); m->direction = in.readByte(); m->distance = in.readByte(); m->callBackIndex = in.readSByte(); m->curPos = in.readByte(); m->flags = in.readByte(); m->unused = in.readByte(); } for (int ii = 0; ii < 5; ii++) { WallOfForce *w = &lw[ii]; w->block = in.readUint16BE(); w->duration = in.readUint32BE(); } } loadLevel(_currentLevel, _currentSub); _sceneUpdateRequired = true; _screen->setFont(Screen::FID_6_FNT); for (int i = 0; i < 6; i++) { for (int ii = 0; ii < 10; ii++) { if (_characters[i].events[ii] == -57) spellCallback_start_trueSeeing(); } } _screen->setCurPage(0); gui_drawPlayField(false); if (_currentControlMode) _screen->copyRegion(176, 0, 0, 0, 144, 168, 0, 5, Screen::CR_NO_P_CHECK); _screen->setCurPage(0); gui_drawAllCharPortraitsWithStats(); drawScene(1); if (_updateFlags) { _updateFlags = 0; useMagicBookOrSymbol(_openBookChar, _openBookType); } _screen->copyRegion(0, 120, 0, 0, 176, 24, 0, 12, Screen::CR_NO_P_CHECK); gui_toggleButtons(); setHandItem(_itemInHand); while (!_screen->isMouseVisible()) _screen->showMouse(); _loading = false; _screen->fadeFromBlack(20); removeInputTop(); return Common::kNoError; }
Common::String EoBCoreEngine::readOriginalSaveFile(Common::String &file) { Common::String desc; Common::SeekableReadStream *fs = _res->createReadStream(file); if (!fs) return desc; Common::SeekableSubReadStreamEndian in(fs, 0, fs->size(), _flags.platform == Common::kPlatformAmiga, DisposeAfterUse::YES); if (_flags.gameID == GI_EOB1) { // Nothing to read here for EOB 1. Original EOB 1 has // only one save slot without save file description. desc = "<IMPORTED GAME>"; } else { char tempStr[20]; in.read(tempStr, 20); desc = tempStr; } for (int i = 0; i < 6; i++) { EoBCharacter *c = &_characters[i]; c->id = in.readByte(); c->flags = in.readByte(); in.read(c->name, 11); c->strengthCur = in.readSByte(); c->strengthMax = in.readSByte(); c->strengthExtCur = in.readSByte(); c->strengthExtMax = in.readSByte(); c->intelligenceCur = in.readSByte(); c->intelligenceMax = in.readSByte(); c->wisdomCur = in.readSByte(); c->wisdomMax = in.readSByte(); c->dexterityCur = in.readSByte(); c->dexterityMax = in.readSByte(); c->constitutionCur = in.readSByte(); c->constitutionMax = in.readSByte(); c->charismaCur = in.readSByte(); c->charismaMax = in.readSByte(); c->hitPointsCur = (_flags.gameID == GI_EOB1) ? in.readSByte() : in.readSint16(); c->hitPointsMax = (_flags.gameID == GI_EOB1) ? in.readSByte() : in.readSint16(); c->armorClass = in.readSByte(); c->disabledSlots = in.readByte(); c->raceSex = in.readByte(); c->cClass = in.readByte(); c->alignment = in.readByte(); c->portrait = in.readSByte(); c->food = in.readByte(); in.read(c->level, 3); for (int ii = 0; ii < 3; ii++) c->experience[ii] = in.readUint32(); in.skip(4); delete[] c->faceShape; c->faceShape = 0; in.read(c->mageSpells, (_flags.gameID == GI_EOB1) ? 30 : 80); in.read(c->clericSpells, (_flags.gameID == GI_EOB1) ? 30 : 80); c->mageSpellsAvailableFlags = in.readUint32(); for (int ii = 0; ii < 27; ii++) c->inventory[ii] = in.readSint16(); uint32 ct = _system->getMillis(); for (int ii = 0; ii < 10; ii++) { c->timers[ii] = in.readUint32() * _tickLength; if (c->timers[ii]) c->timers[ii] += ct; } in.read(c->events, 10); in.read(c->effectsRemainder, 4); c->effectFlags = in.readUint32(); if (c->effectFlags && _flags.gameID == GI_EOB1) { warning("EoBCoreEngine::readOriginalSaveFile(): Unhandled character effect flags encountered in original EOB1 save file '%s' ('%s')", file.c_str(), desc.c_str()); c->effectFlags = 0; } c->damageTaken = in.readByte(); in.read(c->slotStatus, 5); in.skip(6); } setupCharacterTimers(); _currentLevel = in.readUint16(); _currentSub = (_flags.gameID == GI_EOB1) ? 0 : in.readSint16(); _currentBlock = in.readUint16(); _currentDirection = in.readUint16(); _itemInHand = in.readSint16(); _hasTempDataFlags = (_flags.gameID == GI_EOB1) ? in.readUint16() : in.readUint32(); _partyEffectFlags = (_flags.gameID == GI_EOB1) ? in.readUint16() : in.readUint32(); if (_partyEffectFlags && _flags.gameID == GI_EOB1) { warning("EoBCoreEngine::readOriginalSaveFile(): Unhandled party effect flags encountered in original EOB1 save file '%s' ('%s')", file.c_str(), desc.c_str()); _partyEffectFlags = 0; } if (_flags.gameID == GI_EOB2) in.skip(1); _inf->loadState(in, true); int numItems = (_flags.gameID == GI_EOB1) ? 500 : 600; for (int i = 0; i < numItems; i++) { EoBItem *t = &_items[i]; t->nameUnid = in.readByte(); t->nameId = in.readByte(); t->flags = in.readByte(); t->icon = in.readSByte(); t->type = in.readSByte(); t->pos = in.readSByte(); t->block = in.readSint16(); t->next = in.readSint16(); t->prev = in.readSint16(); t->level = in.readByte(); t->value = in.readSByte(); } int numParts = (_flags.gameID == GI_EOB1) ? 13 : 18; int partSize = (_flags.gameID == GI_EOB1) ? 2040 : 2130; uint32 nextPart = in.pos(); uint8 *cmpData = new uint8[1200]; for (int i = 0; i < numParts; i++) { in.seek(nextPart); nextPart += partSize; if (!(_hasTempDataFlags & (1 << i))) continue; if (_lvlTempData[i]) { delete[] _lvlTempData[i]->wallsXorData; delete[] _lvlTempData[i]->flags; releaseMonsterTempData(_lvlTempData[i]); releaseFlyingObjectTempData(_lvlTempData[i]); releaseWallOfForceTempData(_lvlTempData[i]); delete _lvlTempData[i]; } _lvlTempData[i] = new LevelTempData; LevelTempData *l = _lvlTempData[i]; l->wallsXorData = new uint8[4096]; l->flags = new uint16[1024]; memset(l->flags, 0, 1024 * sizeof(uint16)); EoBMonsterInPlay *lm = new EoBMonsterInPlay[30]; l->monsters = lm; EoBFlyingObject *lf = new EoBFlyingObject[_numFlyingObjects]; memset(lf, 0, _numFlyingObjects * sizeof(EoBFlyingObject)); l->flyingObjects = lf; WallOfForce *lw = new WallOfForce[5]; memset(lw, 0, 5 * sizeof(WallOfForce)); l->wallsOfForce = lw; in.read(cmpData, 1200); _screen->decodeFrame4(cmpData, l->wallsXorData, 4096); _curBlockFile = getBlockFileName(i + 1, 0); const uint8 *p = getBlockFileData(); uint16 len = READ_LE_UINT16(p + 4); p += 6; uint8 *d = l->wallsXorData; for (int ii = 0; ii < 1024; ii++) { for (int iii = 0; iii < 4; iii++) *d++ ^= p[ii * len + iii]; } for (int ii = 0; ii < 30; ii++) { EoBMonsterInPlay *m = &lm[ii]; m->type = in.readByte(); m->unit = in.readByte(); m->block = in.readUint16(); m->pos = in.readByte(); m->dir = in.readSByte(); m->animStep = in.readByte(); m->shpIndex = in.readByte(); m->mode = in.readSByte(); m->f_9 = in.readSByte(); m->curAttackFrame = in.readSByte(); m->spellStatusLeft = in.readSByte(); m->hitPointsMax = in.readSint16(); m->hitPointsCur = in.readSint16(); m->dest = in.readUint16(); m->randItem = in.readUint16(); m->fixedItem = in.readUint16(); m->flags = in.readByte(); m->idleAnimState = in.readByte(); if (_flags.gameID == GI_EOB1) m->stepsTillRemoteAttack = in.readByte(); else m->curRemoteWeapon = in.readByte(); m->numRemoteAttacks = in.readByte(); m->palette = in.readSByte(); if (_flags.gameID == GI_EOB1) { in.skip(1); } else { m->directionChanged = in.readByte(); m->stepsTillRemoteAttack = in.readByte(); m->sub = in.readByte(); } _levelBlockProperties[m->block].flags++; } if (_flags.gameID == GI_EOB1) continue; for (int ii = 0; ii < 5; ii++) { WallOfForce *w = &lw[ii]; w->block = in.readUint16(); w->duration = in.readUint32(); } } delete[] cmpData; restoreBlockTempData(_currentLevel); in.skip(3); delete[] _itemTypes; _itemTypes = new EoBItemType[65]; memset(_itemTypes, 0, sizeof(EoBItemType) * 65); if (_flags.gameID == GI_EOB1) return desc; for (int i = 51; i < 65; i++) { EoBItemType *t = &_itemTypes[i]; t->invFlags = in.readUint16(); t->handFlags = in.readUint16(); t->armorClass = in.readSByte(); t->allowedClasses = in.readSByte(); t->requiredHands = in.readSByte(); t->dmgNumDiceS = in.readSByte(); t->dmgNumPipsS = in.readSByte(); t->dmgIncS = in.readSByte(); t->dmgNumDiceL = in.readSByte(); t->dmgNumPipsL = in.readSByte(); t->dmgIncL = in.readSByte(); t->unk1 = in.readByte(); t->extraProperties = in.readUint16(); } return in.err() ? Common::String() : desc; }