Inventory/Container GUI

Everything about development and the OpenMW source code.
User avatar
scrawl
Posts: 2152
Joined: 18 Feb 2012, 11:51

Re: Inventory/Container GUI

Post by scrawl »

By the way, this is a new method that I added to MWWorld::Scene in order to drop items on the ground from the inventory, and I'm not entirely sure if the second part (insert into the correct CellRefList) is correct?

Code: Select all

    void Scene::insertObject(MWWorld::Ptr ptr, Ptr::CellStore* cell)
    {
        ptr.mCell = cell;

        mRendering.addObject(ptr);
        MWWorld::Class::get(ptr).insertObject(ptr, *mPhysics);
        MWWorld::Class::get(ptr).enable(ptr);

        std::string type = ptr.getTypeName();

        // insert into the correct CellRefList
        if      (type == typeid(ESM::Potion).name())
            cell->potions.list.push_back( *ptr.get<ESM::Potion>() );
        else if (type == typeid(ESM::Apparatus).name())
            cell->appas.list.push_back( *ptr.get<ESM::Apparatus>() );
        else if (type == typeid(ESM::Armor).name())
            cell->armors.list.push_back( *ptr.get<ESM::Armor>() );
        else if (type == typeid(ESM::Book).name())
            cell->books.list.push_back( *ptr.get<ESM::Book>() );
        else if (type == typeid(ESM::Clothing).name())
            cell->clothes.list.push_back( *ptr.get<ESM::Clothing>() );
        else if (type == typeid(ESM::Ingredient).name())
            cell->ingreds.list.push_back( *ptr.get<ESM::Ingredient>() );
        else if (type == typeid(ESM::Light).name())
            cell->lights.list.push_back( *ptr.get<ESM::Light>() );
        else if (type == typeid(ESM::Tool).name())
            cell->lockpicks.list.push_back( *ptr.get<ESM::Tool>() );
        else if (type == typeid(ESM::Repair).name())
            cell->repairs.list.push_back( *ptr.get<ESM::Repair>() );
        else if (type == typeid(ESM::Probe).name())
            cell->probes.list.push_back( *ptr.get<ESM::Probe>() );
        else if (type == typeid(ESM::Weapon).name())
            cell->weapons.list.push_back( *ptr.get<ESM::Weapon>() );
        else if (type == typeid(ESM::Miscellaneous).name())
            cell->miscItems.list.push_back( *ptr.get<ESM::Miscellaneous>() );
        else
            throw std::runtime_error("Trying to insert object of unhandled type");
    }
User avatar
Zini
Posts: 5538
Joined: 06 Aug 2011, 15:16

Re: Inventory/Container GUI

Post by Zini »

It is not. You are calling addObject, insertObject and enable on the Ptr passed into the function (presumably pointing to an object still in the inventory). And then you create a copy of the object in the cell. You need to do it the other way around. First create a copy, acquire a Ptr to it and then call those function for this Ptr.

btw. there are multiple other problems with the implementation (starting with that this function definitely does not belong into the scene class). But nothing of that affects dropping items from inventory, so we should be good for now, if you just fix the problem mentioned above.
User avatar
scrawl
Posts: 2152
Joined: 18 Feb 2012, 11:51

Re: Inventory/Container GUI

Post by scrawl »

How can I acquire the new pointer after inserting it in the cell?
User avatar
Zini
Posts: 5538
Joined: 06 Aug 2011, 15:16

Re: Inventory/Container GUI

Post by Zini »

The Ptr class has a constructor that takes a pointer to a LiveCellRef and a pointer to a CellStore. Use it.
User avatar
scrawl
Posts: 2152
Joined: 18 Feb 2012, 11:51

Re: Inventory/Container GUI

Post by scrawl »

Here's the new method, but it crashes when dropping an object.

