Example #1
0
    void Land::loadData(int flags) const
    {
        OpenThreads::ScopedLock<OpenThreads::Mutex> lock(mMutex);

        // Try to load only available data
        flags = flags & mDataTypes;
        // Return if all required data is loaded
        if ((mDataLoaded & flags) == flags) {
            return;
        }
        // Create storage if nothing is loaded
        if (mLandData == NULL) {
            mLandData = new LandData;
            mLandData->mDataTypes = mDataTypes;
        }

        ESM::ESMReader reader;
        reader.restoreContext(mContext);

        if (reader.isNextSub("VNML")) {
            condLoad(reader, flags, DATA_VNML, mLandData->mNormals, sizeof(mLandData->mNormals));
        }

        if (reader.isNextSub("VHGT")) {
            static VHGT vhgt;
            if (condLoad(reader, flags, DATA_VHGT, &vhgt, sizeof(vhgt))) {
                float rowOffset = vhgt.mHeightOffset;
                for (int y = 0; y < LAND_SIZE; y++) {
                    rowOffset += vhgt.mHeightData[y * LAND_SIZE];

                    mLandData->mHeights[y * LAND_SIZE] = rowOffset * HEIGHT_SCALE;

                    float colOffset = rowOffset;
                    for (int x = 1; x < LAND_SIZE; x++) {
                        colOffset += vhgt.mHeightData[y * LAND_SIZE + x];
                        mLandData->mHeights[x + y * LAND_SIZE] = colOffset * HEIGHT_SCALE;
                    }
                }
                mLandData->mUnk1 = vhgt.mUnk1;
                mLandData->mUnk2 = vhgt.mUnk2;
            }
        }

        if (reader.isNextSub("WNAM")) {
            condLoad(reader, flags, DATA_WNAM, mLandData->mWnam, 81);
        }
        if (reader.isNextSub("VCLR"))
            condLoad(reader, flags, DATA_VCLR, mLandData->mColours, 3 * LAND_NUM_VERTS);
        if (reader.isNextSub("VTEX")) {
            static uint16_t vtex[LAND_NUM_TEXTURES];
            if (condLoad(reader, flags, DATA_VTEX, vtex, sizeof(vtex))) {
                LandData::transposeTextureData(vtex, mLandData->mTextures);
            }
        }
    }
