bool ESMStore::readRecord (ESM::ESMReader& reader, uint32_t type) { switch (type) { case ESM::REC_ALCH: case ESM::REC_ARMO: case ESM::REC_BOOK: case ESM::REC_CLAS: case ESM::REC_CLOT: case ESM::REC_ENCH: case ESM::REC_SPEL: case ESM::REC_WEAP: case ESM::REC_NPC_: case ESM::REC_LEVI: case ESM::REC_LEVC: { std::string id = reader.getHNString ("NAME"); mStores[type]->read (reader, id); // FIXME: there might be stale dynamic IDs in mIds from an earlier savegame // that really should be cleared instead of just overwritten mIds[id] = type; } if (type==ESM::REC_NPC_) { // NPC record will always be last and we know that there can be only one // dynamic NPC record (player) -> We are done here with dynamic record laoding setUp(); const ESM::NPC *player = mNpcs.find ("player"); if (!mRaces.find (player->mRace) || !mClasses.find (player->mClass)) throw std::runtime_error ("Invalid player record (race or class unavailable"); } return true; case ESM::REC_DYNA: reader.getSubNameIs("COUN"); reader.getHT(mDynamicCount); return true; default: return false; } }
bool ESMStore::readRecord (ESM::ESMReader& reader, uint32_t type) { switch (type) { case ESM::REC_ALCH: case ESM::REC_ARMO: case ESM::REC_BOOK: case ESM::REC_CLAS: case ESM::REC_CLOT: case ESM::REC_ENCH: case ESM::REC_SPEL: case ESM::REC_WEAP: case ESM::REC_NPC_: case ESM::REC_LEVI: case ESM::REC_LEVC: { mStores[type]->read (reader); } if (type==ESM::REC_NPC_) { // NPC record will always be last and we know that there can be only one // dynamic NPC record (player) -> We are done here with dynamic record loading setUp(); const ESM::NPC *player = mNpcs.find ("player"); if (!mRaces.find (player->mRace) || !mClasses.find (player->mClass)) throw std::runtime_error ("Invalid player record (race or class unavailable"); } return true; case ESM::REC_DYNA: reader.getSubNameIs("COUN"); reader.getHT(mDynamicCount); return true; default: return false; } }
void CellStore::readReferences (ESM::ESMReader& reader, const std::map<int, int>& contentFileMap) { while (reader.isNextSub ("OBJE")) { unsigned int id = 0; reader.getHT (id); switch (id) { case ESM::REC_ACTI: readReferenceCollection<ESM::ObjectState> (reader, mActivators, contentFileMap); break; case ESM::REC_ALCH: readReferenceCollection<ESM::ObjectState> (reader, mPotions, contentFileMap); break; case ESM::REC_APPA: readReferenceCollection<ESM::ObjectState> (reader, mAppas, contentFileMap); break; case ESM::REC_ARMO: readReferenceCollection<ESM::ObjectState> (reader, mArmors, contentFileMap); break; case ESM::REC_BOOK: readReferenceCollection<ESM::ObjectState> (reader, mBooks, contentFileMap); break; case ESM::REC_CLOT: readReferenceCollection<ESM::ObjectState> (reader, mClothes, contentFileMap); break; case ESM::REC_CONT: readReferenceCollection<ESM::ContainerState> (reader, mContainers, contentFileMap); break; case ESM::REC_CREA: readReferenceCollection<ESM::CreatureState> (reader, mCreatures, contentFileMap); break; case ESM::REC_DOOR: readReferenceCollection<ESM::ObjectState> (reader, mDoors, contentFileMap); break; case ESM::REC_INGR: readReferenceCollection<ESM::ObjectState> (reader, mIngreds, contentFileMap); break; case ESM::REC_LEVC: readReferenceCollection<ESM::ObjectState> (reader, mCreatureLists, contentFileMap); break; case ESM::REC_LEVI: readReferenceCollection<ESM::ObjectState> (reader, mItemLists, contentFileMap); break; case ESM::REC_LIGH: readReferenceCollection<ESM::LightState> (reader, mLights, contentFileMap); break; case ESM::REC_LOCK: readReferenceCollection<ESM::ObjectState> (reader, mLockpicks, contentFileMap); break; case ESM::REC_MISC: readReferenceCollection<ESM::ObjectState> (reader, mMiscItems, contentFileMap); break; case ESM::REC_NPC_: readReferenceCollection<ESM::NpcState> (reader, mNpcs, contentFileMap); break; case ESM::REC_PROB: readReferenceCollection<ESM::ObjectState> (reader, mProbes, contentFileMap); break; case ESM::REC_REPA: readReferenceCollection<ESM::ObjectState> (reader, mRepairs, contentFileMap); break; case ESM::REC_STAT: readReferenceCollection<ESM::ObjectState> (reader, mStatics, contentFileMap); break; case ESM::REC_WEAP: readReferenceCollection<ESM::ObjectState> (reader, mWeapons, contentFileMap); break; default: throw std::runtime_error ("unknown type in cell reference section"); } } }
void CellStore::readReferences (ESM::ESMReader& reader, const std::map<int, int>& contentFileMap, GetCellStoreCallback* callback) { mHasState = true; while (reader.isNextSub ("OBJE")) { unsigned int unused; reader.getHT (unused); // load the RefID first so we know what type of object it is ESM::CellRef cref; cref.loadId(reader, true); int type = MWBase::Environment::get().getWorld()->getStore().find(cref.mRefID); if (type == 0) { std::cerr << "Dropping reference to '" << cref.mRefID << "' (object no longer exists)" << std::endl; reader.skipHSubUntil("OBJE"); continue; } switch (type) { case ESM::REC_ACTI: readReferenceCollection<ESM::ObjectState> (reader, mActivators, cref, contentFileMap); break; case ESM::REC_ALCH: readReferenceCollection<ESM::ObjectState> (reader, mPotions, cref, contentFileMap); break; case ESM::REC_APPA: readReferenceCollection<ESM::ObjectState> (reader, mAppas, cref, contentFileMap); break; case ESM::REC_ARMO: readReferenceCollection<ESM::ObjectState> (reader, mArmors, cref, contentFileMap); break; case ESM::REC_BOOK: readReferenceCollection<ESM::ObjectState> (reader, mBooks, cref, contentFileMap); break; case ESM::REC_CLOT: readReferenceCollection<ESM::ObjectState> (reader, mClothes, cref, contentFileMap); break; case ESM::REC_CONT: readReferenceCollection<ESM::ContainerState> (reader, mContainers, cref, contentFileMap); break; case ESM::REC_CREA: readReferenceCollection<ESM::CreatureState> (reader, mCreatures, cref, contentFileMap); break; case ESM::REC_DOOR: readReferenceCollection<ESM::DoorState> (reader, mDoors, cref, contentFileMap); break; case ESM::REC_INGR: readReferenceCollection<ESM::ObjectState> (reader, mIngreds, cref, contentFileMap); break; case ESM::REC_LEVC: readReferenceCollection<ESM::CreatureLevListState> (reader, mCreatureLists, cref, contentFileMap); break; case ESM::REC_LEVI: readReferenceCollection<ESM::ObjectState> (reader, mItemLists, cref, contentFileMap); break; case ESM::REC_LIGH: readReferenceCollection<ESM::ObjectState> (reader, mLights, cref, contentFileMap); break; case ESM::REC_LOCK: readReferenceCollection<ESM::ObjectState> (reader, mLockpicks, cref, contentFileMap); break; case ESM::REC_MISC: readReferenceCollection<ESM::ObjectState> (reader, mMiscItems, cref, contentFileMap); break; case ESM::REC_NPC_: readReferenceCollection<ESM::NpcState> (reader, mNpcs, cref, contentFileMap); break; case ESM::REC_PROB: readReferenceCollection<ESM::ObjectState> (reader, mProbes, cref, contentFileMap); break; case ESM::REC_REPA: readReferenceCollection<ESM::ObjectState> (reader, mRepairs, cref, contentFileMap); break; case ESM::REC_STAT: readReferenceCollection<ESM::ObjectState> (reader, mStatics, cref, contentFileMap); break; case ESM::REC_WEAP: readReferenceCollection<ESM::ObjectState> (reader, mWeapons, cref, contentFileMap); break; case ESM::REC_BODY: readReferenceCollection<ESM::ObjectState> (reader, mBodyParts, cref, contentFileMap); break; default: throw std::runtime_error ("unknown type in cell reference section"); } } // Do another update here to make sure objects referred to by MVRF tags can be found // This update is only needed for old saves that used the old copy&delete way of moving objects updateMergedRefs(); while (reader.isNextSub("MVRF")) { reader.cacheSubName(); ESM::RefNum refnum; ESM::CellId movedTo; refnum.load(reader, true, "MVRF"); movedTo.load(reader); // Search for the reference. It might no longer exist if its content file was removed. SearchByRefNumVisitor visitor(refnum); forEachInternal(visitor); if (!visitor.mFound) { std::cerr << "Dropping moved ref tag for " << refnum.mIndex << " (moved object no longer exists)" << std::endl; continue; } MWWorld::LiveCellRefBase* movedRef = visitor.mFound; CellStore* otherCell = callback->getCellStore(movedTo); if (otherCell == NULL) { std::cerr << "Dropping moved ref tag for " << movedRef->mRef.getRefId() << " (target cell " << movedTo.mWorldspace << " no longer exists). Reference moved back to its original location." << std::endl; // Note by dropping tag the object will automatically re-appear in its original cell, though potentially at inapproriate coordinates. // Restore original coordinates: movedRef->mData.setPosition(movedRef->mRef.getPosition()); continue; } if (otherCell == this) { // Should never happen unless someone's tampering with files. std::cerr << "Found invalid moved ref, ignoring" << std::endl; continue; } moveTo(MWWorld::Ptr(movedRef, this), otherCell); } }
void PCDT::load(ESM::ESMReader &esm) { while (esm.isNextSub("DNAM")) { mKnownDialogueTopics.push_back(esm.getHString()); } mHasMark = false; if (esm.isNextSub("MNAM")) { mHasMark = true; mMNAM = esm.getHString(); } esm.getHNT(mPNAM, "PNAM"); if (esm.isNextSub("SNAM")) esm.skipHSub(); if (esm.isNextSub("NAM9")) esm.skipHSub(); // Rest state. You shouldn't even be able to save during rest, but skip just in case. if (esm.isNextSub("RNAM")) /* int hoursLeft; float x, y, z; // resting position */ esm.skipHSub(); // 16 bytes mBounty = 0; esm.getHNOT(mBounty, "CNAM"); mBirthsign = esm.getHNOString("BNAM"); // Holds the names of the last used Alchemy apparatus. Don't need to import this ATM, // because our GUI auto-selects the best apparatus. if (esm.isNextSub("NAM0")) esm.skipHSub(); if (esm.isNextSub("NAM1")) esm.skipHSub(); if (esm.isNextSub("NAM2")) esm.skipHSub(); if (esm.isNextSub("NAM3")) esm.skipHSub(); mHasENAM = false; if (esm.isNextSub("ENAM")) { mHasENAM = true; esm.getHT(mENAM); } if (esm.isNextSub("LNAM")) esm.skipHSub(); while (esm.isNextSub("FNAM")) { FNAM fnam; esm.getHT(fnam); mFactions.push_back(fnam); } mHasAADT = false; if (esm.isNextSub("AADT")) // Attack animation data? { mHasAADT = true; esm.getHT(mAADT); } if (esm.isNextSub("KNAM")) esm.skipHSub(); // assigned Quick Keys, I think if (esm.isNextSub("ANIS")) esm.skipHSub(); // 16 bytes if (esm.isNextSub("WERE")) { // some werewolf data, 152 bytes // maybe current skills and attributes for werewolf form esm.getSubHeader(); esm.skip(152); } }
void Inventory::load(ESM::ESMReader &esm) { while (esm.isNextSub("NPCO")) { ESM::ContItem contItem; esm.getHT(contItem); InventoryItem item; item.mId = contItem.mItem.toString(); item.mCount = contItem.mCount; item.mRelativeEquipmentSlot = -1; unsigned int itemCount = std::abs(item.mCount); bool separateStacks = false; for (unsigned int i=0;i<itemCount;++i) { bool newStack = esm.isNextSub("XIDX"); if (newStack) { unsigned int idx; esm.getHT(idx); separateStacks = true; item.mCount = 1; } item.mSCRI.load(esm); // for XSOL and XCHG seen so far, but probably others too bool isDeleted = false; item.ESM::CellRef::loadData(esm, isDeleted); int charge=-1; esm.getHNOT(charge, "XHLT"); item.mChargeInt = charge; if (newStack) mItems.push_back(item); } if (!separateStacks) mItems.push_back(item); } // equipped items while (esm.isNextSub("WIDX")) { // note: same item can be equipped 2 items (e.g. 2 rings) // and will be *stacked* in the NPCO list, unlike openmw! // this is currently not handled properly. esm.getSubHeader(); int itemIndex; // index of the item in the NPCO list esm.getT(itemIndex); if (itemIndex < 0 || itemIndex >= int(mItems.size())) esm.fail("equipment item index out of range"); // appears to be a relative index for only the *possible* slots this item can be equipped in, // i.e. 0 most of the time int slotIndex; esm.getT(slotIndex); mItems[itemIndex].mRelativeEquipmentSlot = slotIndex; } }