void Creature::load(ESMReader &esm) { mPersistent = esm.getRecordFlags() & 0x0400; mModel = esm.getHNString("MODL"); mOriginal = esm.getHNOString("CNAM"); mName = esm.getHNOString("FNAM"); mScript = esm.getHNOString("SCRI"); esm.getHNT(mData, "NPDT", 96); esm.getHNT(mFlags, "FLAG"); mScale = 1.0; esm.getHNOT(mScale, "XSCL"); mInventory.load(esm); mSpells.load(esm); if (esm.isNextSub("AIDT")) { esm.getHExact(&mAiData, sizeof(mAiData)); mHasAI = true; } else mHasAI = false; mAiPackage.load(esm); esm.skipRecord(); }
bool Cell::getNextRef(ESMReader &esm, CellRef &ref, bool& deleted) { // TODO: Try and document reference numbering, I don't think this has been done anywhere else. if (!esm.hasMoreSubs()) return false; // NOTE: We should not need this check. It is a safety check until we have checked // more plugins, and how they treat these moved references. if (esm.isNextSub("MVRF")) { esm.skipRecord(); // skip MVRF esm.skipRecord(); // skip CNDT // That should be it, I haven't seen any other fields yet. } ref.load (esm); // Identify references belonging to a parent file and adapt the ID accordingly. adjustRefNum (ref.mRefNum, esm); if (esm.isNextSub("DELE")) { esm.skipHSub(); deleted = true; } else deleted = false; return true; }
void NPC::load(ESMReader &esm) { mNpdt52.mGold = -10; mPersistent = esm.getRecordFlags() & 0x0400; mModel = esm.getHNOString("MODL"); mName = esm.getHNOString("FNAM"); mRace = esm.getHNString("RNAM"); mClass = esm.getHNString("CNAM"); mFaction = esm.getHNString("ANAM"); mHead = esm.getHNString("BNAM"); mHair = esm.getHNString("KNAM"); mScript = esm.getHNOString("SCRI"); esm.getSubNameIs("NPDT"); esm.getSubHeader(); if (esm.getSubSize() == 52) { mNpdtType = 52; esm.getExact(&mNpdt52, 52); } else if (esm.getSubSize() == 12) { mNpdtType = 12; esm.getExact(&mNpdt12, 12); } else esm.fail("NPC_NPDT must be 12 or 52 bytes long"); esm.getHNT(mFlags, "FLAG"); mInventory.load(esm); mSpells.load(esm); if (esm.isNextSub("AIDT")) { esm.getHExact(&mAiData, sizeof(mAiData)); mHasAI= true; } else mHasAI = false; while (esm.isNextSub("DODT") || esm.isNextSub("DNAM")) { if (esm.retSubName() == 0x54444f44) { // DODT struct Dest dodt; esm.getHExact(&dodt.mPos, 24); mTransport.push_back(dodt); } else if (esm.retSubName() == 0x4d414e44) { // DNAM struct mTransport.back().mCellName = esm.getHString(); } } mAiPackage.load(esm); esm.skipRecord(); }
void Cell::loadCell(ESMReader &esm, bool saveContext) { mRefNumCounter = 0; if (mData.mFlags & Interior) { // Interior cells if (esm.isNextSub("INTV")) { int waterl; esm.getHT(waterl); mWater = (float) waterl; mWaterInt = true; } else if (esm.isNextSub("WHGT")) { esm.getHT(mWater); } // Quasi-exterior cells have a region (which determines the // weather), pure interior cells have ambient lighting // instead. if (mData.mFlags & QuasiEx) mRegion = esm.getHNOString("RGNN"); else if (esm.isNextSub("AMBI")) esm.getHT(mAmbi); } else { // Exterior cells mRegion = esm.getHNOString("RGNN"); mMapColor = 0; esm.getHNOT(mMapColor, "NAM5"); } if (esm.isNextSub("NAM0")) { esm.getHT(mRefNumCounter); } if (saveContext) { mContextList.push_back(esm.getContext()); esm.skipRecord(); } }
void Cell::loadCell(ESMReader &esm, bool saveContext) { bool isLoaded = false; while (!isLoaded && esm.hasMoreSubs()) { esm.getSubName(); switch (esm.retSubName().intval) { case ESM::FourCC<'I','N','T','V'>::value: int waterl; esm.getHT(waterl); mWater = static_cast<float>(waterl); mWaterInt = true; break; case ESM::FourCC<'W','H','G','T'>::value: esm.getHT(mWater); mWaterInt = false; break; case ESM::FourCC<'A','M','B','I'>::value: esm.getHT(mAmbi); break; case ESM::FourCC<'R','G','N','N'>::value: mRegion = esm.getHString(); break; case ESM::FourCC<'N','A','M','5'>::value: esm.getHT(mMapColor); break; case ESM::FourCC<'N','A','M','0'>::value: esm.getHT(mRefNumCounter); break; default: esm.cacheSubName(); isLoaded = true; break; } } if (saveContext) { mContextList.push_back(esm.getContext()); esm.skipRecord(); } }
void ESMStore::load(ESMReader &esm) { set<string> missing; // Loop through all records while(esm.hasMoreRecs()) { NAME n = esm.getRecName(); esm.getRecHeader(); // Look up the record type. RecListList::iterator it = recLists.find(n.val); if(it == recLists.end()) { // Not found (this would be an error later) esm.skipRecord(); missing.insert(n.toString()); continue; } // Load it std::string id = esm.getHNOString("NAME"); it->second->load(esm, id); // Insert the reference into the global lookup if(!id.empty()) all[id] = n.val; } /* This information isn't needed on screen. But keep the code around for debugging purposes later. cout << "\n" << recLists.size() << " record types:\n"; for(RecListList::iterator it = recLists.begin(); it != recLists.end(); it++) cout << " " << toStr(it->first) << ": " << it->second->getSize() << endl; cout << "\nNot implemented yet: "; for(set<string>::iterator it = missing.begin(); it != missing.end(); it++ ) cout << *it << " "; cout << endl; */ }
void Creature::load(ESMReader &esm, const std::string& id) { mId = id; model = esm.getHNString("MODL"); original = esm.getHNOString("CNAM"); name = esm.getHNOString("FNAM"); script = esm.getHNOString("SCRI"); esm.getHNT(data, "NPDT", 96); esm.getHNT(flags, "FLAG"); scale = 1.0; esm.getHNOT(scale, "XSCL"); inventory.load(esm); if (esm.isNextSub("AIDT")) { esm.getHExact(&AI, sizeof(AI)); hasAI = true; } else hasAI = false; // More subrecords: // AI_W - wander (14 bytes, i don't understand it) // short distance // byte duration // byte timeOfDay // byte idle[10] // // Rest is optional: // AI_T - travel? // AI_F - follow? // AI_E - escort? // AI_A - activate? esm.skipRecord(); }
bool Cell::getNextRef(ESMReader &esm, CellRef &ref, bool& deleted, bool ignoreMoves, MovedCellRef *mref) { // TODO: Try and document reference numbering, I don't think this has been done anywhere else. if (!esm.hasMoreSubs()) return false; // NOTE: We should not need this check. It is a safety check until we have checked // more plugins, and how they treat these moved references. if (esm.isNextSub("MVRF")) { if (ignoreMoves) { esm.getHT (mref->mRefNum.mIndex); esm.getHNOT (mref->mTarget, "CNDT"); adjustRefNum (mref->mRefNum, esm); } else { // skip rest of cell record (moved references), they are handled elsewhere esm.skipRecord(); // skip MVRF, CNDT return false; } } ref.load (esm); // Identify references belonging to a parent file and adapt the ID accordingly. adjustRefNum (ref.mRefNum, esm); if (esm.isNextSub("DELE")) { esm.skipHSub(); deleted = true; } else deleted = false; return true; }
void Cell::load(ESMReader &esm) { // Ignore this for now, it might mean we should delete the entire // cell? if (esm.isNextSub("DELE")) esm.skipHSub(); esm.getHNT(data, "DATA", 12); // Water level water = 0; if (data.flags & Interior) { // Interior cells if (esm.isNextSub("INTV") || esm.isNextSub("WHGT")) esm.getHT(water); // Quasi-exterior cells have a region (which determines the // weather), pure interior cells have ambient lighting // instead. if (data.flags & QuasiEx) region = esm.getHNOString("RGNN"); else esm.getHNT(ambi, "AMBI", 16); } else { // Exterior cells region = esm.getHNOString("RGNN"); esm.getHNOT(mapColor, "NAM5"); } // Save position of the cell references and move on context = esm.getContext(); esm.skipRecord(); }
void NPC::load(ESMReader &esm, const std::string& id) { mId = id; npdt52.gold = -10; model = esm.getHNOString("MODL"); name = esm.getHNOString("FNAM"); race = esm.getHNString("RNAM"); cls = esm.getHNString("CNAM"); faction = esm.getHNString("ANAM"); head = esm.getHNString("BNAM"); hair = esm.getHNString("KNAM"); script = esm.getHNOString("SCRI"); esm.getSubNameIs("NPDT"); esm.getSubHeader(); if(esm.getSubSize() == 52) esm.getExact(&npdt52, 52); else if(esm.getSubSize() == 12) esm.getExact(&npdt12, 12); else esm.fail("NPC_NPDT must be 12 or 52 bytes long"); esm.getHNT(flags, "FLAG"); inventory.load(esm); spells.load(esm); if(esm.isNextSub("AIDT")) { esm.getHExact(&AI, sizeof(AI)); hasAI = true; } else hasAI = false; esm.skipRecord(); }
void LevelledListBase::load(ESMReader &esm, bool &isDeleted) { isDeleted = false; bool hasName = false; bool hasList = false; while (esm.hasMoreSubs()) { esm.getSubName(); switch (esm.retSubName().val) { case ESM::SREC_NAME: mId = esm.getHString(); hasName = true; break; case ESM::FourCC<'D','A','T','A'>::value: esm.getHT(mFlags); break; case ESM::FourCC<'N','N','A','M'>::value: esm.getHT(mChanceNone); break; case ESM::FourCC<'I','N','D','X'>::value: { int length = 0; esm.getHT(length); mList.resize(length); // If this levelled list was already loaded by a previous content file, // we overwrite the list. Merging lists should probably be left to external tools, // with the limited amount of information there is in the records, all merging methods // will be flawed in some way. For a proper fix the ESM format would have to be changed // to actually track list changes instead of including the whole list for every file // that does something with that list. for (size_t i = 0; i < mList.size(); i++) { LevelItem &li = mList[i]; li.mId = esm.getHNString(mRecName); esm.getHNT(li.mLevel, "INTV"); } hasList = true; break; } case ESM::SREC_DELE: esm.skipHSub(); isDeleted = true; break; default: { if (!hasList) { // Original engine ignores rest of the record, even if there are items following mList.clear(); esm.skipRecord(); } else { esm.fail("Unknown subrecord"); } break; } } } if (!hasName) esm.fail("Missing NAME subrecord"); }
void DialInfo::load(ESMReader &esm) { mId = esm.getHNString("INAM"); mPrev = esm.getHNString("PNAM"); mNext = esm.getHNString("NNAM"); // Not present if deleted if (esm.isNextSub("DATA")) { esm.getHT(mData, 12); } // What follows is somewhat spaghetti-ish, but it's worth if for // an extra speedup. INFO is by far the most common record type. // subName is a reference to the original, so it changes whenever // a new sub name is read. esm.isEmptyOrGetName() will get the // next name for us, or return true if there are no more records. esm.getSubName(); const NAME &subName = esm.retSubName(); if (subName.val == REC_ONAM) { mActor = esm.getHString(); if (esm.isEmptyOrGetName()) return; } if (subName.val == REC_RNAM) { mRace = esm.getHString(); if (esm.isEmptyOrGetName()) return; } if (subName.val == REC_CNAM) { mClass = esm.getHString(); if (esm.isEmptyOrGetName()) return; } mFactionLess = false; if (subName.val == REC_FNAM) { mNpcFaction = esm.getHString(); if (mNpcFaction == "FFFF") mFactionLess = true; if (esm.isEmptyOrGetName()) return; } if (subName.val == REC_ANAM) { mCell = esm.getHString(); if (esm.isEmptyOrGetName()) return; } if (subName.val == REC_DNAM) { mPcFaction = esm.getHString(); if (esm.isEmptyOrGetName()) return; } if (subName.val == REC_SNAM) { mSound = esm.getHString(); if (esm.isEmptyOrGetName()) return; } if (subName.val == REC_NAME) { mResponse = esm.getHString(); if (esm.isEmptyOrGetName()) return; } while (subName.val == REC_SCVR) { SelectStruct ss; ss.mSelectRule = esm.getHString(); esm.isEmptyOrGetName(); if (subName.val == REC_INTV) { ss.mType = VT_Int; esm.getHT(ss.mI); } else if (subName.val == REC_FLTV) { ss.mType = VT_Float; esm.getHT(ss.mF); } else esm.fail( "INFO.SCVR must precede INTV or FLTV, not " + subName.toString()); mSelects.push_back(ss); if (esm.isEmptyOrGetName()) return; } if (subName.val == REC_BNAM) { mResultScript = esm.getHString(); if (esm.isEmptyOrGetName()) return; } mQuestStatus = QS_None; if (subName.val == REC_QSTN) mQuestStatus = QS_Name; else if (subName.val == REC_QSTF) mQuestStatus = QS_Finished; else if (subName.val == REC_QSTR) mQuestStatus = QS_Restart; else if (subName.val == REC_DELE) mQuestStatus = QS_Deleted; else esm.fail( "Don't know what to do with " + subName.toString() + " in INFO " + mId); if (mQuestStatus != QS_None) // Skip rest of record esm.skipRecord(); }
void load(ESMReader &esm) { esm.skipRecord(); }
int main(int argc, char**argv) { Arguments info; if(!parseOptions (argc, argv, info)) return 1; ESMReader esm; esm.setEncoding(info.encoding); string filename = info.filename; cout << "\nFile: " << filename << endl; try { if(info.raw_given) { cout << "RAW file listing:\n"; esm.openRaw(filename); printRaw(esm); return 0; } bool quiet = info.quiet_given; bool loadCells = info.loadcells_given; esm.open(filename); cout << "Author: " << esm.getAuthor() << endl; cout << "Description: " << esm.getDesc() << endl; cout << "File format version: " << esm.getFVer() << endl; cout << "Special flag: " << esm.getSpecial() << endl; cout << "Masters:\n"; ESMReader::MasterList m = esm.getMasters(); for(unsigned int i=0;i<m.size();i++) cout << " " << m[i].name << ", " << m[i].size << " bytes\n"; // Loop through all records while(esm.hasMoreRecs()) { NAME n = esm.getRecName(); esm.getRecHeader(); string id = esm.getHNOString("NAME"); if(!quiet) cout << "\nRecord: " << n.toString() << " '" << id << "'\n"; switch(n.val) { case REC_ACTI: { Activator ac; ac.load(esm); if(quiet) break; cout << " Name: " << ac.name << endl; cout << " Mesh: " << ac.model << endl; cout << " Script: " << ac.script << endl; break; } case REC_ALCH: { Potion p; p.load(esm); if(quiet) break; cout << " Name: " << p.name << endl; break; } case REC_APPA: { Apparatus p; p.load(esm); if(quiet) break; cout << " Name: " << p.name << endl; break; } case REC_ARMO: { Armor am; am.load(esm); if(quiet) break; cout << " Name: " << am.name << endl; cout << " Mesh: " << am.model << endl; cout << " Icon: " << am.icon << endl; cout << " Script: " << am.script << endl; cout << " Enchantment: " << am.enchant << endl; cout << " Type: " << am.data.type << endl; cout << " Weight: " << am.data.weight << endl; break; } case REC_BODY: { BodyPart bp; bp.load(esm); if(quiet) break; cout << " Name: " << bp.name << endl; cout << " Mesh: " << bp.model << endl; break; } case REC_BOOK: { Book b; b.load(esm); if(quiet) break; cout << " Name: " << b.name << endl; cout << " Mesh: " << b.model << endl; break; } case REC_BSGN: { BirthSign bs; bs.load(esm); if(quiet) break; cout << " Name: " << bs.name << endl; cout << " Texture: " << bs.texture << endl; cout << " Description: " << bs.description << endl; break; } case REC_CELL: { Cell b; b.load(esm); if(!quiet) { cout << " Name: " << b.name << endl; cout << " Region: " << b.region << endl; } if(loadCells) loadCell(b, esm, quiet); break; } case REC_CLAS: { Class b; b.load(esm); if(quiet) break; cout << " Name: " << b.name << endl; cout << " Description: " << b.description << endl; break; } case REC_CLOT: { Clothing b; b.load(esm); if(quiet) break; cout << " Name: " << b.name << endl; break; } case REC_CONT: { Container b; b.load(esm); if(quiet) break; cout << " Name: " << b.name << endl; break; } case REC_CREA: { Creature b; b.load(esm, id); if(quiet) break; cout << " Name: " << b.name << endl; break; } case REC_DIAL: { Dialogue b; b.load(esm); break; } case REC_DOOR: { Door d; d.load(esm); if(quiet) break; cout << " Name: " << d.name << endl; cout << " Mesh: " << d.model << endl; cout << " Script: " << d.script << endl; cout << " OpenSound: " << d.openSound << endl; cout << " CloseSound: " << d.closeSound << endl; break; } case REC_ENCH: { Enchantment b; b.load(esm); break; } case REC_GMST: { GameSetting b; b.id = id; b.load(esm); if(quiet) break; cout << " Value: "; if(b.type == VT_String) cout << "'" << b.str << "' (string)"; else if(b.type == VT_Float) cout << b.f << " (float)"; else if(b.type == VT_Int) cout << b.i << " (int)"; cout << "\n Dirty: " << b.dirty << endl; break; } case REC_INFO: { DialInfo p; p.load(esm); if(quiet) break; cout << " Id: " << p.id << endl; cout << " Text: " << p.response << endl; break; } case REC_SOUN: { Sound d; d.load(esm); if(quiet) break; cout << " Sound: " << d.sound << endl; cout << " Volume: " << (int)d.data.volume << endl; break; } case REC_SPEL: { Spell s; s.load(esm); if(quiet) break; cout << " Name: " << s.name << endl; break; } default: esm.skipRecord(); if(quiet) break; cout << " Skipping\n"; } } } catch(exception &e) { cout << "\nERROR:\n\n " << e.what() << endl; return 1; } return 0; }
void ESMStore::load(ESMReader &esm) { set<string> missing; ESM::Dialogue *dialogue = 0; // Loop through all records while(esm.hasMoreRecs()) { NAME n = esm.getRecName(); esm.getRecHeader(); // Look up the record type. RecListList::iterator it = recLists.find(n.val); if(it == recLists.end()) { if (n.val==ESM::REC_INFO) { if (dialogue) { ESM::DialInfo info; info.load (esm); dialogue->mInfo.push_back (info); } else { std::cerr << "error: info record without dialog" << std::endl; esm.skipRecord(); continue; } } else { // Not found (this would be an error later) esm.skipRecord(); missing.insert(n.toString()); continue; } } else { // Load it std::string id = esm.getHNOString("NAME"); it->second->load(esm, id); if (n.val==ESM::REC_DIAL) { RecListT<Dialogue>& recList = static_cast<RecListT<Dialogue>& > (*it->second); id = recList.toLower (id); RecListT<Dialogue>::MapType::iterator iter = recList.list.find (id); assert (iter!=recList.list.end()); dialogue = &iter->second; } else dialogue = 0; // Insert the reference into the global lookup if(!id.empty()) all[id] = n.val; } } /* This information isn't needed on screen. But keep the code around for debugging purposes later. cout << "\n" << recLists.size() << " record types:\n"; for(RecListList::iterator it = recLists.begin(); it != recLists.end(); it++) cout << " " << toStr(it->first) << ": " << it->second->getSize() << endl; cout << "\nNot implemented yet: "; for(set<string>::iterator it = missing.begin(); it != missing.end(); it++ ) cout << *it << " "; cout << endl; */ }
bool Cell::getNextRef(ESMReader &esm, CellRef &ref) { // TODO: Try and document reference numbering, I don't think this has been done anywhere else. if (!esm.hasMoreSubs()) return false; // NOTE: We should not need this check. It is a safety check until we have checked // more plugins, and how they treat these moved references. if (esm.isNextSub("MVRF")) { esm.skipRecord(); // skip MVRF esm.skipRecord(); // skip CNDT // That should be it, I haven't seen any other fields yet. } // NAM0 sometimes appears here, sometimes further on ref.mNam0 = 0; if (esm.isNextSub("NAM0")) { esm.getHT(ref.mNam0); //esm.getHNOT(NAM0, "NAM0"); } esm.getHNT(ref.mRefnum, "FRMR"); ref.mRefID = esm.getHNString("NAME"); // Identify references belonging to a parent file and adapt the ID accordingly. int local = (ref.mRefnum & 0xff000000) >> 24; size_t global = esm.getIndex() + 1; if (local) { // If the most significant 8 bits are used, then this reference already exists. // In this case, do not spawn a new reference, but overwrite the old one. ref.mRefnum &= 0x00ffffff; // delete old plugin ID const std::vector<Header::MasterData> &masters = esm.getGameFiles(); global = masters[local-1].index + 1; ref.mRefnum |= global << 24; // insert global plugin ID } else { // This is an addition by the present plugin. Set the corresponding plugin index. ref.mRefnum |= global << 24; // insert global plugin ID } // getHNOT will not change the existing value if the subrecord is // missing ref.mScale = 1.0; esm.getHNOT(ref.mScale, "XSCL"); // TODO: support loading references from saves, there are tons of keys not recognized yet. // The following is just an incomplete list. if (esm.isNextSub("ACTN")) esm.skipHSub(); if (esm.isNextSub("STPR")) esm.skipHSub(); if (esm.isNextSub("ACDT")) esm.skipHSub(); if (esm.isNextSub("ACSC")) esm.skipHSub(); if (esm.isNextSub("ACSL")) esm.skipHSub(); if (esm.isNextSub("CHRD")) esm.skipHSub(); else if (esm.isNextSub("CRED")) // ??? esm.skipHSub(); ref.mOwner = esm.getHNOString("ANAM"); ref.mGlob = esm.getHNOString("BNAM"); ref.mSoul = esm.getHNOString("XSOL"); ref.mFaction = esm.getHNOString("CNAM"); ref.mFactIndex = -2; esm.getHNOT(ref.mFactIndex, "INDX"); ref.mGoldValue = 1; ref.mCharge = -1; ref.mEnchantmentCharge = -1; esm.getHNOT(ref.mEnchantmentCharge, "XCHG"); esm.getHNOT(ref.mCharge, "INTV"); esm.getHNOT(ref.mGoldValue, "NAM9"); // Present for doors that teleport you to another cell. if (esm.isNextSub("DODT")) { ref.mTeleport = true; esm.getHT(ref.mDoorDest); ref.mDestCell = esm.getHNOString("DNAM"); } else { ref.mTeleport = false; } // Integer, despite the name suggesting otherwise ref.mLockLevel = -1; esm.getHNOT(ref.mLockLevel, "FLTV"); ref.mKey = esm.getHNOString("KNAM"); ref.mTrap = esm.getHNOString("TNAM"); ref.mReferenceBlocked = -1; ref.mFltv = 0; esm.getHNOT(ref.mReferenceBlocked, "UNAM"); esm.getHNOT(ref.mFltv, "FLTV"); esm.getHNOT(ref.mPos, "DATA", 24); // Number of references in the cell? Maximum once in each cell, // but not always at the beginning, and not always right. In other // words, completely useless. // Update: Well, maybe not completely useless. This might actually be // number_of_references + number_of_references_moved_here_Across_boundaries, // and could be helpful for collecting these weird moved references. if (esm.isNextSub("NAM0")) { esm.getHT(ref.mNam0); //esm.getHNOT(NAM0, "NAM0"); } if (esm.isNextSub("DELE")) { esm.skipHSub(); ref.mDeleted = 2; // Deleted, will not respawn. // TODO: find out when references do respawn. } else ref.mDeleted = 0; return true; }
void Cell::postLoad(ESMReader &esm) { // Save position of the cell references and move on mContextList.push_back(esm.getContext()); esm.skipRecord(); }
void ESMStore::load(ESMReader &esm) { set<string> missing; ESM::Dialogue *dialogue = 0; // Loop through all records while(esm.hasMoreRecs()) { NAME n = esm.getRecName(); esm.getRecHeader(); // Look up the record type. RecListList::iterator it = recLists.find(n.val); if(it == recLists.end()) { if (n.val==ESM::REC_INFO) { if (dialogue) { ESM::DialInfo info; info.load (esm); dialogue->mInfo.push_back (info); } else { std::cerr << "error: info record without dialog" << std::endl; esm.skipRecord(); } } else if (n.val==ESM::REC_MGEF) { magicEffects.load (esm); } else if (n.val==ESM::REC_SKIL) { skills.load (esm); } else { // Not found (this would be an error later) esm.skipRecord(); missing.insert(n.toString()); } } else { // Load it std::string id = esm.getHNOString("NAME"); it->second->load(esm, id); if (n.val==ESM::REC_DIAL) { RecListT<Dialogue>& recList = static_cast<RecListT<Dialogue>& > (*it->second); id = recList.toLower (id); RecListT<Dialogue>::MapType::iterator iter = recList.list.find (id); assert (iter!=recList.list.end()); dialogue = &iter->second; } else dialogue = 0; // Insert the reference into the global lookup if(!id.empty() && (n.val==REC_ACTI || n.val==REC_ALCH || n.val==REC_APPA || n.val==REC_ARMO || n.val==REC_BOOK || n.val==REC_CLOT || n.val==REC_CONT || n.val==REC_CREA || n.val==REC_DOOR || n.val==REC_INGR || n.val==REC_LEVC || n.val==REC_LEVI || n.val==REC_LIGH || n.val==REC_LOCK || n.val==REC_MISC || n.val==REC_NPC_ || n.val==REC_PROB || n.val==REC_REPA || n.val==REC_STAT || n.val==REC_WEAP) ) all[id] = n.val; } } for (int i = 0; i < Attribute::Length; ++i) { Attribute::AttributeID id = Attribute::attributeIds[i]; attributes.list.insert(std::make_pair(id, Attribute(id, Attribute::gmstAttributeIds[i], Attribute::gmstAttributeDescIds[i]))); } /* This information isn't needed on screen. But keep the code around for debugging purposes later. cout << "\n" << recLists.size() << " record types:\n"; for(RecListList::iterator it = recLists.begin(); it != recLists.end(); it++) cout << " " << toStr(it->first) << ": " << it->second->getSize() << endl; cout << "\nNot implemented yet: "; for(set<string>::iterator it = missing.begin(); it != missing.end(); it++ ) cout << *it << " "; cout << endl; */ }