Example #2
0
void Store<ESM::Cell>::handleMovedCellRefs(ESM::ESMReader& esm, ESM::Cell* cell)
{
    //Handling MovedCellRefs, there is no way to do it inside loadcell
    while (esm.isNextSub("MVRF")) {
        ESM::CellRef ref;
        ESM::MovedCellRef cMRef;
        cell->getNextMVRF(esm, cMRef);

        MWWorld::Store<ESM::Cell> &cStore = const_cast<MWWorld::Store<ESM::Cell>&>(mEsmStore->get<ESM::Cell>());
        ESM::Cell *cellAlt = const_cast<ESM::Cell*>(cStore.searchOrCreate(cMRef.mTarget[0], cMRef.mTarget[1]));

        // Get regular moved reference data. Adapted from CellStore::loadRefs. Maybe we can optimize the following
        //  implementation when the oher implementation works as well.
        bool deleted = false;
        cell->getNextRef(esm, ref, deleted);

        // Add data required to make reference appear in the correct cell.
        // We should not need to test for duplicates, as this part of the code is pre-cell merge.
        cell->mMovedRefs.push_back(cMRef);
        // But there may be duplicates here!
        ESM::CellRefTracker::iterator iter = std::find(cellAlt->mLeasedRefs.begin(), cellAlt->mLeasedRefs.end(), ref.mRefNum);
        if (iter == cellAlt->mLeasedRefs.end())
          cellAlt->mLeasedRefs.push_back(ref);
        else
          *iter = ref;
    }
}
Example #3
0
void CSMWorld::RefIdCollection::load (ESM::ESMReader& reader, bool base, UniversalId::Type type)
{
    std::string id = reader.getHNOString ("NAME");

    int index = searchId (id);

    if (reader.isNextSub ("DELE"))
    {
        reader.skipRecord();

        if (index==-1)
        {
            // deleting a record that does not exist

            // ignore it for now

            /// \todo report the problem to the user
        }
        else if (base)
        {
            mData.erase (index, 1);
        }
        else
        {
            mData.getRecord (mData.globalToLocalIndex (index)).mState = RecordBase::State_Deleted;
        }
    }
    else
    {
        if (index==-1)
        {
            // new record
            int index = mData.getAppendIndex (type);
            mData.appendRecord (type, id);

            RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (index);

            mData.load (localIndex, reader, base);

            mData.getRecord (localIndex).mState =
                base ? RecordBase::State_BaseOnly : RecordBase::State_ModifiedOnly;
        }
        else
        {
            // old record
            RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (index);

            if (!base)
                if (mData.getRecord (localIndex).mState==RecordBase::State_Erased)
                    throw std::logic_error ("attempt to access a deleted record");

            mData.load (localIndex, reader, base);

            if (!base)
                mData.getRecord (localIndex).mState = RecordBase::State_Modified;
        }
    }
}
Example #4
0
    void IdCollection<ESXRecordT>::load (ESM::ESMReader& reader, bool base)
    {
        std::string id = reader.getHNOString ("NAME");

        if (reader.isNextSub ("DELE"))
        {
            int index = searchId (id);

            reader.skipRecord();

            if (index==-1)
            {
                // deleting a record that does not exist

                // ignore it for now

                /// \todo report the problem to the user
            }
            else if (base)
            {
                removeRows (index, 1);
            }
            else
            {
                mRecords[index].mState = RecordBase::State_Deleted;
            }
        }
        else
        {
            ESXRecordT record;
            record.mId = id;
            record.load (reader);

            int index = searchId (record.mId);

            if (index==-1)
            {
                // new record
                Record<ESXRecordT> record2;
                record2.mState = base ? RecordBase::State_BaseOnly : RecordBase::State_ModifiedOnly;
                (base ? record2.mBase : record2.mModified) = record;

                appendRecord (record2);
            }
            else
            {
                // old record
                Record<ESXRecordT>& record2 = mRecords[index];

                if (base)
                    record2.mBase = record;
                else
                    record2.setModified (record);
            }
        }
    }
Example #5
0
    virtual void read(ESM::ESMReader &esm)
    {
        std::string itemid = esm.getHNString("NAME");
        Misc::StringUtils::lowerCaseInPlace(itemid);

        while (esm.isNextSub("FNAM") || esm.isNextSub("ONAM"))
        {
            if (esm.retSubName().toString() == "FNAM")
            {
                std::string factionid = esm.getHString();
                mStolenItems[itemid].insert(std::make_pair(Misc::StringUtils::lowerCase(factionid), true));
            }
            else
            {
                std::string ownerid = esm.getHString();
                mStolenItems[itemid].insert(std::make_pair(Misc::StringUtils::lowerCase(ownerid), false));
            }
        }
    }
Example #6
0
    void IdCollection<ESXRecordT, IdAccessorT>::load (ESM::ESMReader& reader, bool base)
    {
        std::string id = reader.getHNOString ("NAME");

        if (reader.isNextSub ("DELE"))
        {
            int index = Collection<ESXRecordT, IdAccessorT>::searchId (id);

            reader.skipRecord();

            if (index==-1)
            {
                // deleting a record that does not exist

                // ignore it for now

                /// \todo report the problem to the user
            }
            else if (base)
            {
                Collection<ESXRecordT, IdAccessorT>::removeRows (index, 1);
            }
            else
            {
                Record<ESXRecordT> record = Collection<ESXRecordT, IdAccessorT>::getRecord (index);
                record.mState = RecordBase::State_Deleted;
                this->setRecord (index, record);
            }
        }
        else
        {
            ESXRecordT record;

            int index = this->searchId (id);

            if (index==-1)
                IdAccessorT().getId (record) = id;
            else
            {
                record = this->getRecord (index).get();
            }

            record.load (reader);

            load (record, base, index);
        }
    }
