void PathGrid::load(ESMReader &esm) { esm.getHNT(data, "DATA", 12); cell = esm.getHNString("NAME"); // Remember this file position context = esm.getContext(); // Check that the sizes match up. Size = 16 * s2 (path points?) if (esm.isNextSub("PGRP")) { esm.skipHSub(); int size = esm.getSubSize(); if (size != 16 * data.s2) esm.fail("Path grid table size mismatch"); } // Size varies. Path grid chances? Connections? Multiples of 4 // suggest either int or two shorts, or perhaps a float. Study // it later. if (esm.isNextSub("PGRC")) { esm.skipHSub(); int size = esm.getSubSize(); if (size % 4 != 0) esm.fail("PGRC size not a multiple of 4"); } }
void StartScript::load(ESMReader &esm, bool &isDeleted) { isDeleted = false; bool hasData = false; bool hasName = 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: mData = esm.getHString(); hasData = true; break; case ESM::SREC_DELE: esm.skipHSub(); isDeleted = true; break; default: esm.fail("Unknown subrecord"); break; } } if (!hasName) esm.fail("Missing NAME"); if (!hasData && !isDeleted) esm.fail("Missing DATA"); }
void Skill::load(ESMReader &esm) { bool hasIndex = false; bool hasData = false; while (esm.hasMoreSubs()) { esm.getSubName(); uint32_t name = esm.retSubName().val; switch (name) { case ESM::FourCC<'I','N','D','X'>::value: esm.getHT(mIndex); hasIndex = true; break; case ESM::FourCC<'S','K','D','T'>::value: esm.getHT(mData, 24); hasData = true; break; case ESM::FourCC<'D','E','S','C'>::value: mDescription = esm.getHString(); break; default: esm.fail("Unknown subrecord"); } } if (!hasIndex) esm.fail("Missing INDX"); if (!hasData) esm.fail("Missing SKDT"); // create an ID from the index and the name (only used in the editor and likely to change in the // future) mId = indexToId (mIndex); }
void BodyPart::load(ESMReader &esm) { bool hasData = false; while (esm.hasMoreSubs()) { esm.getSubName(); uint32_t name = esm.retSubName().val; switch (name) { case ESM::FourCC<'M','O','D','L'>::value: mModel = esm.getHString(); break; case ESM::FourCC<'F','N','A','M'>::value: mRace = esm.getHString(); break; case ESM::FourCC<'B','Y','D','T'>::value: esm.getHT(mData, 4); hasData = true; break; default: esm.fail("Unknown subrecord"); } } if (!hasData) esm.fail("Missing BYDT subrecord"); }
void Weapon::load(ESMReader &esm) { bool hasData = false; while (esm.hasMoreSubs()) { esm.getSubName(); uint32_t name = esm.retSubName().val; switch (name) { case ESM::FourCC<'M','O','D','L'>::value: mModel = esm.getHString(); break; case ESM::FourCC<'F','N','A','M'>::value: mName = esm.getHString(); break; case ESM::FourCC<'W','P','D','T'>::value: esm.getHT(mData, 32); hasData = true; break; case ESM::FourCC<'S','C','R','I'>::value: mScript = esm.getHString(); break; case ESM::FourCC<'I','T','E','X'>::value: mIcon = esm.getHString(); break; case ESM::FourCC<'E','N','A','M'>::value: mEnchant = esm.getHString(); break; default: esm.fail("Unknown subrecord"); } } if (!hasData) esm.fail("Missing WPDT subrecord"); }
void Faction::load(ESMReader &esm, bool &isDeleted) { isDeleted = false; mReactions.clear(); for (int i=0;i<10;++i) mRanks[i].clear(); int rankCounter = 0; bool hasName = false; bool hasData = false; while (esm.hasMoreSubs()) { esm.getSubName(); switch (esm.retSubName().val) { case ESM::SREC_NAME: mId = esm.getHString(); hasName = true; break; case ESM::FourCC<'F','N','A','M'>::value: mName = esm.getHString(); break; case ESM::FourCC<'R','N','A','M'>::value: if (rankCounter >= 10) esm.fail("Rank out of range"); mRanks[rankCounter++] = esm.getHString(); break; case ESM::FourCC<'F','A','D','T'>::value: esm.getHT(mData, 240); if (mData.mIsHidden > 1) esm.fail("Unknown flag!"); hasData = true; break; case ESM::FourCC<'A','N','A','M'>::value: { std::string faction = esm.getHString(); int reaction; esm.getHNT(reaction, "INTV"); mReactions[faction] = reaction; break; } case ESM::SREC_DELE: esm.skipHSub(); isDeleted = true; break; default: esm.fail("Unknown subrecord"); break; } } if (!hasName) esm.fail("Missing NAME subrecord"); if (!hasData && !isDeleted) esm.fail("Missing FADT subrecord"); }
void Book::load(ESMReader &esm, bool &isDeleted) { isDeleted = false; bool hasName = false; bool hasData = false; while (esm.hasMoreSubs()) { esm.getSubName(); switch (esm.retSubName().intval) { case ESM::SREC_NAME: mId = esm.getHString(); hasName = true; break; case ESM::FourCC<'M','O','D','L'>::value: mModel = esm.getHString(); break; case ESM::FourCC<'F','N','A','M'>::value: mName = esm.getHString(); break; case ESM::FourCC<'B','K','D','T'>::value: esm.getHT(mData, 20); hasData = true; break; case ESM::FourCC<'S','C','R','I'>::value: mScript = esm.getHString(); break; case ESM::FourCC<'I','T','E','X'>::value: mIcon = esm.getHString(); break; case ESM::FourCC<'E','N','A','M'>::value: mEnchant = esm.getHString(); break; case ESM::FourCC<'T','E','X','T'>::value: mText = esm.getHString(); break; case ESM::SREC_DELE: esm.skipHSub(); isDeleted = true; break; default: esm.fail("Unknown subrecord"); break; } } if (!hasName) esm.fail("Missing NAME subrecord"); if (!hasData && !isDeleted) esm.fail("Missing BKDT subrecord"); }
void ESM::VariantIntegerData::read (ESMReader& esm, Variant::Format format, VarType type) { if (type!=VT_Short && type!=VT_Long && type!=VT_Int) throw std::logic_error ("not an integer type"); if (format==Variant::Format_Global) { float value; esm.getHNT (value, "FLTV"); if (type==VT_Short) { if (value!=value) mValue = 0; // nan else mValue = static_cast<short> (value); } else if (type==VT_Long) mValue = static_cast<int> (value); else esm.fail ("unsupported global variable integer type"); } else if (format==Variant::Format_Gmst || format==Variant::Format_Info) { if (type!=VT_Int) { std::ostringstream stream; stream << "unsupported " <<(format==Variant::Format_Gmst ? "gmst" : "info") << " variable integer type"; esm.fail (stream.str()); } esm.getHT (mValue); } else if (format==Variant::Format_Local) { if (type==VT_Short) { short value; esm.getHT(value); mValue = value; } else if (type==VT_Int) { esm.getHT(mValue); } else esm.fail("unsupported local variable integer type"); } }
void ESM::VariantStringData::read (ESMReader& esm, Variant::Format format, VarType type) { if (type!=VT_String) throw std::logic_error ("not a string type"); if (format==Variant::Format_Global) esm.fail ("global variables of type string not supported"); if (format==Variant::Format_Info) esm.fail ("info variables of type string not supported"); // GMST mValue = esm.getHString(); }
void GameSetting::load(ESMReader &esm) { assert(mId != ""); // We are apparently allowed to be empty if (!esm.hasMoreSubs()) { mType = VT_None; return; } // Load some data esm.getSubName(); NAME n = esm.retSubName(); if (n == "STRV") { mStr = esm.getHString(); mType = VT_String; } else if (n == "INTV") { esm.getHT(mI); mType = VT_Int; } else if (n == "FLTV") { esm.getHT(mF); mType = VT_Float; } else esm.fail("Unwanted subrecord type"); }
void ESM::Header::load (ESMReader &esm) { if (esm.isNextSub("HEDR")) { esm.getSubHeader(); esm.getT(mData.version); esm.getT(mData.type); mData.author.assign(esm.getString(sizeof(mData.author.name))); mData.desc.assign(esm.getString(sizeof(mData.desc.name))); esm.getT(mData.records); } if (esm.isNextSub ("FORM")) { esm.getHT (mFormat); if (mFormat<0) esm.fail ("invalid format code"); } else mFormat = 0; while (esm.isNextSub ("MAST")) { MasterData m; m.name = esm.getHString(); m.size = esm.getHNLong ("DATA"); mMaster.push_back (m); } }
void Script::load(ESMReader &esm) { SCHD data; esm.getHNT(data, "SCHD", 52); mData = data.mData; mId = data.mName.toString(); mVarNames.clear(); while (esm.hasMoreSubs()) { esm.getSubName(); uint32_t name = esm.retSubName().val; switch (name) { case ESM::FourCC<'S','C','V','R'>::value: // list of local variables loadSCVR(esm); break; case ESM::FourCC<'S','C','D','T'>::value: // compiled script mScriptData.resize(mData.mScriptDataSize); esm.getHExact(&mScriptData[0], mScriptData.size()); break; case ESM::FourCC<'S','C','T','X'>::value: mScriptText = esm.getHString(); break; default: esm.fail("Unknown subrecord"); } } }
void Door::load(ESMReader &esm) { while (esm.hasMoreSubs()) { esm.getSubName(); uint32_t name = esm.retSubName().val; switch (name) { case ESM::FourCC<'M','O','D','L'>::value: mModel = esm.getHString(); break; case ESM::FourCC<'F','N','A','M'>::value: mName = esm.getHString(); break; case ESM::FourCC<'S','C','R','I'>::value: mScript = esm.getHString(); break; case ESM::FourCC<'S','N','A','M'>::value: mOpenSound = esm.getHString(); break; case ESM::FourCC<'A','N','A','M'>::value: mCloseSound = esm.getHString(); break; default: esm.fail("Unknown subrecord"); } } }
void Container::load(ESMReader &esm) { mModel = esm.getHNString("MODL"); mName = esm.getHNOString("FNAM"); esm.getHNT(mWeight, "CNDT", 4); esm.getHNT(mFlags, "FLAG", 4); if (mFlags & 0xf4) esm.fail("Unknown flags"); if (!(mFlags & 0x8)) esm.fail("Flag 8 not set"); mScript = esm.getHNOString("SCRI"); mInventory.load(esm); }
void ESM::DebugProfile::load (ESMReader& esm, bool &isDeleted) { isDeleted = false; while (esm.hasMoreSubs()) { esm.getSubName(); switch (esm.retSubName().intval) { case ESM::SREC_NAME: mId = esm.getHString(); break; case ESM::FourCC<'D','E','S','C'>::value: mDescription = esm.getHString(); break; case ESM::FourCC<'S','C','R','P'>::value: mScriptText = esm.getHString(); break; case ESM::FourCC<'F','L','A','G'>::value: esm.getHT(mFlags); break; case ESM::SREC_DELE: esm.skipHSub(); isDeleted = true; break; default: esm.fail("Unknown subrecord"); break; } } }
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 Container::load(ESMReader &esm) { mInventory.mList.clear(); bool hasWeight = false; bool hasFlags = false; while (esm.hasMoreSubs()) { esm.getSubName(); uint32_t name = esm.retSubName().val; switch (name) { case ESM::FourCC<'M','O','D','L'>::value: mModel = esm.getHString(); break; case ESM::FourCC<'F','N','A','M'>::value: mName = esm.getHString(); break; case ESM::FourCC<'C','N','D','T'>::value: esm.getHT(mWeight, 4); hasWeight = true; break; case ESM::FourCC<'F','L','A','G'>::value: esm.getHT(mFlags, 4); if (mFlags & 0xf4) esm.fail("Unknown flags"); if (!(mFlags & 0x8)) esm.fail("Flag 8 not set"); hasFlags = true; break; case ESM::FourCC<'S','C','R','I'>::value: mScript = esm.getHString(); break; case ESM::FourCC<'N','P','C','O'>::value: mInventory.add(esm); break; default: esm.fail("Unknown subrecord"); } } if (!hasWeight) esm.fail("Missing CNDT subrecord"); if (!hasFlags) esm.fail("Missing FLAG subrecord"); }
void Spell::load(ESMReader &esm, bool &isDeleted) { isDeleted = false; mEffects.mList.clear(); bool hasName = false; bool hasData = false; while (esm.hasMoreSubs()) { esm.getSubName(); switch (esm.retSubName().val) { case ESM::SREC_NAME: mId = esm.getHString(); hasName = true; break; case ESM::FourCC<'F','N','A','M'>::value: mName = esm.getHString(); break; case ESM::FourCC<'S','P','D','T'>::value: esm.getHT(mData, 12); hasData = true; break; case ESM::FourCC<'E','N','A','M'>::value: ENAMstruct s; esm.getHT(s, 24); mEffects.mList.push_back(s); break; case ESM::SREC_DELE: esm.skipHSub(); isDeleted = true; break; default: esm.fail("Unknown subrecord"); break; } } if (!hasName) esm.fail("Missing NAME subrecord"); if (!hasData && !isDeleted) esm.fail("Missing SPDT subrecord"); }
void Race::load(ESMReader &esm, bool &isDeleted) { isDeleted = false; mPowers.mList.clear(); bool hasName = false; bool hasData = false; while (esm.hasMoreSubs()) { esm.getSubName(); switch (esm.retSubName().val) { case ESM::SREC_NAME: mId = esm.getHString(); hasName = true; break; case ESM::FourCC<'F','N','A','M'>::value: mName = esm.getHString(); break; case ESM::FourCC<'R','A','D','T'>::value: esm.getHT(mData, 140); hasData = true; break; case ESM::FourCC<'D','E','S','C'>::value: mDescription = esm.getHString(); break; case ESM::FourCC<'N','P','C','S'>::value: mPowers.add(esm); break; case ESM::SREC_DELE: esm.skipHSub(); isDeleted = true; break; default: esm.fail("Unknown subrecord"); } } if (!hasName) esm.fail("Missing NAME subrecord"); if (!hasData && !isDeleted) esm.fail("Missing RADT subrecord"); }
void Class::load(ESMReader &esm) { mName = esm.getHNOString("FNAM"); esm.getHNT(mData, "CLDT", 60); if (mData.mIsPlayable > 1) esm.fail("Unknown bool value"); mDescription = esm.getHNOString("DESC"); }
void Faction::load(ESMReader &esm) { mReactions.clear(); for (int i=0;i<10;++i) mRanks[i].clear(); int rankCounter=0; bool hasData = false; while (esm.hasMoreSubs()) { esm.getSubName(); uint32_t name = esm.retSubName().val; switch (name) { case ESM::FourCC<'F','N','A','M'>::value: mName = esm.getHString(); break; case ESM::FourCC<'R','N','A','M'>::value: if (rankCounter >= 10) esm.fail("Rank out of range"); mRanks[rankCounter++] = esm.getHString(); break; case ESM::FourCC<'F','A','D','T'>::value: esm.getHT(mData, 240); if (mData.mIsHidden > 1) esm.fail("Unknown flag!"); hasData = true; break; case ESM::FourCC<'A','N','A','M'>::value: { std::string faction = esm.getHString(); int reaction; esm.getHNT(reaction, "INTV"); mReactions[faction] = reaction; break; } default: esm.fail("Unknown subrecord"); } } if (!hasData) esm.fail("Missing FADT subrecord"); }
void Class::load(ESMReader &esm, bool &isDeleted) { isDeleted = false; bool hasName = false; bool hasData = false; while (esm.hasMoreSubs()) { esm.getSubName(); switch (esm.retSubName().intval) { case ESM::SREC_NAME: mId = esm.getHString(); hasName = true; break; case ESM::FourCC<'F','N','A','M'>::value: mName = esm.getHString(); break; case ESM::FourCC<'C','L','D','T'>::value: esm.getHT(mData, 60); if (mData.mIsPlayable > 1) esm.fail("Unknown bool value"); hasData = true; break; case ESM::FourCC<'D','E','S','C'>::value: mDescription = esm.getHString(); break; case ESM::SREC_DELE: esm.skipHSub(); isDeleted = true; break; default: esm.fail("Unknown subrecord"); break; } } if (!hasName) esm.fail("Missing NAME subrecord"); if (!hasData && !isDeleted) esm.fail("Missing CLDT subrecord"); }
void Door::load(ESMReader &esm, bool &isDeleted) { isDeleted = false; bool hasName = false; while (esm.hasMoreSubs()) { esm.getSubName(); switch (esm.retSubName().val) { case ESM::SREC_NAME: mId = esm.getHString(); hasName = true; break; case ESM::FourCC<'M','O','D','L'>::value: mModel = esm.getHString(); break; case ESM::FourCC<'F','N','A','M'>::value: mName = esm.getHString(); break; case ESM::FourCC<'S','C','R','I'>::value: mScript = esm.getHString(); break; case ESM::FourCC<'S','N','A','M'>::value: mOpenSound = esm.getHString(); break; case ESM::FourCC<'A','N','A','M'>::value: mCloseSound = esm.getHString(); break; case ESM::SREC_DELE: esm.skipHSub(); isDeleted = true; break; default: esm.fail("Unknown subrecord"); break; } } if (!hasName) esm.fail("Missing NAME subrecord"); }
void Enchantment::load(ESMReader &esm, bool &isDeleted) { isDeleted = false; mEffects.mList.clear(); bool hasName = false; bool hasData = false; while (esm.hasMoreSubs()) { esm.getSubName(); switch (esm.retSubName().intval) { case ESM::SREC_NAME: mId = esm.getHString(); hasName = true; break; case ESM::FourCC<'E','N','D','T'>::value: esm.getHT(mData, 16); hasData = true; break; case ESM::FourCC<'E','N','A','M'>::value: mEffects.add(esm); break; case ESM::SREC_DELE: esm.skipHSub(); isDeleted = true; break; default: esm.fail("Unknown subrecord"); break; } } if (!hasName) esm.fail("Missing NAME subrecord"); if (!hasData && !isDeleted) esm.fail("Missing ENDT subrecord"); }
void Cell::loadNameAndData(ESMReader &esm, bool &isDeleted) { isDeleted = false; blank(); bool hasData = false; bool isLoaded = false; while (!isLoaded && esm.hasMoreSubs()) { esm.getSubName(); switch (esm.retSubName().intval) { case ESM::SREC_NAME: mName = esm.getHString(); break; case ESM::FourCC<'D','A','T','A'>::value: esm.getHT(mData, 12); hasData = true; break; case ESM::SREC_DELE: esm.skipHSub(); isDeleted = true; break; default: esm.cacheSubName(); isLoaded = true; break; } } if (!hasData) esm.fail("Missing DATA subrecord"); mCellId.mPaged = !(mData.mFlags & Interior); if (mCellId.mPaged) { mCellId.mWorldspace = ESM::CellId::sDefaultWorldspace; mCellId.mIndex.mX = mData.mX; mCellId.mIndex.mY = mData.mY; } else { mCellId.mWorldspace = Misc::StringUtils::lowerCase (mName); mCellId.mIndex.mX = 0; mCellId.mIndex.mY = 0; } }
void Script::loadSCVR(ESMReader &esm) { int s = mData.mStringTableSize; std::vector<char> tmp (s); // not using getHExact, vanilla doesn't seem to mind unused bytes at the end esm.getSubHeader(); int left = esm.getSubSize(); if (left < s) esm.fail("SCVR string list is smaller than specified"); esm.getExact(&tmp[0], s); if (left > s) esm.skip(left-s); // skip the leftover junk // Set up the list of variable names mVarNames.resize(mData.mNumShorts + mData.mNumLongs + mData.mNumFloats); // The tmp buffer is a null-byte separated string list, we // just have to pick out one string at a time. char* str = &tmp[0]; for (size_t i = 0; i < mVarNames.size(); i++) { // Support '\r' terminated strings like vanilla. See Bug #1324. char *termsym = strchr(str, '\r'); if(termsym) *termsym = '\0'; mVarNames[i] = std::string(str); str += mVarNames[i].size() + 1; if (str - &tmp[0] > s) { // Apparently SCVR subrecord is not used and variable names are // determined on the fly from the script text. Therefore don't throw // an exeption, just log an error and continue. std::stringstream ss; ss << "ESM Error: " << "String table overflow"; ss << "\n File: " << esm.getName(); ss << "\n Record: " << esm.getContext().recName.toString(); ss << "\n Subrecord: " << "SCVR"; ss << "\n Offset: 0x" << std::hex << esm.getFileOffset(); std::cerr << ss.str() << std::endl; break; } } }
void Dialogue::load(ESMReader &esm) { esm.getSubNameIs("DATA"); esm.getSubHeader(); int si = esm.getSubSize(); if (si == 1) esm.getT(type); else if (si == 4) { // These are just markers, their values are not used. int i; esm.getT(i); esm.getHNT(i, "DELE"); type = Deleted; } else esm.fail("Unknown sub record size"); }
void ESM::Header::load (ESMReader &esm) { esm.getHNT (mData, "HEDR", 300); if (esm.isNextSub ("FORM")) { esm.getHT (mFormat); if (mFormat<0) esm.fail ("invalid format code"); } else mFormat = 0; while (esm.isNextSub ("MAST")) { MasterData m; m.name = esm.getHString(); m.size = esm.getHNLong ("DATA"); mMaster.push_back (m); } }
void load(ESMReader &esm) { name = esm.getHNString("FNAM"); // Read rank names. These are optional. int i = 0; while(esm.isNextSub("RNAM") && i<10) ranks[i++] = esm.getHString(); // Main data struct esm.getHNT(data, "FADT", 240); if(data.isHidden > 1) esm.fail("Unknown flag!"); // Read faction response values while(esm.hasMoreSubs()) { Reaction r; r.faction = esm.getHNString("ANAM"); esm.getHNT(r.reaction, "INTV"); reactions.push_back(r); } }
void Region::load(ESMReader &esm) { mName = esm.getHNString("FNAM"); if (esm.getVer() == VER_12) esm.getHNExact(&mData, sizeof(mData) - 2, "WEAT"); else if (esm.getVer() == VER_13) esm.getHNExact(&mData, sizeof(mData), "WEAT"); else esm.fail("Don't know what to do in this version"); mSleepList = esm.getHNOString("BNAM"); esm.getHNT(mMapColor, "CNAM"); while (esm.hasMoreSubs()) { SoundRef sr; esm.getHNT(sr, "SNAM", 33); mSoundList.push_back(sr); } }