Code: Select all

    void Scene::insertObject(MWWorld::Ptr ptr, Ptr::CellStore* cell)
    {
        std::string type = ptr.getTypeName();

        MWWorld::Ptr newPtr;

        // insert into the correct CellRefList
        if      (type == typeid(ESM::Potion).name())
        {
            ESMS::LiveCellRef<ESM::Potion, MWWorld::RefData>* ref = ptr.get<ESM::Potion>();
            newPtr = MWWorld::Ptr(ref, cell);
            cell->potions.list.push_back( *ref );
        }
        else if (type == typeid(ESM::Apparatus).name())
        {
            ESMS::LiveCellRef<ESM::Apparatus, MWWorld::RefData>* ref = ptr.get<ESM::Apparatus>();
            newPtr = MWWorld::Ptr(ref, cell);
            cell->appas.list.push_back( *ref );
        }
        else if (type == typeid(ESM::Armor).name())
        {
            ESMS::LiveCellRef<ESM::Armor, MWWorld::RefData>* ref = ptr.get<ESM::Armor>();
            newPtr = MWWorld::Ptr(ref, cell);
            cell->armors.list.push_back( *ref );
        }
        else if (type == typeid(ESM::Book).name())
        {
            ESMS::LiveCellRef<ESM::Book, MWWorld::RefData>* ref = ptr.get<ESM::Book>();
            newPtr = MWWorld::Ptr(ref, cell);
            cell->books.list.push_back( *ref );
        }
        else if (type == typeid(ESM::Clothing).name())
        {
            ESMS::LiveCellRef<ESM::Clothing, MWWorld::RefData>* ref = ptr.get<ESM::Clothing>();
            newPtr = MWWorld::Ptr(ref, cell);
            cell->clothes.list.push_back( *ref );
        }
        else if (type == typeid(ESM::Ingredient).name())
        {
            ESMS::LiveCellRef<ESM::Ingredient, MWWorld::RefData>* ref = ptr.get<ESM::Ingredient>();
            newPtr = MWWorld::Ptr(ref, cell);
            cell->ingreds.list.push_back( *ref );
        }
        else if (type == typeid(ESM::Light).name())
        {
            ESMS::LiveCellRef<ESM::Light, MWWorld::RefData>* ref = ptr.get<ESM::Light>();
            newPtr = MWWorld::Ptr(ref, cell);
            cell->lights.list.push_back( *ref );
        }
        else if (type == typeid(ESM::Tool).name())
        {
            ESMS::LiveCellRef<ESM::Tool, MWWorld::RefData>* ref = ptr.get<ESM::Tool>();
            newPtr = MWWorld::Ptr(ref, cell);
            cell->lockpicks.list.push_back( *ref );
        }
        else if (type == typeid(ESM::Repair).name())
        {
            ESMS::LiveCellRef<ESM::Repair, MWWorld::RefData>* ref = ptr.get<ESM::Repair>();
            newPtr = MWWorld::Ptr(ref, cell);
            cell->repairs.list.push_back( *ref );
        }
        else if (type == typeid(ESM::Probe).name())
        {
            ESMS::LiveCellRef<ESM::Probe, MWWorld::RefData>* ref = ptr.get<ESM::Probe>();
            newPtr = MWWorld::Ptr(ref, cell);
            cell->probes.list.push_back( *ref );
        }
        else if (type == typeid(ESM::Weapon).name())
        {
            ESMS::LiveCellRef<ESM::Weapon, MWWorld::RefData>* ref = ptr.get<ESM::Weapon>();
            newPtr = MWWorld::Ptr(ref, cell);
            cell->weapons.list.push_back( *ref );
        }
        else if (type == typeid(ESM::Miscellaneous).name())
        {
            ESMS::LiveCellRef<ESM::Miscellaneous, MWWorld::RefData>* ref = ptr.get<ESM::Miscellaneous>();
            newPtr = MWWorld::Ptr(ref, cell);
            cell->miscItems.list.push_back( *ref );
        }
        else
            throw std::runtime_error("Trying to insert object of unhandled type");

        newPtr.getRefData().setCount(ptr.getRefData().getCount());
        ptr.getRefData().setCount(0);
        newPtr.getRefData().enable();

        mRendering.addObject(newPtr);
        MWWorld::Class::get(newPtr).insertObject(newPtr, *mPhysics);
        MWWorld::Class::get(newPtr).enable(newPtr);

    }