Example #7
0
void CSMWorld::InfoCollection::load (ESM::ESMReader& reader, bool base, const ESM::Dialogue& dialogue)
{
    std::string id = Misc::StringUtils::lowerCase (dialogue.mId) + "#" +
        reader.getHNOString ("INAM");

    if (reader.isNextSub ("DELE"))
    {
        int index = searchId (id);

        reader.skipRecord();

        if (index==-1)
        {
            // deleting a record that does not exist

            // ignore it for now

            /// \todo report the problem to the user
        }
        else if (base)
        {
            removeRows (index, 1);
        }
        else
        {
            Record<Info> record = getRecord (index);
            record.mState = RecordBase::State_Deleted;
            setRecord (index, record);
        }
    }
    else
    {
        Info record;
        record.mTopicId = dialogue.mId;
        record.mId = id;
        record.load (reader);

        load (record, base);
    }
}
Example #8
0
    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");
            }
        }
    }
Example #9
0
    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);
        }
    }
Example #10
0
    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);
        }
    }
Example #11
0
    void ActorData::load(ESM::ESMReader &esm)
    {
        if (esm.isNextSub("ACTN"))
            esm.skipHSub();

        if (esm.isNextSub("STPR"))
            esm.skipHSub();

        if (esm.isNextSub("MNAM"))
           esm.skipHSub();

        ESM::CellRef::loadData(esm);

        // FIXME: not all actors have this, add flag
        esm.getHNOT(mACDT, "ACDT");

        ACSC acsc;
        esm.getHNOT(acsc, "ACSC");
        esm.getHNOT(acsc, "ACSL");

        if (esm.isNextSub("CSTN"))
            esm.skipHSub(); // "PlayerSaveGame", link to some object?

        if (esm.isNextSub("LSTN"))
            esm.skipHSub(); // "PlayerSaveGame", link to some object?

        // unsure at which point between LSTN and TGTN
        if (esm.isNextSub("CSHN"))
            esm.skipHSub(); // "PlayerSaveGame", link to some object?

        // unsure if before or after CSTN/LSTN
        if (esm.isNextSub("LSHN"))
            esm.skipHSub(); // "PlayerSaveGame", link to some object?

        while (esm.isNextSub("TGTN"))
            esm.skipHSub(); // "PlayerSaveGame", link to some object?

        while (esm.isNextSub("FGTN"))
            esm.getHString(); // fight target?

        // unsure at which point between TGTN and CRED
        if (esm.isNextSub("AADT"))
        {
            // occured when a creature was in the middle of its attack, 44 bytes
            esm.skipHSub();
        }

        // unsure at which point between FGTN and CHRD
        if (esm.isNextSub("PWPC"))
            esm.skipHSub();
        if (esm.isNextSub("PWPS"))
            esm.skipHSub();

        // unsure at which point between LSTN and CHRD
        if (esm.isNextSub("APUD"))
            esm.skipHSub(); // 40 bytes, starts with string "ancestor guardian". maybe spellcasting in progress?

        if (esm.isNextSub("WNAM"))
        {
            std::string id = esm.getHString();

            if (esm.isNextSub("XNAM"))
                mSelectedEnchantItem = esm.getHString();
            else
                mSelectedSpell = id;

            if (esm.isNextSub("YNAM"))
                esm.skipHSub(); // 4 byte, 0
        }

        // FIXME: not all actors have this, add flag
        if (esm.isNextSub("CHRD")) // npc only
                esm.getHExact(mSkills, 27*2*sizeof(int));

        if (esm.isNextSub("CRED")) // creature only
            esm.getHExact(mCombatStats, 3*2*sizeof(int));

        mSCRI.load(esm);

        if (esm.isNextSub("ND3D"))
            esm.skipHSub();
        if (esm.isNextSub("ANIS"))
            esm.skipHSub();
    }
