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 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); } }
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 SpellState::load(ESMReader &esm) { while (esm.isNextSub("SPEL")) { std::string id = esm.getHString(); std::map<const int, float> random; while (esm.isNextSub("INDX")) { int index; esm.getHT(index); float magnitude; esm.getHNT(magnitude, "RAND"); random[index] = magnitude; } mSpells[id] = random; } while (esm.isNextSub("USED")) { std::string id = esm.getHString(); TimeStamp time; esm.getHNT(time, "TIME"); mUsedPowers[id] = time; } mSelectedSpell = esm.getHNOString("SLCT"); }
void load(ESMReader &esm) { // Get the grid location esm.getSubNameIs("INTV"); esm.getT(X); esm.getT(Y); esm.getHNT(flags, "DATA"); // Store the file position context = esm.getContext(); hasData = false; int cnt = 0; // Skip these here. Load the actual data when the cell is loaded. if(esm.isNextSub("VNML")) {esm.skipHSubSize(12675);cnt++;} if(esm.isNextSub("VHGT")) {esm.skipHSubSize(4232);cnt++;} if(esm.isNextSub("WNAM")) esm.skipHSubSize(81); if(esm.isNextSub("VCLR")) esm.skipHSubSize(12675); if(esm.isNextSub("VTEX")) {esm.skipHSubSize(512);cnt++;} // We need all three of VNML, VHGT and VTEX in order to use the // landscape. hasData = (cnt == 3); }
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 ESM::CellRef::loadData(ESMReader &esm) { // Again, UNAM sometimes appears after NAME and sometimes later. // Or perhaps this UNAM means something different? mReferenceBlocked = -1; esm.getHNOT (mReferenceBlocked, "UNAM"); mScale = 1.0; esm.getHNOT (mScale, "XSCL"); mOwner = esm.getHNOString ("ANAM"); mGlobalVariable = esm.getHNOString ("BNAM"); mSoul = esm.getHNOString ("XSOL"); mFaction = esm.getHNOString ("CNAM"); mFactionRank = -2; esm.getHNOT (mFactionRank, "INDX"); mGoldValue = 1; mChargeInt = -1; mEnchantmentCharge = -1; esm.getHNOT (mEnchantmentCharge, "XCHG"); esm.getHNOT (mChargeInt, "INTV"); esm.getHNOT (mGoldValue, "NAM9"); // Present for doors that teleport you to another cell. if (esm.isNextSub ("DODT")) { mTeleport = true; esm.getHT (mDoorDest); mDestCell = esm.getHNOString ("DNAM"); } else mTeleport = false; mLockLevel = 0; //Set to 0 to indicate no lock esm.getHNOT (mLockLevel, "FLTV"); mKey = esm.getHNOString ("KNAM"); mTrap = esm.getHNOString ("TNAM"); esm.getHNOT (mReferenceBlocked, "UNAM"); if (esm.isNextSub("FLTV")) // no longer used esm.skipHSub(); esm.getHNOT(mPos, "DATA", 24); if (esm.isNextSub("NAM0")) esm.skipHSub(); }
void Land::load(ESMReader &esm) { mEsm = &esm; mPlugin = mEsm->getIndex(); // Get the grid location esm.getSubNameIs("INTV"); esm.getSubHeaderIs(8); esm.getT<int>(mX); esm.getT<int>(mY); esm.getHNT(mFlags, "DATA"); // Store the file position mContext = esm.getContext(); mHasData = false; // Skip these here. Load the actual data when the cell is loaded. if (esm.isNextSub("VNML")) { esm.skipHSubSize(12675); mDataTypes |= DATA_VNML; } if (esm.isNextSub("VHGT")) { esm.skipHSubSize(4232); mDataTypes |= DATA_VHGT; } if (esm.isNextSub("WNAM")) { esm.skipHSubSize(81); mDataTypes |= DATA_WNAM; } if (esm.isNextSub("VCLR")) { esm.skipHSubSize(12675); mDataTypes |= DATA_VCLR; } if (esm.isNextSub("VTEX")) { esm.skipHSubSize(512); mDataTypes |= DATA_VTEX; } // We need all three of VNML, VHGT and VTEX in order to use the // landscape. (Though Morrowind seems to accept terrain without VTEX/VCLR entries) mHasData = mDataTypes & (DATA_VNML|DATA_VHGT|DATA_WNAM); mDataLoaded = 0; mLandData = NULL; }
void ESM::Player::load (ESMReader &esm) { mObject.load (esm); mCellId.load (esm); esm.getHNT (mLastKnownExteriorPosition, "LKEP", 12); if (esm.isNextSub ("MARK")) { mHasMark = true; esm.getHT (mMarkedPosition, 24); mMarkedCell.load (esm); } else mHasMark = false; mAutoMove = 0; esm.getHNOT (mAutoMove, "AMOV"); mBirthsign = esm.getHNString ("SIGN"); mCurrentCrimeId = -1; esm.getHNOT (mCurrentCrimeId, "CURD"); mPayedCrimeId = -1; esm.getHNOT (mPayedCrimeId, "PAYD"); }
void LeveledListBase::load(ESMReader &esm) { esm.getHNT(mFlags, "DATA"); esm.getHNT(mChanceNone, "NNAM"); if (esm.isNextSub("INDX")) { int len; esm.getHT(len); mList.resize(len); } else return; // TODO: Merge with an existing lists here. This can be done // simply by adding the lists together, making sure that they are // sorted by level. A better way might be to exclude repeated // items. Also, some times we don't want to merge lists, just // overwrite. Figure out a way to give the user this option. for (size_t i = 0; i < mList.size(); i++) { LevelItem &li = mList[i]; li.mId = esm.getHNString(mRecName); esm.getHNT(li.mLevel, "INTV"); } }
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(); }
void ESM::ObjectState::load (ESMReader &esm) { mVersion = esm.getFormat(); bool isDeleted; mRef.loadData(esm, isDeleted); mHasLocals = 0; esm.getHNOT (mHasLocals, "HLOC"); if (mHasLocals) mLocals.load (esm); mEnabled = 1; esm.getHNOT (mEnabled, "ENAB"); mCount = 1; esm.getHNOT (mCount, "COUN"); esm.getHNOT (mPosition, "POS_", 24); if (esm.isNextSub("LROT")) esm.skipHSub(); // local rotation, no longer used // obsolete int unused; esm.getHNOT(unused, "LTIM"); // FIXME: assuming "false" as default would make more sense, but also break compatibility with older save files mHasCustomState = true; esm.getHNOT (mHasCustomState, "HCUS"); }
void EffectList::load(ESMReader &esm) { ENAMstruct s; while (esm.isNextSub("ENAM")) { esm.getHT(s, 24); mList.push_back(s); } }
void Land::load(ESMReader &esm) { mEsm = &esm; mPlugin = mEsm->getIndex(); // Get the grid location esm.getSubNameIs("INTV"); esm.getSubHeaderIs(8); esm.getT<int>(mX); esm.getT<int>(mY); esm.getHNT(mFlags, "DATA"); // Store the file position mContext = esm.getContext(); // Skip these here. Load the actual data when the cell is loaded. if (esm.isNextSub("VNML")) { esm.skipHSubSize(12675); mDataTypes |= DATA_VNML; } if (esm.isNextSub("VHGT")) { esm.skipHSubSize(4232); mDataTypes |= DATA_VHGT; } if (esm.isNextSub("WNAM")) { esm.skipHSubSize(81); mDataTypes |= DATA_WNAM; } if (esm.isNextSub("VCLR")) { esm.skipHSubSize(12675); mDataTypes |= DATA_VCLR; } if (esm.isNextSub("VTEX")) { esm.skipHSubSize(512); mDataTypes |= DATA_VTEX; } mDataLoaded = 0; mLandData = NULL; }
void InventoryList::load(ESMReader &esm) { ContItem ci; while (esm.isNextSub("NPCO")) { esm.getHT(ci, 36); mList.push_back(ci); } }
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 load(ESMReader &esm) { while(esm.isNextSub("INDX")) { PartReference pr; esm.getHT(pr.part); // The INDX byte pr.male = esm.getHNOString("BNAM"); pr.female = esm.getHNOString("CNAM"); } }
void ESM::DialogueState::load (ESMReader &esm) { while (esm.isNextSub ("TOPI")) mKnownTopics.push_back (esm.getHString()); while (esm.isNextSub ("FACT")) { std::string faction = esm.getHString(); while (esm.isNextSub ("REAC")) { std::string faction2 = esm.getHString(); int reaction; esm.getHNT(reaction, "INTV"); mModFactionReaction[faction][faction2] = reaction; } } }
void Cell::loadData(ESMReader &esm) { // Ignore this for now, it might mean we should delete the entire // cell? // TODO: treat the special case "another plugin moved this ref, but we want to delete it"! if (esm.isNextSub("DELE")) { esm.skipHSub(); } esm.getHNT(mData, "DATA", 12); }
void AiWander::load(ESMReader &esm) { esm.getHNT (mData, "DATA"); esm.getHNT(mDurationData, "STAR"); // was mStartTime mStoredInitialActorPosition = false; if (esm.isNextSub("POS_")) { mStoredInitialActorPosition = true; esm.getHT(mInitialActorPosition); } }
void ESM::CellId::load (ESMReader &esm) { mWorldspace = esm.getHNString ("SPAC"); if (esm.isNextSub ("CIDX")) { esm.getHT (mIndex, 8); mPaged = true; } else mPaged = false; }
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); } }
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 ESM::CellRef::loadId(ESMReader &esm, bool wideRefNum) { // According to Hrnchamd, this does not belong to the actual ref. Instead, it is a marker indicating that // the following refs are part of a "temp refs" section. A temp ref is not being tracked by the moved references system. // Its only purpose is a performance optimization for "immovable" things. We don't need this, and it's problematic anyway, // because any item can theoretically be moved by a script. if (esm.isNextSub ("NAM0")) esm.skipHSub(); if (wideRefNum) esm.getHNT (mRefNum, "FRMR", 8); else esm.getHNT (mRefNum.mIndex, "FRMR"); mRefID = esm.getHNString ("NAME"); }
void ESM::GlobalMap::load (ESMReader &esm) { esm.getHNT(mBounds, "BNDS"); esm.getSubNameIs("DATA"); esm.getSubHeader(); mImageData.resize(esm.getSubSize()); esm.getExact(&mImageData[0], mImageData.size()); while (esm.isNextSub("MRK_")) { esm.getSubHeader(); CellId cell; esm.getT(cell.first); esm.getT(cell.second); mMarkers.push_back(cell); } }
void ESM::CellRef::loadId (ESMReader& esm, bool wideRefNum) { // According to Hrnchamd, this does not belong to the actual ref. Instead, it is a marker indicating that // the following refs are part of a "temp refs" section. A temp ref is not being tracked by the moved references system. // Its only purpose is a performance optimization for "immovable" things. We don't need this, and it's problematic anyway, // because any item can theoretically be moved by a script. if (esm.isNextSub ("NAM0")) esm.skipHSub(); blank(); mRefNum.load (esm, wideRefNum); mRefID = esm.getHNOString ("NAME"); if (mRefID.empty()) { std::ios::fmtflags f(std::cerr.flags()); std::cerr << "Warning: got CellRef with empty RefId in " << esm.getName() << " 0x" << std::hex << esm.getFileOffset() << std::endl; std::cerr.flags(f); } }
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(); }
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 Script::load(ESMReader &esm) { SCHD data; esm.getHNT(data, "SCHD", 52); mData = data.mData; mId = data.mName.toString(); // List of local variables if (esm.isNextSub("SCVR")) { int s = mData.mStringTableSize; char* tmp = new char[s]; esm.getHExact(tmp, s); // 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; for (size_t i = 0; i < mVarNames.size(); i++) { mVarNames[i] = std::string(str); str += mVarNames[i].size() + 1; if (str - tmp > s) esm.fail("String table overflow"); } delete[] tmp; } // Script mData mScriptData.resize(mData.mScriptDataSize); esm.getHNExact(&mScriptData[0], mScriptData.size(), "SCDT"); // Script text mScriptText = esm.getHNOString("SCTX"); }