The crash happens in the next frame update in RefData::getHandle(), because mBaseNode is apparently not set. But I can't imagine how that happens, because mRendering.addObject calls Class::insertObjectRendering which creates the scenenode and assigns it to the ptr's refdata?


By the way, here's a bug in refdata.cpp

Code: Select all

void RefData::enable()
    {
        mEnabled = true;
    }

    void RefData::disable()
    {
        mEnabled = true;
    }
User avatar
Zini
Posts: 5538
Joined: 06 Aug 2011, 15:16

Re: Inventory/Container GUI

Post by Zini »

Code: Select all

            ESMS::LiveCellRef<ESM::Potion, MWWorld::RefData>* ref = ptr.get<ESM::Potion>();
            newPtr = MWWorld::Ptr(ref, cell);
            cell->potions.list.push_back( *ref );
Still the same problem. You get the live cell ref from the object in the inventory and create a Ptr to it. Then you make a copy of this object and store it in the cell.
User avatar
scrawl
Posts: 2152
Joined: 18 Feb 2012, 11:51

Re: Inventory/Container GUI

Post by scrawl »

this stuff is really confusing :roll: is it better like this?

Code: Select all

            ESMS::LiveCellRef<ESM::Miscellaneous, MWWorld::RefData>* ref = ptr.get<ESM::Miscellaneous>();
            cell->miscItems.list.push_back( *ref );
            newPtr = MWWorld::Ptr(&cell->miscItems.list.back(), cell);
User avatar
Zini
Posts: 5538
Joined: 06 Aug 2011, 15:16

Re: Inventory/Container GUI

Post by Zini »

It looks correct.
User avatar
scrawl
Posts: 2152
Joined: 18 Feb 2012, 11:51

Re: Inventory/Container GUI

Post by scrawl »

Good, it works too. Now I have still a crash when dropping gold, because I'm trying to set the correct mesh based on how much gold was dropped (In MW, for example when you drop more than 100 gold, it uses a the "Gold_100" mesh to show a little "pile" of gold). Here's the code:

Code: Select all

        // if this is gold, we need to fetch the correct mesh depending on the amount of gold.
        if (MWWorld::Class::get(object).getName(object) == getStore().gameSettings.search("sGold")->str)
        {
            int goldAmount = object.getRefData().getCount();

            std::string base = "Gold_001";
            if (goldAmount >= 5)
                base = "Gold_005";
            else if (goldAmount >= 10)
                base = "Gold_010";
            else if (goldAmount >= 25)
                base = "Gold_025";
            else if (goldAmount >= 100)
                base = "Gold_100";

            std::cout << "using " << base << std::endl;
            MWWorld::ManualRef newRef (getStore(), base);
            object = newRef.getPtr();
            object.getRefData().setCount(goldAmount);
            object.mCell = cell;
        }

  ...

        mWorldScene->insertObject(object, cell);
the crash happens in the miscItems.push_back call, any idea? Is it correct to create the ManualRef like I did?

On a side note, the use/equip item code is now unified (like you suggested). Scripts are not done though.
Chris
Posts: 1626
Joined: 04 Sep 2011, 08:33

Re: Inventory/Container GUI

Post by Chris »

scrawl wrote:

Code: Select all

std::string base = "Gold_001";
            if (goldAmount >= 5)
                base = "Gold_005";
            else if (goldAmount >= 10)
                base = "Gold_010";
            else if (goldAmount >= 25)
                base = "Gold_025";
            else if (goldAmount >= 100)
                base = "Gold_100";
I don't know about the crash, but this is backwards. Any amount equal to or greater than 5 (including 50 or 1000) will succeed in the first check and use Gold_005.
Post Reply