Example #12
0
void ESMStore::load(ESM::ESMReader &esm, Loading::Listener* listener)
{
    listener->setProgressRange(1000);

    std::set<std::string> missing;

    ESM::Dialogue *dialogue = 0;

    /// \todo Move this to somewhere else. ESMReader?
    // Cache parent esX files by tracking their indices in the global list of
    //  all files/readers used by the engine. This will greaty accelerate
    //  refnumber mangling, as required for handling moved references.
    int index = ~0;
    const std::vector<ESM::Header::MasterData> &masters = esm.getGameFiles();
    std::vector<ESM::ESMReader> *allPlugins = esm.getGlobalReaderList();
    for (size_t j = 0; j < masters.size(); j++) {
        ESM::Header::MasterData &mast = const_cast<ESM::Header::MasterData&>(masters[j]);
        std::string fname = mast.name;
        for (int i = 0; i < esm.getIndex(); i++) {
            const std::string &candidate = allPlugins->at(i).getContext().filename;
            std::string fnamecandidate = boost::filesystem::path(candidate).filename().string();
            if (fname == fnamecandidate) {
                index = i;
                break;
            }
        }
        if (index == (int)~0) {
            // Tried to load a parent file that has not been loaded yet. This is bad,
            //  the launcher should have taken care of this.
            std::string fstring = "File " + esm.getName() + " asks for parent file " + masters[j].name
                + ", but it has not been loaded yet. Please check your load order.";
            esm.fail(fstring);
        }
        mast.index = index;
    }

    // Loop through all records
    while(esm.hasMoreRecs())
    {
        ESM::NAME n = esm.getRecName();
        esm.getRecHeader();

        // Look up the record type.
        std::map<int, StoreBase *>::iterator it = mStores.find(n.val);

        if (it == mStores.end()) {
            if (n.val == ESM::REC_INFO) {
                std::string id = esm.getHNOString("INAM");
                if (dialogue) {
                    dialogue->mInfo.push_back(ESM::DialInfo());
                    dialogue->mInfo.back().mId = id;
                    dialogue->mInfo.back().load(esm);
                } else {
                    std::cerr << "error: info record without dialog" << std::endl;
                    esm.skipRecord();
                }
            } else if (n.val == ESM::REC_MGEF) {
                mMagicEffects.load (esm);
            } else if (n.val == ESM::REC_SKIL) {
                mSkills.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");
            // ... unless it got deleted! This means that the following record
            //  has been deleted, and trying to load it using standard assumptions
            //  on the structure will (probably) fail.
            if (esm.isNextSub("DELE")) {
              esm.skipRecord();
              it->second->eraseStatic(id);
              continue;
            }
            it->second->load(esm, id);

            if (n.val==ESM::REC_DIAL) {
                dialogue = const_cast<ESM::Dialogue*>(mDialogs.find(id));
            } else {
                dialogue = 0;
            }
            // Insert the reference into the global lookup
            if (!id.empty() && isCacheableRecord(n.val)) {
                mIds[Misc::StringUtils::lowerCase (id)] = n.val;
            }
        }
        listener->setProgress(esm.getFileOffset() / (float)esm.getFileSize() * 1000);
    }

  /* This information isn't needed on screen. But keep the code around
     for debugging purposes later.

  cout << "\n" << mStores.size() << " record types:\n";
  for(RecListList::iterator it = mStores.begin(); it != mStores.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;
  */
}
Example #13
0
    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;
        }
    }
