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 AiFollow::load(ESMReader &esm) { esm.getHNT (mData, "DATA"); mTargetId = esm.getHNString("TARG"); esm.getHNT (mRemainingDuration, "DURA"); mCellId = esm.getHNOString ("CELL"); esm.getHNT (mAlwaysFollow, "ALWY"); mCommanded = false; esm.getHNOT (mCommanded, "CMND"); mActive = false; esm.getHNOT (mActive, "ACTV"); }
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 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 DoorState::load(ESMReader &esm) { ObjectState::load(esm); mDoorState = 0; esm.getHNOT (mDoorState, "ANIM"); }
void ESM::ObjectState::load (ESMReader &esm) { mVersion = esm.getFormat(); mRef.loadData(esm); 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); esm.getHNOT (mLocalRotation, "LROT", 12); // 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 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 mFlags = 0; esm.getHNOT (mFlags, "FLAG"); // 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"); }
bool Cell::getNextMVRF(ESMReader &esm, MovedCellRef &mref) { esm.getHT(mref.mRefNum.mIndex); esm.getHNOT(mref.mTarget, "CNDT"); adjustRefNum (mref.mRefNum, esm); return true; }
void AiEscort::load(ESMReader &esm) { esm.getHNT (mData, "DATA"); mTargetId = esm.getHNString("TARG"); mTargetActorId = -1; esm.getHNOT (mTargetActorId, "TAID"); esm.getHNT (mRemainingDuration, "DURA"); mCellId = esm.getHNOString ("CELL"); }
void ProjectileState::load(ESMReader &esm) { BaseProjectileState::load(esm); mBowId = esm.getHNString ("BOW_"); esm.getHNT (mVelocity, "VEL_"); mAttackStrength = 1.f; esm.getHNOT(mAttackStrength, "STR_"); }
void ESM::GlobalScript::load (ESMReader &esm) { mId = esm.getHNString ("NAME"); mLocals.load (esm); mRunning = 0; esm.getHNOT (mRunning, "RUN_"); mTargetId = esm.getHNOString ("TARG"); }
bool Cell::getNextMVRF(ESMReader &esm, MovedCellRef &mref) { esm.getHT(mref.mRefnum); esm.getHNOT(mref.mTarget, "CNDT"); // Identify references belonging to a parent file and adapt the ID accordingly. int local = (mref.mRefnum & 0xff000000) >> 24; size_t global = esm.getIndex() + 1; mref.mRefnum &= 0x00ffffff; // delete old plugin ID const std::vector<Header::MasterData> &masters = esm.getGameFiles(); global = masters[local-1].index + 1; mref.mRefnum |= global << 24; // insert global plugin ID return true; }
void ESM::JournalEntry::load (ESMReader &esm) { esm.getHNOT (mType, "JETY"); mTopic = esm.getHNString ("YETO"); mInfo = esm.getHNString ("YEIN"); mText = esm.getHNString ("TEXT"); if (mType==Type_Journal) { esm.getHNT (mDay, "JEDA"); esm.getHNT (mMonth, "JEMO"); esm.getHNT (mDayOfMonth, "JEDM"); } else if (mType==Type_Topic) mActorName = esm.getHNOString("ACT_"); }
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 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 ESM::CreatureStats::load (ESMReader &esm) { for (int i=0; i<8; ++i) mAttributes[i].load (esm); for (int i=0; i<3; ++i) mDynamic[i].load (esm); mGoldPool = 0; esm.getHNOT (mGoldPool, "GOLD"); mTradeTime.mDay = 0; mTradeTime.mHour = 0; esm.getHNOT (mTradeTime, "TIME"); mDead = false; esm.getHNOT (mDead, "DEAD"); mDied = false; esm.getHNOT (mDied, "DIED"); mMurdered = false; esm.getHNOT (mMurdered, "MURD"); mFriendlyHits = 0; esm.getHNOT (mFriendlyHits, "FRHT"); mTalkedTo = false; esm.getHNOT (mTalkedTo, "TALK"); mAlarmed = false; esm.getHNOT (mAlarmed, "ALRM"); mAttacked = false; esm.getHNOT (mAttacked, "ATKD"); if (esm.isNextSub("HOST")) esm.skipHSub(); // Hostile, no longer used mAttackingOrSpell = false; esm.getHNOT (mAttackingOrSpell, "ATCK"); mKnockdown = false; esm.getHNOT (mKnockdown, "KNCK"); mKnockdownOneFrame = false; esm.getHNOT (mKnockdownOneFrame, "KNC1"); mKnockdownOverOneFrame = false; esm.getHNOT (mKnockdownOverOneFrame, "KNCO"); mHitRecovery = false; esm.getHNOT (mHitRecovery, "HITR"); mBlock = false; esm.getHNOT (mBlock, "BLCK"); mMovementFlags = 0; esm.getHNOT (mMovementFlags, "MOVE"); mAttackStrength = 0; esm.getHNOT (mAttackStrength, "ASTR"); mFallHeight = 0; esm.getHNOT (mFallHeight, "FALL"); mLastHitObject = esm.getHNOString ("LHIT"); mLastHitAttemptObject = esm.getHNOString ("LHAT"); mRecalcDynamicStats = false; esm.getHNOT (mRecalcDynamicStats, "CALC"); mDrawState = 0; esm.getHNOT (mDrawState, "DRAW"); mLevel = 1; esm.getHNOT (mLevel, "LEVL"); mActorId = -1; esm.getHNOT (mActorId, "ACID"); mDeathAnimation = 0; esm.getHNOT (mDeathAnimation, "DANM"); mSpells.load(esm); mActiveSpells.load(esm); mAiSequence.load(esm); mMagicEffects.load(esm); while (esm.isNextSub("SUMM")) { int magicEffect; esm.getHT(magicEffect); std::string source = esm.getHNOString("SOUR"); int actorId; esm.getHNT (actorId, "ACID"); mSummonedCreatureMap[std::make_pair(magicEffect, source)] = actorId; } while (esm.isNextSub("GRAV")) { int actorId; esm.getHT(actorId); mSummonGraveyard.push_back(actorId); } mHasAiSettings = false; esm.getHNOT(mHasAiSettings, "AISE"); if (mHasAiSettings) { for (int i=0; i<4; ++i) mAiSettings[i].load(esm); } }
bool Cell::getNextRef(ESMReader &esm, CellRef &ref) { if (!esm.hasMoreSubs()) return false; // 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. { int i; esm.getHNOT(i, "NAM0"); } esm.getHNT(ref.refnum, "FRMR"); ref.refID = esm.getHNString("NAME"); // getHNOT will not change the existing value if the subrecord is // missing ref.scale = 1.0; esm.getHNOT(ref.scale, "XSCL"); ref.owner = esm.getHNOString("ANAM"); ref.glob = esm.getHNOString("BNAM"); ref.soul = esm.getHNOString("XSOL"); ref.faction = esm.getHNOString("CNAM"); ref.factIndex = -1; esm.getHNOT(ref.factIndex, "INDX"); ref.charge = -1.0; esm.getHNOT(ref.charge, "XCHG"); ref.intv = 0; ref.nam9 = 0; esm.getHNOT(ref.intv, "INTV"); esm.getHNOT(ref.nam9, "NAM9"); // Present for doors that teleport you to another cell. if (esm.isNextSub("DODT")) { ref.teleport = true; esm.getHT(ref.doorDest); ref.destCell = esm.getHNOString("DNAM"); } else ref.teleport = false; // Integer, despite the name suggesting otherwise ref.lockLevel = 0; esm.getHNOT(ref.lockLevel, "FLTV"); ref.key = esm.getHNOString("KNAM"); ref.trap = esm.getHNOString("TNAM"); ref.unam = 0; ref.fltv = 0; esm.getHNOT(ref.unam, "UNAM"); esm.getHNOT(ref.fltv, "FLTV"); esm.getHNT(ref.pos, "DATA", 24); return true; }
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 AiSequence::load(ESMReader &esm) { while (esm.isNextSub("AIPK")) { int type; esm.getHT(type); mPackages.push_back(AiPackageContainer()); mPackages.back().mType = type; switch (type) { case Ai_Wander: { std::unique_ptr<AiWander> ptr (new AiWander()); ptr->load(esm); mPackages.back().mPackage = ptr.release(); break; } case Ai_Travel: { std::unique_ptr<AiTravel> ptr (new AiTravel()); ptr->load(esm); mPackages.back().mPackage = ptr.release(); break; } case Ai_Escort: { std::unique_ptr<AiEscort> ptr (new AiEscort()); ptr->load(esm); mPackages.back().mPackage = ptr.release(); break; } case Ai_Follow: { std::unique_ptr<AiFollow> ptr (new AiFollow()); ptr->load(esm); mPackages.back().mPackage = ptr.release(); break; } case Ai_Activate: { std::unique_ptr<AiActivate> ptr (new AiActivate()); ptr->load(esm); mPackages.back().mPackage = ptr.release(); break; } case Ai_Combat: { std::unique_ptr<AiCombat> ptr (new AiCombat()); ptr->load(esm); mPackages.back().mPackage = ptr.release(); break; } case Ai_Pursue: { std::unique_ptr<AiPursue> ptr (new AiPursue()); ptr->load(esm); mPackages.back().mPackage = ptr.release(); break; } default: return; } } esm.getHNOT (mLastAiPackage, "LAST"); }
void AiTravel::load(ESMReader &esm) { esm.getHNT (mData, "DATA"); esm.getHNOT (mHidden, "HIDD"); }
void ESM::NpcStats::load (ESMReader &esm) { while (esm.isNextSub ("FACT")) { std::string id = esm.getHString(); Faction faction; int expelled = 0; esm.getHNOT (expelled, "FAEX"); if (expelled) faction.mExpelled = true; esm.getHNOT (faction.mRank, "FARA"); esm.getHNOT (faction.mReputation, "FARE"); mFactions.insert (std::make_pair (id, faction)); } mDisposition = 0; esm.getHNOT (mDisposition, "DISP"); for (int i=0; i<27; ++i) { mSkills[i].mRegular.load (esm); mSkills[i].mWerewolf.load (esm); } bool hasWerewolfAttributes = false; esm.getHNOT (hasWerewolfAttributes, "HWAT"); if (hasWerewolfAttributes) { for (int i=0; i<8; ++i) mWerewolfAttributes[i].load (esm); } mIsWerewolf = false; esm.getHNOT (mIsWerewolf, "WOLF"); mBounty = 0; esm.getHNOT (mBounty, "BOUN"); mReputation = 0; esm.getHNOT (mReputation, "REPU"); mWerewolfKills = 0; esm.getHNOT (mWerewolfKills, "WKIL"); mProfit = 0; esm.getHNOT (mProfit, "PROF"); // No longer used. Now part of CreatureStats. float attackStrength = 0; esm.getHNOT (attackStrength, "ASTR"); mLevelProgress = 0; esm.getHNOT (mLevelProgress, "LPRO"); esm.getHNT (mSkillIncrease, "INCR"); while (esm.isNextSub ("USED")) mUsedIds.push_back (esm.getHString()); mTimeToStartDrowning = 0; esm.getHNOT (mTimeToStartDrowning, "DRTI"); mLastDrowningHit = 0; esm.getHNOT (mLastDrowningHit, "DRLH"); mLevelHealthBonus = 0; esm.getHNOT (mLevelHealthBonus, "LVLH"); mCrimeId = -1; esm.getHNOT (mCrimeId, "CRID"); }