From f29c4086cd575a83c1ef29b078c64e052bde3468 Mon Sep 17 00:00:00 2001 From: Lukasz Gromanowski Date: Sun, 12 Oct 2014 15:18:37 +0200 Subject: [PATCH 01/24] Fixes #1982: Long class names are cut off in the UI Increased length of text filed for race, class name in stats window, and class name cation in chargen create class window. Signed-off-by: Lukasz Gromanowski --- files/mygui/openmw_chargen_create_class.layout | 2 +- files/mygui/openmw_stats_window.layout | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/files/mygui/openmw_chargen_create_class.layout b/files/mygui/openmw_chargen_create_class.layout index dee2f4fcf..1d071e621 100644 --- a/files/mygui/openmw_chargen_create_class.layout +++ b/files/mygui/openmw_chargen_create_class.layout @@ -3,7 +3,7 @@ - + diff --git a/files/mygui/openmw_stats_window.layout b/files/mygui/openmw_stats_window.layout index 6cdd4c02a..0b8dee5c8 100644 --- a/files/mygui/openmw_stats_window.layout +++ b/files/mygui/openmw_stats_window.layout @@ -89,11 +89,11 @@ - + - + From 02f0b7caa38a7d2342c9dcf0fa6798b3fc507244 Mon Sep 17 00:00:00 2001 From: Lukasz Gromanowski Date: Thu, 16 Oct 2014 23:22:22 +0200 Subject: [PATCH 02/24] Fixes #1982: Long class names are cut off in the UI Added HBox widget with AutoSizedTextBox, spacer, and TextBox for level, race, class caption and text pairs. Signed-off-by: Lukasz Gromanowski --- files/mygui/openmw_stats_window.layout | 66 ++++++++++++++++---------- 1 file changed, 42 insertions(+), 24 deletions(-) diff --git a/files/mygui/openmw_stats_window.layout b/files/mygui/openmw_stats_window.layout index 0b8dee5c8..df0a3f39f 100644 --- a/files/mygui/openmw_stats_window.layout +++ b/files/mygui/openmw_stats_window.layout @@ -70,32 +70,50 @@ - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - + + + + + + + + + + + + + + - - - + + + + + + + + + + + + + + From 2106893563518fde86d4d3dd18a63bcd92ff829d Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 17 Oct 2014 15:46:07 +0200 Subject: [PATCH 03/24] silenced a compiler warning regarding null pointer dereferencing --- apps/opencs/view/settings/rangeview.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/view/settings/rangeview.cpp b/apps/opencs/view/settings/rangeview.cpp index c96df9859..c24fd3888 100644 --- a/apps/opencs/view/settings/rangeview.cpp +++ b/apps/opencs/view/settings/rangeview.cpp @@ -117,7 +117,7 @@ void CSVSettings::RangeView::buildSpinBox (CSMSettings::Setting *setting) break; default: - break; + return; } //min / max values are set automatically in AlphaSpinBox From 2be65a89a729d79777af9d3d7fe245c9a382931e Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 17 Oct 2014 18:58:20 +0200 Subject: [PATCH 04/24] Show tooltip for non-affordable list items (Fixes #2025) --- apps/openmw/mwgui/merchantrepair.cpp | 8 +++++--- apps/openmw/mwgui/spellbuyingwindow.cpp | 6 ++++-- apps/openmw/mwgui/trainingwindow.cpp | 6 ++++-- files/mygui/openmw_text.skin.xml | 8 ++++++++ 4 files changed, 21 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwgui/merchantrepair.cpp b/apps/openmw/mwgui/merchantrepair.cpp index 499383d5f..e85681c04 100644 --- a/apps/openmw/mwgui/merchantrepair.cpp +++ b/apps/openmw/mwgui/merchantrepair.cpp @@ -73,7 +73,7 @@ void MerchantRepair::startRepair(const MWWorld::Ptr &actor) MyGUI::Button* button = - mList->createWidget("SandTextButton", + mList->createWidget(price <= playerGold ? "SandTextButton" : "SandTextButtonDisabled", // can't use setEnabled since that removes tooltip 0, currentY, 0, @@ -83,7 +83,6 @@ void MerchantRepair::startRepair(const MWWorld::Ptr &actor) currentY += 18; - button->setEnabled(price<=playerGold); button->setUserString("Price", boost::lexical_cast(price)); button->setUserData(*iter); button->setCaptionWithReplacing(name); @@ -124,6 +123,10 @@ void MerchantRepair::onRepairButtonClick(MyGUI::Widget *sender) { MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + int price = boost::lexical_cast(sender->getUserString("Price")); + if (price > player.getClass().getContainerStore(player).count(MWWorld::ContainerStore::sGoldId)) + return; + // repair MWWorld::Ptr item = *sender->getUserData(); item.getCellRef().setCharge(item.getClass().getItemMaxHealth(item)); @@ -132,7 +135,6 @@ void MerchantRepair::onRepairButtonClick(MyGUI::Widget *sender) MWBase::Environment::get().getSoundManager()->playSound("Repair",1,1); - int price = boost::lexical_cast(sender->getUserString("Price")); player.getClass().getContainerStore(player).remove(MWWorld::ContainerStore::sGoldId, price, player); diff --git a/apps/openmw/mwgui/spellbuyingwindow.cpp b/apps/openmw/mwgui/spellbuyingwindow.cpp index dd6339b4c..38b1bce7b 100644 --- a/apps/openmw/mwgui/spellbuyingwindow.cpp +++ b/apps/openmw/mwgui/spellbuyingwindow.cpp @@ -54,14 +54,13 @@ namespace MWGui MyGUI::Button* toAdd = mSpellsView->createWidget( - "SandTextButton", + price <= playerGold ? "SandTextButton" : "SandTextButtonDisabled", // can't use setEnabled since that removes tooltip 0, mCurrentY, 200, sLineHeight, MyGUI::Align::Default ); - toAdd->setEnabled(price<=playerGold); mCurrentY += sLineHeight; @@ -140,6 +139,9 @@ namespace MWGui int price = *_sender->getUserData(); MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + if (price > player.getClass().getContainerStore(player).count(MWWorld::ContainerStore::sGoldId)) + return; + MWMechanics::CreatureStats& stats = player.getClass().getCreatureStats(player); MWMechanics::Spells& spells = stats.getSpells(); spells.add (mSpellsWidgetMap.find(_sender)->second); diff --git a/apps/openmw/mwgui/trainingwindow.cpp b/apps/openmw/mwgui/trainingwindow.cpp index f67376c93..6ff5ae35f 100644 --- a/apps/openmw/mwgui/trainingwindow.cpp +++ b/apps/openmw/mwgui/trainingwindow.cpp @@ -93,10 +93,9 @@ namespace MWGui int price = MWBase::Environment::get().getMechanicsManager()->getBarterOffer (mPtr,pcStats.getSkill (skills[i].first).getBase() * gmst.find("iTrainingMod")->getInt (),true); - MyGUI::Button* button = mTrainingOptions->createWidget("SandTextButton", + MyGUI::Button* button = mTrainingOptions->createWidget(price <= playerGold ? "SandTextButton" : "SandTextButtonDisabled", // can't use setEnabled since that removes tooltip MyGUI::IntCoord(5, 5+i*18, mTrainingOptions->getWidth()-10, 18), MyGUI::Align::Default); - button->setEnabled(price <= playerGold); button->setUserData(skills[i].first); button->eventMouseButtonClick += MyGUI::newDelegate(this, &TrainingWindow::onTrainingSelected); @@ -133,6 +132,9 @@ namespace MWGui int price = pcStats.getSkill (skillId).getBase() * store.get().find("iTrainingMod")->getInt (); price = MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mPtr,price,true); + if (price > player.getClass().getContainerStore(player).count(MWWorld::ContainerStore::sGoldId)) + return; + MWMechanics::NpcStats& npcStats = mPtr.getClass().getNpcStats (mPtr); if (npcStats.getSkill (skillId).getBase () <= pcStats.getSkill (skillId).getBase ()) { diff --git a/files/mygui/openmw_text.skin.xml b/files/mygui/openmw_text.skin.xml index bae094ef6..fe01d3417 100644 --- a/files/mygui/openmw_text.skin.xml +++ b/files/mygui/openmw_text.skin.xml @@ -100,6 +100,14 @@ color_misc=0,205,205 # ???? + + + + + + + + From 8233f5894adf757b9fc346944bf0fffdd2a3332a Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 17 Oct 2014 23:04:36 +0200 Subject: [PATCH 05/24] Fix NpcAnimation non-existing skeleton crash (Fixes #2028) --- apps/openmw/mwrender/npcanimation.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 67be5916c..c43d3663e 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -200,10 +200,10 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, int v mPartPriorities[i] = 0; } + updateNpcBase(); + if (!disableListener) mPtr.getClass().getInventoryStore(mPtr).setListener(this, mPtr); - - updateNpcBase(); } void NpcAnimation::setViewMode(NpcAnimation::ViewMode viewMode) From 415f67f85963a0c264fa6b468d0d3c56ae03bb30 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 17 Oct 2014 23:29:13 +0200 Subject: [PATCH 06/24] Treat "Root Bone" as the animation root if existing (Fixes #2019) --- apps/openmw/mwrender/animation.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 625d0706f..29db648d0 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -298,7 +298,7 @@ void Animation::addAnimSource(const std::string &model) } } - if (grp == 0 && dstval->getNode()->getName() == "Bip01") + if (grp == 0 && (dstval->getNode()->getName() == "Bip01" || dstval->getNode()->getName() == "Root Bone")) { mNonAccumRoot = dstval->getNode(); mAccumRoot = mNonAccumRoot->getParent(); From 738f010b5ed8241d6d3864414bc04b9d8a12e4ba Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 18 Oct 2014 00:36:07 +0200 Subject: [PATCH 07/24] Ignore some extra string arguments to ShowMap (Fixes #2029) Required for a dialogue result script in Morrowind.esm ("ShowMap Dren Plantation"). This must do the same as "ShowMap Dren", which actually does work properly, since ShowMap supports partial string matching. --- components/compiler/extensions0.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/compiler/extensions0.cpp b/components/compiler/extensions0.cpp index 25ee6fdb6..8a17b5e79 100644 --- a/components/compiler/extensions0.cpp +++ b/components/compiler/extensions0.cpp @@ -226,7 +226,7 @@ namespace Compiler extensions.registerInstruction ("togglefullhelp", "", opcodeToggleFullHelp); extensions.registerInstruction ("tfh", "", opcodeToggleFullHelp); - extensions.registerInstruction ("showmap", "S", opcodeShowMap); + extensions.registerInstruction ("showmap", "Sxxxx", opcodeShowMap); extensions.registerInstruction ("fillmap", "", opcodeFillMap); extensions.registerInstruction ("menutest", "/l", opcodeMenuTest); extensions.registerInstruction ("togglemenus", "", opcodeToggleMenus); From 8ba2b24a13372428d05d9903e8d043852286423a Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 18 Oct 2014 18:13:08 +0200 Subject: [PATCH 08/24] updated changelog --- readme.txt | 117 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 117 insertions(+) diff --git a/readme.txt b/readme.txt index 5f96771c7..254e60f7f 100644 --- a/readme.txt +++ b/readme.txt @@ -98,6 +98,123 @@ Allowed options: CHANGELOG +0.33.0 + +Bug #371: If console assigned to ` (probably to any symbolic key), "`" symbol will be added to console every time it closed +Bug #1148: Some books'/scrolls' contents are displayed incorrectly +Bug #1290: Editor: status bar is not updated when record filter is changed +Bug #1292: Editor: Documents are not removed on closing the last view +Bug #1301: Editor: File->Exit only checks the document it was issued from. +Bug #1353: Bluetooth on with no speaker connected results in significantly longer initial load times +Bug #1436: NPCs react from too far distance +Bug #1472: PC is placed on top of following NPC when changing cell +Bug #1487: Tall PC can get stuck in staircases +Bug #1565: Editor: Subviews are deleted on shutdown instead when they are closed +Bug #1623: Door marker on Ghorak Manor's balcony makes PC stuck +Bug #1633: Loaddoor to Sadrith Mora, Telvanni Council House spawns PC in the air +Bug #1655: Use Appropriate Application Icons on Windows +Bug #1679: Tribunal expansion, Meryn Othralas the backstage manager in the theatre group in Mournhold in the great bazaar district is floating a good feet above the ground. +Bug #1705: Rain is broken in third person +Bug #1706: Thunder and lighting still occurs while the game is paused during the rain +Bug #1708: No long jumping +Bug #1710: Editor: ReferenceableID drag to references record filter field creates incorrect filter +Bug #1712: Rest on Water +Bug #1715: "Cancel" button is not always on the same side of menu +Bug #1725: Editor: content file can be opened multiple times from the same dialogue +Bug #1730: [MOD: Less Generic Nerevarine] Compile failure attempting to enter the Corprusarium. +Bug #1733: Unhandled ffmpeg sample formats +Bug #1735: Editor: "Edit Record" context menu button not opening subview for journal infos +Bug #1750: Editor: record edits result in duplicate entries +Bug #1789: Editor: Some characters cannot be used in addon name +Bug #1803: Resizing the map does not keep the pre-resize center at the post-resize center +Bug #1821: Recovering Cloudcleaver quest: attacking Sosia is considered a crime when you side with Hlormar +Bug #1838: Editor: Preferences window appears off screen +Bug #1839: Editor: Record filter title should be moved two pixels to the right +Bug #1849: Subrecord error in MAO_Containers +Bug #1854: Knocked-out actors don't fully act knocked out +Bug #1855: "Soul trapped" sound doesn't play +Bug #1857: Missing sound effect for enchanted items with empty charge +Bug #1859: Missing console command: ResetActors (RA) +Bug #1861: Vendor category "MagicItems" is unhandled +Bug #1862: Launcher doesn't start if a file listed in launcher.cfg has correct name but wrong capitalization +Bug #1864: Editor: Region field for cell record in dialogue subview not working +Bug #1869: Editor: Change label "Musics" to "Music" +Bug #1870: Goblins killed while knocked down remain in knockdown-pose +Bug #1874: CellChanged events should not trigger when crossing exterior cell border +Bug #1877: Spriggans killed instantly if hit while regening +Bug #1878: Magic Menu text not un-highlighting correctly when going from spell to item as active magic +Bug #1881: Stuck in ceiling when entering castle karstaags tower +Bug #1884: Unlit torches still produce a burning sound +Bug #1885: Can type text in price field in barter window +Bug #1887: Equipped items do not emit sounds +Bug #1889: draugr lord aesliip will attack you and remain non-hostile +Bug #1892: Guard asks player to pay bounty of 0 gold +Bug #1895: getdistance should only return max float if ref and target are in different worldspaces +Bug #1896: Crash Report +Bug #1897: Conjured Equipment cant be re-equipped if removed +Bug #1898: Only Gidar Verothan follows you during establish the mine quest +Bug #1900: Black screen when you open the door and breath underwater +Bug #1904: Crash on casting recall spell +Bug #1906: Bound item checks should use the GMSTs +Bug #1907: Bugged door. Mournhold, The Winged Guar +Bug #1908: Crime reported for attacking Drathas Nerus's henchmen while they attack Dilborn +Bug #1909: Weird Quest Flow Infidelities quest +Bug #1910: Follower fighting with gone npc +Bug #1911: Npcs will drown themselves +Bug #1912: World map arrow stays static when inside a building +Bug #1920: Ulyne Henim disappears when game is loaded inside Vas +Bug #1922: alchemy-> potion of paralyze +Bug #1923: "levitation magic cannot be used here" shows outside of tribunal +Bug #1927: AI prefer melee over magic. +Bug #1929: Tamriel Rebuilt: Named cells that lie within the overlap with Morrowind.esm are not shown +Bug #1932: BTB - Spells 14.1 magic effects donĀ“t overwrite the Vanilla ones but are added +Bug #1935: Stacks of items are worth more when sold individually +Bug #1940: Launcher does not list addon files if base game file is renamed to a different case +Bug #1946: Mod "Tel Nechim - moved" breaks savegames +Bug #1947: Buying/Selling price doesn't properly affect the growth of mercantile skill +Bug #1950: followers from east empire company quest will fight each other if combat happens with anything +Bug #1958: Journal can be scrolled indefinitely with a mouse wheel +Bug #1959: Follower not leaving party on quest end +Bug #1960: Key bindings not always saved correctly +Bug #1961: Spell merchants selling racial bonus spells +Bug #1967: segmentation fault on load saves +Bug #1968: Jump sounds are not controlled by footsteps slider, sound weird compared to footsteps +Bug #1970: PC suffers silently when taking damage from lava +Bug #1971: Dwarven Sceptre collision area is not removed after killing one +Bug #1974: Dalin/Daris Norvayne follows player indefinitely +Bug #1975: East Empire Company faction rank breaks during Raven Rock questline +Bug #1979: 0 strength = permanently over encumbered +Bug #1993: Shrine blessing in Maar Gan doesn't work +Bug #2008: Enchanted items do not recharge +Bug #2011: Editor: OpenCS script compiler doesn't handle member variable access properly +Bug #2016: Dagoth Ur already dead in Facility Cavern +Bug #2017: Fighters Guild Quest: The Code Book - dialogue loop when UMP is loaded. +Bug #2019: Animation of 'Correct UV Mudcrabs' broken +Bug #2022: Alchemy window - Removing ingredient doesn't remove the number of ingredients +Bug #2025: Missing mouse-over text for non affordable items +Bug #2028: [MOD: Tamriel Rebuilt] Crashing when trying to enter interior cell "Ruinous Keep, Great Hall" +Bug #2029: Ienith Brothers Thiev's Guild quest journal entry not adding +Feature #471: Editor: Special case implementation for top-level window with single sub-window +Feature #472: Editor: Sub-Window re-use settings +Feature #704: Font colors import from fallback settings +Feature #854: Editor: Add user setting to show status bar +Feature #879: Editor: Open sub-views in a new top-level window +Feature #932: Editor: magic effect table +Feature #937: Editor: Path Grid table +Feature #938: Editor: Sound Gen table +Feature #1117: Death and LevelUp music +Feature #1226: Editor: Request UniversalId editing from table columns +Feature #1310: Editor: Rendering User Settings +Feature #1545: Targeting console on player +Feature #1597: Editor: Render terrain +Feature #1695: Editor: add column for CellRef's global variable +Feature #1696: Editor: use ESM::Cell's RefNum counter +Feature #1697: Redden player's vision when hit +Feature #1856: Spellcasting for non-biped creatures +Feature #1879: Editor: Run OpenMW with the currently edited content list +Task #1851: Move AI temporary state out of AI packages +Task #1865: Replace char type in records + 0.32.0 Bug #1132: Unable to jump when facing a wall From ed6bdc0bde1f5bc2ab1b2ef56eea20ca011e2ebd Mon Sep 17 00:00:00 2001 From: MiroslavR Date: Sat, 18 Oct 2014 19:51:07 +0200 Subject: [PATCH 09/24] Use all topics to search for keywords in dialogues (Fixes #2013) Move KeywordSearch to MWDialogue Move hypertext parsing functions to a new file --- apps/openmw/CMakeLists.txt | 4 +- apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 95 +++---------------- apps/openmw/mwdialogue/dialoguemanagerimp.hpp | 15 --- apps/openmw/mwdialogue/hypertextparser.cpp | 89 +++++++++++++++++ apps/openmw/mwdialogue/hypertextparser.hpp | 36 +++++++ .../{mwgui => mwdialogue}/keywordsearch.cpp | 0 .../{mwgui => mwdialogue}/keywordsearch.hpp | 7 +- apps/openmw/mwgui/dialogue.hpp | 4 +- apps/openmw/mwgui/journalviewmodel.cpp | 6 +- 9 files changed, 150 insertions(+), 106 deletions(-) create mode 100644 apps/openmw/mwdialogue/hypertextparser.cpp create mode 100644 apps/openmw/mwdialogue/hypertextparser.hpp rename apps/openmw/{mwgui => mwdialogue}/keywordsearch.cpp (100%) rename apps/openmw/{mwgui => mwdialogue}/keywordsearch.hpp (98%) diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index e37cd1391..a1b31d38e 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -38,13 +38,13 @@ add_openmw_dir (mwgui itemselection spellbuyingwindow loadingscreen levelupdialog waitdialog spellcreationdialog enchantingdialog trainingwindow travelwindow exposedwindow cursor spellicons merchantrepair repair soulgemdialog companionwindow bookpage journalviewmodel journalbooks - keywordsearch itemmodel containeritemmodel inventoryitemmodel sortfilteritemmodel itemview + itemmodel containeritemmodel inventoryitemmodel sortfilteritemmodel itemview tradeitemmodel companionitemmodel pickpocketitemmodel controllers savegamedialog recharge mode videowidget backgroundimage itemwidget screenfader debugwindow ) add_openmw_dir (mwdialogue - dialoguemanagerimp journalimp journalentry quest topic filter selectwrapper + dialoguemanagerimp journalimp journalentry quest topic filter selectwrapper hypertextparser keywordsearch ) add_openmw_dir (mwscript diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index 892669678..aae3d9b41 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -42,6 +42,7 @@ #include "../mwmechanics/npcstats.hpp" #include "filter.hpp" +#include "hypertextparser.hpp" namespace MWDialogue { @@ -82,42 +83,27 @@ namespace MWDialogue void DialogueManager::parseText (const std::string& text) { - std::vector hypertext = ParseHyperText(text); + std::vector hypertext = HyperTextParser::parseHyperText(text); - //calculation of standard form fir all hyperlinks - for (size_t i = 0; i < hypertext.size(); ++i) + for (std::vector::iterator tok = hypertext.begin(); tok != hypertext.end(); ++tok) { - if (hypertext[i].mLink) + Misc::StringUtils::toLower(tok->mText); + + if (tok->isExplicitLink()) { - size_t asterisk_count = MWDialogue::RemovePseudoAsterisks(hypertext[i].mText); + // calculation of standard form for all hyperlinks + size_t asterisk_count = HyperTextParser::removePseudoAsterisks(tok->mText); for(; asterisk_count > 0; --asterisk_count) - hypertext[i].mText.append("*"); + tok->mText.append("*"); - hypertext[i].mText = mTranslationDataStorage.topicStandardForm(hypertext[i].mText); + tok->mText = mTranslationDataStorage.topicStandardForm(tok->mText); } - } - for (size_t i = 0; i < hypertext.size(); ++i) - { - std::list::iterator it; - for(it = mActorKnownTopics.begin(); it != mActorKnownTopics.end(); ++it) - { - if (hypertext[i].mLink) - { - if( hypertext[i].mText == *it ) - { - mKnownTopics[hypertext[i].mText] = true; - } - } - else if( !mTranslationDataStorage.hasTranslation() ) - { - size_t pos = Misc::StringUtils::lowerCase(hypertext[i].mText).find(*it, 0); - if(pos !=std::string::npos) - { - mKnownTopics[*it] = true; - } - } - } + if (tok->isImplicitKeyword() && mTranslationDataStorage.hasTranslation()) + continue; + + if (std::find(mActorKnownTopics.begin(), mActorKnownTopics.end(), tok->mText) != mActorKnownTopics.end()) + mKnownTopics[tok->mText] = true; } updateTopics(); @@ -724,55 +710,4 @@ namespace MWDialogue mLastTopic, actor.getClass().getName(actor)); } } - - std::vector ParseHyperText(const std::string& text) - { - std::vector result; - MyGUI::UString utext(text); - size_t pos_end, iteration_pos = 0; - for(;;) - { - size_t pos_begin = utext.find('@', iteration_pos); - if (pos_begin != std::string::npos) - pos_end = utext.find('#', pos_begin); - - if (pos_begin != std::string::npos && pos_end != std::string::npos) - { - result.push_back( HyperTextToken(utext.substr(iteration_pos, pos_begin - iteration_pos), false) ); - - std::string link = utext.substr(pos_begin + 1, pos_end - pos_begin - 1); - result.push_back( HyperTextToken(link, true) ); - - iteration_pos = pos_end + 1; - } - else - { - result.push_back( HyperTextToken(utext.substr(iteration_pos), false) ); - break; - } - } - - return result; - } - - size_t RemovePseudoAsterisks(std::string& phrase) - { - size_t pseudoAsterisksCount = 0; - - if( !phrase.empty() ) - { - std::string::reverse_iterator rit = phrase.rbegin(); - - const char specialPseudoAsteriskCharacter = 127; - while( rit != phrase.rend() && *rit == specialPseudoAsteriskCharacter ) - { - pseudoAsterisksCount++; - ++rit; - } - } - - phrase = phrase.substr(0, phrase.length() - pseudoAsterisksCount); - - return pseudoAsterisksCount; - } } diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.hpp b/apps/openmw/mwdialogue/dialoguemanagerimp.hpp index 6553ddc01..9c3d0d54b 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.hpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.hpp @@ -103,21 +103,6 @@ namespace MWDialogue /// Removes the last added topic response for the given actor from the journal virtual void clearInfoActor (const MWWorld::Ptr& actor) const; }; - - - struct HyperTextToken - { - HyperTextToken(const std::string& text, bool link) : mText(text), mLink(link) {} - - std::string mText; - bool mLink; - }; - - // In translations (at least Russian) the links are marked with @#, so - // it should be a function to parse it - std::vector ParseHyperText(const std::string& text); - - size_t RemovePseudoAsterisks(std::string& phrase); } #endif diff --git a/apps/openmw/mwdialogue/hypertextparser.cpp b/apps/openmw/mwdialogue/hypertextparser.cpp new file mode 100644 index 000000000..776edac94 --- /dev/null +++ b/apps/openmw/mwdialogue/hypertextparser.cpp @@ -0,0 +1,89 @@ +#include + +#include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" + +#include "../mwworld/store.hpp" +#include "../mwworld/esmstore.hpp" + +#include "keywordsearch.hpp" + +#include "hypertextparser.hpp" + +namespace MWDialogue +{ + namespace HyperTextParser + { + std::vector parseHyperText(const std::string & text) + { + std::vector result; + size_t pos_end, iteration_pos = 0; + for(;;) + { + size_t pos_begin = text.find('@', iteration_pos); + if (pos_begin != std::string::npos) + pos_end = text.find('#', pos_begin); + + if (pos_begin != std::string::npos && pos_end != std::string::npos) + { + if (pos_begin != iteration_pos) + tokenizeKeywords(text.substr(iteration_pos, pos_begin - iteration_pos), result); + + std::string link = text.substr(pos_begin + 1, pos_end - pos_begin - 1); + result.push_back(Token(link, Token::ExplicitLink)); + + iteration_pos = pos_end + 1; + } + else + { + if (iteration_pos != text.size()) + tokenizeKeywords(text.substr(iteration_pos), result); + break; + } + } + + return result; + } + + void tokenizeKeywords(const std::string & text, std::vector & tokens) + { + const MWWorld::Store & dialogs = + MWBase::Environment::get().getWorld()->getStore().get(); + + std::list keywordList; + for (MWWorld::Store::iterator it = dialogs.begin(); it != dialogs.end(); ++it) + keywordList.push_back(Misc::StringUtils::lowerCase(it->mId)); + keywordList.sort(Misc::StringUtils::ciLess); + + KeywordSearch keywordSearch; + KeywordSearch::Match match; + + for (std::list::const_iterator it = keywordList.begin(); it != keywordList.end(); ++it) + keywordSearch.seed(*it, 0 /*unused*/); + + for (std::string::const_iterator it = text.begin(); it != text.end() && keywordSearch.search(it, text.end(), match, text.begin()); it = match.mEnd) + tokens.push_back(Token(std::string(match.mBeg, match.mEnd), Token::ImplicitKeyword)); + } + + size_t removePseudoAsterisks(std::string & phrase) + { + size_t pseudoAsterisksCount = 0; + + if( !phrase.empty() ) + { + std::string::reverse_iterator rit = phrase.rbegin(); + + const char specialPseudoAsteriskCharacter = 127; + while( rit != phrase.rend() && *rit == specialPseudoAsteriskCharacter ) + { + pseudoAsterisksCount++; + ++rit; + } + } + + phrase = phrase.substr(0, phrase.length() - pseudoAsterisksCount); + + return pseudoAsterisksCount; + } + } +} diff --git a/apps/openmw/mwdialogue/hypertextparser.hpp b/apps/openmw/mwdialogue/hypertextparser.hpp new file mode 100644 index 000000000..13e135f3c --- /dev/null +++ b/apps/openmw/mwdialogue/hypertextparser.hpp @@ -0,0 +1,36 @@ +#ifndef GAME_MWDIALOGUE_HYPERTEXTPARSER_H +#define GAME_MWDIALOGUE_HYPERTEXTPARSER_H + +#include +#include + +namespace MWDialogue +{ + namespace HyperTextParser + { + struct Token + { + enum Type + { + ExplicitLink, // enclosed in @# + ImplicitKeyword + }; + + Token(const std::string & text, Type type) : mText(text), mType(type) {} + + bool isExplicitLink() { return mType == ExplicitLink; } + bool isImplicitKeyword() { return mType == ImplicitKeyword; } + + std::string mText; + Type mType; + }; + + // In translations (at least Russian) the links are marked with @#, so + // it should be a function to parse it + std::vector parseHyperText(const std::string & text); + void tokenizeKeywords(const std::string & text, std::vector & tokens); + size_t removePseudoAsterisks(std::string & phrase); + } +} + +#endif diff --git a/apps/openmw/mwgui/keywordsearch.cpp b/apps/openmw/mwdialogue/keywordsearch.cpp similarity index 100% rename from apps/openmw/mwgui/keywordsearch.cpp rename to apps/openmw/mwdialogue/keywordsearch.cpp diff --git a/apps/openmw/mwgui/keywordsearch.hpp b/apps/openmw/mwdialogue/keywordsearch.hpp similarity index 98% rename from apps/openmw/mwgui/keywordsearch.hpp rename to apps/openmw/mwdialogue/keywordsearch.hpp index 4f4459b35..51508890c 100644 --- a/apps/openmw/mwgui/keywordsearch.hpp +++ b/apps/openmw/mwdialogue/keywordsearch.hpp @@ -1,5 +1,5 @@ -#ifndef MWGUI_KEYWORDSEARCH_H -#define MWGUI_KEYWORDSEARCH_H +#ifndef GAME_MWDIALOGUE_KEYWORDSEARCH_H +#define GAME_MWDIALOGUE_KEYWORDSEARCH_H #include #include @@ -9,7 +9,7 @@ #include -namespace MWGui +namespace MWDialogue { template @@ -141,7 +141,6 @@ public: match.mValue = candidate->second.mValue; match.mBeg = i; match.mEnd = k; - return true; } } diff --git a/apps/openmw/mwgui/dialogue.hpp b/apps/openmw/mwgui/dialogue.hpp index 18f1f1555..23709e8fe 100644 --- a/apps/openmw/mwgui/dialogue.hpp +++ b/apps/openmw/mwgui/dialogue.hpp @@ -6,7 +6,7 @@ #include "bookpage.hpp" -#include "keywordsearch.hpp" +#include "../mwdialogue/keywordsearch.hpp" namespace Gui { @@ -76,7 +76,7 @@ namespace MWGui virtual void activated (); }; - typedef KeywordSearch KeywordSearchT; + typedef MWDialogue::KeywordSearch KeywordSearchT; struct DialogueText { diff --git a/apps/openmw/mwgui/journalviewmodel.cpp b/apps/openmw/mwgui/journalviewmodel.cpp index 0ab56200d..059af463f 100644 --- a/apps/openmw/mwgui/journalviewmodel.cpp +++ b/apps/openmw/mwgui/journalviewmodel.cpp @@ -12,9 +12,9 @@ #include "../mwbase/journal.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" -#include "../mwdialogue/journalentry.hpp" -#include "keywordsearch.hpp" +#include "../mwdialogue/journalentry.hpp" +#include "../mwdialogue/keywordsearch.hpp" namespace MWGui { @@ -22,7 +22,7 @@ struct JournalViewModelImpl; struct JournalViewModelImpl : JournalViewModel { - typedef KeywordSearch KeywordSearchT; + typedef MWDialogue::KeywordSearch KeywordSearchT; mutable bool mKeywordSearchLoaded; mutable KeywordSearchT mKeywordSearch; From b0f98687e6a9c2d9e240fd47c8a7b5bd64c5572c Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 19 Oct 2014 17:45:18 +0200 Subject: [PATCH 10/24] Properly handle DialInfo records that were marked as Deleted (Fixes #2035) --- apps/openmw/mwworld/esmstore.cpp | 1 + apps/openmw/mwworld/store.hpp | 19 +++++++++++++++++++ components/esm/loaddial.cpp | 11 +++++++++++ components/esm/loaddial.hpp | 3 +++ 4 files changed, 34 insertions(+) diff --git a/apps/openmw/mwworld/esmstore.cpp b/apps/openmw/mwworld/esmstore.cpp index 1b5d3d1e9..56cb05c64 100644 --- a/apps/openmw/mwworld/esmstore.cpp +++ b/apps/openmw/mwworld/esmstore.cpp @@ -135,6 +135,7 @@ void ESMStore::setUp() mSkills.setUp(); mMagicEffects.setUp(); mAttributes.setUp(); + mDialogs.setUp(); } int ESMStore::countSavedGameRecords() const diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index 107db68b1..2611bacbd 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -1174,6 +1174,25 @@ namespace MWWorld mShared.erase(mShared.begin() + mStatic.size(), mShared.end()); } + template<> + inline void Store::setUp() + { + // DialInfos marked as deleted are kept during the loading phase, so that the linked list + // structure is kept intact for inserting further INFOs. Delete them now that loading is done. + for (Static::iterator it = mStatic.begin(); it != mStatic.end(); ++it) + { + ESM::Dialogue& dial = it->second; + dial.clearDeletedInfos(); + } + + mShared.clear(); + mShared.reserve(mStatic.size()); + typename std::map::iterator it = mStatic.begin(); + for (; it != mStatic.end(); ++it) { + mShared.push_back(&(it->second)); + } + } + } //end namespace #endif diff --git a/components/esm/loaddial.cpp b/components/esm/loaddial.cpp index 92077b572..ff0362aa2 100644 --- a/components/esm/loaddial.cpp +++ b/components/esm/loaddial.cpp @@ -110,4 +110,15 @@ void Dialogue::readInfo(ESMReader &esm, bool merge) std::cerr << "Failed to insert info " << id << std::endl; } +void Dialogue::clearDeletedInfos() +{ + for (InfoContainer::iterator it = mInfo.begin(); it != mInfo.end(); ) + { + if (it->mQuestStatus == DialInfo::QS_Deleted) + it = mInfo.erase(it); + else + ++it; + } +} + } diff --git a/components/esm/loaddial.hpp b/components/esm/loaddial.hpp index fd46ad210..d29948c63 100644 --- a/components/esm/loaddial.hpp +++ b/components/esm/loaddial.hpp @@ -47,6 +47,9 @@ struct Dialogue void load(ESMReader &esm); void save(ESMWriter &esm) const; + /// Remove all INFOs marked as QS_Deleted from mInfos. + void clearDeletedInfos(); + /// Read the next info record /// @param merge Merge with existing list, or just push each record to the end of the list? void readInfo (ESM::ESMReader& esm, bool merge); From 5a7dbb19f74e49e1cb511c2cff5cec7f4eb109b8 Mon Sep 17 00:00:00 2001 From: MiroslavR Date: Mon, 20 Oct 2014 01:10:08 +0200 Subject: [PATCH 11/24] Code clarity --- apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index aae3d9b41..eff54fbc0 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -87,23 +87,23 @@ namespace MWDialogue for (std::vector::iterator tok = hypertext.begin(); tok != hypertext.end(); ++tok) { - Misc::StringUtils::toLower(tok->mText); + std::string topicId = Misc::StringUtils::lowerCase(tok->mText); if (tok->isExplicitLink()) { // calculation of standard form for all hyperlinks - size_t asterisk_count = HyperTextParser::removePseudoAsterisks(tok->mText); + size_t asterisk_count = HyperTextParser::removePseudoAsterisks(topicId); for(; asterisk_count > 0; --asterisk_count) - tok->mText.append("*"); + topicId.append("*"); - tok->mText = mTranslationDataStorage.topicStandardForm(tok->mText); + topicId = mTranslationDataStorage.topicStandardForm(topicId); } if (tok->isImplicitKeyword() && mTranslationDataStorage.hasTranslation()) continue; - if (std::find(mActorKnownTopics.begin(), mActorKnownTopics.end(), tok->mText) != mActorKnownTopics.end()) - mKnownTopics[tok->mText] = true; + if (std::find(mActorKnownTopics.begin(), mActorKnownTopics.end(), topicId) != mActorKnownTopics.end()) + mKnownTopics[topicId] = true; } updateTopics(); From 7f06e3e7e308f99c14e83aee82286528154d7bab Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 20 Oct 2014 17:07:54 +0200 Subject: [PATCH 12/24] Fix alchemy producing potion IDs from content files --- apps/openmw/mwmechanics/alchemy.cpp | 61 +++++++++++++++-------------- apps/openmw/mwmechanics/alchemy.hpp | 12 ++---- 2 files changed, 35 insertions(+), 38 deletions(-) diff --git a/apps/openmw/mwmechanics/alchemy.cpp b/apps/openmw/mwmechanics/alchemy.cpp index 90c180817..5549c85ed 100644 --- a/apps/openmw/mwmechanics/alchemy.cpp +++ b/apps/openmw/mwmechanics/alchemy.cpp @@ -205,7 +205,7 @@ void MWMechanics::Alchemy::updateEffects() } } -const ESM::Potion *MWMechanics::Alchemy::getRecord() const +const ESM::Potion *MWMechanics::Alchemy::getRecord(const ESM::Potion& toFind) const { const MWWorld::Store &potions = MWBase::Environment::get().getWorld()->getStore().get(); @@ -216,6 +216,18 @@ const ESM::Potion *MWMechanics::Alchemy::getRecord() const if (iter->mEffects.mList.size() != mEffects.size()) continue; + if (iter->mName != toFind.mName + || iter->mScript != toFind.mScript + || iter->mData.mWeight != toFind.mData.mWeight + || iter->mData.mValue != toFind.mData.mValue + || iter->mData.mAutoCalc != toFind.mData.mAutoCalc) + continue; + + // Don't choose an ID that came from the content files, would have unintended side effects + // where alchemy can be used to produce quest-relevant items + if (!potions.isDynamic(iter->mId)) + continue; + bool mismatch = false; for (int i=0; i (iter->mEffects.mList.size()); ++i) @@ -266,37 +278,34 @@ void MWMechanics::Alchemy::removeIngredients() void MWMechanics::Alchemy::addPotion (const std::string& name) { - const ESM::Potion *record = getRecord(); + ESM::Potion newRecord; - if (!record) - { - ESM::Potion newRecord; + newRecord.mData.mWeight = 0; - newRecord.mData.mWeight = 0; - - for (TIngredientsIterator iter (beginIngredients()); iter!=endIngredients(); ++iter) - if (!iter->isEmpty()) - newRecord.mData.mWeight += iter->get()->mBase->mData.mWeight; + for (TIngredientsIterator iter (beginIngredients()); iter!=endIngredients(); ++iter) + if (!iter->isEmpty()) + newRecord.mData.mWeight += iter->get()->mBase->mData.mWeight; - newRecord.mData.mWeight /= countIngredients(); + newRecord.mData.mWeight /= countIngredients(); - newRecord.mData.mValue = mValue; - newRecord.mData.mAutoCalc = 0; + newRecord.mData.mValue = mValue; + newRecord.mData.mAutoCalc = 0; - newRecord.mName = name; + newRecord.mName = name; - int index = static_cast (std::rand()/(static_cast (RAND_MAX)+1)*6); - assert (index>=0 && index<6); + int index = static_cast (std::rand()/(static_cast (RAND_MAX)+1)*6); + assert (index>=0 && index<6); - static const char *name[] = { "standard", "bargain", "cheap", "fresh", "exclusive", "quality" }; + static const char *meshes[] = { "standard", "bargain", "cheap", "fresh", "exclusive", "quality" }; - newRecord.mModel = "m\\misc_potion_" + std::string (name[index]) + "_01.nif"; - newRecord.mIcon = "m\\tx_potion_" + std::string (name[index]) + "_01.dds"; + newRecord.mModel = "m\\misc_potion_" + std::string (meshes[index]) + "_01.nif"; + newRecord.mIcon = "m\\tx_potion_" + std::string (meshes[index]) + "_01.dds"; - newRecord.mEffects.mList = mEffects; + newRecord.mEffects.mList = mEffects; + const ESM::Potion* record = getRecord(newRecord); + if (!record) record = MWBase::Environment::get().getWorld()->createRecord (newRecord); - } mAlchemist.getClass().getContainerStore (mAlchemist).add (record->mId, 1, mAlchemist); } @@ -436,14 +445,6 @@ MWMechanics::Alchemy::TEffectsIterator MWMechanics::Alchemy::endEffects() const return mEffects.end(); } -std::string MWMechanics::Alchemy::getPotionName() const -{ - if (const ESM::Potion *potion = getRecord()) - return potion->mName; - - return ""; -} - MWMechanics::Alchemy::Result MWMechanics::Alchemy::create (const std::string& name) { if (mTools[ESM::Apparatus::MortarPestle].isEmpty()) @@ -452,7 +453,7 @@ MWMechanics::Alchemy::Result MWMechanics::Alchemy::create (const std::string& na if (countIngredients()<2) return Result_LessThanTwoIngredients; - if (name.empty() && getPotionName().empty()) + if (name.empty()) return Result_NoName; if (listEffects().empty()) diff --git a/apps/openmw/mwmechanics/alchemy.hpp b/apps/openmw/mwmechanics/alchemy.hpp index e6b8c6650..c96356ebb 100644 --- a/apps/openmw/mwmechanics/alchemy.hpp +++ b/apps/openmw/mwmechanics/alchemy.hpp @@ -56,8 +56,9 @@ namespace MWMechanics void updateEffects(); - const ESM::Potion *getRecord() const; - ///< Return existing record for created potion (may return 0) + const ESM::Potion *getRecord(const ESM::Potion& toFind) const; + ///< Try to find a potion record similar to \a toFind in the record store, or return 0 if not found + /// \note Does not account for record ID, model or icon void removeIngredients(); ///< Remove selected ingredients from alchemist's inventory, cleanup selected ingredients and @@ -108,15 +109,10 @@ namespace MWMechanics void removeIngredient (int index); ///< Remove ingredient from slot (calling this function on an empty slot is a no-op). - std::string getPotionName() const; - ///< Return the name of the potion that would be created when calling create (if a record for such - /// a potion already exists) or return an empty string. - Result create (const std::string& name); ///< Try to create a potion from the ingredients, place it in the inventory of the alchemist and /// adjust the skills of the alchemist accordingly. - /// \param name must not be an empty string, unless there is already a potion record ( - /// getPotionName() does not return an empty string). + /// \param name must not be an empty string, or Result_NoName is returned }; } From 29ac97be7adf4d8bb0156dceadb378f6d87be389 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 20 Oct 2014 17:28:22 +0200 Subject: [PATCH 13/24] Add automatic potion naming --- apps/openmw/mwgui/alchemywindow.cpp | 5 +++++ apps/openmw/mwgui/alchemywindow.hpp | 2 ++ apps/openmw/mwmechanics/alchemy.cpp | 11 +++++++++++ apps/openmw/mwmechanics/alchemy.hpp | 3 +++ 4 files changed, 21 insertions(+) diff --git a/apps/openmw/mwgui/alchemywindow.cpp b/apps/openmw/mwgui/alchemywindow.cpp index 0fa9121b7..e67a8512a 100644 --- a/apps/openmw/mwgui/alchemywindow.cpp +++ b/apps/openmw/mwgui/alchemywindow.cpp @@ -173,6 +173,11 @@ namespace MWGui void AlchemyWindow::update() { + std::string suggestedName = mAlchemy.suggestPotionName(); + if (suggestedName != mSuggestedPotionName) + mNameEdit->setCaptionWithReplacing(suggestedName); + mSuggestedPotionName = suggestedName; + mSortModel->clearDragItems(); MWMechanics::Alchemy::TIngredientsIterator it = mAlchemy.beginIngredients (); diff --git a/apps/openmw/mwgui/alchemywindow.hpp b/apps/openmw/mwgui/alchemywindow.hpp index b538a1f80..36f540c1b 100644 --- a/apps/openmw/mwgui/alchemywindow.hpp +++ b/apps/openmw/mwgui/alchemywindow.hpp @@ -23,6 +23,8 @@ namespace MWGui virtual void exit(); private: + std::string mSuggestedPotionName; + ItemView* mItemView; SortFilterItemModel* mSortModel; diff --git a/apps/openmw/mwmechanics/alchemy.cpp b/apps/openmw/mwmechanics/alchemy.cpp index 5549c85ed..328f3a25d 100644 --- a/apps/openmw/mwmechanics/alchemy.cpp +++ b/apps/openmw/mwmechanics/alchemy.cpp @@ -480,3 +480,14 @@ MWMechanics::Alchemy::Result MWMechanics::Alchemy::create (const std::string& na return Result_Success; } + +std::string MWMechanics::Alchemy::suggestPotionName() +{ + std::set effects = listEffects(); + if (effects.empty()) + return ""; + + int effectId = effects.begin()->mId; + return MWBase::Environment::get().getWorld()->getStore().get().find( + ESM::MagicEffect::effectIdToString(effectId)); +} diff --git a/apps/openmw/mwmechanics/alchemy.hpp b/apps/openmw/mwmechanics/alchemy.hpp index c96356ebb..caba26f14 100644 --- a/apps/openmw/mwmechanics/alchemy.hpp +++ b/apps/openmw/mwmechanics/alchemy.hpp @@ -109,6 +109,9 @@ namespace MWMechanics void removeIngredient (int index); ///< Remove ingredient from slot (calling this function on an empty slot is a no-op). + std::string suggestPotionName (); + ///< Suggest a name for the potion, based on the current effects + Result create (const std::string& name); ///< Try to create a potion from the ingredients, place it in the inventory of the alchemist and /// adjust the skills of the alchemist accordingly. From ace8e0175bdc63d2354c969fddf7730d31797506 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 20 Oct 2014 17:27:25 +0200 Subject: [PATCH 14/24] Fix old alchemy apparatus still showing in alchemy window after removal --- apps/openmw/mwgui/alchemywindow.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/alchemywindow.cpp b/apps/openmw/mwgui/alchemywindow.cpp index e67a8512a..b9e0044ce 100644 --- a/apps/openmw/mwgui/alchemywindow.cpp +++ b/apps/openmw/mwgui/alchemywindow.cpp @@ -134,11 +134,12 @@ namespace MWGui for (MWMechanics::Alchemy::TToolsIterator iter (mAlchemy.beginTools()); iter!=mAlchemy.endTools() && index (mApparatus.size()); ++iter, ++index) { + mApparatus.at (index)->setItem(*iter); + mApparatus.at (index)->clearUserStrings(); if (!iter->isEmpty()) { mApparatus.at (index)->setUserString ("ToolTipType", "ItemPtr"); mApparatus.at (index)->setUserData (*iter); - mApparatus.at (index)->setItem(*iter); } } From 9bb51fd9c2f65d13548e115011d91cc993e10035 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 20 Oct 2014 17:42:51 +0200 Subject: [PATCH 15/24] Compile fix --- apps/openmw/mwmechanics/alchemy.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/alchemy.cpp b/apps/openmw/mwmechanics/alchemy.cpp index 328f3a25d..da2492a77 100644 --- a/apps/openmw/mwmechanics/alchemy.cpp +++ b/apps/openmw/mwmechanics/alchemy.cpp @@ -489,5 +489,5 @@ std::string MWMechanics::Alchemy::suggestPotionName() int effectId = effects.begin()->mId; return MWBase::Environment::get().getWorld()->getStore().get().find( - ESM::MagicEffect::effectIdToString(effectId)); + ESM::MagicEffect::effectIdToString(effectId))->getString(); } From b5a57920b640c4251d302b0400cde2e3e37e49ae Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Tue, 21 Oct 2014 19:35:17 +0200 Subject: [PATCH 16/24] Fix compile error on Windows --- apps/openmw/mwworld/store.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index 2611bacbd..55c5b8191 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -1187,7 +1187,7 @@ namespace MWWorld mShared.clear(); mShared.reserve(mStatic.size()); - typename std::map::iterator it = mStatic.begin(); + std::map::iterator it = mStatic.begin(); for (; it != mStatic.end(); ++it) { mShared.push_back(&(it->second)); } From 925fa8d1931b909d688e95246e96c056fd82b46e Mon Sep 17 00:00:00 2001 From: MiroslavR Date: Fri, 24 Oct 2014 12:46:14 +0200 Subject: [PATCH 17/24] Reset ownership of items dropped via 'drop' instruction (Fixes #2053) --- apps/openmw/mwscript/miscextensions.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index 0de8f3b91..c7d221139 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -454,7 +454,8 @@ namespace MWScript if (::Misc::StringUtils::ciEqual(iter->getCellRef().getRefId(), item)) { int removed = store.remove(*iter, toRemove, ptr); - MWBase::Environment::get().getWorld()->dropObjectOnGround(ptr, *iter, removed); + MWWorld::Ptr dropped = MWBase::Environment::get().getWorld()->dropObjectOnGround(ptr, *iter, removed); + dropped.getCellRef().setOwner(""); toRemove -= removed; From fa746b8e54a54c3ba9fb9399d21795791dc28f3c Mon Sep 17 00:00:00 2001 From: MiroslavR Date: Fri, 24 Oct 2014 13:05:39 +0200 Subject: [PATCH 18/24] Do not display weight or value in tooltip for zero-weight items (Fixes #2047) --- apps/openmw/mwclass/light.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index 7b2d7e132..e6d266de2 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -191,8 +191,11 @@ namespace MWClass std::string text; - text += "\n#{sWeight}: " + MWGui::ToolTips::toString(ref->mBase->mData.mWeight); - text += MWGui::ToolTips::getValueString(ref->mBase->mData.mValue, "#{sValue}"); + if (ref->mBase->mData.mWeight != 0) + { + text += "\n#{sWeight}: " + MWGui::ToolTips::toString(ref->mBase->mData.mWeight); + text += MWGui::ToolTips::getValueString(ref->mBase->mData.mValue, "#{sValue}"); + } if (MWBase::Environment::get().getWindowManager()->getFullHelp()) { text += MWGui::ToolTips::getCellRefString(ptr.getCellRef()); From ed3a3f717f3387fdf8978862d78d50a0e0cc5dbd Mon Sep 17 00:00:00 2001 From: MiroslavR Date: Fri, 24 Oct 2014 18:49:38 +0200 Subject: [PATCH 19/24] Handle getdistance on objects inside a container (Fixes #2046) --- apps/openmw/mwbase/world.hpp | 4 ++ apps/openmw/mwscript/interpretercontext.cpp | 11 ++++++ apps/openmw/mwworld/cellstore.hpp | 11 ++++++ apps/openmw/mwworld/containerstore.cpp | 2 +- apps/openmw/mwworld/worldimp.cpp | 41 +++++++++++++++++++++ apps/openmw/mwworld/worldimp.hpp | 4 ++ 6 files changed, 72 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 71a45a92c..c1a889913 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -199,6 +199,10 @@ namespace MWBase virtual MWWorld::Ptr searchPtrViaActorId (int actorId) = 0; ///< Search is limited to the active cells. + virtual MWWorld::Ptr findContainer (const MWWorld::Ptr& ptr) = 0; + ///< Return a pointer to a liveCellRef which contains \a ptr. + /// \note Search is limited to the active cells. + /// \todo enable reference in the OGRE scene virtual void enable (const MWWorld::Ptr& ptr) = 0; diff --git a/apps/openmw/mwscript/interpretercontext.cpp b/apps/openmw/mwscript/interpretercontext.cpp index cb02a6c97..52021839d 100644 --- a/apps/openmw/mwscript/interpretercontext.cpp +++ b/apps/openmw/mwscript/interpretercontext.cpp @@ -21,6 +21,7 @@ #include "../mwworld/class.hpp" #include "../mwworld/cellstore.hpp" +#include "../mwworld/containerstore.hpp" #include "../mwmechanics/npcstats.hpp" @@ -434,6 +435,16 @@ namespace MWScript else ref2 = MWBase::Environment::get().getWorld()->getPtr(id, false); + if (ref2.getContainerStore()) // is the object contained? + { + MWWorld::Ptr container = MWBase::Environment::get().getWorld()->findContainer(ref2); + + if (!container.isEmpty()) + ref2 = container; + else + throw std::runtime_error("failed to find container ptr"); + } + const MWWorld::Ptr ref = MWBase::Environment::get().getWorld()->getPtr(name, false); // If the objects are in different worldspaces, return a large value (just like vanilla) diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index ba6fad7ba..e322ef4a4 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -149,6 +149,17 @@ namespace MWWorld forEachImp (functor, mCreatureLists); } + template + bool forEachContainer (Functor& functor) + { + mHasState = true; + + return + forEachImp (functor, mContainers) && + forEachImp (functor, mCreatures) && + forEachImp (functor, mNpcs); + } + bool isExterior() const; Ptr searchInContainer (const std::string& id); diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index 085b079d9..45728371b 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -272,7 +272,7 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::add (const Ptr& itemPtr item.mCell = actorPtr.getCell(); } - item.mContainerStore = 0; + item.mContainerStore = this; MWBase::Environment::get().getWorld()->getLocalScripts().add(script, item); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index d8e0d52b8..5d07a26a0 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -657,6 +657,47 @@ namespace MWWorld return mWorldScene->searchPtrViaActorId (actorId); } + struct FindContainerFunctor + { + Ptr mContainedPtr; + Ptr mResult; + + FindContainerFunctor(const Ptr& containedPtr) : mContainedPtr(containedPtr) {} + + bool operator() (Ptr ptr) + { + if (mContainedPtr.getContainerStore() == &ptr.getClass().getContainerStore(ptr)) + { + mResult = ptr; + return false; + } + + return true; + } + }; + + Ptr World::findContainer(const Ptr& ptr) + { + if (ptr.isInCell()) + return Ptr(); + + Ptr player = getPlayerPtr(); + if (ptr.getContainerStore() == &player.getClass().getContainerStore(player)) + return player; + + const Scene::CellStoreCollection& collection = mWorldScene->getActiveCells(); + for (Scene::CellStoreCollection::const_iterator cellIt = collection.begin(); cellIt != collection.end(); ++cellIt) + { + FindContainerFunctor functor(ptr); + (*cellIt)->forEachContainer(functor); + + if (!functor.mResult.isEmpty()) + return functor.mResult; + } + + return Ptr(); + } + void World::addContainerScripts(const Ptr& reference, CellStore * cell) { if( reference.getTypeName()==typeid (ESM::Container).name() || diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 334e799f2..fef279705 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -260,6 +260,10 @@ namespace MWWorld virtual Ptr searchPtrViaActorId (int actorId); ///< Search is limited to the active cells. + virtual MWWorld::Ptr findContainer (const MWWorld::Ptr& ptr); + ///< Return a pointer to a liveCellRef which contains \a ptr. + /// \note Search is limited to the active cells. + virtual void adjustPosition (const Ptr& ptr, bool force); ///< Adjust position after load to be on ground. Must be called after model load. /// @param force do this even if the ptr is flying From e01795556f3a04b4e5ff202e7c154df09b85080d Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sat, 25 Oct 2014 10:37:57 +1100 Subject: [PATCH 20/24] Suppress some warnings for MSVC. --- apps/openmw/mwgui/formatting.hpp | 1 + extern/ogre-ffmpeg-videoplayer/audiofactory.hpp | 1 + extern/ogre-ffmpeg-videoplayer/videostate.cpp | 2 +- 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/formatting.hpp b/apps/openmw/mwgui/formatting.hpp index 3e21b62e2..5b7925057 100644 --- a/apps/openmw/mwgui/formatting.hpp +++ b/apps/openmw/mwgui/formatting.hpp @@ -132,6 +132,7 @@ namespace MWGui virtual int pageSplit(); protected: + virtual ~GraphicElement() {} MyGUI::Widget * mParent; Paginator & mPaginator; BlockStyle mBlockStyle; diff --git a/extern/ogre-ffmpeg-videoplayer/audiofactory.hpp b/extern/ogre-ffmpeg-videoplayer/audiofactory.hpp index cf1ff46a8..06abd6a74 100644 --- a/extern/ogre-ffmpeg-videoplayer/audiofactory.hpp +++ b/extern/ogre-ffmpeg-videoplayer/audiofactory.hpp @@ -12,6 +12,7 @@ class MovieAudioFactory { public: virtual boost::shared_ptr createDecoder(VideoState* videoState) = 0; + virtual ~MovieAudioFactory() {} }; } diff --git a/extern/ogre-ffmpeg-videoplayer/videostate.cpp b/extern/ogre-ffmpeg-videoplayer/videostate.cpp index c77723421..ece491edc 100644 --- a/extern/ogre-ffmpeg-videoplayer/videostate.cpp +++ b/extern/ogre-ffmpeg-videoplayer/videostate.cpp @@ -221,7 +221,7 @@ void VideoState::video_refresh() } else { - const float threshold = 0.03; + const float threshold = 0.03f; if (this->pictq[pictq_rindex].pts > this->get_master_clock() + threshold) return; // not ready yet to show this picture From 69d0c7fd7090b84729fbd3ca48870b0501f1ffb4 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sat, 25 Oct 2014 10:40:33 +1100 Subject: [PATCH 21/24] Cleanup leftover from previous osx support attempts. --- cmake/FindOGRE.cmake | 1 - 1 file changed, 1 deletion(-) diff --git a/cmake/FindOGRE.cmake b/cmake/FindOGRE.cmake index 51589698f..f2acf9d33 100644 --- a/cmake/FindOGRE.cmake +++ b/cmake/FindOGRE.cmake @@ -382,7 +382,6 @@ endmacro() ogre_find_component(Paging OgrePaging.h) # look for Overlay component ogre_find_component(Overlay OgreOverlaySystem.h) -ogre_find_component(Overlay OgreOverlay.h) # look for Terrain component ogre_find_component(Terrain OgreTerrain.h) # look for Property component From ea67cf0ebeb87e29db96c555c2be217bdd91bba0 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sat, 25 Oct 2014 15:37:09 +1100 Subject: [PATCH 22/24] Try the fix again. --- extern/ogre-ffmpeg-videoplayer/audiofactory.hpp | 1 - extern/ogre-ffmpeg-videoplayer/videoplayer.cpp | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/extern/ogre-ffmpeg-videoplayer/audiofactory.hpp b/extern/ogre-ffmpeg-videoplayer/audiofactory.hpp index 06abd6a74..cf1ff46a8 100644 --- a/extern/ogre-ffmpeg-videoplayer/audiofactory.hpp +++ b/extern/ogre-ffmpeg-videoplayer/audiofactory.hpp @@ -12,7 +12,6 @@ class MovieAudioFactory { public: virtual boost::shared_ptr createDecoder(VideoState* videoState) = 0; - virtual ~MovieAudioFactory() {} }; } diff --git a/extern/ogre-ffmpeg-videoplayer/videoplayer.cpp b/extern/ogre-ffmpeg-videoplayer/videoplayer.cpp index 434b676ee..5487e916a 100644 --- a/extern/ogre-ffmpeg-videoplayer/videoplayer.cpp +++ b/extern/ogre-ffmpeg-videoplayer/videoplayer.cpp @@ -1,5 +1,6 @@ #include "videoplayer.hpp" +#include "audiofactory.hpp" #include "videostate.hpp" namespace Video From d7716e7314a4054038a5c7119d1c1f128608fa57 Mon Sep 17 00:00:00 2001 From: Lukasz Gromanowski Date: Sat, 25 Oct 2014 09:37:51 +0200 Subject: [PATCH 23/24] Fixes #1982: Long class names are cut off in the UI Corrected HBox, AutoSizedTextBox and TextBox positions and alignment. Signed-off-by: Lukasz Gromanowski --- files/mygui/openmw_stats_window.layout | 30 ++++++++++---------------- 1 file changed, 11 insertions(+), 19 deletions(-) diff --git a/files/mygui/openmw_stats_window.layout b/files/mygui/openmw_stats_window.layout index df0a3f39f..ef6db8323 100644 --- a/files/mygui/openmw_stats_window.layout +++ b/files/mygui/openmw_stats_window.layout @@ -69,47 +69,39 @@ - - - + + + - - - - + + - - + + - - - - + - - + + - - - - + From c8a273f5527fc654cf43ba3bf14e191a3fcf4d95 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 25 Oct 2014 19:57:01 +0200 Subject: [PATCH 24/24] Stats window layout fix --- files/mygui/openmw_stats_window.layout | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/files/mygui/openmw_stats_window.layout b/files/mygui/openmw_stats_window.layout index ef6db8323..11119c404 100644 --- a/files/mygui/openmw_stats_window.layout +++ b/files/mygui/openmw_stats_window.layout @@ -70,8 +70,8 @@ - - + + @@ -80,10 +80,11 @@ + - + @@ -93,9 +94,10 @@ + - + @@ -105,6 +107,7 @@ +