diff -Nru openmw-0.29+git20140518.141/apps/esmtool/record.cpp openmw-0.29+git20140519.144/apps/esmtool/record.cpp --- openmw-0.29+git20140518.141/apps/esmtool/record.cpp 2014-05-18 11:17:04.000000000 +0000 +++ openmw-0.29+git20140519.144/apps/esmtool/record.cpp 2014-05-19 11:18:08.000000000 +0000 @@ -651,7 +651,7 @@ // Sadly, there are no DialInfos, because the loader dumps as it // loads, rather than loading and then dumping. :-( Anyone mind if // I change this? - std::vector::iterator iit; + ESM::Dialogue::InfoContainer::iterator iit; for (iit = mData.mInfo.begin(); iit != mData.mInfo.end(); iit++) std::cout << "INFO!" << iit->mId << std::endl; } diff -Nru openmw-0.29+git20140518.141/apps/openmw/mwbase/journal.hpp openmw-0.29+git20140519.144/apps/openmw/mwbase/journal.hpp --- openmw-0.29+git20140518.141/apps/openmw/mwbase/journal.hpp 2014-05-18 11:17:04.000000000 +0000 +++ openmw-0.29+git20140519.144/apps/openmw/mwbase/journal.hpp 2014-05-19 11:18:08.000000000 +0000 @@ -37,7 +37,7 @@ typedef std::deque TEntryContainer; typedef TEntryContainer::const_iterator TEntryIter; - typedef std::map TQuestContainer; // topc, quest + typedef std::map TQuestContainer; // topic, quest typedef TQuestContainer::const_iterator TQuestIter; typedef std::map TTopicContainer; // topic-id, topic-content typedef TTopicContainer::const_iterator TTopicIter; diff -Nru openmw-0.29+git20140518.141/apps/openmw/mwclass/container.cpp openmw-0.29+git20140519.144/apps/openmw/mwclass/container.cpp --- openmw-0.29+git20140518.141/apps/openmw/mwclass/container.cpp 2014-05-18 11:17:04.000000000 +0000 +++ openmw-0.29+git20140519.144/apps/openmw/mwclass/container.cpp 2014-05-19 11:18:08.000000000 +0000 @@ -70,6 +70,14 @@ } } + void Container::restock(const MWWorld::Ptr& ptr) const + { + MWWorld::LiveCellRef *ref = ptr.get(); + const ESM::InventoryList& list = ref->mBase->mInventory; + MWWorld::ContainerStore& store = getContainerStore(ptr); + store.restock(list, ptr, ptr.getCellRef().mOwner, ptr.getCellRef().mFaction); + } + void Container::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const { const std::string model = getModel(ptr); diff -Nru openmw-0.29+git20140518.141/apps/openmw/mwclass/container.hpp openmw-0.29+git20140519.144/apps/openmw/mwclass/container.hpp --- openmw-0.29+git20140518.141/apps/openmw/mwclass/container.hpp 2014-05-18 11:17:04.000000000 +0000 +++ openmw-0.29+git20140519.144/apps/openmw/mwclass/container.hpp 2014-05-19 11:18:08.000000000 +0000 @@ -66,6 +66,8 @@ virtual void respawn (const MWWorld::Ptr& ptr) const; + virtual void restock (const MWWorld::Ptr &ptr) const; + virtual std::string getModel(const MWWorld::Ptr &ptr) const; }; } diff -Nru openmw-0.29+git20140518.141/apps/openmw/mwclass/creature.cpp openmw-0.29+git20140519.144/apps/openmw/mwclass/creature.cpp --- openmw-0.29+git20140518.141/apps/openmw/mwclass/creature.cpp 2014-05-18 11:17:04.000000000 +0000 +++ openmw-0.29+git20140519.144/apps/openmw/mwclass/creature.cpp 2014-05-19 11:18:08.000000000 +0000 @@ -123,9 +123,6 @@ else data->mContainerStore = new MWWorld::ContainerStore(); - // Relates to NPC gold reset delay - data->mCreatureStats.setTradeTime(MWWorld::TimeStamp(0.0, 0)); - data->mCreatureStats.setGoldPool(ref->mBase->mData.mGold); // store @@ -842,6 +839,14 @@ } } + void Creature::restock(const MWWorld::Ptr& ptr) const + { + MWWorld::LiveCellRef *ref = ptr.get(); + const ESM::InventoryList& list = ref->mBase->mInventory; + MWWorld::ContainerStore& store = getContainerStore(ptr); + store.restock(list, ptr, ptr.getCellRef().mRefID, ptr.getCellRef().mFaction); + } + const ESM::GameSetting* Creature::fMinWalkSpeedCreature; const ESM::GameSetting* Creature::fMaxWalkSpeedCreature; const ESM::GameSetting *Creature::fEncumberedMoveEffect; diff -Nru openmw-0.29+git20140518.141/apps/openmw/mwclass/creature.hpp openmw-0.29+git20140519.144/apps/openmw/mwclass/creature.hpp --- openmw-0.29+git20140518.141/apps/openmw/mwclass/creature.hpp 2014-05-18 11:17:04.000000000 +0000 +++ openmw-0.29+git20140519.144/apps/openmw/mwclass/creature.hpp 2014-05-19 11:18:08.000000000 +0000 @@ -145,6 +145,8 @@ virtual int getBaseGold(const MWWorld::Ptr& ptr) const; virtual void respawn (const MWWorld::Ptr& ptr) const; + + virtual void restock (const MWWorld::Ptr &ptr) const; }; } diff -Nru openmw-0.29+git20140518.141/apps/openmw/mwclass/npc.cpp openmw-0.29+git20140519.144/apps/openmw/mwclass/npc.cpp --- openmw-0.29+git20140518.141/apps/openmw/mwclass/npc.cpp 2014-05-18 11:17:04.000000000 +0000 +++ openmw-0.29+git20140519.144/apps/openmw/mwclass/npc.cpp 2014-05-19 11:18:08.000000000 +0000 @@ -1330,6 +1330,14 @@ } } + void Npc::restock(const MWWorld::Ptr& ptr) const + { + MWWorld::LiveCellRef *ref = ptr.get(); + const ESM::InventoryList& list = ref->mBase->mInventory; + MWWorld::ContainerStore& store = getContainerStore(ptr); + store.restock(list, ptr, ptr.getCellRef().mRefID, ptr.getCellRef().mFaction); + } + const ESM::GameSetting *Npc::fMinWalkSpeed; const ESM::GameSetting *Npc::fMaxWalkSpeed; const ESM::GameSetting *Npc::fEncumberedMoveEffect; diff -Nru openmw-0.29+git20140518.141/apps/openmw/mwclass/npc.hpp openmw-0.29+git20140519.144/apps/openmw/mwclass/npc.hpp --- openmw-0.29+git20140518.141/apps/openmw/mwclass/npc.hpp 2014-05-18 11:17:04.000000000 +0000 +++ openmw-0.29+git20140519.144/apps/openmw/mwclass/npc.hpp 2014-05-19 11:18:08.000000000 +0000 @@ -180,6 +180,8 @@ } virtual void respawn (const MWWorld::Ptr& ptr) const; + + virtual void restock (const MWWorld::Ptr& ptr) const; }; } diff -Nru openmw-0.29+git20140518.141/apps/openmw/mwdialogue/dialoguemanagerimp.cpp openmw-0.29+git20140519.144/apps/openmw/mwdialogue/dialoguemanagerimp.cpp --- openmw-0.29+git20140518.141/apps/openmw/mwdialogue/dialoguemanagerimp.cpp 2014-05-18 11:17:04.000000000 +0000 +++ openmw-0.29+git20140519.144/apps/openmw/mwdialogue/dialoguemanagerimp.cpp 2014-05-19 11:18:08.000000000 +0000 @@ -286,7 +286,18 @@ MWScript::InterpreterContext interpreterContext(&mActor.getRefData().getLocals(),mActor); win->addResponse (Interpreter::fixDefinesDialog(info->mResponse, interpreterContext), title); - MWBase::Environment::get().getJournal()->addTopic (topic, info->mId, mActor.getClass().getName(mActor)); + + // Make sure the returned DialInfo is from the Dialogue we supplied. If could also be from the Info refusal group, + // in which case it should not be added to the journal. + for (ESM::Dialogue::InfoContainer::const_iterator iter = dialogue.mInfo.begin(); + iter!=dialogue.mInfo.end(); ++iter) + { + if (iter->mId == info->mId) + { + MWBase::Environment::get().getJournal()->addTopic (topic, info->mId, mActor.getClass().getName(mActor)); + break; + } + } executeScript (info->mResultScript); @@ -453,7 +464,19 @@ MWScript::InterpreterContext interpreterContext(&mActor.getRefData().getLocals(),mActor); MWBase::Environment::get().getWindowManager()->getDialogueWindow()->addResponse (Interpreter::fixDefinesDialog(text, interpreterContext)); - MWBase::Environment::get().getJournal()->addTopic (mLastTopic, info->mId, mActor.getClass().getName(mActor)); + + // Make sure the returned DialInfo is from the Dialogue we supplied. If could also be from the Info refusal group, + // in which case it should not be added to the journal. + for (ESM::Dialogue::InfoContainer::const_iterator iter = mDialogueMap[mLastTopic].mInfo.begin(); + iter!=mDialogueMap[mLastTopic].mInfo.end(); ++iter) + { + if (iter->mId == info->mId) + { + MWBase::Environment::get().getJournal()->addTopic (mLastTopic, info->mId, mActor.getClass().getName(mActor)); + break; + } + } + executeScript (info->mResultScript); } } diff -Nru openmw-0.29+git20140518.141/apps/openmw/mwdialogue/filter.cpp openmw-0.29+git20140519.144/apps/openmw/mwdialogue/filter.cpp --- openmw-0.29+git20140518.141/apps/openmw/mwdialogue/filter.cpp 2014-05-18 11:17:04.000000000 +0000 +++ openmw-0.29+git20140519.144/apps/openmw/mwdialogue/filter.cpp 2014-05-19 11:18:08.000000000 +0000 @@ -621,7 +621,7 @@ bool infoRefusal = false; // Iterate over topic responses to find a matching one - for (std::vector::const_iterator iter = dialogue.mInfo.begin(); + for (ESM::Dialogue::InfoContainer::const_iterator iter = dialogue.mInfo.begin(); iter!=dialogue.mInfo.end(); ++iter) { if (testActor (*iter) && testPlayer (*iter) && testSelectStructs (*iter)) @@ -646,7 +646,7 @@ const ESM::Dialogue& infoRefusalDialogue = *dialogues.find ("Info Refusal"); - for (std::vector::const_iterator iter = infoRefusalDialogue.mInfo.begin(); + for (ESM::Dialogue::InfoContainer::const_iterator iter = infoRefusalDialogue.mInfo.begin(); iter!=infoRefusalDialogue.mInfo.end(); ++iter) if (testActor (*iter) && testPlayer (*iter) && testSelectStructs (*iter) && testDisposition(*iter, invertDisposition)) { infos.push_back(&*iter); @@ -660,7 +660,7 @@ bool MWDialogue::Filter::responseAvailable (const ESM::Dialogue& dialogue) const { - for (std::vector::const_iterator iter = dialogue.mInfo.begin(); + for (ESM::Dialogue::InfoContainer::const_iterator iter = dialogue.mInfo.begin(); iter!=dialogue.mInfo.end(); ++iter) { if (testActor (*iter) && testPlayer (*iter) && testSelectStructs (*iter)) diff -Nru openmw-0.29+git20140518.141/apps/openmw/mwdialogue/filter.hpp openmw-0.29+git20140519.144/apps/openmw/mwdialogue/filter.hpp --- openmw-0.29+git20140518.141/apps/openmw/mwdialogue/filter.hpp 2014-05-18 11:17:04.000000000 +0000 +++ openmw-0.29+git20140519.144/apps/openmw/mwdialogue/filter.hpp 2014-05-19 11:18:08.000000000 +0000 @@ -55,6 +55,7 @@ std::vector list (const ESM::Dialogue& dialogue, bool fallbackToInfoRefusal, bool searchAll, bool invertDisposition=false) const; + ///< \note If fallbackToInfoRefusal is used, the returned DialInfo might not be from the supplied ESM::Dialogue. const ESM::DialInfo* search (const ESM::Dialogue& dialogue, const bool fallbackToInfoRefusal) const; ///< Get a matching response for the requested dialogue. diff -Nru openmw-0.29+git20140518.141/apps/openmw/mwdialogue/journalentry.cpp openmw-0.29+git20140519.144/apps/openmw/mwdialogue/journalentry.cpp --- openmw-0.29+git20140518.141/apps/openmw/mwdialogue/journalentry.cpp 2014-05-18 11:17:04.000000000 +0000 +++ openmw-0.29+git20140519.144/apps/openmw/mwdialogue/journalentry.cpp 2014-05-19 11:18:08.000000000 +0000 @@ -20,7 +20,7 @@ const ESM::Dialogue *dialogue = MWBase::Environment::get().getWorld()->getStore().get().find (topic); - for (std::vector::const_iterator iter (dialogue->mInfo.begin()); + for (ESM::Dialogue::InfoContainer::const_iterator iter (dialogue->mInfo.begin()); iter!=dialogue->mInfo.end(); ++iter) if (iter->mId == mInfoId) { @@ -73,7 +73,7 @@ const ESM::Dialogue *dialogue = MWBase::Environment::get().getWorld()->getStore().get().find (topic); - for (std::vector::const_iterator iter (dialogue->mInfo.begin()); + for (ESM::Dialogue::InfoContainer::const_iterator iter (dialogue->mInfo.begin()); iter!=dialogue->mInfo.end(); ++iter) if (iter->mData.mDisposition==index) /// \todo cleanup info structure { diff -Nru openmw-0.29+git20140518.141/apps/openmw/mwdialogue/journalimp.cpp openmw-0.29+git20140519.144/apps/openmw/mwdialogue/journalimp.cpp --- openmw-0.29+git20140518.141/apps/openmw/mwdialogue/journalimp.cpp 2014-05-18 11:17:04.000000000 +0000 +++ openmw-0.29+git20140519.144/apps/openmw/mwdialogue/journalimp.cpp 2014-05-19 11:18:08.000000000 +0000 @@ -56,7 +56,7 @@ if (infoId.empty()) return true; - for (std::vector::const_iterator iter (dialogue->mInfo.begin()); + for (ESM::Dialogue::InfoContainer::const_iterator iter (dialogue->mInfo.begin()); iter!=dialogue->mInfo.end(); ++iter) if (iter->mId == infoId) return true; diff -Nru openmw-0.29+git20140518.141/apps/openmw/mwdialogue/quest.cpp openmw-0.29+git20140519.144/apps/openmw/mwdialogue/quest.cpp --- openmw-0.29+git20140518.141/apps/openmw/mwdialogue/quest.cpp 2014-05-18 11:17:04.000000000 +0000 +++ openmw-0.29+git20140519.144/apps/openmw/mwdialogue/quest.cpp 2014-05-19 11:18:08.000000000 +0000 @@ -27,7 +27,7 @@ const ESM::Dialogue *dialogue = MWBase::Environment::get().getWorld()->getStore().get().find (mTopic); - for (std::vector::const_iterator iter (dialogue->mInfo.begin()); + for (ESM::Dialogue::InfoContainer::const_iterator iter (dialogue->mInfo.begin()); iter!=dialogue->mInfo.end(); ++iter) if (iter->mQuestStatus==ESM::DialInfo::QS_Name) return iter->mResponse; @@ -45,8 +45,7 @@ const ESM::Dialogue *dialogue = MWBase::Environment::get().getWorld()->getStore().get().find (mTopic); - bool found=false; - for (std::vector::const_iterator iter (dialogue->mInfo.begin()); + for (ESM::Dialogue::InfoContainer::const_iterator iter (dialogue->mInfo.begin()); iter!=dialogue->mInfo.end(); ++iter) if (iter->mData.mDisposition==index && iter->mQuestStatus!=ESM::DialInfo::QS_Name) { @@ -54,15 +53,10 @@ mFinished = true; else if (iter->mQuestStatus==ESM::DialInfo::QS_Restart) mFinished = false; - - found = true; - // Don't return here. Quest status may actually be in a different info record, since we don't merge these (yet?) } - if (found) - mIndex = index; - else - throw std::runtime_error ("unknown journal index for topic " + mTopic); + // The index must be set even if no related journal entry was found + mIndex = index; } bool Quest::isFinished() const @@ -77,7 +71,7 @@ const ESM::Dialogue *dialogue = MWBase::Environment::get().getWorld()->getStore().get().find (entry.mTopic); - for (std::vector::const_iterator iter (dialogue->mInfo.begin()); + for (ESM::Dialogue::InfoContainer::const_iterator iter (dialogue->mInfo.begin()); iter!=dialogue->mInfo.end(); ++iter) if (iter->mId == entry.mInfoId) { diff -Nru openmw-0.29+git20140518.141/apps/openmw/mwgui/bookpage.cpp openmw-0.29+git20140519.144/apps/openmw/mwgui/bookpage.cpp --- openmw-0.29+git20140518.141/apps/openmw/mwgui/bookpage.cpp 2014-05-18 11:17:04.000000000 +0000 +++ openmw-0.29+git20140519.144/apps/openmw/mwgui/bookpage.cpp 2014-05-19 11:18:08.000000000 +0000 @@ -93,7 +93,10 @@ typedef std::vector
Sections; + // Holds "top" and "bottom" vertical coordinates in the source text. + // A page is basically a "window" into a portion of the source text, similar to a ScrollView. typedef std::pair Page; + typedef std::vector Pages; Pages mPages; @@ -374,6 +377,29 @@ else { //split section + int sectionHeightLeft = sectionHeight; + while (sectionHeightLeft > mPageHeight) + { + spaceLeft = mPageHeight - (curPageStop - curPageStart); + + // Adjust to the top of the first line that does not fit on the current page anymore + int splitPos = curPageStop; + for (Lines::iterator j = i->mLines.begin (); j != i->mLines.end (); ++j) + { + if (j->mRect.bottom > curPageStart + mPageHeight) + { + splitPos = j->mRect.top; + break; + } + } + + mBook->mPages.push_back (Page (curPageStart, splitPos)); + curPageStart = splitPos; + curPageStop = splitPos; + + sectionHeightLeft = (i->mRect.bottom - splitPos); + } + curPageStop = i->mRect.bottom; } } diff -Nru openmw-0.29+git20140518.141/apps/openmw/mwgui/list.cpp openmw-0.29+git20140519.144/apps/openmw/mwgui/list.cpp --- openmw-0.29+git20140518.141/apps/openmw/mwgui/list.cpp 2014-05-18 11:17:04.000000000 +0000 +++ openmw-0.29+git20140519.144/apps/openmw/mwgui/list.cpp 2014-05-19 11:18:08.000000000 +0000 @@ -26,7 +26,7 @@ if (mClient == 0) mClient = this; - mScrollView = mClient->createWidgetReal( + mScrollView = mClient->createWidgetReal( "MW_ScrollView", MyGUI::FloatCoord(0.0, 0.0, 1.0, 1.0), MyGUI::Align::Top | MyGUI::Align::Left | MyGUI::Align::Stretch, getName() + "_ScrollView"); } @@ -51,7 +51,7 @@ const int _scrollBarWidth = 20; // fetch this from skin? const int scrollBarWidth = scrollbarShown ? _scrollBarWidth : 0; const int spacing = 3; - size_t scrollbarPosition = mScrollView->getScrollPosition(); + size_t viewPosition = -mScrollView->getViewOffset().top; while (mScrollView->getChildCount()) { @@ -96,10 +96,10 @@ if (!scrollbarShown && mItemHeight > mClient->getSize().height) redraw(true); - size_t scrollbarRange = mScrollView->getScrollRange(); - if(scrollbarPosition > scrollbarRange) - scrollbarPosition = scrollbarRange; - mScrollView->setScrollPosition(scrollbarPosition); + size_t viewRange = mScrollView->getCanvasSize().height; + if(viewPosition > viewRange) + viewPosition = viewRange; + mScrollView->setViewOffset(MyGUI::IntPoint(0, -viewPosition)); } bool MWList::hasItem(const std::string& name) @@ -151,19 +151,5 @@ return mScrollView->findWidget (getName() + "_item_" + name); } - size_t MWScrollView::getScrollPosition() - { - return getVScroll()->getScrollPosition(); - } - - void MWScrollView::setScrollPosition(size_t position) - { - getVScroll()->setScrollPosition(position); - } - size_t MWScrollView::getScrollRange() - { - return getVScroll()->getScrollRange(); - } - } } diff -Nru openmw-0.29+git20140518.141/apps/openmw/mwgui/list.hpp openmw-0.29+git20140519.144/apps/openmw/mwgui/list.hpp --- openmw-0.29+git20140518.141/apps/openmw/mwgui/list.hpp 2014-05-18 11:17:04.000000000 +0000 +++ openmw-0.29+git20140519.144/apps/openmw/mwgui/list.hpp 2014-05-19 11:18:08.000000000 +0000 @@ -8,18 +8,6 @@ namespace Widgets { /** - * \brief a custom ScrollView which has access to scrollbar properties - */ - class MWScrollView : public MyGUI::ScrollView - { - MYGUI_RTTI_DERIVED(MWScrollView) - public: - size_t getScrollPosition(); - void setScrollPosition(size_t); - size_t getScrollRange(); - }; - - /** * \brief a very simple list widget that supports word-wrapping entries * \note if the width or height of the list changes, you must call adjustSize() method */ @@ -70,7 +58,7 @@ void onItemSelected(MyGUI::Widget* _sender); private: - MWGui::Widgets::MWScrollView* mScrollView; + MyGUI::ScrollView* mScrollView; MyGUI::Widget* mClient; std::vector mItems; diff -Nru openmw-0.29+git20140518.141/apps/openmw/mwgui/tradewindow.cpp openmw-0.29+git20140519.144/apps/openmw/mwgui/tradewindow.cpp --- openmw-0.29+git20140518.141/apps/openmw/mwgui/tradewindow.cpp 2014-05-18 11:17:04.000000000 +0000 +++ openmw-0.29+git20140519.144/apps/openmw/mwgui/tradewindow.cpp 2014-05-19 11:18:08.000000000 +0000 @@ -84,7 +84,7 @@ mCurrentBalance = 0; mCurrentMerchantOffer = 0; - checkTradeTime(); + restock(); std::vector itemSources; MWBase::Environment::get().getWorld()->getContainersOwnedBy(actor, itemSources); @@ -364,8 +364,6 @@ mPtr.getClass().getCreatureStats(mPtr).getGoldPool() - mCurrentBalance ); } - updateTradeTime(); - MWBase::Environment::get().getWindowManager()->getDialogueWindow()->addResponse( MWBase::Environment::get().getWorld()->getStore().get().find("sBarterDialog5")->getString()); @@ -475,30 +473,26 @@ return merchantGold; } - // Relates to NPC gold reset delay - void TradeWindow::checkTradeTime() + void TradeWindow::restock() { MWMechanics::CreatureStats &sellerStats = mPtr.getClass().getCreatureStats(mPtr); - double delay = boost::lexical_cast(MWBase::Environment::get().getWorld()->getStore().get().find("fBarterGoldResetDelay")->getInt()); + float delay = MWBase::Environment::get().getWorld()->getStore().get().find("fBarterGoldResetDelay")->getFloat(); - // if time stamp longer than gold reset delay, reset gold. - if (MWBase::Environment::get().getWorld()->getTimeStamp() >= sellerStats.getTradeTime() + delay) + if (MWBase::Environment::get().getWorld()->getTimeStamp() >= sellerStats.getLastRestockTime() + delay) { sellerStats.setGoldPool(mPtr.getClass().getBaseGold(mPtr)); - } - } - void TradeWindow::updateTradeTime() - { - MWWorld::ContainerStore store = mPtr.getClass().getContainerStore(mPtr); - MWMechanics::CreatureStats &sellerStats = mPtr.getClass().getCreatureStats(mPtr); - double delay = boost::lexical_cast(MWBase::Environment::get().getWorld()->getStore().get().find("fBarterGoldResetDelay")->getInt()); + mPtr.getClass().restock(mPtr); - // If trade timestamp is within reset delay don't set - if ( ! (MWBase::Environment::get().getWorld()->getTimeStamp() >= sellerStats.getTradeTime() && - MWBase::Environment::get().getWorld()->getTimeStamp() < sellerStats.getTradeTime() + delay) ) - { - sellerStats.setTradeTime(MWBase::Environment::get().getWorld()->getTimeStamp()); + // Also restock any containers owned by this merchant, which are also available to buy in the trade window + std::vector itemSources; + MWBase::Environment::get().getWorld()->getContainersOwnedBy(mPtr, itemSources); + for (std::vector::iterator it = itemSources.begin(); it != itemSources.end(); ++it) + { + it->getClass().restock(*it); + } + + sellerStats.setLastRestockTime(MWBase::Environment::get().getWorld()->getTimeStamp()); } } } diff -Nru openmw-0.29+git20140518.141/apps/openmw/mwgui/tradewindow.hpp openmw-0.29+git20140519.144/apps/openmw/mwgui/tradewindow.hpp --- openmw-0.29+git20140518.141/apps/openmw/mwgui/tradewindow.hpp 2014-05-18 11:17:04.000000000 +0000 +++ openmw-0.29+git20140519.144/apps/openmw/mwgui/tradewindow.hpp 2014-05-19 11:18:08.000000000 +0000 @@ -101,9 +101,7 @@ int getMerchantGold(); - // Relates to NPC gold reset delay - void checkTradeTime(); - void updateTradeTime(); + void restock(); }; } diff -Nru openmw-0.29+git20140518.141/apps/openmw/mwgui/windowmanagerimp.cpp openmw-0.29+git20140519.144/apps/openmw/mwgui/windowmanagerimp.cpp --- openmw-0.29+git20140518.141/apps/openmw/mwgui/windowmanagerimp.cpp 2014-05-18 11:17:04.000000000 +0000 +++ openmw-0.29+git20140519.144/apps/openmw/mwgui/windowmanagerimp.cpp 2014-05-19 11:18:08.000000000 +0000 @@ -158,7 +158,6 @@ MyGUI::FactoryManager::getInstance().registerFactory("Widget"); MyGUI::FactoryManager::getInstance().registerFactory("Widget"); MyGUI::FactoryManager::getInstance().registerFactory("Widget"); - MyGUI::FactoryManager::getInstance().registerFactory("Widget"); MyGUI::FactoryManager::getInstance().registerFactory("Widget"); MyGUI::FactoryManager::getInstance().registerFactory("Widget"); MyGUI::FactoryManager::getInstance().registerFactory("Widget"); diff -Nru openmw-0.29+git20140518.141/apps/openmw/mwmechanics/actors.cpp openmw-0.29+git20140519.144/apps/openmw/mwmechanics/actors.cpp --- openmw-0.29+git20140518.141/apps/openmw/mwmechanics/actors.cpp 2014-05-18 11:17:04.000000000 +0000 +++ openmw-0.29+git20140519.144/apps/openmw/mwmechanics/actors.cpp 2014-05-19 11:18:08.000000000 +0000 @@ -181,54 +181,65 @@ calculateDynamicStats (ptr); calculateCreatureStatModifiers (ptr, duration); + // fatigue restoration + calculateRestoration(ptr, duration, false); + } + + void Actors::engageCombat (const MWWorld::Ptr& actor1, const MWWorld::Ptr& actor2, bool againstPlayer) + { + CreatureStats& creatureStats = MWWorld::Class::get(actor1).getCreatureStats(actor1); + + if (againstPlayer && creatureStats.isHostile()) return; // already fighting against player + + float fight; - // AI - if(MWBase::Environment::get().getMechanicsManager()->isAIActive()) + if (againstPlayer) + fight = actor1.getClass().getCreatureStats(actor1).getAiSetting(CreatureStats::AI_Fight).getModified(); + else { - CreatureStats& creatureStats = MWWorld::Class::get(ptr).getCreatureStats(ptr); - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + fight = 0; + // if one of actors is creature then we should make a decision to start combat or not + // NOTE: function doesn't take into account combat between 2 creatures + if (!actor1.getClass().isNpc()) + { + // if creature is hostile then it is necessarily to start combat + if (creatureStats.isHostile()) fight = 100; + else fight = creatureStats.getAiSetting(CreatureStats::AI_Fight).getModified(); + } + } + + ESM::Position actor1Pos = actor1.getRefData().getPosition(); + ESM::Position actor2Pos = actor2.getRefData().getPosition(); + float d = Ogre::Vector3(actor1Pos.pos).distance(Ogre::Vector3(actor2Pos.pos)); - //engage combat or not? - if(ptr != player && !creatureStats.isHostile()) + if( (fight == 100 && d <= 5000) + || (fight >= 95 && d <= 3000) + || (fight >= 90 && d <= 2000) + || (fight >= 80 && d <= 1000)) + { + if (againstPlayer || actor2.getClass().getCreatureStats(actor2).getAiSequence().canAddTarget(actor2Pos, d)) { - ESM::Position playerpos = player.getRefData().getPosition(); - ESM::Position actorpos = ptr.getRefData().getPosition(); - float d = sqrt((actorpos.pos[0] - playerpos.pos[0])*(actorpos.pos[0] - playerpos.pos[0]) - +(actorpos.pos[1] - playerpos.pos[1])*(actorpos.pos[1] - playerpos.pos[1]) - +(actorpos.pos[2] - playerpos.pos[2])*(actorpos.pos[2] - playerpos.pos[2])); - float fight = ptr.getClass().getCreatureStats(ptr).getAiSetting(CreatureStats::AI_Fight).getModified(); - - if( (fight == 100 ) - || (fight >= 95 && d <= 3000) - || (fight >= 90 && d <= 2000) - || (fight >= 80 && d <= 1000) - ) - { - bool LOS = MWBase::Environment::get().getWorld()->getLOS(ptr,player) - && MWBase::Environment::get().getMechanicsManager()->awarenessCheck(player, ptr); + bool LOS = MWBase::Environment::get().getWorld()->getLOS(actor1, actor2); + + if (againstPlayer) LOS &= MWBase::Environment::get().getMechanicsManager()->awarenessCheck(actor2, actor1); - if (LOS) + if (LOS) + { + MWBase::Environment::get().getMechanicsManager()->startCombat(actor1, actor2); + if (!againstPlayer) // start combat between each other { - MWBase::Environment::get().getMechanicsManager()->startCombat(ptr, player); + MWBase::Environment::get().getMechanicsManager()->startCombat(actor2, actor1); } } } - updateCrimePersuit(ptr, duration); - creatureStats.getAiSequence().execute (ptr,duration); } - - // fatigue restoration - calculateRestoration(ptr, duration, false); } - void Actors::updateNpc (const MWWorld::Ptr& ptr, float duration, bool paused) + void Actors::updateNpc (const MWWorld::Ptr& ptr, float duration) { - if(!paused) - { - updateDrowning(ptr, duration); - calculateNpcStatModifiers(ptr); - updateEquippedLight(ptr, duration); - } + updateDrowning(ptr, duration); + calculateNpcStatModifiers(ptr); + updateEquippedLight(ptr, duration); } void Actors::adjustMagicEffects (const MWWorld::Ptr& creature) @@ -861,10 +872,24 @@ } } + static Ogre::Vector3 sBasePoint; + bool comparePtrDist (const MWWorld::Ptr& ptr1, const MWWorld::Ptr& ptr2) + { + return (sBasePoint.squaredDistance(Ogre::Vector3(ptr1.getRefData().getPosition().pos)) + < sBasePoint.squaredDistance(Ogre::Vector3(ptr2.getRefData().getPosition().pos))); + } + void Actors::update (float duration, bool paused) { if(!paused) { + std::list listGuards; // at the moment only guards certainly will fight with creatures + + static float timerUpdateAITargets = 0; + + // target lists get updated once every 1.0 sec + if (timerUpdateAITargets >= 1.0f) timerUpdateAITargets = 0; + // Reset data from previous frame for (PtrControllerMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter) { @@ -872,29 +897,63 @@ // Note, the new hit object for this frame may be set by CharacterController::update -> Animation::runAnimation // (below) iter->first.getClass().getCreatureStats(iter->first).setLastHitObject(std::string()); + + // add guards to list to later make them fight with creatures + if (timerUpdateAITargets == 0 && iter->first.getClass().isClass(iter->first, "Guard")) + listGuards.push_back(iter->first); } - // AI and magic effects update - for (PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter) + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + + listGuards.push_back(player); + + // AI and magic effects update + for(PtrControllerMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter) { if (!iter->first.getClass().getCreatureStats(iter->first).isDead()) { updateActor(iter->first, duration); - if (iter->first.getTypeName() == typeid(ESM::NPC).name()) - updateNpc(iter->first, duration, paused); + + if (MWBase::Environment::get().getMechanicsManager()->isAIActive()) + { + // make guards and creatures fight each other + if (timerUpdateAITargets == 0 && iter->first.getTypeName() == typeid(ESM::Creature).name() && !listGuards.empty()) + { + sBasePoint = Ogre::Vector3(iter->first.getRefData().getPosition().pos); + listGuards.sort(comparePtrDist); // try to engage combat starting from the nearest creature + + for (std::list::iterator it = listGuards.begin(); it != listGuards.end(); ++it) + { + engageCombat(iter->first, *it, false); + } + } + + if (iter->first != player) engageCombat(iter->first, player, true); + + if (iter->first.getClass().isNpc() && iter->first != player) + updateCrimePersuit(iter->first, duration); + + if (iter->first != player) + iter->first.getClass().getCreatureStats(iter->first).getAiSequence().execute(iter->first, duration); + } + + if(iter->first.getTypeName() == typeid(ESM::NPC).name()) + updateNpc(iter->first, duration); } } + timerUpdateAITargets += duration; + // Looping magic VFX update // Note: we need to do this before any of the animations are updated. // Reaching the text keys may trigger Hit / Spellcast (and as such, particles), // so updating VFX immediately after that would just remove the particle effects instantly. // There needs to be a magic effect update in between. - for (PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter) + for(PtrControllerMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter) iter->second->updateContinuousVfx(); // Animation/movement update - for (PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter) + for(PtrControllerMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter) { if (iter->first.getClass().getCreatureStats(iter->first).getMagicEffects().get( ESM::MagicEffect::Paralyze).mMagnitude > 0) @@ -903,7 +962,7 @@ } // Kill dead actors, update some variables - for (PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();iter++) + for(PtrControllerMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter) { const MWWorld::Class &cls = MWWorld::Class::get(iter->first); CreatureStats &stats = cls.getCreatureStats(iter->first); @@ -975,7 +1034,6 @@ } // if player is in sneak state see if anyone detects him - const MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); if (player.getClass().getCreatureStats(player).getMovementFlag(MWMechanics::CreatureStats::Flag_Sneak)) { const MWWorld::ESMStore& esmStore = MWBase::Environment::get().getWorld()->getStore(); @@ -1105,9 +1163,7 @@ if(!stats.isDead() && stats.getAiSequence().getTypeId() == AiPackage::TypeIdCombat) { MWMechanics::AiCombat* package = static_cast(stats.getAiSequence().getActivePackage()); - // TODO: This is wrong! It's comparing Ref IDs with Ogre handles. The only case where this (coincidentally) works is the player. - // possibly applies to other code using getTargetId. - if(package->getTargetId() == actor.getCellRef().mRefID) + if(package->getTarget() == actor) list.push_front(*iter); } } diff -Nru openmw-0.29+git20140518.141/apps/openmw/mwmechanics/actors.hpp openmw-0.29+git20140519.144/apps/openmw/mwmechanics/actors.hpp --- openmw-0.29+git20140518.141/apps/openmw/mwmechanics/actors.hpp 2014-05-18 11:17:04.000000000 +0000 +++ openmw-0.29+git20140519.144/apps/openmw/mwmechanics/actors.hpp 2014-05-19 11:18:08.000000000 +0000 @@ -27,7 +27,7 @@ { std::map mDeathCount; - void updateNpc(const MWWorld::Ptr &ptr, float duration, bool paused); + void updateNpc(const MWWorld::Ptr &ptr, float duration); void adjustMagicEffects (const MWWorld::Ptr& creature); @@ -81,6 +81,12 @@ ///< This function is normally called automatically during the update process, but it can /// also be called explicitly at any time to force an update. + /** Start combat between two actors + @Notes: If againstPlayer = true then actor2 should be the Player. + If one of the combatants is creature it should be actor1. + */ + void engageCombat(const MWWorld::Ptr& actor1, const MWWorld::Ptr& actor2, bool againstPlayer); + void restoreDynamicStats(bool sleep); ///< If the player is sleeping, this should be called every hour. diff -Nru openmw-0.29+git20140518.141/apps/openmw/mwmechanics/aicombat.cpp openmw-0.29+git20140519.144/apps/openmw/mwmechanics/aicombat.cpp --- openmw-0.29+git20140518.141/apps/openmw/mwmechanics/aicombat.cpp 2014-05-18 11:17:04.000000000 +0000 +++ openmw-0.29+git20140519.144/apps/openmw/mwmechanics/aicombat.cpp 2014-05-19 11:18:08.000000000 +0000 @@ -149,9 +149,7 @@ bool AiCombat::execute (const MWWorld::Ptr& actor,float duration) { //General description - if(!actor.getClass().getCreatureStats(actor).isHostile() - || actor.getClass().getCreatureStats(actor).getHealth().getCurrent() <= 0) - return true; + if(actor.getClass().getCreatureStats(actor).isDead()) return true; MWWorld::Ptr target = MWBase::Environment::get().getWorld()->searchPtrViaActorId(mTargetActorId); @@ -629,12 +627,9 @@ return 1; } - std::string AiCombat::getTargetId() const + MWWorld::Ptr AiCombat::getTarget() const { - MWWorld::Ptr target = MWBase::Environment::get().getWorld()->searchPtrViaActorId(mTargetActorId); - if (target.isEmpty()) - return ""; - return target.getRefData().getHandle(); + return MWBase::Environment::get().getWorld()->searchPtrViaActorId(mTargetActorId); } diff -Nru openmw-0.29+git20140518.141/apps/openmw/mwmechanics/aicombat.hpp openmw-0.29+git20140519.144/apps/openmw/mwmechanics/aicombat.hpp --- openmw-0.29+git20140518.141/apps/openmw/mwmechanics/aicombat.hpp 2014-05-18 11:17:04.000000000 +0000 +++ openmw-0.29+git20140519.144/apps/openmw/mwmechanics/aicombat.hpp 2014-05-19 11:18:08.000000000 +0000 @@ -31,7 +31,7 @@ virtual unsigned int getPriority() const; ///Returns target ID - std::string getTargetId() const; + MWWorld::Ptr getTarget() const; private: PathFinder mPathFinder; diff -Nru openmw-0.29+git20140518.141/apps/openmw/mwmechanics/aipursue.cpp openmw-0.29+git20140519.144/apps/openmw/mwmechanics/aipursue.cpp --- openmw-0.29+git20140518.141/apps/openmw/mwmechanics/aipursue.cpp 2014-05-18 11:17:04.000000000 +0000 +++ openmw-0.29+git20140519.144/apps/openmw/mwmechanics/aipursue.cpp 2014-05-19 11:18:08.000000000 +0000 @@ -1,6 +1,5 @@ #include "aipursue.hpp" -#include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" #include "../mwworld/class.hpp" @@ -9,26 +8,27 @@ #include "../mwmechanics/creaturestats.hpp" -#include "steering.hpp" #include "movement.hpp" #include "creaturestats.hpp" -MWMechanics::AiPursue::AiPursue(const MWWorld::Ptr& actor) - : mActorId(actor.getClass().getCreatureStats(actor).getActorId()) +namespace MWMechanics +{ + +AiPursue::AiPursue(const MWWorld::Ptr& actor) + : mTargetActorId(actor.getClass().getCreatureStats(actor).getActorId()) { } -MWMechanics::AiPursue *MWMechanics::AiPursue::clone() const +AiPursue *MWMechanics::AiPursue::clone() const { return new AiPursue(*this); } -bool MWMechanics::AiPursue::execute (const MWWorld::Ptr& actor, float duration) +bool AiPursue::execute (const MWWorld::Ptr& actor, float duration) { - ESM::Position pos = actor.getRefData().getPosition(); //position of the actor - const MWWorld::Ptr target = MWBase::Environment::get().getWorld()->searchPtrViaActorId(mActorId); //The target to follow + const MWWorld::Ptr target = MWBase::Environment::get().getWorld()->searchPtrViaActorId(mTargetActorId); //The target to follow if(target == MWWorld::Ptr()) - return true; //Target doesn't exist + return true; //Target doesn't exist //Set the target desition from the actor ESM::Pathgrid::Point dest = target.getRefData().getPosition().pos; @@ -47,7 +47,14 @@ return false; } -int MWMechanics::AiPursue::getTypeId() const +int AiPursue::getTypeId() const { return TypeIdPursue; } + +MWWorld::Ptr AiPursue::getTarget() const +{ + return MWBase::Environment::get().getWorld()->searchPtrViaActorId(mTargetActorId); +} + +} // namespace MWMechanics diff -Nru openmw-0.29+git20140518.141/apps/openmw/mwmechanics/aipursue.hpp openmw-0.29+git20140519.144/apps/openmw/mwmechanics/aipursue.hpp --- openmw-0.29+git20140518.141/apps/openmw/mwmechanics/aipursue.hpp 2014-05-18 11:17:04.000000000 +0000 +++ openmw-0.29+git20140519.144/apps/openmw/mwmechanics/aipursue.hpp 2014-05-19 11:18:08.000000000 +0000 @@ -2,7 +2,8 @@ #define GAME_MWMECHANICS_AIPURSUE_H #include "aipackage.hpp" -#include + +#include "../mwbase/world.hpp" #include "pathfinding.hpp" @@ -18,12 +19,16 @@ ///Constructor /** \param actor Actor to pursue **/ AiPursue(const MWWorld::Ptr& actor); + virtual AiPursue *clone() const; virtual bool execute (const MWWorld::Ptr& actor,float duration); virtual int getTypeId() const; + MWWorld::Ptr getTarget() const; + private: - int mActorId; // The actor to pursue + + int mTargetActorId; // The actor to pursue int mCellX; int mCellY; }; diff -Nru openmw-0.29+git20140518.141/apps/openmw/mwmechanics/aisequence.cpp openmw-0.29+git20140519.144/apps/openmw/mwmechanics/aisequence.cpp --- openmw-0.29+git20140518.141/apps/openmw/mwmechanics/aisequence.cpp 2014-05-18 11:17:04.000000000 +0000 +++ openmw-0.29+git20140519.144/apps/openmw/mwmechanics/aisequence.cpp 2014-05-19 11:18:08.000000000 +0000 @@ -9,6 +9,7 @@ #include "aifollow.hpp" #include "aiactivate.hpp" #include "aicombat.hpp" +#include "aipursue.hpp" #include "../mwworld/class.hpp" #include "creaturestats.hpp" @@ -16,21 +17,24 @@ #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" -void MWMechanics::AiSequence::copy (const AiSequence& sequence) +namespace MWMechanics +{ + +void AiSequence::copy (const AiSequence& sequence) { for (std::list::const_iterator iter (sequence.mPackages.begin()); iter!=sequence.mPackages.end(); ++iter) mPackages.push_back ((*iter)->clone()); } -MWMechanics::AiSequence::AiSequence() : mDone (false), mLastAiPackage(-1) {} +AiSequence::AiSequence() : mDone (false), mLastAiPackage(-1) {} -MWMechanics::AiSequence::AiSequence (const AiSequence& sequence) : mDone (false) +AiSequence::AiSequence (const AiSequence& sequence) : mDone (false) { copy (sequence); } -MWMechanics::AiSequence& MWMechanics::AiSequence::operator= (const AiSequence& sequence) +AiSequence& AiSequence::operator= (const AiSequence& sequence) { if (this!=&sequence) { @@ -42,12 +46,12 @@ return *this; } -MWMechanics::AiSequence::~AiSequence() +AiSequence::~AiSequence() { clear(); } -int MWMechanics::AiSequence::getTypeId() const +int AiSequence::getTypeId() const { if (mPackages.empty()) return -1; @@ -55,16 +59,45 @@ return mPackages.front()->getTypeId(); } -bool MWMechanics::AiSequence::getCombatTarget(std::string &targetActorId) const +bool AiSequence::getCombatTarget(MWWorld::Ptr &targetActor) const { if (getTypeId() != AiPackage::TypeIdCombat) return false; const AiCombat *combat = static_cast(mPackages.front()); - targetActorId = combat->getTargetId(); + + targetActor = combat->getTarget(); + + return true; +} + +bool AiSequence::canAddTarget(const ESM::Position& actorPos, float distToTarget) const +{ + bool firstCombatFound = false; + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + + for(std::list::const_iterator it = mPackages.begin(); it != mPackages.end(); ++it) + { + if ((*it)->getTypeId() == AiPackage::TypeIdCombat) + { + firstCombatFound = true; + + const AiCombat *combat = static_cast(*it); + if (combat->getTarget() != player ) return false; // only 1 non-player target allowed + else + { + // add new target only if current target (player) is farther + ESM::Position &targetPos = combat->getTarget().getRefData().getPosition(); + + float distToCurrTarget = (Ogre::Vector3(targetPos.pos) - Ogre::Vector3(actorPos.pos)).length(); + return (distToCurrTarget > distToTarget); + } + } + else if (firstCombatFound) break; // assumes combat packages go one-by-one in packages list + } return true; } -void MWMechanics::AiSequence::stopCombat() +void AiSequence::stopCombat() { while (getTypeId() == AiPackage::TypeIdCombat) { @@ -73,7 +106,7 @@ } } -void MWMechanics::AiSequence::stopPursuit() +void AiSequence::stopPursuit() { while (getTypeId() == AiPackage::TypeIdPursue) { @@ -82,12 +115,12 @@ } } -bool MWMechanics::AiSequence::isPackageDone() const +bool AiSequence::isPackageDone() const { return mDone; } -void MWMechanics::AiSequence::execute (const MWWorld::Ptr& actor,float duration) +void AiSequence::execute (const MWWorld::Ptr& actor,float duration) { if(actor != MWBase::Environment::get().getWorld()->getPlayerPtr()) { @@ -95,6 +128,36 @@ { MWMechanics::AiPackage* package = mPackages.front(); mLastAiPackage = package->getTypeId(); + + // if active package is combat one, choose nearest target + if (mLastAiPackage == AiPackage::TypeIdCombat) + { + std::list::iterator itActualCombat; + + float nearestDist = std::numeric_limits::max(); + Ogre::Vector3 vActorPos = Ogre::Vector3(actor.getRefData().getPosition().pos); + + for(std::list::iterator it = mPackages.begin(); it != mPackages.end(); ++it) + { + if ((*it)->getTypeId() != AiPackage::TypeIdCombat) break; + + ESM::Position &targetPos = static_cast(*it)->getTarget().getRefData().getPosition(); + + float distTo = (Ogre::Vector3(targetPos.pos) - vActorPos).length(); + if (distTo < nearestDist) + { + nearestDist = distTo; + itActualCombat = it; + } + } + + if (mPackages.begin() != itActualCombat) + { + // move combat package with nearest target to the front + mPackages.splice(mPackages.begin(), mPackages, itActualCombat); + } + } + if (package->execute (actor,duration)) { // To account for the rare case where AiPackage::execute() queued another AI package @@ -113,7 +176,7 @@ } } -void MWMechanics::AiSequence::clear() +void AiSequence::clear() { for (std::list::const_iterator iter (mPackages.begin()); iter!=mPackages.end(); ++iter) delete *iter; @@ -121,14 +184,19 @@ mPackages.clear(); } -void MWMechanics::AiSequence::stack (const AiPackage& package, const MWWorld::Ptr& actor) +void AiSequence::stack (const AiPackage& package, const MWWorld::Ptr& actor) { if (package.getTypeId() == AiPackage::TypeIdCombat || package.getTypeId() == AiPackage::TypeIdPursue) { // Notify AiWander of our current position so we can return to it after combat finished for (std::list::const_iterator iter (mPackages.begin()); iter!=mPackages.end(); ++iter) { - if ((*iter)->getTypeId() == AiPackage::TypeIdWander) + if((*iter)->getTypeId() == AiPackage::TypeIdPursue && package.getTypeId() == AiPackage::TypeIdPursue + && static_cast(*iter)->getTarget() == static_cast(&package)->getTarget()) + { + return; // target is already pursued + } + else if ((*iter)->getTypeId() == AiPackage::TypeIdWander) static_cast(*iter)->setReturnPosition(Ogre::Vector3(actor.getRefData().getPosition().pos)); } } @@ -146,12 +214,12 @@ mPackages.push_front (package.clone()); } -void MWMechanics::AiSequence::queue (const AiPackage& package) +void AiSequence::queue (const AiPackage& package) { mPackages.push_back (package.clone()); } -MWMechanics::AiPackage* MWMechanics::AiSequence::getActivePackage() +AiPackage* MWMechanics::AiSequence::getActivePackage() { if(mPackages.empty()) throw std::runtime_error(std::string("No AI Package!")); @@ -159,7 +227,7 @@ return mPackages.front(); } -void MWMechanics::AiSequence::fill(const ESM::AIPackageList &list) +void AiSequence::fill(const ESM::AIPackageList &list) { for (std::vector::const_iterator it = list.mList.begin(); it != list.mList.end(); ++it) { @@ -195,3 +263,5 @@ mPackages.push_back(package); } } + +} // namespace MWMechanics diff -Nru openmw-0.29+git20140518.141/apps/openmw/mwmechanics/aisequence.hpp openmw-0.29+git20140519.144/apps/openmw/mwmechanics/aisequence.hpp --- openmw-0.29+git20140518.141/apps/openmw/mwmechanics/aisequence.hpp 2014-05-18 11:17:04.000000000 +0000 +++ openmw-0.29+git20140519.144/apps/openmw/mwmechanics/aisequence.hpp 2014-05-19 11:18:08.000000000 +0000 @@ -53,7 +53,10 @@ int getLastRunTypeId() const { return mLastAiPackage; } /// Return true and assign target if combat package is currently active, return false otherwise - bool getCombatTarget (std::string &targetActorId) const; + bool getCombatTarget (MWWorld::Ptr &targetActor) const; + + bool canAddTarget(const ESM::Position& actorPos, float distToTarget) const; + ///< Function assumes that actor can have only 1 target apart player /// Removes all combat packages until first non-combat or stack empty. void stopCombat(); diff -Nru openmw-0.29+git20140518.141/apps/openmw/mwmechanics/character.cpp openmw-0.29+git20140519.144/apps/openmw/mwmechanics/character.cpp --- openmw-0.29+git20140518.141/apps/openmw/mwmechanics/character.cpp 2014-05-18 11:17:04.000000000 +0000 +++ openmw-0.29+git20140519.144/apps/openmw/mwmechanics/character.cpp 2014-05-19 11:18:08.000000000 +0000 @@ -1012,7 +1012,16 @@ bool flying = world->isFlying(mPtr); //Ogre::Vector3 vec = cls.getMovementVector(mPtr); Ogre::Vector3 vec(cls.getMovementSettings(mPtr).mPosition); - vec.normalise(); + if(vec.z > 0.0f) // to avoid slow-down when jumping + { + Ogre::Vector2 vecXY = Ogre::Vector2(vec.x, vec.y); + vecXY.normalise(); + vec.x = vecXY.x; + vec.y = vecXY.y; + } + else + vec.normalise(); + if(mHitState != CharState_None && mJumpState == JumpState_None) vec = Ogre::Vector3(0.0f); Ogre::Vector3 rot = cls.getRotationVector(mPtr); @@ -1113,9 +1122,12 @@ if(cls.isNpc()) { const NpcStats &stats = cls.getNpcStats(mPtr); - mult = gmst.find("fJumpMoveBase")->getFloat() + + static const float fJumpMoveBase = gmst.find("fJumpMoveBase")->getFloat(); + static const float fJumpMoveMult = gmst.find("fJumpMoveMult")->getFloat(); + + mult = fJumpMoveBase + (stats.getSkill(ESM::Skill::Acrobatics).getModified()/100.0f * - gmst.find("fJumpMoveMult")->getFloat()); + fJumpMoveMult); } vec.x *= mult; @@ -1125,14 +1137,7 @@ else if(vec.z > 0.0f && mJumpState == JumpState_None) { // Started a jump. - float z = cls.getJump(mPtr); - if(vec.x == 0 && vec.y == 0) - vec = Ogre::Vector3(0.0f, 0.0f, z); - else - { - Ogre::Vector3 lat = Ogre::Vector3(vec.x, vec.y, 0.0f).normalisedCopy(); - vec = Ogre::Vector3(lat.x, lat.y, 1.0f) * z * 0.707f; - } + vec.z = cls.getJump(mPtr); // advance acrobatics if (mPtr.getRefData().getHandle() == "player") @@ -1444,14 +1449,14 @@ void CharacterController::determineAttackType() { - float * move = mPtr.getClass().getMovementSettings(mPtr).mPosition; + float *move = mPtr.getClass().getMovementSettings(mPtr).mPosition; if(mPtr.getClass().hasInventoryStore(mPtr)) { - if (move[0] && !move[1]) //sideway - mAttackType = "slash"; - else if (move[1]) //forward + if (move[1]) // forward-backward mAttackType = "thrust"; + else if (move[0]) //sideway + mAttackType = "slash"; else mAttackType = "chop"; } diff -Nru openmw-0.29+git20140518.141/apps/openmw/mwmechanics/creaturestats.cpp openmw-0.29+git20140519.144/apps/openmw/mwmechanics/creaturestats.cpp --- openmw-0.29+git20140518.141/apps/openmw/mwmechanics/creaturestats.cpp 2014-05-18 11:17:04.000000000 +0000 +++ openmw-0.29+git20140519.144/apps/openmw/mwmechanics/creaturestats.cpp 2014-05-19 11:18:08.000000000 +0000 @@ -22,7 +22,7 @@ mFallHeight(0), mRecalcDynamicStats(false), mKnockdown(false), mKnockdownOneFrame(false), mKnockdownOverOneFrame(false), mHitRecovery(false), mBlock(false), mMovementFlags(0), mDrawState (DrawState_Nothing), mAttackStrength(0.f), - mTradeTime(0,0), mGoldPool(0), mActorId(-1) + mLastRestock(0,0), mGoldPool(0), mActorId(-1) { for (int i=0; i<4; ++i) mAiSettings[i] = 0; @@ -322,11 +322,9 @@ bool CreatureStats::getCreatureTargetted() const { - std::string target; - if (mAiSequence.getCombatTarget(target)) + MWWorld::Ptr targetPtr; + if (mAiSequence.getCombatTarget(targetPtr)) { - MWWorld::Ptr targetPtr; - targetPtr = MWBase::Environment::get().getWorld()->getPtr(target, true); return targetPtr.getTypeName() == typeid(ESM::Creature).name(); } return false; @@ -477,7 +475,7 @@ for (int i=0; i<3; ++i) mDynamic[i].writeState (state.mDynamic[i]); - state.mTradeTime = mTradeTime.toEsm(); + state.mTradeTime = mLastRestock.toEsm(); state.mGoldPool = mGoldPool; state.mDead = mDead; @@ -515,7 +513,7 @@ for (int i=0; i<3; ++i) mDynamic[i].readState (state.mDynamic[i]); - mTradeTime = MWWorld::TimeStamp(state.mTradeTime); + mLastRestock = MWWorld::TimeStamp(state.mTradeTime); mGoldPool = state.mGoldPool; mFallHeight = state.mFallHeight; @@ -546,15 +544,14 @@ mActiveSpells.readState(state.mActiveSpells); } - // Relates to NPC gold reset delay - void CreatureStats::setTradeTime(MWWorld::TimeStamp tradeTime) + void CreatureStats::setLastRestockTime(MWWorld::TimeStamp tradeTime) { - mTradeTime = tradeTime; + mLastRestock = tradeTime; } - MWWorld::TimeStamp CreatureStats::getTradeTime() const + MWWorld::TimeStamp CreatureStats::getLastRestockTime() const { - return mTradeTime; + return mLastRestock; } void CreatureStats::setGoldPool(int pool) diff -Nru openmw-0.29+git20140518.141/apps/openmw/mwmechanics/creaturestats.hpp openmw-0.29+git20140519.144/apps/openmw/mwmechanics/creaturestats.hpp --- openmw-0.29+git20140518.141/apps/openmw/mwmechanics/creaturestats.hpp 2014-05-18 11:17:04.000000000 +0000 +++ openmw-0.29+git20140519.144/apps/openmw/mwmechanics/creaturestats.hpp 2014-05-19 11:18:08.000000000 +0000 @@ -56,9 +56,12 @@ // Do we need to recalculate stats derived from attributes or other factors? bool mRecalcDynamicStats; - MWWorld::TimeStamp mTradeTime; // Relates to NPC gold reset delay + // For merchants: the last time items were restocked and gold pool refilled. + MWWorld::TimeStamp mLastRestock; + + // The pool of merchant gold (not in inventory) + int mGoldPool; - int mGoldPool; // the pool of merchant gold not in inventory int mActorId; protected: @@ -241,9 +244,8 @@ static void writeActorIdCounter (ESM::ESMWriter& esm); static void readActorIdCounter (ESM::ESMReader& esm); - // Relates to NPC gold reset delay - void setTradeTime(MWWorld::TimeStamp tradeTime); - MWWorld::TimeStamp getTradeTime() const; + void setLastRestockTime(MWWorld::TimeStamp tradeTime); + MWWorld::TimeStamp getLastRestockTime() const; void setGoldPool(int pool); int getGoldPool() const; diff -Nru openmw-0.29+git20140518.141/apps/openmw/mwmechanics/pathgrid.cpp openmw-0.29+git20140519.144/apps/openmw/mwmechanics/pathgrid.cpp --- openmw-0.29+git20140518.141/apps/openmw/mwmechanics/pathgrid.cpp 2014-05-18 11:17:04.000000000 +0000 +++ openmw-0.29+git20140519.144/apps/openmw/mwmechanics/pathgrid.cpp 2014-05-19 11:18:08.000000000 +0000 @@ -328,6 +328,12 @@ path.push_front(pt); current = graphParent[current]; } + + // add first node to path explicitly + ESM::Pathgrid::Point pt = mPathgrid->mPoints[start]; + pt.mX += xCell; + pt.mY += yCell; + path.push_front(pt); return path; } } diff -Nru openmw-0.29+git20140518.141/apps/openmw/mwscript/aiextensions.cpp openmw-0.29+git20140519.144/apps/openmw/mwscript/aiextensions.cpp --- openmw-0.29+git20140518.141/apps/openmw/mwscript/aiextensions.cpp 2014-05-18 11:17:04.000000000 +0000 +++ openmw-0.29+git20140519.144/apps/openmw/mwscript/aiextensions.cpp 2014-05-19 11:18:08.000000000 +0000 @@ -415,9 +415,10 @@ std::string currentTargetId; bool targetsAreEqual = false; - if (creatureStats.getAiSequence().getCombatTarget (currentTargetId)) + MWWorld::Ptr targetPtr; + if (creatureStats.getAiSequence().getCombatTarget (targetPtr)) { - if (currentTargetId == testedTargetId) + if (targetPtr.getRefData().getHandle() == testedTargetId) targetsAreEqual = true; } runtime.push(int(targetsAreEqual)); diff -Nru openmw-0.29+git20140518.141/apps/openmw/mwworld/class.hpp openmw-0.29+git20140519.144/apps/openmw/mwworld/class.hpp --- openmw-0.29+git20140518.141/apps/openmw/mwworld/class.hpp 2014-05-18 11:17:04.000000000 +0000 +++ openmw-0.29+git20140519.144/apps/openmw/mwworld/class.hpp 2014-05-19 11:18:08.000000000 +0000 @@ -343,6 +343,8 @@ virtual void setDoorState (const MWWorld::Ptr &ptr, int state) const; virtual void respawn (const MWWorld::Ptr& ptr) const {} + + virtual void restock (const MWWorld::Ptr& ptr) const {} }; } diff -Nru openmw-0.29+git20140518.141/apps/openmw/mwworld/containerstore.cpp openmw-0.29+git20140519.144/apps/openmw/mwworld/containerstore.cpp --- openmw-0.29+git20140518.141/apps/openmw/mwworld/containerstore.cpp 2014-05-18 11:17:04.000000000 +0000 +++ openmw-0.29+git20140519.144/apps/openmw/mwworld/containerstore.cpp 2014-05-19 11:18:08.000000000 +0000 @@ -366,7 +366,7 @@ for (std::vector::const_iterator iter (items.mList.begin()); iter!=items.mList.end(); ++iter) { - std::string id = iter->mItem.toString(); + std::string id = Misc::StringUtils::lowerCase(iter->mItem.toString()); addInitialItem(id, owner, faction, iter->mCount); } @@ -374,20 +374,18 @@ } void MWWorld::ContainerStore::addInitialItem (const std::string& id, const std::string& owner, const std::string& faction, - int count, bool topLevel) + int count, bool topLevel, const std::string& levItem) { - count = std::abs(count); /// \todo implement item restocking (indicated by negative count) - ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), id, count); if (ref.getPtr().getTypeName()==typeid (ESM::ItemLevList).name()) { const ESM::ItemLevList* levItem = ref.getPtr().get()->mBase; - if (topLevel && count > 1 && levItem->mFlags & ESM::ItemLevList::Each) + if (topLevel && std::abs(count) > 1 && levItem->mFlags & ESM::ItemLevList::Each) { - for (int i=0; i 0 ? 1 : -1, true, levItem->mId); return; } else @@ -395,17 +393,58 @@ std::string id = MWMechanics::getLevelledItem(ref.getPtr().get()->mBase, false); if (id.empty()) return; - addInitialItem(id, owner, faction, count, false); + addInitialItem(id, owner, faction, count, false, levItem->mId); } } else { + // A negative count indicates restocking items + // For a restocking levelled item, remember what we spawned so we can delete it later when the merchant restocks + if (!levItem.empty() && count < 0) + { + if (mLevelledItemMap.find(id) == mLevelledItemMap.end()) + mLevelledItemMap[id] = 0; + mLevelledItemMap[id] += std::abs(count); + } + count = std::abs(count); + ref.getPtr().getCellRef().mOwner = owner; ref.getPtr().getCellRef().mFaction = faction; addImp (ref.getPtr(), count); } } +void MWWorld::ContainerStore::restock (const ESM::InventoryList& items, const MWWorld::Ptr& ptr, const std::string& owner, const std::string& faction) +{ + // Remove the items already spawned by levelled items that will restock + for (std::map::iterator it = mLevelledItemMap.begin(); it != mLevelledItemMap.end(); ++it) + { + if (count(it->first) >= it->second) + remove(it->first, it->second, ptr); + } + mLevelledItemMap.clear(); + + for (std::vector::const_iterator it = items.mList.begin(); it != items.mList.end(); ++it) + { + if (it->mCount >= 0) + continue; + + std::string item = Misc::StringUtils::lowerCase(it->mItem.toString()); + + if (MWBase::Environment::get().getWorld()->getStore().get().search(it->mItem.toString())) + { + addInitialItem(item, owner, faction, it->mCount, true); + } + else + { + int currentCount = count(item); + if (currentCount < std::abs(it->mCount)) + add (item, std::abs(it->mCount) - currentCount, ptr); + } + } + flagAsModified(); +} + void MWWorld::ContainerStore::clear() { for (ContainerStoreIterator iter (begin()); iter!=end(); ++iter) @@ -584,6 +623,8 @@ state.mLights.clear(); + state.mLevelledItemMap = mLevelledItemMap; + for (MWWorld::CellRefList::List::const_iterator iter (lights.mList.begin()); iter!=lights.mList.end(); ++iter) { @@ -627,6 +668,8 @@ { getState (lights, iter->first); } + + mLevelledItemMap = state.mLevelledItemMap; } diff -Nru openmw-0.29+git20140518.141/apps/openmw/mwworld/containerstore.hpp openmw-0.29+git20140519.144/apps/openmw/mwworld/containerstore.hpp --- openmw-0.29+git20140518.141/apps/openmw/mwworld/containerstore.hpp 2014-05-18 11:17:04.000000000 +0000 +++ openmw-0.29+git20140519.144/apps/openmw/mwworld/containerstore.hpp 2014-05-19 11:18:08.000000000 +0000 @@ -2,6 +2,7 @@ #define GAME_MWWORLD_CONTAINERSTORE_H #include +#include #include #include @@ -65,10 +66,15 @@ MWWorld::CellRefList probes; MWWorld::CellRefList repairs; MWWorld::CellRefList weapons; + + std::map mLevelledItemMap; + ///< Stores result of levelled item spawns. + /// This is used to remove the spawned item(s) if the levelled item is restocked. + mutable float mCachedWeight; mutable bool mWeightUpToDate; ContainerStoreIterator addImp (const Ptr& ptr, int count); - void addInitialItem (const std::string& id, const std::string& owner, const std::string& faction, int count, bool topLevel=true); + void addInitialItem (const std::string& id, const std::string& owner, const std::string& faction, int count, bool topLevel=true, const std::string& levItem = ""); template ContainerStoreIterator getState (CellRefList& collection, @@ -145,6 +151,8 @@ void fill (const ESM::InventoryList& items, const std::string& owner, const std::string& faction, const MWWorld::ESMStore& store); ///< Insert items into *this. + void restock (const ESM::InventoryList& items, const MWWorld::Ptr& ptr, const std::string& owner, const std::string& faction); + virtual void clear(); ///< Empty container. diff -Nru openmw-0.29+git20140518.141/apps/openmw/mwworld/esmstore.cpp openmw-0.29+git20140519.144/apps/openmw/mwworld/esmstore.cpp --- openmw-0.29+git20140518.141/apps/openmw/mwworld/esmstore.cpp 2014-05-18 11:17:04.000000000 +0000 +++ openmw-0.29+git20140519.144/apps/openmw/mwworld/esmstore.cpp 2014-05-19 11:18:08.000000000 +0000 @@ -27,8 +27,6 @@ { listener->setProgressRange(1000); - std::set missing; - ESM::Dialogue *dialogue = 0; /// \todo Move this to somewhere else. ESMReader? @@ -72,9 +70,10 @@ 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); + ESM::DialInfo info; + info.mId = id; + info.load(esm); + dialogue->addInfo(info, esm.getIndex() != 0); } else { std::cerr << "error: info record without dialog" << std::endl; esm.skipRecord(); @@ -84,9 +83,9 @@ } 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()); + std::stringstream error; + error << "Unknown record: " << n.toString(); + throw std::runtime_error(error.str()); } } else { // Load it @@ -113,19 +112,6 @@ } 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::iterator it = missing.begin(); - it != missing.end(); it++ ) - cout << *it << " "; - cout << endl; - */ } void ESMStore::setUp() diff -Nru openmw-0.29+git20140518.141/apps/openmw/mwworld/physicssystem.cpp openmw-0.29+git20140519.144/apps/openmw/mwworld/physicssystem.cpp --- openmw-0.29+git20140518.141/apps/openmw/mwworld/physicssystem.cpp 2014-05-18 11:17:04.000000000 +0000 +++ openmw-0.29+git20140519.144/apps/openmw/mwworld/physicssystem.cpp 2014-05-19 11:18:08.000000000 +0000 @@ -242,6 +242,15 @@ // If falling, add part of the incoming velocity with the current inertia // TODO: but we could be jumping up? velocity = velocity * time + physicActor->getInertialForce(); + + // avoid getting infinite inertia in air + float actorSpeed = ptr.getClass().getSpeed(ptr); + float speedXY = Ogre::Vector2(velocity.x, velocity.y).length(); + if (speedXY > actorSpeed) + { + velocity.x *= actorSpeed / speedXY; + velocity.y *= actorSpeed / speedXY; + } } inertia = velocity; // NOTE: velocity is for z axis only in this code block diff -Nru openmw-0.29+git20140518.141/components/esm/inventorystate.cpp openmw-0.29+git20140519.144/components/esm/inventorystate.cpp --- openmw-0.29+git20140518.141/components/esm/inventorystate.cpp 2014-05-18 11:17:04.000000000 +0000 +++ openmw-0.29+git20140519.144/components/esm/inventorystate.cpp 2014-05-19 11:18:08.000000000 +0000 @@ -47,6 +47,14 @@ mItems.push_back (std::make_pair (state, std::make_pair (id, slot))); } } + + while (esm.isNextSub("LEVM")) + { + std::string id = esm.getHString(); + int count; + esm.getHNT (count, "COUN"); + mLevelledItemMap[id] = count; + } } void ESM::InventoryState::save (ESMWriter &esm) const @@ -57,4 +65,10 @@ for (std::vector >::const_iterator iter (mLights.begin()); iter!=mLights.end(); ++iter) write (esm, iter->first, ESM::REC_LIGH, iter->second); -} \ No newline at end of file + + for (std::map::const_iterator it = mLevelledItemMap.begin(); it != mLevelledItemMap.end(); ++it) + { + esm.writeHNString ("LEVM", it->first); + esm.writeHNT ("COUN", it->second); + } +} diff -Nru openmw-0.29+git20140518.141/components/esm/inventorystate.hpp openmw-0.29+git20140519.144/components/esm/inventorystate.hpp --- openmw-0.29+git20140518.141/components/esm/inventorystate.hpp 2014-05-18 11:17:04.000000000 +0000 +++ openmw-0.29+git20140519.144/components/esm/inventorystate.hpp 2014-05-19 11:18:08.000000000 +0000 @@ -1,6 +1,8 @@ #ifndef OPENMW_ESM_INVENTORYSTATE_H #define OPENMW_ESM_INVENTORYSTATE_H +#include + #include "objectstate.hpp" #include "lightstate.hpp" @@ -20,6 +22,8 @@ // lights (slot) std::vector > mLights; + std::map mLevelledItemMap; + virtual ~InventoryState() {} virtual void load (ESMReader &esm); diff -Nru openmw-0.29+git20140518.141/components/esm/loaddial.cpp openmw-0.29+git20140519.144/components/esm/loaddial.cpp --- openmw-0.29+git20140518.141/components/esm/loaddial.cpp 2014-05-18 11:17:04.000000000 +0000 +++ openmw-0.29+git20140519.144/components/esm/loaddial.cpp 2014-05-19 11:18:08.000000000 +0000 @@ -1,5 +1,7 @@ #include "loaddial.hpp" +#include + #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" @@ -43,4 +45,50 @@ mInfo.clear(); } +void Dialogue::addInfo(const ESM::DialInfo& info, bool merge) +{ + if (!merge || mInfo.empty() || info.mNext.empty()) + { + mLookup[info.mId] = mInfo.insert(mInfo.end(), info); + return; + } + if (info.mPrev.empty()) + { + mLookup[info.mId] = mInfo.insert(mInfo.begin(), info); + return; + } + + ESM::Dialogue::InfoContainer::iterator it = mInfo.end(); + + std::map::iterator lookup; + + lookup = mLookup.find(info.mId); + if (lookup != mLookup.end()) + { + it = lookup->second; + *it = info; + return; + } + + lookup = mLookup.find(info.mPrev); + if (lookup != mLookup.end()) + { + it = lookup->second; + + mLookup[info.mId] = mInfo.insert(++it, info); + return; + } + + lookup = mLookup.find(info.mNext); + if (lookup != mLookup.end()) + { + it = lookup->second; + + mLookup[info.mId] = mInfo.insert(it, info); + return; + } + + std::cerr << "Failed to insert info " << info.mId << std::endl; +} + } diff -Nru openmw-0.29+git20140518.141/components/esm/loaddial.hpp openmw-0.29+git20140519.144/components/esm/loaddial.hpp --- openmw-0.29+git20140518.141/components/esm/loaddial.hpp 2014-05-18 11:17:04.000000000 +0000 +++ openmw-0.29+git20140519.144/components/esm/loaddial.hpp 2014-05-19 11:18:08.000000000 +0000 @@ -2,7 +2,8 @@ #define OPENMW_ESM_DIAL_H #include -#include +#include +#include #include "loadinfo.hpp" @@ -33,11 +34,22 @@ std::string mId; signed char mType; - std::vector mInfo; + + typedef std::list InfoContainer; + + typedef std::map LookupMap; + + InfoContainer mInfo; + + // This is only used during the loading phase to speed up DialInfo merging. + LookupMap mLookup; void load(ESMReader &esm); void save(ESMWriter &esm) const; + /// @param merge Merge with existing list, or just push each record to the end of the list? + void addInfo (const ESM::DialInfo& info, bool merge); + void blank(); ///< Set record to default state (does not touch the ID and does not change the type). }; diff -Nru openmw-0.29+git20140518.141/debian/bzr-builder.manifest openmw-0.29+git20140519.144/debian/bzr-builder.manifest --- openmw-0.29+git20140518.141/debian/bzr-builder.manifest 2014-05-18 11:17:06.000000000 +0000 +++ openmw-0.29+git20140519.144/debian/bzr-builder.manifest 2014-05-19 11:18:09.000000000 +0000 @@ -1,2 +1,2 @@ -# bzr-builder format 0.3 deb-version 0.29+git20140518.141-0 -lp:openmw revid:showard@debian.org-20140518100003-qx71sz9cey542vxg +# bzr-builder format 0.3 deb-version 0.29+git20140519.144-0 +lp:openmw revid:showard@debian.org-20140518180004-nqnhodzp4al2rwwm diff -Nru openmw-0.29+git20140518.141/debian/changelog openmw-0.29+git20140519.144/debian/changelog --- openmw-0.29+git20140518.141/debian/changelog 2014-05-18 11:17:06.000000000 +0000 +++ openmw-0.29+git20140519.144/debian/changelog 2014-05-19 11:18:09.000000000 +0000 @@ -1,8 +1,8 @@ -openmw (0.29+git20140518.141-0~ubuntu14.04.1) trusty; urgency=low +openmw (0.29+git20140519.144-0~ubuntu14.04.1) trusty; urgency=low * Auto build. - -- Launchpad Package Builder Sun, 18 May 2014 11:17:06 +0000 + -- Launchpad Package Builder Mon, 19 May 2014 11:18:09 +0000 openmw (0.28.0-1) experimental; urgency=low