Example #14
0
void ESMStore::load(ESM::ESMReader &esm, Loading::Listener* listener)
{
    listener->setProgressRange(1000);

    ESM::Dialogue *dialogue = 0;

    /// \todo Move this to somewhere else. ESMReader?
    // Cache parent esX files by tracking their indices in the global list of
    //  all files/readers used by the engine. This will greaty accelerate
    //  refnumber mangling, as required for handling moved references.
    const std::vector<ESM::Header::MasterData> &masters = esm.getGameFiles();
    std::vector<ESM::ESMReader> *allPlugins = esm.getGlobalReaderList();
    for (size_t j = 0; j < masters.size(); j++) {
        ESM::Header::MasterData &mast = const_cast<ESM::Header::MasterData&>(masters[j]);
        std::string fname = mast.name;
        int index = ~0;
        for (int i = 0; i < esm.getIndex(); i++) {
            const std::string &candidate = allPlugins->at(i).getContext().filename;
            std::string fnamecandidate = boost::filesystem::path(candidate).filename().string();
            if (Misc::StringUtils::ciEqual(fname, fnamecandidate)) {
                index = i;
                break;
            }
        }
        if (index == (int)~0) {
            // Tried to load a parent file that has not been loaded yet. This is bad,
            //  the launcher should have taken care of this.
            std::string fstring = "File " + esm.getName() + " asks for parent file " + masters[j].name
                + ", but it has not been loaded yet. Please check your load order.";
            esm.fail(fstring);
        }
        mast.index = index;
    }

    // Loop through all records
    while(esm.hasMoreRecs())
    {
        ESM::NAME n = esm.getRecName();
        esm.getRecHeader();

        // Look up the record type.
        std::map<int, StoreBase *>::iterator it = mStores.find(n.val);

        if (it == mStores.end()) {
            if (n.val == ESM::REC_INFO) {
                if (dialogue)
                {
                    dialogue->readInfo(esm, esm.getIndex() != 0);
                }
                else
                {
                    std::cerr << "error: info record without dialog" << std::endl;
                    esm.skipRecord();
                }
            } else if (n.val == ESM::REC_MGEF) {
                mMagicEffects.load (esm);
            } else if (n.val == ESM::REC_SKIL) {
                mSkills.load (esm);
            }
            else if (n.val==ESM::REC_FILT || ESM::REC_DBGP)
            {
                // ignore project file only records
                esm.skipRecord();
            }
            else {
                std::stringstream error;
                error << "Unknown record: " << n.toString();
                throw std::runtime_error(error.str());
            }
        } else {
            // Load it
            std::string id = esm.getHNOString("NAME");
            // ... unless it got deleted! This means that the following record
            //  has been deleted, and trying to load it using standard assumptions
            //  on the structure will (probably) fail.
            if (esm.isNextSub("DELE")) {
              esm.skipRecord();
              it->second->eraseStatic(id);
              continue;
            }
            it->second->load(esm, id);

            // DELE can also occur after the usual subrecords
            if (esm.isNextSub("DELE")) {
              esm.skipRecord();
              it->second->eraseStatic(id);
              continue;
            }

            if (n.val==ESM::REC_DIAL) {
                dialogue = const_cast<ESM::Dialogue*>(mDialogs.find(id));
            } else {
                dialogue = 0;
            }
            // Insert the reference into the global lookup
            if (!id.empty() && isCacheableRecord(n.val)) {
                mIds[Misc::StringUtils::lowerCase (id)] = n.val;
            }
        }
        listener->setProgress(esm.getFileOffset() / (float)esm.getFileSize() * 1000);
    }
}
Example #15
0
void Store<ESM::Cell>::load(ESM::ESMReader &esm, const std::string &id)
{
    // Don't automatically assume that a new cell must be spawned. Multiple plugins write to the same cell,
    //  and we merge all this data into one Cell object. However, we can't simply search for the cell id,
    //  as many exterior cells do not have a name. Instead, we need to search by (x,y) coordinates - and they
    //  are not available until both cells have been loaded! So first, proceed as usual.
    
    // All cells have a name record, even nameless exterior cells.
    std::string idLower = Misc::StringUtils::lowerCase(id);
    ESM::Cell *cell = new ESM::Cell;
    cell->mName = id;

    //First part of cell loading
    cell->preLoad(esm);

    //Handling MovedCellRefs, there is no way to do it inside loadcell
    while (esm.isNextSub("MVRF")) {
        ESM::CellRef ref;
        ESM::MovedCellRef cMRef;
        cell->getNextMVRF(esm, cMRef);

        MWWorld::Store<ESM::Cell> &cStore = const_cast<MWWorld::Store<ESM::Cell>&>(mEsmStore->get<ESM::Cell>());
        ESM::Cell *cellAlt = const_cast<ESM::Cell*>(cStore.searchOrCreate(cMRef.mTarget[0], cMRef.mTarget[1]));

        // Get regular moved reference data. Adapted from CellStore::loadRefs. Maybe we can optimize the following
        //  implementation when the oher implementation works as well.
        cell->getNextRef(esm, ref);
        std::string lowerCase;

        std::transform (ref.mRefID.begin(), ref.mRefID.end(), std::back_inserter (lowerCase),
            (int(*)(int)) std::tolower);

        // Add data required to make reference appear in the correct cell.
        // We should not need to test for duplicates, as this part of the code is pre-cell merge.
        cell->mMovedRefs.push_back(cMRef);
        // But there may be duplicates here!
        ESM::CellRefTracker::iterator iter = std::find(cellAlt->mLeasedRefs.begin(), cellAlt->mLeasedRefs.end(), ref.mRefnum);
        if (iter == cellAlt->mLeasedRefs.end())
          cellAlt->mLeasedRefs.push_back(ref);
        else
          *iter = ref;
    }

    //Second part of cell loading
    cell->postLoad(esm);

    if(cell->mData.mFlags & ESM::Cell::Interior)
    {
        // Store interior cell by name, try to merge with existing parent data.
        ESM::Cell *oldcell = const_cast<ESM::Cell*>(search(idLower));
        if (oldcell) {
            // push the new references on the list of references to manage
            oldcell->mContextList.push_back(cell->mContextList.at(0));
            // copy list into new cell
            cell->mContextList = oldcell->mContextList;
            // have new cell replace old cell
            *oldcell = *cell;
        } else
            mInt[idLower] = *cell;
    }
    else
    {
        // Store exterior cells by grid position, try to merge with existing parent data.
        ESM::Cell *oldcell = const_cast<ESM::Cell*>(search(cell->getGridX(), cell->getGridY()));
        if (oldcell) {
            // push the new references on the list of references to manage
            oldcell->mContextList.push_back(cell->mContextList.at(0));
            // copy list into new cell
            cell->mContextList = oldcell->mContextList;
            // merge lists of leased references, use newer data in case of conflict
            for (ESM::MovedCellRefTracker::const_iterator it = cell->mMovedRefs.begin(); it != cell->mMovedRefs.end(); it++) {
                // remove reference from current leased ref tracker and add it to new cell
                ESM::MovedCellRefTracker::iterator itold = std::find(oldcell->mMovedRefs.begin(), oldcell->mMovedRefs.end(), it->mRefnum);
                if (itold != oldcell->mMovedRefs.end()) {
                    ESM::MovedCellRef target0 = *itold;
                    ESM::Cell *wipecell = const_cast<ESM::Cell*>(search(target0.mTarget[0], target0.mTarget[1]));
                    ESM::CellRefTracker::iterator it_lease = std::find(wipecell->mLeasedRefs.begin(), wipecell->mLeasedRefs.end(), it->mRefnum);
                    wipecell->mLeasedRefs.erase(it_lease);
                    *itold = *it;
                }
            }
            cell->mMovedRefs = oldcell->mMovedRefs;
            // have new cell replace old cell
            *oldcell = *cell;
        } else
            mExt[std::make_pair(cell->mData.mX, cell->mData.mY)] = *cell;
    }
    delete cell;
}