From b1dfb0bc294b5b5580671961e6b6829d852a73b7 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 24 Jul 2018 12:57:09 +0200 Subject: [PATCH 001/196] stage1: priorities for event music and other minor improvements to the music system --- docs/openmw-stage1.md | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/docs/openmw-stage1.md b/docs/openmw-stage1.md index 4707a4435..4290080b8 100644 --- a/docs/openmw-stage1.md +++ b/docs/openmw-stage1.md @@ -1383,9 +1383,9 @@ We add several new script instructions: * PlayBackgroundMusic (t) * PlaylistBackgroundMusic (pl) * StopBackgroundMusic -* PlayEventMusic (t, loop=0, force=0) -* PlaylistEventMusic (pl, loop=0, force=0) -* StopEventMusic +* PlayEventMusic (t, priority, loop=0, force=0) +* PlaylistEventMusic (pl, priority, loop=0, force=0) +* StopEventMusic (priority) Arguments: @@ -1393,8 +1393,14 @@ Arguments: * pl (string): a playlist (specified by its ID) * loop (integer): looping or not * force (integer): Terminate any other running event music first. If this flag is 0 and there is already event music playing the new event music is ignored. Event music provided by content developers will usually not set this flag. +* priority (integer): Priority for event music. If there are multiple instances of active event music only the one with the highest priority will play. There can only ever be one instance of event music for any priority level. If event music of higher priority stops and there is event music of lower priority the event music of lower priority starts to play. -Note: An attempt to play a track or playlist that is currently playing is ignored. In this case the track or playlist does not restart. +Note: An attempt to play a track or playlist that is currently playing is ignored. In this case the track or playlist does not restart. Changes in looping behaviour are considered though. + +New games starting with a new format omwgame file can use priorities as the developer sees fit. For old games where automatic injection of scripts and music records take place we define the following priorities: + +* 10: Combat music +* 0: Basic event music ### Transition of Existing System From a06c9c767d1beb2cc1222e3d2ed61a4c8f2cf4e4 Mon Sep 17 00:00:00 2001 From: Capostrophic <21265616+Capostrophic@users.noreply.github.com> Date: Sun, 19 Aug 2018 18:36:43 +0300 Subject: [PATCH 002/196] Treat <> and << operators as < and >< and >> as > in scripts (bug #4597) --- CHANGELOG.md | 1 + components/compiler/scanner.cpp | 10 ++++++++++ 2 files changed, 11 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d6d8df78e..4b573766a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -98,6 +98,7 @@ Bug #4575: Weird result of attack animation blending with movement animations Bug #4576: Reset of idle animations when attack can not be started Bug #4591: Attack strength should be 0 if player did not hold the attack button + Bug #4597: <> operator causes a compile error Feature #1645: Casting effects from objects Feature #2606: Editor: Implemented (optional) case sensitive global search Feature #3083: Play animation when NPC is casting spell via script diff --git a/components/compiler/scanner.cpp b/components/compiler/scanner.cpp index bb0fb9374..f159b8b8b 100644 --- a/components/compiler/scanner.cpp +++ b/components/compiler/scanner.cpp @@ -502,6 +502,11 @@ namespace Compiler if (get (c) && c!='=') // <== is a allowed as an alternative to <= :( putback (c); } + else if (c == '<' || c == '>') // Treat <> and << as < + { + special = S_cmpLT; + mErrorHandler.warning (std::string("invalid operator <") + c + ", treating it as <", mLoc); + } else { putback (c); @@ -525,6 +530,11 @@ namespace Compiler if (get (c) && c!='=') // >== is a allowed as an alternative to >= :( putback (c); } + else if (c == '<' || c == '>') // Treat >< and >> as > + { + special = S_cmpGT; + mErrorHandler.warning (std::string("invalid operator >") + c + ", treating it as >", mLoc); + } else { putback (c); From e1afa1c2c38a5b18e4fd493b7b9682569aab7792 Mon Sep 17 00:00:00 2001 From: Thunderforge Date: Mon, 20 Aug 2018 12:49:26 -0500 Subject: [PATCH 003/196] Adding common problems that were previous on the site FAQ The [OpenMW FAQ](https://openmw.org/faq/) currently has two problems on it: a black screen and pink textures due to ST3C issues. Given that these are less common now, and that we have a dedicated space for "common problems" anyway, I figure that we should just move this to these questions to there. --- .../manuals/installation/common-problems.rst | 31 ++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/docs/source/manuals/installation/common-problems.rst b/docs/source/manuals/installation/common-problems.rst index 543b8ec9b..a44f2d581 100644 --- a/docs/source/manuals/installation/common-problems.rst +++ b/docs/source/manuals/installation/common-problems.rst @@ -47,4 +47,33 @@ Installing game files via Steam on macOS: DISK WRITE ERROR [other entries] } - Restart the Steam client. The download should now proceed. \ No newline at end of file + Restart the Steam client. The download should now proceed. + +In-game textures show up as pink +################################ + +:Symptoms: + Some textures don't show up and are replaced by pink "filler" textures. + +:Cause: + Textures shipped with Morrowind are compressed with S3TC, a texture compression algorithm that was patented in + the United States until October 2017. Software drivers and operating system distributions released before that date + may not include support for this algorithm. + +:Fix: + Upgrade your graphics drivers and/or operating system the latest version. + +Music plays, but only a black screen is shown +############################################# + +:Symptoms: + When launching OpenMW, audio is heard but there is only a black screen. + +:Cause: + This can occur when you did not import the Morrowind.ini file when the launcher asked for it. + +:Fix: + To fix it, you need to delete the `launcher.cfg` file from your configuration path + ([Path description on Wiki](https://wiki.openmw.org/index.php?title=Paths)), then start the launcher, select your + Morrowind installation, and when the launcher asks whether the `Morrowind.ini` file should be imported, make sure + to select "Yes". \ No newline at end of file From 9b10fe0edb0bc940eea8addecacc696b7f6b2869 Mon Sep 17 00:00:00 2001 From: Thunderforge Date: Tue, 21 Aug 2018 07:03:55 -0500 Subject: [PATCH 004/196] Addiong missing "to" word --- docs/source/manuals/installation/common-problems.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/manuals/installation/common-problems.rst b/docs/source/manuals/installation/common-problems.rst index a44f2d581..0967ea9ef 100644 --- a/docs/source/manuals/installation/common-problems.rst +++ b/docs/source/manuals/installation/common-problems.rst @@ -61,7 +61,7 @@ In-game textures show up as pink may not include support for this algorithm. :Fix: - Upgrade your graphics drivers and/or operating system the latest version. + Upgrade your graphics drivers and/or operating system to the latest version. Music plays, but only a black screen is shown ############################################# From b77d733c3eb50623e8f7ab0407b6feca1be16e3c Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Tue, 21 Aug 2018 16:47:29 +0300 Subject: [PATCH 005/196] Fix freeze in getActorsSidingWith --- apps/openmw/mwmechanics/actors.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 6f5b4eeb8..c28f6df28 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -1790,14 +1790,13 @@ namespace MWMechanics // Actors that are targeted by this actor's Follow or Escort packages also side with them for (auto package = stats.getAiSequence().begin(); package != stats.getAiSequence().end(); ++package) { - const MWWorld::Ptr &target = (*package)->getTarget(); - if ((*package)->sideWithTarget() && !target.isEmpty()) + if ((*package)->sideWithTarget() && !(*package)->getTarget().isEmpty()) { if (iteratedActor == actor) { - list.push_back(target); + list.push_back((*package)->getTarget()); } - else if (target == actor) + else if ((*package)->getTarget() == actor) { list.push_back(iteratedActor); } From 910065f38fffce09f8db68d6598e262ad9b25c86 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Tue, 21 Aug 2018 17:02:56 +0300 Subject: [PATCH 006/196] Make some more optimizations to actor processing loops --- apps/openmw/mwmechanics/actors.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index c28f6df28..d203dccf4 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -1782,6 +1782,8 @@ namespace MWMechanics if (iteratedActor == getPlayer()) continue; + const bool sameActor = (iteratedActor == actor); + const CreatureStats &stats = iteratedActor.getClass().getCreatureStats(iteratedActor); if (stats.isDead()) continue; @@ -1792,7 +1794,7 @@ namespace MWMechanics { if ((*package)->sideWithTarget() && !(*package)->getTarget().isEmpty()) { - if (iteratedActor == actor) + if (sameActor) { list.push_back((*package)->getTarget()); } @@ -1815,7 +1817,7 @@ namespace MWMechanics for(PtrActorMap::iterator iter(mActors.begin());iter != mActors.end();++iter) { const MWWorld::Ptr &iteratedActor = iter->first; - if (iteratedActor == getPlayer()) + if (iteratedActor == getPlayer() || iteratedActor == actor) continue; const CreatureStats &stats = iteratedActor.getClass().getCreatureStats(iteratedActor); @@ -1878,7 +1880,7 @@ namespace MWMechanics for(PtrActorMap::iterator iter(mActors.begin());iter != mActors.end();++iter) { const MWWorld::Ptr &iteratedActor = iter->first; - if (iteratedActor == getPlayer()) + if (iteratedActor == getPlayer() || iteratedActor == actor) continue; const CreatureStats &stats = iteratedActor.getClass().getCreatureStats(iteratedActor); @@ -1908,8 +1910,11 @@ namespace MWMechanics getObjectsInRange(position, aiProcessingDistance, neighbors); for(auto neighbor = neighbors.begin(); neighbor != neighbors.end(); ++neighbor) { + if (*neighbor == actor) + continue; + const CreatureStats &stats = neighbor->getClass().getCreatureStats(*neighbor); - if (stats.isDead() || *neighbor == actor) + if (stats.isDead()) continue; if (stats.getAiSequence().isInCombat(actor)) From 2b45fd84ead5ee55aa5e00e6bddf61d24ea4bacb Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Sun, 19 Aug 2018 20:41:09 +0300 Subject: [PATCH 007/196] Play landing sound manually and ignore land soundgen textkeys (bug #2256) --- CHANGELOG.md | 1 + apps/openmw/mwclass/npc.cpp | 7 +++---- apps/openmw/mwmechanics/character.cpp | 10 ++++++++-- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d6d8df78e..a01948943 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ Bug #1990: Sunrise/sunset not set correct Bug #2131: Lustidrike's spell misses the player every time Bug #2222: Fatigue's effect on selling price is backwards + Bug #2256: Landing sound not playing when jumping immediately after landing Bug #2326: After a bound item expires the last equipped item of that type is not automatically re-equipped Bug #2455: Creatures attacks degrade armor Bug #2562: Forcing AI to activate a teleport door sometimes causes a crash diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index c06c3f67c..95d7fa66d 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -1241,11 +1241,10 @@ namespace MWClass { MWBase::World *world = MWBase::Environment::get().getWorld(); osg::Vec3f pos(ptr.getRefData().getPosition().asVec3()); - if(world->isUnderwater(ptr.getCell(), pos) || world->isWalkingOnWater(ptr)) + if (world->isUnderwater(ptr.getCell(), pos) || world->isWalkingOnWater(ptr)) return "DefaultLandWater"; - if(world->isOnGround(ptr)) - return "DefaultLand"; - return ""; + + return "DefaultLand"; } if(name == "swimleft") return "Swim Left"; diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index c7c6b57d0..be9daee88 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -939,10 +939,10 @@ void CharacterController::handleTextKey(const std::string &groupname, const std: } std::string sound = mPtr.getClass().getSoundIdFromSndGen(mPtr, soundgen); - if(!sound.empty()) + if(!sound.empty() && evt.compare(10, evt.size()-10, "land") != 0) // Don't play landing sounds here { MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); - if(evt.compare(10, evt.size()-10, "left") == 0 || evt.compare(10, evt.size()-10, "right") == 0 || evt.compare(10, evt.size()-10, "land") == 0) + if(evt.compare(10, evt.size()-10, "left") == 0 || evt.compare(10, evt.size()-10, "right") == 0) { // Don't make foot sounds local for the player, it makes sense to keep them // positioned on the ground. @@ -2027,6 +2027,12 @@ void CharacterController::update(float duration) cls.skillUsageSucceeded(mPtr, ESM::Skill::Acrobatics, 1); } } + + // Play landing sound + MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); + std::string sound = cls.getSoundIdFromSndGen(mPtr, "land"); + if (!sound.empty()) + sndMgr->playSound3D(mPtr, sound, 1.f, 1.f, MWSound::Type::Foot, MWSound::PlayMode::NoPlayerLocal); } else { From 5a2e9868c1e65862f6c139da338de41f9e30aa98 Mon Sep 17 00:00:00 2001 From: Thunderforge Date: Tue, 21 Aug 2018 22:13:05 -0500 Subject: [PATCH 008/196] Fixes #3681 This changes the way that the popup works to use [`QtColorDialog::getColor()`](http://doc.qt.io/archives/qt-4.8/qcolordialog.html#getColor) instead of the problematic open() function. Also makes the button change to create the modal dialog when pushed, rather than being a checkbox of sorts --- apps/opencs/view/widget/coloreditor.cpp | 19 +------------------ apps/opencs/view/widget/coloreditor.hpp | 1 - apps/opencs/view/widget/colorpickerpopup.cpp | 13 +++---------- apps/opencs/view/widget/colorpickerpopup.hpp | 2 -- 4 files changed, 4 insertions(+), 31 deletions(-) diff --git a/apps/opencs/view/widget/coloreditor.cpp b/apps/opencs/view/widget/coloreditor.cpp index 5f82f8e26..82ca2b0c9 100644 --- a/apps/opencs/view/widget/coloreditor.cpp +++ b/apps/opencs/view/widget/coloreditor.cpp @@ -1,11 +1,9 @@ #include "coloreditor.hpp" #include -#include #include #include #include -#include #include #include "colorpickerpopup.hpp" @@ -27,9 +25,7 @@ CSVWidget::ColorEditor::ColorEditor(QWidget *parent, const bool popupOnStart) mColorPicker(new ColorPickerPopup(this)), mPopupOnStart(popupOnStart) { - setCheckable(true); connect(this, SIGNAL(clicked()), this, SLOT(showPicker())); - connect(mColorPicker, SIGNAL(hid()), this, SLOT(pickerHid())); connect(mColorPicker, SIGNAL(colorChanged(const QColor &)), this, SLOT(pickerColorChanged(const QColor &))); } @@ -85,20 +81,7 @@ void CSVWidget::ColorEditor::setColor(const int colorInt) void CSVWidget::ColorEditor::showPicker() { - if (isChecked()) - { - mColorPicker->showPicker(calculatePopupPosition(), mColor); - } - else - { - mColorPicker->hide(); - } -} - -void CSVWidget::ColorEditor::pickerHid() -{ - setChecked(false); - emit pickingFinished(); + mColorPicker->showPicker(calculatePopupPosition(), mColor); } void CSVWidget::ColorEditor::pickerColorChanged(const QColor &color) diff --git a/apps/opencs/view/widget/coloreditor.hpp b/apps/opencs/view/widget/coloreditor.hpp index 668f22cc9..368896e42 100644 --- a/apps/opencs/view/widget/coloreditor.hpp +++ b/apps/opencs/view/widget/coloreditor.hpp @@ -45,7 +45,6 @@ namespace CSVWidget private slots: void showPicker(); - void pickerHid(); void pickerColorChanged(const QColor &color); signals: diff --git a/apps/opencs/view/widget/colorpickerpopup.cpp b/apps/opencs/view/widget/colorpickerpopup.cpp index 8e71ce39e..47aab8981 100644 --- a/apps/opencs/view/widget/colorpickerpopup.cpp +++ b/apps/opencs/view/widget/colorpickerpopup.cpp @@ -4,7 +4,6 @@ #include #include #include -#include #include #include @@ -19,7 +18,6 @@ CSVWidget::ColorPickerPopup::ColorPickerPopup(QWidget *parent) mColorPicker->setWindowFlags(Qt::Widget); mColorPicker->setOptions(QColorDialog::NoButtons | QColorDialog::DontUseNativeDialog); mColorPicker->installEventFilter(this); - mColorPicker->open(); connect(mColorPicker, SIGNAL(currentColorChanged(const QColor &)), this, @@ -39,8 +37,9 @@ void CSVWidget::ColorPickerPopup::showPicker(const QPoint &position, const QColo geometry.moveTo(position); setGeometry(geometry); - mColorPicker->setCurrentColor(initialColor); - show(); + // Calling getColor() creates a blocking dialog that will continue execution once the user chooses OK or Cancel + QColor color = mColorPicker->getColor(initialColor); + mColorPicker->setCurrentColor(color); } void CSVWidget::ColorPickerPopup::mousePressEvent(QMouseEvent *event) @@ -63,12 +62,6 @@ void CSVWidget::ColorPickerPopup::mousePressEvent(QMouseEvent *event) QFrame::mousePressEvent(event); } -void CSVWidget::ColorPickerPopup::hideEvent(QHideEvent *event) -{ - QFrame::hideEvent(event); - emit hid(); -} - bool CSVWidget::ColorPickerPopup::eventFilter(QObject *object, QEvent *event) { if (object == mColorPicker && event->type() == QEvent::KeyPress) diff --git a/apps/opencs/view/widget/colorpickerpopup.hpp b/apps/opencs/view/widget/colorpickerpopup.hpp index 602bbdb6d..eb5653f46 100644 --- a/apps/opencs/view/widget/colorpickerpopup.hpp +++ b/apps/opencs/view/widget/colorpickerpopup.hpp @@ -20,11 +20,9 @@ namespace CSVWidget protected: virtual void mousePressEvent(QMouseEvent *event); - virtual void hideEvent(QHideEvent *event); virtual bool eventFilter(QObject *object, QEvent *event); signals: - void hid(); void colorChanged(const QColor &color); }; } From ae0a6a22b3a0cdcfda40dec66e1963e90fdb1930 Mon Sep 17 00:00:00 2001 From: Capostrophic <21265616+Capostrophic@users.noreply.github.com> Date: Wed, 22 Aug 2018 14:43:12 +0300 Subject: [PATCH 009/196] Move "land" check earlier --- apps/openmw/mwmechanics/character.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index be9daee88..686d0924a 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -913,7 +913,8 @@ void CharacterController::handleTextKey(const std::string &groupname, const std: sndMgr->playSound3D(mPtr, evt.substr(7), 1.0f, 1.0f); return; } - if(evt.compare(0, 10, "soundgen: ") == 0) + if(evt.compare(0, 10, "soundgen: ") == 0 + && evt.compare(10, evt.size()-10, "land") != 0) // Morrowind ignores land soundgen for some reason { std::string soundgen = evt.substr(10); @@ -939,7 +940,7 @@ void CharacterController::handleTextKey(const std::string &groupname, const std: } std::string sound = mPtr.getClass().getSoundIdFromSndGen(mPtr, soundgen); - if(!sound.empty() && evt.compare(10, evt.size()-10, "land") != 0) // Don't play landing sounds here + if(!sound.empty()) { MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); if(evt.compare(10, evt.size()-10, "left") == 0 || evt.compare(10, evt.size()-10, "right") == 0) From f74ebb64af6e9d64e6d180de9b49badc424762da Mon Sep 17 00:00:00 2001 From: Capostrophic <21265616+Capostrophic@users.noreply.github.com> Date: Wed, 22 Aug 2018 15:26:21 +0300 Subject: [PATCH 010/196] Correct special case soundgen comparisons --- apps/openmw/mwmechanics/character.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 686d0924a..49e2c4e6d 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -913,8 +913,7 @@ void CharacterController::handleTextKey(const std::string &groupname, const std: sndMgr->playSound3D(mPtr, evt.substr(7), 1.0f, 1.0f); return; } - if(evt.compare(0, 10, "soundgen: ") == 0 - && evt.compare(10, evt.size()-10, "land") != 0) // Morrowind ignores land soundgen for some reason + if(evt.compare(0, 10, "soundgen: ") == 0) { std::string soundgen = evt.substr(10); @@ -939,11 +938,14 @@ void CharacterController::handleTextKey(const std::string &groupname, const std: } } + if (soundgen == "land") // Morrowind ignores land soundgen for some reason + return; + std::string sound = mPtr.getClass().getSoundIdFromSndGen(mPtr, soundgen); if(!sound.empty()) { MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); - if(evt.compare(10, evt.size()-10, "left") == 0 || evt.compare(10, evt.size()-10, "right") == 0) + if(soundgen == "left" || soundgen == "right") { // Don't make foot sounds local for the player, it makes sense to keep them // positioned on the ground. From 3f76f1d3ed4d45e53fb72fdc923dd5389e79a69b Mon Sep 17 00:00:00 2001 From: Capostrophic <21265616+Capostrophic@users.noreply.github.com> Date: Wed, 22 Aug 2018 22:30:46 +0300 Subject: [PATCH 011/196] Fix gold count calculation in pickupObject (bug #4604) --- CHANGELOG.md | 1 + apps/openmw/mwgui/inventorywindow.cpp | 2 ++ 2 files changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4b573766a..cf1bf91d4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -99,6 +99,7 @@ Bug #4576: Reset of idle animations when attack can not be started Bug #4591: Attack strength should be 0 if player did not hold the attack button Bug #4597: <> operator causes a compile error + Bug #4604: Picking up gold from the ground only makes 1 grabbed Feature #1645: Casting effects from objects Feature #2606: Editor: Implemented (optional) case sensitive global search Feature #3083: Play animation when NPC is casting spell via script diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 0b35bd9de..523409ceb 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -681,6 +681,8 @@ namespace MWGui return; int count = object.getRefData().getCount(); + if (object.getClass().isGold(object)) + count *= object.getClass().getValue(object); MWWorld::Ptr player = MWMechanics::getPlayer(); MWBase::Environment::get().getWorld()->breakInvisibility(player); From 3d4f5536d238d0957e8e53843af4a55eb76f3ee6 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Fri, 24 Aug 2018 15:03:54 +0400 Subject: [PATCH 012/196] Check for impact immediately when launch a projectile (bug #3059) --- CHANGELOG.md | 1 + apps/openmw/mwbase/world.hpp | 4 ++-- apps/openmw/mwrender/weaponanimation.cpp | 9 ++++--- apps/openmw/mwworld/worldimp.cpp | 30 +++++++++++++++++++++--- apps/openmw/mwworld/worldimp.hpp | 4 ++-- 5 files changed, 38 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9c4c96cf9..1b8afe14b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ Bug #2872: Tab completion in console doesn't work with explicit reference Bug #2971: Compiler did not reject lines with naked expressions beginning with x.y Bug #3049: Drain and Fortify effects are not properly applied on health, magicka and fatigue + Bug #3059: Unable to hit with marksman weapons when too close to an enemy Bug #3072: Fatal error on AddItem that has a script containing Equip Bug #3249: Fixed revert function not updating views properly Bug #3374: Touch spells not hitting kwama foragers diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 3c46298b0..5561d13ca 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -490,8 +490,8 @@ namespace MWBase virtual void castSpell (const MWWorld::Ptr& actor, bool manualSpell=false) = 0; virtual void launchMagicBolt (const std::string& spellId, const MWWorld::Ptr& caster, const osg::Vec3f& fallbackDirection) = 0; - virtual void launchProjectile (MWWorld::Ptr actor, MWWorld::ConstPtr projectile, - const osg::Vec3f& worldPos, const osg::Quat& orient, MWWorld::Ptr bow, float speed, float attackStrength) = 0; + virtual void launchProjectile (MWWorld::Ptr& actor, MWWorld::Ptr& projectile, + const osg::Vec3f& worldPos, const osg::Quat& orient, MWWorld::Ptr& bow, float speed, float attackStrength) = 0; virtual void applyLoopingParticles(const MWWorld::Ptr& ptr) = 0; diff --git a/apps/openmw/mwrender/weaponanimation.cpp b/apps/openmw/mwrender/weaponanimation.cpp index 0b3d000f3..054ce1b1d 100644 --- a/apps/openmw/mwrender/weaponanimation.cpp +++ b/apps/openmw/mwrender/weaponanimation.cpp @@ -123,7 +123,8 @@ void WeaponAnimation::releaseArrow(MWWorld::Ptr actor, float attackStrength) float fThrownWeaponMaxSpeed = gmst.find("fThrownWeaponMaxSpeed")->getFloat(); float speed = fThrownWeaponMinSpeed + (fThrownWeaponMaxSpeed - fThrownWeaponMinSpeed) * attackStrength; - MWBase::Environment::get().getWorld()->launchProjectile(actor, *weapon, launchPos, orient, *weapon, speed, attackStrength); + MWWorld::Ptr weaponPtr = *weapon; + MWBase::Environment::get().getWorld()->launchProjectile(actor, weaponPtr, launchPos, orient, weaponPtr, speed, attackStrength); showWeapon(false); @@ -149,9 +150,11 @@ void WeaponAnimation::releaseArrow(MWWorld::Ptr actor, float attackStrength) float fProjectileMaxSpeed = gmst.find("fProjectileMaxSpeed")->getFloat(); float speed = fProjectileMinSpeed + (fProjectileMaxSpeed - fProjectileMinSpeed) * attackStrength; - MWBase::Environment::get().getWorld()->launchProjectile(actor, *ammo, launchPos, orient, *weapon, speed, attackStrength); + MWWorld::Ptr weaponPtr = *weapon; + MWWorld::Ptr ammoPtr = *ammo; + MWBase::Environment::get().getWorld()->launchProjectile(actor, ammoPtr, launchPos, orient, weaponPtr, speed, attackStrength); - inv.remove(*ammo, 1, actor); + inv.remove(ammoPtr, 1, actor); mAmmunition.reset(); } } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index c2ebac8fc..ae00595bb 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2892,10 +2892,34 @@ namespace MWWorld } } - void World::launchProjectile (MWWorld::Ptr actor, MWWorld::ConstPtr projectile, - const osg::Vec3f& worldPos, const osg::Quat& orient, MWWorld::Ptr bow, float speed, float attackStrength) + void World::launchProjectile (MWWorld::Ptr& actor, MWWorld::Ptr& projectile, + const osg::Vec3f& worldPos, const osg::Quat& orient, MWWorld::Ptr& bow, float speed, float attackStrength) { - mProjectileManager->launchProjectile(actor, projectile, worldPos, orient, bow, speed, attackStrength); + // An initial position of projectile can be outside shooter's collision box, so any object between shooter and launch position will be ignored. + // To avoid this issue, we should check for impact immediately before launch the projectile. + // So we cast a 1-yard-length ray from shooter to launch position and check if there are collisions in this area. + // TODO: as a better solutuon we should handle projectiles during physics update, not during world update. + const osg::Vec3f sourcePos = worldPos + orient * osg::Vec3f(0,-1,0) * 64.f; + + // Early out if the launch position is underwater + bool underwater = MWBase::Environment::get().getWorld()->isUnderwater(MWMechanics::getPlayer().getCell(), worldPos); + if (underwater) + { + mRendering->emitWaterRipple(worldPos); + return; + } + + // For AI actors, get combat targets to use in the ray cast. Only those targets will return a positive hit result. + std::vector targetActors; + if (!actor.isEmpty() && actor.getClass().isActor() && actor != MWMechanics::getPlayer()) + actor.getClass().getCreatureStats(actor).getAiSequence().getCombatTargets(targetActors); + + // Check for impact, if yes, handle hit, if not, launch projectile + MWPhysics::PhysicsSystem::RayResult result = mPhysics->castRay(sourcePos, worldPos, actor, targetActors, 0xff, MWPhysics::CollisionType_Projectile); + if (result.mHit) + MWMechanics::projectileHit(actor, result.mHitObject, bow, projectile, result.mHitPos, attackStrength); + else + mProjectileManager->launchProjectile(actor, projectile, worldPos, orient, bow, speed, attackStrength); } void World::launchMagicBolt (const std::string &spellId, const MWWorld::Ptr& caster, const osg::Vec3f& fallbackDirection) diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 432991059..1c055cbf7 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -607,8 +607,8 @@ namespace MWWorld void castSpell (const MWWorld::Ptr& actor, bool manualSpell=false) override; void launchMagicBolt (const std::string& spellId, const MWWorld::Ptr& caster, const osg::Vec3f& fallbackDirection) override; - void launchProjectile (MWWorld::Ptr actor, MWWorld::ConstPtr projectile, - const osg::Vec3f& worldPos, const osg::Quat& orient, MWWorld::Ptr bow, float speed, float attackStrength) override; + void launchProjectile (MWWorld::Ptr& actor, MWWorld::Ptr& projectile, + const osg::Vec3f& worldPos, const osg::Quat& orient, MWWorld::Ptr& bow, float speed, float attackStrength) override; void applyLoopingParticles(const MWWorld::Ptr& ptr) override; From a560a9e00d93b1bdd00f4971a72b0645c969944c Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sat, 18 Aug 2018 16:12:01 +0400 Subject: [PATCH 013/196] Allow messageboxes arguments to have newline characters (bug #3836) --- CHANGELOG.md | 1 + components/compiler/scanner.cpp | 32 +++++++++++++++++++++++++++----- components/compiler/scanner.hpp | 6 ++++++ 3 files changed, 34 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c016ca82f..945d114b7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,7 @@ Bug #3591: Angled hit distance too low Bug #3629: DB assassin attack never triggers creature spawning Bug #3788: GetPCInJail and GetPCTraveling do not work as in vanilla + Bug #3836: Script fails to compile when command argument contains "\n" Bug #3876: Landscape texture painting is misaligned Bug #3897: Have Goodbye give all choices the effects of Goodbye Bug #3911: [macOS] Typing in the "Content List name" dialog box produces double characters diff --git a/components/compiler/scanner.cpp b/components/compiler/scanner.cpp index bb0fb9374..257c3314e 100644 --- a/components/compiler/scanner.cpp +++ b/components/compiler/scanner.cpp @@ -306,10 +306,22 @@ namespace Compiler int i = 0; std::string lowerCase = Misc::StringUtils::lowerCase(name); - + bool isKeyword = false; for (; sKeywords[i]; ++i) if (lowerCase==sKeywords[i]) + { + isKeyword = true; break; + } + + // Russian localization and some mods use a quirk - add newline character directly + // to compiled bytecode via HEX-editor to implement multiline messageboxes. + // Of course, original editor will not compile such script. + // Allow messageboxes to bybass the "incomplete string or name" error. + if (lowerCase == "messagebox") + enableIgnoreNewlines(); + else if (isKeyword) + mIgnoreNewline = false; if (sKeywords[i]) { @@ -357,9 +369,14 @@ namespace Compiler // } else if (c=='\n') { - error = true; - mErrorHandler.error ("incomplete string or name", mLoc); - break; + if (mIgnoreNewline) + mErrorHandler.warning ("string contains newline character, make sure that it is intended", mLoc); + else + { + error = true; + mErrorHandler.error ("incomplete string or name", mLoc); + break; + } } } else if (!(c=='"' && name.empty())) @@ -578,7 +595,7 @@ namespace Compiler const Extensions *extensions) : mErrorHandler (errorHandler), mStream (inputStream), mExtensions (extensions), mPutback (Putback_None), mPutbackCode(0), mPutbackInteger(0), mPutbackFloat(0), - mStrictKeywords (false), mTolerantNames (false) + mStrictKeywords (false), mTolerantNames (false), mIgnoreNewline(false) { } @@ -631,6 +648,11 @@ namespace Compiler mExtensions->listKeywords (keywords); } + void Scanner::enableIgnoreNewlines() + { + mIgnoreNewline = true; + } + void Scanner::enableStrictKeywords() { mStrictKeywords = true; diff --git a/components/compiler/scanner.hpp b/components/compiler/scanner.hpp index 49fbaa96a..a431cabb2 100644 --- a/components/compiler/scanner.hpp +++ b/components/compiler/scanner.hpp @@ -39,6 +39,7 @@ namespace Compiler TokenLoc mPutbackLoc; bool mStrictKeywords; bool mTolerantNames; + bool mIgnoreNewline; public: @@ -126,6 +127,11 @@ namespace Compiler void listKeywords (std::vector& keywords); ///< Append all known keywords to \a keywords. + /// Treat newline character as a part of script command. + /// + /// \attention This mode lasts only until the next keyword is reached. + void enableIgnoreNewlines(); + /// Do not accept keywords in quotation marks anymore. /// /// \attention This mode lasts only until the next newline is reached. From 4dd9386c4f04e1e45c1d377e9ac560d9ac0539e2 Mon Sep 17 00:00:00 2001 From: Sophie Kirschner Date: Fri, 24 Aug 2018 16:41:52 +0300 Subject: [PATCH 014/196] Fix error: member access into incomplete type 'SceneUtil::UnrefWorkItem' Fixes compile error encountered on OSX 10.9 with g++ sophie:build pineapple$ g++ --version Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/usr/include/c++/4.2.1 Apple LLVM version 6.0 (clang-600.0.56) (based on LLVM 3.5svn) Target: x86_64-apple-darwin13.4.0 Thread model: posix The compilation error: [ 24%] Building CXX object apps/openmw/CMakeFiles/openmw.dir/mwrender/renderingmanager.cpp.o In file included from /Users/pineapple/git/openmw/apps/openmw/mwrender/renderingmanager.cpp:1: In file included from /Users/pineapple/git/openmw/apps/openmw/mwrender/renderingmanager.hpp:4: /Users/pineapple/git/openmw/openmw-deps/include/osg/ref_ptr:35:36: error: member access into incomplete type 'SceneUtil::UnrefWorkItem' ~ref_ptr() { if (_ptr) _ptr->unref(); _ptr = 0; } ^ /Users/pineapple/git/openmw/./components/sceneutil/unrefqueue.hpp:14:11: note: in instantiation of member function 'osg::ref_ptr::~ref_ptr' requested here class UnrefQueue : public osg::Referenced ^ /Users/pineapple/git/openmw/./components/sceneutil/unrefqueue.hpp:10:11: note: forward declaration of 'SceneUtil::UnrefWorkItem' class UnrefWorkItem; --- components/sceneutil/unrefqueue.cpp | 22 ++++++---------------- components/sceneutil/unrefqueue.hpp | 12 +++++++++++- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/components/sceneutil/unrefqueue.cpp b/components/sceneutil/unrefqueue.cpp index 42ea31133..271c17af2 100644 --- a/components/sceneutil/unrefqueue.cpp +++ b/components/sceneutil/unrefqueue.cpp @@ -1,28 +1,18 @@ #include "unrefqueue.hpp" -#include - //#include //#include -#include namespace SceneUtil { - - class UnrefWorkItem : public SceneUtil::WorkItem + void UnrefWorkItem::doWork() { - public: - std::deque > mObjects; - - virtual void doWork() - { - //osg::Timer timer; - //size_t objcount = mObjects.size(); - mObjects.clear(); - //Log(Debug::Verbose) << "cleared " << objcount << " objects in " << timer.time_m(); - } - }; + //osg::Timer timer; + //size_t objcount = mObjects.size(); + mObjects.clear(); + //Log(Debug::Verbose) << "cleared " << objcount << " objects in " << timer.time_m(); + } UnrefQueue::UnrefQueue() { diff --git a/components/sceneutil/unrefqueue.hpp b/components/sceneutil/unrefqueue.hpp index 4a2724927..7155e669c 100644 --- a/components/sceneutil/unrefqueue.hpp +++ b/components/sceneutil/unrefqueue.hpp @@ -1,13 +1,23 @@ #ifndef OPENMW_COMPONENTS_UNREFQUEUE_H #define OPENMW_COMPONENTS_UNREFQUEUE_H +#include + #include #include +#include + namespace SceneUtil { class WorkQueue; - class UnrefWorkItem; + + class UnrefWorkItem : public SceneUtil::WorkItem + { + public: + std::deque > mObjects; + virtual void doWork(); + }; /// @brief Handles unreferencing of objects through the WorkQueue. Typical use scenario /// would be the main thread pushing objects that are no longer needed, and the background thread deleting them. From 67055b18c41a2599128f9e7bac1348467dd18a27 Mon Sep 17 00:00:00 2001 From: Thunderforge Date: Fri, 24 Aug 2018 12:51:18 -0500 Subject: [PATCH 015/196] Adding Changelog entry --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d6d8df78e..b77c5be1f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,7 @@ Bug #3533: GetSpellEffects should detect effects with zero duration Bug #3591: Angled hit distance too low Bug #3629: DB assassin attack never triggers creature spawning + Bug #3681: OpenMW-CS: Clicking Scripts in Preferences spawns many color pickers Bug #3788: GetPCInJail and GetPCTraveling do not work as in vanilla Bug #3876: Landscape texture painting is misaligned Bug #3897: Have Goodbye give all choices the effects of Goodbye From de08c1cb1b024761671a00a27621268d66c0fef6 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sat, 25 Aug 2018 10:34:33 +0400 Subject: [PATCH 016/196] Make Move and MoveWorld console commands move actors standing on moving object (bug #2274) --- CHANGELOG.md | 1 + apps/openmw/mwbase/world.hpp | 1 + .../mwscript/transformationextensions.cpp | 35 +++++++++++++------ apps/openmw/mwworld/worldimp.cpp | 5 +++ apps/openmw/mwworld/worldimp.hpp | 1 + 5 files changed, 33 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9c4c96cf9..0fe2edb0b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ Bug #2131: Lustidrike's spell misses the player every time Bug #2222: Fatigue's effect on selling price is backwards Bug #2256: Landing sound not playing when jumping immediately after landing + Bug #2274: Thin platform clips through player character instead of lifting Bug #2326: After a bound item expires the last equipped item of that type is not automatically re-equipped Bug #2455: Creatures attacks degrade armor Bug #2562: Forcing AI to activate a teleport door sometimes causes a crash diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 3c46298b0..115d2a217 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -412,6 +412,7 @@ namespace MWBase /// @note throws an exception when invoked on a teleport door virtual void activateDoor(const MWWorld::Ptr& door, int state) = 0; + virtual void getActorsStandingOn (const MWWorld::ConstPtr& object, std::vector &actors) = 0; ///< get a list of actors standing on \a object virtual bool getPlayerStandingOn (const MWWorld::ConstPtr& object) = 0; ///< @return true if the player is standing on \a object virtual bool getActorStandingOn (const MWWorld::ConstPtr& object) = 0; ///< @return true if any actor is standing on \a object virtual bool getPlayerCollidingWith(const MWWorld::ConstPtr& object) = 0; ///< @return true if the player is colliding with \a object diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index 8f0c72519..16d7e8036 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -29,6 +29,18 @@ namespace MWScript { namespace Transformation { + void moveStandingActors(const MWWorld::Ptr &ptr, const osg::Vec3f& diff) + { + std::vector actors; + MWBase::Environment::get().getWorld()->getActorsStandingOn (ptr, actors); + for (auto& actor : actors) + { + osg::Vec3f actorPos(actor.getRefData().getPosition().asVec3()); + actorPos += diff; + MWBase::Environment::get().getWorld()->moveObject(actor, actorPos.x(), actorPos.y(), actorPos.z()); + } + } + template class OpSetScale : public Interpreter::Opcode0 { @@ -666,6 +678,10 @@ namespace MWScript osg::Vec3f diff = ptr.getRefData().getBaseNode()->getAttitude() * posChange; osg::Vec3f worldPos(ptr.getRefData().getPosition().asVec3()); worldPos += diff; + + // We should move actors, standing on moving object, too. + // This approach can be used to create elevators. + moveStandingActors(ptr, diff); MWBase::Environment::get().getWorld()->moveObject(ptr, worldPos.x(), worldPos.y(), worldPos.z()); } }; @@ -688,22 +704,21 @@ namespace MWScript runtime.pop(); const float *objPos = ptr.getRefData().getPosition().pos; + osg::Vec3f diff; - MWWorld::Ptr updated; if (axis == "x") - { - updated = MWBase::Environment::get().getWorld()->moveObject(ptr, objPos[0]+movement, objPos[1], objPos[2]); - } + diff.x() += movement; else if (axis == "y") - { - updated = MWBase::Environment::get().getWorld()->moveObject(ptr, objPos[0], objPos[1]+movement, objPos[2]); - } + diff.y() += movement; else if (axis == "z") - { - updated = MWBase::Environment::get().getWorld()->moveObject(ptr, objPos[0], objPos[1], objPos[2]+movement); - } + diff.z() += movement; else throw std::runtime_error ("invalid movement axis: " + axis); + + // We should move actors, standing on moving object, too. + // This approach can be used to create elevators. + moveStandingActors(ptr, diff); + MWBase::Environment::get().getWorld()->moveObject(ptr, objPos[0]+diff.x(), objPos[1]+diff.y(), objPos[2]+diff.z()); } }; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index c2ebac8fc..3ae5fd317 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2377,6 +2377,11 @@ namespace MWWorld return !actors.empty(); } + void World::getActorsStandingOn (const MWWorld::ConstPtr& object, std::vector &actors) + { + mPhysics->getActorsStandingOn(object, actors); + } + bool World::getPlayerCollidingWith (const MWWorld::ConstPtr& object) { MWWorld::Ptr player = getPlayerPtr(); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 432991059..ca87ae5e3 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -525,6 +525,7 @@ namespace MWWorld /// @note throws an exception when invoked on a teleport door void activateDoor(const MWWorld::Ptr& door, int state) override; + void getActorsStandingOn (const MWWorld::ConstPtr& object, std::vector &actors); ///< get a list of actors standing on \a object bool getPlayerStandingOn (const MWWorld::ConstPtr& object) override; ///< @return true if the player is standing on \a object bool getActorStandingOn (const MWWorld::ConstPtr& object) override; ///< @return true if any actor is standing on \a object bool getPlayerCollidingWith(const MWWorld::ConstPtr& object) override; ///< @return true if the player is colliding with \a object From 4e3ae85c110591094745f7197cc445d913ec6dc3 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 24 Aug 2018 01:54:50 -0700 Subject: [PATCH 017/196] Set the OpenAL source offset after setting the buffer This is to work around a bug in the Rapture3D driver. --- apps/openmw/mwsound/openal_output.cpp | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index 3569cd3da..076162fde 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -1145,14 +1145,24 @@ bool OpenAL_Output::playSound(Sound *sound, Sound_Handle data, float offset) initCommon2D(source, sound->getPosition(), sound->getRealVolume(), sound->getPitch(), sound->getIsLooping(), sound->getUseEnv()); + alSourcei(source, AL_BUFFER, GET_PTRID(data)); alSourcef(source, AL_SEC_OFFSET, offset); if(getALError() != AL_NO_ERROR) + { + alSourceRewind(source); + alSourcei(source, AL_BUFFER, 0); + alGetError(); return false; + } - alSourcei(source, AL_BUFFER, GET_PTRID(data)); alSourcePlay(source); if(getALError() != AL_NO_ERROR) + { + alSourceRewind(source); + alSourcei(source, AL_BUFFER, 0); + alGetError(); return false; + } mFreeSources.pop_front(); sound->mHandle = MAKE_PTRID(source); @@ -1175,14 +1185,24 @@ bool OpenAL_Output::playSound3D(Sound *sound, Sound_Handle data, float offset) initCommon3D(source, sound->getPosition(), sound->getMinDistance(), sound->getMaxDistance(), sound->getRealVolume(), sound->getPitch(), sound->getIsLooping(), sound->getUseEnv()); + alSourcei(source, AL_BUFFER, GET_PTRID(data)); alSourcef(source, AL_SEC_OFFSET, offset); if(getALError() != AL_NO_ERROR) + { + alSourceRewind(source); + alSourcei(source, AL_BUFFER, 0); + alGetError(); return false; + } - alSourcei(source, AL_BUFFER, GET_PTRID(data)); alSourcePlay(source); if(getALError() != AL_NO_ERROR) + { + alSourceRewind(source); + alSourcei(source, AL_BUFFER, 0); + alGetError(); return false; + } mFreeSources.pop_front(); sound->mHandle = MAKE_PTRID(source); From c2b3ca9638199a50f4d2f50cc3fdbdc26496088a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 24 Aug 2018 05:48:14 -0700 Subject: [PATCH 018/196] Update some comments It wasn't actually a bug in OSX like the comment said, but intended behavior. --- apps/openmw/mwsound/openal_output.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index 076162fde..42dd6b5fd 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -1217,9 +1217,8 @@ void OpenAL_Output::finishSound(Sound *sound) ALuint source = GET_PTRID(sound->mHandle); sound->mHandle = 0; - // Rewind the stream instead of stopping it, this puts the source into an AL_INITIAL state, - // which works around a bug in the MacOS OpenAL implementation which would otherwise think - // the initial queue already played when it hasn't. + // Rewind the stream to put the source back into an AL_INITIAL state, for + // the next time it's used. alSourceRewind(source); alSourcei(source, AL_BUFFER, 0); getALError(); @@ -1322,9 +1321,8 @@ void OpenAL_Output::finishStream(Stream *sound) sound->mHandle = 0; mStreamThread->remove(stream); - // Rewind the stream instead of stopping it, this puts the source into an AL_INITIAL state, - // which works around a bug in the MacOS OpenAL implementation which would otherwise think - // the initial queue already played when it hasn't. + // Rewind the stream to put the source back into an AL_INITIAL state, for + // the next time it's used. alSourceRewind(source); alSourcei(source, AL_BUFFER, 0); getALError(); From 77bdd0ea662d34f75bb4291e46de55b0e08a5b58 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 25 Aug 2018 01:24:19 -0700 Subject: [PATCH 019/196] Update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index bfb77be8d..ef417facb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -129,6 +129,7 @@ Feature #4581: Use proper logging system Task #2490: Don't open command prompt window on Release-mode builds automatically Task #4545: Enable is_pod string test + Task #4606: Support Rapture3D's OpenAL driver 0.44.0 ------ From dd01c4d2240acc21a220f1fd60ac6e6081b1cb05 Mon Sep 17 00:00:00 2001 From: Sophie Kirschner Date: Sat, 25 Aug 2018 11:53:43 +0300 Subject: [PATCH 020/196] Fix: 'sizeof' to an incomplete type 'Video::VideoPlayer' Alternate solution to same problem reported in https://github.com/OpenMW/openmw/pull/1888 --- apps/openmw/mwgui/videowidget.cpp | 2 ++ apps/openmw/mwgui/videowidget.hpp | 2 ++ 2 files changed, 4 insertions(+) diff --git a/apps/openmw/mwgui/videowidget.cpp b/apps/openmw/mwgui/videowidget.cpp index 516f5cfcc..28432b811 100644 --- a/apps/openmw/mwgui/videowidget.cpp +++ b/apps/openmw/mwgui/videowidget.cpp @@ -22,6 +22,8 @@ VideoWidget::VideoWidget() setNeedKeyFocus(true); } +VideoWidget::~VideoWidget() = default; + void VideoWidget::setVFS(const VFS::Manager *vfs) { mVFS = vfs; diff --git a/apps/openmw/mwgui/videowidget.hpp b/apps/openmw/mwgui/videowidget.hpp index ac240e69d..20af579a2 100644 --- a/apps/openmw/mwgui/videowidget.hpp +++ b/apps/openmw/mwgui/videowidget.hpp @@ -25,6 +25,8 @@ namespace MWGui MYGUI_RTTI_DERIVED(VideoWidget) VideoWidget(); + + ~VideoWidget(); /// Set the VFS (virtual file system) to find the videos on. void setVFS(const VFS::Manager* vfs); From c6dcfd1fcec013b32f47c60d64e2d0aebeab669e Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sat, 25 Aug 2018 17:26:17 +0400 Subject: [PATCH 021/196] Do not apply scale twice for animated collision nodes (bug #4607) --- CHANGELOG.md | 1 + apps/openmw/mwphysics/physicssystem.cpp | 5 ++--- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bfb77be8d..735d7683d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -104,6 +104,7 @@ Bug #4591: Attack strength should be 0 if player did not hold the attack button Bug #4597: <> operator causes a compile error Bug #4604: Picking up gold from the ground only makes 1 grabbed + Bug #4607: Scaling for animated collision shapes is applied twice Feature #1645: Casting effects from objects Feature #2606: Editor: Implemented (optional) case sensitive global search Feature #3083: Play animation when NPC is casting spell via script diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 13a0f23ac..2a7b65cac 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -650,7 +650,6 @@ namespace MWPhysics osg::NodePath& nodePath = nodePathFound->second; osg::Matrixf matrix = osg::computeLocalToWorld(nodePath); - osg::Vec3f scale = matrix.getScale(); matrix.orthoNormalize(matrix); btTransform transform; @@ -659,8 +658,8 @@ namespace MWPhysics for (int j=0; j<3; ++j) transform.getBasis()[i][j] = matrix(j,i); // NB column/row major difference - if (compound->getLocalScaling() * toBullet(scale) != compound->getChildShape(shapeIndex)->getLocalScaling()) - compound->getChildShape(shapeIndex)->setLocalScaling(compound->getLocalScaling() * toBullet(scale)); + // Note: we can not apply scaling here for now since we treat scaled shapes + // as new shapes (btScaledBvhTriangleMeshShape) with 1.0 scale for now if (!(transform == compound->getChildTransform(shapeIndex))) compound->updateChildTransform(shapeIndex, transform); } From ff241fb7873ce412282eba10cc6c42a5b87b017e Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Wed, 22 Aug 2018 12:48:05 +0400 Subject: [PATCH 022/196] Optimize skinning (task #4605) --- CHANGELOG.md | 1 + components/sceneutil/riggeometry.cpp | 77 ++++++++++++++-------------- 2 files changed, 40 insertions(+), 38 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4b573766a..b7f3272d4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -124,6 +124,7 @@ Feature #4581: Use proper logging system Task #2490: Don't open command prompt window on Release-mode builds automatically Task #4545: Enable is_pod string test + Task #4605: Optimize skinning 0.44.0 ------ diff --git a/components/sceneutil/riggeometry.cpp b/components/sceneutil/riggeometry.cpp index ee30f1c85..c409bcd5c 100644 --- a/components/sceneutil/riggeometry.cpp +++ b/components/sceneutil/riggeometry.cpp @@ -8,6 +8,31 @@ #include "skeleton.hpp" #include "util.hpp" +namespace +{ + inline void accumulateMatrix(const osg::Matrixf& invBindMatrix, const osg::Matrixf& matrix, const float weight, osg::Matrixf& result) + { + osg::Matrixf m = invBindMatrix * matrix; + float* ptr = m.ptr(); + float* ptrresult = result.ptr(); + ptrresult[0] += ptr[0] * weight; + ptrresult[1] += ptr[1] * weight; + ptrresult[2] += ptr[2] * weight; + + ptrresult[4] += ptr[4] * weight; + ptrresult[5] += ptr[5] * weight; + ptrresult[6] += ptr[6] * weight; + + ptrresult[8] += ptr[8] * weight; + ptrresult[9] += ptr[9] * weight; + ptrresult[10] += ptr[10] * weight; + + ptrresult[12] += ptr[12] * weight; + ptrresult[13] += ptr[13] * weight; + ptrresult[14] += ptr[14] * weight; + } +} + namespace SceneUtil { @@ -141,28 +166,6 @@ bool RigGeometry::initFromParentSkeleton(osg::NodeVisitor* nv) return true; } -void accumulateMatrix(const osg::Matrixf& invBindMatrix, const osg::Matrixf& matrix, float weight, osg::Matrixf& result) -{ - osg::Matrixf m = invBindMatrix * matrix; - float* ptr = m.ptr(); - float* ptrresult = result.ptr(); - ptrresult[0] += ptr[0] * weight; - ptrresult[1] += ptr[1] * weight; - ptrresult[2] += ptr[2] * weight; - - ptrresult[4] += ptr[4] * weight; - ptrresult[5] += ptr[5] * weight; - ptrresult[6] += ptr[6] * weight; - - ptrresult[8] += ptr[8] * weight; - ptrresult[9] += ptr[9] * weight; - ptrresult[10] += ptr[10] * weight; - - ptrresult[12] += ptr[12] * weight; - ptrresult[13] += ptr[13] * weight; - ptrresult[14] += ptr[14] * weight; -} - void RigGeometry::cull(osg::NodeVisitor* nv) { if (!mSkeleton) @@ -173,7 +176,8 @@ void RigGeometry::cull(osg::NodeVisitor* nv) return; } - if ((!mSkeleton->getActive() && mLastFrameNumber != 0) || mLastFrameNumber == nv->getTraversalNumber()) + unsigned int traversalNumber = nv->getTraversalNumber(); + if (mLastFrameNumber == traversalNumber || (mLastFrameNumber != 0 && !mSkeleton->getActive())) { osg::Geometry& geom = *getGeometry(mLastFrameNumber); nv->pushOntoNodePath(&geom); @@ -181,10 +185,10 @@ void RigGeometry::cull(osg::NodeVisitor* nv) nv->popFromNodePath(); return; } - mLastFrameNumber = nv->getTraversalNumber(); + mLastFrameNumber = traversalNumber; osg::Geometry& geom = *getGeometry(mLastFrameNumber); - mSkeleton->updateBoneMatrices(nv->getTraversalNumber()); + mSkeleton->updateBoneMatrices(traversalNumber); // skinning const osg::Vec3Array* positionSrc = static_cast(mSourceGeometry->getVertexArray()); @@ -195,34 +199,31 @@ void RigGeometry::cull(osg::NodeVisitor* nv) osg::Vec3Array* normalDst = static_cast(geom.getNormalArray()); osg::Vec4Array* tangentDst = static_cast(geom.getTexCoordArray(7)); - for (Bone2VertexMap::const_iterator it = mBone2VertexMap.begin(); it != mBone2VertexMap.end(); ++it) + for (auto &pair : mBone2VertexMap) { - osg::Matrixf resultMat (0, 0, 0, 0, + osg::Matrixf resultMat (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1); - for (std::vector::const_iterator weightIt = it->first.begin(); weightIt != it->first.end(); ++weightIt) + for (auto &weight : pair.first) { - Bone* bone = weightIt->first.first; - const osg::Matrix& invBindMatrix = weightIt->first.second; - float weight = weightIt->second; - const osg::Matrixf& boneMatrix = bone->mMatrixInSkeletonSpace; - accumulateMatrix(invBindMatrix, boneMatrix, weight, resultMat); + accumulateMatrix(weight.first.second, weight.first.first->mMatrixInSkeletonSpace, weight.second, resultMat); } + if (mGeomToSkelMatrix) resultMat *= (*mGeomToSkelMatrix); - for (std::vector::const_iterator vertexIt = it->second.begin(); vertexIt != it->second.end(); ++vertexIt) + for (auto &vertex : pair.second) { - unsigned short vertex = *vertexIt; (*positionDst)[vertex] = resultMat.preMult((*positionSrc)[vertex]); if (normalDst) - (*normalDst)[vertex] = osg::Matrix::transform3x3((*normalSrc)[vertex], resultMat); + (*normalDst)[vertex] = osg::Matrixf::transform3x3((*normalSrc)[vertex], resultMat); + if (tangentDst) { - osg::Vec4f srcTangent = (*tangentSrc)[vertex]; - osg::Vec3f transformedTangent = osg::Matrix::transform3x3(osg::Vec3f(srcTangent.x(), srcTangent.y(), srcTangent.z()), resultMat); + const osg::Vec4f& srcTangent = (*tangentSrc)[vertex]; + osg::Vec3f transformedTangent = osg::Matrixf::transform3x3(osg::Vec3f(srcTangent.x(), srcTangent.y(), srcTangent.z()), resultMat); (*tangentDst)[vertex] = osg::Vec4f(transformedTangent, srcTangent.w()); } } From c412f99963f03a4305271dfe00bfd03b500ba274 Mon Sep 17 00:00:00 2001 From: Sophie Kirschner Date: Sun, 26 Aug 2018 11:08:06 +0300 Subject: [PATCH 023/196] Remove commented lines in UnrefWorkItem::doWork --- components/sceneutil/unrefqueue.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/components/sceneutil/unrefqueue.cpp b/components/sceneutil/unrefqueue.cpp index 271c17af2..21ba836c0 100644 --- a/components/sceneutil/unrefqueue.cpp +++ b/components/sceneutil/unrefqueue.cpp @@ -8,10 +8,7 @@ namespace SceneUtil { void UnrefWorkItem::doWork() { - //osg::Timer timer; - //size_t objcount = mObjects.size(); mObjects.clear(); - //Log(Debug::Verbose) << "cleared " << objcount << " objects in " << timer.time_m(); } UnrefQueue::UnrefQueue() From dc68b2ff2681e64d9e4ae61289562b7e1f88065d Mon Sep 17 00:00:00 2001 From: Sophie Kirschner Date: Sun, 26 Aug 2018 11:10:25 +0300 Subject: [PATCH 024/196] Add Sophie Kirschner (me) to AUTHORS.md --- AUTHORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.md b/AUTHORS.md index 3422f28a9..5320a2462 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -153,6 +153,7 @@ Programmers Siimacore sir_herrbatka smbas + Sophie Kirschner (pineapplemachine) spycrab Stefan Galowicz (bogglez) Stanislav Bobrov (Jiub) From 9e253f6a46263f92e8a5939459d66a2d541b4e4c Mon Sep 17 00:00:00 2001 From: Sophie Kirschner Date: Sun, 26 Aug 2018 12:02:49 +0300 Subject: [PATCH 025/196] Add issue #4613 to changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d6d8df78e..a8a072105 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -123,6 +123,7 @@ Feature #4581: Use proper logging system Task #2490: Don't open command prompt window on Release-mode builds automatically Task #4545: Enable is_pod string test + Task #4613: Incomplete type errors when compiling with g++ on OSX 10.9 0.44.0 ------ From 60698e6f8aab18b612653dc7acd4c242cdf3b3d1 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sun, 26 Aug 2018 21:02:14 +0400 Subject: [PATCH 026/196] Optimize new magic effects update system --- apps/openmw/mwmechanics/actors.cpp | 2 +- apps/openmw/mwmechanics/character.cpp | 3 --- apps/openmw/mwrender/animation.cpp | 32 ++++++++++++++++++++++----- apps/openmw/mwrender/animation.hpp | 3 ++- 4 files changed, 29 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index d203dccf4..ba8f62e2f 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -1679,7 +1679,7 @@ namespace MWMechanics MWRender::Animation* animation = MWBase::Environment::get().getWorld()->getAnimation(iter->first); if (animation) - animation->updateEffects(duration); + animation->updateEffects(); } diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 49e2c4e6d..9d5db08b0 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -2219,9 +2219,6 @@ void CharacterController::update(float duration) moved *= (l / newLength); } - if (mSkipAnim) - mAnimation->updateEffects(duration); - if (mFloatToSurface && cls.isActor() && cls.getCreatureStats(mPtr).isDead() && cls.canSwim(mPtr)) moved.z() = 1.0; diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 4da3ec4a8..1ace2f8b4 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -208,8 +208,11 @@ namespace class RemoveFinishedCallbackVisitor : public RemoveVisitor { public: + bool mHasMagicEffects; + RemoveFinishedCallbackVisitor() : RemoveVisitor() + , mHasMagicEffects(false) , mEffectId(-1) { } @@ -234,11 +237,14 @@ namespace { // We should remove empty transformation nodes and finished callbacks here MWRender::UpdateVfxCallback* vfxCallback = dynamic_cast(callback); - bool finished = vfxCallback && vfxCallback->mFinished; - bool toRemove = vfxCallback && mEffectId >= 0 && vfxCallback->mParams.mEffectId == mEffectId; - if (finished || toRemove) + if (vfxCallback) { - mToRemove.push_back(std::make_pair(group.asNode(), group.getParent(0))); + bool finished = vfxCallback->mFinished; + bool toRemove = mEffectId >= 0 && vfxCallback->mParams.mEffectId == mEffectId; + if (finished || toRemove) + mToRemove.push_back(std::make_pair(group.asNode(), group.getParent(0))); + else + mHasMagicEffects = true; } } } @@ -610,6 +616,7 @@ namespace MWRender , mTextKeyListener(NULL) , mHeadYawRadians(0.f) , mHeadPitchRadians(0.f) + , mHasMagicEffects(false) , mAlpha(1.f) { for(size_t i = 0;i < sNumBlendMasks;i++) @@ -1321,7 +1328,7 @@ namespace MWRender ++stateiter; } - updateEffects(duration); + updateEffects(); if (mHeadController) { @@ -1633,6 +1640,9 @@ namespace MWRender SceneUtil::AssignControllerSourcesVisitor assignVisitor(std::shared_ptr(params.mAnimTime)); node->accept(assignVisitor); + // Notify that this animation has attached magic effects + mHasMagicEffects = true; + overrideFirstRootTexture(texture, mResourceSystem, node); } @@ -1641,10 +1651,14 @@ namespace MWRender RemoveFinishedCallbackVisitor visitor(effectId); mInsert->accept(visitor); visitor.remove(); + mHasMagicEffects = visitor.mHasMagicEffects; } void Animation::getLoopingEffects(std::vector &out) const { + if (!mHasMagicEffects) + return; + FindVfxCallbacksVisitor visitor; mInsert->accept(visitor); @@ -1657,13 +1671,19 @@ namespace MWRender } } - void Animation::updateEffects(float duration) + void Animation::updateEffects() { + // We do not need to visit scene every frame. + // We can use a bool flag to check in spellcasting effect found. + if (!mHasMagicEffects) + return; + // TODO: objects without animation still will have // transformation nodes with finished callbacks RemoveFinishedCallbackVisitor visitor; mInsert->accept(visitor); visitor.remove(); + mHasMagicEffects = visitor.mHasMagicEffects; } bool Animation::upperBodyReady() const diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 1da1fe4ef..e10d2c995 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -263,6 +263,7 @@ protected: osg::ref_ptr mHeadController; float mHeadYawRadians; float mHeadPitchRadians; + bool mHasMagicEffects; osg::ref_ptr mGlowLight; osg::ref_ptr mGlowUpdater; @@ -450,7 +451,7 @@ public: void setLoopingEnabled(const std::string &groupname, bool enabled); /// This is typically called as part of runAnimation, but may be called manually if needed. - void updateEffects(float duration); + void updateEffects(); /// Return a node with the specified name, or NULL if not existing. /// @note The matching is case-insensitive. From d448b802ef28d8a5343db3c79a0388490720c1f4 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sun, 26 Aug 2018 22:57:08 +0400 Subject: [PATCH 027/196] Add a small threshold for player turning animations --- apps/openmw/mwmechanics/character.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 49e2c4e6d..46676c076 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -2045,6 +2045,12 @@ void CharacterController::update(float duration) inJump = false; + // Do not play turning animation for player if rotation speed is very slow. + // Actual threshold should take framerate in account. + float rotationThreshold = 0; + if (mPtr == getPlayer()) + rotationThreshold = 0.015 * 60 * duration; + if(std::abs(vec.x()/2.0f) > std::abs(vec.y())) { if(vec.x() > 0.0f) @@ -2069,9 +2075,9 @@ void CharacterController::update(float duration) } else if(rot.z() != 0.0f && !sneak && !(mPtr == getPlayer() && MWBase::Environment::get().getWorld()->isFirstPerson())) { - if(rot.z() > 0.0f) + if(rot.z() > rotationThreshold) movestate = inwater ? CharState_SwimTurnRight : CharState_TurnRight; - else if(rot.z() < 0.0f) + else if(rot.z() < -rotationThreshold) movestate = inwater ? CharState_SwimTurnLeft : CharState_TurnLeft; } } From 8fa6c6f726ac27b54b621795d27208d17c7c7b1d Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Mon, 27 Aug 2018 09:37:08 +0400 Subject: [PATCH 028/196] Update pinned windows in-game (bug #4560) --- CHANGELOG.md | 1 + apps/openmw/mwgui/inventorywindow.cpp | 17 +++++++++++++++++ apps/openmw/mwgui/inventorywindow.hpp | 1 + apps/openmw/mwgui/spellwindow.cpp | 4 ++++ 4 files changed, 23 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 34f4dbbad..91e11fb80 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -96,6 +96,7 @@ Bug #4553: Forcegreeting on non-actor opens a dialogue window which cannot be closed Bug #4557: Topics with reserved names are handled differently from vanilla Bug #4558: Mesh optimizer: check for reserved node name is case-sensitive + Bug #4560: OpenMW does not update pinned windows properly Bug #4563: Fast travel price logic checks destination cell instead of service actor cell Bug #4565: Underwater view distance should be limited Bug #4573: Player uses headtracking in the 1st-person mode diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 523409ceb..0d37bbff3 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -68,6 +68,7 @@ namespace MWGui , mPreview(new MWRender::InventoryPreview(parent, resourceSystem, MWMechanics::getPlayer())) , mTrading(false) , mScaleFactor(1.0f) + , mUpdateTimer(0.f) { float uiScale = Settings::Manager::getFloat("scaling factor", "GUI"); if (uiScale > 1.0) @@ -631,6 +632,22 @@ namespace MWGui void InventoryWindow::onFrame(float dt) { updateEncumbranceBar(); + + if (mPinned) + { + mUpdateTimer += dt; + if (0.1f < mUpdateTimer) + { + mUpdateTimer = 0; + + // Update pinned inventory in-game + if (!MWBase::Environment::get().getWindowManager()->isGuiMode()) + { + mItemView->update(); + notifyContentChanged(); + } + } + } } void InventoryWindow::setTrading(bool trading) diff --git a/apps/openmw/mwgui/inventorywindow.hpp b/apps/openmw/mwgui/inventorywindow.hpp index d9cf6870c..c60e37363 100644 --- a/apps/openmw/mwgui/inventorywindow.hpp +++ b/apps/openmw/mwgui/inventorywindow.hpp @@ -102,6 +102,7 @@ namespace MWGui bool mTrading; float mScaleFactor; + float mUpdateTimer; void onItemSelected(int index); void onItemSelectedFromSourceModel(int index); diff --git a/apps/openmw/mwgui/spellwindow.cpp b/apps/openmw/mwgui/spellwindow.cpp index 3fe171e4e..38de9288b 100644 --- a/apps/openmw/mwgui/spellwindow.cpp +++ b/apps/openmw/mwgui/spellwindow.cpp @@ -86,6 +86,10 @@ namespace MWGui mUpdateTimer = 0; mSpellView->incrementalUpdate(); } + + // Update effects in-game too if the window is pinned + if (mPinned && !MWBase::Environment::get().getWindowManager()->isGuiMode()) + mSpellIcons->updateWidgets(mEffectBox, false); } void SpellWindow::updateSpells() From 2564fcc37e810a4e9314946172c9c65b454aeabc Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Tue, 28 Aug 2018 03:29:00 +0300 Subject: [PATCH 029/196] Apply sneaking offset to camera while the character is in air (bug #4617) --- CHANGELOG.md | 1 + apps/openmw/mwworld/worldimp.cpp | 3 +-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0584445c8..023ec4937 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -105,6 +105,7 @@ Bug #4591: Attack strength should be 0 if player did not hold the attack button Bug #4597: <> operator causes a compile error Bug #4604: Picking up gold from the ground only makes 1 grabbed + Bug #4617: First person sneaking offset is not applied while the character is in air Feature #1645: Casting effects from objects Feature #2606: Editor: Implemented (optional) case sensitive global search Feature #3083: Play animation when NPC is casting spell via script diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index a3d7873d7..6194e831f 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1706,11 +1706,10 @@ namespace MWWorld // Sink the camera while sneaking bool sneaking = player.getClass().getCreatureStats(getPlayerPtr()).getStance(MWMechanics::CreatureStats::Stance_Sneak); - bool inair = !isOnGround(player); bool swimming = isSwimming(player); static const float i1stPersonSneakDelta = getStore().get().find("i1stPersonSneakDelta")->getFloat(); - if (sneaking && !(swimming || inair)) + if (sneaking && !swimming) mRendering->getCamera()->setSneakOffset(i1stPersonSneakDelta); else mRendering->getCamera()->setSneakOffset(0.f); From c677f7ca2768262164531385d81b6d2ac29d6f60 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Tue, 28 Aug 2018 12:05:27 +0400 Subject: [PATCH 030/196] Rework pulsing light sources (bug #4615) --- CHANGELOG.md | 1 + components/sceneutil/lightcontroller.cpp | 16 ++++++++-------- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 34f4dbbad..f5c990b4c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -105,6 +105,7 @@ Bug #4591: Attack strength should be 0 if player did not hold the attack button Bug #4597: <> operator causes a compile error Bug #4604: Picking up gold from the ground only makes 1 grabbed + Bug #4615: Flicker effects for light sources are handled incorrectly Feature #1645: Casting effects from objects Feature #2606: Editor: Implemented (optional) case sensitive global search Feature #3083: Play animation when NPC is casting spell via script diff --git a/components/sceneutil/lightcontroller.cpp b/components/sceneutil/lightcontroller.cpp index e3ea93843..b89cfc4bc 100644 --- a/components/sceneutil/lightcontroller.cpp +++ b/components/sceneutil/lightcontroller.cpp @@ -73,17 +73,15 @@ namespace SceneUtil float cycle_time; float time_distortion; - const float pi = 3.14159265359; - if(mType == LT_Pulse || mType == LT_PulseSlow) { - cycle_time = 2.0f * pi; - time_distortion = mType == LT_Pulse ? 20.0f : 4.f; + cycle_time = 2.0f * osg::PI; + time_distortion = 3.0f; } else { - static const float fa = 0.785398f; - static const float phase_wavelength = 120.0f * pi / fa; + static const float fa = osg::PI / 4.0f; + static const float phase_wavelength = 120.0f * osg::PI / fa; cycle_time = 500.0f; mPhase = std::fmod(mPhase + dt, phase_wavelength); @@ -94,12 +92,14 @@ namespace SceneUtil if(mDirection > 0 && mDeltaCount > +cycle_time) { mDirection = -1.0f; - mDeltaCount = 2.0f*cycle_time - mDeltaCount; + float extra = mDeltaCount - cycle_time; + mDeltaCount -= 2*extra; } if(mDirection < 0 && mDeltaCount < -cycle_time) { mDirection = +1.0f; - mDeltaCount = -2.0f*cycle_time - mDeltaCount; + float extra = cycle_time - mDeltaCount; + mDeltaCount += 2*extra; } static const float fast = 4.0f/1.0f; From 0ddd0e4edc7f5fc9c5cff13117518453965aff47 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Tue, 28 Aug 2018 13:41:44 +0400 Subject: [PATCH 031/196] Fix light flicker amplitude calculation --- components/sceneutil/lightcontroller.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/sceneutil/lightcontroller.cpp b/components/sceneutil/lightcontroller.cpp index b89cfc4bc..199b408d7 100644 --- a/components/sceneutil/lightcontroller.cpp +++ b/components/sceneutil/lightcontroller.cpp @@ -26,7 +26,7 @@ namespace float v = 0.0f; for(int i = 0;i < 3;++i) - v += std::sin(fb*time*f[i] + o[1])*m[i]; + v += std::sin(fb*time*f[i] + o[i])*m[i]; return v * s; } From 079b60c1ea25e78445c82edad83af5616303430c Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Tue, 28 Aug 2018 14:28:27 +0300 Subject: [PATCH 032/196] Don't allow actors to use sneaking while flying (bug #4618) --- CHANGELOG.md | 1 + apps/openmw/mwmechanics/character.cpp | 4 ++-- apps/openmw/mwworld/worldimp.cpp | 3 ++- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 023ec4937..e34dee833 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -106,6 +106,7 @@ Bug #4597: <> operator causes a compile error Bug #4604: Picking up gold from the ground only makes 1 grabbed Bug #4617: First person sneaking offset is not applied while the character is in air + Bug #4618: Sneaking is possible while the character is flying Feature #1645: Casting effects from objects Feature #2606: Editor: Implemented (optional) case sensitive global search Feature #3083: Play animation when NPC is casting spell via script diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 49e2c4e6d..a7ef7c816 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1825,9 +1825,9 @@ void CharacterController::update(float duration) { bool onground = world->isOnGround(mPtr); bool inwater = world->isSwimming(mPtr); - bool sneak = cls.getCreatureStats(mPtr).getStance(MWMechanics::CreatureStats::Stance_Sneak); bool flying = world->isFlying(mPtr); - // Can't run while flying (see speed formula in Npc/Creature::getSpeed) + // Can't run and sneak while flying (see speed formula in Npc/Creature::getSpeed) + bool sneak = cls.getCreatureStats(mPtr).getStance(MWMechanics::CreatureStats::Stance_Sneak) && !flying; bool isrunning = cls.getCreatureStats(mPtr).getStance(MWMechanics::CreatureStats::Stance_Run) && !flying; CreatureStats &stats = cls.getCreatureStats(mPtr); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 6194e831f..0bc952e89 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1707,9 +1707,10 @@ namespace MWWorld // Sink the camera while sneaking bool sneaking = player.getClass().getCreatureStats(getPlayerPtr()).getStance(MWMechanics::CreatureStats::Stance_Sneak); bool swimming = isSwimming(player); + bool flying = isFlying(player); static const float i1stPersonSneakDelta = getStore().get().find("i1stPersonSneakDelta")->getFloat(); - if (sneaking && !swimming) + if (sneaking && !swimming && !flying) mRendering->getCamera()->setSneakOffset(i1stPersonSneakDelta); else mRendering->getCamera()->setSneakOffset(0.f); From 7f459f06108b651012daff256e680aa07f0bfbf3 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Tue, 28 Aug 2018 16:42:15 +0300 Subject: [PATCH 033/196] Knockdown and godmode fixes Make sure an incapacitated player is not able to jump Cleanup of redundant player and godmode checks in creature class Make sure the player is not knocked down while in godmode --- apps/openmw/mwclass/creature.cpp | 12 ++---------- apps/openmw/mwclass/npc.cpp | 6 +++++- apps/openmw/mwmechanics/character.cpp | 6 ++++-- 3 files changed, 11 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 161711751..7f4694af2 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -253,7 +253,7 @@ namespace MWClass // For AI actors, get combat targets to use in the ray cast. Only those targets will return a positive hit result. std::vector targetActors; - if (!ptr.isEmpty() && ptr.getClass().isActor() && ptr != MWMechanics::getPlayer()) + if (!ptr.isEmpty() && ptr.getClass().isActor()) ptr.getClass().getCreatureStats(ptr).getAiSequence().getCombatTargets(targetActors); std::pair result = MWBase::Environment::get().getWorld()->getHitContact(ptr, dist, targetActors); @@ -325,9 +325,6 @@ namespace MWClass if (MWMechanics::blockMeleeAttack(ptr, victim, weapon, damage, attackStrength)) damage = 0; - if (victim == MWMechanics::getPlayer() && MWBase::Environment::get().getWorld()->getGodModeState()) - damage = 0; - MWMechanics::diseaseContact(victim, ptr); victim.getClass().onHit(victim, damage, healthdmg, weapon, ptr, hitPosition, true); @@ -376,11 +373,6 @@ namespace MWClass ptr.getRefData().getLocals().setVarByInt(script, "onpchitme", 1); } - bool godmode = object == MWMechanics::getPlayer() && MWBase::Environment::get().getWorld()->getGodModeState(); - - if (godmode) - damage = 0; - if (!successful) { // Missed @@ -415,7 +407,7 @@ namespace MWClass if(ishealth) { - if (!attacker.isEmpty() && !godmode) + if (!attacker.isEmpty()) { damage = scaleDamage(damage, attacker, ptr); MWBase::Environment::get().getWorld()->spawnBloodEffect(ptr, hitPosition); diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 95d7fa66d..0b8b60feb 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -992,6 +992,10 @@ namespace MWClass if(getEncumbrance(ptr) > getCapacity(ptr)) return 0.f; + const MWMechanics::CreatureStats& stats = ptr.getClass().getCreatureStats(ptr); + if (stats.isParalyzed() || stats.getKnockedDown() || stats.isDead()) + return 0.f; + const NpcCustomData *npcdata = static_cast(ptr.getRefData().getCustomData()); const GMST& gmst = getGmst(); const MWMechanics::MagicEffects &mageffects = npcdata->mNpcStats.getMagicEffects(); @@ -1013,7 +1017,7 @@ namespace MWClass x += mageffects.get(ESM::MagicEffect::Jump).getMagnitude() * 64; x *= encumbranceTerm; - if(ptr.getClass().getCreatureStats(ptr).getStance(MWMechanics::CreatureStats::Stance_Run)) + if(stats.getStance(MWMechanics::CreatureStats::Stance_Run)) x *= gmst.fJumpRunMultiplier->getFloat(); x *= npcdata->mNpcStats.getFatigueTerm(); x -= -627.2f;/*gravity constant*/ diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 49e2c4e6d..2bd3dadac 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1824,6 +1824,7 @@ void CharacterController::update(float duration) else if(!cls.getCreatureStats(mPtr).isDead()) { bool onground = world->isOnGround(mPtr); + bool incapacitated = (cls.getCreatureStats(mPtr).isParalyzed() || cls.getCreatureStats(mPtr).getKnockedDown()); bool inwater = world->isSwimming(mPtr); bool sneak = cls.getCreatureStats(mPtr).getStance(MWMechanics::CreatureStats::Stance_Sneak); bool flying = world->isFlying(mPtr); @@ -1942,7 +1943,7 @@ void CharacterController::update(float duration) cls.getCreatureStats(mPtr).setFatigue(fatigue); } - if(sneak || inwater || flying) + if(sneak || inwater || flying || incapacitated) vec.z() = 0.0f; bool inJump = true; @@ -2021,7 +2022,8 @@ void CharacterController::update(float duration) const int acrobaticsSkill = cls.getSkill(mPtr, ESM::Skill::Acrobatics); if (healthLost > (acrobaticsSkill * fatigueTerm)) { - cls.getCreatureStats(mPtr).setKnockedDown(true); + if (!godmode) + cls.getCreatureStats(mPtr).setKnockedDown(true); } else { From 6c47f95677e748e1e2aea4324ab6f1d95824a72a Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Mon, 27 Aug 2018 02:17:49 +0300 Subject: [PATCH 034/196] Make RemoveSpellEffects affect permanent spells (bug #3920) Also make it remove the effects but not the spells themselves --- CHANGELOG.md | 1 + apps/openmw/mwmechanics/activespells.cpp | 8 ++++++-- apps/openmw/mwmechanics/spells.cpp | 13 +++++++++++++ apps/openmw/mwmechanics/spells.hpp | 2 ++ apps/openmw/mwscript/statsextensions.cpp | 1 + 5 files changed, 23 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5453ffb49..f147c7536 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,6 +31,7 @@ Bug #3876: Landscape texture painting is misaligned Bug #3897: Have Goodbye give all choices the effects of Goodbye Bug #3911: [macOS] Typing in the "Content List name" dialog box produces double characters + Bug #3920: RemoveSpellEffects doesn't remove constant effects Bug #3948: AiCombat moving target aiming uses incorrect speed for magic projectiles Bug #3950: FLATTEN_STATIC_TRANSFORMS optimization breaks animated collision shapes Bug #3993: Terrain texture blending map is not upscaled diff --git a/apps/openmw/mwmechanics/activespells.cpp b/apps/openmw/mwmechanics/activespells.cpp index 90d29f686..9e523a845 100644 --- a/apps/openmw/mwmechanics/activespells.cpp +++ b/apps/openmw/mwmechanics/activespells.cpp @@ -197,8 +197,12 @@ namespace MWMechanics void ActiveSpells::removeEffects(const std::string &id) { - mSpells.erase(Misc::StringUtils::lowerCase(id)); - mSpellsChanged = true; + TContainer::iterator spell(mSpells.find(id)); + if (spell != end()); + { + spell->second.mEffects.clear(); + mSpellsChanged = true; + } } void ActiveSpells::visitEffectSources(EffectSourceVisitor &visitor) const diff --git a/apps/openmw/mwmechanics/spells.cpp b/apps/openmw/mwmechanics/spells.cpp index ff397f69d..25f301118 100644 --- a/apps/openmw/mwmechanics/spells.cpp +++ b/apps/openmw/mwmechanics/spells.cpp @@ -279,6 +279,19 @@ namespace MWMechanics } } + void Spells::removeEffects(const std::string &id) + { + if (isSpellActive(id)) + { + TContainer::iterator spellIt = mSpells.find(getSpell(id)); + for (long unsigned int i = 0; i != spellIt->first->mEffects.mList.size(); i++) + { + spellIt->second.mPurgedEffects.insert(i); + mSpellsChanged = true; + } + } + } + void Spells::visitEffectSources(EffectSourceVisitor &visitor) const { if (mSpellsChanged) { diff --git a/apps/openmw/mwmechanics/spells.hpp b/apps/openmw/mwmechanics/spells.hpp index c1705b38a..e635f4f56 100644 --- a/apps/openmw/mwmechanics/spells.hpp +++ b/apps/openmw/mwmechanics/spells.hpp @@ -124,6 +124,8 @@ namespace MWMechanics bool hasBlightDisease() const; + void removeEffects(const std::string& id); + void visitEffectSources (MWMechanics::EffectSourceVisitor& visitor) const; void readState (const ESM::SpellState& state); diff --git a/apps/openmw/mwscript/statsextensions.cpp b/apps/openmw/mwscript/statsextensions.cpp index 5df767da8..29160d47e 100644 --- a/apps/openmw/mwscript/statsextensions.cpp +++ b/apps/openmw/mwscript/statsextensions.cpp @@ -501,6 +501,7 @@ namespace MWScript runtime.pop(); ptr.getClass().getCreatureStats (ptr).getActiveSpells().removeEffects(spellid); + ptr.getClass().getCreatureStats (ptr).getSpells().removeEffects(spellid); } }; From ed1f8f7be7b43d1ca6b1154c7b9f33633835d6c6 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Wed, 29 Aug 2018 13:40:37 +0300 Subject: [PATCH 035/196] Remove effects from all active spells with the same ID --- apps/openmw/mwmechanics/activespells.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwmechanics/activespells.cpp b/apps/openmw/mwmechanics/activespells.cpp index 9e523a845..57b009689 100644 --- a/apps/openmw/mwmechanics/activespells.cpp +++ b/apps/openmw/mwmechanics/activespells.cpp @@ -197,11 +197,13 @@ namespace MWMechanics void ActiveSpells::removeEffects(const std::string &id) { - TContainer::iterator spell(mSpells.find(id)); - if (spell != end()); + for (TContainer::iterator spell = mSpells.begin(); spell != mSpells.end(); ++spell) { - spell->second.mEffects.clear(); - mSpellsChanged = true; + if (spell->first == id) + { + spell->second.mEffects.clear(); + mSpellsChanged = true; + } } } From b8ba9092cb1657df934ece8c7d93dae135dab6ea Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Wed, 29 Aug 2018 14:09:43 +0300 Subject: [PATCH 036/196] Purge effects from all permanent spells with the same ID --- apps/openmw/mwmechanics/spells.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwmechanics/spells.cpp b/apps/openmw/mwmechanics/spells.cpp index 25f301118..0a11ed641 100644 --- a/apps/openmw/mwmechanics/spells.cpp +++ b/apps/openmw/mwmechanics/spells.cpp @@ -283,12 +283,18 @@ namespace MWMechanics { if (isSpellActive(id)) { - TContainer::iterator spellIt = mSpells.find(getSpell(id)); - for (long unsigned int i = 0; i != spellIt->first->mEffects.mList.size(); i++) + for (TContainer::iterator spell = mSpells.begin(); spell != mSpells.end(); ++spell) { - spellIt->second.mPurgedEffects.insert(i); - mSpellsChanged = true; + if (spell->first == getSpell(id)) + { + for (long unsigned int i = 0; i != spell->first->mEffects.mList.size(); i++) + { + spell->second.mPurgedEffects.insert(i); + } + } } + + mSpellsChanged = true; } } From 23834b5ed81123fc1426c1490d5bb884d2e437f4 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Wed, 29 Aug 2018 15:09:03 +0300 Subject: [PATCH 037/196] Don't apply falling damage twice (bug #4608) --- CHANGELOG.md | 1 + apps/openmw/mwmechanics/character.cpp | 3 --- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5453ffb49..528e8963a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -107,6 +107,7 @@ Bug #4597: <> operator causes a compile error Bug #4604: Picking up gold from the ground only makes 1 grabbed Bug #4607: Scaling for animated collision shapes is applied twice + Bug #4608: Falling damage is applied twice Bug #4615: Flicker effects for light sources are handled incorrectly Bug #4617: First person sneaking offset is not applied while the character is in air Bug #4618: Sneaking is possible while the character is flying diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index aca3dde7f..79527f886 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -2012,10 +2012,7 @@ void CharacterController::update(float duration) // inflict fall damages if (!godmode) { - DynamicStat health = cls.getCreatureStats(mPtr).getHealth(); float realHealthLost = static_cast(healthLost * (1.0f - 0.25f * fatigueTerm)); - health.setCurrent(health.getCurrent() - realHealthLost); - cls.getCreatureStats(mPtr).setHealth(health); cls.onHit(mPtr, realHealthLost, true, MWWorld::Ptr(), MWWorld::Ptr(), osg::Vec3f(), true); } From b0ac0b0b225355066a8ba66deb0109efd0d32d55 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Mon, 27 Aug 2018 13:33:50 +0400 Subject: [PATCH 038/196] Do not initialize map every call --- CHANGELOG.md | 1 + components/esm/loadmgef.cpp | 139 +++++++++++++++++++----------------- 2 files changed, 73 insertions(+), 67 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5453ffb49..fec409d48 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -138,6 +138,7 @@ Task #4605: Optimize skinning Task #4606: Support Rapture3D's OpenAL driver Task #4613: Incomplete type errors when compiling with g++ on OSX 10.9 + Task #4621: Optimize combat AI 0.44.0 ------ diff --git a/components/esm/loadmgef.cpp b/components/esm/loadmgef.cpp index 9f8ad94e1..75a94f828 100644 --- a/components/esm/loadmgef.cpp +++ b/components/esm/loadmgef.cpp @@ -274,43 +274,46 @@ short MagicEffect::getResistanceEffect(short effect) // Source https://wiki.openmw.org/index.php?title=Research:Magic#Effect_attribute // - std::map effects; - effects[DisintegrateArmor] = Sanctuary; - effects[DisintegrateWeapon] = Sanctuary; - - for (int i=0; i<5; ++i) - effects[DrainAttribute+i] = ResistMagicka; - for (int i=0; i<5; ++i) - effects[DamageAttribute+i] = ResistMagicka; - for (int i=0; i<5; ++i) - effects[AbsorbAttribute+i] = ResistMagicka; - for (int i=0; i<10; ++i) - effects[WeaknessToFire+i] = ResistMagicka; - - effects[Burden] = ResistMagicka; - effects[Charm] = ResistMagicka; - effects[Silence] = ResistMagicka; - effects[Blind] = ResistMagicka; - effects[Sound] = ResistMagicka; - - for (int i=0; i<2; ++i) + static std::map effects; + if (effects.empty()) { - effects[CalmHumanoid+i] = ResistMagicka; - effects[FrenzyHumanoid+i] = ResistMagicka; - effects[DemoralizeHumanoid+i] = ResistMagicka; - effects[RallyHumanoid+i] = ResistMagicka; + effects[DisintegrateArmor] = Sanctuary; + effects[DisintegrateWeapon] = Sanctuary; + + for (int i=0; i<5; ++i) + effects[DrainAttribute+i] = ResistMagicka; + for (int i=0; i<5; ++i) + effects[DamageAttribute+i] = ResistMagicka; + for (int i=0; i<5; ++i) + effects[AbsorbAttribute+i] = ResistMagicka; + for (int i=0; i<10; ++i) + effects[WeaknessToFire+i] = ResistMagicka; + + effects[Burden] = ResistMagicka; + effects[Charm] = ResistMagicka; + effects[Silence] = ResistMagicka; + effects[Blind] = ResistMagicka; + effects[Sound] = ResistMagicka; + + for (int i=0; i<2; ++i) + { + effects[CalmHumanoid+i] = ResistMagicka; + effects[FrenzyHumanoid+i] = ResistMagicka; + effects[DemoralizeHumanoid+i] = ResistMagicka; + effects[RallyHumanoid+i] = ResistMagicka; + } + + effects[TurnUndead] = ResistMagicka; + + effects[FireDamage] = ResistFire; + effects[FrostDamage] = ResistFrost; + effects[ShockDamage] = ResistShock; + effects[Vampirism] = ResistCommonDisease; + effects[Corprus] = ResistCorprusDisease; + effects[Poison] = ResistPoison; + effects[Paralyze] = ResistParalysis; } - effects[TurnUndead] = ResistMagicka; - - effects[FireDamage] = ResistFire; - effects[FrostDamage] = ResistFrost; - effects[ShockDamage] = ResistShock; - effects[Vampirism] = ResistCommonDisease; - effects[Corprus] = ResistCorprusDisease; - effects[Poison] = ResistPoison; - effects[Paralyze] = ResistParalysis; - if (effects.find(effect) != effects.end()) return effects[effect]; else @@ -319,42 +322,44 @@ short MagicEffect::getResistanceEffect(short effect) short MagicEffect::getWeaknessEffect(short effect) { - std::map effects; - - for (int i=0; i<5; ++i) - effects[DrainAttribute+i] = WeaknessToMagicka; - for (int i=0; i<5; ++i) - effects[DamageAttribute+i] = WeaknessToMagicka; - for (int i=0; i<5; ++i) - effects[AbsorbAttribute+i] = WeaknessToMagicka; - for (int i=0; i<10; ++i) - effects[WeaknessToFire+i] = WeaknessToMagicka; - - effects[Burden] = WeaknessToMagicka; - effects[Charm] = WeaknessToMagicka; - effects[Silence] = WeaknessToMagicka; - effects[Blind] = WeaknessToMagicka; - effects[Sound] = WeaknessToMagicka; - - for (int i=0; i<2; ++i) + static std::map effects; + if (effects.empty()) { - effects[CalmHumanoid+i] = WeaknessToMagicka; - effects[FrenzyHumanoid+i] = WeaknessToMagicka; - effects[DemoralizeHumanoid+i] = WeaknessToMagicka; - effects[RallyHumanoid+i] = WeaknessToMagicka; + for (int i=0; i<5; ++i) + effects[DrainAttribute+i] = WeaknessToMagicka; + for (int i=0; i<5; ++i) + effects[DamageAttribute+i] = WeaknessToMagicka; + for (int i=0; i<5; ++i) + effects[AbsorbAttribute+i] = WeaknessToMagicka; + for (int i=0; i<10; ++i) + effects[WeaknessToFire+i] = WeaknessToMagicka; + + effects[Burden] = WeaknessToMagicka; + effects[Charm] = WeaknessToMagicka; + effects[Silence] = WeaknessToMagicka; + effects[Blind] = WeaknessToMagicka; + effects[Sound] = WeaknessToMagicka; + + for (int i=0; i<2; ++i) + { + effects[CalmHumanoid+i] = WeaknessToMagicka; + effects[FrenzyHumanoid+i] = WeaknessToMagicka; + effects[DemoralizeHumanoid+i] = WeaknessToMagicka; + effects[RallyHumanoid+i] = WeaknessToMagicka; + } + + effects[TurnUndead] = WeaknessToMagicka; + + effects[FireDamage] = WeaknessToFire; + effects[FrostDamage] = WeaknessToFrost; + effects[ShockDamage] = WeaknessToShock; + effects[Vampirism] = WeaknessToCommonDisease; + effects[Corprus] = WeaknessToCorprusDisease; + effects[Poison] = WeaknessToPoison; + + effects[Paralyze] = -1; } - effects[TurnUndead] = WeaknessToMagicka; - - effects[FireDamage] = WeaknessToFire; - effects[FrostDamage] = WeaknessToFrost; - effects[ShockDamage] = WeaknessToShock; - effects[Vampirism] = WeaknessToCommonDisease; - effects[Corprus] = WeaknessToCorprusDisease; - effects[Poison] = WeaknessToPoison; - - effects[Paralyze] = -1; - if (effects.find(effect) != effects.end()) return effects[effect]; else From 4c0ef4ddb6b1739d3fc614c877519cf316a21840 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Wed, 29 Aug 2018 17:19:31 +0400 Subject: [PATCH 039/196] Do not initialize magic schools map every time we access it --- apps/openmw/mwmechanics/spellcasting.cpp | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 76140013d..77b5bc123 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -34,13 +34,17 @@ namespace MWMechanics { ESM::Skill::SkillEnum spellSchoolToSkill(int school) { - std::map schoolSkillMap; // maps spell school to skill id - schoolSkillMap[0] = ESM::Skill::Alteration; - schoolSkillMap[1] = ESM::Skill::Conjuration; - schoolSkillMap[3] = ESM::Skill::Illusion; - schoolSkillMap[2] = ESM::Skill::Destruction; - schoolSkillMap[4] = ESM::Skill::Mysticism; - schoolSkillMap[5] = ESM::Skill::Restoration; + static std::map schoolSkillMap; // maps spell school to skill id + if (schoolSkillMap.empty()) + { + schoolSkillMap[0] = ESM::Skill::Alteration; + schoolSkillMap[1] = ESM::Skill::Conjuration; + schoolSkillMap[3] = ESM::Skill::Illusion; + schoolSkillMap[2] = ESM::Skill::Destruction; + schoolSkillMap[4] = ESM::Skill::Mysticism; + schoolSkillMap[5] = ESM::Skill::Restoration; + } + assert(schoolSkillMap.find(school) != schoolSkillMap.end()); return schoolSkillMap[school]; } From 2cac8b59b1b70d166315d79e26c81ca53fb131dd Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Mon, 27 Aug 2018 13:35:49 +0400 Subject: [PATCH 040/196] Use square distance to target --- apps/openmw/mwmechanics/aisequence.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwmechanics/aisequence.cpp b/apps/openmw/mwmechanics/aisequence.cpp index b64b3568f..cf572abc0 100644 --- a/apps/openmw/mwmechanics/aisequence.cpp +++ b/apps/openmw/mwmechanics/aisequence.cpp @@ -228,7 +228,7 @@ void AiSequence::execute (const MWWorld::Ptr& actor, CharacterController& charac { if ((*it)->getTypeId() != AiPackage::TypeIdCombat) break; - MWWorld::Ptr target = static_cast(*it)->getTarget(); + MWWorld::Ptr target = (*it)->getTarget(); // target disappeared (e.g. summoned creatures) if (target.isEmpty()) @@ -242,11 +242,11 @@ void AiSequence::execute (const MWWorld::Ptr& actor, CharacterController& charac const ESM::Position &targetPos = target.getRefData().getPosition(); - float distTo = (targetPos.asVec3() - vActorPos).length(); + float distTo = (targetPos.asVec3() - vActorPos).length2(); // Small threshold for changing target if (it == mPackages.begin()) - distTo = std::max(0.f, distTo - 50.f); + distTo = std::max(0.f, distTo - 2500.f); // if a target has higher priority than current target or has same priority but closer if (rating > bestRating || ((distTo < nearestDist) && rating == bestRating)) From 5d54214acb18b92afb676466d61966068c7d8258 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Mon, 27 Aug 2018 13:38:53 +0400 Subject: [PATCH 041/196] Optimize combat action iteration --- apps/openmw/mwmechanics/aicombataction.cpp | 22 ++++------------------ apps/openmw/mwmechanics/spellcasting.cpp | 4 ++++ apps/openmw/mwmechanics/spellcasting.hpp | 2 ++ apps/openmw/mwmechanics/spellpriority.cpp | 5 ++--- apps/openmw/mwmechanics/weaponpriority.cpp | 3 +++ 5 files changed, 15 insertions(+), 21 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombataction.cpp b/apps/openmw/mwmechanics/aicombataction.cpp index 2685e0e0c..421e5a99f 100644 --- a/apps/openmw/mwmechanics/aicombataction.cpp +++ b/apps/openmw/mwmechanics/aicombataction.cpp @@ -190,11 +190,6 @@ namespace MWMechanics for (MWWorld::ContainerStoreIterator it = store.begin(); it != store.end(); ++it) { - std::vector equipmentSlots = it->getClass().getEquipmentSlots(*it).first; - if (std::find(equipmentSlots.begin(), equipmentSlots.end(), (int)MWWorld::InventoryStore::Slot_CarriedRight) - == equipmentSlots.end()) - continue; - float rating = rateWeapon(*it, actor, enemy, -1, bestArrowRating, bestBoltRating); if (rating > bestActionRating) { @@ -215,14 +210,12 @@ namespace MWMechanics for (Spells::TIterator it = spells.begin(); it != spells.end(); ++it) { - const ESM::Spell* spell = it->first; - - float rating = rateSpell(spell, actor, enemy); + float rating = rateSpell(it->first, actor, enemy); if (rating > bestActionRating) { bestActionRating = rating; - bestAction.reset(new ActionSpell(spell->mId)); - antiFleeRating = vanillaRateSpell(spell, actor, enemy); + bestAction.reset(new ActionSpell(it->first->mId)); + antiFleeRating = vanillaRateSpell(it->first, actor, enemy); } } @@ -265,11 +258,6 @@ namespace MWMechanics for (MWWorld::ContainerStoreIterator it = store.begin(); it != store.end(); ++it) { - std::vector equipmentSlots = it->getClass().getEquipmentSlots(*it).first; - if (std::find(equipmentSlots.begin(), equipmentSlots.end(), (int)MWWorld::InventoryStore::Slot_CarriedRight) - == equipmentSlots.end()) - continue; - float rating = rateWeapon(*it, actor, enemy, -1, bestArrowRating, bestBoltRating); if (rating > bestActionRating) { @@ -280,9 +268,7 @@ namespace MWMechanics for (Spells::TIterator it = spells.begin(); it != spells.end(); ++it) { - const ESM::Spell* spell = it->first; - - float rating = rateSpell(spell, actor, enemy); + float rating = rateSpell(it->first, actor, enemy); if (rating > bestActionRating) { bestActionRating = rating; diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 77b5bc123..1d7b1783e 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -52,7 +52,11 @@ namespace MWMechanics float calcEffectCost(const ESM::ENAMstruct& effect) { const ESM::MagicEffect* magicEffect = MWBase::Environment::get().getWorld()->getStore().get().find(effect.mEffectID); + return calcEffectCost(effect, magicEffect); + } + float calcEffectCost(const ESM::ENAMstruct& effect, const ESM::MagicEffect* magicEffect) + { int minMagn = 1; int maxMagn = 1; if (!(magicEffect->mData.mFlags & ESM::MagicEffect::NoMagnitude)) diff --git a/apps/openmw/mwmechanics/spellcasting.hpp b/apps/openmw/mwmechanics/spellcasting.hpp index 72f6a1f4a..2844e7f23 100644 --- a/apps/openmw/mwmechanics/spellcasting.hpp +++ b/apps/openmw/mwmechanics/spellcasting.hpp @@ -3,6 +3,7 @@ #include #include +#include #include "../mwworld/ptr.hpp" @@ -25,6 +26,7 @@ namespace MWMechanics ESM::Skill::SkillEnum spellSchoolToSkill(int school); float calcEffectCost(const ESM::ENAMstruct& effect); + float calcEffectCost(const ESM::ENAMstruct& effect, const ESM::MagicEffect* magicEffect); bool isSummoningEffect(int effectId); diff --git a/apps/openmw/mwmechanics/spellpriority.cpp b/apps/openmw/mwmechanics/spellpriority.cpp index 7bedb1e37..afe6329a2 100644 --- a/apps/openmw/mwmechanics/spellpriority.cpp +++ b/apps/openmw/mwmechanics/spellpriority.cpp @@ -515,8 +515,6 @@ namespace MWMechanics return 0.f; } - const ESM::MagicEffect* magicEffect = MWBase::Environment::get().getWorld()->getStore().get().find(effect.mEffectID); - // Underwater casting not possible if (effect.mRange == ESM::RT_Target) { @@ -530,6 +528,7 @@ namespace MWMechanics return 0.f; } + const ESM::MagicEffect* magicEffect = MWBase::Environment::get().getWorld()->getStore().get().find(effect.mEffectID); if (magicEffect->mData.mFlags & ESM::MagicEffect::Harmful) { rating *= -1.f; @@ -565,7 +564,7 @@ namespace MWMechanics } } - rating *= calcEffectCost(effect); + rating *= calcEffectCost(effect, magicEffect); // Currently treating all "on target" or "on touch" effects to target the enemy actor. // Combat AI is egoistic, so doesn't consider applying positive effects to friendly actors. diff --git a/apps/openmw/mwmechanics/weaponpriority.cpp b/apps/openmw/mwmechanics/weaponpriority.cpp index 9030d6254..81bd08626 100644 --- a/apps/openmw/mwmechanics/weaponpriority.cpp +++ b/apps/openmw/mwmechanics/weaponpriority.cpp @@ -29,6 +29,9 @@ namespace MWMechanics if (type != -1 && weapon->mData.mType != type) return 0.f; + if (type == -1 && (weapon->mData.mType == ESM::Weapon::Arrow || weapon->mData.mType == ESM::Weapon::Bolt)) + return 0.f; + float rating=0.f; float rangedMult=1.f; From 7ef6fa9f61ad174bbc74c3cbce19756608e183c9 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Wed, 29 Aug 2018 18:38:12 +0300 Subject: [PATCH 042/196] Remove deprecated GMST get* functions --- apps/openmw/mwclass/armor.cpp | 8 +- apps/openmw/mwclass/creature.cpp | 22 ++-- apps/openmw/mwclass/creaturelevlist.cpp | 4 +- apps/openmw/mwclass/ingredient.cpp | 2 +- apps/openmw/mwclass/npc.cpp | 64 +++++------ apps/openmw/mwclass/weapon.cpp | 6 +- apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 4 +- apps/openmw/mwgui/dialogue.cpp | 40 +++---- apps/openmw/mwgui/enchantingdialog.cpp | 2 +- apps/openmw/mwgui/hud.cpp | 4 +- apps/openmw/mwgui/jailscreen.cpp | 10 +- apps/openmw/mwgui/merchantrepair.cpp | 4 +- apps/openmw/mwgui/recharge.cpp | 2 +- apps/openmw/mwgui/spellbuyingwindow.cpp | 2 +- apps/openmw/mwgui/spellcreationdialog.cpp | 10 +- apps/openmw/mwgui/spellicons.cpp | 2 +- apps/openmw/mwgui/statswindow.cpp | 4 +- apps/openmw/mwgui/tradewindow.cpp | 6 +- apps/openmw/mwgui/trainingwindow.cpp | 4 +- apps/openmw/mwgui/travelwindow.cpp | 6 +- apps/openmw/mwgui/waitdialog.cpp | 6 +- apps/openmw/mwgui/windowmanagerimp.cpp | 2 +- apps/openmw/mwinput/inputmanagerimp.cpp | 2 +- apps/openmw/mwmechanics/actors.cpp | 52 ++++----- apps/openmw/mwmechanics/aibreathe.cpp | 2 +- apps/openmw/mwmechanics/aicombat.cpp | 18 +-- apps/openmw/mwmechanics/aicombataction.cpp | 28 ++--- apps/openmw/mwmechanics/aiwander.cpp | 6 +- apps/openmw/mwmechanics/alchemy.cpp | 12 +- apps/openmw/mwmechanics/autocalcspell.cpp | 18 +-- apps/openmw/mwmechanics/character.cpp | 34 +++--- apps/openmw/mwmechanics/combat.cpp | 54 ++++----- apps/openmw/mwmechanics/creaturestats.cpp | 4 +- apps/openmw/mwmechanics/difficultyscaling.cpp | 2 +- apps/openmw/mwmechanics/disease.hpp | 4 +- apps/openmw/mwmechanics/enchanting.cpp | 14 +-- .../mwmechanics/mechanicsmanagerimp.cpp | 106 +++++++++--------- apps/openmw/mwmechanics/npcstats.cpp | 28 ++--- apps/openmw/mwmechanics/pickpocket.cpp | 6 +- apps/openmw/mwmechanics/repair.cpp | 4 +- apps/openmw/mwmechanics/security.cpp | 4 +- apps/openmw/mwmechanics/spellcasting.cpp | 14 +-- apps/openmw/mwmechanics/spellpriority.cpp | 4 +- apps/openmw/mwmechanics/trading.cpp | 6 +- apps/openmw/mwmechanics/weaponpriority.cpp | 6 +- apps/openmw/mwphysics/physicssystem.cpp | 8 +- apps/openmw/mwrender/weaponanimation.cpp | 8 +- apps/openmw/mwsound/soundmanagerimp.cpp | 16 +-- apps/openmw/mwworld/cellstore.cpp | 4 +- apps/openmw/mwworld/inventorystore.cpp | 6 +- apps/openmw/mwworld/player.cpp | 8 +- apps/openmw/mwworld/projectilemanager.cpp | 2 +- apps/openmw/mwworld/weather.cpp | 2 +- apps/openmw/mwworld/worldimp.cpp | 16 +-- components/esm/loadgmst.cpp | 15 --- components/esm/loadgmst.hpp | 11 -- 56 files changed, 356 insertions(+), 382 deletions(-) diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index 0d267046f..b90c1ec58 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -142,14 +142,14 @@ namespace MWClass const MWWorld::Store &gmst = MWBase::Environment::get().getWorld()->getStore().get(); - float iWeight = floor(gmst.find(typeGmst)->getFloat()); + float iWeight = floor(gmst.find(typeGmst)->mValue.getFloat()); float epsilon = 0.0005f; - if (ref->mBase->mData.mWeight <= iWeight * gmst.find ("fLightMaxMod")->getFloat() + epsilon) + if (ref->mBase->mData.mWeight <= iWeight * gmst.find ("fLightMaxMod")->mValue.getFloat() + epsilon) return ESM::Skill::LightArmor; - if (ref->mBase->mData.mWeight <= iWeight * gmst.find ("fMedMaxMod")->getFloat() + epsilon) + if (ref->mBase->mData.mWeight <= iWeight * gmst.find ("fMedMaxMod")->mValue.getFloat() + epsilon) return ESM::Skill::MediumArmor; else @@ -285,7 +285,7 @@ namespace MWClass int armorSkill = actor.getClass().getSkill(actor, armorSkillType); const MWBase::World *world = MWBase::Environment::get().getWorld(); - int iBaseArmorSkill = world->getStore().get().find("iBaseArmorSkill")->getInt(); + int iBaseArmorSkill = world->getStore().get().find("iBaseArmorSkill")->mValue.getInteger(); if(ref->mBase->mData.mWeight == 0) return ref->mBase->mData.mArmor; diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 7f4694af2..6999558ae 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -247,7 +247,7 @@ namespace MWClass MWMechanics::applyFatigueLoss(ptr, weapon, attackStrength); - float dist = gmst.find("fCombatDistance")->getFloat(); + float dist = gmst.find("fCombatDistance")->mValue.getFloat(); if (!weapon.isEmpty()) dist *= weapon.get()->mBase->mData.mReach; @@ -394,9 +394,9 @@ namespace MWClass if (!attacker.isEmpty()) { // Check for knockdown - float agilityTerm = stats.getAttribute(ESM::Attribute::Agility).getModified() * getGmst().fKnockDownMult->getFloat(); + float agilityTerm = stats.getAttribute(ESM::Attribute::Agility).getModified() * getGmst().fKnockDownMult->mValue.getFloat(); float knockdownTerm = stats.getAttribute(ESM::Attribute::Agility).getModified() - * getGmst().iKnockDownOddsMult->getInt() * 0.01f + getGmst().iKnockDownOddsBase->getInt(); + * getGmst().iKnockDownOddsMult->mValue.getInteger() * 0.01f + getGmst().iKnockDownOddsBase->mValue.getInteger(); if (ishealth && agilityTerm <= damage && knockdownTerm <= Misc::Rng::roll0to99()) stats.setKnockedDown(true); else @@ -516,8 +516,8 @@ namespace MWClass const GMST& gmst = getGmst(); - float walkSpeed = gmst.fMinWalkSpeedCreature->getFloat() + 0.01f * stats.getAttribute(ESM::Attribute::Speed).getModified() - * (gmst.fMaxWalkSpeedCreature->getFloat() - gmst.fMinWalkSpeedCreature->getFloat()); + float walkSpeed = gmst.fMinWalkSpeedCreature->mValue.getFloat() + 0.01f * stats.getAttribute(ESM::Attribute::Speed).getModified() + * (gmst.fMaxWalkSpeedCreature->mValue.getFloat() - gmst.fMinWalkSpeedCreature->mValue.getFloat()); const MWBase::World *world = MWBase::Environment::get().getWorld(); const MWMechanics::MagicEffects &mageffects = stats.getMagicEffects(); @@ -536,9 +536,9 @@ namespace MWClass { float flySpeed = 0.01f*(stats.getAttribute(ESM::Attribute::Speed).getModified() + mageffects.get(ESM::MagicEffect::Levitate).getMagnitude()); - flySpeed = gmst.fMinFlySpeed->getFloat() + flySpeed*(gmst.fMaxFlySpeed->getFloat() - gmst.fMinFlySpeed->getFloat()); + flySpeed = gmst.fMinFlySpeed->mValue.getFloat() + flySpeed*(gmst.fMaxFlySpeed->mValue.getFloat() - gmst.fMinFlySpeed->mValue.getFloat()); const float normalizedEncumbrance = getNormalizedEncumbrance(ptr); - flySpeed *= 1.0f - gmst.fEncumberedMoveEffect->getFloat() * normalizedEncumbrance; + flySpeed *= 1.0f - gmst.fEncumberedMoveEffect->mValue.getFloat() * normalizedEncumbrance; flySpeed = std::max(0.0f, flySpeed); moveSpeed = flySpeed; } @@ -548,8 +548,8 @@ namespace MWClass if(running) swimSpeed = runSpeed; swimSpeed *= 1.0f + 0.01f * mageffects.get(ESM::MagicEffect::SwiftSwim).getMagnitude(); - swimSpeed *= gmst.fSwimRunBase->getFloat() + 0.01f*getSkill(ptr, ESM::Skill::Athletics) * - gmst.fSwimRunAthleticsMult->getFloat(); + swimSpeed *= gmst.fSwimRunBase->mValue.getFloat() + 0.01f*getSkill(ptr, ESM::Skill::Athletics) * + gmst.fSwimRunAthleticsMult->mValue.getFloat(); moveSpeed = swimSpeed; } else if(running) @@ -814,8 +814,8 @@ namespace MWClass return; const MWWorld::Store& gmst = MWBase::Environment::get().getWorld()->getStore().get(); - static const float fCorpseRespawnDelay = gmst.find("fCorpseRespawnDelay")->getFloat(); - static const float fCorpseClearDelay = gmst.find("fCorpseClearDelay")->getFloat(); + static const float fCorpseRespawnDelay = gmst.find("fCorpseRespawnDelay")->mValue.getFloat(); + static const float fCorpseClearDelay = gmst.find("fCorpseClearDelay")->mValue.getFloat(); float delay = ptr.getRefData().getCount() == 0 ? fCorpseClearDelay : std::min(fCorpseRespawnDelay, fCorpseClearDelay); diff --git a/apps/openmw/mwclass/creaturelevlist.cpp b/apps/openmw/mwclass/creaturelevlist.cpp index 4a4d9793e..b8c4cbb62 100644 --- a/apps/openmw/mwclass/creaturelevlist.cpp +++ b/apps/openmw/mwclass/creaturelevlist.cpp @@ -56,8 +56,8 @@ namespace MWClass else if (creatureStats.isDead()) { const MWWorld::Store& gmst = MWBase::Environment::get().getWorld()->getStore().get(); - static const float fCorpseRespawnDelay = gmst.find("fCorpseRespawnDelay")->getFloat(); - static const float fCorpseClearDelay = gmst.find("fCorpseClearDelay")->getFloat(); + static const float fCorpseRespawnDelay = gmst.find("fCorpseRespawnDelay")->mValue.getFloat(); + static const float fCorpseClearDelay = gmst.find("fCorpseClearDelay")->mValue.getFloat(); float delay = std::min(fCorpseRespawnDelay, fCorpseClearDelay); if (creatureStats.getTimeOfDeath() + delay <= MWBase::Environment::get().getWorld()->getTimeStamp()) diff --git a/apps/openmw/mwclass/ingredient.cpp b/apps/openmw/mwclass/ingredient.cpp index df7c61ebf..c133b6a26 100644 --- a/apps/openmw/mwclass/ingredient.cpp +++ b/apps/openmw/mwclass/ingredient.cpp @@ -138,7 +138,7 @@ namespace MWClass int alchemySkill = npcStats.getSkill (ESM::Skill::Alchemy).getBase(); static const float fWortChanceValue = - MWBase::Environment::get().getWorld()->getStore().get().find("fWortChanceValue")->getFloat(); + MWBase::Environment::get().getWorld()->getStore().get().find("fWortChanceValue")->mValue.getFloat(); MWGui::Widgets::SpellEffectList list; for (int i=0; i<4; ++i) diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 0b8b60feb..c247ee543 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -372,9 +372,9 @@ namespace MWClass if (!ref->mBase->mFaction.empty()) { static const int iAutoRepFacMod = MWBase::Environment::get().getWorld()->getStore().get() - .find("iAutoRepFacMod")->getInt(); + .find("iAutoRepFacMod")->mValue.getInteger(); static const int iAutoRepLevMod = MWBase::Environment::get().getWorld()->getStore().get() - .find("iAutoRepLevMod")->getInt(); + .find("iAutoRepLevMod")->mValue.getInteger(); int rank = ref->mBase->getFactionRank(); data->mNpcStats.setReputation(iAutoRepFacMod * (rank+1) + iAutoRepLevMod * (data->mNpcStats.getLevel()-1)); @@ -528,7 +528,7 @@ namespace MWClass const MWBase::World *world = MWBase::Environment::get().getWorld(); const MWWorld::Store &store = world->getStore().get(); - return store.find("sWerewolfPopup")->getString(); + return store.find("sWerewolfPopup")->mValue.getString(); } const MWWorld::LiveCellRef *ref = ptr.get(); @@ -565,10 +565,10 @@ namespace MWClass MWMechanics::applyFatigueLoss(ptr, weapon, attackStrength); - const float fCombatDistance = store.find("fCombatDistance")->getFloat(); + const float fCombatDistance = store.find("fCombatDistance")->mValue.getFloat(); float dist = fCombatDistance * (!weapon.isEmpty() ? weapon.get()->mBase->mData.mReach : - store.find("fHandToHandReach")->getFloat()); + store.find("fHandToHandReach")->mValue.getFloat()); // For AI actors, get combat targets to use in the ray cast. Only those targets will return a positive hit result. std::vector targetActors; @@ -638,14 +638,14 @@ namespace MWClass && !MWBase::Environment::get().getMechanicsManager()->awarenessCheck(ptr, victim); if(unaware) { - damage *= store.find("fCombatCriticalStrikeMult")->getFloat(); + damage *= store.find("fCombatCriticalStrikeMult")->mValue.getFloat(); MWBase::Environment::get().getWindowManager()->messageBox("#{sTargetCriticalStrike}"); MWBase::Environment::get().getSoundManager()->playSound3D(victim, "critical damage", 1.0f, 1.0f); } } if (othercls.getCreatureStats(victim).getKnockedDown()) - damage *= store.find("fCombatKODamageMult")->getFloat(); + damage *= store.find("fCombatKODamageMult")->mValue.getFloat(); // Apply "On hit" enchanted weapons MWMechanics::applyOnStrikeEnchantment(ptr, victim, weapon, hitPosition); @@ -737,14 +737,14 @@ namespace MWClass const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); const GMST& gmst = getGmst(); - int chance = store.get().find("iVoiceHitOdds")->getInt(); + int chance = store.get().find("iVoiceHitOdds")->mValue.getInteger(); if (Misc::Rng::roll0to99() < chance) MWBase::Environment::get().getDialogueManager()->say(ptr, "hit"); // Check for knockdown - float agilityTerm = stats.getAttribute(ESM::Attribute::Agility).getModified() * gmst.fKnockDownMult->getFloat(); + float agilityTerm = stats.getAttribute(ESM::Attribute::Agility).getModified() * gmst.fKnockDownMult->mValue.getFloat(); float knockdownTerm = stats.getAttribute(ESM::Attribute::Agility).getModified() - * gmst.iKnockDownOddsMult->getInt() * 0.01f + gmst.iKnockDownOddsBase->getInt(); + * gmst.iKnockDownOddsMult->mValue.getInteger() * 0.01f + gmst.iKnockDownOddsBase->mValue.getInteger(); if (ishealth && agilityTerm <= damage && knockdownTerm <= Misc::Rng::roll0to99()) stats.setKnockedDown(true); else @@ -772,7 +772,7 @@ namespace MWClass float unmitigatedDamage = damage; float x = damage / (damage + getArmorRating(ptr)); - damage *= std::max(gmst.fCombatArmorMinMult->getFloat(), x); + damage *= std::max(gmst.fCombatArmorMinMult->mValue.getFloat(), x); int damageDiff = static_cast(unmitigatedDamage - damage); damage = std::max(1.f, damage); damageDiff = std::max(1, damageDiff); @@ -941,15 +941,15 @@ namespace MWClass bool sneaking = stats.getStance(MWMechanics::CreatureStats::Stance_Sneak); bool running = stats.getStance(MWMechanics::CreatureStats::Stance_Run); - float walkSpeed = gmst.fMinWalkSpeed->getFloat() + 0.01f*npcdata->mNpcStats.getAttribute(ESM::Attribute::Speed).getModified()* - (gmst.fMaxWalkSpeed->getFloat() - gmst.fMinWalkSpeed->getFloat()); - walkSpeed *= 1.0f - gmst.fEncumberedMoveEffect->getFloat()*normalizedEncumbrance; + float walkSpeed = gmst.fMinWalkSpeed->mValue.getFloat() + 0.01f*npcdata->mNpcStats.getAttribute(ESM::Attribute::Speed).getModified()* + (gmst.fMaxWalkSpeed->mValue.getFloat() - gmst.fMinWalkSpeed->mValue.getFloat()); + walkSpeed *= 1.0f - gmst.fEncumberedMoveEffect->mValue.getFloat()*normalizedEncumbrance; walkSpeed = std::max(0.0f, walkSpeed); if(sneaking) - walkSpeed *= gmst.fSneakSpeedMultiplier->getFloat(); + walkSpeed *= gmst.fSneakSpeedMultiplier->mValue.getFloat(); float runSpeed = walkSpeed*(0.01f * npcdata->mNpcStats.getSkill(ESM::Skill::Athletics).getModified() * - gmst.fAthleticsRunBonus->getFloat() + gmst.fBaseRunMultiplier->getFloat()); + gmst.fAthleticsRunBonus->mValue.getFloat() + gmst.fBaseRunMultiplier->mValue.getFloat()); float moveSpeed; if(getEncumbrance(ptr) > getCapacity(ptr)) @@ -959,8 +959,8 @@ namespace MWClass { float flySpeed = 0.01f*(npcdata->mNpcStats.getAttribute(ESM::Attribute::Speed).getModified() + mageffects.get(ESM::MagicEffect::Levitate).getMagnitude()); - flySpeed = gmst.fMinFlySpeed->getFloat() + flySpeed*(gmst.fMaxFlySpeed->getFloat() - gmst.fMinFlySpeed->getFloat()); - flySpeed *= 1.0f - gmst.fEncumberedMoveEffect->getFloat() * normalizedEncumbrance; + flySpeed = gmst.fMinFlySpeed->mValue.getFloat() + flySpeed*(gmst.fMaxFlySpeed->mValue.getFloat() - gmst.fMinFlySpeed->mValue.getFloat()); + flySpeed *= 1.0f - gmst.fEncumberedMoveEffect->mValue.getFloat() * normalizedEncumbrance; flySpeed = std::max(0.0f, flySpeed); moveSpeed = flySpeed; } @@ -970,8 +970,8 @@ namespace MWClass if(running) swimSpeed = runSpeed; swimSpeed *= 1.0f + 0.01f * mageffects.get(ESM::MagicEffect::SwiftSwim).getMagnitude(); - swimSpeed *= gmst.fSwimRunBase->getFloat() + 0.01f*npcdata->mNpcStats.getSkill(ESM::Skill::Athletics).getModified()* - gmst.fSwimRunAthleticsMult->getFloat(); + swimSpeed *= gmst.fSwimRunBase->mValue.getFloat() + 0.01f*npcdata->mNpcStats.getSkill(ESM::Skill::Athletics).getModified()* + gmst.fSwimRunAthleticsMult->mValue.getFloat(); moveSpeed = swimSpeed; } else if(running && !sneaking) @@ -982,7 +982,7 @@ namespace MWClass moveSpeed *= 0.75f; if(npcdata->mNpcStats.isWerewolf() && running && npcdata->mNpcStats.getDrawState() == MWMechanics::DrawState_Nothing) - moveSpeed *= gmst.fWereWolfRunMult->getFloat(); + moveSpeed *= gmst.fWereWolfRunMult->mValue.getFloat(); return moveSpeed; } @@ -999,8 +999,8 @@ namespace MWClass const NpcCustomData *npcdata = static_cast(ptr.getRefData().getCustomData()); const GMST& gmst = getGmst(); const MWMechanics::MagicEffects &mageffects = npcdata->mNpcStats.getMagicEffects(); - const float encumbranceTerm = gmst.fJumpEncumbranceBase->getFloat() + - gmst.fJumpEncumbranceMultiplier->getFloat() * + const float encumbranceTerm = gmst.fJumpEncumbranceBase->mValue.getFloat() + + gmst.fJumpEncumbranceMultiplier->mValue.getFloat() * (1.0f - Npc::getNormalizedEncumbrance(ptr)); float a = static_cast(npcdata->mNpcStats.getSkill(ESM::Skill::Acrobatics).getModified()); @@ -1011,14 +1011,14 @@ namespace MWClass a = 50.0f; } - float x = gmst.fJumpAcrobaticsBase->getFloat() + - std::pow(a / 15.0f, gmst.fJumpAcroMultiplier->getFloat()); - x += 3.0f * b * gmst.fJumpAcroMultiplier->getFloat(); + float x = gmst.fJumpAcrobaticsBase->mValue.getFloat() + + std::pow(a / 15.0f, gmst.fJumpAcroMultiplier->mValue.getFloat()); + x += 3.0f * b * gmst.fJumpAcroMultiplier->mValue.getFloat(); x += mageffects.get(ESM::MagicEffect::Jump).getMagnitude() * 64; x *= encumbranceTerm; if(stats.getStance(MWMechanics::CreatureStats::Stance_Run)) - x *= gmst.fJumpRunMultiplier->getFloat(); + x *= gmst.fJumpRunMultiplier->mValue.getFloat(); x *= npcdata->mNpcStats.getFatigueTerm(); x -= -627.2f;/*gravity constant*/ x /= 3.0f; @@ -1083,7 +1083,7 @@ namespace MWClass float Npc::getCapacity (const MWWorld::Ptr& ptr) const { const MWMechanics::CreatureStats& stats = getCreatureStats (ptr); - static const float fEncumbranceStrMult = MWBase::Environment::get().getWorld()->getStore().get().find("fEncumbranceStrMult")->getFloat(); + static const float fEncumbranceStrMult = MWBase::Environment::get().getWorld()->getStore().get().find("fEncumbranceStrMult")->mValue.getFloat(); return stats.getAttribute(ESM::Attribute::Strength).getModified()*fEncumbranceStrMult; } @@ -1126,8 +1126,8 @@ namespace MWClass MWMechanics::NpcStats &stats = getNpcStats(ptr); const MWWorld::InventoryStore &invStore = getInventoryStore(ptr); - float fUnarmoredBase1 = store.find("fUnarmoredBase1")->getFloat(); - float fUnarmoredBase2 = store.find("fUnarmoredBase2")->getFloat(); + float fUnarmoredBase1 = store.find("fUnarmoredBase1")->mValue.getFloat(); + float fUnarmoredBase2 = store.find("fUnarmoredBase2")->mValue.getFloat(); int unarmoredSkill = stats.getSkill(ESM::Skill::Unarmored).getModified(); float ratings[MWWorld::InventoryStore::Slots]; @@ -1367,8 +1367,8 @@ namespace MWClass return; const MWWorld::Store& gmst = MWBase::Environment::get().getWorld()->getStore().get(); - static const float fCorpseRespawnDelay = gmst.find("fCorpseRespawnDelay")->getFloat(); - static const float fCorpseClearDelay = gmst.find("fCorpseClearDelay")->getFloat(); + static const float fCorpseRespawnDelay = gmst.find("fCorpseRespawnDelay")->mValue.getFloat(); + static const float fCorpseClearDelay = gmst.find("fCorpseClearDelay")->mValue.getFloat(); float delay = ptr.getRefData().getCount() == 0 ? fCorpseClearDelay : std::min(fCorpseRespawnDelay, fCorpseClearDelay); diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index bb1ca09a3..294aebd94 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -287,8 +287,8 @@ namespace MWClass std::string type = mapping[ref->mBase->mData.mType].first; std::string oneOrTwoHanded = mapping[ref->mBase->mData.mType].second; - text += store.get().find(type)->getString() + - ((oneOrTwoHanded != "") ? ", " + store.get().find(oneOrTwoHanded)->getString() : ""); + text += store.get().find(type)->mValue.getString() + + ((oneOrTwoHanded != "") ? ", " + store.get().find(oneOrTwoHanded)->mValue.getString() : ""); // weapon damage if (ref->mBase->mData.mType >= 9) @@ -326,7 +326,7 @@ namespace MWClass if (ref->mBase->mData.mType < 9 && Settings::Manager::getBool("show melee info", "Game")) { // 64 game units = 1 yard = 3 ft, display value in feet - const float combatDistance = store.get().find("fCombatDistance")->getFloat() * ref->mBase->mData.mReach; + const float combatDistance = store.get().find("fCombatDistance")->mValue.getFloat() * ref->mBase->mData.mReach; text += MWGui::ToolTips::getWeightString(combatDistance*3/64, "#{sRange}"); text += " #{sFeet}"; diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index c3e56c0bf..dcc33d1c3 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -261,7 +261,7 @@ namespace MWDialogue const MWWorld::Store& gmsts = MWBase::Environment::get().getWorld()->getStore().get(); - title = gmsts.find (modifiedTopic)->getString(); + title = gmsts.find (modifiedTopic)->mValue.getString(); } else title = topic; @@ -537,7 +537,7 @@ namespace MWDialogue MWScript::InterpreterContext interpreterContext(&mActor.getRefData().getLocals(),mActor); - callback->addResponse(gmsts.find ("sServiceRefusal")->getString(), Interpreter::fixDefinesDialog(info->mResponse, interpreterContext)); + callback->addResponse(gmsts.find ("sServiceRefusal")->mValue.getString(), Interpreter::fixDefinesDialog(info->mResponse, interpreterContext)); executeScript (info->mResultScript, mActor); return true; diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index aeb6dfc0f..6aceccaff 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -365,15 +365,15 @@ namespace MWGui const MWWorld::Store &gmst = MWBase::Environment::get().getWorld()->getStore().get(); - const std::string sPersuasion = gmst.find("sPersuasion")->getString(); - const std::string sCompanionShare = gmst.find("sCompanionShare")->getString(); - const std::string sBarter = gmst.find("sBarter")->getString(); - const std::string sSpells = gmst.find("sSpells")->getString(); - const std::string sTravel = gmst.find("sTravel")->getString(); - const std::string sSpellMakingMenuTitle = gmst.find("sSpellMakingMenuTitle")->getString(); - const std::string sEnchanting = gmst.find("sEnchanting")->getString(); - const std::string sServiceTrainingTitle = gmst.find("sServiceTrainingTitle")->getString(); - const std::string sRepair = gmst.find("sRepair")->getString(); + const std::string sPersuasion = gmst.find("sPersuasion")->mValue.getString(); + const std::string sCompanionShare = gmst.find("sCompanionShare")->mValue.getString(); + const std::string sBarter = gmst.find("sBarter")->mValue.getString(); + const std::string sSpells = gmst.find("sSpells")->mValue.getString(); + const std::string sTravel = gmst.find("sTravel")->mValue.getString(); + const std::string sSpellMakingMenuTitle = gmst.find("sSpellMakingMenuTitle")->mValue.getString(); + const std::string sEnchanting = gmst.find("sEnchanting")->mValue.getString(); + const std::string sServiceTrainingTitle = gmst.find("sServiceTrainingTitle")->mValue.getString(); + const std::string sRepair = gmst.find("sRepair")->mValue.getString(); if (topic != sPersuasion && topic != sCompanionShare && topic != sBarter && topic != sSpells && topic != sTravel && topic != sSpellMakingMenuTitle @@ -458,7 +458,7 @@ namespace MWGui void DialogueWindow::restock() { MWMechanics::CreatureStats &sellerStats = mPtr.getClass().getCreatureStats(mPtr); - float delay = MWBase::Environment::get().getWorld()->getStore().get().find("fBarterGoldResetDelay")->getFloat(); + float delay = MWBase::Environment::get().getWorld()->getStore().get().find("fBarterGoldResetDelay")->mValue.getFloat(); // Gold is restocked every 24h if (MWBase::Environment::get().getWorld()->getTimeStamp() >= sellerStats.getLastRestockTime() + delay) @@ -503,31 +503,31 @@ namespace MWGui MWBase::Environment::get().getWorld()->getStore().get(); if (mPtr.getTypeName() == typeid(ESM::NPC).name()) - mTopicsList->addItem(gmst.find("sPersuasion")->getString()); + mTopicsList->addItem(gmst.find("sPersuasion")->mValue.getString()); if (services & ESM::NPC::AllItems) - mTopicsList->addItem(gmst.find("sBarter")->getString()); + mTopicsList->addItem(gmst.find("sBarter")->mValue.getString()); if (services & ESM::NPC::Spells) - mTopicsList->addItem(gmst.find("sSpells")->getString()); + mTopicsList->addItem(gmst.find("sSpells")->mValue.getString()); if (travel) - mTopicsList->addItem(gmst.find("sTravel")->getString()); + mTopicsList->addItem(gmst.find("sTravel")->mValue.getString()); if (services & ESM::NPC::Spellmaking) - mTopicsList->addItem(gmst.find("sSpellmakingMenuTitle")->getString()); + mTopicsList->addItem(gmst.find("sSpellmakingMenuTitle")->mValue.getString()); if (services & ESM::NPC::Enchanting) - mTopicsList->addItem(gmst.find("sEnchanting")->getString()); + mTopicsList->addItem(gmst.find("sEnchanting")->mValue.getString()); if (services & ESM::NPC::Training) - mTopicsList->addItem(gmst.find("sServiceTrainingTitle")->getString()); + mTopicsList->addItem(gmst.find("sServiceTrainingTitle")->mValue.getString()); if (services & ESM::NPC::Repair) - mTopicsList->addItem(gmst.find("sRepair")->getString()); + mTopicsList->addItem(gmst.find("sRepair")->mValue.getString()); if (isCompanion()) - mTopicsList->addItem(gmst.find("sCompanionShare")->getString()); + mTopicsList->addItem(gmst.find("sCompanionShare")->mValue.getString()); if (mTopicsList->getItemCount() > 0) mTopicsList->addSeparator(); @@ -592,7 +592,7 @@ namespace MWGui Goodbye* link = new Goodbye(); link->eventActivated += MyGUI::newDelegate(this, &DialogueWindow::onGoodbyeActivated); mLinks.push_back(link); - std::string goodbye = MWBase::Environment::get().getWorld()->getStore().get().find("sGoodbye")->getString(); + std::string goodbye = MWBase::Environment::get().getWorld()->getStore().get().find("sGoodbye")->mValue.getString(); BookTypesetter::Style* questionStyle = typesetter->createHotStyle(body, textColours.answer, textColours.answerOver, textColours.answerPressed, TypesetBook::InteractiveId(link)); diff --git a/apps/openmw/mwgui/enchantingdialog.cpp b/apps/openmw/mwgui/enchantingdialog.cpp index f7764e0f1..8fbfa65c6 100644 --- a/apps/openmw/mwgui/enchantingdialog.cpp +++ b/apps/openmw/mwgui/enchantingdialog.cpp @@ -341,7 +341,7 @@ namespace MWGui MWWorld::Ptr item = (i == 0) ? mEnchanting.getOldItem() : mEnchanting.getGem(); if (MWBase::Environment::get().getMechanicsManager()->isItemStolenFrom(item.getCellRef().getRefId(), mPtr)) { - std::string msg = MWBase::Environment::get().getWorld()->getStore().get().find("sNotifyMessage49")->getString(); + std::string msg = MWBase::Environment::get().getWorld()->getStore().get().find("sNotifyMessage49")->mValue.getString(); if (msg.find("%s") != std::string::npos) msg.replace(msg.find("%s"), 2, item.getClass().getName(item)); MWBase::Environment::get().getWindowManager()->messageBox(msg); diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index 1841303f2..91467d490 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -611,7 +611,7 @@ namespace MWGui // Therefore any value < 1 should show as an empty health bar. We do the same in statswindow :) mEnemyHealth->setProgressPosition(static_cast(stats.getHealth().getCurrent() / stats.getHealth().getModified() * 100)); - static const float fNPCHealthBarFade = MWBase::Environment::get().getWorld()->getStore().get().find("fNPCHealthBarFade")->getFloat(); + static const float fNPCHealthBarFade = MWBase::Environment::get().getWorld()->getStore().get().find("fNPCHealthBarFade")->mValue.getFloat(); if (fNPCHealthBarFade > 0.f) mEnemyHealth->setAlpha(std::max(0.f, std::min(1.f, mEnemyHealthTimer/fNPCHealthBarFade))); @@ -620,7 +620,7 @@ namespace MWGui void HUD::setEnemy(const MWWorld::Ptr &enemy) { mEnemyActorId = enemy.getClass().getCreatureStats(enemy).getActorId(); - mEnemyHealthTimer = MWBase::Environment::get().getWorld()->getStore().get().find("fNPCHealthBarTime")->getFloat(); + mEnemyHealthTimer = MWBase::Environment::get().getWorld()->getStore().get().find("fNPCHealthBarTime")->mValue.getFloat(); if (!mEnemyHealth->getVisible()) mWeaponSpellBox->setPosition(mWeaponSpellBox->getPosition() - MyGUI::IntPoint(0,20)); mEnemyHealth->setVisible(true); diff --git a/apps/openmw/mwgui/jailscreen.cpp b/apps/openmw/mwgui/jailscreen.cpp index 9fa5927ac..1761e1346 100644 --- a/apps/openmw/mwgui/jailscreen.cpp +++ b/apps/openmw/mwgui/jailscreen.cpp @@ -99,9 +99,9 @@ namespace MWGui std::string message; if (mDays == 1) - message = gmst.find("sNotifyMessage42")->getString(); + message = gmst.find("sNotifyMessage42")->mValue.getString(); else - message = gmst.find("sNotifyMessage43")->getString(); + message = gmst.find("sNotifyMessage43")->mValue.getString(); std::stringstream dayStr; dayStr << mDays; @@ -110,12 +110,12 @@ namespace MWGui for (std::set::iterator it = skills.begin(); it != skills.end(); ++it) { - std::string skillName = gmst.find(ESM::Skill::sSkillNameIds[*it])->getString(); + std::string skillName = gmst.find(ESM::Skill::sSkillNameIds[*it])->mValue.getString(); std::stringstream skillValue; skillValue << player.getClass().getNpcStats(player).getSkill(*it).getBase(); - std::string skillMsg = gmst.find("sNotifyMessage44")->getString(); + std::string skillMsg = gmst.find("sNotifyMessage44")->mValue.getString(); if (*it == ESM::Skill::Sneak || *it == ESM::Skill::Security) - skillMsg = gmst.find("sNotifyMessage39")->getString(); + skillMsg = gmst.find("sNotifyMessage39")->mValue.getString(); if (skillMsg.find("%s") != std::string::npos) skillMsg.replace(skillMsg.find("%s"), 2, skillName); diff --git a/apps/openmw/mwgui/merchantrepair.cpp b/apps/openmw/mwgui/merchantrepair.cpp index d3504ebc3..9974c6d16 100644 --- a/apps/openmw/mwgui/merchantrepair.cpp +++ b/apps/openmw/mwgui/merchantrepair.cpp @@ -57,7 +57,7 @@ void MerchantRepair::setPtr(const MWWorld::Ptr &actor) int basePrice = iter->getClass().getValue(*iter); float fRepairMult = MWBase::Environment::get().getWorld()->getStore().get() - .find("fRepairMult")->getFloat(); + .find("fRepairMult")->mValue.getFloat(); float p = static_cast(std::max(1, basePrice)); float r = static_cast(std::max(1, static_cast(maxDurability / p))); @@ -71,7 +71,7 @@ void MerchantRepair::setPtr(const MWWorld::Ptr &actor) std::string name = iter->getClass().getName(*iter) + " - " + MyGUI::utility::toString(price) + MWBase::Environment::get().getWorld()->getStore().get() - .find("sgp")->getString(); + .find("sgp")->mValue.getString(); MyGUI::Button* button = diff --git a/apps/openmw/mwgui/recharge.cpp b/apps/openmw/mwgui/recharge.cpp index 26a364f72..3133dc0cb 100644 --- a/apps/openmw/mwgui/recharge.cpp +++ b/apps/openmw/mwgui/recharge.cpp @@ -181,7 +181,7 @@ void Recharge::onItemClicked(MyGUI::Widget *sender, const MWWorld::Ptr& item) if (gem.getRefData().getCount() == 0) { - std::string message = MWBase::Environment::get().getWorld()->getStore().get().find("sNotifyMessage51")->getString(); + std::string message = MWBase::Environment::get().getWorld()->getStore().get().find("sNotifyMessage51")->mValue.getString(); message = boost::str(boost::format(message) % gem.getClass().getName(gem)); MWBase::Environment::get().getWindowManager()->messageBox(message); diff --git a/apps/openmw/mwgui/spellbuyingwindow.cpp b/apps/openmw/mwgui/spellbuyingwindow.cpp index d9c3a5f16..9876013f1 100644 --- a/apps/openmw/mwgui/spellbuyingwindow.cpp +++ b/apps/openmw/mwgui/spellbuyingwindow.cpp @@ -44,7 +44,7 @@ namespace MWGui const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); - int price = static_cast(spell.mData.mCost*store.get().find("fSpellValueMult")->getFloat()); + int price = static_cast(spell.mData.mCost*store.get().find("fSpellValueMult")->mValue.getFloat()); price = MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mPtr,price,true); MWWorld::Ptr player = MWMechanics::getPlayer(); diff --git a/apps/openmw/mwgui/spellcreationdialog.cpp b/apps/openmw/mwgui/spellcreationdialog.cpp index 4aa208d8f..65d66f9e2 100644 --- a/apps/openmw/mwgui/spellcreationdialog.cpp +++ b/apps/openmw/mwgui/spellcreationdialog.cpp @@ -32,8 +32,8 @@ namespace const MWWorld::Store &gmst = MWBase::Environment::get().getWorld()->getStore().get(); - return gmst.find(ESM::MagicEffect::effectIdToString (id1))->getString() - < gmst.find(ESM::MagicEffect::effectIdToString (id2))->getString(); + return gmst.find(ESM::MagicEffect::effectIdToString (id1))->mValue.getString() + < gmst.find(ESM::MagicEffect::effectIdToString (id2))->mValue.getString(); } void init(ESM::ENAMstruct& effect) @@ -469,7 +469,7 @@ namespace MWGui mMagickaCost->setCaption(MyGUI::utility::toString(int(y))); float fSpellMakingValueMult = - store.get().find("fSpellMakingValueMult")->getFloat(); + store.get().find("fSpellMakingValueMult")->mValue.getFloat(); int price = MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mPtr, static_cast(y * fSpellMakingValueMult),true); @@ -547,7 +547,7 @@ namespace MWGui for (std::vector::const_iterator it = knownEffects.begin(); it != knownEffects.end(); ++it) { mAvailableEffectsList->addItem(MWBase::Environment::get().getWorld ()->getStore ().get().find( - ESM::MagicEffect::effectIdToString (*it))->getString()); + ESM::MagicEffect::effectIdToString (*it))->mValue.getString()); mButtonMapping[i] = *it; ++i; } @@ -557,7 +557,7 @@ namespace MWGui for (std::vector::const_iterator it = knownEffects.begin(); it != knownEffects.end(); ++it) { std::string name = MWBase::Environment::get().getWorld ()->getStore ().get().find( - ESM::MagicEffect::effectIdToString (*it))->getString(); + ESM::MagicEffect::effectIdToString (*it))->mValue.getString(); MyGUI::Widget* w = mAvailableEffectsList->getItemWidget(name); ToolTips::createMagicEffectToolTip (w, *it); diff --git a/apps/openmw/mwgui/spellicons.cpp b/apps/openmw/mwgui/spellicons.cpp index 27896381e..c0f56e654 100644 --- a/apps/openmw/mwgui/spellicons.cpp +++ b/apps/openmw/mwgui/spellicons.cpp @@ -75,7 +75,7 @@ namespace MWGui std::string sourcesDescription; - static const float fadeTime = MWBase::Environment::get().getWorld()->getStore().get().find("fMagicStartIconBlink")->getFloat(); + static const float fadeTime = MWBase::Environment::get().getWorld()->getStore().get().find("fMagicStartIconBlink")->mValue.getFloat(); for (std::vector::const_iterator effectIt = it->second.begin(); effectIt != it->second.end(); ++effectIt) diff --git a/apps/openmw/mwgui/statswindow.cpp b/apps/openmw/mwgui/statswindow.cpp index d3d487579..db73351bf 100644 --- a/apps/openmw/mwgui/statswindow.cpp +++ b/apps/openmw/mwgui/statswindow.cpp @@ -61,7 +61,7 @@ namespace MWGui const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); for (int i=0; names[i][0]; ++i) { - setText (names[i][0], store.get().find (names[i][1])->getString()); + setText (names[i][0], store.get().find (names[i][1])->mValue.getString()); } getWidget(mSkillView, "SkillView"); @@ -306,7 +306,7 @@ namespace MWGui MyGUI::Widget* levelWidget; for (int i=0; i<2; ++i) { - int max = MWBase::Environment::get().getWorld()->getStore().get().find("iLevelUpTotal")->getInt(); + int max = MWBase::Environment::get().getWorld()->getStore().get().find("iLevelUpTotal")->mValue.getInteger(); getWidget(levelWidget, i==0 ? "Level_str" : "LevelText"); levelWidget->setUserString("RangePosition_LevelProgress", MyGUI::utility::toString(PCstats.getLevelProgress())); levelWidget->setUserString("Range_LevelProgress", MyGUI::utility::toString(max)); diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index e11147c74..3871baa09 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -313,7 +313,7 @@ namespace MWGui { if (MWBase::Environment::get().getMechanicsManager()->isItemStolenFrom(it->mBase.getCellRef().getRefId(), mPtr)) { - std::string msg = gmst.find("sNotifyMessage49")->getString(); + std::string msg = gmst.find("sNotifyMessage49")->mValue.getString(); if (msg.find("%s") != std::string::npos) msg.replace(msg.find("%s"), 2, it->mBase.getClass().getName(it->mBase)); MWBase::Environment::get().getWindowManager()->messageBox(msg); @@ -331,8 +331,8 @@ namespace MWGui // apply disposition change if merchant is NPC if ( mPtr.getClass().isNpc() ) { int dispositionDelta = offerAccepted - ? gmst.find("iBarterSuccessDisposition")->getInt() - : gmst.find("iBarterFailDisposition")->getInt(); + ? gmst.find("iBarterSuccessDisposition")->mValue.getInteger() + : gmst.find("iBarterFailDisposition")->mValue.getInteger(); MWBase::Environment::get().getDialogueManager()->applyBarterDispositionChange(dispositionDelta); } diff --git a/apps/openmw/mwgui/trainingwindow.cpp b/apps/openmw/mwgui/trainingwindow.cpp index 630ba8ce1..b309da27d 100644 --- a/apps/openmw/mwgui/trainingwindow.cpp +++ b/apps/openmw/mwgui/trainingwindow.cpp @@ -98,7 +98,7 @@ namespace MWGui for (int i=0; i<3; ++i) { int price = MWBase::Environment::get().getMechanicsManager()->getBarterOffer - (mPtr,pcStats.getSkill (skills[i].first).getBase() * gmst.find("iTrainingMod")->getInt (),true); + (mPtr,pcStats.getSkill (skills[i].first).getBase() * gmst.find("iTrainingMod")->mValue.getInteger(),true); 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); @@ -136,7 +136,7 @@ namespace MWGui const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); - int price = pcStats.getSkill (skillId).getBase() * store.get().find("iTrainingMod")->getInt (); + int price = pcStats.getSkill (skillId).getBase() * store.get().find("iTrainingMod")->mValue.getInteger(); price = MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mPtr,price,true); if (price > player.getClass().getContainerStore(player).count(MWWorld::ContainerStore::sGoldId)) diff --git a/apps/openmw/mwgui/travelwindow.cpp b/apps/openmw/mwgui/travelwindow.cpp index cf4fb1b5e..23a5b322f 100644 --- a/apps/openmw/mwgui/travelwindow.cpp +++ b/apps/openmw/mwgui/travelwindow.cpp @@ -58,13 +58,13 @@ namespace MWGui if (!mPtr.getCell()->isExterior()) { - price = gmst.find("fMagesGuildTravel")->getInt(); + price = gmst.find("fMagesGuildTravel")->mValue.getInteger(); } else { ESM::Position PlayerPos = player.getRefData().getPosition(); float d = sqrt(pow(pos.pos[0] - PlayerPos.pos[0], 2) + pow(pos.pos[1] - PlayerPos.pos[1], 2) + pow(pos.pos[2] - PlayerPos.pos[2], 2)); - price = static_cast(d / gmst.find("fTravelMult")->getFloat()); + price = static_cast(d / gmst.find("fTravelMult")->mValue.getFloat()); } price = MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mPtr, price, true); @@ -176,7 +176,7 @@ namespace MWGui { ESM::Position playerPos = player.getRefData().getPosition(); float d = (osg::Vec3f(pos.pos[0], pos.pos[1], 0) - osg::Vec3f(playerPos.pos[0], playerPos.pos[1], 0)).length(); - int hours = static_cast(d /MWBase::Environment::get().getWorld()->getStore().get().find("fTravelTimeMult")->getFloat()); + int hours = static_cast(d /MWBase::Environment::get().getWorld()->getStore().get().find("fTravelTimeMult")->mValue.getFloat()); for(int i = 0;i < hours;i++) { MWBase::Environment::get().getMechanicsManager ()->rest (true); diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index 52575e25c..c5a06a12c 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -183,10 +183,10 @@ namespace MWGui { // figure out if player will be woken while sleeping int x = Misc::Rng::rollDice(hoursToWait); - float fSleepRandMod = world->getStore().get().find("fSleepRandMod")->getFloat(); + float fSleepRandMod = world->getStore().get().find("fSleepRandMod")->mValue.getFloat(); if (x < fSleepRandMod * hoursToWait) { - float fSleepRestMod = world->getStore().get().find("fSleepRestMod")->getFloat(); + float fSleepRestMod = world->getStore().get().find("fSleepRestMod")->mValue.getFloat(); int interruptAtHoursRemaining = int(fSleepRestMod * hoursToWait); if (interruptAtHoursRemaining != 0) { @@ -252,7 +252,7 @@ namespace MWGui // trigger levelup if possible const MWWorld::Store &gmst = MWBase::Environment::get().getWorld()->getStore().get(); - if (mSleeping && pcstats.getLevelProgress () >= gmst.find("iLevelUpTotal")->getInt()) + if (mSleeping && pcstats.getLevelProgress () >= gmst.find("iLevelUpTotal")->mValue.getInteger()) { MWBase::Environment::get().getWindowManager()->pushGuiMode (GM_Levelup); } diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index e1bf9627d..45897b88c 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -358,7 +358,7 @@ namespace MWGui mGuiModeStates[GM_Journal].mCloseSound = "book close"; mGuiModeStates[GM_Journal].mOpenSound = "book open"; - mMessageBoxManager = new MessageBoxManager(mStore->get().find("fMessageTimePerChar")->getFloat()); + mMessageBoxManager = new MessageBoxManager(mStore->get().find("fMessageTimePerChar")->mValue.getFloat()); SpellBuyingWindow* spellBuyingWindow = new SpellBuyingWindow(); mWindows.push_back(spellBuyingWindow); diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 65fc0c098..b24c8cc14 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -1192,7 +1192,7 @@ namespace MWInput void InputManager::updateIdleTime(float dt) { static const float vanityDelay = MWBase::Environment::get().getWorld()->getStore().get() - .find("fVanityDelay")->getFloat(); + .find("fVanityDelay")->mValue.getFloat(); if (mTimeIdle >= 0.f) mTimeIdle += dt; if (mTimeIdle > vanityDelay) { diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index ba8f62e2f..0ee49ac45 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -54,22 +54,22 @@ int getBoundItemSlot (const std::string& itemId) static std::map boundItemsMap; if (boundItemsMap.empty()) { - std::string boundId = MWBase::Environment::get().getWorld()->getStore().get().find("sMagicBoundBootsID")->getString(); + std::string boundId = MWBase::Environment::get().getWorld()->getStore().get().find("sMagicBoundBootsID")->mValue.getString(); boundItemsMap[boundId] = MWWorld::InventoryStore::Slot_Boots; - boundId = MWBase::Environment::get().getWorld()->getStore().get().find("sMagicBoundCuirassID")->getString(); + boundId = MWBase::Environment::get().getWorld()->getStore().get().find("sMagicBoundCuirassID")->mValue.getString(); boundItemsMap[boundId] = MWWorld::InventoryStore::Slot_Cuirass; - boundId = MWBase::Environment::get().getWorld()->getStore().get().find("sMagicBoundLeftGauntletID")->getString(); + boundId = MWBase::Environment::get().getWorld()->getStore().get().find("sMagicBoundLeftGauntletID")->mValue.getString(); boundItemsMap[boundId] = MWWorld::InventoryStore::Slot_LeftGauntlet; - boundId = MWBase::Environment::get().getWorld()->getStore().get().find("sMagicBoundRightGauntletID")->getString(); + boundId = MWBase::Environment::get().getWorld()->getStore().get().find("sMagicBoundRightGauntletID")->mValue.getString(); boundItemsMap[boundId] = MWWorld::InventoryStore::Slot_RightGauntlet; - boundId = MWBase::Environment::get().getWorld()->getStore().get().find("sMagicBoundHelmID")->getString(); + boundId = MWBase::Environment::get().getWorld()->getStore().get().find("sMagicBoundHelmID")->mValue.getString(); boundItemsMap[boundId] = MWWorld::InventoryStore::Slot_Helmet; - boundId = MWBase::Environment::get().getWorld()->getStore().get().find("sMagicBoundShieldID")->getString(); + boundId = MWBase::Environment::get().getWorld()->getStore().get().find("sMagicBoundShieldID")->mValue.getString(); boundItemsMap[boundId] = MWWorld::InventoryStore::Slot_CarriedLeft; } @@ -138,7 +138,7 @@ void getRestorationPerHourOfSleep (const MWWorld::Ptr& ptr, float& health, float magicka = 0; if (!stunted) { - float fRestMagicMult = settings.find("fRestMagicMult")->getFloat (); + float fRestMagicMult = settings.find("fRestMagicMult")->mValue.getFloat (); magicka = fRestMagicMult * stats.getAttribute(ESM::Attribute::Intelligence).getModified(); } } @@ -179,7 +179,7 @@ namespace MWMechanics if (caster.isEmpty() || !caster.getClass().isActor()) return; - static const float fSoulgemMult = world->getStore().get().find("fSoulgemMult")->getFloat(); + static const float fSoulgemMult = world->getStore().get().find("fSoulgemMult")->mValue.getFloat(); int creatureSoulValue = mCreature.get()->mBase->mData.mSoul; if (creatureSoulValue == 0) @@ -313,9 +313,9 @@ namespace MWMechanics MWWorld::Ptr& headTrackTarget, float& sqrHeadTrackDistance) { static const float fMaxHeadTrackDistance = MWBase::Environment::get().getWorld()->getStore().get() - .find("fMaxHeadTrackDistance")->getFloat(); + .find("fMaxHeadTrackDistance")->mValue.getFloat(); static const float fInteriorHeadTrackMult = MWBase::Environment::get().getWorld()->getStore().get() - .find("fInteriorHeadTrackMult")->getFloat(); + .find("fInteriorHeadTrackMult")->mValue.getFloat(); float maxDistance = fMaxHeadTrackDistance; const ESM::Cell* currentCell = actor.getCell()->getCell(); if (!currentCell->isExterior() && !(currentCell->mData.mFlags & ESM::Cell::QuasiEx)) @@ -470,7 +470,7 @@ namespace MWMechanics if (actor1.getClass().isClass(actor1, "Guard") && !actor2.getClass().isNpc()) { // Check if the creature is too far - static const float fAlarmRadius = MWBase::Environment::get().getWorld()->getStore().get().find("fAlarmRadius")->getFloat(); + static const float fAlarmRadius = MWBase::Environment::get().getWorld()->getStore().get().find("fAlarmRadius")->mValue.getFloat(); if (sqrDist > fAlarmRadius * fAlarmRadius) return; @@ -534,9 +534,9 @@ namespace MWMechanics float base = 1.f; if (ptr == getPlayer()) - base = MWBase::Environment::get().getWorld()->getStore().get().find("fPCbaseMagickaMult")->getFloat(); + base = MWBase::Environment::get().getWorld()->getStore().get().find("fPCbaseMagickaMult")->mValue.getFloat(); else - base = MWBase::Environment::get().getWorld()->getStore().get().find("fNPCbaseMagickaMult")->getFloat(); + base = MWBase::Environment::get().getWorld()->getStore().get().find("fNPCbaseMagickaMult")->mValue.getFloat(); double magickaFactor = base + creatureStats.getMagicEffects().get (EffectKey (ESM::MagicEffect::FortifyMaximumMagicka)).getMagnitude() * 0.1; @@ -584,9 +584,9 @@ namespace MWMechanics return; // Restore fatigue - float fFatigueReturnBase = settings.find("fFatigueReturnBase")->getFloat (); - float fFatigueReturnMult = settings.find("fFatigueReturnMult")->getFloat (); - float fEndFatigueMult = settings.find("fEndFatigueMult")->getFloat (); + float fFatigueReturnBase = settings.find("fFatigueReturnBase")->mValue.getFloat (); + float fFatigueReturnMult = settings.find("fFatigueReturnMult")->mValue.getFloat (); + float fEndFatigueMult = settings.find("fEndFatigueMult")->mValue.getFloat (); float x = fFatigueReturnBase + fFatigueReturnMult * (1 - normalizedEncumbrance); x *= fEndFatigueMult * endurance; @@ -611,8 +611,8 @@ namespace MWMechanics // Restore fatigue int endurance = stats.getAttribute(ESM::Attribute::Endurance).getModified(); const MWWorld::Store& settings = MWBase::Environment::get().getWorld()->getStore().get(); - static const float fFatigueReturnBase = settings.find("fFatigueReturnBase")->getFloat (); - static const float fFatigueReturnMult = settings.find("fFatigueReturnMult")->getFloat (); + static const float fFatigueReturnBase = settings.find("fFatigueReturnBase")->mValue.getFloat (); + static const float fFatigueReturnMult = settings.find("fFatigueReturnMult")->mValue.getFloat (); float x = fFatigueReturnBase + fFatigueReturnMult * endurance; @@ -853,14 +853,14 @@ namespace MWMechanics std::string itemGmst = it->second; std::string item = MWBase::Environment::get().getWorld()->getStore().get().find( - itemGmst)->getString(); + itemGmst)->mValue.getString(); magnitude > 0 ? addBoundItem(item, ptr) : removeBoundItem(item, ptr); if (it->first == ESM::MagicEffect::BoundGloves) { item = MWBase::Environment::get().getWorld()->getStore().get().find( - "sMagicBoundRightGauntletID")->getString(); + "sMagicBoundRightGauntletID")->mValue.getString(); magnitude > 0 ? addBoundItem(item, ptr) : removeBoundItem(item, ptr); } } @@ -936,7 +936,7 @@ namespace MWMechanics NpcStats &stats = ptr.getClass().getNpcStats(ptr); // When npc stats are just initialized, mTimeToStartDrowning == -1 and we should get value from GMST - static const float fHoldBreathTime = MWBase::Environment::get().getWorld()->getStore().get().find("fHoldBreathTime")->getFloat(); + static const float fHoldBreathTime = MWBase::Environment::get().getWorld()->getStore().get().find("fHoldBreathTime")->mValue.getFloat(); if (stats.getTimeToStartDrowning() == -1.f) stats.setTimeToStartDrowning(fHoldBreathTime); @@ -970,7 +970,7 @@ namespace MWMechanics if(timeLeft == 0.0f && !godmode) { // If drowning, apply 3 points of damage per second - static const float fSuffocationDamage = world->getStore().get().find("fSuffocationDamage")->getFloat(); + static const float fSuffocationDamage = world->getStore().get().find("fSuffocationDamage")->mValue.getFloat(); DynamicStat health = stats.getHealth(); health.setCurrent(health.getCurrent() - fSuffocationDamage*duration); stats.setHealth(health); @@ -1096,7 +1096,7 @@ namespace MWMechanics && creatureStats.getMagicEffects().get(ESM::MagicEffect::CalmHumanoid).getMagnitude() == 0) { const MWWorld::ESMStore& esmStore = MWBase::Environment::get().getWorld()->getStore(); - static const int cutoff = esmStore.get().find("iCrimeThreshold")->getInt(); + static const int cutoff = esmStore.get().find("iCrimeThreshold")->mValue.getInteger(); // Force dialogue on sight if bounty is greater than the cutoff // In vanilla morrowind, the greeting dialogue is scripted to either arrest the player (< 5000 bounty) or attack (>= 5000 bounty) if ( player.getClass().getNpcStats(player).getBounty() >= cutoff @@ -1104,7 +1104,7 @@ namespace MWMechanics && MWBase::Environment::get().getWorld()->getLOS(ptr, player) && MWBase::Environment::get().getMechanicsManager()->awarenessCheck(player, ptr)) { - static const int iCrimeThresholdMultiplier = esmStore.get().find("iCrimeThresholdMultiplier")->getInt(); + static const int iCrimeThresholdMultiplier = esmStore.get().find("iCrimeThresholdMultiplier")->mValue.getInteger(); if (player.getClass().getNpcStats(player).getBounty() >= cutoff * iCrimeThresholdMultiplier) { MWBase::Environment::get().getMechanicsManager()->startCombat(ptr, player); @@ -1487,9 +1487,9 @@ namespace MWMechanics static float sneakSkillTimer = 0.f; // times sneak skill progress from "avoid notice" const MWWorld::ESMStore& esmStore = MWBase::Environment::get().getWorld()->getStore(); - const int radius = esmStore.get().find("fSneakUseDist")->getInt(); + const int radius = esmStore.get().find("fSneakUseDist")->mValue.getInteger(); - static float fSneakUseDelay = esmStore.get().find("fSneakUseDelay")->getFloat(); + static float fSneakUseDelay = esmStore.get().find("fSneakUseDelay")->mValue.getFloat(); if (sneakTimer >= fSneakUseDelay) sneakTimer = 0.f; diff --git a/apps/openmw/mwmechanics/aibreathe.cpp b/apps/openmw/mwmechanics/aibreathe.cpp index 4e0076824..36acc75d5 100644 --- a/apps/openmw/mwmechanics/aibreathe.cpp +++ b/apps/openmw/mwmechanics/aibreathe.cpp @@ -19,7 +19,7 @@ MWMechanics::AiBreathe::AiBreathe() bool MWMechanics::AiBreathe::execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) { - static const float fHoldBreathTime = MWBase::Environment::get().getWorld()->getStore().get().find("fHoldBreathTime")->getFloat(); + static const float fHoldBreathTime = MWBase::Environment::get().getWorld()->getStore().get().find("fHoldBreathTime")->mValue.getFloat(); const MWWorld::Class& actorClass = actor.getClass(); if (actorClass.isNpc()) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index 438f4f7c6..9824347e3 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -351,7 +351,7 @@ namespace MWMechanics case AiCombatStorage::FleeState_RunToDestination: { - static const float fFleeDistance = MWBase::Environment::get().getWorld()->getStore().get().find("fFleeDistance")->getFloat(); + static const float fFleeDistance = MWBase::Environment::get().getWorld()->getStore().get().find("fFleeDistance")->mValue.getFloat(); float dist = (actor.getRefData().getPosition().asVec3() - target.getRefData().getPosition().asVec3()).length(); if ((dist > fFleeDistance && !storage.mLOS) @@ -520,13 +520,13 @@ namespace MWMechanics const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); - float baseDelay = store.get().find("fCombatDelayCreature")->getFloat(); + float baseDelay = store.get().find("fCombatDelayCreature")->mValue.getFloat(); if (actor.getClass().isNpc()) { - baseDelay = store.get().find("fCombatDelayNPC")->getFloat(); + baseDelay = store.get().find("fCombatDelayNPC")->mValue.getFloat(); //say a provoking combat phrase - int chance = store.get().find("iVoiceAttackOdds")->getInt(); + int chance = store.get().find("iVoiceAttackOdds")->mValue.getInteger(); if (Misc::Rng::roll0to99() < chance) { MWBase::Environment::get().getDialogueManager()->say(actor, "attack"); @@ -616,21 +616,21 @@ osg::Vec3f AimDirToMovingTarget(const MWWorld::Ptr& actor, const MWWorld::Ptr& t // get projectile speed (depending on weapon type) if (weapType == ESM::Weapon::MarksmanThrown) { - static float fThrownWeaponMinSpeed = gmst.find("fThrownWeaponMinSpeed")->getFloat(); - static float fThrownWeaponMaxSpeed = gmst.find("fThrownWeaponMaxSpeed")->getFloat(); + static float fThrownWeaponMinSpeed = gmst.find("fThrownWeaponMinSpeed")->mValue.getFloat(); + static float fThrownWeaponMaxSpeed = gmst.find("fThrownWeaponMaxSpeed")->mValue.getFloat(); projSpeed = fThrownWeaponMinSpeed + (fThrownWeaponMaxSpeed - fThrownWeaponMinSpeed) * strength; } else if (weapType != 0) { - static float fProjectileMinSpeed = gmst.find("fProjectileMinSpeed")->getFloat(); - static float fProjectileMaxSpeed = gmst.find("fProjectileMaxSpeed")->getFloat(); + static float fProjectileMinSpeed = gmst.find("fProjectileMinSpeed")->mValue.getFloat(); + static float fProjectileMaxSpeed = gmst.find("fProjectileMaxSpeed")->mValue.getFloat(); projSpeed = fProjectileMinSpeed + (fProjectileMaxSpeed - fProjectileMinSpeed) * strength; } else // weapType is 0 ==> it's a target spell projectile { - projSpeed = gmst.find("fTargetSpellMaxSpeed")->getFloat(); + projSpeed = gmst.find("fTargetSpellMaxSpeed")->mValue.getFloat(); } // idea: perpendicular to dir to target speed components of target move vector and projectile vector should be the same diff --git a/apps/openmw/mwmechanics/aicombataction.cpp b/apps/openmw/mwmechanics/aicombataction.cpp index 2685e0e0c..52da1417e 100644 --- a/apps/openmw/mwmechanics/aicombataction.cpp +++ b/apps/openmw/mwmechanics/aicombataction.cpp @@ -23,8 +23,8 @@ namespace MWMechanics { float suggestCombatRange(int rangeTypes) { - static const float fCombatDistance = MWBase::Environment::get().getWorld()->getStore().get().find("fCombatDistance")->getFloat(); - static float fHandToHandReach = MWBase::Environment::get().getWorld()->getStore().get().find("fHandToHandReach")->getFloat(); + static const float fCombatDistance = MWBase::Environment::get().getWorld()->getStore().get().find("fCombatDistance")->mValue.getFloat(); + static float fHandToHandReach = MWBase::Environment::get().getWorld()->getStore().get().find("fHandToHandReach")->mValue.getFloat(); // This distance is a possible distance of melee attack static float distance = fCombatDistance * std::max(2.f, fHandToHandReach); @@ -114,13 +114,13 @@ namespace MWMechanics { isRanged = false; - static const float fCombatDistance = MWBase::Environment::get().getWorld()->getStore().get().find("fCombatDistance")->getFloat(); - static const float fProjectileMaxSpeed = MWBase::Environment::get().getWorld()->getStore().get().find("fProjectileMaxSpeed")->getFloat(); + static const float fCombatDistance = MWBase::Environment::get().getWorld()->getStore().get().find("fCombatDistance")->mValue.getFloat(); + static const float fProjectileMaxSpeed = MWBase::Environment::get().getWorld()->getStore().get().find("fProjectileMaxSpeed")->mValue.getFloat(); if (mWeapon.isEmpty()) { static float fHandToHandReach = - MWBase::Environment::get().getWorld()->getStore().get().find("fHandToHandReach")->getFloat(); + MWBase::Environment::get().getWorld()->getStore().get().find("fHandToHandReach")->mValue.getFloat(); return fHandToHandReach * fCombatDistance; } @@ -336,7 +336,7 @@ namespace MWMechanics float dist = 1.0f; if (activeWeapon.isEmpty() && !selectedSpellId.empty() && !selectedEnchItem.isEmpty()) { - static const float fHandToHandReach = gmst.find("fHandToHandReach")->getFloat(); + static const float fHandToHandReach = gmst.find("fHandToHandReach")->mValue.getFloat(); dist = fHandToHandReach; } else if (stats.getDrawState() == MWMechanics::DrawState_Spell) @@ -375,7 +375,7 @@ namespace MWMechanics } } - static const float fTargetSpellMaxSpeed = gmst.find("fTargetSpellMaxSpeed")->getFloat(); + static const float fTargetSpellMaxSpeed = gmst.find("fTargetSpellMaxSpeed")->mValue.getFloat(); dist *= std::max(1000.0f, fTargetSpellMaxSpeed); } else if (!activeWeapon.isEmpty()) @@ -383,7 +383,7 @@ namespace MWMechanics const ESM::Weapon* esmWeap = activeWeapon.get()->mBase; if (esmWeap->mData.mType >= ESM::Weapon::MarksmanBow) { - static const float fTargetSpellMaxSpeed = gmst.find("fProjectileMaxSpeed")->getFloat(); + static const float fTargetSpellMaxSpeed = gmst.find("fProjectileMaxSpeed")->mValue.getFloat(); dist = fTargetSpellMaxSpeed; if (!activeAmmo.isEmpty()) { @@ -399,8 +399,8 @@ namespace MWMechanics dist = (dist > 0.f) ? dist : 1.0f; - static const float fCombatDistance = gmst.find("fCombatDistance")->getFloat(); - static const float fCombatDistanceWerewolfMod = gmst.find("fCombatDistanceWerewolfMod")->getFloat(); + static const float fCombatDistance = gmst.find("fCombatDistance")->mValue.getFloat(); + static const float fCombatDistanceWerewolfMod = gmst.find("fCombatDistanceWerewolfMod")->mValue.getFloat(); float combatDistance = fCombatDistance; if (actor.getClass().isNpc() && actor.getClass().getNpcStats(actor).isWerewolf()) @@ -485,20 +485,20 @@ namespace MWMechanics if (flee >= 100) return flee; - static const float fAIFleeHealthMult = gmst.find("fAIFleeHealthMult")->getFloat(); - static const float fAIFleeFleeMult = gmst.find("fAIFleeFleeMult")->getFloat(); + static const float fAIFleeHealthMult = gmst.find("fAIFleeHealthMult")->mValue.getFloat(); + static const float fAIFleeFleeMult = gmst.find("fAIFleeFleeMult")->mValue.getFloat(); float healthPercentage = (stats.getHealth().getModified() == 0.0f) ? 1.0f : stats.getHealth().getCurrent() / stats.getHealth().getModified(); float rating = (1.0f - healthPercentage) * fAIFleeHealthMult + flee * fAIFleeFleeMult; - static const int iWereWolfLevelToAttack = gmst.find("iWereWolfLevelToAttack")->getInt(); + static const int iWereWolfLevelToAttack = gmst.find("iWereWolfLevelToAttack")->mValue.getInteger(); if (actor.getClass().isNpc() && enemy.getClass().isNpc()) { if (enemy.getClass().getNpcStats(enemy).isWerewolf() && stats.getLevel() < iWereWolfLevelToAttack) { - static const int iWereWolfFleeMod = gmst.find("iWereWolfFleeMod")->getInt(); + static const int iWereWolfFleeMod = gmst.find("iWereWolfFleeMod")->mValue.getInteger(); rating = iWereWolfFleeMod; } } diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 67468453a..d36c5930f 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -495,7 +495,7 @@ namespace MWMechanics MWWorld::Ptr player = getPlayer(); static float fVoiceIdleOdds = MWBase::Environment::get().getWorld()->getStore() - .get().find("fVoiceIdleOdds")->getFloat(); + .get().find("fVoiceIdleOdds")->mValue.getFloat(); float roll = Misc::Rng::rollProbability() * 10000.0f; @@ -522,7 +522,7 @@ namespace MWMechanics int hello = actor.getClass().getCreatureStats(actor).getAiSetting(CreatureStats::AI_Hello).getModified(); float helloDistance = static_cast(hello); static int iGreetDistanceMultiplier = MWBase::Environment::get().getWorld()->getStore() - .get().find("iGreetDistanceMultiplier")->getInt(); + .get().find("iGreetDistanceMultiplier")->mValue.getInteger(); helloDistance *= iGreetDistanceMultiplier; @@ -700,7 +700,7 @@ namespace MWMechanics for(unsigned int counter = 0; counter < mIdle.size(); counter++) { static float fIdleChanceMultiplier = MWBase::Environment::get().getWorld()->getStore() - .get().find("fIdleChanceMultiplier")->getFloat(); + .get().find("fIdleChanceMultiplier")->mValue.getFloat(); unsigned short idleChance = static_cast(fIdleChanceMultiplier * mIdle[counter]); unsigned short randSelect = (int)(Misc::Rng::rollProbability() * int(100 / fIdleChanceMultiplier)); diff --git a/apps/openmw/mwmechanics/alchemy.cpp b/apps/openmw/mwmechanics/alchemy.cpp index 48705dc72..b8f820307 100644 --- a/apps/openmw/mwmechanics/alchemy.cpp +++ b/apps/openmw/mwmechanics/alchemy.cpp @@ -140,11 +140,11 @@ void MWMechanics::Alchemy::updateEffects() float x = getAlchemyFactor(); x *= mTools[ESM::Apparatus::MortarPestle].get()->mBase->mData.mQuality; - x *= MWBase::Environment::get().getWorld()->getStore().get().find ("fPotionStrengthMult")->getFloat(); + x *= MWBase::Environment::get().getWorld()->getStore().get().find ("fPotionStrengthMult")->mValue.getFloat(); // value mValue = static_cast ( - x * MWBase::Environment::get().getWorld()->getStore().get().find ("iAlchemyMod")->getFloat()); + x * MWBase::Environment::get().getWorld()->getStore().get().find ("iAlchemyMod")->mValue.getFloat()); // build quantified effect list for (std::set::const_iterator iter (effects.begin()); iter!=effects.end(); ++iter) @@ -160,13 +160,13 @@ void MWMechanics::Alchemy::updateEffects() } float fPotionT1MagMul = - MWBase::Environment::get().getWorld()->getStore().get().find ("fPotionT1MagMult")->getFloat(); + MWBase::Environment::get().getWorld()->getStore().get().find ("fPotionT1MagMult")->mValue.getFloat(); if (fPotionT1MagMul<=0) throw std::runtime_error ("invalid gmst: fPotionT1MagMul"); float fPotionT1DurMult = - MWBase::Environment::get().getWorld()->getStore().get().find ("fPotionT1DurMult")->getFloat(); + MWBase::Environment::get().getWorld()->getStore().get().find ("fPotionT1DurMult")->mValue.getFloat(); if (fPotionT1DurMult<=0) throw std::runtime_error ("invalid gmst: fPotionT1DurMult"); @@ -449,7 +449,7 @@ bool MWMechanics::Alchemy::knownEffect(unsigned int potionEffectIndex, const MWW MWMechanics::NpcStats& npcStats = npc.getClass().getNpcStats(npc); int alchemySkill = npcStats.getSkill (ESM::Skill::Alchemy).getBase(); static const float fWortChanceValue = - MWBase::Environment::get().getWorld()->getStore().get().find("fWortChanceValue")->getFloat(); + MWBase::Environment::get().getWorld()->getStore().get().find("fWortChanceValue")->mValue.getFloat(); return (potionEffectIndex <= 1 && alchemySkill >= fWortChanceValue) || (potionEffectIndex <= 3 && alchemySkill >= fWortChanceValue*2) || (potionEffectIndex <= 5 && alchemySkill >= fWortChanceValue*3) @@ -503,5 +503,5 @@ std::string MWMechanics::Alchemy::suggestPotionName() int effectId = effects.begin()->mId; return MWBase::Environment::get().getWorld()->getStore().get().find( - ESM::MagicEffect::effectIdToString(effectId))->getString(); + ESM::MagicEffect::effectIdToString(effectId))->mValue.getString(); } diff --git a/apps/openmw/mwmechanics/autocalcspell.cpp b/apps/openmw/mwmechanics/autocalcspell.cpp index f655a68b4..a52fcc059 100644 --- a/apps/openmw/mwmechanics/autocalcspell.cpp +++ b/apps/openmw/mwmechanics/autocalcspell.cpp @@ -25,7 +25,7 @@ namespace MWMechanics std::vector autoCalcNpcSpells(const int *actorSkills, const int *actorAttributes, const ESM::Race* race) { const MWWorld::Store& gmst = MWBase::Environment::get().getWorld()->getStore().get(); - static const float fNPCbaseMagickaMult = gmst.find("fNPCbaseMagickaMult")->getFloat(); + static const float fNPCbaseMagickaMult = gmst.find("fNPCbaseMagickaMult")->mValue.getFloat(); float baseMagicka = fNPCbaseMagickaMult * actorAttributes[ESM::Attribute::Intelligence]; static const std::string schools[] = { @@ -38,7 +38,7 @@ namespace MWMechanics for (int i=0; i<6; ++i) { const std::string& gmstName = "iAutoSpell" + schools[i] + "Max"; - iAutoSpellSchoolMax[i] = gmst.find(gmstName)->getInt(); + iAutoSpellSchoolMax[i] = gmst.find(gmstName)->mValue.getInteger(); } init = true; } @@ -70,7 +70,7 @@ namespace MWMechanics continue; if (!(spell->mData.mFlags & ESM::Spell::F_Autocalc)) continue; - static const int iAutoSpellTimesCanCast = gmst.find("iAutoSpellTimesCanCast")->getInt(); + static const int iAutoSpellTimesCanCast = gmst.find("iAutoSpellTimesCanCast")->mValue.getInteger(); if (baseMagicka < iAutoSpellTimesCanCast * spell->mData.mCost) continue; @@ -89,7 +89,7 @@ namespace MWMechanics if (cap.mReachedLimit && spell->mData.mCost <= cap.mMinCost) continue; - static const float fAutoSpellChance = gmst.find("fAutoSpellChance")->getFloat(); + static const float fAutoSpellChance = gmst.find("fAutoSpellChance")->mValue.getFloat(); if (calcAutoCastChance(spell, actorSkills, actorAttributes, school) < fAutoSpellChance) continue; @@ -146,7 +146,7 @@ namespace MWMechanics { const MWWorld::ESMStore& esmStore = MWBase::Environment::get().getWorld()->getStore(); - static const float fPCbaseMagickaMult = esmStore.get().find("fPCbaseMagickaMult")->getFloat(); + static const float fPCbaseMagickaMult = esmStore.get().find("fPCbaseMagickaMult")->mValue.getFloat(); float baseMagicka = fPCbaseMagickaMult * actorAttributes[ESM::Attribute::Intelligence]; bool reachedLimit = false; @@ -173,7 +173,7 @@ namespace MWMechanics if (baseMagicka < spell->mData.mCost) continue; - static const float fAutoPCSpellChance = esmStore.get().find("fAutoPCSpellChance")->getFloat(); + static const float fAutoPCSpellChance = esmStore.get().find("fAutoPCSpellChance")->mValue.getFloat(); if (calcAutoCastChance(spell, actorSkills, actorAttributes, -1) < fAutoPCSpellChance) continue; @@ -206,7 +206,7 @@ namespace MWMechanics weakestSpell = spell; minCost = weakestSpell->mData.mCost; } - static const unsigned int iAutoPCSpellMax = esmStore.get().find("iAutoPCSpellMax")->getInt(); + static const unsigned int iAutoPCSpellMax = esmStore.get().find("iAutoPCSpellMax")->mValue.getInteger(); if (selectedSpells.size() == iAutoPCSpellMax) reachedLimit = true; } @@ -221,7 +221,7 @@ namespace MWMechanics for (std::vector::const_iterator effectIt = effects.begin(); effectIt != effects.end(); ++effectIt) { const ESM::MagicEffect* magicEffect = MWBase::Environment::get().getWorld()->getStore().get().find(effectIt->mEffectID); - static const int iAutoSpellAttSkillMin = MWBase::Environment::get().getWorld()->getStore().get().find("iAutoSpellAttSkillMin")->getInt(); + static const int iAutoSpellAttSkillMin = MWBase::Environment::get().getWorld()->getStore().get().find("iAutoSpellAttSkillMin")->mValue.getInteger(); if ((magicEffect->mData.mFlags & ESM::MagicEffect::TargetSkill)) { @@ -278,7 +278,7 @@ namespace MWMechanics duration = effect.mDuration; static const float fEffectCostMult = MWBase::Environment::get().getWorld()->getStore() - .get().find("fEffectCostMult")->getFloat(); + .get().find("fEffectCostMult")->mValue.getFloat(); float x = 0.5 * (std::max(1, minMagn) + std::max(1, maxMagn)); x *= 0.1 * magicEffect->mData.mBaseCost; diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index aca3dde7f..9d3d6a80e 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -123,16 +123,16 @@ float getFallDamage(const MWWorld::Ptr& ptr, float fallHeight) MWBase::World *world = MWBase::Environment::get().getWorld(); const MWWorld::Store &store = world->getStore().get(); - const float fallDistanceMin = store.find("fFallDamageDistanceMin")->getFloat(); + const float fallDistanceMin = store.find("fFallDamageDistanceMin")->mValue.getFloat(); if (fallHeight >= fallDistanceMin) { const float acrobaticsSkill = static_cast(ptr.getClass().getSkill(ptr, ESM::Skill::Acrobatics)); const float jumpSpellBonus = ptr.getClass().getCreatureStats(ptr).getMagicEffects().get(ESM::MagicEffect::Jump).getMagnitude(); - const float fallAcroBase = store.find("fFallAcroBase")->getFloat(); - const float fallAcroMult = store.find("fFallAcroMult")->getFloat(); - const float fallDistanceBase = store.find("fFallDistanceBase")->getFloat(); - const float fallDistanceMult = store.find("fFallDistanceMult")->getFloat(); + const float fallAcroBase = store.find("fFallAcroBase")->mValue.getFloat(); + const float fallAcroMult = store.find("fFallAcroMult")->mValue.getFloat(); + const float fallDistanceBase = store.find("fFallDistanceBase")->mValue.getFloat(); + const float fallDistanceMult = store.find("fFallDistanceMult")->mValue.getFloat(); float x = fallHeight - fallDistanceMin; x -= (1.5f * acrobaticsSkill) + jumpSpellBonus; @@ -1907,14 +1907,14 @@ void CharacterController::update(float duration) // reduce fatigue const MWWorld::Store &gmst = world->getStore().get(); float fatigueLoss = 0; - static const float fFatigueRunBase = gmst.find("fFatigueRunBase")->getFloat(); - static const float fFatigueRunMult = gmst.find("fFatigueRunMult")->getFloat(); - static const float fFatigueSwimWalkBase = gmst.find("fFatigueSwimWalkBase")->getFloat(); - static const float fFatigueSwimRunBase = gmst.find("fFatigueSwimRunBase")->getFloat(); - static const float fFatigueSwimWalkMult = gmst.find("fFatigueSwimWalkMult")->getFloat(); - static const float fFatigueSwimRunMult = gmst.find("fFatigueSwimRunMult")->getFloat(); - static const float fFatigueSneakBase = gmst.find("fFatigueSneakBase")->getFloat(); - static const float fFatigueSneakMult = gmst.find("fFatigueSneakMult")->getFloat(); + static const float fFatigueRunBase = gmst.find("fFatigueRunBase")->mValue.getFloat(); + static const float fFatigueRunMult = gmst.find("fFatigueRunMult")->mValue.getFloat(); + static const float fFatigueSwimWalkBase = gmst.find("fFatigueSwimWalkBase")->mValue.getFloat(); + static const float fFatigueSwimRunBase = gmst.find("fFatigueSwimRunBase")->mValue.getFloat(); + static const float fFatigueSwimWalkMult = gmst.find("fFatigueSwimWalkMult")->mValue.getFloat(); + static const float fFatigueSwimRunMult = gmst.find("fFatigueSwimRunMult")->mValue.getFloat(); + static const float fFatigueSneakBase = gmst.find("fFatigueSneakBase")->mValue.getFloat(); + static const float fFatigueSneakMult = gmst.find("fFatigueSneakMult")->mValue.getFloat(); if (cls.getEncumbrance(mPtr) <= cls.getCapacity(mPtr)) { @@ -1954,8 +1954,8 @@ void CharacterController::update(float duration) forcestateupdate = (mJumpState != JumpState_InAir); jumpstate = JumpState_InAir; - static const float fJumpMoveBase = gmst.find("fJumpMoveBase")->getFloat(); - static const float fJumpMoveMult = gmst.find("fJumpMoveMult")->getFloat(); + static const float fJumpMoveBase = gmst.find("fJumpMoveBase")->mValue.getFloat(); + static const float fJumpMoveMult = gmst.find("fJumpMoveMult")->mValue.getFloat(); float factor = fJumpMoveBase + fJumpMoveMult * mPtr.getClass().getSkill(mPtr, ESM::Skill::Acrobatics)/100.f; factor = std::min(1.f, factor); vec.x() *= factor; @@ -1982,8 +1982,8 @@ void CharacterController::update(float duration) cls.skillUsageSucceeded(mPtr, ESM::Skill::Acrobatics, 0); // decrease fatigue - const float fatigueJumpBase = gmst.find("fFatigueJumpBase")->getFloat(); - const float fatigueJumpMult = gmst.find("fFatigueJumpMult")->getFloat(); + const float fatigueJumpBase = gmst.find("fFatigueJumpBase")->mValue.getFloat(); + const float fatigueJumpMult = gmst.find("fFatigueJumpMult")->mValue.getFloat(); float normalizedEncumbrance = mPtr.getClass().getNormalizedEncumbrance(mPtr); if (normalizedEncumbrance > 1) normalizedEncumbrance = 1; diff --git a/apps/openmw/mwmechanics/combat.cpp b/apps/openmw/mwmechanics/combat.cpp index 06ed99f5a..be55b681f 100644 --- a/apps/openmw/mwmechanics/combat.cpp +++ b/apps/openmw/mwmechanics/combat.cpp @@ -82,9 +82,9 @@ namespace MWMechanics osg::Vec3f(0,0,1))); const MWWorld::Store& gmst = MWBase::Environment::get().getWorld()->getStore().get(); - if (angleDegrees < gmst.find("fCombatBlockLeftAngle")->getFloat()) + if (angleDegrees < gmst.find("fCombatBlockLeftAngle")->mValue.getFloat()) return false; - if (angleDegrees > gmst.find("fCombatBlockRightAngle")->getFloat()) + if (angleDegrees > gmst.find("fCombatBlockRightAngle")->mValue.getFloat()) return false; MWMechanics::CreatureStats& attackerStats = attacker.getClass().getCreatureStats(attacker); @@ -92,11 +92,11 @@ namespace MWMechanics float blockTerm = blocker.getClass().getSkill(blocker, ESM::Skill::Block) + 0.2f * blockerStats.getAttribute(ESM::Attribute::Agility).getModified() + 0.1f * blockerStats.getAttribute(ESM::Attribute::Luck).getModified(); float enemySwing = attackStrength; - float swingTerm = enemySwing * gmst.find("fSwingBlockMult")->getFloat() + gmst.find("fSwingBlockBase")->getFloat(); + float swingTerm = enemySwing * gmst.find("fSwingBlockMult")->mValue.getFloat() + gmst.find("fSwingBlockBase")->mValue.getFloat(); float blockerTerm = blockTerm * swingTerm; if (blocker.getClass().getMovementSettings(blocker).mPosition[1] <= 0) - blockerTerm *= gmst.find("fBlockStillBonus")->getFloat(); + blockerTerm *= gmst.find("fBlockStillBonus")->mValue.getFloat(); blockerTerm *= blockerStats.getFatigueTerm(); int attackerSkill = 0; @@ -109,8 +109,8 @@ namespace MWMechanics attackerTerm *= attackerStats.getFatigueTerm(); int x = int(blockerTerm - attackerTerm); - int iBlockMaxChance = gmst.find("iBlockMaxChance")->getInt(); - int iBlockMinChance = gmst.find("iBlockMinChance")->getInt(); + int iBlockMaxChance = gmst.find("iBlockMaxChance")->mValue.getInteger(); + int iBlockMinChance = gmst.find("iBlockMinChance")->mValue.getInteger(); x = std::min(iBlockMaxChance, std::max(iBlockMinChance, x)); if (Misc::Rng::roll0to99() < x) @@ -126,9 +126,9 @@ namespace MWMechanics inv.unequipItem(*shield, blocker); } // Reduce blocker fatigue - const float fFatigueBlockBase = gmst.find("fFatigueBlockBase")->getFloat(); - const float fFatigueBlockMult = gmst.find("fFatigueBlockMult")->getFloat(); - const float fWeaponFatigueBlockMult = gmst.find("fWeaponFatigueBlockMult")->getFloat(); + const float fFatigueBlockBase = gmst.find("fFatigueBlockBase")->mValue.getFloat(); + const float fFatigueBlockMult = gmst.find("fFatigueBlockMult")->mValue.getFloat(); + const float fWeaponFatigueBlockMult = gmst.find("fWeaponFatigueBlockMult")->mValue.getFloat(); MWMechanics::DynamicStat fatigue = blockerStats.getFatigue(); float normalizedEncumbrance = blocker.getClass().getNormalizedEncumbrance(blocker); normalizedEncumbrance = std::min(1.f, normalizedEncumbrance); @@ -166,7 +166,7 @@ namespace MWMechanics if ((weapon.get()->mBase->mData.mFlags & ESM::Weapon::Silver) && actor.getClass().isNpc() && actor.getClass().getNpcStats(actor).isWerewolf()) - damage *= MWBase::Environment::get().getWorld()->getStore().get().find("fWereWolfSilverWeaponDamageMult")->getFloat(); + damage *= MWBase::Environment::get().getWorld()->getStore().get().find("fWereWolfSilverWeaponDamageMult")->mValue.getFloat(); if (damage == 0 && attacker == getPlayer()) MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicTargetResistsWeapons}"); @@ -219,14 +219,14 @@ namespace MWMechanics if (unaware) { - damage *= gmst.find("fCombatCriticalStrikeMult")->getFloat(); + damage *= gmst.find("fCombatCriticalStrikeMult")->mValue.getFloat(); MWBase::Environment::get().getWindowManager()->messageBox("#{sTargetCriticalStrike}"); MWBase::Environment::get().getSoundManager()->playSound3D(victim, "critical damage", 1.0f, 1.0f); } } if (victim.getClass().getCreatureStats(victim).getKnockedDown()) - damage *= gmst.find("fCombatKODamageMult")->getFloat(); + damage *= gmst.find("fCombatKODamageMult")->mValue.getFloat(); } reduceWeaponCondition(damage, validVictim, weapon, attacker); @@ -241,7 +241,7 @@ namespace MWMechanics // Non-enchanted arrows shot at enemies have a chance to turn up in their inventory if (victim != getPlayer() && !appliedEnchantment) { - float fProjectileThrownStoreChance = gmst.find("fProjectileThrownStoreChance")->getFloat(); + float fProjectileThrownStoreChance = gmst.find("fProjectileThrownStoreChance")->mValue.getFloat(); if (Misc::Rng::rollProbability() < fProjectileThrownStoreChance / 100.f) victim.getClass().getContainerStore(victim).add(projectile, 1, victim); } @@ -273,10 +273,10 @@ namespace MWMechanics defenseTerm = victimStats.getEvasion(); } defenseTerm += std::min(100.f, - gmst.find("fCombatInvisoMult")->getFloat() * + gmst.find("fCombatInvisoMult")->mValue.getFloat() * victimStats.getMagicEffects().get(ESM::MagicEffect::Chameleon).getMagnitude()); defenseTerm += std::min(100.f, - gmst.find("fCombatInvisoMult")->getFloat() * + gmst.find("fCombatInvisoMult")->mValue.getFloat() * victimStats.getMagicEffects().get(ESM::MagicEffect::Invisibility).getMagnitude()); } float attackTerm = skillValue + @@ -322,7 +322,7 @@ namespace MWMechanics x = std::min(100.f, x + elementResistance); - static const float fElementalShieldMult = MWBase::Environment::get().getWorld()->getStore().get().find("fElementalShieldMult")->getFloat(); + static const float fElementalShieldMult = MWBase::Environment::get().getWorld()->getStore().get().find("fElementalShieldMult")->mValue.getFloat(); x = fElementalShieldMult * magnitude * (1.f - 0.01f * x); // Note swapped victim and attacker, since the attacker takes the damage here. @@ -352,7 +352,7 @@ namespace MWMechanics // weapon condition does not degrade when godmode is on if (!godmode) { - const float fWeaponDamageMult = MWBase::Environment::get().getWorld()->getStore().get().find("fWeaponDamageMult")->getFloat(); + const float fWeaponDamageMult = MWBase::Environment::get().getWorld()->getStore().get().find("fWeaponDamageMult")->mValue.getFloat(); float x = std::max(1.f, fWeaponDamageMult * damage); weaphealth -= std::min(int(x), weaphealth); @@ -379,9 +379,9 @@ namespace MWMechanics } static const float fDamageStrengthBase = MWBase::Environment::get().getWorld()->getStore().get() - .find("fDamageStrengthBase")->getFloat(); + .find("fDamageStrengthBase")->mValue.getFloat(); static const float fDamageStrengthMult = MWBase::Environment::get().getWorld()->getStore().get() - .find("fDamageStrengthMult")->getFloat(); + .find("fDamageStrengthMult")->mValue.getFloat(); damage *= fDamageStrengthBase + (attacker.getClass().getCreatureStats(attacker).getAttribute(ESM::Attribute::Strength).getModified() * fDamageStrengthMult * 0.1f); } @@ -389,8 +389,8 @@ namespace MWMechanics void getHandToHandDamage(const MWWorld::Ptr &attacker, const MWWorld::Ptr &victim, float &damage, bool &healthdmg, float attackStrength) { const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); - float minstrike = store.get().find("fMinHandToHandMult")->getFloat(); - float maxstrike = store.get().find("fMaxHandToHandMult")->getFloat(); + float minstrike = store.get().find("fMinHandToHandMult")->mValue.getFloat(); + float maxstrike = store.get().find("fMaxHandToHandMult")->mValue.getFloat(); damage = static_cast(attacker.getClass().getSkill(attacker, ESM::Skill::HandToHand)); damage *= minstrike + ((maxstrike-minstrike)*attackStrength); @@ -415,7 +415,7 @@ namespace MWMechanics damage *= MWBase::Environment::get().getWorld()->getGlobalFloat("werewolfclawmult"); } if(healthdmg) - damage *= store.get().find("fHandtoHandHealthPer")->getFloat(); + damage *= store.get().find("fHandtoHandHealthPer")->mValue.getFloat(); MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); if(isWerewolf) @@ -432,9 +432,9 @@ namespace MWMechanics { // somewhat of a guess, but using the weapon weight makes sense const MWWorld::Store& store = MWBase::Environment::get().getWorld()->getStore().get(); - const float fFatigueAttackBase = store.find("fFatigueAttackBase")->getFloat(); - const float fFatigueAttackMult = store.find("fFatigueAttackMult")->getFloat(); - const float fWeaponFatigueMult = store.find("fWeaponFatigueMult")->getFloat(); + const float fFatigueAttackBase = store.find("fFatigueAttackBase")->mValue.getFloat(); + const float fFatigueAttackMult = store.find("fFatigueAttackMult")->mValue.getFloat(); + const float fWeaponFatigueMult = store.find("fWeaponFatigueMult")->mValue.getFloat(); CreatureStats& stats = attacker.getClass().getCreatureStats(attacker); MWMechanics::DynamicStat fatigue = stats.getFatigue(); const float normalizedEncumbrance = attacker.getClass().getNormalizedEncumbrance(attacker); @@ -459,9 +459,9 @@ namespace MWMechanics float d = (pos1 - pos2).length(); static const int iFightDistanceBase = MWBase::Environment::get().getWorld()->getStore().get().find( - "iFightDistanceBase")->getInt(); + "iFightDistanceBase")->mValue.getInteger(); static const float fFightDistanceMultiplier = MWBase::Environment::get().getWorld()->getStore().get().find( - "fFightDistanceMultiplier")->getFloat(); + "fFightDistanceMultiplier")->mValue.getFloat(); return (iFightDistanceBase - fFightDistanceMultiplier * d); } diff --git a/apps/openmw/mwmechanics/creaturestats.cpp b/apps/openmw/mwmechanics/creaturestats.cpp index d1128860c..2994eac28 100644 --- a/apps/openmw/mwmechanics/creaturestats.cpp +++ b/apps/openmw/mwmechanics/creaturestats.cpp @@ -48,8 +48,8 @@ namespace MWMechanics const MWWorld::Store &gmst = MWBase::Environment::get().getWorld()->getStore().get(); - static const float fFatigueBase = gmst.find("fFatigueBase")->getFloat(); - static const float fFatigueMult = gmst.find("fFatigueMult")->getFloat(); + static const float fFatigueBase = gmst.find("fFatigueBase")->mValue.getFloat(); + static const float fFatigueMult = gmst.find("fFatigueMult")->mValue.getFloat(); return fFatigueBase - fFatigueMult * (1-normalised); } diff --git a/apps/openmw/mwmechanics/difficultyscaling.cpp b/apps/openmw/mwmechanics/difficultyscaling.cpp index 53cf47dea..237698974 100644 --- a/apps/openmw/mwmechanics/difficultyscaling.cpp +++ b/apps/openmw/mwmechanics/difficultyscaling.cpp @@ -17,7 +17,7 @@ float scaleDamage(float damage, const MWWorld::Ptr& attacker, const MWWorld::Ptr difficultySetting = std::min(difficultySetting, 500); difficultySetting = std::max(difficultySetting, -500); - static const float fDifficultyMult = MWBase::Environment::get().getWorld()->getStore().get().find("fDifficultyMult")->getFloat(); + static const float fDifficultyMult = MWBase::Environment::get().getWorld()->getStore().get().find("fDifficultyMult")->mValue.getFloat(); float difficultyTerm = 0.01f * difficultySetting; diff --git a/apps/openmw/mwmechanics/disease.hpp b/apps/openmw/mwmechanics/disease.hpp index 5746af2a2..fec3bdd37 100644 --- a/apps/openmw/mwmechanics/disease.hpp +++ b/apps/openmw/mwmechanics/disease.hpp @@ -28,7 +28,7 @@ namespace MWMechanics float fDiseaseXferChance = MWBase::Environment::get().getWorld()->getStore().get().find( - "fDiseaseXferChance")->getFloat(); + "fDiseaseXferChance")->mValue.getFloat(); MagicEffects& actorEffects = actor.getClass().getCreatureStats(actor).getMagicEffects(); @@ -59,7 +59,7 @@ namespace MWMechanics actor.getClass().getCreatureStats(actor).getSpells().add(it->first); std::string msg = "sMagicContractDisease"; - msg = MWBase::Environment::get().getWorld()->getStore().get().find(msg)->getString(); + msg = MWBase::Environment::get().getWorld()->getStore().get().find(msg)->mValue.getString(); if (msg.find("%s") != std::string::npos) msg.replace(msg.find("%s"), 2, spell->mName); MWBase::Environment::get().getWindowManager()->messageBox(msg); diff --git a/apps/openmw/mwmechanics/enchanting.cpp b/apps/openmw/mwmechanics/enchanting.cpp index 08f30aba1..c0bffc4cb 100644 --- a/apps/openmw/mwmechanics/enchanting.cpp +++ b/apps/openmw/mwmechanics/enchanting.cpp @@ -107,7 +107,7 @@ namespace MWMechanics } const bool powerfulSoul = getGemCharge() >= \ - MWBase::Environment::get().getWorld()->getStore().get().find ("iSoulAmountForConstantEffect")->getInt(); + MWBase::Environment::get().getWorld()->getStore().get().find ("iSoulAmountForConstantEffect")->mValue.getInteger(); if ((mObjectType == typeid(ESM::Armor).name()) || (mObjectType == typeid(ESM::Clothing).name())) { // Armor or Clothing switch(mCastStyle) @@ -184,7 +184,7 @@ namespace MWMechanics float magnitudeCost = (magMin + magMax) * baseCost * 0.05f; if (mCastStyle == ESM::Enchantment::ConstantEffect) { - magnitudeCost *= store.get().find("fEnchantmentConstantDurationMult")->getFloat(); + magnitudeCost *= store.get().find("fEnchantmentConstantDurationMult")->mValue.getFloat(); } else { @@ -193,7 +193,7 @@ namespace MWMechanics float areaCost = area * 0.05f * baseCost; - const float fEffectCostMult = store.get().find("fEffectCostMult")->getFloat(); + const float fEffectCostMult = store.get().find("fEffectCostMult")->mValue.getFloat(); cost += (magnitudeCost + areaCost) * fEffectCostMult; @@ -230,7 +230,7 @@ namespace MWMechanics if(mEnchanter.isEmpty()) return 0; - float priceMultipler = MWBase::Environment::get().getWorld()->getStore().get().find ("fEnchantmentValueMult")->getFloat(); + float priceMultipler = MWBase::Environment::get().getWorld()->getStore().get().find ("fEnchantmentValueMult")->mValue.getFloat(); int price = MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mEnchanter, static_cast(getEnchantPoints() * priceMultipler), true); return price; } @@ -256,7 +256,7 @@ namespace MWMechanics const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); - return static_cast(mOldItemPtr.getClass().getEnchantmentPoints(mOldItemPtr) * store.get().find("fEnchantmentMult")->getFloat()); + return static_cast(mOldItemPtr.getClass().getEnchantmentPoints(mOldItemPtr) * store.get().find("fEnchantmentMult")->mValue.getFloat()); } bool Enchanting::soulEmpty() const { @@ -288,8 +288,8 @@ namespace MWMechanics const MWWorld::Store& gmst = MWBase::Environment::get().getWorld()->getStore().get(); - float chance2 = 7.5f / (gmst.find("fEnchantmentChanceMult")->getFloat() * ((mCastStyle == ESM::Enchantment::ConstantEffect) ? - gmst.find("fEnchantmentConstantChanceMult")->getFloat() : 1.0f )) + float chance2 = 7.5f / (gmst.find("fEnchantmentChanceMult")->mValue.getFloat() * ((mCastStyle == ESM::Enchantment::ConstantEffect) ? + gmst.find("fEnchantmentConstantChanceMult")->mValue.getFloat() : 1.0f )) * getEnchantPoints(); return (chance1-chance2); diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index e7343e23a..859b2e522 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -36,7 +36,7 @@ namespace float getFightDispositionBias(float disposition) { static const float fFightDispMult = MWBase::Environment::get().getWorld()->getStore().get().find( - "fFightDispMult")->getFloat(); + "fFightDispMult")->mValue.getFloat(); return ((50.f - disposition) * fFightDispMult); } @@ -45,11 +45,11 @@ namespace const MWWorld::Store &gmst = MWBase::Environment::get().getWorld()->getStore().get(); - float persTerm = stats.getAttribute(ESM::Attribute::Personality).getModified() / gmst.find("fPersonalityMod")->getFloat(); - float luckTerm = stats.getAttribute(ESM::Attribute::Luck).getModified() / gmst.find("fLuckMod")->getFloat(); - float repTerm = stats.getReputation() * gmst.find("fReputationMod")->getFloat(); + float persTerm = stats.getAttribute(ESM::Attribute::Personality).getModified() / gmst.find("fPersonalityMod")->mValue.getFloat(); + float luckTerm = stats.getAttribute(ESM::Attribute::Luck).getModified() / gmst.find("fLuckMod")->mValue.getFloat(); + float repTerm = stats.getReputation() * gmst.find("fReputationMod")->mValue.getFloat(); float fatigueTerm = stats.getFatigueTerm(); - float levelTerm = stats.getLevel() * gmst.find("fLevelMod")->getFloat(); + float levelTerm = stats.getLevel() * gmst.find("fLevelMod")->mValue.getFloat(); rating1 = (repTerm + luckTerm + persTerm + stats.getSkill(ESM::Skill::Speechcraft).getModified()) * fatigueTerm; @@ -342,7 +342,7 @@ namespace MWMechanics if(timeToDrown != mWatchedTimeToStartDrowning) { static const float fHoldBreathTime = MWBase::Environment::get().getWorld()->getStore().get() - .find("fHoldBreathTime")->getFloat(); + .find("fHoldBreathTime")->mValue.getFloat(); mWatchedTimeToStartDrowning = timeToDrown; @@ -543,12 +543,12 @@ namespace MWMechanics const MWMechanics::NpcStats &playerStats = playerPtr.getClass().getNpcStats(playerPtr); const MWWorld::Store& gmst = MWBase::Environment::get().getWorld()->getStore().get(); - static const float fDispRaceMod = gmst.find("fDispRaceMod")->getFloat(); + static const float fDispRaceMod = gmst.find("fDispRaceMod")->mValue.getFloat(); if (Misc::StringUtils::ciEqual(npc->mBase->mRace, player->mBase->mRace)) x += fDispRaceMod; - static const float fDispPersonalityMult = gmst.find("fDispPersonalityMult")->getFloat(); - static const float fDispPersonalityBase = gmst.find("fDispPersonalityBase")->getFloat(); + static const float fDispPersonalityMult = gmst.find("fDispPersonalityMult")->mValue.getFloat(); + static const float fDispPersonalityBase = gmst.find("fDispPersonalityBase")->mValue.getFloat(); x += fDispPersonalityMult * (playerStats.getAttribute(ESM::Attribute::Personality).getModified() - fDispPersonalityBase); float reaction = 0; @@ -592,20 +592,20 @@ namespace MWMechanics rank = 0; } - static const float fDispFactionRankMult = gmst.find("fDispFactionRankMult")->getFloat(); - static const float fDispFactionRankBase = gmst.find("fDispFactionRankBase")->getFloat(); - static const float fDispFactionMod = gmst.find("fDispFactionMod")->getFloat(); + static const float fDispFactionRankMult = gmst.find("fDispFactionRankMult")->mValue.getFloat(); + static const float fDispFactionRankBase = gmst.find("fDispFactionRankBase")->mValue.getFloat(); + static const float fDispFactionMod = gmst.find("fDispFactionMod")->mValue.getFloat(); x += (fDispFactionRankMult * rank + fDispFactionRankBase) * fDispFactionMod * reaction; - static const float fDispCrimeMod = gmst.find("fDispCrimeMod")->getFloat(); - static const float fDispDiseaseMod = gmst.find("fDispDiseaseMod")->getFloat(); + static const float fDispCrimeMod = gmst.find("fDispCrimeMod")->mValue.getFloat(); + static const float fDispDiseaseMod = gmst.find("fDispDiseaseMod")->mValue.getFloat(); x -= fDispCrimeMod * playerStats.getBounty(); if (playerStats.hasCommonDisease() || playerStats.hasBlightDisease()) x += fDispDiseaseMod; - static const float fDispWeaponDrawn = gmst.find("fDispWeaponDrawn")->getFloat(); + static const float fDispWeaponDrawn = gmst.find("fDispWeaponDrawn")->mValue.getFloat(); if (playerStats.getDrawState() == MWMechanics::DrawState_Weapon) x += fDispWeaponDrawn; @@ -673,16 +673,16 @@ namespace MWMechanics float target2 = d * (playerRating2 - npcRating2 + 50); float bribeMod; - if (type == PT_Bribe10) bribeMod = gmst.find("fBribe10Mod")->getFloat(); - else if (type == PT_Bribe100) bribeMod = gmst.find("fBribe100Mod")->getFloat(); - else bribeMod = gmst.find("fBribe1000Mod")->getFloat(); + if (type == PT_Bribe10) bribeMod = gmst.find("fBribe10Mod")->mValue.getFloat(); + else if (type == PT_Bribe100) bribeMod = gmst.find("fBribe100Mod")->mValue.getFloat(); + else bribeMod = gmst.find("fBribe1000Mod")->mValue.getFloat(); float target3 = d * (playerRating3 - npcRating3 + 50) + bribeMod; - float iPerMinChance = floor(gmst.find("iPerMinChance")->getFloat()); - float iPerMinChange = floor(gmst.find("iPerMinChange")->getFloat()); - float fPerDieRollMult = gmst.find("fPerDieRollMult")->getFloat(); - float fPerTempMult = gmst.find("fPerTempMult")->getFloat(); + float iPerMinChance = floor(gmst.find("iPerMinChance")->mValue.getFloat()); + float iPerMinChange = floor(gmst.find("iPerMinChange")->mValue.getFloat()); + float fPerDieRollMult = gmst.find("fPerDieRollMult")->mValue.getFloat(); + float fPerTempMult = gmst.find("fPerTempMult")->mValue.getFloat(); float x = 0; float y = 0; @@ -867,7 +867,7 @@ namespace MWMechanics continue; // All sMagicBound* GMST's should be of type string - std::string currentGMSTValue = currentSetting.getString(); + std::string currentGMSTValue = currentSetting.mValue.getString(); Misc::StringUtils::lowerCaseInPlace(currentGMSTValue); boundItemIDCache.insert(currentGMSTValue); @@ -1163,7 +1163,7 @@ namespace MWMechanics osg::Vec3f from (player.getRefData().getPosition().asVec3()); const MWWorld::ESMStore& esmStore = MWBase::Environment::get().getWorld()->getStore(); - float radius = esmStore.get().find("fAlarmRadius")->getFloat(); + float radius = esmStore.get().find("fAlarmRadius")->mValue.getFloat(); mActors.getObjectsInRange(from, radius, neighbors); @@ -1261,29 +1261,29 @@ namespace MWMechanics float disp = 0.f, dispVictim = 0.f; if (type == OT_Trespassing || type == OT_SleepingInOwnedBed) { - arg = store.find("iCrimeTresspass")->getInt(); - disp = dispVictim = store.find("iDispTresspass")->getFloat(); + arg = store.find("iCrimeTresspass")->mValue.getInteger(); + disp = dispVictim = store.find("iDispTresspass")->mValue.getFloat(); } else if (type == OT_Pickpocket) { - arg = store.find("iCrimePickPocket")->getInt(); - disp = dispVictim = store.find("fDispPickPocketMod")->getFloat(); + arg = store.find("iCrimePickPocket")->mValue.getInteger(); + disp = dispVictim = store.find("fDispPickPocketMod")->mValue.getFloat(); } else if (type == OT_Assault) { - arg = store.find("iCrimeAttack")->getInt(); - disp = store.find("iDispAttackMod")->getFloat(); - dispVictim = store.find("fDispAttacking")->getFloat(); + arg = store.find("iCrimeAttack")->mValue.getInteger(); + disp = store.find("iDispAttackMod")->mValue.getFloat(); + dispVictim = store.find("fDispAttacking")->mValue.getFloat(); } else if (type == OT_Murder) { - arg = store.find("iCrimeKilling")->getInt(); - disp = dispVictim = store.find("iDispKilling")->getFloat(); + arg = store.find("iCrimeKilling")->mValue.getInteger(); + disp = dispVictim = store.find("iDispKilling")->mValue.getFloat(); } else if (type == OT_Theft) { - disp = dispVictim = store.find("fDispStealing")->getFloat() * arg; - arg = static_cast(arg * store.find("fCrimeStealing")->getFloat()); + disp = dispVictim = store.find("fDispStealing")->mValue.getFloat() * arg; + arg = static_cast(arg * store.find("fCrimeStealing")->mValue.getFloat()); arg = std::max(1, arg); // Minimum bounty of 1, in case items with zero value are stolen } @@ -1293,7 +1293,7 @@ namespace MWMechanics const MWWorld::ESMStore& esmStore = MWBase::Environment::get().getWorld()->getStore(); osg::Vec3f from (player.getRefData().getPosition().asVec3()); - float radius = esmStore.get().find("fAlarmRadius")->getFloat(); + float radius = esmStore.get().find("fAlarmRadius")->mValue.getFloat(); mActors.getObjectsInRange(from, radius, neighbors); @@ -1307,21 +1307,21 @@ namespace MWMechanics // Controls whether witnesses will engage combat with the criminal. int fight = 0, fightVictim = 0; if (type == OT_Trespassing || type == OT_SleepingInOwnedBed) - fight = fightVictim = esmStore.get().find("iFightTrespass")->getInt(); + fight = fightVictim = esmStore.get().find("iFightTrespass")->mValue.getInteger(); else if (type == OT_Pickpocket) { - fight = esmStore.get().find("iFightPickpocket")->getInt(); - fightVictim = esmStore.get().find("iFightPickpocket")->getInt() * 4; // *4 according to research wiki + fight = esmStore.get().find("iFightPickpocket")->mValue.getInteger(); + fightVictim = esmStore.get().find("iFightPickpocket")->mValue.getInteger() * 4; // *4 according to research wiki } else if (type == OT_Assault) { - fight = esmStore.get().find("iFightAttacking")->getInt(); - fightVictim = esmStore.get().find("iFightAttack")->getInt(); + fight = esmStore.get().find("iFightAttacking")->mValue.getInteger(); + fightVictim = esmStore.get().find("iFightAttack")->mValue.getInteger(); } else if (type == OT_Murder) - fight = fightVictim = esmStore.get().find("iFightKilling")->getInt(); + fight = fightVictim = esmStore.get().find("iFightKilling")->mValue.getInteger(); else if (type == OT_Theft) - fight = fightVictim = esmStore.get().find("fFightStealing")->getInt(); + fight = fightVictim = esmStore.get().find("fFightStealing")->mValue.getInteger(); bool reported = false; @@ -1552,8 +1552,8 @@ namespace MWMechanics && !MWBase::Environment::get().getWorld()->isSwimming(ptr) && MWBase::Environment::get().getWorld()->isOnGround(ptr)) { - static float fSneakSkillMult = store.find("fSneakSkillMult")->getFloat(); - static float fSneakBootMult = store.find("fSneakBootMult")->getFloat(); + static float fSneakSkillMult = store.find("fSneakSkillMult")->mValue.getFloat(); + static float fSneakBootMult = store.find("fSneakBootMult")->mValue.getFloat(); float sneak = static_cast(ptr.getClass().getSkill(ptr, ESM::Skill::Sneak)); int agility = stats.getAttribute(ESM::Attribute::Agility).getModified(); int luck = stats.getAttribute(ESM::Attribute::Luck).getModified(); @@ -1568,8 +1568,8 @@ namespace MWMechanics sneakTerm = fSneakSkillMult * sneak + 0.2f * agility + 0.1f * luck + bootWeight * fSneakBootMult; } - static float fSneakDistBase = store.find("fSneakDistanceBase")->getFloat(); - static float fSneakDistMult = store.find("fSneakDistanceMultiplier")->getFloat(); + static float fSneakDistBase = store.find("fSneakDistanceBase")->mValue.getFloat(); + static float fSneakDistMult = store.find("fSneakDistanceMultiplier")->mValue.getFloat(); osg::Vec3f pos1 (ptr.getRefData().getPosition().asVec3()); osg::Vec3f pos2 (observer.getRefData().getPosition().asVec3()); @@ -1587,8 +1587,8 @@ namespace MWMechanics float obsTerm = obsSneak + 0.2f * obsAgility + 0.1f * obsLuck - obsBlind; // is ptr behind the observer? - static float fSneakNoViewMult = store.find("fSneakNoViewMult")->getFloat(); - static float fSneakViewMult = store.find("fSneakViewMult")->getFloat(); + static float fSneakNoViewMult = store.find("fSneakNoViewMult")->mValue.getFloat(); + static float fSneakViewMult = store.find("fSneakViewMult")->mValue.getFloat(); float y = 0; osg::Vec3f vec = pos1 - pos2; if (observer.getRefData().getBaseNode()) @@ -1748,7 +1748,7 @@ namespace MWMechanics MWBase::Environment::get().getWorld()->getGlobalInt("pcknownwerewolf"))) { const ESM::GameSetting * iWerewolfFightMod = MWBase::Environment::get().getWorld()->getStore().get().find("iWerewolfFightMod"); - fight += iWerewolfFightMod->getInt(); + fight += iWerewolfFightMod->mValue.getInteger(); } } @@ -1841,7 +1841,7 @@ namespace MWMechanics // Witnesses of the player's transformation will make them a globally known werewolf std::vector closeActors; const MWWorld::Store& gmst = MWBase::Environment::get().getWorld()->getStore().get(); - getActorsInRange(actor.getRefData().getPosition().asVec3(), gmst.find("fAlarmRadius")->getFloat(), closeActors); + getActorsInRange(actor.getRefData().getPosition().asVec3(), gmst.find("fAlarmRadius")->mValue.getFloat(), closeActors); bool detected = false, reported = false; for (std::vector::const_iterator it = closeActors.begin(); it != closeActors.end(); ++it) @@ -1866,7 +1866,7 @@ namespace MWMechanics if (reported) { npcStats.setBounty(npcStats.getBounty()+ - gmst.find("iWereWolfBounty")->getInt()); + gmst.find("iWereWolfBounty")->mValue.getInteger()); windowManager->messageBox("#{sCrimeMessage}"); } } @@ -1878,7 +1878,7 @@ namespace MWMechanics const MWWorld::Store& gmst = MWBase::Environment::get().getWorld()->getStore().get(); MWMechanics::NpcStats &stats = actor.getClass().getNpcStats(actor); - stats.getSkill(ESM::Skill::Acrobatics).setBase(gmst.find("fWerewolfAcrobatics")->getInt()); + stats.getSkill(ESM::Skill::Acrobatics).setBase(gmst.find("fWerewolfAcrobatics")->mValue.getInteger()); } void MechanicsManager::cleanupSummonedCreature(const MWWorld::Ptr &caster, int creatureActorId) diff --git a/apps/openmw/mwmechanics/npcstats.cpp b/apps/openmw/mwmechanics/npcstats.cpp index f15152759..cb9ef5477 100644 --- a/apps/openmw/mwmechanics/npcstats.cpp +++ b/apps/openmw/mwmechanics/npcstats.cpp @@ -149,12 +149,12 @@ float MWMechanics::NpcStats::getSkillProgressRequirement (int skillIndex, const const MWWorld::Store &gmst = MWBase::Environment::get().getWorld()->getStore().get(); - float typeFactor = gmst.find ("fMiscSkillBonus")->getFloat(); + float typeFactor = gmst.find ("fMiscSkillBonus")->mValue.getFloat(); for (int i=0; i<5; ++i) if (class_.mData.mSkills[i][0]==skillIndex) { - typeFactor = gmst.find ("fMinorSkillBonus")->getFloat(); + typeFactor = gmst.find ("fMinorSkillBonus")->mValue.getFloat(); break; } @@ -162,7 +162,7 @@ float MWMechanics::NpcStats::getSkillProgressRequirement (int skillIndex, const for (int i=0; i<5; ++i) if (class_.mData.mSkills[i][1]==skillIndex) { - typeFactor = gmst.find ("fMajorSkillBonus")->getFloat(); + typeFactor = gmst.find ("fMajorSkillBonus")->mValue.getFloat(); break; } @@ -178,7 +178,7 @@ float MWMechanics::NpcStats::getSkillProgressRequirement (int skillIndex, const MWBase::Environment::get().getWorld()->getStore().get().find (skillIndex); if (skill->mData.mSpecialization==class_.mData.mSpecialization) { - specialisationFactor = gmst.find ("fSpecialSkillBonus")->getFloat(); + specialisationFactor = gmst.find ("fSpecialSkillBonus")->mValue.getFloat(); if (specialisationFactor<=0) throw std::runtime_error ("invalid skill specialisation factor"); @@ -227,21 +227,21 @@ void MWMechanics::NpcStats::increaseSkill(int skillIndex, const ESM::Class &clas MWBase::Environment::get().getWorld()->getStore().get(); // is this a minor or major skill? - int increase = gmst.find("iLevelupMiscMultAttriubte")->getInt(); // Note: GMST has a typo + int increase = gmst.find("iLevelupMiscMultAttriubte")->mValue.getInteger(); // Note: GMST has a typo for (int k=0; k<5; ++k) { if (class_.mData.mSkills[k][0] == skillIndex) { - mLevelProgress += gmst.find("iLevelUpMinorMult")->getInt(); - increase = gmst.find("iLevelUpMajorMultAttribute")->getInt(); + mLevelProgress += gmst.find("iLevelUpMinorMult")->mValue.getInteger(); + increase = gmst.find("iLevelUpMajorMultAttribute")->mValue.getInteger(); } } for (int k=0; k<5; ++k) { if (class_.mData.mSkills[k][1] == skillIndex) { - mLevelProgress += gmst.find("iLevelUpMajorMult")->getInt(); - increase = gmst.find("iLevelUpMinorMultAttribute")->getInt(); + mLevelProgress += gmst.find("iLevelUpMajorMult")->mValue.getInteger(); + increase = gmst.find("iLevelUpMinorMultAttribute")->mValue.getInteger(); } } @@ -249,7 +249,7 @@ void MWMechanics::NpcStats::increaseSkill(int skillIndex, const ESM::Class &clas MWBase::Environment::get().getWorld ()->getStore ().get().find(skillIndex); mSkillIncreases[skill->mData.mAttribute] += increase; - mSpecIncreases[skill->mData.mSpecialization] += gmst.find("iLevelupSpecialization")->getInt(); + mSpecIncreases[skill->mData.mSpecialization] += gmst.find("iLevelupSpecialization")->mValue.getInteger(); // Play sound & skill progress notification /// \todo check if character is the player, if levelling is ever implemented for NPCs @@ -266,7 +266,7 @@ void MWMechanics::NpcStats::increaseSkill(int skillIndex, const ESM::Class &clas MWBase::Environment::get().getWindowManager ()->messageBox(message.str(), MWGui::ShowInDialogueMode_Never); - if (mLevelProgress >= gmst.find("iLevelUpTotal")->getInt()) + if (mLevelProgress >= gmst.find("iLevelUpTotal")->mValue.getInteger()) { // levelup is possible now MWBase::Environment::get().getWindowManager ()->messageBox ("#{sLevelUpMsg}", MWGui::ShowInDialogueMode_Never); @@ -287,7 +287,7 @@ void MWMechanics::NpcStats::levelUp() const MWWorld::Store &gmst = MWBase::Environment::get().getWorld()->getStore().get(); - mLevelProgress -= gmst.find("iLevelUpTotal")->getInt(); + mLevelProgress -= gmst.find("iLevelUpTotal")->mValue.getInteger(); mLevelProgress = std::max(0, mLevelProgress); // might be necessary when levelup was invoked via console for (int i=0; igetFloat()); + setHealth(getHealth().getBase() + endurance * gmst.find("fLevelUpHealthEndMult")->mValue.getFloat()); setLevel(getLevel()+1); } @@ -324,7 +324,7 @@ int MWMechanics::NpcStats::getLevelupAttributeMultiplier(int attribute) const std::stringstream gmst; gmst << "iLevelUp" << std::setfill('0') << std::setw(2) << num << "Mult"; - return MWBase::Environment::get().getWorld()->getStore().get().find(gmst.str())->getInt(); + return MWBase::Environment::get().getWorld()->getStore().get().find(gmst.str())->mValue.getInteger(); } int MWMechanics::NpcStats::getSkillIncreasesForSpecialization(int spec) const diff --git a/apps/openmw/mwmechanics/pickpocket.cpp b/apps/openmw/mwmechanics/pickpocket.cpp index eca24606e..ed6469106 100644 --- a/apps/openmw/mwmechanics/pickpocket.cpp +++ b/apps/openmw/mwmechanics/pickpocket.cpp @@ -37,9 +37,9 @@ namespace MWMechanics float pcSneak = static_cast(mThief.getClass().getSkill(mThief, ESM::Skill::Sneak)); int iPickMinChance = MWBase::Environment::get().getWorld()->getStore().get() - .find("iPickMinChance")->getInt(); + .find("iPickMinChance")->mValue.getInteger(); int iPickMaxChance = MWBase::Environment::get().getWorld()->getStore().get() - .find("iPickMaxChance")->getInt(); + .find("iPickMaxChance")->mValue.getInteger(); int roll = Misc::Rng::roll0to99(); if (t < pcSneak / iPickMinChance) @@ -57,7 +57,7 @@ namespace MWMechanics { float stackValue = static_cast(item.getClass().getValue(item) * count); float fPickPocketMod = MWBase::Environment::get().getWorld()->getStore().get() - .find("fPickPocketMod")->getFloat(); + .find("fPickPocketMod")->mValue.getFloat(); float valueTerm = 10 * fPickPocketMod * stackValue; return getDetected(valueTerm); diff --git a/apps/openmw/mwmechanics/repair.cpp b/apps/openmw/mwmechanics/repair.cpp index 5c6123e82..3ebef36bf 100644 --- a/apps/openmw/mwmechanics/repair.cpp +++ b/apps/openmw/mwmechanics/repair.cpp @@ -42,7 +42,7 @@ void Repair::repair(const MWWorld::Ptr &itemToRepair) int armorerSkill = npcStats.getSkill(ESM::Skill::Armorer).getModified(); float fRepairAmountMult = MWBase::Environment::get().getWorld()->getStore().get() - .find("fRepairAmountMult")->getFloat(); + .find("fRepairAmountMult")->mValue.getFloat(); float toolQuality = ref->mBase->mData.mQuality; @@ -87,7 +87,7 @@ void Repair::repair(const MWWorld::Ptr &itemToRepair) store.remove(mTool, 1, player); std::string message = MWBase::Environment::get().getWorld()->getStore().get() - .find("sNotifyMessage51")->getString(); + .find("sNotifyMessage51")->mValue.getString(); MWBase::Environment::get().getWindowManager()->messageBox((boost::format(message) % mTool.getClass().getName(mTool)).str()); diff --git a/apps/openmw/mwmechanics/security.cpp b/apps/openmw/mwmechanics/security.cpp index 3e38bc521..c8a4dd770 100644 --- a/apps/openmw/mwmechanics/security.cpp +++ b/apps/openmw/mwmechanics/security.cpp @@ -40,7 +40,7 @@ namespace MWMechanics float pickQuality = lockpick.get()->mBase->mData.mQuality; - float fPickLockMult = MWBase::Environment::get().getWorld()->getStore().get().find("fPickLockMult")->getFloat(); + float fPickLockMult = MWBase::Environment::get().getWorld()->getStore().get().find("fPickLockMult")->mValue.getFloat(); float x = 0.2f * mAgility + 0.1f * mLuck + mSecuritySkill; x *= pickQuality * mFatigueTerm; @@ -81,7 +81,7 @@ namespace MWMechanics const ESM::Spell* trapSpell = MWBase::Environment::get().getWorld()->getStore().get().find(trap.getCellRef().getTrap()); int trapSpellPoints = trapSpell->mData.mCost; - float fTrapCostMult = MWBase::Environment::get().getWorld()->getStore().get().find("fTrapCostMult")->getFloat(); + float fTrapCostMult = MWBase::Environment::get().getWorld()->getStore().get().find("fTrapCostMult")->mValue.getFloat(); float x = 0.2f * mAgility + 0.1f * mLuck + mSecuritySkill; x += fTrapCostMult * trapSpellPoints; diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 76140013d..9e163f132 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -62,7 +62,7 @@ namespace MWMechanics duration = effect.mDuration; static const float fEffectCostMult = MWBase::Environment::get().getWorld()->getStore() - .get().find("fEffectCostMult")->getFloat(); + .get().find("fEffectCostMult")->mValue.getFloat(); float x = 0.5 * (std::max(1, minMagn) + std::max(1, maxMagn)); x *= 0.1 * magicEffect->mData.mBaseCost; @@ -93,7 +93,7 @@ namespace MWMechanics if (it->mRange == ESM::RT_Target) x *= 1.5f; static const float fEffectCostMult = MWBase::Environment::get().getWorld()->getStore().get().find( - "fEffectCostMult")->getFloat(); + "fEffectCostMult")->mValue.getFloat(); x *= fEffectCostMult; float s = 2.0f * actor.getClass().getSkill(actor, spellSchoolToSkill(magicEffect->mData.mSchool)); @@ -883,8 +883,8 @@ namespace MWMechanics if (!godmode) { // Reduce fatigue (note that in the vanilla game, both GMSTs are 0, and there's no fatigue loss) - static const float fFatigueSpellBase = store.get().find("fFatigueSpellBase")->getFloat(); - static const float fFatigueSpellMult = store.get().find("fFatigueSpellMult")->getFloat(); + static const float fFatigueSpellBase = store.get().find("fFatigueSpellBase")->mValue.getFloat(); + static const float fFatigueSpellMult = store.get().find("fFatigueSpellMult")->mValue.getFloat(); DynamicStat fatigue = stats.getFatigue(); const float normalizedEncumbrance = mCaster.getClass().getNormalizedEncumbrance(mCaster); @@ -968,7 +968,7 @@ namespace MWMechanics if (roll > x) { // "X has no effect on you" - std::string message = MWBase::Environment::get().getWorld()->getStore().get().find("sNotifyMessage50")->getString(); + std::string message = MWBase::Environment::get().getWorld()->getStore().get().find("sNotifyMessage50")->mValue.getString(); message = boost::str(boost::format(message) % ingredient->mName); MWBase::Environment::get().getWindowManager()->messageBox(message); return false; @@ -1251,7 +1251,7 @@ namespace MWMechanics float damageScale = 1.f - timeDiff / 7.f; // When cloudy, the sun damage effect is halved static float fMagicSunBlockedMult = MWBase::Environment::get().getWorld()->getStore().get().find( - "fMagicSunBlockedMult")->getFloat(); + "fMagicSunBlockedMult")->mValue.getFloat(); int weather = MWBase::Environment::get().getWorld()->getCurrentWeather(); if (weather > 1) @@ -1348,7 +1348,7 @@ namespace MWMechanics if (it == summonMap.end()) return std::string(); else - return MWBase::Environment::get().getWorld()->getStore().get().find(it->second)->getString(); + return MWBase::Environment::get().getWorld()->getStore().get().find(it->second)->mValue.getString(); } void ApplyLoopingParticlesVisitor::visit (MWMechanics::EffectKey key, diff --git a/apps/openmw/mwmechanics/spellpriority.cpp b/apps/openmw/mwmechanics/spellpriority.cpp index 7bedb1e37..9a366a916 100644 --- a/apps/openmw/mwmechanics/spellpriority.cpp +++ b/apps/openmw/mwmechanics/spellpriority.cpp @@ -593,8 +593,8 @@ namespace MWMechanics { const MWWorld::Store& gmst = MWBase::Environment::get().getWorld()->getStore().get(); - static const float fAIMagicSpellMult = gmst.find("fAIMagicSpellMult")->getFloat(); - static const float fAIRangeMagicSpellMult = gmst.find("fAIRangeMagicSpellMult")->getFloat(); + static const float fAIMagicSpellMult = gmst.find("fAIMagicSpellMult")->mValue.getFloat(); + static const float fAIRangeMagicSpellMult = gmst.find("fAIRangeMagicSpellMult")->mValue.getFloat(); float mult = fAIMagicSpellMult; diff --git a/apps/openmw/mwmechanics/trading.cpp b/apps/openmw/mwmechanics/trading.cpp index eee5e6449..b824d7c45 100644 --- a/apps/openmw/mwmechanics/trading.cpp +++ b/apps/openmw/mwmechanics/trading.cpp @@ -50,11 +50,11 @@ namespace MWMechanics float e1 = 0.1f * merchantStats.getAttribute(ESM::Attribute::Luck).getModified(); float f1 = 0.2f * merchantStats.getAttribute(ESM::Attribute::Personality).getModified(); - float dispositionTerm = gmst.find("fDispositionMod")->getFloat() * (clampedDisposition - 50); + float dispositionTerm = gmst.find("fDispositionMod")->mValue.getFloat() * (clampedDisposition - 50); float pcTerm = (dispositionTerm + a1 + b1 + c1) * playerStats.getFatigueTerm(); float npcTerm = (d1 + e1 + f1) * merchantStats.getFatigueTerm(); - float x = gmst.find("fBargainOfferMulti")->getFloat() * d - + gmst.find("fBargainOfferBase")->getFloat() + float x = gmst.find("fBargainOfferMulti")->mValue.getFloat() * d + + gmst.find("fBargainOfferBase")->mValue.getFloat() + int(pcTerm - npcTerm); int roll = Misc::Rng::rollDice(100) + 1; diff --git a/apps/openmw/mwmechanics/weaponpriority.cpp b/apps/openmw/mwmechanics/weaponpriority.cpp index 9030d6254..7e33784c1 100644 --- a/apps/openmw/mwmechanics/weaponpriority.cpp +++ b/apps/openmw/mwmechanics/weaponpriority.cpp @@ -157,9 +157,9 @@ namespace MWMechanics { const MWWorld::Store& gmst = MWBase::Environment::get().getWorld()->getStore().get(); - static const float fAIMeleeWeaponMult = gmst.find("fAIMeleeWeaponMult")->getFloat(); - static const float fAIMeleeArmorMult = gmst.find("fAIMeleeArmorMult")->getFloat(); - static const float fAIRangeMeleeWeaponMult = gmst.find("fAIRangeMeleeWeaponMult")->getFloat(); + static const float fAIMeleeWeaponMult = gmst.find("fAIMeleeWeaponMult")->mValue.getFloat(); + static const float fAIMeleeArmorMult = gmst.find("fAIMeleeArmorMult")->mValue.getFloat(); + static const float fAIRangeMeleeWeaponMult = gmst.find("fAIRangeMeleeWeaponMult")->mValue.getFloat(); if (weapon.isEmpty()) return 0.f; diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 2a7b65cac..90668914f 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -303,7 +303,7 @@ namespace MWPhysics position.z() += halfExtents.z(); static const float fSwimHeightScale = MWBase::Environment::get().getWorld()->getStore().get() - .find("fSwimHeightScale")->getFloat(); + .find("fSwimHeightScale")->mValue.getFloat(); float swimlevel = waterlevel + halfExtents.z() - (physicActor->getRenderingHalfExtents().z() * 2 * fSwimHeightScale); ActorTracer tracer; @@ -339,7 +339,7 @@ namespace MWPhysics osg::Vec3f stormDirection = MWBase::Environment::get().getWorld()->getStormDirection(); float angleDegrees = osg::RadiansToDegrees(std::acos(stormDirection * velocity / (stormDirection.length() * velocity.length()))); static const float fStromWalkMult = MWBase::Environment::get().getWorld()->getStore().get() - .find("fStromWalkMult")->getFloat(); + .find("fStromWalkMult")->mValue.getFloat(); velocity *= 1.f-(fStromWalkMult * (angleDegrees/180.f)); } @@ -860,8 +860,8 @@ namespace MWPhysics // Use cone shape as fallback const MWWorld::Store &store = MWBase::Environment::get().getWorld()->getStore().get(); - btConeShape shape (osg::DegreesToRadians(store.find("fCombatAngleXY")->getFloat()/2.0f), queryDistance); - shape.setLocalScaling(btVector3(1, 1, osg::DegreesToRadians(store.find("fCombatAngleZ")->getFloat()/2.0f) / + btConeShape shape (osg::DegreesToRadians(store.find("fCombatAngleXY")->mValue.getFloat()/2.0f), queryDistance); + shape.setLocalScaling(btVector3(1, 1, osg::DegreesToRadians(store.find("fCombatAngleZ")->mValue.getFloat()/2.0f) / shape.getRadius())); // The shape origin is its center, so we have to move it forward by half the length. The diff --git a/apps/openmw/mwrender/weaponanimation.cpp b/apps/openmw/mwrender/weaponanimation.cpp index 054ce1b1d..32990482a 100644 --- a/apps/openmw/mwrender/weaponanimation.cpp +++ b/apps/openmw/mwrender/weaponanimation.cpp @@ -119,8 +119,8 @@ void WeaponAnimation::releaseArrow(MWWorld::Ptr actor, float attackStrength) return; osg::Vec3f launchPos = osg::computeLocalToWorld(nodepaths[0]).getTrans(); - float fThrownWeaponMinSpeed = gmst.find("fThrownWeaponMinSpeed")->getFloat(); - float fThrownWeaponMaxSpeed = gmst.find("fThrownWeaponMaxSpeed")->getFloat(); + float fThrownWeaponMinSpeed = gmst.find("fThrownWeaponMinSpeed")->mValue.getFloat(); + float fThrownWeaponMaxSpeed = gmst.find("fThrownWeaponMaxSpeed")->mValue.getFloat(); float speed = fThrownWeaponMinSpeed + (fThrownWeaponMaxSpeed - fThrownWeaponMinSpeed) * attackStrength; MWWorld::Ptr weaponPtr = *weapon; @@ -146,8 +146,8 @@ void WeaponAnimation::releaseArrow(MWWorld::Ptr actor, float attackStrength) return; osg::Vec3f launchPos = osg::computeLocalToWorld(nodepaths[0]).getTrans(); - float fProjectileMinSpeed = gmst.find("fProjectileMinSpeed")->getFloat(); - float fProjectileMaxSpeed = gmst.find("fProjectileMaxSpeed")->getFloat(); + float fProjectileMinSpeed = gmst.find("fProjectileMinSpeed")->mValue.getFloat(); + float fProjectileMaxSpeed = gmst.find("fProjectileMaxSpeed")->mValue.getFloat(); float speed = fProjectileMinSpeed + (fProjectileMaxSpeed - fProjectileMinSpeed) * attackStrength; MWWorld::Ptr weaponPtr = *weapon; diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index d6dc2ba99..9c12584d7 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -139,10 +139,10 @@ namespace MWSound Sound_Buffer *SoundManager::insertSound(const std::string &soundId, const ESM::Sound *sound) { MWBase::World* world = MWBase::Environment::get().getWorld(); - static const float fAudioDefaultMinDistance = world->getStore().get().find("fAudioDefaultMinDistance")->getFloat(); - static const float fAudioDefaultMaxDistance = world->getStore().get().find("fAudioDefaultMaxDistance")->getFloat(); - static const float fAudioMinDistanceMult = world->getStore().get().find("fAudioMinDistanceMult")->getFloat(); - static const float fAudioMaxDistanceMult = world->getStore().get().find("fAudioMaxDistanceMult")->getFloat(); + static const float fAudioDefaultMinDistance = world->getStore().get().find("fAudioDefaultMinDistance")->mValue.getFloat(); + static const float fAudioDefaultMaxDistance = world->getStore().get().find("fAudioDefaultMaxDistance")->mValue.getFloat(); + static const float fAudioMinDistanceMult = world->getStore().get().find("fAudioMinDistanceMult")->mValue.getFloat(); + static const float fAudioMaxDistanceMult = world->getStore().get().find("fAudioMaxDistanceMult")->mValue.getFloat(); float volume, min, max; volume = static_cast(pow(10.0, (sound->mData.mVolume / 255.0*3348.0 - 3348.0) / 2000.0)); @@ -296,10 +296,10 @@ namespace MWSound Stream *SoundManager::playVoice(DecoderPtr decoder, const osg::Vec3f &pos, bool playlocal) { MWBase::World* world = MWBase::Environment::get().getWorld(); - static const float fAudioMinDistanceMult = world->getStore().get().find("fAudioMinDistanceMult")->getFloat(); - static const float fAudioMaxDistanceMult = world->getStore().get().find("fAudioMaxDistanceMult")->getFloat(); - static const float fAudioVoiceDefaultMinDistance = world->getStore().get().find("fAudioVoiceDefaultMinDistance")->getFloat(); - static const float fAudioVoiceDefaultMaxDistance = world->getStore().get().find("fAudioVoiceDefaultMaxDistance")->getFloat(); + static const float fAudioMinDistanceMult = world->getStore().get().find("fAudioMinDistanceMult")->mValue.getFloat(); + static const float fAudioMaxDistanceMult = world->getStore().get().find("fAudioMaxDistanceMult")->mValue.getFloat(); + static const float fAudioVoiceDefaultMinDistance = world->getStore().get().find("fAudioVoiceDefaultMinDistance")->mValue.getFloat(); + static const float fAudioVoiceDefaultMaxDistance = world->getStore().get().find("fAudioVoiceDefaultMaxDistance")->mValue.getFloat(); static float minDistance = std::max(fAudioVoiceDefaultMinDistance * fAudioMinDistanceMult, 1.0f); static float maxDistance = std::max(fAudioVoiceDefaultMaxDistance * fAudioMaxDistanceMult, minDistance); diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index 40e904ec2..05ff1e326 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -944,7 +944,7 @@ namespace MWWorld void clearCorpse(const MWWorld::Ptr& ptr) { const MWMechanics::CreatureStats& creatureStats = ptr.getClass().getCreatureStats(ptr); - static const float fCorpseClearDelay = MWBase::Environment::get().getWorld()->getStore().get().find("fCorpseClearDelay")->getFloat(); + static const float fCorpseClearDelay = MWBase::Environment::get().getWorld()->getStore().get().find("fCorpseClearDelay")->mValue.getFloat(); if (creatureStats.isDead() && creatureStats.isDeathAnimationFinished() && !ptr.getClass().isPersistent(ptr) && @@ -958,7 +958,7 @@ namespace MWWorld { if (mState == State_Loaded) { - static const int iMonthsToRespawn = MWBase::Environment::get().getWorld()->getStore().get().find("iMonthsToRespawn")->getInt(); + static const int iMonthsToRespawn = MWBase::Environment::get().getWorld()->getStore().get().find("iMonthsToRespawn")->mValue.getInteger(); if (MWBase::Environment::get().getWorld()->getTimeStamp() - mLastRespawn > 24*30*iMonthsToRespawn) { mLastRespawn = MWBase::Environment::get().getWorld()->getTimeStamp(); diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index 6cfffcde6..7f3018c55 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -252,8 +252,8 @@ void MWWorld::InventoryStore::autoEquip (const MWWorld::Ptr& actor) const MWWorld::Store &store = world->getStore().get(); MWMechanics::NpcStats& stats = actor.getClass().getNpcStats(actor); - static float fUnarmoredBase1 = store.find("fUnarmoredBase1")->getFloat(); - static float fUnarmoredBase2 = store.find("fUnarmoredBase2")->getFloat(); + static float fUnarmoredBase1 = store.find("fUnarmoredBase1")->mValue.getFloat(); + static float fUnarmoredBase2 = store.find("fUnarmoredBase2")->mValue.getFloat(); int unarmoredSkill = stats.getSkill(ESM::Skill::Unarmored).getModified(); float unarmoredRating = (fUnarmoredBase1 * unarmoredSkill) * (fUnarmoredBase2 * unarmoredSkill); @@ -921,7 +921,7 @@ void MWWorld::InventoryStore::rechargeItems(float duration) continue; static float fMagicItemRechargePerSecond = MWBase::Environment::get().getWorld()->getStore().get().find( - "fMagicItemRechargePerSecond")->getFloat(); + "fMagicItemRechargePerSecond")->mValue.getFloat(); if (it->first->getCellRef().getEnchantmentCharge() <= it->second) { diff --git a/apps/openmw/mwworld/player.cpp b/apps/openmw/mwworld/player.cpp index 44b78336d..389f59983 100644 --- a/apps/openmw/mwworld/player.cpp +++ b/apps/openmw/mwworld/player.cpp @@ -64,7 +64,7 @@ namespace MWWorld MWMechanics::CreatureStats& creatureStats = getPlayer().getClass().getCreatureStats(getPlayer()); MWMechanics::NpcStats& npcStats = getPlayer().getClass().getNpcStats(getPlayer()); MWMechanics::DynamicStat health = creatureStats.getDynamic(0); - creatureStats.setHealth(int(health.getBase() / gmst.find("fWereWolfHealth")->getFloat())); + creatureStats.setHealth(int(health.getBase() / gmst.find("fWereWolfHealth")->mValue.getFloat())); for (int i=0; i health = creatureStats.getDynamic(0); - creatureStats.setHealth(int(health.getBase() * gmst.find("fWereWolfHealth")->getFloat())); + creatureStats.setHealth(int(health.getBase() * gmst.find("fWereWolfHealth")->mValue.getFloat())); for(size_t i = 0;i < ESM::Attribute::Length;++i) { // Oh, Bethesda. It's "Intelligence". @@ -85,7 +85,7 @@ namespace MWWorld ESM::Attribute::sAttributeNames[i]); MWMechanics::AttributeValue value = npcStats.getAttribute(i); - value.setBase(int(gmst.find(name)->getFloat())); + value.setBase(int(gmst.find(name)->mValue.getFloat())); npcStats.setAttribute(i, value); } @@ -100,7 +100,7 @@ namespace MWWorld ESM::Skill::sSkillNames[i]); MWMechanics::SkillValue value = npcStats.getSkill(i); - value.setBase(int(gmst.find(name)->getFloat())); + value.setBase(int(gmst.find(name)->mValue.getFloat())); npcStats.setSkill(i, value); } } diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index f150ff0ba..21218fab0 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -385,7 +385,7 @@ namespace MWWorld { osg::Quat orient = it->mNode->getAttitude(); static float fTargetSpellMaxSpeed = MWBase::Environment::get().getWorld()->getStore().get() - .find("fTargetSpellMaxSpeed")->getFloat(); + .find("fTargetSpellMaxSpeed")->mValue.getFloat(); float speed = fTargetSpellMaxSpeed * it->mSpeed; osg::Vec3f direction = orient * osg::Vec3f(0,1,0); direction.normalize(); diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index d12e633be..2a9e8d7cc 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -911,7 +911,7 @@ inline void WeatherManager::addWeather(const std::string& name, float dlFactor, float dlOffset, const std::string& particleEffect) { - static const float fStromWindSpeed = mStore.get().find("fStromWindSpeed")->getFloat(); + static const float fStromWindSpeed = mStore.get().find("fStromWindSpeed")->mValue.getFloat(); Weather weather(name, fallback, fStromWindSpeed, mRainSpeed, dlFactor, dlOffset, particleEffect); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 0bc952e89..48cb1dda3 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -190,7 +190,7 @@ namespace MWWorld mStore.setUp(true); mStore.movePlayerRecord(); - mSwimHeightScale = mStore.get().find("fSwimHeightScale")->getFloat(); + mSwimHeightScale = mStore.get().find("fSwimHeightScale")->mValue.getFloat(); mWeatherManager.reset(new MWWorld::WeatherManager(*mRendering, mFallback, mStore)); @@ -1026,7 +1026,7 @@ namespace MWWorld if (mActivationDistanceOverride >= 0) return static_cast(mActivationDistanceOverride); - static const int iMaxActivateDist = getStore().get().find("iMaxActivateDist")->getInt(); + static const int iMaxActivateDist = getStore().get().find("iMaxActivateDist")->mValue.getInteger(); return static_cast(iMaxActivateDist); } @@ -1709,7 +1709,7 @@ namespace MWWorld bool swimming = isSwimming(player); bool flying = isFlying(player); - static const float i1stPersonSneakDelta = getStore().get().find("i1stPersonSneakDelta")->getFloat(); + static const float i1stPersonSneakDelta = getStore().get().find("i1stPersonSneakDelta")->mValue.getFloat(); if (sneaking && !swimming && !flying) mRendering->getCamera()->setSneakOffset(i1stPersonSneakDelta); else @@ -2803,7 +2803,7 @@ namespace MWWorld if (!actor.isEmpty() && actor != MWMechanics::getPlayer() && !manualSpell) stats.getAiSequence().getCombatTargets(targetActors); - const float fCombatDistance = getStore().get().find("fCombatDistance")->getFloat(); + const float fCombatDistance = getStore().get().find("fCombatDistance")->mValue.getFloat(); osg::Vec3f hitPosition = actor.getRefData().getPosition().asVec3(); @@ -3267,8 +3267,8 @@ namespace MWWorld int bounty = player.getClass().getNpcStats(player).getBounty(); int playerGold = player.getClass().getContainerStore(player).count(ContainerStore::sGoldId); - float fCrimeGoldDiscountMult = getStore().get().find("fCrimeGoldDiscountMult")->getFloat(); - float fCrimeGoldTurnInMult = getStore().get().find("fCrimeGoldTurnInMult")->getFloat(); + float fCrimeGoldDiscountMult = getStore().get().find("fCrimeGoldDiscountMult")->mValue.getFloat(); + float fCrimeGoldTurnInMult = getStore().get().find("fCrimeGoldTurnInMult")->mValue.getFloat(); int discount = static_cast(bounty * fCrimeGoldDiscountMult); int turnIn = static_cast(bounty * fCrimeGoldTurnInMult); @@ -3333,7 +3333,7 @@ namespace MWWorld mPlayer->recordCrimeId(); confiscateStolenItems(player); - int iDaysinPrisonMod = getStore().get().find("iDaysinPrisonMod")->getInt(); + int iDaysinPrisonMod = getStore().get().find("iDaysinPrisonMod")->mValue.getInteger(); mDaysInPrison = std::max(1, bounty / iDaysinPrisonMod); return; @@ -3391,7 +3391,7 @@ namespace MWWorld { const ESM::CreatureLevList* list = getStore().get().find(creatureList); - int iNumberCreatures = getStore().get().find("iNumberCreatures")->getInt(); + int iNumberCreatures = getStore().get().find("iNumberCreatures")->mValue.getInteger(); int numCreatures = 1 + Misc::Rng::rollDice(iNumberCreatures); // [1, iNumberCreatures] for (int i=0; i Date: Thu, 30 Aug 2018 23:52:33 +0300 Subject: [PATCH 043/196] Grant Enchant experience even if recharging fails (bug #4622) --- CHANGELOG.md | 1 + apps/openmw/mwgui/recharge.cpp | 3 +-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5453ffb49..8ae6088de 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -110,6 +110,7 @@ Bug #4615: Flicker effects for light sources are handled incorrectly Bug #4617: First person sneaking offset is not applied while the character is in air Bug #4618: Sneaking is possible while the character is flying + Bug #4622: Recharging enchanted items with Soul Gems does not award experience if it fails Feature #1645: Casting effects from objects Feature #2606: Editor: Implemented (optional) case sensitive global search Feature #3083: Play animation when NPC is casting spell via script diff --git a/apps/openmw/mwgui/recharge.cpp b/apps/openmw/mwgui/recharge.cpp index 26a364f72..8bd8e250b 100644 --- a/apps/openmw/mwgui/recharge.cpp +++ b/apps/openmw/mwgui/recharge.cpp @@ -169,14 +169,13 @@ void Recharge::onItemClicked(MyGUI::Widget *sender, const MWWorld::Ptr& item) MWBase::Environment::get().getWindowManager()->playSound("Enchant Success"); player.getClass().getContainerStore(player).restack(item); - - player.getClass().skillUsageSucceeded (player, ESM::Skill::Enchant, 0); } else { MWBase::Environment::get().getWindowManager()->playSound("Enchant Fail"); } + player.getClass().skillUsageSucceeded (player, ESM::Skill::Enchant, 0); gem.getContainerStore()->remove(gem, 1, player); if (gem.getRefData().getCount() == 0) From 374e98d665f303f2a981b4d2dfcc5601e073c48d Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Thu, 30 Aug 2018 23:04:02 +0300 Subject: [PATCH 044/196] Make rateWeapon more sensible and account for weapon speed --- apps/openmw/mwmechanics/weaponpriority.cpp | 71 +++++++++------------- 1 file changed, 30 insertions(+), 41 deletions(-) diff --git a/apps/openmw/mwmechanics/weaponpriority.cpp b/apps/openmw/mwmechanics/weaponpriority.cpp index ac01a0714..8d09bd8d1 100644 --- a/apps/openmw/mwmechanics/weaponpriority.cpp +++ b/apps/openmw/mwmechanics/weaponpriority.cpp @@ -21,13 +21,19 @@ namespace MWMechanics float rateWeapon (const MWWorld::Ptr &item, const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy, int type, float arrowRating, float boltRating) { - if (item.getTypeName() != typeid(ESM::Weapon).name()) + if (enemy.isEmpty() || item.getTypeName() != typeid(ESM::Weapon).name()) + return 0.f; + + if (item.getClass().hasItemHealth(item) && item.getClass().getItemHealth(item) == 0) return 0.f; const ESM::Weapon* weapon = item.get()->mBase; if (type != -1 && weapon->mData.mType != type) return 0.f; + + const MWBase::World* world = MWBase::Environment::get().getWorld(); + const MWWorld::Store& gmst = world->getStore().get(); if (type == -1 && (weapon->mData.mType == ESM::Weapon::Arrow || weapon->mData.mType == ESM::Weapon::Bolt)) return 0.f; @@ -37,54 +43,34 @@ namespace MWMechanics if (weapon->mData.mType >= ESM::Weapon::MarksmanBow && weapon->mData.mType <= ESM::Weapon::MarksmanThrown) { - // Range weapon is useless under water - if (MWBase::Environment::get().getWorld()->isUnderwater(MWWorld::ConstPtr(actor), 0.75f)) - return 0.f; - - if (enemy.isEmpty()) - return 0.f; - - if (MWBase::Environment::get().getWorld()->isUnderwater(MWWorld::ConstPtr(enemy), 0.75f)) + // Underwater ranged combat is impossible + if (world->isUnderwater(MWWorld::ConstPtr(actor), 0.75f) + || world->isUnderwater(MWWorld::ConstPtr(enemy), 0.75f)) return 0.f; if (getDistanceMinusHalfExtents(actor, enemy) >= getMaxAttackDistance(enemy)) - rangedMult = 1.5f; + { + static const float fAIMeleeWeaponMult = gmst.find("fAIMeleeWeaponMult")->mValue.getFloat(); + static const float fAIRangeMeleeWeaponMult = gmst.find("fAIRangeMeleeWeaponMult")->mValue.getFloat(); + rangedMult = fAIRangeMeleeWeaponMult / fAIMeleeWeaponMult; + } } + const float chop = (weapon->mData.mChop[0] + weapon->mData.mChop[1]) / 2.f; if (weapon->mData.mType >= ESM::Weapon::MarksmanBow) - { - float rangedDamage = weapon->mData.mChop[0] + weapon->mData.mChop[1]; - MWMechanics::adjustWeaponDamage(rangedDamage, item, actor); - - rating = rangedDamage / 2.f; - - if (weapon->mData.mType >= ESM::Weapon::MarksmanThrown) - MWMechanics::resistNormalWeapon(enemy, actor, item, rating); - } + rating = chop; else { - float meleeDamage = 0.f; - - for (int i=0; i<2; ++i) - { - meleeDamage += weapon->mData.mSlash[i]; - meleeDamage += weapon->mData.mThrust[i]; - meleeDamage += weapon->mData.mChop[i]; - } - - MWMechanics::adjustWeaponDamage(meleeDamage, item, actor); - rating = meleeDamage / 6.f; - - MWMechanics::resistNormalWeapon(enemy, actor, item, rating); + const float slash = (weapon->mData.mSlash[0] + weapon->mData.mSlash[1]) / 2.f; + const float thrust = (weapon->mData.mThrust[0] + weapon->mData.mThrust[1]) / 2.f; + rating = (slash * slash + thrust * thrust + chop * chop) / (slash + thrust + chop); } - if (item.getClass().hasItemHealth(item)) - { - if (item.getClass().getItemHealth(item) == 0) - return 0.f; - } + adjustWeaponDamage(rating, item, actor); - if (weapon->mData.mType == ESM::Weapon::MarksmanBow) + if (weapon->mData.mType != ESM::Weapon::MarksmanBow && weapon->mData.mType != ESM::Weapon::MarksmanCrossbow) + resistNormalWeapon(enemy, actor, item, rating); + else if (weapon->mData.mType == ESM::Weapon::MarksmanBow) { if (arrowRating <= 0.f) rating = 0.f; @@ -101,7 +87,7 @@ namespace MWMechanics if (!weapon->mEnchant.empty()) { - const ESM::Enchantment* enchantment = MWBase::Environment::get().getWorld()->getStore().get().find(weapon->mEnchant); + const ESM::Enchantment* enchantment = world->getStore().get().find(weapon->mEnchant); if (enchantment->mData.mType == ESM::Enchantment::WhenStrikes) { int castCost = getEffectiveEnchantmentCastCost(static_cast(enchantment->mData.mCost), actor); @@ -111,19 +97,22 @@ namespace MWMechanics } } + if (weapon->mData.mType <= ESM::Weapon::MarksmanThrown) + rating *= weapon->mData.mSpeed; + if (actor.getClass().isNpc()) { int skill = item.getClass().getEquipmentSkill(item); if (skill != -1) { int value = actor.getClass().getSkill(actor, skill); - rating *= MWMechanics::getHitChance(actor, enemy, value) / 100.f; + rating *= getHitChance(actor, enemy, value) / 100.f; } } else { MWWorld::LiveCellRef *ref = actor.get(); - rating *= MWMechanics::getHitChance(actor, enemy, ref->mBase->mData.mCombat) / 100.f; + rating *= getHitChance(actor, enemy, ref->mBase->mData.mCombat) / 100.f; } return rating * rangedMult; From 00c847db195e41036510681796d0279db0cbdf02 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Thu, 30 Aug 2018 23:36:47 +0300 Subject: [PATCH 045/196] Make AI Blind, Sound and Silence effect rating more logical --- apps/openmw/mwmechanics/spellpriority.cpp | 54 ++++++++++++++++++++--- 1 file changed, 47 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwmechanics/spellpriority.cpp b/apps/openmw/mwmechanics/spellpriority.cpp index a4bf46769..b43756162 100644 --- a/apps/openmw/mwmechanics/spellpriority.cpp +++ b/apps/openmw/mwmechanics/spellpriority.cpp @@ -232,20 +232,59 @@ namespace MWMechanics case ESM::MagicEffect::CommandHumanoid: return 0.f; + case ESM::MagicEffect::Blind: + { + if (enemy.isEmpty()) + return 0.f; + + const CreatureStats& stats = enemy.getClass().getCreatureStats(enemy); + + // Enemy can't attack + if (stats.getMagicEffects().get(ESM::MagicEffect::Paralyze).getMagnitude() > 0) + return 0.f; + + // Enemy doesn't attack + if (stats.getDrawState() != MWMechanics::DrawState_Weapon) + return 0.f; + + break; + } + case ESM::MagicEffect::Sound: { if (enemy.isEmpty()) return 0.f; - // there is no need to cast sound if enemy is not able to cast spells - CreatureStats& stats = enemy.getClass().getCreatureStats(enemy); + const CreatureStats& stats = enemy.getClass().getCreatureStats(enemy); + // Enemy can't cast spells if (stats.getMagicEffects().get(ESM::MagicEffect::Silence).getMagnitude() > 0) return 0.f; if (stats.getMagicEffects().get(ESM::MagicEffect::Paralyze).getMagnitude() > 0) return 0.f; + // Enemy doesn't cast spells + if (stats.getDrawState() != MWMechanics::DrawState_Spell) + return 0.f; + + break; + } + + case ESM::MagicEffect::Silence: + { + if (enemy.isEmpty()) + return 0.f; + + const CreatureStats& stats = enemy.getClass().getCreatureStats(enemy); + + // Enemy can't cast spells + if (stats.getMagicEffects().get(ESM::MagicEffect::Paralyze).getMagnitude() > 0) + return 0.f; + + // Enemy doesn't cast spells + if (stats.getDrawState() != MWMechanics::DrawState_Spell) + return 0.f; break; } @@ -353,9 +392,10 @@ namespace MWMechanics int priority = 1; if (effect.mEffectID == ESM::MagicEffect::RestoreHealth) priority = 10; - const DynamicStat& current = actor.getClass().getCreatureStats(actor). - getDynamic(effect.mEffectID - ESM::MagicEffect::RestoreHealth); - float toHeal = (effect.mMagnMin + effect.mMagnMax)/2.f * effect.mDuration; + const MWMechanics::CreatureStats& stats = actor.getClass().getCreatureStats(actor); + const DynamicStat& current = stats.getDynamic(effect.mEffectID - ESM::MagicEffect::RestoreHealth); + const float magnitude = (effect.mMagnMin + effect.mMagnMax)/2.f; + const float toHeal = magnitude * effect.mDuration; // Effect doesn't heal more than we need, *or* we are below 1/2 health if (current.getModified() - current.getCurrent() > toHeal || current.getCurrent() < current.getModified()*0.5) @@ -363,8 +403,8 @@ namespace MWMechanics return 10000.f * priority - (toHeal - (current.getModified()-current.getCurrent())); // prefer the most fitting potion } - else - return -10000.f * priority; // Save for later + + return 0.f; } break; From 533b72eff609dc9cdc3af1de9591dcfc410981eb Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Fri, 31 Aug 2018 00:36:30 +0300 Subject: [PATCH 046/196] Cache weapon type strings --- apps/openmw/mwclass/weapon.cpp | 37 ++++++++++++---------- apps/openmw/mwmechanics/spellpriority.cpp | 4 +-- apps/openmw/mwmechanics/weaponpriority.cpp | 2 +- 3 files changed, 23 insertions(+), 20 deletions(-) diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index 294aebd94..466ae4716 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -268,24 +268,27 @@ namespace MWClass { text += "\n#{sType} "; - std::map > mapping; - mapping[ESM::Weapon::ShortBladeOneHand] = std::make_pair("sSkillShortblade", "sOneHanded"); - mapping[ESM::Weapon::LongBladeOneHand] = std::make_pair("sSkillLongblade", "sOneHanded"); - mapping[ESM::Weapon::LongBladeTwoHand] = std::make_pair("sSkillLongblade", "sTwoHanded"); - mapping[ESM::Weapon::BluntOneHand] = std::make_pair("sSkillBluntweapon", "sOneHanded"); - mapping[ESM::Weapon::BluntTwoClose] = std::make_pair("sSkillBluntweapon", "sTwoHanded"); - mapping[ESM::Weapon::BluntTwoWide] = std::make_pair("sSkillBluntweapon", "sTwoHanded"); - mapping[ESM::Weapon::SpearTwoWide] = std::make_pair("sSkillSpear", "sTwoHanded"); - mapping[ESM::Weapon::AxeOneHand] = std::make_pair("sSkillAxe", "sOneHanded"); - mapping[ESM::Weapon::AxeTwoHand] = std::make_pair("sSkillAxe", "sTwoHanded"); - mapping[ESM::Weapon::MarksmanBow] = std::make_pair("sSkillMarksman", ""); - mapping[ESM::Weapon::MarksmanCrossbow] = std::make_pair("sSkillMarksman", ""); - mapping[ESM::Weapon::MarksmanThrown] = std::make_pair("sSkillMarksman", ""); - mapping[ESM::Weapon::Arrow] = std::make_pair("sSkillMarksman", ""); - mapping[ESM::Weapon::Bolt] = std::make_pair("sSkillMarksman", ""); + static std::map > mapping; + if (mapping.empty()) + { + mapping[ESM::Weapon::ShortBladeOneHand] = std::make_pair("sSkillShortblade", "sOneHanded"); + mapping[ESM::Weapon::LongBladeOneHand] = std::make_pair("sSkillLongblade", "sOneHanded"); + mapping[ESM::Weapon::LongBladeTwoHand] = std::make_pair("sSkillLongblade", "sTwoHanded"); + mapping[ESM::Weapon::BluntOneHand] = std::make_pair("sSkillBluntweapon", "sOneHanded"); + mapping[ESM::Weapon::BluntTwoClose] = std::make_pair("sSkillBluntweapon", "sTwoHanded"); + mapping[ESM::Weapon::BluntTwoWide] = std::make_pair("sSkillBluntweapon", "sTwoHanded"); + mapping[ESM::Weapon::SpearTwoWide] = std::make_pair("sSkillSpear", "sTwoHanded"); + mapping[ESM::Weapon::AxeOneHand] = std::make_pair("sSkillAxe", "sOneHanded"); + mapping[ESM::Weapon::AxeTwoHand] = std::make_pair("sSkillAxe", "sTwoHanded"); + mapping[ESM::Weapon::MarksmanBow] = std::make_pair("sSkillMarksman", ""); + mapping[ESM::Weapon::MarksmanCrossbow] = std::make_pair("sSkillMarksman", ""); + mapping[ESM::Weapon::MarksmanThrown] = std::make_pair("sSkillMarksman", ""); + mapping[ESM::Weapon::Arrow] = std::make_pair("sSkillMarksman", ""); + mapping[ESM::Weapon::Bolt] = std::make_pair("sSkillMarksman", ""); + } - std::string type = mapping[ref->mBase->mData.mType].first; - std::string oneOrTwoHanded = mapping[ref->mBase->mData.mType].second; + const std::string type = mapping[ref->mBase->mData.mType].first; + const std::string oneOrTwoHanded = mapping[ref->mBase->mData.mType].second; text += store.get().find(type)->mValue.getString() + ((oneOrTwoHanded != "") ? ", " + store.get().find(oneOrTwoHanded)->mValue.getString() : ""); diff --git a/apps/openmw/mwmechanics/spellpriority.cpp b/apps/openmw/mwmechanics/spellpriority.cpp index b43756162..f55b30d7c 100644 --- a/apps/openmw/mwmechanics/spellpriority.cpp +++ b/apps/openmw/mwmechanics/spellpriority.cpp @@ -403,8 +403,8 @@ namespace MWMechanics return 10000.f * priority - (toHeal - (current.getModified()-current.getCurrent())); // prefer the most fitting potion } - - return 0.f; + else + return -10000.f * priority; // Save for later } break; diff --git a/apps/openmw/mwmechanics/weaponpriority.cpp b/apps/openmw/mwmechanics/weaponpriority.cpp index 8d09bd8d1..61d348e14 100644 --- a/apps/openmw/mwmechanics/weaponpriority.cpp +++ b/apps/openmw/mwmechanics/weaponpriority.cpp @@ -31,7 +31,7 @@ namespace MWMechanics if (type != -1 && weapon->mData.mType != type) return 0.f; - + const MWBase::World* world = MWBase::Environment::get().getWorld(); const MWWorld::Store& gmst = world->getStore().get(); From fa3e45fa7dfb4a1f2733e8b02b73c6c6aa596623 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Fri, 31 Aug 2018 01:54:59 +0300 Subject: [PATCH 047/196] Slight cleanup --- apps/openmw/mwmechanics/weaponpriority.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwmechanics/weaponpriority.cpp b/apps/openmw/mwmechanics/weaponpriority.cpp index 61d348e14..6b9616359 100644 --- a/apps/openmw/mwmechanics/weaponpriority.cpp +++ b/apps/openmw/mwmechanics/weaponpriority.cpp @@ -100,21 +100,21 @@ namespace MWMechanics if (weapon->mData.mType <= ESM::Weapon::MarksmanThrown) rating *= weapon->mData.mSpeed; + int value = 50.f; if (actor.getClass().isNpc()) { int skill = item.getClass().getEquipmentSkill(item); if (skill != -1) - { - int value = actor.getClass().getSkill(actor, skill); - rating *= getHitChance(actor, enemy, value) / 100.f; - } + value = actor.getClass().getSkill(actor, skill); } else { MWWorld::LiveCellRef *ref = actor.get(); - rating *= getHitChance(actor, enemy, ref->mBase->mData.mCombat) / 100.f; + value = ref->mBase->mData.mCombat; } + rating *= getHitChance(actor, enemy, value) / 100.f; + return rating * rangedMult; } From e66be02e2e2f4a6ebd8fb883e58402aa0bc17cdf Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Fri, 31 Aug 2018 02:06:29 +0300 Subject: [PATCH 048/196] Account for enemy armor rating in weapon rating --- apps/openmw/mwmechanics/weaponpriority.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/weaponpriority.cpp b/apps/openmw/mwmechanics/weaponpriority.cpp index 6b9616359..6861a1b77 100644 --- a/apps/openmw/mwmechanics/weaponpriority.cpp +++ b/apps/openmw/mwmechanics/weaponpriority.cpp @@ -97,8 +97,11 @@ namespace MWMechanics } } - if (weapon->mData.mType <= ESM::Weapon::MarksmanThrown) - rating *= weapon->mData.mSpeed; + if (enemy.getClass().isNpc()) + { + static const float fCombatArmorMinMult = gmst.find("fCombatArmorMinMult")->mValue.getFloat(); + rating *= std::max(fCombatArmorMinMult, rating / (rating + enemy.getClass().getArmorRating(enemy))); + } int value = 50.f; if (actor.getClass().isNpc()) @@ -115,6 +118,9 @@ namespace MWMechanics rating *= getHitChance(actor, enemy, value) / 100.f; + if (weapon->mData.mType <= ESM::Weapon::MarksmanThrown) + rating *= weapon->mData.mSpeed; + return rating * rangedMult; } From 58bd35c70de83a46ffabacf28d7a0cc7c30be142 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Sat, 1 Sep 2018 01:00:18 +0300 Subject: [PATCH 049/196] Update changelog --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6ab7d88d3..f84ccf050 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -136,6 +136,9 @@ Feature #4550: Weapon priority: make ranged weapon bonus more sensible Feature #4579: Add option for applying Strength into hand to hand damage Feature #4581: Use proper logging system + Feature #4624: Spell priority: don't cast hit chance-affecting spells if the enemy is not in respective stance at the moment + Feature #4625: Weapon priority: use weighted mean for melee damage rating + Feature #4626: Weapon priority: account for weapon speed Task #2490: Don't open command prompt window on Release-mode builds automatically Task #4545: Enable is_pod string test Task #4605: Optimize skinning From 2965373ed69c31be87aa3674c5dd035d3d82f53d Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Sat, 1 Sep 2018 01:24:13 +0300 Subject: [PATCH 050/196] Avoid potential zero division --- apps/openmw/mwmechanics/weaponpriority.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/weaponpriority.cpp b/apps/openmw/mwmechanics/weaponpriority.cpp index 6861a1b77..b2a9c8ded 100644 --- a/apps/openmw/mwmechanics/weaponpriority.cpp +++ b/apps/openmw/mwmechanics/weaponpriority.cpp @@ -52,7 +52,10 @@ namespace MWMechanics { static const float fAIMeleeWeaponMult = gmst.find("fAIMeleeWeaponMult")->mValue.getFloat(); static const float fAIRangeMeleeWeaponMult = gmst.find("fAIRangeMeleeWeaponMult")->mValue.getFloat(); - rangedMult = fAIRangeMeleeWeaponMult / fAIMeleeWeaponMult; + if (fAIMeleeWeaponMult != 0) + rangedMult = fAIRangeMeleeWeaponMult / fAIMeleeWeaponMult; + else + rangedMult = fAIRangeMeleeWeaponMult; } } From ceb6121b33536b371f7edfb07d6425761f7c0139 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Sat, 1 Sep 2018 01:44:29 +0300 Subject: [PATCH 051/196] Better checks for enemy incapacitation --- apps/openmw/mwmechanics/spellpriority.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwmechanics/spellpriority.cpp b/apps/openmw/mwmechanics/spellpriority.cpp index f55b30d7c..f9d19ca28 100644 --- a/apps/openmw/mwmechanics/spellpriority.cpp +++ b/apps/openmw/mwmechanics/spellpriority.cpp @@ -240,7 +240,7 @@ namespace MWMechanics const CreatureStats& stats = enemy.getClass().getCreatureStats(enemy); // Enemy can't attack - if (stats.getMagicEffects().get(ESM::MagicEffect::Paralyze).getMagnitude() > 0) + if (stats.isParalyzed() || stats.getKnockedDown()) return 0.f; // Enemy doesn't attack @@ -261,7 +261,7 @@ namespace MWMechanics if (stats.getMagicEffects().get(ESM::MagicEffect::Silence).getMagnitude() > 0) return 0.f; - if (stats.getMagicEffects().get(ESM::MagicEffect::Paralyze).getMagnitude() > 0) + if (stats.isParalyzed() || stats.getKnockedDown()) return 0.f; // Enemy doesn't cast spells @@ -279,7 +279,7 @@ namespace MWMechanics const CreatureStats& stats = enemy.getClass().getCreatureStats(enemy); // Enemy can't cast spells - if (stats.getMagicEffects().get(ESM::MagicEffect::Paralyze).getMagnitude() > 0) + if (stats.isParalyzed() || stats.getKnockedDown()) return 0.f; // Enemy doesn't cast spells From d758b573e2c5adfd25f5b46935944c19736346de Mon Sep 17 00:00:00 2001 From: Capostrophic <21265616+Capostrophic@users.noreply.github.com> Date: Sat, 1 Sep 2018 12:07:26 +0300 Subject: [PATCH 052/196] Fix erroneous assumption that ranged weaponry has speed Restrict speed mult to melee weaponry --- apps/openmw/mwmechanics/weaponpriority.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/weaponpriority.cpp b/apps/openmw/mwmechanics/weaponpriority.cpp index b2a9c8ded..6ce064fe4 100644 --- a/apps/openmw/mwmechanics/weaponpriority.cpp +++ b/apps/openmw/mwmechanics/weaponpriority.cpp @@ -121,7 +121,7 @@ namespace MWMechanics rating *= getHitChance(actor, enemy, value) / 100.f; - if (weapon->mData.mType <= ESM::Weapon::MarksmanThrown) + if (weapon->mData.mType < ESM::Weapon::MarksmanBow) rating *= weapon->mData.mSpeed; return rating * rangedMult; From 7e2bda459b530680887798486caf435198f0f605 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sun, 2 Sep 2018 17:34:01 +0400 Subject: [PATCH 053/196] Check if there are textures in FlipController to avoid division by zero (bug #4614) --- CHANGELOG.md | 1 + components/nifosg/controller.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6ab7d88d3..72a6fa40c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -109,6 +109,7 @@ Bug #4604: Picking up gold from the ground only makes 1 grabbed Bug #4607: Scaling for animated collision shapes is applied twice Bug #4608: Falling damage is applied twice + Bug #4614: Crash due to division by zero when FlipController has no textures Bug #4615: Flicker effects for light sources are handled incorrectly Bug #4617: First person sneaking offset is not applied while the character is in air Bug #4618: Sneaking is possible while the character is flying diff --git a/components/nifosg/controller.cpp b/components/nifosg/controller.cpp index 262966e95..83841e0e5 100644 --- a/components/nifosg/controller.cpp +++ b/components/nifosg/controller.cpp @@ -409,7 +409,7 @@ FlipController::FlipController(const FlipController ©, const osg::CopyOp &co void FlipController::apply(osg::StateSet* stateset, osg::NodeVisitor* nv) { - if (hasInput() && mDelta != 0) + if (hasInput() && mDelta != 0 && !mTextures.empty()) { int curTexture = int(getInputValue(nv) / mDelta) % mTextures.size(); stateset->setTextureAttribute(mTexSlot, mTextures[curTexture]); From 65ff346b619c5121a02f3f065dea0c4f1b1119f7 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Mon, 3 Sep 2018 16:30:21 +0300 Subject: [PATCH 054/196] Make NPC record reputation, disposition and faction rank have unsigned char type --- CHANGELOG.md | 1 + components/esm/loadnpc.hpp | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 72a6fa40c..f964ca327 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -114,6 +114,7 @@ Bug #4617: First person sneaking offset is not applied while the character is in air Bug #4618: Sneaking is possible while the character is flying Bug #4622: Recharging enchanted items with Soul Gems does not award experience if it fails + Bug #4628: NPC record reputation, disposition and faction rank should have unsigned char type Feature #1645: Casting effects from objects Feature #2606: Editor: Implemented (optional) case sensitive global search Feature #3083: Play animation when NPC is casting spell via script diff --git a/components/esm/loadnpc.hpp b/components/esm/loadnpc.hpp index 5f567d999..fbe1dca1f 100644 --- a/components/esm/loadnpc.hpp +++ b/components/esm/loadnpc.hpp @@ -90,7 +90,7 @@ struct NPC char mFactionID; unsigned short mHealth, mMana, mFatigue; - signed char mDisposition, mReputation, mRank; + unsigned char mDisposition, mReputation, mRank; char mUnknown; int mGold; }; // 52 bytes @@ -101,7 +101,7 @@ struct NPC { short mLevel; // see above - signed char mDisposition, mReputation, mRank; + unsigned char mDisposition, mReputation, mRank; char mUnknown1, mUnknown2, mUnknown3; int mGold; }; // 12 bytes From aed7c1b2bbd47d56614ce0cdba66f38b86e6893f Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Tue, 4 Sep 2018 12:37:43 +0400 Subject: [PATCH 055/196] Fix a couple of Clang warnings --- apps/openmw/mwscript/miscextensions.cpp | 8 +++++++- apps/openmw/mwworld/worldimp.hpp | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index 3d1978d62..8d592f29c 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -1064,7 +1064,13 @@ namespace MWScript runtime.pop(); const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get().find (spellId); - if (spell && spell->mData.mType != ESM::Spell::ST_Spell && spell->mData.mType != ESM::Spell::ST_Power) + if (!spell) + { + runtime.getContext().report("spellcasting failed: can not find spell \""+spellId+"\""); + return; + } + + if (spell->mData.mType != ESM::Spell::ST_Spell && spell->mData.mType != ESM::Spell::ST_Power) { runtime.getContext().report("spellcasting failed: you can cast only spells and powers."); return; diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 2f732ef97..536a40468 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -525,7 +525,7 @@ namespace MWWorld /// @note throws an exception when invoked on a teleport door void activateDoor(const MWWorld::Ptr& door, int state) override; - void getActorsStandingOn (const MWWorld::ConstPtr& object, std::vector &actors); ///< get a list of actors standing on \a object + void getActorsStandingOn (const MWWorld::ConstPtr& object, std::vector &actors) override; ///< get a list of actors standing on \a object bool getPlayerStandingOn (const MWWorld::ConstPtr& object) override; ///< @return true if the player is standing on \a object bool getActorStandingOn (const MWWorld::ConstPtr& object) override; ///< @return true if any actor is standing on \a object bool getPlayerCollidingWith(const MWWorld::ConstPtr& object) override; ///< @return true if the player is colliding with \a object From d3defd83fc3f24968c43bfa5b53ab03377869175 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Tue, 4 Sep 2018 12:58:34 +0400 Subject: [PATCH 056/196] Disable C4643 MSVC warning, caused by boost --- CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 678f3e16b..34e1a8f4b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -624,7 +624,7 @@ if (WIN32) # Warnings that aren't enabled normally and don't need to be enabled # They're unneeded and sometimes completely retarded warnings that /Wall enables # Not going to bother commenting them as they tend to warn on every standard library file - 4061 4263 4264 4266 4350 4371 4435 4514 4548 4571 4610 4619 4623 4625 + 4061 4263 4264 4266 4350 4371 4435 4514 4548 4571 4610 4619 4623 4625 4626 4628 4640 4668 4710 4711 4768 4820 4826 4917 4946 5032 5039 5045 # Warnings that are thrown on standard libraries and not OpenMW @@ -643,6 +643,7 @@ if (WIN32) # caused by boost 4191 # 'type cast' : unsafe conversion (1.56, thread_primitives.hpp, normally off) + 4643 # Forward declaring 'X' in namespace std is not permitted by the C++ Standard. (in *_std_fwd.h files) # caused by MyGUI 4275 # non dll-interface class 'std::exception' used as base for dll-interface class 'MyGUI::Exception' From 5693ceca749e91d222667e930d521630dba8b256 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Tue, 4 Sep 2018 17:56:19 +0400 Subject: [PATCH 057/196] Remove redundant declaration --- components/debug/debuglog.hpp | 8 -------- 1 file changed, 8 deletions(-) diff --git a/components/debug/debuglog.hpp b/components/debug/debuglog.hpp index 1ea18aa9b..f4a8e17be 100644 --- a/components/debug/debuglog.hpp +++ b/components/debug/debuglog.hpp @@ -43,14 +43,6 @@ public: return *this; } - template - Log& operator<<(const T& rhs) - { - if (mLevel <= Debug::CurrentDebugLevel) - std::cout << std::forward(rhs); - - return *this; - } ~Log() { From 6529883527b54409ba04b8750f304a1b284471ac Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Tue, 4 Sep 2018 18:14:51 +0400 Subject: [PATCH 058/196] Fix MSVC warning C4389 --- apps/opencs/model/tools/pathgridcheck.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/model/tools/pathgridcheck.cpp b/apps/opencs/model/tools/pathgridcheck.cpp index 6427bb119..c25845885 100644 --- a/apps/opencs/model/tools/pathgridcheck.cpp +++ b/apps/opencs/model/tools/pathgridcheck.cpp @@ -109,7 +109,7 @@ void CSMTools::PathgridCheckStage::perform (int stage, CSMDoc::Messages& message pathgrid.mPoints[i].mY == pathgrid.mPoints[j].mY && pathgrid.mPoints[i].mZ == pathgrid.mPoints[j].mZ) { - std::vector::const_iterator it = find(duplList.begin(), duplList.end(), i); + std::vector::const_iterator it = find(duplList.begin(), duplList.end(), static_cast(i)); if (it == duplList.end()) { std::ostringstream ss; From 9408876b5891a38fbf7757cc9f3d4a48cf5f633f Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Thu, 6 Sep 2018 17:17:30 +0300 Subject: [PATCH 059/196] Utilize AI GMSTs for priority rating (feature #4632) Fix on-target effect rating calculation --- CHANGELOG.md | 1 + apps/openmw/mwmechanics/spellpriority.cpp | 12 +++++++++--- apps/openmw/mwmechanics/weaponpriority.cpp | 12 +++++------- 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 03036e1e4..c11d92900 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -141,6 +141,7 @@ Feature #4624: Spell priority: don't cast hit chance-affecting spells if the enemy is not in respective stance at the moment Feature #4625: Weapon priority: use weighted mean for melee damage rating Feature #4626: Weapon priority: account for weapon speed + Feature #4632: AI priority: utilize vanilla AI GMSTs for priority rating Task #2490: Don't open command prompt window on Release-mode builds automatically Task #4545: Enable is_pod string test Task #4605: Optimize skinning diff --git a/apps/openmw/mwmechanics/spellpriority.cpp b/apps/openmw/mwmechanics/spellpriority.cpp index f9d19ca28..807b56608 100644 --- a/apps/openmw/mwmechanics/spellpriority.cpp +++ b/apps/openmw/mwmechanics/spellpriority.cpp @@ -617,13 +617,19 @@ namespace MWMechanics float rateEffects(const ESM::EffectList &list, const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy) { // NOTE: enemy may be empty + float rating = 0.f; + float ratingMult = 1.f; // NB: this multiplier is applied to the effect rating, not the final rating + + const MWWorld::Store& gmst = MWBase::Environment::get().getWorld()->getStore().get(); + static const float fAIMagicSpellMult = gmst.find("fAIMagicSpellMult")->mValue.getFloat(); + static const float fAIRangeMagicSpellMult = gmst.find("fAIRangeMagicSpellMult")->mValue.getFloat(); + for (std::vector::const_iterator it = list.mList.begin(); it != list.mList.end(); ++it) { - rating += rateEffect(*it, actor, enemy); + ratingMult = (it->mRange == ESM::RT_Target) ? fAIRangeMagicSpellMult : fAIMagicSpellMult; - if (it->mRange == ESM::RT_Target) - rating *= 1.5f; + rating += rateEffect(*it, actor, enemy) * ratingMult; } return rating; } diff --git a/apps/openmw/mwmechanics/weaponpriority.cpp b/apps/openmw/mwmechanics/weaponpriority.cpp index 6ce064fe4..818065ae4 100644 --- a/apps/openmw/mwmechanics/weaponpriority.cpp +++ b/apps/openmw/mwmechanics/weaponpriority.cpp @@ -39,7 +39,8 @@ namespace MWMechanics return 0.f; float rating=0.f; - float rangedMult=1.f; + static const float fAIMeleeWeaponMult = gmst.find("fAIMeleeWeaponMult")->mValue.getFloat(); + float ratingMult = fAIMeleeWeaponMult; if (weapon->mData.mType >= ESM::Weapon::MarksmanBow && weapon->mData.mType <= ESM::Weapon::MarksmanThrown) { @@ -48,14 +49,11 @@ namespace MWMechanics || world->isUnderwater(MWWorld::ConstPtr(enemy), 0.75f)) return 0.f; + // Use a higher rating multiplier if the actor is out of enemy's reach, use the normal mult otherwise if (getDistanceMinusHalfExtents(actor, enemy) >= getMaxAttackDistance(enemy)) { - static const float fAIMeleeWeaponMult = gmst.find("fAIMeleeWeaponMult")->mValue.getFloat(); static const float fAIRangeMeleeWeaponMult = gmst.find("fAIRangeMeleeWeaponMult")->mValue.getFloat(); - if (fAIMeleeWeaponMult != 0) - rangedMult = fAIRangeMeleeWeaponMult / fAIMeleeWeaponMult; - else - rangedMult = fAIRangeMeleeWeaponMult; + ratingMult = fAIRangeMeleeWeaponMult; } } @@ -124,7 +122,7 @@ namespace MWMechanics if (weapon->mData.mType < ESM::Weapon::MarksmanBow) rating *= weapon->mData.mSpeed; - return rating * rangedMult; + return rating * ratingMult; } float rateAmmo(const MWWorld::Ptr &actor, const MWWorld::Ptr &enemy, MWWorld::Ptr &bestAmmo, ESM::Weapon::Type ammoType) From bbcdfd4078275cbb5e3060e5b04645567b2297d3 Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Thu, 6 Sep 2018 21:49:50 +0200 Subject: [PATCH 060/196] Implements vanilla's off-by-one error, fixing #4611 --- apps/openmw/mwgui/spellcreationdialog.cpp | 4 +++- apps/openmw/mwgui/spellcreationdialog.hpp | 1 + apps/openmw/mwmechanics/spellcasting.cpp | 9 ++++++--- apps/openmw/mwmechanics/spellcasting.hpp | 4 ++-- files/settings-default.cfg | 3 +++ 5 files changed, 15 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwgui/spellcreationdialog.cpp b/apps/openmw/mwgui/spellcreationdialog.cpp index 65d66f9e2..bd54d47ee 100644 --- a/apps/openmw/mwgui/spellcreationdialog.cpp +++ b/apps/openmw/mwgui/spellcreationdialog.cpp @@ -449,11 +449,13 @@ namespace MWGui const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); + static const bool vanillaCost = Settings::Manager::getBool("expensive spells", "Game"); + for (std::vector::const_iterator it = mEffects.begin(); it != mEffects.end(); ++it) { const ESM::ENAMstruct& effect = *it; - y += std::max(1.f, MWMechanics::calcEffectCost(effect)); + y += std::max(1.f, MWMechanics::calcEffectCost(effect, vanillaCost)); if (effect.mRange == ESM::RT_Target) y *= 1.5; diff --git a/apps/openmw/mwgui/spellcreationdialog.hpp b/apps/openmw/mwgui/spellcreationdialog.hpp index ec90fa3ce..084c3e1e1 100644 --- a/apps/openmw/mwgui/spellcreationdialog.hpp +++ b/apps/openmw/mwgui/spellcreationdialog.hpp @@ -3,6 +3,7 @@ #include #include +#include #include "windowbase.hpp" #include "referenceinterface.hpp" diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index b857c6d7e..83af249da 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -49,13 +49,13 @@ namespace MWMechanics return schoolSkillMap[school]; } - float calcEffectCost(const ESM::ENAMstruct& effect) + float calcEffectCost(const ESM::ENAMstruct& effect, const bool customSpellCost) { const ESM::MagicEffect* magicEffect = MWBase::Environment::get().getWorld()->getStore().get().find(effect.mEffectID); - return calcEffectCost(effect, magicEffect); + return calcEffectCost(effect, magicEffect, customSpellCost); } - float calcEffectCost(const ESM::ENAMstruct& effect, const ESM::MagicEffect* magicEffect) + float calcEffectCost(const ESM::ENAMstruct& effect, const ESM::MagicEffect* magicEffect, const bool customSpellCost) { int minMagn = 1; int maxMagn = 1; @@ -68,6 +68,9 @@ namespace MWMechanics int duration = 0; if (!(magicEffect->mData.mFlags & ESM::MagicEffect::NoDuration)) duration = effect.mDuration; + //The wonders of vanilla spellmaking + if (customSpellCost && duration < 1) + duration = 1; static const float fEffectCostMult = MWBase::Environment::get().getWorld()->getStore() .get().find("fEffectCostMult")->mValue.getFloat(); diff --git a/apps/openmw/mwmechanics/spellcasting.hpp b/apps/openmw/mwmechanics/spellcasting.hpp index 2844e7f23..836473653 100644 --- a/apps/openmw/mwmechanics/spellcasting.hpp +++ b/apps/openmw/mwmechanics/spellcasting.hpp @@ -25,8 +25,8 @@ namespace MWMechanics ESM::Skill::SkillEnum spellSchoolToSkill(int school); - float calcEffectCost(const ESM::ENAMstruct& effect); - float calcEffectCost(const ESM::ENAMstruct& effect, const ESM::MagicEffect* magicEffect); + float calcEffectCost(const ESM::ENAMstruct& effect, const bool customSpellCost = false); + float calcEffectCost(const ESM::ENAMstruct& effect, const ESM::MagicEffect* magicEffect, const bool customSpellCost = false); bool isSummoningEffect(int effectId); diff --git a/files/settings-default.cfg b/files/settings-default.cfg index c2ac2eb1c..352b86f65 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -229,6 +229,9 @@ barter disposition change is permanent = false # (0 means it does not factor it in, 1 means it factors into werewolves damage calculation and # 2 means werewolves are ignored) strength influences hand to hand = 0 + +# Makes custom spells cost the same as in vanilla +expensive spells = true [General] From 6705e5aae455219e908ffb3870f4c5d1872a5d4f Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Sat, 8 Sep 2018 11:21:43 +0200 Subject: [PATCH 061/196] forget about the setting till #2887 is implemented at least --- apps/openmw/mwgui/spellcreationdialog.cpp | 4 +--- apps/openmw/mwgui/spellcreationdialog.hpp | 1 - apps/openmw/mwmechanics/spellcasting.cpp | 11 ++++------- apps/openmw/mwmechanics/spellcasting.hpp | 4 ++-- files/settings-default.cfg | 5 +---- 5 files changed, 8 insertions(+), 17 deletions(-) diff --git a/apps/openmw/mwgui/spellcreationdialog.cpp b/apps/openmw/mwgui/spellcreationdialog.cpp index bd54d47ee..65d66f9e2 100644 --- a/apps/openmw/mwgui/spellcreationdialog.cpp +++ b/apps/openmw/mwgui/spellcreationdialog.cpp @@ -449,13 +449,11 @@ namespace MWGui const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); - static const bool vanillaCost = Settings::Manager::getBool("expensive spells", "Game"); - for (std::vector::const_iterator it = mEffects.begin(); it != mEffects.end(); ++it) { const ESM::ENAMstruct& effect = *it; - y += std::max(1.f, MWMechanics::calcEffectCost(effect, vanillaCost)); + y += std::max(1.f, MWMechanics::calcEffectCost(effect)); if (effect.mRange == ESM::RT_Target) y *= 1.5; diff --git a/apps/openmw/mwgui/spellcreationdialog.hpp b/apps/openmw/mwgui/spellcreationdialog.hpp index 084c3e1e1..ec90fa3ce 100644 --- a/apps/openmw/mwgui/spellcreationdialog.hpp +++ b/apps/openmw/mwgui/spellcreationdialog.hpp @@ -3,7 +3,6 @@ #include #include -#include #include "windowbase.hpp" #include "referenceinterface.hpp" diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 83af249da..14dfac283 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -49,13 +49,13 @@ namespace MWMechanics return schoolSkillMap[school]; } - float calcEffectCost(const ESM::ENAMstruct& effect, const bool customSpellCost) + float calcEffectCost(const ESM::ENAMstruct& effect) { const ESM::MagicEffect* magicEffect = MWBase::Environment::get().getWorld()->getStore().get().find(effect.mEffectID); - return calcEffectCost(effect, magicEffect, customSpellCost); + return calcEffectCost(effect, magicEffect); } - float calcEffectCost(const ESM::ENAMstruct& effect, const ESM::MagicEffect* magicEffect, const bool customSpellCost) + float calcEffectCost(const ESM::ENAMstruct& effect, const ESM::MagicEffect* magicEffect) { int minMagn = 1; int maxMagn = 1; @@ -65,12 +65,9 @@ namespace MWMechanics maxMagn = effect.mMagnMax; } - int duration = 0; + int duration = 1; if (!(magicEffect->mData.mFlags & ESM::MagicEffect::NoDuration)) duration = effect.mDuration; - //The wonders of vanilla spellmaking - if (customSpellCost && duration < 1) - duration = 1; static const float fEffectCostMult = MWBase::Environment::get().getWorld()->getStore() .get().find("fEffectCostMult")->mValue.getFloat(); diff --git a/apps/openmw/mwmechanics/spellcasting.hpp b/apps/openmw/mwmechanics/spellcasting.hpp index 836473653..2844e7f23 100644 --- a/apps/openmw/mwmechanics/spellcasting.hpp +++ b/apps/openmw/mwmechanics/spellcasting.hpp @@ -25,8 +25,8 @@ namespace MWMechanics ESM::Skill::SkillEnum spellSchoolToSkill(int school); - float calcEffectCost(const ESM::ENAMstruct& effect, const bool customSpellCost = false); - float calcEffectCost(const ESM::ENAMstruct& effect, const ESM::MagicEffect* magicEffect, const bool customSpellCost = false); + float calcEffectCost(const ESM::ENAMstruct& effect); + float calcEffectCost(const ESM::ENAMstruct& effect, const ESM::MagicEffect* magicEffect); bool isSummoningEffect(int effectId); diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 352b86f65..09672aaac 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -228,10 +228,7 @@ barter disposition change is permanent = false # Uses the MCP formula (damage * (strength / 40)) to factor Strength into hand-to-hand combat. # (0 means it does not factor it in, 1 means it factors into werewolves damage calculation and # 2 means werewolves are ignored) -strength influences hand to hand = 0 - -# Makes custom spells cost the same as in vanilla -expensive spells = true +strength influences hand to hand = 0 [General] From d39c4729d205a0dee9285ea72eee389f1dc3eb23 Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Sat, 8 Sep 2018 21:14:47 +0200 Subject: [PATCH 062/196] add changelog entry --- CHANGELOG.md | 1 + files/settings-default.cfg | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c11d92900..4042326d7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -109,6 +109,7 @@ Bug #4604: Picking up gold from the ground only makes 1 grabbed Bug #4607: Scaling for animated collision shapes is applied twice Bug #4608: Falling damage is applied twice + Bug #4611: Instant magic effects have 0 duration in custom spell cost calculations unlike vanilla Bug #4614: Crash due to division by zero when FlipController has no textures Bug #4615: Flicker effects for light sources are handled incorrectly Bug #4617: First person sneaking offset is not applied while the character is in air diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 09672aaac..c2ac2eb1c 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -228,7 +228,7 @@ barter disposition change is permanent = false # Uses the MCP formula (damage * (strength / 40)) to factor Strength into hand-to-hand combat. # (0 means it does not factor it in, 1 means it factors into werewolves damage calculation and # 2 means werewolves are ignored) -strength influences hand to hand = 0 +strength influences hand to hand = 0 [General] From 6ab42919cf3c2dbe75ac8af473fc0ebf8ff5a4d9 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Sat, 8 Sep 2018 22:40:58 +0300 Subject: [PATCH 063/196] Make sure the actor is actually crouching/running before tweaking movement speed --- CHANGELOG.md | 1 + apps/openmw/mwclass/npc.cpp | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c11d92900..28ff0ca93 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -115,6 +115,7 @@ Bug #4618: Sneaking is possible while the character is flying Bug #4622: Recharging enchanted items with Soul Gems does not award experience if it fails Bug #4628: NPC record reputation, disposition and faction rank should have unsigned char type + Bug #4633: Sneaking stance affects speed even if the actor is not able to crouch Feature #1645: Casting effects from objects Feature #2606: Editor: Implemented (optional) case sensitive global search Feature #3083: Play animation when NPC is casting spell via script diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index c247ee543..3d019ea90 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -938,8 +938,8 @@ namespace MWClass const float normalizedEncumbrance = getNormalizedEncumbrance(ptr); - bool sneaking = stats.getStance(MWMechanics::CreatureStats::Stance_Sneak); - bool running = stats.getStance(MWMechanics::CreatureStats::Stance_Run); + bool sneaking = MWBase::Environment::get().getMechanicsManager()->isSneaking(ptr) && stats.getStance(MWMechanics::CreatureStats::Stance_Sneak); + bool running = MWBase::Environment::get().getMechanicsManager()->isRunning(ptr) && stats.getStance(MWMechanics::CreatureStats::Stance_Run); float walkSpeed = gmst.fMinWalkSpeed->mValue.getFloat() + 0.01f*npcdata->mNpcStats.getAttribute(ESM::Attribute::Speed).getModified()* (gmst.fMaxWalkSpeed->mValue.getFloat() - gmst.fMinWalkSpeed->mValue.getFloat()); @@ -964,7 +964,7 @@ namespace MWClass flySpeed = std::max(0.0f, flySpeed); moveSpeed = flySpeed; } - else if(world->isSwimming(ptr)) + else if (world->isSwimming(ptr)) { float swimSpeed = walkSpeed; if(running) @@ -974,7 +974,7 @@ namespace MWClass gmst.fSwimRunAthleticsMult->mValue.getFloat(); moveSpeed = swimSpeed; } - else if(running && !sneaking) + else if (running) moveSpeed = runSpeed; else moveSpeed = walkSpeed; From 702868255a473b2a8b46f78598686e6fe74745ea Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Sun, 9 Sep 2018 13:56:58 +0300 Subject: [PATCH 064/196] Use sTo GMST in spellmaking menu (feature #4636) --- CHANGELOG.md | 1 + apps/openmw/mwgui/spellcreationdialog.cpp | 7 +++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4042326d7..ab0b2a9ec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -143,6 +143,7 @@ Feature #4625: Weapon priority: use weighted mean for melee damage rating Feature #4626: Weapon priority: account for weapon speed Feature #4632: AI priority: utilize vanilla AI GMSTs for priority rating + Feature #4636: Use sTo GMST in spellmaking menu Task #2490: Don't open command prompt window on Release-mode builds automatically Task #4545: Enable is_pod string test Task #4605: Optimize skinning diff --git a/apps/openmw/mwgui/spellcreationdialog.cpp b/apps/openmw/mwgui/spellcreationdialog.cpp index 65d66f9e2..b4713291b 100644 --- a/apps/openmw/mwgui/spellcreationdialog.cpp +++ b/apps/openmw/mwgui/spellcreationdialog.cpp @@ -147,7 +147,9 @@ namespace MWGui mDurationValue->setCaption("1"); mMagnitudeMinValue->setCaption("1"); - mMagnitudeMaxValue->setCaption("- 1"); + static const std::string &to = MWBase::Environment::get().getWindowManager()->getGameSettingString("sTo", "-"); + + mMagnitudeMaxValue->setCaption(to + " 1"); mAreaValue->setCaption("0"); setVisible(true); @@ -312,8 +314,9 @@ namespace MWGui } mEffect.mMagnMax = pos+1; + static const std::string &to = MWBase::Environment::get().getWindowManager()->getGameSettingString("sTo", "-"); - mMagnitudeMaxValue->setCaption("- " + MyGUI::utility::toString(pos+1)); + mMagnitudeMaxValue->setCaption(to + " " + MyGUI::utility::toString(pos+1)); eventEffectModified(mEffect); } From 33a66b778ffa728ac150c475e0fe5355b47ae947 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sun, 9 Sep 2018 23:10:09 +0400 Subject: [PATCH 065/196] Disable repeating for Accept action in keyboard navigation (bug #4260) --- CHANGELOG.md | 1 + apps/openmw/mwbase/windowmanager.hpp | 2 +- apps/openmw/mwgui/keyboardnavigation.cpp | 7 ++++++- apps/openmw/mwgui/keyboardnavigation.hpp | 2 +- apps/openmw/mwgui/windowmanagerimp.cpp | 4 ++-- apps/openmw/mwgui/windowmanagerimp.hpp | 2 +- apps/openmw/mwinput/inputmanagerimp.cpp | 6 +++--- 7 files changed, 15 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c11d92900..c95e45ec4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -45,6 +45,7 @@ Bug #4230: AiTravel package issues break some Tribunal quests Bug #4231: Infected rats from the "Crimson Plague" quest rendered unconscious by change in Drain Fatigue functionality Bug #4251: Stationary NPCs do not return to their position after combat + Bug #4260: Keyboard navigation makes persuasion exploitable Bug #4271: Scamp flickers when attacking Bug #4274: Pre-0.43 death animations are not forward-compatible with 0.43+ Bug #4286: Scripted animations can be interrupted diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 39eed5537..564c66e75 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -350,7 +350,7 @@ namespace MWBase virtual const MWGui::TextColours& getTextColours() = 0; - virtual bool injectKeyPress(MyGUI::KeyCode key, unsigned int text) = 0; + virtual bool injectKeyPress(MyGUI::KeyCode key, unsigned int text, bool repeat) = 0; }; } diff --git a/apps/openmw/mwgui/keyboardnavigation.cpp b/apps/openmw/mwgui/keyboardnavigation.cpp index cde8a17cc..361ab407a 100644 --- a/apps/openmw/mwgui/keyboardnavigation.cpp +++ b/apps/openmw/mwgui/keyboardnavigation.cpp @@ -172,7 +172,7 @@ enum Direction D_Prev }; -bool KeyboardNavigation::injectKeyPress(MyGUI::KeyCode key, unsigned int text) +bool KeyboardNavigation::injectKeyPress(MyGUI::KeyCode key, unsigned int text, bool repeat) { if (!mEnabled) return false; @@ -192,7 +192,12 @@ bool KeyboardNavigation::injectKeyPress(MyGUI::KeyCode key, unsigned int text) case MyGUI::KeyCode::Return: case MyGUI::KeyCode::NumpadEnter: case MyGUI::KeyCode::Space: + { + if (repeat) + return false; + return accept(); + } default: return false; } diff --git a/apps/openmw/mwgui/keyboardnavigation.hpp b/apps/openmw/mwgui/keyboardnavigation.hpp index 7caf25690..2a094a2df 100644 --- a/apps/openmw/mwgui/keyboardnavigation.hpp +++ b/apps/openmw/mwgui/keyboardnavigation.hpp @@ -14,7 +14,7 @@ namespace MWGui ~KeyboardNavigation(); /// @return Was the key handled by this class? - bool injectKeyPress(MyGUI::KeyCode key, unsigned int text); + bool injectKeyPress(MyGUI::KeyCode key, unsigned int text, bool repeat); void saveFocus(int mode); void restoreFocus(int mode); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 45897b88c..6007846fa 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -2060,9 +2060,9 @@ namespace MWGui return mTextColours; } - bool WindowManager::injectKeyPress(MyGUI::KeyCode key, unsigned int text) + bool WindowManager::injectKeyPress(MyGUI::KeyCode key, unsigned int text, bool repeat) { - if (!mKeyboardNavigation->injectKeyPress(key, text)) + if (!mKeyboardNavigation->injectKeyPress(key, text, repeat)) { MyGUI::Widget* focus = MyGUI::InputManager::getInstance().getKeyFocusWidget(); bool widgetActive = MyGUI::InputManager::getInstance().injectKeyPress(key, text); diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 657548397..2e4fb8a02 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -379,7 +379,7 @@ namespace MWGui virtual const MWGui::TextColours& getTextColours(); - virtual bool injectKeyPress(MyGUI::KeyCode key, unsigned int text); + virtual bool injectKeyPress(MyGUI::KeyCode key, unsigned int text, bool repeat=false); private: const MWWorld::ESMStore* mStore; diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index b24c8cc14..b632bf612 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -214,7 +214,7 @@ namespace MWInput break; } - MWBase::Environment::get().getWindowManager()->injectKeyPress(key, 0); + MWBase::Environment::get().getWindowManager()->injectKeyPress(key, 0, false); } void InputManager::channelChanged(ICS::Channel* channel, float currentValue, float previousValue) @@ -720,7 +720,7 @@ namespace MWInput bool consumed = false; if (kc != OIS::KC_UNASSIGNED && !mInputBinder->detectingBindingState()) { - consumed = MWBase::Environment::get().getWindowManager()->injectKeyPress(MyGUI::KeyCode::Enum(kc), 0); + consumed = MWBase::Environment::get().getWindowManager()->injectKeyPress(MyGUI::KeyCode::Enum(kc), 0, arg.repeat); if (SDL_IsTextInputActive() && // Little trick to check if key is printable ( !(SDLK_SCANCODE_MASK & arg.keysym.sym) && std::isprint(arg.keysym.sym))) consumed = true; @@ -1153,7 +1153,7 @@ namespace MWInput if (MWBase::Environment::get().getWindowManager()->isGuiMode()) { if (!SDL_IsTextInputActive() && !isLeftOrRightButton(A_Activate, mInputBinder, mFakeDeviceID, mJoystickLastUsed)) - MWBase::Environment::get().getWindowManager()->injectKeyPress(MyGUI::KeyCode::Return, 0); + MWBase::Environment::get().getWindowManager()->injectKeyPress(MyGUI::KeyCode::Return, 0, false); } else if (mControlSwitch["playercontrols"]) mPlayer->activate(); From 269ef7a5596de88e4586b64c59a2407e6f9776c2 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Mon, 10 Sep 2018 12:55:00 +0400 Subject: [PATCH 066/196] Disable repeating for ENTER key in GUI --- apps/openmw/mwbase/windowmanager.hpp | 1 + apps/openmw/mwgui/alchemywindow.cpp | 3 +++ apps/openmw/mwgui/countdialog.cpp | 4 +++- apps/openmw/mwgui/enchantingdialog.cpp | 3 +++ apps/openmw/mwgui/keyboardnavigation.cpp | 4 +++- apps/openmw/mwgui/savegamedialog.cpp | 3 +++ apps/openmw/mwgui/spellcreationdialog.cpp | 3 +++ apps/openmw/mwgui/textinput.cpp | 3 +++ apps/openmw/mwgui/tradewindow.cpp | 3 +++ apps/openmw/mwgui/windowmanagerimp.cpp | 5 +++++ apps/openmw/mwgui/windowmanagerimp.hpp | 1 + 11 files changed, 31 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 564c66e75..b2b80cca3 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -351,6 +351,7 @@ namespace MWBase virtual const MWGui::TextColours& getTextColours() = 0; virtual bool injectKeyPress(MyGUI::KeyCode key, unsigned int text, bool repeat) = 0; + virtual bool injectKeyRelease(MyGUI::KeyCode key) = 0; }; } diff --git a/apps/openmw/mwgui/alchemywindow.cpp b/apps/openmw/mwgui/alchemywindow.cpp index 80284e9b2..6fd3d3220 100644 --- a/apps/openmw/mwgui/alchemywindow.cpp +++ b/apps/openmw/mwgui/alchemywindow.cpp @@ -65,6 +65,9 @@ namespace MWGui void AlchemyWindow::onAccept(MyGUI::EditBox* sender) { onCreateButtonClicked(sender); + + // To do not spam onAccept() again and again + MWBase::Environment::get().getWindowManager()->injectKeyRelease(MyGUI::KeyCode::None); } void AlchemyWindow::onCancelButtonClicked(MyGUI::Widget* _sender) diff --git a/apps/openmw/mwgui/countdialog.cpp b/apps/openmw/mwgui/countdialog.cpp index cf058caac..4292f2e04 100644 --- a/apps/openmw/mwgui/countdialog.cpp +++ b/apps/openmw/mwgui/countdialog.cpp @@ -73,8 +73,10 @@ namespace MWGui void CountDialog::onEnterKeyPressed(MyGUI::EditBox* _sender) { eventOkClicked(NULL, mSlider->getScrollPosition()+1); - setVisible(false); + + // To do not spam onEnterKeyPressed() again and again + MWBase::Environment::get().getWindowManager()->injectKeyRelease(MyGUI::KeyCode::None); } void CountDialog::onEditValueChanged(int value) diff --git a/apps/openmw/mwgui/enchantingdialog.cpp b/apps/openmw/mwgui/enchantingdialog.cpp index 8fbfa65c6..039377dee 100644 --- a/apps/openmw/mwgui/enchantingdialog.cpp +++ b/apps/openmw/mwgui/enchantingdialog.cpp @@ -288,6 +288,9 @@ namespace MWGui void EnchantingDialog::onAccept(MyGUI::EditBox *sender) { onBuyButtonClicked(sender); + + // To do not spam onAccept() again and again + MWBase::Environment::get().getWindowManager()->injectKeyRelease(MyGUI::KeyCode::None); } void EnchantingDialog::onBuyButtonClicked(MyGUI::Widget* sender) diff --git a/apps/openmw/mwgui/keyboardnavigation.cpp b/apps/openmw/mwgui/keyboardnavigation.cpp index 361ab407a..aaf369aa7 100644 --- a/apps/openmw/mwgui/keyboardnavigation.cpp +++ b/apps/openmw/mwgui/keyboardnavigation.cpp @@ -193,8 +193,10 @@ bool KeyboardNavigation::injectKeyPress(MyGUI::KeyCode key, unsigned int text, b case MyGUI::KeyCode::NumpadEnter: case MyGUI::KeyCode::Space: { + // We should disable repeating for activation keys + MyGUI::InputManager::getInstance().injectKeyRelease(MyGUI::KeyCode::None); if (repeat) - return false; + return true; return accept(); } diff --git a/apps/openmw/mwgui/savegamedialog.cpp b/apps/openmw/mwgui/savegamedialog.cpp index 45790cbf5..3264e5e33 100644 --- a/apps/openmw/mwgui/savegamedialog.cpp +++ b/apps/openmw/mwgui/savegamedialog.cpp @@ -127,6 +127,9 @@ namespace MWGui void SaveGameDialog::onEditSelectAccept(MyGUI::EditBox *sender) { accept(); + + // To do not spam onEditSelectAccept() again and again + MWBase::Environment::get().getWindowManager()->injectKeyRelease(MyGUI::KeyCode::None); } void SaveGameDialog::onOpen() diff --git a/apps/openmw/mwgui/spellcreationdialog.cpp b/apps/openmw/mwgui/spellcreationdialog.cpp index 65d66f9e2..f06f059cd 100644 --- a/apps/openmw/mwgui/spellcreationdialog.cpp +++ b/apps/openmw/mwgui/spellcreationdialog.cpp @@ -420,6 +420,9 @@ namespace MWGui void SpellCreationDialog::onAccept(MyGUI::EditBox *sender) { onBuyButtonClicked(sender); + + // To do not spam onAccept() again and again + MWBase::Environment::get().getWindowManager()->injectKeyRelease(MyGUI::KeyCode::None); } void SpellCreationDialog::onOpen() diff --git a/apps/openmw/mwgui/textinput.cpp b/apps/openmw/mwgui/textinput.cpp index 169c9e742..54f2d3be9 100644 --- a/apps/openmw/mwgui/textinput.cpp +++ b/apps/openmw/mwgui/textinput.cpp @@ -65,6 +65,9 @@ namespace MWGui void TextInputDialog::onTextAccepted(MyGUI::Edit* _sender) { onOkClicked(_sender); + + // To do not spam onTextAccepted() again and again + MWBase::Environment::get().getWindowManager()->injectKeyRelease(MyGUI::KeyCode::None); } std::string TextInputDialog::getTextInput() const diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index 3871baa09..f461d5f50 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -367,6 +367,9 @@ namespace MWGui void TradeWindow::onAccept(MyGUI::EditBox *sender) { onOfferButtonClicked(sender); + + // To do not spam onAccept() again and again + MWBase::Environment::get().getWindowManager()->injectKeyRelease(MyGUI::KeyCode::None); } void TradeWindow::onCancelButtonClicked(MyGUI::Widget* _sender) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 6007846fa..e332f4f62 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -2091,6 +2091,11 @@ namespace MWGui return true; } + bool WindowManager::injectKeyRelease(MyGUI::KeyCode key) + { + return MyGUI::InputManager::getInstance().injectKeyRelease(key); + } + void WindowManager::GuiModeState::update(bool visible) { for (unsigned int i=0; i Date: Mon, 10 Sep 2018 15:18:07 +0400 Subject: [PATCH 067/196] Use drag and drop for ActionTake when InventoryWindow is active (bug #4543) --- CHANGELOG.md | 1 + apps/openmw/mwworld/actiontake.cpp | 13 +++++++++++++ 2 files changed, 14 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c11d92900..7034202e2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -92,6 +92,7 @@ Bug #4519: Knockdown does not discard movement in the 1st-person mode Bug #4531: Movement does not reset idle animations Bug #4539: Paper Doll is affected by GUI scaling + Bug #4543: Picking cursed items through inventory (menumode) makes it disappear Bug #4545: Creatures flee from werewolves Bug #4551: Replace 0 sound range with default range separately Bug #4553: Forcegreeting on non-actor opens a dialogue window which cannot be closed diff --git a/apps/openmw/mwworld/actiontake.cpp b/apps/openmw/mwworld/actiontake.cpp index d858859a6..a173e87fb 100644 --- a/apps/openmw/mwworld/actiontake.cpp +++ b/apps/openmw/mwworld/actiontake.cpp @@ -5,6 +5,8 @@ #include "../mwbase/windowmanager.hpp" #include "../mwbase/mechanicsmanager.hpp" +#include "../mwgui/inventorywindow.hpp" + #include "class.hpp" #include "containerstore.hpp" @@ -14,6 +16,17 @@ namespace MWWorld void ActionTake::executeImp (const Ptr& actor) { + // When in GUI mode, we should use drag and drop + if (actor == MWBase::Environment::get().getWorld()->getPlayerPtr()) + { + MWGui::GuiMode mode = MWBase::Environment::get().getWindowManager()->getMode(); + if (mode == MWGui::GM_Inventory || mode == MWGui::GM_Container) + { + MWBase::Environment::get().getWindowManager()->getInventoryWindow()->pickUpObject(getTarget()); + return; + } + } + MWBase::Environment::get().getMechanicsManager()->itemTaken( actor, getTarget(), MWWorld::Ptr(), getTarget().getRefData().getCount()); MWWorld::Ptr newitem = *actor.getClass().getContainerStore (actor).add (getTarget(), getTarget().getRefData().getCount(), actor); From e5a81b1f99bb6e23fb633c3fb03cb5145ba352aa Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sat, 8 Sep 2018 18:17:11 +0400 Subject: [PATCH 068/196] Fix some issues, found by Coverity Scan --- apps/openmw/mwmechanics/character.cpp | 4 +++- apps/openmw/mwrender/animation.cpp | 1 + apps/openmw/mwworld/worldimp.cpp | 12 +++++++++--- components/debug/debugging.hpp | 2 -- 4 files changed, 13 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index fddd351fa..69916b37a 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -2145,9 +2145,11 @@ void CharacterController::update(float duration) if (isTurning()) { // Adjust animation speed from 1.0 to 1.5 multiplier - float turnSpeed = std::min(1.5f, std::abs(rot.z()) / duration / static_cast(osg::PI)); if (duration > 0) + { + float turnSpeed = std::min(1.5f, std::abs(rot.z()) / duration / static_cast(osg::PI)); mAnimation->adjustSpeedMult(mCurrentMovement, std::max(turnSpeed, 1.0f)); + } } else if (mMovementState != CharState_None && mAdjustMovementAnimSpeed) { diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 1ace2f8b4..7410dbf03 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -219,6 +219,7 @@ namespace RemoveFinishedCallbackVisitor(int effectId) : RemoveVisitor() + , mHasMagicEffects(false) , mEffectId(effectId) { } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 48cb1dda3..9e08a2563 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1159,11 +1159,17 @@ namespace MWWorld osg::Vec3f vec(x, y, z); - CellStore *currCell = ptr.isInCell() ? ptr.getCell() : NULL; // currCell == NULL should only happen for player, during initial startup + CellStore *currCell = ptr.isInCell() ? ptr.getCell() : nullptr; // currCell == nullptr should only happen for player, during initial startup bool isPlayer = ptr == mPlayer->getPlayer(); bool haveToMove = isPlayer || (currCell && mWorldScene->isCellActive(*currCell)); MWWorld::Ptr newPtr = ptr; + if (!isPlayer && !currCell) + throw std::runtime_error("Can not move actor \"" + ptr.getCellRef().getRefId() + "\" to another cell: current cell is nullptr"); + + if (!newCell) + throw std::runtime_error("Can not move actor \"" + ptr.getCellRef().getRefId() + "\" to another cell: new cell is nullptr"); + if (currCell != newCell) { removeContainerScripts(ptr); @@ -1185,10 +1191,10 @@ namespace MWWorld addContainerScripts (getPlayerPtr(), newCell); newPtr = getPlayerPtr(); } - else if (currCell) + else { bool currCellActive = mWorldScene->isCellActive(*currCell); - bool newCellActive = newCell && mWorldScene->isCellActive(*newCell); + bool newCellActive = mWorldScene->isCellActive(*newCell); if (!currCellActive && newCellActive) { newPtr = currCell->moveTo(ptr, newCell); diff --git a/components/debug/debugging.hpp b/components/debug/debugging.hpp index 59536d685..f47f58e45 100644 --- a/components/debug/debugging.hpp +++ b/components/debug/debugging.hpp @@ -41,8 +41,6 @@ namespace Debug { return size; } - - char mDebugLevel; }; #if defined(_WIN32) && defined(_DEBUG) From d5bcc49079c6b4d229f403816bbacb1ddce9a64d Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sat, 8 Sep 2018 19:54:22 +0400 Subject: [PATCH 069/196] Initialize missing struct fields --- apps/essimporter/converter.hpp | 5 ++++- apps/essimporter/importgame.hpp | 14 +++++++------- apps/openmw/mwsound/openal_output.cpp | 3 ++- apps/openmw/mwsound/openal_output.hpp | 4 ++-- components/esm/loadcell.hpp | 8 ++++---- 5 files changed, 19 insertions(+), 15 deletions(-) diff --git a/apps/essimporter/converter.hpp b/apps/essimporter/converter.hpp index 1772e0e2d..2694ea570 100644 --- a/apps/essimporter/converter.hpp +++ b/apps/essimporter/converter.hpp @@ -526,7 +526,10 @@ public: class ConvertGAME : public Converter { public: - ConvertGAME() : mHasGame(false) {} + ConvertGAME() + : mHasGame(false) + { + } virtual void read(ESM::ESMReader &esm) { diff --git a/apps/essimporter/importgame.hpp b/apps/essimporter/importgame.hpp index fca7d72a0..d8051a527 100644 --- a/apps/essimporter/importgame.hpp +++ b/apps/essimporter/importgame.hpp @@ -14,13 +14,13 @@ namespace ESSImport { struct GMDT { - char mCellName[64]; - int mFogColour; - float mFogDensity; - int mCurrentWeather, mNextWeather; - int mWeatherTransition; // 0-100 transition between weathers, top 3 bytes may be garbage - float mTimeOfNextTransition; // weather changes when gamehour == timeOfNextTransition - int mMasserPhase, mSecundaPhase; // top 3 bytes may be garbage + char mCellName[64] {}; + int mFogColour {0}; + float mFogDensity {0.f}; + int mCurrentWeather {0}, mNextWeather {0}; + int mWeatherTransition {0}; // 0-100 transition between weathers, top 3 bytes may be garbage + float mTimeOfNextTransition {0.f}; // weather changes when gamehour == timeOfNextTransition + int mMasserPhase {0}, mSecundaPhase {0}; // top 3 bytes may be garbage }; GMDT mGMDT; diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index 42dd6b5fd..833b40e38 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -1483,7 +1483,8 @@ void OpenAL_Output::resumeSounds(int types) OpenAL_Output::OpenAL_Output(SoundManager &mgr) - : Sound_Output(mgr), mDevice(0), mContext(0) + : Sound_Output(mgr) + , mDevice(0), mContext(0) , mListenerPos(0.0f, 0.0f, 0.0f), mListenerEnv(Env_Normal) , mWaterFilter(0), mWaterEffect(0), mDefaultEffect(0), mEffectSlot(0) , mStreamThread(new StreamThread) diff --git a/apps/openmw/mwsound/openal_output.hpp b/apps/openmw/mwsound/openal_output.hpp index afc869733..b6a26c99a 100644 --- a/apps/openmw/mwsound/openal_output.hpp +++ b/apps/openmw/mwsound/openal_output.hpp @@ -26,10 +26,10 @@ namespace MWSound struct { bool EXT_EFX : 1; bool SOFT_HRTF : 1; - } ALC; + } ALC = {false, false}; struct { bool SOFT_source_spatialize : 1; - } AL; + } AL = {false}; typedef std::deque IDDq; IDDq mFreeSources; diff --git a/components/esm/loadcell.hpp b/components/esm/loadcell.hpp index 249d812b1..bc5016718 100644 --- a/components/esm/loadcell.hpp +++ b/components/esm/loadcell.hpp @@ -78,14 +78,14 @@ struct Cell struct DATAstruct { - int mFlags; - int mX, mY; + int mFlags {0}; + int mX {0}, mY {0}; }; struct AMBIstruct { - Color mAmbient, mSunlight, mFog; - float mFogDensity; + Color mAmbient {0}, mSunlight {0}, mFog {0}; + float mFogDensity {0.f}; }; Cell() : mName(""), From a262e4b342a5c751311653c7a28950c4ae3472bb Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sat, 8 Sep 2018 20:20:41 +0400 Subject: [PATCH 070/196] Print warning, if can not close or remove temporary file --- components/crashcatcher/crashcatcher.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/components/crashcatcher/crashcatcher.cpp b/components/crashcatcher/crashcatcher.cpp index 04b239a7f..64824b6b3 100644 --- a/components/crashcatcher/crashcatcher.cpp +++ b/components/crashcatcher/crashcatcher.cpp @@ -175,17 +175,18 @@ static void gdb_info(pid_t pid) fflush(stdout); /* Clean up */ - remove(respfile); + if (remove(respfile) != 0) + Log(Debug::Warning) << "Warning: can not remove file '" << respfile << "': " << std::strerror(errno); } else { /* Error creating temp file */ if(fd >= 0) { - if (close(fd) == 0) - remove(respfile); - else - Log(Debug::Warning) << "Warning: can not close and remove file '" << respfile << "': " << std::strerror(errno); + if (close(fd) != 0) + Log(Debug::Warning) << "Warning: can not close file '" << respfile << "': " << std::strerror(errno); + else if (remove(respfile) != 0) + Log(Debug::Warning) << "Warning: can not remove file '" << respfile << "': " << std::strerror(errno); } printf("!!! Could not create gdb command file\n"); } From aca6625af41957d4624944f15d2cf714b2bbde0d Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sat, 8 Sep 2018 23:04:42 +0400 Subject: [PATCH 071/196] Avoid possible memory leak by using the unique_ptr --- components/files/constrainedfilestream.cpp | 15 +++++---------- components/files/constrainedfilestream.hpp | 8 +++++--- 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/components/files/constrainedfilestream.cpp b/components/files/constrainedfilestream.cpp index b239ec6a1..419af0d6c 100644 --- a/components/files/constrainedfilestream.cpp +++ b/components/files/constrainedfilestream.cpp @@ -103,21 +103,16 @@ namespace Files }; - ConstrainedFileStream::ConstrainedFileStream(const char *filename, size_t start, size_t length) - : std::istream(new ConstrainedFileStreamBuf(filename, start, length)) + ConstrainedFileStream::ConstrainedFileStream(std::unique_ptr buf) + : std::istream(buf.get()) + , mBuf(std::move(buf)) { - } - ConstrainedFileStream::~ConstrainedFileStream() - { - delete rdbuf(); - } - - IStreamPtr openConstrainedFileStream(const char *filename, size_t start, size_t length) { - return IStreamPtr(new ConstrainedFileStream(filename, start, length)); + auto buf = std::unique_ptr(new ConstrainedFileStreamBuf(filename, start, length)); + return IStreamPtr(new ConstrainedFileStream(std::move(buf))); } } diff --git a/components/files/constrainedfilestream.hpp b/components/files/constrainedfilestream.hpp index 05ae0fbec..bf67c7b97 100644 --- a/components/files/constrainedfilestream.hpp +++ b/components/files/constrainedfilestream.hpp @@ -11,9 +11,11 @@ namespace Files class ConstrainedFileStream : public std::istream { public: - ConstrainedFileStream(const char *filename, - size_t start=0, size_t length=0xFFFFFFFF); - virtual ~ConstrainedFileStream(); + ConstrainedFileStream(std::unique_ptr buf); + virtual ~ConstrainedFileStream() {}; + +private: + std::unique_ptr mBuf; }; typedef std::shared_ptr IStreamPtr; From c2c24a76a4914af9c5a857368fcc64df6d486e68 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sun, 9 Sep 2018 16:06:25 +0400 Subject: [PATCH 072/196] Handle MyGUI exceptions inside destructors --- apps/openmw/mwgui/keyboardnavigation.cpp | 11 ++++- apps/openmw/mwgui/layout.hpp | 14 ++++++- apps/openmw/mwgui/screenfader.cpp | 9 ++++- apps/openmw/mwgui/windowmanagerimp.cpp | 51 ++++++++++++++---------- components/fontloader/fontloader.cpp | 12 +++++- 5 files changed, 71 insertions(+), 26 deletions(-) diff --git a/apps/openmw/mwgui/keyboardnavigation.cpp b/apps/openmw/mwgui/keyboardnavigation.cpp index cde8a17cc..96970b39f 100644 --- a/apps/openmw/mwgui/keyboardnavigation.cpp +++ b/apps/openmw/mwgui/keyboardnavigation.cpp @@ -6,6 +6,8 @@ #include #include +#include + #include "../mwbase/windowmanager.hpp" #include "../mwbase/environment.hpp" @@ -49,7 +51,14 @@ KeyboardNavigation::KeyboardNavigation() KeyboardNavigation::~KeyboardNavigation() { - MyGUI::WidgetManager::getInstance().unregisterUnlinker(this); + try + { + MyGUI::WidgetManager::getInstance().unregisterUnlinker(this); + } + catch(const MyGUI::Exception& e) + { + Log(Debug::Error) << "Error in the destructor: " << e.what(); + } } void KeyboardNavigation::saveFocus(int mode) diff --git a/apps/openmw/mwgui/layout.hpp b/apps/openmw/mwgui/layout.hpp index 0e7cf3faa..ea51bf541 100644 --- a/apps/openmw/mwgui/layout.hpp +++ b/apps/openmw/mwgui/layout.hpp @@ -5,6 +5,8 @@ #include #include +#include + namespace MWGui { /** The Layout class is an utility class used to load MyGUI layouts @@ -16,7 +18,17 @@ namespace MWGui Layout(const std::string & _layout, MyGUI::Widget* _parent = nullptr) : mMainWidget(nullptr) { initialise(_layout, _parent); } - virtual ~Layout() { shutdown(); } + virtual ~Layout() + { + try + { + shutdown(); + } + catch(const MyGUI::Exception& e) + { + Log(Debug::Error) << "Error in the destructor: " << e.what(); + } + } MyGUI::Widget* getWidget(const std::string& _name); diff --git a/apps/openmw/mwgui/screenfader.cpp b/apps/openmw/mwgui/screenfader.cpp index 9a9a1ae01..e75e4954e 100644 --- a/apps/openmw/mwgui/screenfader.cpp +++ b/apps/openmw/mwgui/screenfader.cpp @@ -99,7 +99,14 @@ namespace MWGui ScreenFader::~ScreenFader() { - MyGUI::Gui::getInstance().eventFrameStart -= MyGUI::newDelegate(this, &ScreenFader::onFrameStart); + try + { + MyGUI::Gui::getInstance().eventFrameStart -= MyGUI::newDelegate(this, &ScreenFader::onFrameStart); + } + catch(const MyGUI::Exception& e) + { + Log(Debug::Error) << "Error in the destructor: " << e.what(); + } } void ScreenFader::onFrameStart(float dt) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 45897b88c..6917e2e8a 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -518,35 +518,42 @@ namespace MWGui WindowManager::~WindowManager() { - mKeyboardNavigation.reset(); + try + { + mKeyboardNavigation.reset(); - MyGUI::LanguageManager::getInstance().eventRequestTag.clear(); - MyGUI::PointerManager::getInstance().eventChangeMousePointer.clear(); - MyGUI::InputManager::getInstance().eventChangeKeyFocus.clear(); - MyGUI::ClipboardManager::getInstance().eventClipboardChanged.clear(); - MyGUI::ClipboardManager::getInstance().eventClipboardRequested.clear(); + MyGUI::LanguageManager::getInstance().eventRequestTag.clear(); + MyGUI::PointerManager::getInstance().eventChangeMousePointer.clear(); + MyGUI::InputManager::getInstance().eventChangeKeyFocus.clear(); + MyGUI::ClipboardManager::getInstance().eventClipboardChanged.clear(); + MyGUI::ClipboardManager::getInstance().eventClipboardRequested.clear(); - for (WindowBase* window : mWindows) - delete window; - mWindows.clear(); + for (WindowBase* window : mWindows) + delete window; + mWindows.clear(); - delete mMessageBoxManager; - delete mLocalMapRender; - delete mCharGen; - delete mDragAndDrop; - delete mSoulgemDialog; - delete mCursorManager; - delete mToolTips; + delete mMessageBoxManager; + delete mLocalMapRender; + delete mCharGen; + delete mDragAndDrop; + delete mSoulgemDialog; + delete mCursorManager; + delete mToolTips; - cleanupGarbage(); + cleanupGarbage(); - mFontLoader.reset(); + mFontLoader.reset(); - mGui->shutdown(); - delete mGui; + mGui->shutdown(); + delete mGui; - mGuiPlatform->shutdown(); - delete mGuiPlatform; + mGuiPlatform->shutdown(); + delete mGuiPlatform; + } + catch(const MyGUI::Exception& e) + { + Log(Debug::Error) << "Error in the destructor: " << e.what(); + } } void WindowManager::setStore(const MWWorld::ESMStore &store) diff --git a/components/fontloader/fontloader.cpp b/components/fontloader/fontloader.cpp index 790df7fa8..37214a038 100644 --- a/components/fontloader/fontloader.cpp +++ b/components/fontloader/fontloader.cpp @@ -161,7 +161,17 @@ namespace Gui mTextures.clear(); for (std::vector::iterator it = mFonts.begin(); it != mFonts.end(); ++it) - MyGUI::ResourceManager::getInstance().removeByName((*it)->getResourceName()); + { + try + { + MyGUI::ResourceManager::getInstance().removeByName((*it)->getResourceName()); + } + catch(const MyGUI::Exception& e) + { + Log(Debug::Error) << "Error in the destructor: " << e.what(); + } + } + mFonts.clear(); } From 9918212a1e4f974f243e41c0026f67bbddf8b84e Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Mon, 10 Sep 2018 10:51:36 +0400 Subject: [PATCH 073/196] Set focus to Close button when opening the container window (bug #4333) --- CHANGELOG.md | 1 + apps/openmw/mwgui/container.cpp | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c11d92900..105ec9f82 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -54,6 +54,7 @@ Bug #4307: World cleanup should remove dead bodies only if death animation is finished Bug #4311: OpenMW does not handle RootCollisionNode correctly Bug #4327: Missing animations during spell/weapon stance switching + Bug #4333: Keyboard navigation in containers is not intuitive Bug #4358: Running animation is interrupted when magic mode is toggled Bug #4368: Settings window ok button doesn't have key focus by default Bug #4378: On-self absorb spells restore stats diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 703ba309e..99d0ea0d1 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -174,6 +174,8 @@ namespace MWGui if(mDragAndDrop != NULL && mDragAndDrop->mIsOnDragAndDrop) return; + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mCloseButton); + // transfer everything into the player's inventory ItemModel* playerModel = MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getModel(); mModel->update(); @@ -219,6 +221,8 @@ namespace MWGui { if(mDragAndDrop == NULL || !mDragAndDrop->mIsOnDragAndDrop) { + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mCloseButton); + onTakeAllButtonClicked(mTakeButton); if (mPtr.getClass().isPersistent(mPtr)) From f0919f51e93e7dd6811074c63188563c2b88bdaa Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Tue, 11 Sep 2018 14:05:44 +0400 Subject: [PATCH 074/196] Fix integer result formatting of scripting functions --- components/compiler/lineparser.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/compiler/lineparser.cpp b/components/compiler/lineparser.cpp index 602bb826f..c2c1dff9b 100644 --- a/components/compiler/lineparser.cpp +++ b/components/compiler/lineparser.cpp @@ -38,7 +38,7 @@ namespace Compiler { case 'l': - Generator::report (mCode, mLiterals, "%g"); + Generator::report (mCode, mLiterals, "%d"); break; case 'f': From 0440c11ccd0dbf9e12fa67805acb595f8beaa883 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Mon, 20 Aug 2018 17:31:56 +0400 Subject: [PATCH 075/196] Fix swim crossbow animations --- apps/openmw/mwmechanics/character.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index fddd351fa..b17b8b20c 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -423,6 +423,7 @@ void CharacterController::refreshMovementAnims(const WeaponInfo* weap, Character movementAnimName = weap->shortgroup + movementAnimName; else movementAnimName += weap->shortgroup; + if(!mAnimation->hasAnimation(movementAnimName)) { movemask = MWRender::Animation::BlendMask_LowerBody; @@ -451,6 +452,10 @@ void CharacterController::refreshMovementAnims(const WeaponInfo* weap, Character } else { + // For crossbow animations use 1h ones as fallback + if (mWeaponType == WeapType_Crossbow) + movementAnimName += "1h"; + movementAnimName.erase(swimpos, 4); if (weap != sWeaponTypeListEnd) { From 929d78d6a3195fb826e90acf670ea2198efc11c6 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Mon, 20 Aug 2018 21:52:05 +0400 Subject: [PATCH 076/196] Randomize attacks for non-bipedal creatures with Weapon flag --- apps/openmw/mwmechanics/character.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index b17b8b20c..f6b6a93e6 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1399,6 +1399,14 @@ bool CharacterController::updateWeaponState() MWBase::Environment::get().getWorld()->breakInvisibility(mPtr); mAttackStrength = 0; + // Randomize attacks for non-bipedal creatures with Weapon flag + if (mPtr.getClass().getTypeName() == typeid(ESM::Creature).name() && + !mPtr.getClass().isBipedal(mPtr) && + (!mAnimation->hasAnimation(mCurrentWeapon) || isRandomAttackAnimation(mCurrentWeapon))) + { + mCurrentWeapon = chooseRandomAttackAnimation(); + } + if(mWeaponType == WeapType_Spell) { // Unset casting flag, otherwise pressing the mouse button down would From 0136f0552bebf7773a4a1f9d82a37c357060d38e Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Mon, 20 Aug 2018 22:04:02 +0400 Subject: [PATCH 077/196] Do not update mIdleState directly --- apps/openmw/mwmechanics/character.cpp | 118 ++++++++++++++++---------- apps/openmw/mwmechanics/character.hpp | 8 +- 2 files changed, 78 insertions(+), 48 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index f6b6a93e6..6b689deaa 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -243,7 +243,7 @@ std::string CharacterController::chooseRandomGroup (const std::string& prefix, i return prefix + toString(roll); } -void CharacterController::refreshHitRecoilAnims() +void CharacterController::refreshHitRecoilAnims(CharacterState& idle) { bool recovery = mPtr.getClass().getCreatureStats(mPtr).getHitRecovery(); bool knockdown = mPtr.getClass().getCreatureStats(mPtr).getKnockedDown(); @@ -348,14 +348,16 @@ void CharacterController::refreshHitRecoilAnims() mAnimation->play(mCurrentHit, Priority_Knockdown, MWRender::Animation::BlendMask_All, true, 1, "loop stop", "stop", 0.0f, 0); } if (mHitState != CharState_None) - mIdleState = CharState_None; + idle = CharState_None; } -void CharacterController::refreshJumpAnims(const WeaponInfo* weap, JumpingState jump, bool force) +void CharacterController::refreshJumpAnims(const WeaponInfo* weap, JumpingState jump, CharacterState& idle, bool force) { if(force || jump != mJumpState) { - mIdleState = CharState_None; + if (jump != JumpState_None) + idle = CharState_None; + bool startAtLoop = (jump == mJumpState); mJumpState = jump; @@ -372,6 +374,11 @@ void CharacterController::refreshJumpAnims(const WeaponInfo* weap, JumpingState jumpmask = MWRender::Animation::BlendMask_LowerBody; jumpAnimName = "jump"; + // Since we apply movement only for lower body, do not reset idle animations. + // For upper body there will be idle animation. + if (idle == CharState_None) + idle = CharState_Idle; + // For crossbow animations use 1h ones as fallback if (mWeaponType == WeapType_Crossbow) jumpAnimName += "1h"; @@ -406,20 +413,21 @@ void CharacterController::refreshJumpAnims(const WeaponInfo* weap, JumpingState } } -void CharacterController::refreshMovementAnims(const WeaponInfo* weap, CharacterState movement, bool force) +void CharacterController::refreshMovementAnims(const WeaponInfo* weap, CharacterState movement, CharacterState& idle, bool force) { - if(force || movement != mMovementState) + std::string movementAnimName; + MWRender::Animation::BlendMask movemask; + const StateInfo *movestate; + if(force || movement != mMovementState || idle != mIdleState) { - mMovementState = movement; - std::string movementAnimName; - MWRender::Animation::BlendMask movemask = MWRender::Animation::BlendMask_All; - const StateInfo *movestate = std::find_if(sMovementList, sMovementListEnd, FindCharState(mMovementState)); + movemask = MWRender::Animation::BlendMask_All; + movestate = std::find_if(sMovementList, sMovementListEnd, FindCharState(movement)); if(movestate != sMovementListEnd) { movementAnimName = movestate->groupname; if(weap != sWeaponTypeListEnd && movementAnimName.find("swim") == std::string::npos) { - if (mWeaponType == WeapType_Spell && (mMovementState == CharState_TurnLeft || mMovementState == CharState_TurnRight)) // Spellcasting stance turning is a special case + if (mWeaponType == WeapType_Spell && (movement == CharState_TurnLeft || movement == CharState_TurnRight)) // Spellcasting stance turning is a special case movementAnimName = weap->shortgroup + movementAnimName; else movementAnimName += weap->shortgroup; @@ -429,12 +437,24 @@ void CharacterController::refreshMovementAnims(const WeaponInfo* weap, Character movemask = MWRender::Animation::BlendMask_LowerBody; movementAnimName = movestate->groupname; + // Since we apply movement only for lower body, do not reset idle animations. + // For upper body there will be idle animation. + if (idle == CharState_None) + idle = CharState_Idle; + // For crossbow animations use 1h ones as fallback if (mWeaponType == WeapType_Crossbow) movementAnimName += "1h"; } } + } + } + if(force || movement != mMovementState) + { + mMovementState = movement; + if(movestate != sMovementListEnd) + { if(!mAnimation->hasAnimation(movementAnimName)) { std::string::size_type swimpos = movementAnimName.find("swim"); @@ -532,7 +552,15 @@ void CharacterController::refreshMovementAnims(const WeaponInfo* weap, Character void CharacterController::refreshIdleAnims(const WeaponInfo* weap, CharacterState idle, bool force) { - if(force || idle != mIdleState || mIdleState == CharState_None || (!mAnimation->isPlaying(mCurrentIdle) && mAnimQueue.empty())) + // FIXME: if one of the below states is close to their last animation frame (i.e. will be disabled in the coming update), + // the idle animation should be displayed + if (((mUpperBodyState != UpperCharState_Nothing && mUpperBodyState != UpperCharState_WeapEquiped) + || (mMovementState != CharState_None && !isTurning()) + || mHitState != CharState_None) + && !mPtr.getClass().isBipedal(mPtr)) + idle = CharState_None; + + if(force || idle != mIdleState || (!mAnimation->isPlaying(mCurrentIdle) && mAnimQueue.empty())) { mIdleState = idle; size_t numLoops = ~0ul; @@ -591,24 +619,16 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat return; if (mPtr.getClass().isActor()) - refreshHitRecoilAnims(); + refreshHitRecoilAnims(idle); const WeaponInfo *weap = std::find_if(sWeaponTypeList, sWeaponTypeListEnd, FindWeaponType(mWeaponType)); if (!mPtr.getClass().hasInventoryStore(mPtr)) weap = sWeaponTypeListEnd; - refreshJumpAnims(weap, jump, force); - refreshMovementAnims(weap, movement, force); + refreshJumpAnims(weap, jump, idle, force); + refreshMovementAnims(weap, movement, idle, force); // idle handled last as it can depend on the other states - // FIXME: if one of the below states is close to their last animation frame (i.e. will be disabled in the coming update), - // the idle animation should be displayed - if (((mUpperBodyState != UpperCharState_Nothing && mUpperBodyState != UpperCharState_WeapEquiped) - || (mMovementState != CharState_None && !isTurning()) - || mHitState != CharState_None) - && !mPtr.getClass().isBipedal(mPtr)) - idle = CharState_None; - refreshIdleAnims(weap, idle, force); } @@ -1200,7 +1220,7 @@ bool CharacterController::updateCarriedLeftVisible(WeaponType weaptype) const } } -bool CharacterController::updateWeaponState() +bool CharacterController::updateWeaponState(CharacterState& idle) { const MWWorld::Class &cls = mPtr.getClass(); CreatureStats &stats = cls.getCreatureStats(mPtr); @@ -1570,11 +1590,11 @@ bool CharacterController::updateWeaponState() // We should reset player's idle animation in the first-person mode. if (resetIdle && mPtr == player && MWBase::Environment::get().getWorld()->isFirstPerson()) - mIdleState = CharState_None; + idle = CharState_None; // In other cases we should not break swim and sneak animations if (resetIdle && mIdleState != CharState_IdleSneak && mIdleState != CharState_IdleSwim) - mIdleState = CharState_None; + idle = CharState_None; animPlaying = mAnimation->getInfo(mCurrentWeapon, &complete); if(mUpperBodyState == UpperCharState_MinAttackToMaxAttack && !isKnockedDown()) @@ -2085,12 +2105,18 @@ void CharacterController::update(float duration) : (sneak ? CharState_SneakBack : (isrunning ? CharState_RunBack : CharState_WalkBack))); } - else if(rot.z() != 0.0f && !sneak && !(mPtr == getPlayer() && MWBase::Environment::get().getWorld()->isFirstPerson())) + else if(rot.z() != 0.0f) { - if(rot.z() > rotationThreshold) - movestate = inwater ? CharState_SwimTurnRight : CharState_TurnRight; - else if(rot.z() < -rotationThreshold) - movestate = inwater ? CharState_SwimTurnLeft : CharState_TurnLeft; + // It seems only bipedal actors use turning animations. + // Also do not use turning animations in the first-person view and when sneaking. + bool isFirstPlayer = mPtr == getPlayer() && MWBase::Environment::get().getWorld()->isFirstPerson(); + if (!sneak && !isFirstPlayer && mPtr.getClass().isBipedal(mPtr)) + { + if(rot.z() > rotationThreshold) + movestate = inwater ? CharState_SwimTurnRight : CharState_TurnRight; + else if(rot.z() < -rotationThreshold) + movestate = inwater ? CharState_SwimTurnLeft : CharState_TurnLeft; + } } } @@ -2108,16 +2134,21 @@ void CharacterController::update(float duration) } else { - mTurnAnimationThreshold -= duration; - if (movestate == CharState_TurnRight || movestate == CharState_TurnLeft || - movestate == CharState_SwimTurnRight || movestate == CharState_SwimTurnLeft) + if (mPtr.getClass().isBipedal(mPtr)) { - mTurnAnimationThreshold = 0.05f; - } - else if (movestate == CharState_None && isTurning() - && mTurnAnimationThreshold > 0) - { - movestate = mMovementState; + if (mTurnAnimationThreshold > 0) + mTurnAnimationThreshold -= duration; + + if (movestate == CharState_TurnRight || movestate == CharState_TurnLeft || + movestate == CharState_SwimTurnRight || movestate == CharState_SwimTurnLeft) + { + mTurnAnimationThreshold = 0.05f; + } + else if (movestate == CharState_None && isTurning() + && mTurnAnimationThreshold > 0) + { + movestate = mMovementState; + } } } @@ -2126,13 +2157,12 @@ void CharacterController::update(float duration) if(mAnimQueue.empty() || inwater || sneak) { - // Note: turning animations should not interrupt idle ones. - // Also movement should not stop idle animation for spellcasting stance. + // Note: turning animations should not interrupt idle ones if (inwater) idlestate = CharState_IdleSwim; else if (sneak && !inJump) idlestate = CharState_IdleSneak; - else if (movestate != CharState_None && !isTurning() && mWeaponType != WeapType_Spell) + else if (movestate != CharState_None && !isTurning()) idlestate = CharState_None; else idlestate = CharState_Idle; @@ -2144,7 +2174,7 @@ void CharacterController::update(float duration) { // bipedal means hand-to-hand could be used (which is handled in updateWeaponState). an existing InventoryStore means an actual weapon could be used. if(cls.isBipedal(mPtr) || cls.hasInventoryStore(mPtr)) - forcestateupdate = updateWeaponState() || forcestateupdate; + forcestateupdate = updateWeaponState(idlestate) || forcestateupdate; else forcestateupdate = updateCreatureState() || forcestateupdate; diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 43d26e52f..8b3c68048 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -213,14 +213,14 @@ class CharacterController : public MWRender::Animation::TextKeyListener void setAttackTypeBasedOnMovement(); void refreshCurrentAnims(CharacterState idle, CharacterState movement, JumpingState jump, bool force=false); - void refreshHitRecoilAnims(); - void refreshJumpAnims(const WeaponInfo* weap, JumpingState jump, bool force=false); - void refreshMovementAnims(const WeaponInfo* weap, CharacterState movement, bool force=false); + void refreshHitRecoilAnims(CharacterState& idle); + void refreshJumpAnims(const WeaponInfo* weap, JumpingState jump, CharacterState& idle, bool force=false); + void refreshMovementAnims(const WeaponInfo* weap, CharacterState movement, CharacterState& idle, bool force=false); void refreshIdleAnims(const WeaponInfo* weap, CharacterState idle, bool force=false); void clearAnimQueue(bool clearPersistAnims = false); - bool updateWeaponState(); + bool updateWeaponState(CharacterState& idle); bool updateCreatureState(); void updateIdleStormState(bool inwater); From adbaeb7ccada43631f580c504ba01a0f2f6a874a Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Mon, 18 Jun 2018 13:43:39 +0400 Subject: [PATCH 078/196] Improve GUI scaling (bug #3288) --- CHANGELOG.md | 1 + apps/openmw/mwbase/windowmanager.hpp | 1 + apps/openmw/mwgui/bookpage.cpp | 45 +++++++------- apps/openmw/mwgui/bookpage.hpp | 46 ++++++++++++++ apps/openmw/mwgui/console.cpp | 6 -- apps/openmw/mwgui/console.hpp | 2 - apps/openmw/mwgui/formatting.cpp | 13 +--- apps/openmw/mwgui/formatting.hpp | 4 +- apps/openmw/mwgui/journalbooks.cpp | 28 ++++++--- apps/openmw/mwgui/journalbooks.hpp | 6 +- apps/openmw/mwgui/journalwindow.cpp | 22 ++++++- apps/openmw/mwgui/merchantrepair.cpp | 11 ++-- apps/openmw/mwgui/merchantrepair.hpp | 2 - apps/openmw/mwgui/review.cpp | 23 +++---- apps/openmw/mwgui/review.hpp | 2 - apps/openmw/mwgui/spellbuyingwindow.cpp | 10 ++-- apps/openmw/mwgui/spellbuyingwindow.hpp | 2 - apps/openmw/mwgui/spellview.cpp | 5 +- apps/openmw/mwgui/statswindow.cpp | 18 +++--- apps/openmw/mwgui/statswindow.hpp | 2 - apps/openmw/mwgui/tooltips.cpp | 7 ++- apps/openmw/mwgui/travelwindow.cpp | 10 ++-- apps/openmw/mwgui/travelwindow.hpp | 2 - apps/openmw/mwgui/windowmanagerimp.cpp | 60 ++++++++++++++++++- apps/openmw/mwgui/windowmanagerimp.hpp | 5 ++ apps/openmw/mwrender/localmap.cpp | 5 ++ components/CMakeLists.txt | 2 +- components/widgets/box.cpp | 9 +-- components/widgets/box.hpp | 26 +++++++- components/widgets/fontwrapper.hpp | 45 ++++++++++++++ components/widgets/numericeditbox.hpp | 7 ++- components/widgets/sharedstatebutton.cpp | 1 - components/widgets/sharedstatebutton.hpp | 4 +- components/widgets/widgets.cpp | 3 + components/widgets/widgets.hpp | 3 +- .../source/reference/modding/settings/GUI.rst | 21 +++++++ files/mygui/core.skin | 1 - files/mygui/openmw_confirmation_dialog.layout | 2 +- files/mygui/openmw_enchanting_dialog.layout | 2 +- files/mygui/openmw_font.xml | 2 - files/mygui/openmw_inventory_window.layout | 2 +- files/mygui/openmw_journal.layout | 5 +- files/mygui/openmw_journal.skin.xml | 6 +- files/mygui/openmw_list.skin.xml | 4 -- files/mygui/openmw_windows.skin.xml | 8 +-- files/settings-default.cfg | 6 ++ 46 files changed, 352 insertions(+), 145 deletions(-) create mode 100644 components/widgets/fontwrapper.hpp diff --git a/CHANGELOG.md b/CHANGELOG.md index 44cb90afd..37bf5e660 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ Bug #3059: Unable to hit with marksman weapons when too close to an enemy Bug #3072: Fatal error on AddItem that has a script containing Equip Bug #3249: Fixed revert function not updating views properly + Bug #3288: TrueType fonts are handled incorrectly Bug #3374: Touch spells not hitting kwama foragers Bug #3486: [Mod] NPC Commands does not work Bug #3533: GetSpellEffects should detect effects with zero duration diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 39eed5537..b40f517f9 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -219,6 +219,7 @@ namespace MWBase virtual const MWWorld::Ptr& getSelectedEnchantItem() const = 0; virtual void setSelectedWeapon(const MWWorld::Ptr& item) = 0; virtual const MWWorld::Ptr& getSelectedWeapon() const = 0; + virtual int getFontHeight() const = 0; virtual void unsetSelectedSpell() = 0; virtual void unsetSelectedWeapon() = 0; diff --git a/apps/openmw/mwgui/bookpage.cpp b/apps/openmw/mwgui/bookpage.cpp index 6f16cf076..8f2e8b5ed 100644 --- a/apps/openmw/mwgui/bookpage.cpp +++ b/apps/openmw/mwgui/bookpage.cpp @@ -1,6 +1,5 @@ #include "bookpage.hpp" -#include "MyGUI_FontManager.h" #include "MyGUI_RenderItem.h" #include "MyGUI_RenderManager.h" #include "MyGUI_TextureUtility.h" @@ -8,6 +7,9 @@ #include +#include "../mwbase/environment.hpp" +#include "../mwbase/windowmanager.hpp" + namespace MWGui { struct TypesetBookImpl; @@ -497,9 +499,9 @@ struct TypesetBookImpl::Typesetter : BookTypesetter while (!stream.eof () && !ucsLineBreak (stream.peek ()) && ucsBreakingSpace (stream.peek ())) { - MyGUI::GlyphInfo* gi = style->mFont->getGlyphInfo (stream.peek ()); - if (gi) - space_width += static_cast(gi->advance + gi->bearingX); + MWGui::GlyphInfo info = GlyphInfo(style->mFont, stream.peek()); + if (info.codePoint >= 0) + space_width += static_cast(info.advance + info.bearingX); stream.consume (); } @@ -507,9 +509,9 @@ struct TypesetBookImpl::Typesetter : BookTypesetter while (!stream.eof () && !ucsLineBreak (stream.peek ()) && !ucsBreakingSpace (stream.peek ())) { - MyGUI::GlyphInfo* gi = style->mFont->getGlyphInfo (stream.peek ()); - if (gi) - word_width += static_cast(gi->advance + gi->bearingX); + MWGui::GlyphInfo info = GlyphInfo(style->mFont, stream.peek()); + if (info.codePoint >= 0) + word_width += static_cast(info.advance + info.bearingX); stream.consume (); } @@ -530,6 +532,7 @@ struct TypesetBookImpl::Typesetter : BookTypesetter if (mPartialWhitespace.empty() && mPartialWord.empty()) return; + int fontHeight = MWBase::Environment::get().getWindowManager()->getFontHeight(); int space_width = 0; int word_width = 0; @@ -549,9 +552,8 @@ struct TypesetBookImpl::Typesetter : BookTypesetter for (PartialTextConstIterator i = mPartialWhitespace.begin (); i != mPartialWhitespace.end (); ++i) { int top = mLine ? mLine->mRect.top : mBook->mRect.bottom; - int line_height = i->mStyle->mFont->getDefaultHeight (); - append_run ( i->mStyle, i->mBegin, i->mEnd, 0, left + i->mWidth, top + line_height); + append_run ( i->mStyle, i->mBegin, i->mEnd, 0, left + i->mWidth, top + fontHeight); left = mLine->mRect.right; } @@ -560,9 +562,8 @@ struct TypesetBookImpl::Typesetter : BookTypesetter for (PartialTextConstIterator i = mPartialWord.begin (); i != mPartialWord.end (); ++i) { int top = mLine ? mLine->mRect.top : mBook->mRect.bottom; - int line_height = i->mStyle->mFont->getDefaultHeight (); - append_run (i->mStyle, i->mBegin, i->mEnd, i->mEnd - i->mBegin, left + i->mWidth, top + line_height); + append_run (i->mStyle, i->mBegin, i->mEnd, i->mEnd - i->mBegin, left + i->mWidth, top + fontHeight); left = mLine->mRect.right; } @@ -756,32 +757,32 @@ namespace void emitGlyph (wchar_t ch) { - MyGUI::GlyphInfo* gi = mFont->getGlyphInfo (ch); + MWGui::GlyphInfo info = GlyphInfo(mFont, ch); - if (!gi) + if (info.codePoint < 0) return; MyGUI::FloatRect vr; - vr.left = mCursor.left + gi->bearingX; - vr.top = mCursor.top + gi->bearingY; - vr.right = vr.left + gi->width; - vr.bottom = vr.top + gi->height; + vr.left = mCursor.left + info.bearingX; + vr.top = mCursor.top + info.bearingY; + vr.right = vr.left + info.width; + vr.bottom = vr.top + info.height; - MyGUI::FloatRect tr = gi->uvRect; + MyGUI::FloatRect tr = info.uvRect; if (mRenderXform.clip (vr, tr)) quad (vr, tr); - mCursor.left += gi->bearingX + gi->advance; + mCursor.left += static_cast(info.bearingX + info.advance); } void emitSpace (wchar_t ch) { - MyGUI::GlyphInfo* gi = mFont->getGlyphInfo (ch); + MWGui::GlyphInfo info = GlyphInfo(mFont, ch); - if (gi) - mCursor.left += gi->bearingX + gi->advance; + if (info.codePoint >= 0) + mCursor.left += static_cast(info.bearingX + info.advance); } private: diff --git a/apps/openmw/mwgui/bookpage.hpp b/apps/openmw/mwgui/bookpage.hpp index 66d1834c7..b8174bd3d 100644 --- a/apps/openmw/mwgui/bookpage.hpp +++ b/apps/openmw/mwgui/bookpage.hpp @@ -3,10 +3,17 @@ #include "MyGUI_Colour.h" #include "MyGUI_Widget.h" +#include "MyGUI_FontManager.h" #include #include +#include +#include + +#include "../mwbase/environment.hpp" +#include "../mwbase/windowmanager.hpp" + namespace MWGui { /// A formatted and paginated document to be used with @@ -28,6 +35,45 @@ namespace MWGui virtual std::pair getSize () const = 0; }; + struct GlyphInfo + { + char codePoint; + float width; + float height; + float advance; + float bearingX; + float bearingY; + MyGUI::FloatRect uvRect; + + GlyphInfo(MyGUI::IFont* font, MyGUI::Char ch) + { + static const int fontHeight = MWBase::Environment::get().getWindowManager()->getFontHeight(); + + MyGUI::GlyphInfo* gi = font->getGlyphInfo(ch); + if (gi) + { + const float scale = font->getDefaultHeight() / (float) fontHeight; + + codePoint = gi->codePoint; + bearingX = (int) gi->bearingX / scale; + bearingY = (int) gi->bearingY / scale; + width = (int) gi->width / scale; + height = (int) gi->height / scale; + advance = (int) gi->advance / scale; + uvRect = gi->uvRect; + } + else + { + codePoint = -1; + bearingX = 0; + bearingY = 0; + width = 0; + height = 0; + advance = 0; + } + } + }; + /// A factory class for creating a typeset book instance. struct BookTypesetter { diff --git a/apps/openmw/mwgui/console.cpp b/apps/openmw/mwgui/console.cpp index b367c6f49..dc22e4193 100644 --- a/apps/openmw/mwgui/console.cpp +++ b/apps/openmw/mwgui/console.cpp @@ -152,12 +152,6 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mCommandLine); } - void Console::setFont(const std::string &fntName) - { - mHistory->setFontName(fntName); - mCommandLine->setFontName(fntName); - } - void Console::print(const std::string &msg, const std::string& color) { mHistory->addText(color + MyGUI::TextIterator::toTagsString(msg)); diff --git a/apps/openmw/mwgui/console.hpp b/apps/openmw/mwgui/console.hpp index bbff34c8d..883bc8967 100644 --- a/apps/openmw/mwgui/console.hpp +++ b/apps/openmw/mwgui/console.hpp @@ -41,8 +41,6 @@ namespace MWGui virtual void onOpen(); - void setFont(const std::string &fntName); - void onResChange(int width, int height); // Print a message to the console, in specified color. diff --git a/apps/openmw/mwgui/formatting.cpp b/apps/openmw/mwgui/formatting.cpp index 663bd7338..157aeba26 100644 --- a/apps/openmw/mwgui/formatting.cpp +++ b/apps/openmw/mwgui/formatting.cpp @@ -415,7 +415,7 @@ namespace MWGui : GraphicElement(parent, pag, blockStyle), mTextStyle(textStyle) { - MyGUI::EditBox* box = parent->createWidget("NormalText", + Gui::EditBox* box = parent->createWidget("NormalText", MyGUI::IntCoord(0, pag.getCurrentTop(), pag.getPageWidth(), 0), MyGUI::Align::Left | MyGUI::Align::Top, parent->getName() + MyGUI::utility::toString(parent->getChildCount())); box->setEditStatic(true); @@ -432,15 +432,6 @@ namespace MWGui mEditBox = box; } - int TextElement::currentFontHeight() const - { - std::string fontName(mTextStyle.mFont == "Default" ? MyGUI::FontManager::getInstance().getDefaultFont() : mTextStyle.mFont); - MyGUI::IFont* font = MyGUI::FontManager::getInstance().getByName(fontName); - if (!font) - return 0; - return font->getDefaultHeight(); - } - int TextElement::getHeight() { return mEditBox->getTextSize().height; @@ -449,7 +440,7 @@ namespace MWGui int TextElement::pageSplit() { // split lines - const int lineHeight = currentFontHeight(); + const int lineHeight = MWBase::Environment::get().getWindowManager()->getFontHeight(); unsigned int lastLine = (mPaginator.getStartTop() + mPaginator.getPageHeight() - mPaginator.getCurrentTop()); if (lineHeight > 0) lastLine /= lineHeight; diff --git a/apps/openmw/mwgui/formatting.hpp b/apps/openmw/mwgui/formatting.hpp index d525baace..7ccb0824e 100644 --- a/apps/openmw/mwgui/formatting.hpp +++ b/apps/openmw/mwgui/formatting.hpp @@ -4,6 +4,8 @@ #include #include +#include + namespace MWGui { namespace Formatting @@ -152,7 +154,7 @@ namespace MWGui private: int currentFontHeight() const; TextStyle mTextStyle; - MyGUI::EditBox * mEditBox; + Gui::EditBox * mEditBox; }; class ImageElement : public GraphicElement diff --git a/apps/openmw/mwgui/journalbooks.cpp b/apps/openmw/mwgui/journalbooks.cpp index 1075239fa..1956ee1c2 100644 --- a/apps/openmw/mwgui/journalbooks.cpp +++ b/apps/openmw/mwgui/journalbooks.cpp @@ -218,21 +218,24 @@ book JournalBooks::createQuestBook (const std::string& questName) return typesetter->complete (); } -book JournalBooks::createTopicIndexBook () +book JournalBooks::createTopicIndexBook (int& columnsCount) { bool isRussian = (mEncoding == ToUTF8::WINDOWS_1251); - BookTypesetter::Ptr typesetter = isRussian ? createCyrillicJournalIndex() : createLatinJournalIndex(); + BookTypesetter::Ptr typesetter = isRussian ? createCyrillicJournalIndex(columnsCount) : createLatinJournalIndex(columnsCount); return typesetter->complete (); } -BookTypesetter::Ptr JournalBooks::createLatinJournalIndex () +BookTypesetter::Ptr JournalBooks::createLatinJournalIndex (int& columnsCount) { - BookTypesetter::Ptr typesetter = BookTypesetter::create (92, 250); + BookTypesetter::Ptr typesetter = BookTypesetter::create (92, 260); typesetter->setSectionAlignment (BookTypesetter::AlignCenter); + // Latin journal index always has two columns for now. + columnsCount = 2; + char ch = 'A'; BookTypesetter::Style* body = typesetter->createStyle ("", MyGUI::Colour::Black); @@ -258,14 +261,25 @@ BookTypesetter::Ptr JournalBooks::createLatinJournalIndex () return typesetter; } -BookTypesetter::Ptr JournalBooks::createCyrillicJournalIndex () +BookTypesetter::Ptr JournalBooks::createCyrillicJournalIndex (int& columnsCount) { - BookTypesetter::Ptr typesetter = BookTypesetter::create (92, 250); + BookTypesetter::Ptr typesetter = BookTypesetter::create (92, 260); typesetter->setSectionAlignment (BookTypesetter::AlignCenter); BookTypesetter::Style* body = typesetter->createStyle ("", MyGUI::Colour::Black); + int fontHeight = MWBase::Environment::get().getWindowManager()->getFontHeight(); + + // for small font size split alphabet to two columns (2x15 characers), for big font size split it to three colums (3x10 characters). + int sectionBreak = 10; + columnsCount = 3; + if (fontHeight < 18) + { + sectionBreak = 15; + columnsCount = 2; + } + unsigned char ch[2] = {0xd0, 0x90}; // CYRILLIC CAPITAL A is a 0xd090 in UTF-8 for (int i = 0; i < 32; ++i) @@ -287,7 +301,7 @@ BookTypesetter::Ptr JournalBooks::createCyrillicJournalIndex () if (i == 26 || i == 28) continue; - if (i == 15) + if (i % sectionBreak == 0) typesetter->sectionBreak (); typesetter->write (style, to_utf8_span (buffer)); diff --git a/apps/openmw/mwgui/journalbooks.hpp b/apps/openmw/mwgui/journalbooks.hpp index aa36eecdf..cc6f42cc8 100644 --- a/apps/openmw/mwgui/journalbooks.hpp +++ b/apps/openmw/mwgui/journalbooks.hpp @@ -22,14 +22,14 @@ namespace MWGui Book createTopicBook (uintptr_t topicId); Book createTopicBook (const std::string& topicId); Book createQuestBook (const std::string& questName); - Book createTopicIndexBook (); + Book createTopicIndexBook (int& columnsCount); ToUTF8::FromType mEncoding; private: BookTypesetter::Ptr createTypesetter (); - BookTypesetter::Ptr createLatinJournalIndex (); - BookTypesetter::Ptr createCyrillicJournalIndex (); + BookTypesetter::Ptr createLatinJournalIndex (int& columnsCount); + BookTypesetter::Ptr createCyrillicJournalIndex (int& columnsCount); }; } diff --git a/apps/openmw/mwgui/journalwindow.cpp b/apps/openmw/mwgui/journalwindow.cpp index 0776706d8..cef20159d 100644 --- a/apps/openmw/mwgui/journalwindow.cpp +++ b/apps/openmw/mwgui/journalwindow.cpp @@ -43,6 +43,7 @@ namespace static char const LeftBookPage [] = "LeftBookPage"; static char const RightBookPage [] = "RightBookPage"; static char const LeftTopicIndex [] = "LeftTopicIndex"; + static char const CenterTopicIndex [] = "CenterTopicIndex"; static char const RightTopicIndex [] = "RightTopicIndex"; struct JournalWindowImpl : MWGui::JournalBooks, MWGui::JournalWindow @@ -148,6 +149,7 @@ namespace callback = std::bind(&JournalWindowImpl::notifyIndexLinkClicked, this, std::placeholders::_1); getPage (LeftTopicIndex)->adviseLinkClicked (callback); + getPage (CenterTopicIndex)->adviseLinkClicked (callback); getPage (RightTopicIndex)->adviseLinkClicked (callback); } @@ -312,6 +314,7 @@ namespace setVisible (TopicsList, false); setVisible (QuestsList, mQuestMode); setVisible (LeftTopicIndex, !mQuestMode); + setVisible (CenterTopicIndex, !mQuestMode); setVisible (RightTopicIndex, !mQuestMode); setVisible (ShowAllBTN, mQuestMode && !mAllQuests); setVisible (ShowActiveBTN, mQuestMode && mAllQuests); @@ -462,11 +465,21 @@ namespace { setOptionsMode (); + int pagesCount; if (!mTopicIndexBook) - mTopicIndexBook = createTopicIndexBook (); + mTopicIndexBook = createTopicIndexBook (pagesCount); - getPage (LeftTopicIndex)->showPage (mTopicIndexBook, 0); - getPage (RightTopicIndex)->showPage (mTopicIndexBook, 1); + if (pagesCount == 3) + { + getPage (LeftTopicIndex)->showPage (mTopicIndexBook, 0); + getPage (CenterTopicIndex)->showPage (mTopicIndexBook, 1); + getPage (RightTopicIndex)->showPage (mTopicIndexBook, 2); + } + else + { + getPage (LeftTopicIndex)->showPage (mTopicIndexBook, 0); + getPage (RightTopicIndex)->showPage (mTopicIndexBook, 1); + } } void notifyJournal(MyGUI::Widget* _sender) @@ -480,6 +493,7 @@ namespace void notifyIndexLinkClicked (MWGui::TypesetBook::InteractiveId index) { setVisible (LeftTopicIndex, false); + setVisible (CenterTopicIndex, false); setVisible (RightTopicIndex, false); setVisible (TopicsList, true); @@ -502,6 +516,7 @@ namespace mQuestMode = false; mTopicsMode = false; setVisible (LeftTopicIndex, true); + setVisible (CenterTopicIndex, true); setVisible (RightTopicIndex, true); setVisible (TopicsList, false); setVisible (QuestsList, false); @@ -540,6 +555,7 @@ namespace mQuestMode = true; setVisible (LeftTopicIndex, false); + setVisible (CenterTopicIndex, true); setVisible (RightTopicIndex, false); setVisible (TopicsList, false); setVisible (QuestsList, true); diff --git a/apps/openmw/mwgui/merchantrepair.cpp b/apps/openmw/mwgui/merchantrepair.cpp index 9974c6d16..b9d4c80f4 100644 --- a/apps/openmw/mwgui/merchantrepair.cpp +++ b/apps/openmw/mwgui/merchantrepair.cpp @@ -20,8 +20,6 @@ namespace MWGui { -const int MerchantRepair::sLineHeight = 18; - MerchantRepair::MerchantRepair() : WindowBase("openmw_merchantrepair.layout") { @@ -39,6 +37,7 @@ void MerchantRepair::setPtr(const MWWorld::Ptr &actor) while (mList->getChildCount()) MyGUI::Gui::getInstance().destroyWidget(mList->getChildAt(0)); + int lineHeight = MWBase::Environment::get().getWindowManager()->getFontHeight() + 2; int currentY = 0; MWWorld::Ptr player = MWMechanics::getPlayer(); @@ -67,28 +66,26 @@ void MerchantRepair::setPtr(const MWWorld::Ptr &actor) int price = MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mActor, x, true); - std::string name = iter->getClass().getName(*iter) + " - " + MyGUI::utility::toString(price) + MWBase::Environment::get().getWorld()->getStore().get() .find("sgp")->mValue.getString(); - MyGUI::Button* button = mList->createWidget(price <= playerGold ? "SandTextButton" : "SandTextButtonDisabled", // can't use setEnabled since that removes tooltip 0, currentY, 0, - sLineHeight, + lineHeight, MyGUI::Align::Default ); - currentY += sLineHeight; + currentY += lineHeight; button->setUserString("Price", MyGUI::utility::toString(price)); button->setUserData(MWWorld::Ptr(*iter)); button->setCaptionWithReplacing(name); - button->setSize(mList->getWidth(),sLineHeight); + button->setSize(mList->getWidth(), lineHeight); button->eventMouseWheel += MyGUI::newDelegate(this, &MerchantRepair::onMouseWheel); button->setUserString("ToolTipType", "ItemPtr"); button->eventMouseButtonClick += MyGUI::newDelegate(this, &MerchantRepair::onRepairButtonClick); diff --git a/apps/openmw/mwgui/merchantrepair.hpp b/apps/openmw/mwgui/merchantrepair.hpp index 4e4e7164f..26887ae2c 100644 --- a/apps/openmw/mwgui/merchantrepair.hpp +++ b/apps/openmw/mwgui/merchantrepair.hpp @@ -27,8 +27,6 @@ protected: void onMouseWheel(MyGUI::Widget* _sender, int _rel); void onRepairButtonClick(MyGUI::Widget* sender); void onOkButtonClick(MyGUI::Widget* sender); - - static const int sLineHeight; }; } diff --git a/apps/openmw/mwgui/review.cpp b/apps/openmw/mwgui/review.cpp index 61a7a2ac0..b59b1582c 100644 --- a/apps/openmw/mwgui/review.cpp +++ b/apps/openmw/mwgui/review.cpp @@ -26,9 +26,6 @@ namespace namespace MWGui { - - const int ReviewDialog::sLineHeight = 18; - ReviewDialog::ReviewDialog() : WindowModal("openmw_chargen_review.layout"), mUpdateSkillArea(false) @@ -261,8 +258,9 @@ namespace MWGui groupWidget->setCaption(label); mSkillWidgets.push_back(groupWidget); - coord1.top += sLineHeight; - coord2.top += sLineHeight; + int lineHeight = MWBase::Environment::get().getWindowManager()->getFontHeight() + 2; + coord1.top += lineHeight; + coord2.top += lineHeight; } MyGUI::TextBox* ReviewDialog::addValueItem(const std::string& text, const std::string &value, const std::string& state, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) @@ -282,8 +280,9 @@ namespace MWGui mSkillWidgets.push_back(skillNameWidget); mSkillWidgets.push_back(skillValueWidget); - coord1.top += sLineHeight; - coord2.top += sLineHeight; + int lineHeight = MWBase::Environment::get().getWindowManager()->getFontHeight() + 2; + coord1.top += lineHeight; + coord2.top += lineHeight; return skillValueWidget; } @@ -298,8 +297,9 @@ namespace MWGui mSkillWidgets.push_back(skillNameWidget); - coord1.top += sLineHeight; - coord2.top += sLineHeight; + int lineHeight = MWBase::Environment::get().getWindowManager()->getFontHeight() + 2; + coord1.top += lineHeight; + coord2.top += lineHeight; } void ReviewDialog::addItem(const ESM::Spell* spell, MyGUI::IntCoord& coord1, MyGUI::IntCoord& coord2) @@ -312,8 +312,9 @@ namespace MWGui mSkillWidgets.push_back(widget); - coord1.top += sLineHeight; - coord2.top += sLineHeight; + int lineHeight = MWBase::Environment::get().getWindowManager()->getFontHeight() + 2; + coord1.top += lineHeight; + coord2.top += lineHeight; } void ReviewDialog::addSkills(const SkillList &skills, const std::string &titleId, const std::string &titleDefault, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) diff --git a/apps/openmw/mwgui/review.hpp b/apps/openmw/mwgui/review.hpp index 8e9ec0ec7..f46ad280d 100644 --- a/apps/openmw/mwgui/review.hpp +++ b/apps/openmw/mwgui/review.hpp @@ -87,8 +87,6 @@ namespace MWGui void addItem(const ESM::Spell* spell, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2); void updateSkillArea(); - static const int sLineHeight; - MyGUI::TextBox *mNameWidget, *mRaceWidget, *mClassWidget, *mBirthSignWidget; MyGUI::ScrollView* mSkillView; diff --git a/apps/openmw/mwgui/spellbuyingwindow.cpp b/apps/openmw/mwgui/spellbuyingwindow.cpp index 9876013f1..bc5d161d8 100644 --- a/apps/openmw/mwgui/spellbuyingwindow.cpp +++ b/apps/openmw/mwgui/spellbuyingwindow.cpp @@ -18,8 +18,6 @@ namespace MWGui { - const int SpellBuyingWindow::sLineHeight = 18; - SpellBuyingWindow::SpellBuyingWindow() : WindowBase("openmw_spell_buying_window.layout") , mCurrentY(0) @@ -52,21 +50,23 @@ namespace MWGui // TODO: refactor to use MyGUI::ListBox + int lineHeight = MWBase::Environment::get().getWindowManager()->getFontHeight() + 2; + MyGUI::Button* toAdd = mSpellsView->createWidget( price <= playerGold ? "SandTextButton" : "SandTextButtonDisabled", // can't use setEnabled since that removes tooltip 0, mCurrentY, 200, - sLineHeight, + lineHeight, MyGUI::Align::Default ); - mCurrentY += sLineHeight; + mCurrentY += lineHeight; toAdd->setUserData(price); toAdd->setCaptionWithReplacing(spell.mName+" - "+MyGUI::utility::toString(price)+"#{sgp}"); - toAdd->setSize(mSpellsView->getWidth(),sLineHeight); + toAdd->setSize(mSpellsView->getWidth(), lineHeight); toAdd->eventMouseWheel += MyGUI::newDelegate(this, &SpellBuyingWindow::onMouseWheel); toAdd->setUserString("ToolTipType", "Spell"); toAdd->setUserString("Spell", spell.mId); diff --git a/apps/openmw/mwgui/spellbuyingwindow.hpp b/apps/openmw/mwgui/spellbuyingwindow.hpp index 3414c1b94..30727a545 100644 --- a/apps/openmw/mwgui/spellbuyingwindow.hpp +++ b/apps/openmw/mwgui/spellbuyingwindow.hpp @@ -48,8 +48,6 @@ namespace MWGui void clearSpells(); int mCurrentY; - static const int sLineHeight; - void updateLabels(); virtual void onReferenceUnavailable(); diff --git a/apps/openmw/mwgui/spellview.cpp b/apps/openmw/mwgui/spellview.cpp index 758e6b306..702c2f840 100644 --- a/apps/openmw/mwgui/spellview.cpp +++ b/apps/openmw/mwgui/spellview.cpp @@ -6,6 +6,7 @@ #include #include +#include #include "tooltips.hpp" @@ -240,7 +241,7 @@ namespace MWGui mLines.push_back(LineInfo(separator, (MyGUI::Widget*)NULL, NoSpellIndex)); } - MyGUI::TextBox* groupWidget = mScrollView->createWidget("SandBrightText", + MyGUI::TextBox* groupWidget = mScrollView->createWidget("SandBrightText", MyGUI::IntCoord(0, 0, mScrollView->getWidth(), 24), MyGUI::Align::Left | MyGUI::Align::Top); groupWidget->setCaptionWithReplacing(label); @@ -249,7 +250,7 @@ namespace MWGui if (label2 != "") { - MyGUI::TextBox* groupWidget2 = mScrollView->createWidget("SandBrightText", + MyGUI::TextBox* groupWidget2 = mScrollView->createWidget("SandBrightText", MyGUI::IntCoord(0, 0, mScrollView->getWidth(), 24), MyGUI::Align::Left | MyGUI::Align::Top); groupWidget2->setCaptionWithReplacing(label2); diff --git a/apps/openmw/mwgui/statswindow.cpp b/apps/openmw/mwgui/statswindow.cpp index db73351bf..dfa029467 100644 --- a/apps/openmw/mwgui/statswindow.cpp +++ b/apps/openmw/mwgui/statswindow.cpp @@ -23,9 +23,6 @@ namespace MWGui { - - const int StatsWindow::sLineHeight = 18; - StatsWindow::StatsWindow (DragAndDrop* drag) : WindowPinnableBase("openmw_stats_window.layout") , NoDrop(drag, mMainWidget) @@ -376,8 +373,9 @@ namespace MWGui groupWidget->eventMouseWheel += MyGUI::newDelegate(this, &StatsWindow::onMouseWheel); mSkillWidgets.push_back(groupWidget); - coord1.top += sLineHeight; - coord2.top += sLineHeight; + int lineHeight = MWBase::Environment::get().getWindowManager()->getFontHeight() + 2; + coord1.top += lineHeight; + coord2.top += lineHeight; } std::pair StatsWindow::addValueItem(const std::string& text, const std::string &value, const std::string& state, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) @@ -401,8 +399,9 @@ namespace MWGui mSkillWidgets.push_back(skillNameWidget); mSkillWidgets.push_back(skillValueWidget); - coord1.top += sLineHeight; - coord2.top += sLineHeight; + int lineHeight = MWBase::Environment::get().getWindowManager()->getFontHeight() + 2; + coord1.top += lineHeight; + coord2.top += lineHeight; return std::make_pair(skillNameWidget, skillValueWidget); } @@ -421,8 +420,9 @@ namespace MWGui mSkillWidgets.push_back(skillNameWidget); - coord1.top += sLineHeight; - coord2.top += sLineHeight; + int lineHeight = MWBase::Environment::get().getWindowManager()->getFontHeight() + 2; + coord1.top += lineHeight; + coord2.top += lineHeight; return skillNameWidget; } diff --git a/apps/openmw/mwgui/statswindow.hpp b/apps/openmw/mwgui/statswindow.hpp index 487953e00..8dab2f3d9 100644 --- a/apps/openmw/mwgui/statswindow.hpp +++ b/apps/openmw/mwgui/statswindow.hpp @@ -53,8 +53,6 @@ namespace MWGui void onWindowResize(MyGUI::Window* window); void onMouseWheel(MyGUI::Widget* _sender, int _rel); - static const int sLineHeight; - MyGUI::Widget* mLeftPane; MyGUI::Widget* mRightPane; diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 20814aac5..0bd0d191c 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -8,6 +8,7 @@ #include #include +#include #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" @@ -421,7 +422,7 @@ namespace MWGui std::string realImage = MWBase::Environment::get().getWindowManager()->correctIconPath(image); - MyGUI::EditBox* captionWidget = mDynamicToolTipBox->createWidget("NormalText", MyGUI::IntCoord(0, 0, 300, 300), MyGUI::Align::Left | MyGUI::Align::Top, "ToolTipCaption"); + Gui::EditBox* captionWidget = mDynamicToolTipBox->createWidget("NormalText", MyGUI::IntCoord(0, 0, 300, 300), MyGUI::Align::Left | MyGUI::Align::Top, "ToolTipCaption"); captionWidget->setEditStatic(true); captionWidget->setNeedKeyFocus(false); captionWidget->setCaptionWithReplacing(caption); @@ -429,7 +430,7 @@ namespace MWGui int captionHeight = std::max(caption != "" ? captionSize.height : 0, imageSize); - MyGUI::EditBox* textWidget = mDynamicToolTipBox->createWidget("SandText", MyGUI::IntCoord(0, captionHeight+imageCaptionVPadding, 300, 300-captionHeight-imageCaptionVPadding), MyGUI::Align::Stretch, "ToolTipText"); + Gui::EditBox* textWidget = mDynamicToolTipBox->createWidget("SandText", MyGUI::IntCoord(0, captionHeight+imageCaptionVPadding, 300, 300-captionHeight-imageCaptionVPadding), MyGUI::Align::Stretch, "ToolTipText"); textWidget->setEditStatic(true); textWidget->setEditMultiLine(true); textWidget->setEditWordWrap(info.wordWrap); @@ -447,7 +448,7 @@ namespace MWGui MyGUI::ImageBox* icon = mDynamicToolTipBox->createWidget("MarkerButton", MyGUI::IntCoord(padding.left, totalSize.height+padding.top, 8, 8), MyGUI::Align::Default); icon->setColour(MyGUI::Colour(1.0f, 0.3f, 0.3f)); - MyGUI::EditBox* edit = mDynamicToolTipBox->createWidget("SandText", + Gui::EditBox* edit = mDynamicToolTipBox->createWidget("SandText", MyGUI::IntCoord(padding.left+8+4, totalSize.height+padding.top, 300-padding.left-8-4, 300-totalSize.height), MyGUI::Align::Default); edit->setEditMultiLine(true); diff --git a/apps/openmw/mwgui/travelwindow.cpp b/apps/openmw/mwgui/travelwindow.cpp index 23a5b322f..5f5430524 100644 --- a/apps/openmw/mwgui/travelwindow.cpp +++ b/apps/openmw/mwgui/travelwindow.cpp @@ -22,8 +22,6 @@ namespace MWGui { - const int TravelWindow::sLineHeight = 18; - TravelWindow::TravelWindow() : WindowBase("openmw_travel_window.layout") , mCurrentY(0) @@ -79,9 +77,11 @@ namespace MWGui else price *= std::max(1, static_cast(followers.size())); - MyGUI::Button* toAdd = mDestinationsView->createWidget("SandTextButton", 0, mCurrentY, 200, sLineHeight, MyGUI::Align::Default); + int lineHeight = MWBase::Environment::get().getWindowManager()->getFontHeight() + 2; + + MyGUI::Button* toAdd = mDestinationsView->createWidget("SandTextButton", 0, mCurrentY, 200, lineHeight, MyGUI::Align::Default); toAdd->setEnabled(price <= playerGold); - mCurrentY += sLineHeight; + mCurrentY += lineHeight; if(interior) toAdd->setUserString("interior","y"); else @@ -92,7 +92,7 @@ namespace MWGui toAdd->setUserString("price",oss.str()); toAdd->setCaptionWithReplacing("#{sCell=" + name + "} - " + MyGUI::utility::toString(price)+"#{sgp}"); - toAdd->setSize(mDestinationsView->getWidth(),sLineHeight); + toAdd->setSize(mDestinationsView->getWidth(),lineHeight); toAdd->eventMouseWheel += MyGUI::newDelegate(this, &TravelWindow::onMouseWheel); toAdd->setUserString("Destination", name); toAdd->setUserData(pos); diff --git a/apps/openmw/mwgui/travelwindow.hpp b/apps/openmw/mwgui/travelwindow.hpp index 5ae466047..dcf0b7727 100644 --- a/apps/openmw/mwgui/travelwindow.hpp +++ b/apps/openmw/mwgui/travelwindow.hpp @@ -41,8 +41,6 @@ namespace MWGui void clearDestinations(); int mCurrentY; - static const int sLineHeight; - void updateLabels(); virtual void onReferenceUnavailable(); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 6917e2e8a..493a14a1c 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -44,7 +44,6 @@ #include -#include #include #include @@ -196,6 +195,7 @@ namespace MWGui , mFallbackMap(fallbackMap) , mShowOwned(0) , mEncoding(encoding) + , mFontHeight(16) , mVersionDescription(versionDescription) { float uiScale = Settings::Manager::getFloat("scaling factor", "GUI"); @@ -233,6 +233,13 @@ namespace MWGui SpellView::registerComponents(); Gui::registerAllWidgets(); + int fontSize = Settings::Manager::getInt("font size", "GUI"); + fontSize = std::min(std::max(12, fontSize), 20); + mFontHeight = fontSize; + + MyGUI::ResourceManager::getInstance().unregisterLoadXmlDelegate("Resource"); + MyGUI::ResourceManager::getInstance().registerLoadXmlDelegate("Resource") = newDelegate(this, &WindowManager::loadFontDelegate); + MyGUI::FactoryManager::getInstance().registerFactory("Controller"); MyGUI::FactoryManager::getInstance().registerFactory("Controller"); @@ -284,6 +291,51 @@ namespace MWGui mShowOwned = Settings::Manager::getInt("show owned", "Game"); } + void WindowManager::loadFontDelegate(MyGUI::xml::ElementPtr _node, const std::string& _file, MyGUI::Version _version) + { + MyGUI::xml::ElementEnumerator root = _node->getElementEnumerator(); + while (root.next("Resource")) + { + std::string type, name; + root->findAttribute("type", type); + root->findAttribute("name", name); + + if (name.empty()) + continue; + + if (Misc::StringUtils::ciEqual(type, "ResourceTrueTypeFont")) + { + // For TrueType fonts we should override Size and Resolution properties + // to allow to configure font size via config file, without need to edit XML file. + // Also we should take UI scaling factor in account + int resolution = Settings::Manager::getInt("ttf resolution", "GUI"); + resolution = std::max(0, resolution); + + float uiScale = Settings::Manager::getFloat("scaling factor", "GUI"); + + if (uiScale > 1.0f) + resolution *= uiScale; + + MyGUI::xml::ElementPtr resolutionNode = root->createChild("Property"); + resolutionNode->addAttribute("key", "Resolution"); + resolutionNode->addAttribute("value", std::to_string(resolution)); + + MyGUI::xml::ElementPtr sizeNode = root->createChild("Property"); + sizeNode->addAttribute("key", "Size"); + sizeNode->addAttribute("value", std::to_string(mFontHeight)); + } + else if (Misc::StringUtils::ciEqual(type, "ResourceSkin")) + { + // We should adjust line height for MyGUI widgets depending on font size + MyGUI::xml::ElementPtr heightNode = root->createChild("Property"); + heightNode->addAttribute("key", "HeightLine"); + heightNode->addAttribute("value", std::to_string(mFontHeight+2)); + } + } + + MyGUI::ResourceManager::getInstance().loadFromXmlNode(_node, _file, _version); + } + void WindowManager::initUI() { // Get size info from the Gui object @@ -504,6 +556,11 @@ namespace MWGui updateVisible(); } + int WindowManager::getFontHeight() const + { + return mFontHeight; + } + void WindowManager::setNewGame(bool newgame) { if (newgame) @@ -522,6 +579,7 @@ namespace MWGui { mKeyboardNavigation.reset(); + MyGUI::ResourceManager::getInstance().unregisterLoadXmlDelegate("Resource"); MyGUI::LanguageManager::getInstance().eventRequestTag.clear(); MyGUI::PointerManager::getInstance().eventChangeMousePointer.clear(); MyGUI::InputManager::getInstance().eventChangeKeyFocus.clear(); diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 657548397..f3bf6d00f 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -246,6 +246,7 @@ namespace MWGui virtual const MWWorld::Ptr& getSelectedEnchantItem() const; virtual void setSelectedWeapon(const MWWorld::Ptr& item); virtual const MWWorld::Ptr& getSelectedWeapon() const; + virtual int getFontHeight() const; virtual void unsetSelectedSpell(); virtual void unsetSelectedWeapon(); @@ -401,6 +402,8 @@ namespace MWGui MWWorld::Ptr mSelectedEnchantItem; MWWorld::Ptr mSelectedWeapon; + void loadFontDelegate(MyGUI::xml::ElementPtr _node, const std::string& _file, MyGUI::Version _version); + std::vector mCurrentModals; // Markers placed manually by the player. Must be shared between both map views (the HUD map and the map window). @@ -513,6 +516,8 @@ namespace MWGui ToUTF8::FromType mEncoding; + int mFontHeight; + std::string mVersionDescription; MWGui::TextColours mTextColours; diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index 5e501ecf8..8ed3441de 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -76,6 +76,11 @@ LocalMap::LocalMap(osg::Group* root) , mAngle(0.f) , mInterior(false) { + // Increase map resolution, if use UI scaling + float uiScale = Settings::Manager::getFloat("scaling factor", "GUI"); + if (uiScale > 1.0) + mMapResolution *= uiScale; + SceneUtil::FindByNameVisitor find("Scene Root"); mRoot->accept(find); mSceneRoot = find.mFoundNode; diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 551767f8f..8e798455f 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -130,7 +130,7 @@ add_component_dir (myguiplatform ) add_component_dir (widgets - box imagebutton tags list numericeditbox sharedstatebutton windowcaption widgets + box fontwrapper imagebutton tags list numericeditbox sharedstatebutton windowcaption widgets ) add_component_dir (fontloader diff --git a/components/widgets/box.cpp b/components/widgets/box.cpp index bf18cef5b..d38410a2c 100644 --- a/components/widgets/box.cpp +++ b/components/widgets/box.cpp @@ -48,7 +48,7 @@ namespace Gui } else { - TextBox::setPropertyOverride (_key, _value); + Gui::TextBox::setPropertyOverride (_key, _value); } } @@ -81,11 +81,10 @@ namespace Gui } else { - EditBox::setPropertyOverride (_key, _value); + Gui::EditBox::setPropertyOverride (_key, _value); } } - MyGUI::IntSize AutoSizedButton::getRequestedSize() { MyGUI::IntSize padding(24, 8); @@ -111,16 +110,14 @@ namespace Gui } else { - Button::setPropertyOverride (_key, _value); + Gui::Button::setPropertyOverride (_key, _value); } } - Box::Box() : mSpacing(4) , mPadding(0) , mAutoResize(false) { - } void Box::notifyChildrenSizeChanged () diff --git a/components/widgets/box.hpp b/components/widgets/box.hpp index 66be00719..9bab575c4 100644 --- a/components/widgets/box.hpp +++ b/components/widgets/box.hpp @@ -4,10 +4,27 @@ #include #include #include +#include #include +#include "fontwrapper.hpp" + namespace Gui { + class Button : public FontWrapper + { + MYGUI_RTTI_DERIVED( Button ) + }; + + class TextBox : public FontWrapper + { + MYGUI_RTTI_DERIVED( TextBox ) + }; + + class EditBox : public FontWrapper + { + MYGUI_RTTI_DERIVED( EditBox ) + }; class AutoSizedWidget { @@ -22,7 +39,7 @@ namespace Gui MyGUI::Align mExpandDirection; }; - class AutoSizedTextBox : public AutoSizedWidget, public MyGUI::TextBox + class AutoSizedTextBox : public AutoSizedWidget, public TextBox { MYGUI_RTTI_DERIVED( AutoSizedTextBox ) @@ -32,9 +49,10 @@ namespace Gui protected: virtual void setPropertyOverride(const std::string& _key, const std::string& _value); + std::string mFontSize; }; - class AutoSizedEditBox : public AutoSizedWidget, public MyGUI::EditBox + class AutoSizedEditBox : public AutoSizedWidget, public EditBox { MYGUI_RTTI_DERIVED( AutoSizedEditBox ) @@ -47,9 +65,10 @@ namespace Gui protected: virtual void setPropertyOverride(const std::string& _key, const std::string& _value); + std::string mFontSize; }; - class AutoSizedButton : public AutoSizedWidget, public MyGUI::Button + class AutoSizedButton : public AutoSizedWidget, public Button { MYGUI_RTTI_DERIVED( AutoSizedButton ) @@ -59,6 +78,7 @@ namespace Gui protected: virtual void setPropertyOverride(const std::string& _key, const std::string& _value); + std::string mFontSize; }; /** diff --git a/components/widgets/fontwrapper.hpp b/components/widgets/fontwrapper.hpp new file mode 100644 index 000000000..2424b22a7 --- /dev/null +++ b/components/widgets/fontwrapper.hpp @@ -0,0 +1,45 @@ +#ifndef OPENMW_WIDGETS_WRAPPER_H +#define OPENMW_WIDGETS_WRAPPER_H + +#include "widgets.hpp" + +#include + +namespace Gui +{ + template + class FontWrapper : public T + { + public: + virtual void setFontName(const std::string& name) + { + T::setFontName(name); + T::setPropertyOverride ("FontHeight", mFontSize); + } + + protected: + FontWrapper() + { + // Note: we can not use the WindowManager here, so there is a code duplication a bit. + int fontSize = Settings::Manager::getInt("font size", "GUI"); + fontSize = std::min(std::max(12, fontSize), 20); + mFontSize = std::to_string(fontSize); + } + + virtual void setPropertyOverride(const std::string& _key, const std::string& _value) + { + T::setPropertyOverride (_key, _value); + + // There is a bug in MyGUI: when it initializes the FontName property, it reset the font height. + // We should restore it. + if (_key == "FontName") + { + T::setPropertyOverride ("FontHeight", mFontSize); + } + } + + std::string mFontSize; + }; +} + +#endif diff --git a/components/widgets/numericeditbox.hpp b/components/widgets/numericeditbox.hpp index ca7674f22..3edae2fc7 100644 --- a/components/widgets/numericeditbox.hpp +++ b/components/widgets/numericeditbox.hpp @@ -3,13 +3,15 @@ #include +#include "fontwrapper.hpp" + namespace Gui { /** * @brief A variant of the EditBox that only allows integer inputs */ - class NumericEditBox : public MyGUI::EditBox + class NumericEditBox : public FontWrapper { MYGUI_RTTI_DERIVED(NumericEditBox) @@ -17,7 +19,8 @@ namespace Gui NumericEditBox() : mValue(0), mMinValue(std::numeric_limits::min()), mMaxValue(std::numeric_limits::max()) - {} + { + } void initialiseOverride(); void shutdownOverride(); diff --git a/components/widgets/sharedstatebutton.cpp b/components/widgets/sharedstatebutton.cpp index 6859a3065..f4456275b 100644 --- a/components/widgets/sharedstatebutton.cpp +++ b/components/widgets/sharedstatebutton.cpp @@ -7,7 +7,6 @@ namespace Gui : mIsMousePressed(false) , mIsMouseFocus(false) { - } void SharedStateButton::shutdownOverride() diff --git a/components/widgets/sharedstatebutton.hpp b/components/widgets/sharedstatebutton.hpp index 3d7fbc84e..414349396 100644 --- a/components/widgets/sharedstatebutton.hpp +++ b/components/widgets/sharedstatebutton.hpp @@ -3,6 +3,8 @@ #include +#include "fontwrapper.hpp" + namespace Gui { @@ -11,7 +13,7 @@ namespace Gui typedef std::vector ButtonGroup; /// @brief A button that applies its own state changes to other widgets, to do this you define it as part of a ButtonGroup. - class SharedStateButton : public MyGUI::Button + class SharedStateButton : public FontWrapper { MYGUI_RTTI_DERIVED(SharedStateButton) diff --git a/components/widgets/widgets.cpp b/components/widgets/widgets.cpp index 92f2084df..c1a9a5053 100644 --- a/components/widgets/widgets.cpp +++ b/components/widgets/widgets.cpp @@ -18,9 +18,12 @@ namespace Gui 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"); 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 --git a/components/widgets/widgets.hpp b/components/widgets/widgets.hpp index d17132135..a5ba84b11 100644 --- a/components/widgets/widgets.hpp +++ b/components/widgets/widgets.hpp @@ -1,9 +1,10 @@ #ifndef OPENMW_COMPONENTS_WIDGETS_H #define OPENMW_COMPONENTS_WIDGETS_H +extern int GuiFontHeight; + namespace Gui { - /// Register all widgets from this component with MyGUI's factory manager. void registerAllWidgets(); diff --git a/docs/source/reference/modding/settings/GUI.rst b/docs/source/reference/modding/settings/GUI.rst index 3040fc48b..3fe943b6f 100644 --- a/docs/source/reference/modding/settings/GUI.rst +++ b/docs/source/reference/modding/settings/GUI.rst @@ -12,6 +12,27 @@ This setting scales the GUI interface windows. A value of 1.0 results in the normal scale. Larger values are useful to increase the scale of the GUI for high resolution displays. This setting can only be configured by editing the settings configuration file. +font size +--------- + +:Type: integer +:Range: 12 to 20 +:Default: 16 + +Allows to specify glyph size for in-game fonts. +Note: default bitmap fonts are supposed to work with 16px size, otherwise glyphs will be blurry. +TrueType fonts do not have this issue. + +ttf resolution +-------------- + +:Type: integer +:Range: > 0 +:Default: 96 + +Allows to specify resolution for in-game TrueType fonts. +Note: actual resolution depends on "scaling factor" setting value, this value is for 1.0 or lower scaling factor. + menu transparency ----------------- diff --git a/files/mygui/core.skin b/files/mygui/core.skin index 9aa566451..ee9135554 100644 --- a/files/mygui/core.skin +++ b/files/mygui/core.skin @@ -2,7 +2,6 @@ - diff --git a/files/mygui/openmw_confirmation_dialog.layout b/files/mygui/openmw_confirmation_dialog.layout index c5eb573a7..246c8aa8f 100644 --- a/files/mygui/openmw_confirmation_dialog.layout +++ b/files/mygui/openmw_confirmation_dialog.layout @@ -13,7 +13,7 @@ - + diff --git a/files/mygui/openmw_enchanting_dialog.layout b/files/mygui/openmw_enchanting_dialog.layout index ed3cfb03e..4738cdc13 100644 --- a/files/mygui/openmw_enchanting_dialog.layout +++ b/files/mygui/openmw_enchanting_dialog.layout @@ -50,7 +50,7 @@ - + diff --git a/files/mygui/openmw_font.xml b/files/mygui/openmw_font.xml index e4037561d..6ffe3017e 100644 --- a/files/mygui/openmw_font.xml +++ b/files/mygui/openmw_font.xml @@ -2,8 +2,6 @@ - - diff --git a/files/mygui/openmw_inventory_window.layout b/files/mygui/openmw_inventory_window.layout index 6221799b5..e935e2f5c 100644 --- a/files/mygui/openmw_inventory_window.layout +++ b/files/mygui/openmw_inventory_window.layout @@ -29,7 +29,7 @@ - + diff --git a/files/mygui/openmw_journal.layout b/files/mygui/openmw_journal.layout index 964b5ea95..0d3a71ab5 100644 --- a/files/mygui/openmw_journal.layout +++ b/files/mygui/openmw_journal.layout @@ -59,8 +59,9 @@ - - + + + diff --git a/files/mygui/openmw_journal.skin.xml b/files/mygui/openmw_journal.skin.xml index 42be2bb62..e9eecba79 100644 --- a/files/mygui/openmw_journal.skin.xml +++ b/files/mygui/openmw_journal.skin.xml @@ -13,11 +13,9 @@ + - - - - + diff --git a/files/mygui/openmw_list.skin.xml b/files/mygui/openmw_list.skin.xml index 5b6f14dd5..9af0e7966 100644 --- a/files/mygui/openmw_list.skin.xml +++ b/files/mygui/openmw_list.skin.xml @@ -127,7 +127,6 @@ - @@ -140,8 +139,6 @@ - - @@ -153,7 +150,6 @@ - diff --git a/files/mygui/openmw_windows.skin.xml b/files/mygui/openmw_windows.skin.xml index a272ae84a..ef618b316 100644 --- a/files/mygui/openmw_windows.skin.xml +++ b/files/mygui/openmw_windows.skin.xml @@ -156,10 +156,10 @@ - + - + @@ -443,7 +443,6 @@ - @@ -458,7 +457,6 @@ ------------------------------------------------------ --> - @@ -593,7 +591,6 @@ - @@ -730,7 +727,6 @@ - diff --git a/files/settings-default.cfg b/files/settings-default.cfg index c2ac2eb1c..45cee0559 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -142,6 +142,12 @@ global = false # Scales GUI window and widget size. (<1.0 is smaller, >1.0 is larger). scaling factor = 1.0 +# Size of in-game fonts +font size = 16 + +# Resolution of TrueType fonts glyphs +ttf resolution = 96 + # Transparency of GUI windows (0.0 to 1.0, transparent to opaque). menu transparency = 0.84 From 8da099713e8c7a7535a2932dfe454013feb16f85 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sat, 1 Sep 2018 22:02:43 +0400 Subject: [PATCH 079/196] Minor layout fixes to fit different font size --- files/mygui/openmw_alchemy_window.layout | 2 +- files/mygui/openmw_chargen_birth.layout | 2 +- files/mygui/openmw_chargen_class.layout | 6 ++-- .../mygui/openmw_chargen_create_class.layout | 6 ++-- ...penmw_chargen_generate_class_result.layout | 2 +- files/mygui/openmw_chargen_race.layout | 16 ++++----- .../openmw_chargen_select_attribute.layout | 31 +++++++++-------- .../mygui/openmw_chargen_select_skill.layout | 33 ++++++++++--------- ...penmw_chargen_select_specialization.layout | 11 ++++--- files/mygui/openmw_container_window.layout | 2 +- files/mygui/openmw_count_window.layout | 6 ++-- files/mygui/openmw_trade_window.layout | 4 +-- 12 files changed, 65 insertions(+), 56 deletions(-) diff --git a/files/mygui/openmw_alchemy_window.layout b/files/mygui/openmw_alchemy_window.layout index a8e5431fb..edc9a4c3d 100644 --- a/files/mygui/openmw_alchemy_window.layout +++ b/files/mygui/openmw_alchemy_window.layout @@ -74,7 +74,7 @@ - + diff --git a/files/mygui/openmw_chargen_birth.layout b/files/mygui/openmw_chargen_birth.layout index a137d83d1..18d412340 100644 --- a/files/mygui/openmw_chargen_birth.layout +++ b/files/mygui/openmw_chargen_birth.layout @@ -16,7 +16,7 @@ > - + diff --git a/files/mygui/openmw_chargen_class.layout b/files/mygui/openmw_chargen_class.layout index 98c8e4fde..1402d9b5c 100644 --- a/files/mygui/openmw_chargen_class.layout +++ b/files/mygui/openmw_chargen_class.layout @@ -27,11 +27,11 @@ - + - + @@ -73,7 +73,7 @@ - + diff --git a/files/mygui/openmw_chargen_create_class.layout b/files/mygui/openmw_chargen_create_class.layout index c04cfe064..fe491eb6d 100644 --- a/files/mygui/openmw_chargen_create_class.layout +++ b/files/mygui/openmw_chargen_create_class.layout @@ -11,7 +11,7 @@ - + @@ -26,7 +26,7 @@ - + @@ -74,7 +74,7 @@ - + diff --git a/files/mygui/openmw_chargen_generate_class_result.layout b/files/mygui/openmw_chargen_generate_class_result.layout index d49f57dde..48a203b18 100644 --- a/files/mygui/openmw_chargen_generate_class_result.layout +++ b/files/mygui/openmw_chargen_generate_class_result.layout @@ -24,7 +24,7 @@ - + diff --git a/files/mygui/openmw_chargen_race.layout b/files/mygui/openmw_chargen_race.layout index 31f0436d5..ea7ec6179 100644 --- a/files/mygui/openmw_chargen_race.layout +++ b/files/mygui/openmw_chargen_race.layout @@ -1,7 +1,7 @@ - + @@ -54,28 +54,28 @@ - + - + - + - + - + - + - + diff --git a/files/mygui/openmw_chargen_select_attribute.layout b/files/mygui/openmw_chargen_select_attribute.layout index 0821d4a57..57bd4ebc6 100644 --- a/files/mygui/openmw_chargen_select_attribute.layout +++ b/files/mygui/openmw_chargen_select_attribute.layout @@ -1,28 +1,31 @@ - - + + - + - - - - - - - - + + + + + + + + - - - + + + + + + diff --git a/files/mygui/openmw_chargen_select_skill.layout b/files/mygui/openmw_chargen_select_skill.layout index d1061882d..3737ea904 100644 --- a/files/mygui/openmw_chargen_select_skill.layout +++ b/files/mygui/openmw_chargen_select_skill.layout @@ -1,10 +1,10 @@ - - + + - + @@ -44,20 +44,23 @@ - - - - - - - - - + + + + + + + + + - - - + + + + + + diff --git a/files/mygui/openmw_chargen_select_specialization.layout b/files/mygui/openmw_chargen_select_specialization.layout index c4fe6c631..47dc32f62 100644 --- a/files/mygui/openmw_chargen_select_specialization.layout +++ b/files/mygui/openmw_chargen_select_specialization.layout @@ -2,7 +2,7 @@ - + @@ -22,9 +22,12 @@ - - - + + + + + + diff --git a/files/mygui/openmw_container_window.layout b/files/mygui/openmw_container_window.layout index 6bb585e50..5783779db 100644 --- a/files/mygui/openmw_container_window.layout +++ b/files/mygui/openmw_container_window.layout @@ -9,7 +9,7 @@ - + diff --git a/files/mygui/openmw_count_window.layout b/files/mygui/openmw_count_window.layout index 520d49fa3..2e083dcea 100644 --- a/files/mygui/openmw_count_window.layout +++ b/files/mygui/openmw_count_window.layout @@ -16,12 +16,12 @@ - + - + - + diff --git a/files/mygui/openmw_trade_window.layout b/files/mygui/openmw_trade_window.layout index 0af9d59fe..30e22302d 100644 --- a/files/mygui/openmw_trade_window.layout +++ b/files/mygui/openmw_trade_window.layout @@ -48,7 +48,7 @@ - + @@ -62,7 +62,7 @@ - + From f89393fd6244e38ff4abed1f7a317d29599dc453 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sun, 2 Sep 2018 18:08:49 +0400 Subject: [PATCH 080/196] Validate 'ttf resolution' option value --- apps/openmw/mwgui/windowmanagerimp.cpp | 2 +- docs/source/reference/modding/settings/GUI.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 493a14a1c..03cbc3ef2 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -309,7 +309,7 @@ namespace MWGui // to allow to configure font size via config file, without need to edit XML file. // Also we should take UI scaling factor in account int resolution = Settings::Manager::getInt("ttf resolution", "GUI"); - resolution = std::max(0, resolution); + resolution = std::min(960, std::max(48, resolution)); float uiScale = Settings::Manager::getFloat("scaling factor", "GUI"); diff --git a/docs/source/reference/modding/settings/GUI.rst b/docs/source/reference/modding/settings/GUI.rst index 3fe943b6f..2092096c9 100644 --- a/docs/source/reference/modding/settings/GUI.rst +++ b/docs/source/reference/modding/settings/GUI.rst @@ -27,7 +27,7 @@ ttf resolution -------------- :Type: integer -:Range: > 0 +:Range: 48 to 960 :Default: 96 Allows to specify resolution for in-game TrueType fonts. From c9c0230d2ac6a2fb8798608cf36c3ec487a9ab27 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Mon, 3 Sep 2018 20:45:04 +0400 Subject: [PATCH 081/196] Scale journal fonts separately from common ones --- apps/openmw/mwgui/bookpage.cpp | 23 +++++-- apps/openmw/mwgui/bookpage.hpp | 2 +- apps/openmw/mwgui/formatting.cpp | 2 +- apps/openmw/mwgui/formatting.hpp | 2 +- apps/openmw/mwgui/windowmanagerimp.cpp | 67 +++++++++++++++---- components/fontloader/fontloader.cpp | 15 +++++ components/sdlutil/sdlvideowrapper.cpp | 5 ++ .../source/reference/modding/settings/GUI.rst | 2 +- files/mygui/openmw_book.layout | 2 + files/mygui/openmw_journal.layout | 2 + files/mygui/openmw_journal.skin.xml | 4 +- 11 files changed, 102 insertions(+), 24 deletions(-) diff --git a/apps/openmw/mwgui/bookpage.cpp b/apps/openmw/mwgui/bookpage.cpp index 8f2e8b5ed..8e264312e 100644 --- a/apps/openmw/mwgui/bookpage.cpp +++ b/apps/openmw/mwgui/bookpage.cpp @@ -264,18 +264,29 @@ struct TypesetBookImpl::Typesetter : BookTypesetter { } - Style * createStyle (char const * fontName, const Colour& fontColour) + Style * createStyle (const std::string& fontName, const Colour& fontColour) { - if (strcmp(fontName, "") == 0) - return createStyle(MyGUI::FontManager::getInstance().getDefaultFont().c_str(), fontColour); + const std::string templateName = "Journalbook "; + std::string bookFont; + if (fontName.empty()) + { + bookFont = MyGUI::FontManager::getInstance().getDefaultFont(); + bookFont = templateName + bookFont; + return createStyle(bookFont, fontColour); + } + + if (fontName.compare(0, templateName.size(), templateName) == 0) + bookFont = fontName; + else + bookFont = templateName + bookFont; for (Styles::iterator i = mBook->mStyles.begin (); i != mBook->mStyles.end (); ++i) - if (i->match (fontName, fontColour, fontColour, fontColour, 0)) + if (i->match (bookFont.c_str(), fontColour, fontColour, fontColour, 0)) return &*i; - MyGUI::IFont* font = MyGUI::FontManager::getInstance().getByName(fontName); + MyGUI::IFont* font = MyGUI::FontManager::getInstance().getByName(bookFont); if (!font) - throw std::runtime_error(std::string("can't find font ") + fontName); + throw std::runtime_error(std::string("can't find font ") + bookFont); StyleImpl & style = *mBook->mStyles.insert (mBook->mStyles.end (), StyleImpl ()); style.mFont = font; diff --git a/apps/openmw/mwgui/bookpage.hpp b/apps/openmw/mwgui/bookpage.hpp index b8174bd3d..c75f00ca4 100644 --- a/apps/openmw/mwgui/bookpage.hpp +++ b/apps/openmw/mwgui/bookpage.hpp @@ -102,7 +102,7 @@ namespace MWGui static Ptr create (int pageWidth, int pageHeight); /// Create a simple text style consisting of a font and a text color. - virtual Style* createStyle (char const * Font, const Colour& Colour) = 0; + virtual Style* createStyle (const std::string& fontName, const Colour& colour) = 0; /// Create a hyper-link style with a user-defined identifier based on an /// existing style. The unique flag forces a new instance of this style diff --git a/apps/openmw/mwgui/formatting.cpp b/apps/openmw/mwgui/formatting.cpp index 157aeba26..fd5ed4faa 100644 --- a/apps/openmw/mwgui/formatting.cpp +++ b/apps/openmw/mwgui/formatting.cpp @@ -377,7 +377,7 @@ namespace MWGui if (attr.find("face") != attr.end()) { std::string face = attr.at("face"); - mTextStyle.mFont = face; + mTextStyle.mFont = "Journalbook "+face; } if (attr.find("size") != attr.end()) { diff --git a/apps/openmw/mwgui/formatting.hpp b/apps/openmw/mwgui/formatting.hpp index 7ccb0824e..6d98d48b3 100644 --- a/apps/openmw/mwgui/formatting.hpp +++ b/apps/openmw/mwgui/formatting.hpp @@ -14,7 +14,7 @@ namespace MWGui { TextStyle() : mColour(0,0,0) - , mFont("Default") + , mFont("") , mTextSize(16) { } diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 03cbc3ef2..f4723da47 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -293,47 +293,90 @@ namespace MWGui void WindowManager::loadFontDelegate(MyGUI::xml::ElementPtr _node, const std::string& _file, MyGUI::Version _version) { - MyGUI::xml::ElementEnumerator root = _node->getElementEnumerator(); - while (root.next("Resource")) + const std::string templateName = "Journalbook "; + MyGUI::xml::ElementEnumerator font = _node->getElementEnumerator(); + bool createCopy = false; + while (font.next("Resource")) { std::string type, name; - root->findAttribute("type", type); - root->findAttribute("name", name); + font->findAttribute("type", type); + font->findAttribute("name", name); if (name.empty()) continue; if (Misc::StringUtils::ciEqual(type, "ResourceTrueTypeFont")) { + createCopy = true; + // For TrueType fonts we should override Size and Resolution properties - // to allow to configure font size via config file, without need to edit XML file. - // Also we should take UI scaling factor in account + // to allow to configure font size via config file, without need to edit XML files. + // Also we should take UI scaling factor in account. int resolution = Settings::Manager::getInt("ttf resolution", "GUI"); resolution = std::min(960, std::max(48, resolution)); float uiScale = Settings::Manager::getFloat("scaling factor", "GUI"); + resolution *= uiScale; - if (uiScale > 1.0f) - resolution *= uiScale; - - MyGUI::xml::ElementPtr resolutionNode = root->createChild("Property"); + MyGUI::xml::ElementPtr resolutionNode = font->createChild("Property"); resolutionNode->addAttribute("key", "Resolution"); resolutionNode->addAttribute("value", std::to_string(resolution)); - MyGUI::xml::ElementPtr sizeNode = root->createChild("Property"); + MyGUI::xml::ElementPtr sizeNode = font->createChild("Property"); sizeNode->addAttribute("key", "Size"); sizeNode->addAttribute("value", std::to_string(mFontHeight)); } else if (Misc::StringUtils::ciEqual(type, "ResourceSkin")) { // We should adjust line height for MyGUI widgets depending on font size - MyGUI::xml::ElementPtr heightNode = root->createChild("Property"); + MyGUI::xml::ElementPtr heightNode = font->createChild("Property"); heightNode->addAttribute("key", "HeightLine"); heightNode->addAttribute("value", std::to_string(mFontHeight+2)); } } MyGUI::ResourceManager::getInstance().loadFromXmlNode(_node, _file, _version); + + if (createCopy) + { + MyGUI::xml::ElementPtr copy = _node->createCopy(); + + MyGUI::xml::ElementEnumerator copyFont = copy->getElementEnumerator(); + while (copyFont.next("Resource")) + { + std::string type, name; + copyFont->findAttribute("type", type); + copyFont->findAttribute("name", name); + + if (name.empty()) + continue; + + if (Misc::StringUtils::ciEqual(type, "ResourceTrueTypeFont")) + { + // Since the journal and books use the custom scaling factor depending on resolution, + // setup separate fonts with different Resolution to fit these windows. + // These fonts have an internal prefix. + int resolution = Settings::Manager::getInt("ttf resolution", "GUI"); + resolution = std::min(960, std::max(48, resolution)); + + float currentX = Settings::Manager::getInt("resolution x", "Video"); + float currentY = Settings::Manager::getInt("resolution y", "Video"); + // TODO: read size from openmw_layout.xml + float heightScale = (currentY / 520); + float widthScale = (currentX / 600); + float uiScale = std::min(widthScale, heightScale); + resolution *= uiScale; + + MyGUI::xml::ElementPtr resolutionNode = copyFont->createChild("Property"); + resolutionNode->addAttribute("key", "Resolution"); + resolutionNode->addAttribute("value", std::to_string(resolution)); + + copyFont->setAttribute("name", "Journalbook " + name); + } + } + + MyGUI::ResourceManager::getInstance().loadFromXmlNode(copy, _file, _version); + } } void WindowManager::initUI() diff --git a/components/fontloader/fontloader.cpp b/components/fontloader/fontloader.cpp index 37214a038..adcdd2d14 100644 --- a/components/fontloader/fontloader.cpp +++ b/components/fontloader/fontloader.cpp @@ -480,6 +480,14 @@ namespace Gui font->deserialization(root, MyGUI::Version(3,2,0)); + // Setup "book" version of font as fallback if we will not use TrueType fonts + MyGUI::ResourceManualFont* bookFont = static_cast( + MyGUI::FactoryManager::getInstance().createObject("Resource", "ResourceManualFont")); + mFonts.push_back(bookFont); + bookFont->deserialization(root, MyGUI::Version(3,2,0)); + bookFont->setResourceName("Journalbook " + resourceName); + + // Remove automatically registered fonts for (std::vector::iterator it = mFonts.begin(); it != mFonts.end();) { if ((*it)->getResourceName() == font->getResourceName()) @@ -487,10 +495,17 @@ namespace Gui MyGUI::ResourceManager::getInstance().removeByName(font->getResourceName()); it = mFonts.erase(it); } + else if ((*it)->getResourceName() == bookFont->getResourceName()) + { + MyGUI::ResourceManager::getInstance().removeByName(bookFont->getResourceName()); + it = mFonts.erase(it); + } else ++it; } + MyGUI::ResourceManager::getInstance().addResource(font); + MyGUI::ResourceManager::getInstance().addResource(bookFont); } } diff --git a/components/sdlutil/sdlvideowrapper.cpp b/components/sdlutil/sdlvideowrapper.cpp index c2963be86..d5c8833ea 100644 --- a/components/sdlutil/sdlvideowrapper.cpp +++ b/components/sdlutil/sdlvideowrapper.cpp @@ -2,6 +2,8 @@ #include +#include + #include #include @@ -89,6 +91,9 @@ namespace SDLUtil SDL_SetWindowSize(mWindow, width, height); SDL_SetWindowBordered(mWindow, windowBorder ? SDL_TRUE : SDL_FALSE); } + + // We should reload TrueType fonts for new resolution + MyGUI::ResourceManager::getInstance().load("openmw_font.xml"); } } diff --git a/docs/source/reference/modding/settings/GUI.rst b/docs/source/reference/modding/settings/GUI.rst index 2092096c9..c8f4e16f8 100644 --- a/docs/source/reference/modding/settings/GUI.rst +++ b/docs/source/reference/modding/settings/GUI.rst @@ -31,7 +31,7 @@ ttf resolution :Default: 96 Allows to specify resolution for in-game TrueType fonts. -Note: actual resolution depends on "scaling factor" setting value, this value is for 1.0 or lower scaling factor. +Note: actual resolution depends on "scaling factor" setting value, this value is for 1.0 scaling factor. menu transparency ----------------- diff --git a/files/mygui/openmw_book.layout b/files/mygui/openmw_book.layout index c83c4982b..e6f0f858c 100644 --- a/files/mygui/openmw_book.layout +++ b/files/mygui/openmw_book.layout @@ -32,11 +32,13 @@ + + diff --git a/files/mygui/openmw_journal.layout b/files/mygui/openmw_journal.layout index 0d3a71ab5..5d6e29066 100644 --- a/files/mygui/openmw_journal.layout +++ b/files/mygui/openmw_journal.layout @@ -25,10 +25,12 @@ + + diff --git a/files/mygui/openmw_journal.skin.xml b/files/mygui/openmw_journal.skin.xml index e9eecba79..0702d8c5e 100644 --- a/files/mygui/openmw_journal.skin.xml +++ b/files/mygui/openmw_journal.skin.xml @@ -2,7 +2,7 @@ - + @@ -19,7 +19,7 @@ - + From 7a986f38da71544f1d9f6965942ba7463c1e7055 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Tue, 4 Sep 2018 09:15:07 +0400 Subject: [PATCH 082/196] Support for user-defined TrueType fonts --- apps/openmw/engine.cpp | 2 +- apps/openmw/mwbase/windowmanager.hpp | 2 ++ apps/openmw/mwgui/windowmanagerimp.cpp | 15 +++++++++++---- apps/openmw/mwgui/windowmanagerimp.hpp | 5 +++-- apps/openmw/mwinput/inputmanagerimp.cpp | 3 +++ components/fontloader/fontloader.cpp | 24 ++++++++++++++++++++++-- components/fontloader/fontloader.hpp | 9 +++++++-- components/sdlutil/sdlvideowrapper.cpp | 5 ----- 8 files changed, 49 insertions(+), 16 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 2941ede1b..057113ba3 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -516,7 +516,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) MWGui::WindowManager* window = new MWGui::WindowManager(mViewer, guiRoot, mResourceSystem.get(), mWorkQueue.get(), mCfgMgr.getLogPath().string() + std::string("/"), myguiResources, mScriptConsoleMode, mTranslationDataStorage, mEncoding, mExportFonts, mFallbackMap, - Version::getOpenmwVersionDescription(mResDir.string())); + Version::getOpenmwVersionDescription(mResDir.string()), mCfgMgr.getUserConfigPath().string()); mEnvironment.setWindowManager (window); // Create sound system diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index b40f517f9..fb0be30e4 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -290,6 +290,8 @@ namespace MWBase /// Warning: do not use MyGUI::InputManager::setKeyFocusWidget directly. Instead use this. virtual void setKeyFocusWidget (MyGUI::Widget* widget) = 0; + virtual void loadUserFonts() = 0; + virtual Loading::Listener* getLoadingScreen() = 0; /// Should the cursor be visible? diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index f4723da47..481a9ec00 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -38,6 +38,7 @@ #include #include +#include #include #include #include @@ -131,8 +132,8 @@ namespace MWGui WindowManager::WindowManager( osgViewer::Viewer* viewer, osg::Group* guiRoot, Resource::ResourceSystem* resourceSystem, SceneUtil::WorkQueue* workQueue, - const std::string& logpath, const std::string& resourcePath, bool consoleOnlyScripts, - Translation::Storage& translationDataStorage, ToUTF8::FromType encoding, bool exportFonts, const std::map& fallbackMap, const std::string& versionDescription) + const std::string& logpath, const std::string& resourcePath, bool consoleOnlyScripts, Translation::Storage& translationDataStorage, + ToUTF8::FromType encoding, bool exportFonts, const std::map& fallbackMap, const std::string& versionDescription, const std::string& userDataPath) : mStore(NULL) , mResourceSystem(resourceSystem) , mWorkQueue(workQueue) @@ -210,8 +211,8 @@ namespace MWGui MyGUI::LanguageManager::getInstance().eventRequestTag = MyGUI::newDelegate(this, &WindowManager::onRetrieveTag); // Load fonts - mFontLoader.reset(new Gui::FontLoader(encoding, resourceSystem->getVFS())); - mFontLoader->loadAllFonts(exportFonts); + mFontLoader.reset(new Gui::FontLoader(encoding, resourceSystem->getVFS(), userDataPath)); + mFontLoader->loadBitmapFonts(exportFonts); //Register own widgets with MyGUI MyGUI::FactoryManager::getInstance().registerFactory("Widget"); @@ -245,6 +246,7 @@ namespace MWGui MyGUI::FactoryManager::getInstance().registerFactory("Resource", "ResourceImageSetPointer"); MyGUI::ResourceManager::getInstance().load("core.xml"); + loadUserFonts(); bool keyboardNav = Settings::Manager::getBool("keyboard navigation", "GUI"); mKeyboardNavigation.reset(new KeyboardNavigation()); @@ -379,6 +381,11 @@ namespace MWGui } } + void WindowManager::loadUserFonts() + { + mFontLoader->loadTrueTypeFonts(); + } + void WindowManager::initUI() { // Get size info from the Gui object diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index f3bf6d00f..547701496 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -131,14 +131,15 @@ namespace MWGui typedef std::vector FactionList; WindowManager(osgViewer::Viewer* viewer, osg::Group* guiRoot, Resource::ResourceSystem* resourceSystem, SceneUtil::WorkQueue* workQueue, - const std::string& logpath, const std::string& cacheDir, bool consoleOnlyScripts, - Translation::Storage& translationDataStorage, ToUTF8::FromType encoding, bool exportFonts, const std::map& fallbackMap, const std::string& versionDescription); + const std::string& logpath, const std::string& cacheDir, bool consoleOnlyScripts, Translation::Storage& translationDataStorage, + ToUTF8::FromType encoding, bool exportFonts, const std::map& fallbackMap, const std::string& versionDescription, const std::string& localPath); virtual ~WindowManager(); /// Set the ESMStore to use for retrieving of GUI-related strings. void setStore (const MWWorld::ESMStore& store); void initUI(); + virtual void loadUserFonts(); virtual Loading::Listener* getLoadingScreen(); diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index b24c8cc14..ec9ead595 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -676,6 +676,9 @@ namespace MWInput Settings::Manager::getInt("resolution y", "Video"), Settings::Manager::getBool("fullscreen", "Video"), Settings::Manager::getBool("window border", "Video")); + + // We should reload TrueType fonts to fit new resolution + MWBase::Environment::get().getWindowManager()->loadUserFonts(); } } diff --git a/components/fontloader/fontloader.cpp b/components/fontloader/fontloader.cpp index adcdd2d14..0378e294e 100644 --- a/components/fontloader/fontloader.cpp +++ b/components/fontloader/fontloader.cpp @@ -145,8 +145,9 @@ namespace namespace Gui { - FontLoader::FontLoader(ToUTF8::FromType encoding, const VFS::Manager* vfs) + FontLoader::FontLoader(ToUTF8::FromType encoding, const VFS::Manager* vfs, const std::string& userDataPath) : mVFS(vfs) + , mUserDataPath(userDataPath) { if (encoding == ToUTF8::WINDOWS_1252) mEncoding = ToUTF8::CP437; @@ -175,7 +176,7 @@ namespace Gui mFonts.clear(); } - void FontLoader::loadAllFonts(bool exportToFile) + void FontLoader::loadBitmapFonts(bool exportToFile) { const std::map& index = mVFS->getIndex(); @@ -198,6 +199,25 @@ namespace Gui } } + void FontLoader::loadTrueTypeFonts() + { + osgMyGUI::DataManager* dataManager = dynamic_cast(&osgMyGUI::DataManager::getInstance()); + if (!dataManager) + { + Log(Debug::Error) << "Can not load TrueType fonts: osgMyGUI::DataManager is not available."; + return; + } + + const std::string cfg = dataManager->getDataPath(""); + const std::string fontFile = mUserDataPath + "/" + "Fonts" + "/" + "openmw_font.xml"; + if (!boost::filesystem::exists(fontFile)) + return; + + dataManager->setResourcePath(mUserDataPath + "/" + "Fonts"); + MyGUI::ResourceManager::getInstance().load("openmw_font.xml"); + dataManager->setResourcePath(cfg); + } + typedef struct { diff --git a/components/fontloader/fontloader.hpp b/components/fontloader/fontloader.hpp index b92815f13..39301f9f5 100644 --- a/components/fontloader/fontloader.hpp +++ b/components/fontloader/fontloader.hpp @@ -1,6 +1,9 @@ #ifndef OPENMW_COMPONENTS_FONTLOADER_H #define OPENMW_COMPONENTS_FONTLOADER_H +#include "boost/filesystem/operations.hpp" + +#include #include namespace VFS @@ -23,15 +26,17 @@ namespace Gui class FontLoader { public: - FontLoader (ToUTF8::FromType encoding, const VFS::Manager* vfs); + FontLoader (ToUTF8::FromType encoding, const VFS::Manager* vfs, const std::string& userDataPath); ~FontLoader(); /// @param exportToFile export the converted fonts (Images and XML with glyph metrics) to files? - void loadAllFonts (bool exportToFile); + void loadBitmapFonts (bool exportToFile); + void loadTrueTypeFonts (); private: ToUTF8::FromType mEncoding; const VFS::Manager* mVFS; + std::string mUserDataPath; std::vector mTextures; std::vector mFonts; diff --git a/components/sdlutil/sdlvideowrapper.cpp b/components/sdlutil/sdlvideowrapper.cpp index d5c8833ea..c2963be86 100644 --- a/components/sdlutil/sdlvideowrapper.cpp +++ b/components/sdlutil/sdlvideowrapper.cpp @@ -2,8 +2,6 @@ #include -#include - #include #include @@ -91,9 +89,6 @@ namespace SDLUtil SDL_SetWindowSize(mWindow, width, height); SDL_SetWindowBordered(mWindow, windowBorder ? SDL_TRUE : SDL_FALSE); } - - // We should reload TrueType fonts for new resolution - MyGUI::ResourceManager::getInstance().load("openmw_font.xml"); } } From e300a16b24a0f8881549f4c97afb86466ef4612b Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Tue, 4 Sep 2018 12:19:50 +0400 Subject: [PATCH 083/196] Use field for columns count instead of out integer --- apps/openmw/mwgui/journalbooks.cpp | 16 ++++++++-------- apps/openmw/mwgui/journalbooks.hpp | 7 ++++--- apps/openmw/mwgui/journalwindow.cpp | 5 ++--- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwgui/journalbooks.cpp b/apps/openmw/mwgui/journalbooks.cpp index 1956ee1c2..4302740f6 100644 --- a/apps/openmw/mwgui/journalbooks.cpp +++ b/apps/openmw/mwgui/journalbooks.cpp @@ -157,7 +157,7 @@ MWGui::BookTypesetter::Utf8Span to_utf8_span (char const * text) typedef TypesetBook::Ptr book; JournalBooks::JournalBooks (JournalViewModel::Ptr model, ToUTF8::FromType encoding) : - mModel (model), mEncoding(encoding) + mModel (model), mEncoding(encoding), mIndexPagesCount(0) { } @@ -218,23 +218,23 @@ book JournalBooks::createQuestBook (const std::string& questName) return typesetter->complete (); } -book JournalBooks::createTopicIndexBook (int& columnsCount) +book JournalBooks::createTopicIndexBook () { bool isRussian = (mEncoding == ToUTF8::WINDOWS_1251); - BookTypesetter::Ptr typesetter = isRussian ? createCyrillicJournalIndex(columnsCount) : createLatinJournalIndex(columnsCount); + BookTypesetter::Ptr typesetter = isRussian ? createCyrillicJournalIndex() : createLatinJournalIndex(); return typesetter->complete (); } -BookTypesetter::Ptr JournalBooks::createLatinJournalIndex (int& columnsCount) +BookTypesetter::Ptr JournalBooks::createLatinJournalIndex () { BookTypesetter::Ptr typesetter = BookTypesetter::create (92, 260); typesetter->setSectionAlignment (BookTypesetter::AlignCenter); // Latin journal index always has two columns for now. - columnsCount = 2; + mIndexPagesCount = 2; char ch = 'A'; @@ -261,7 +261,7 @@ BookTypesetter::Ptr JournalBooks::createLatinJournalIndex (int& columnsCount) return typesetter; } -BookTypesetter::Ptr JournalBooks::createCyrillicJournalIndex (int& columnsCount) +BookTypesetter::Ptr JournalBooks::createCyrillicJournalIndex () { BookTypesetter::Ptr typesetter = BookTypesetter::create (92, 260); @@ -273,11 +273,11 @@ BookTypesetter::Ptr JournalBooks::createCyrillicJournalIndex (int& columnsCount) // for small font size split alphabet to two columns (2x15 characers), for big font size split it to three colums (3x10 characters). int sectionBreak = 10; - columnsCount = 3; + mIndexPagesCount = 3; if (fontHeight < 18) { sectionBreak = 15; - columnsCount = 2; + mIndexPagesCount = 2; } unsigned char ch[2] = {0xd0, 0x90}; // CYRILLIC CAPITAL A is a 0xd090 in UTF-8 diff --git a/apps/openmw/mwgui/journalbooks.hpp b/apps/openmw/mwgui/journalbooks.hpp index cc6f42cc8..05eda6e22 100644 --- a/apps/openmw/mwgui/journalbooks.hpp +++ b/apps/openmw/mwgui/journalbooks.hpp @@ -22,14 +22,15 @@ namespace MWGui Book createTopicBook (uintptr_t topicId); Book createTopicBook (const std::string& topicId); Book createQuestBook (const std::string& questName); - Book createTopicIndexBook (int& columnsCount); + Book createTopicIndexBook (); ToUTF8::FromType mEncoding; + int mIndexPagesCount; private: BookTypesetter::Ptr createTypesetter (); - BookTypesetter::Ptr createLatinJournalIndex (int& columnsCount); - BookTypesetter::Ptr createCyrillicJournalIndex (int& columnsCount); + BookTypesetter::Ptr createLatinJournalIndex (); + BookTypesetter::Ptr createCyrillicJournalIndex (); }; } diff --git a/apps/openmw/mwgui/journalwindow.cpp b/apps/openmw/mwgui/journalwindow.cpp index cef20159d..a2f6ea142 100644 --- a/apps/openmw/mwgui/journalwindow.cpp +++ b/apps/openmw/mwgui/journalwindow.cpp @@ -465,11 +465,10 @@ namespace { setOptionsMode (); - int pagesCount; if (!mTopicIndexBook) - mTopicIndexBook = createTopicIndexBook (pagesCount); + mTopicIndexBook = createTopicIndexBook (); - if (pagesCount == 3) + if (mIndexPagesCount == 3) { getPage (LeftTopicIndex)->showPage (mTopicIndexBook, 0); getPage (CenterTopicIndex)->showPage (mTopicIndexBook, 1); From 664c630ac023c5dc0b2d3cc313efb41bfeb2db14 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Wed, 12 Sep 2018 16:00:33 +0300 Subject: [PATCH 084/196] Don't make sTo strings static references --- apps/openmw/mwgui/spellcreationdialog.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/spellcreationdialog.cpp b/apps/openmw/mwgui/spellcreationdialog.cpp index b4713291b..f3f104e3c 100644 --- a/apps/openmw/mwgui/spellcreationdialog.cpp +++ b/apps/openmw/mwgui/spellcreationdialog.cpp @@ -147,7 +147,7 @@ namespace MWGui mDurationValue->setCaption("1"); mMagnitudeMinValue->setCaption("1"); - static const std::string &to = MWBase::Environment::get().getWindowManager()->getGameSettingString("sTo", "-"); + const std::string to = MWBase::Environment::get().getWindowManager()->getGameSettingString("sTo", "-"); mMagnitudeMaxValue->setCaption(to + " 1"); mAreaValue->setCaption("0"); @@ -314,7 +314,7 @@ namespace MWGui } mEffect.mMagnMax = pos+1; - static const std::string &to = MWBase::Environment::get().getWindowManager()->getGameSettingString("sTo", "-"); + const std::string to = MWBase::Environment::get().getWindowManager()->getGameSettingString("sTo", "-"); mMagnitudeMaxValue->setCaption(to + " " + MyGUI::utility::toString(pos+1)); From 275d10e1f724824adf293119a9e4fcc77c30245c Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Fri, 27 Jul 2018 23:45:25 +0400 Subject: [PATCH 085/196] Add missing icons for UniversalId tables and use them in the editor menu (feature #912) --- CHANGELOG.md | 1 + apps/opencs/model/prefs/state.cpp | 1 + apps/opencs/model/world/universalid.cpp | 133 ++++----- apps/opencs/model/world/universalid.hpp | 21 +- apps/opencs/view/doc/view.cpp | 254 ++++++------------ apps/opencs/view/doc/view.hpp | 2 + files/opencs/cell.png | Bin 223 -> 1212 bytes files/opencs/debug-profile.png | Bin 0 -> 431 bytes files/opencs/edit-undo.png | Bin 650 -> 0 bytes files/opencs/error-log.png | Bin 0 -> 518 bytes files/opencs/{Info.png => info.png} | Bin files/opencs/instance.png | Bin 0 -> 618 bytes ...led-creature.png => levelled-creature.png} | Bin .../{leveled-item.png => levelled-item.png} | Bin files/opencs/magic-effect.png | Bin 325 -> 356 bytes files/opencs/menu-close.png | Bin 0 -> 438 bytes files/opencs/menu-exit.png | Bin 0 -> 257 bytes files/opencs/menu-merge.png | Bin 0 -> 219 bytes files/opencs/menu-new-addon.png | Bin 0 -> 282 bytes files/opencs/menu-new-game.png | Bin 0 -> 230 bytes files/opencs/menu-new-window.png | Bin 0 -> 213 bytes files/opencs/menu-open.png | Bin 0 -> 241 bytes files/opencs/menu-preferences.png | Bin 0 -> 385 bytes files/opencs/menu-redo.png | Bin 0 -> 323 bytes files/opencs/menu-reload.png | Bin 0 -> 447 bytes files/opencs/menu-save.png | Bin 0 -> 302 bytes files/opencs/menu-search.png | Bin 0 -> 408 bytes files/opencs/menu-status-bar.png | Bin 0 -> 188 bytes files/opencs/menu-undo.png | Bin 0 -> 323 bytes files/opencs/menu-verify.png | Bin 0 -> 487 bytes files/opencs/metadata.png | Bin 0 -> 389 bytes files/opencs/object.png | Bin 0 -> 447 bytes files/opencs/placeholder.png | Bin 2383 -> 2142 bytes files/opencs/region-map.png | Bin 0 -> 428 bytes files/opencs/region.png | Bin 320 -> 605 bytes files/opencs/resources.qrc | 36 ++- files/opencs/run-log.png | Bin 0 -> 294 bytes files/opencs/run-openmw.png | Bin 0 -> 388 bytes files/opencs/scene.png | Bin 0 -> 401 bytes files/opencs/start-script.png | Bin 0 -> 359 bytes files/opencs/stop-openmw.png | Bin 0 -> 252 bytes 41 files changed, 216 insertions(+), 232 deletions(-) create mode 100644 files/opencs/debug-profile.png delete mode 100644 files/opencs/edit-undo.png create mode 100644 files/opencs/error-log.png rename files/opencs/{Info.png => info.png} (100%) create mode 100644 files/opencs/instance.png rename files/opencs/{leveled-creature.png => levelled-creature.png} (100%) rename files/opencs/{leveled-item.png => levelled-item.png} (100%) create mode 100644 files/opencs/menu-close.png create mode 100644 files/opencs/menu-exit.png create mode 100644 files/opencs/menu-merge.png create mode 100644 files/opencs/menu-new-addon.png create mode 100644 files/opencs/menu-new-game.png create mode 100644 files/opencs/menu-new-window.png create mode 100644 files/opencs/menu-open.png create mode 100644 files/opencs/menu-preferences.png create mode 100644 files/opencs/menu-redo.png create mode 100644 files/opencs/menu-reload.png create mode 100644 files/opencs/menu-save.png create mode 100644 files/opencs/menu-search.png create mode 100644 files/opencs/menu-status-bar.png create mode 100644 files/opencs/menu-undo.png create mode 100644 files/opencs/menu-verify.png create mode 100644 files/opencs/metadata.png create mode 100644 files/opencs/object.png create mode 100644 files/opencs/region-map.png create mode 100644 files/opencs/run-log.png create mode 100644 files/opencs/run-openmw.png create mode 100644 files/opencs/scene.png create mode 100644 files/opencs/start-script.png create mode 100644 files/opencs/stop-openmw.png diff --git a/CHANGELOG.md b/CHANGELOG.md index 44cb90afd..2ae2a38a4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -119,6 +119,7 @@ Bug #4622: Recharging enchanted items with Soul Gems does not award experience if it fails Bug #4628: NPC record reputation, disposition and faction rank should have unsigned char type Bug #4633: Sneaking stance affects speed even if the actor is not able to crouch + Feature #912: Editor: Add missing icons to UniversalId tables Feature #1645: Casting effects from objects Feature #2606: Editor: Implemented (optional) case sensitive global search Feature #3083: Play animation when NPC is casting spell via script diff --git a/apps/opencs/model/prefs/state.cpp b/apps/opencs/model/prefs/state.cpp index a704fb825..b6a55ea86 100644 --- a/apps/opencs/model/prefs/state.cpp +++ b/apps/opencs/model/prefs/state.cpp @@ -305,6 +305,7 @@ void CSMPrefs::State::declare() declareShortcut ("document-assets-videos", "Open Video Asset List", QKeySequence()); declareShortcut ("document-debug-run", "Run Debug", QKeySequence()); declareShortcut ("document-debug-shutdown", "Stop Debug", QKeySequence()); + declareShortcut ("document-debug-profiles", "Debug Profiles", QKeySequence()); declareShortcut ("document-debug-runlog", "Open Run Log", QKeySequence()); declareSubcategory ("Table"); diff --git a/apps/opencs/model/world/universalid.cpp b/apps/opencs/model/world/universalid.cpp index 8d7a7761e..6f9eeb24f 100644 --- a/apps/opencs/model/world/universalid.cpp +++ b/apps/opencs/model/world/universalid.cpp @@ -18,47 +18,60 @@ namespace static const TypeData sNoArg[] = { { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, "-", 0 }, - { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Globals, "Global Variables", 0 }, - { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Gmsts, "Game Settings", 0 }, - { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Skills, "Skills", 0 }, - { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Classes, "Classes", 0 }, - { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Factions, "Factions", 0 }, - { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Races, "Races", 0 }, - { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Sounds, "Sounds", 0 }, - { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Scripts, "Scripts", 0 }, - { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Regions, "Regions", 0 }, - { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Birthsigns, "Birthsigns", 0 }, - { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Spells, "Spells", 0 }, - { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Topics, "Topics", 0 }, - { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Journals, "Journals", 0 }, - { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_TopicInfos, "Topic Infos", 0 }, - { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_JournalInfos, "Journal Infos", 0 }, - { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Cells, "Cells", 0 }, - { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Enchantments, "Enchantments", 0 }, - { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_BodyParts, "Body Parts", 0 }, - { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Referenceables, - "Objects", 0 }, - { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_References, - "Instances", 0 }, - { CSMWorld::UniversalId::Class_NonRecord, CSMWorld::UniversalId::Type_RegionMap, - "Region Map", 0 }, - { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Filters, "Filters", 0 }, - { CSMWorld::UniversalId::Class_ResourceList, CSMWorld::UniversalId::Type_Meshes, "Meshes", 0 }, - { CSMWorld::UniversalId::Class_ResourceList, CSMWorld::UniversalId::Type_Icons, "Icons", 0 }, - { CSMWorld::UniversalId::Class_ResourceList, CSMWorld::UniversalId::Type_Musics, "Music Files", 0 }, - { CSMWorld::UniversalId::Class_ResourceList, CSMWorld::UniversalId::Type_SoundsRes, "Sound Files", 0 }, - { CSMWorld::UniversalId::Class_ResourceList, CSMWorld::UniversalId::Type_Textures, "Textures", 0 }, - { CSMWorld::UniversalId::Class_ResourceList, CSMWorld::UniversalId::Type_Videos, "Videos", 0 }, - { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_DebugProfiles, "Debug Profiles", 0 }, - { CSMWorld::UniversalId::Class_Transient, CSMWorld::UniversalId::Type_RunLog, "Run Log", 0 }, - { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_SoundGens, "Sound Generators", 0 }, - { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_MagicEffects, "Magic Effects", 0 }, - { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Lands, "Lands", 0 }, - { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_LandTextures, "LandTextures", 0 }, - { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Pathgrids, "Pathgrids", 0 }, - { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_StartScripts, "Start Scripts", 0 }, - { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_MetaDatas, "Meta Data Table", 0 }, - + { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Globals, "Global Variables", ":./global-variable.png" }, + { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Gmsts, "Game Settings", ":./gmst.png" }, + { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Skills, "Skills", ":./skill.png" }, + { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Classes, "Classes", ":./class.png" }, + { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Factions, "Factions", ":./faction.png" }, + { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Races, "Races", ":./race.png" }, + { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Sounds, "Sounds", ":./sound.png" }, + { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Scripts, "Scripts", ":./script.png" }, + { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Regions, "Regions", ":./region.png" }, + { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Birthsigns, "Birthsigns", ":./birthsign.png" }, + { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Spells, "Spells", ":./spell.png" }, + { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Topics, "Topics", ":./dialogue-topics.png" }, + { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Journals, "Journals", ":./journal-topics.png" }, + { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_TopicInfos, "Topic Infos", ":./dialogue-topic-infos.png" }, + { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_JournalInfos, "Journal Infos", ":./journal-topic-infos.png" }, + { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Cells, "Cells", ":./cell.png" }, + { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Enchantments, "Enchantments", ":./enchantment.png" }, + { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_BodyParts, "Body Parts", ":./body-part.png" }, + { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Referenceables, "Objects", ":./object.png" }, + { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_References, "Instances", ":./instance.png" }, + { CSMWorld::UniversalId::Class_NonRecord, CSMWorld::UniversalId::Type_RegionMap, "Region Map", ":./region-map.png" }, + { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Filters, "Filters", ":./filter.png" }, + { CSMWorld::UniversalId::Class_ResourceList, CSMWorld::UniversalId::Type_Meshes, "Meshes", ":./resources-mesh" }, + { CSMWorld::UniversalId::Class_ResourceList, CSMWorld::UniversalId::Type_Icons, "Icons", ":./resources-icon" }, + { CSMWorld::UniversalId::Class_ResourceList, CSMWorld::UniversalId::Type_Musics, "Music Files", ":./resources-music" }, + { CSMWorld::UniversalId::Class_ResourceList, CSMWorld::UniversalId::Type_SoundsRes, "Sound Files", ":resources-sound" }, + { CSMWorld::UniversalId::Class_ResourceList, CSMWorld::UniversalId::Type_Textures, "Textures", ":./resources-texture" }, + { CSMWorld::UniversalId::Class_ResourceList, CSMWorld::UniversalId::Type_Videos, "Videos", ":./resources-video" }, + { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_DebugProfiles, "Debug Profiles", ":./debug-profile.png" }, + { CSMWorld::UniversalId::Class_Transient, CSMWorld::UniversalId::Type_RunLog, "Run Log", ":./run-log.png" }, + { CSMWorld::UniversalId::Class_Transient, CSMWorld::UniversalId::Type_RunGame, "Run OpenMW", ":./run-openmw.png" }, + { CSMWorld::UniversalId::Class_Transient, CSMWorld::UniversalId::Type_StopGame, "Stop OpenMW", ":./stop-openmw.png" }, + { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_SoundGens, "Sound Generators", ":./sound-generator.png" }, + { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_MagicEffects, "Magic Effects", ":./magic-effect.png" }, + { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Lands, "Lands", ":./land-heightmap.png" }, + { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_LandTextures, "Land Textures", ":./land-texture.png" }, + { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Pathgrids, "Pathgrids", ":./pathgrid.png" }, + { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_StartScripts, "Start Scripts", ":./start-script.png" }, + { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_MetaDatas, "Metadata", ":./metadata.png" }, + { CSMWorld::UniversalId::Class_Transient, CSMWorld::UniversalId::Type_Redo, "Redo", ":./menu-redo.png" }, + { CSMWorld::UniversalId::Class_Transient, CSMWorld::UniversalId::Type_Undo, "Undo", ":./menu-undo.png" }, + { CSMWorld::UniversalId::Class_Transient, CSMWorld::UniversalId::Type_Preferences, "Preferences", ":./menu-preferences.png" }, + { CSMWorld::UniversalId::Class_Transient, CSMWorld::UniversalId::Type_Reload, "Reload", ":./menu-reload.png" }, + { CSMWorld::UniversalId::Class_Transient, CSMWorld::UniversalId::Type_NewWindow, "New View", ":./menu-new-window.png" }, + { CSMWorld::UniversalId::Class_Transient, CSMWorld::UniversalId::Type_StatusBar, "Toggle Status Bar", ":./menu-status-bar.png" }, + { CSMWorld::UniversalId::Class_Transient, CSMWorld::UniversalId::Type_NewGame, "New Game", ":./menu-new-game.png" }, + { CSMWorld::UniversalId::Class_Transient, CSMWorld::UniversalId::Type_NewAddon, "New Addon", ":./menu-new-addon.png" }, + { CSMWorld::UniversalId::Class_Transient, CSMWorld::UniversalId::Type_Open, "Open", ":./menu-open.png" }, + { CSMWorld::UniversalId::Class_Transient, CSMWorld::UniversalId::Type_Save, "Save", ":./menu-save.png" }, + { CSMWorld::UniversalId::Class_Transient, CSMWorld::UniversalId::Type_Verify, "Verify", ":./menu-verify.png" }, + { CSMWorld::UniversalId::Class_Transient, CSMWorld::UniversalId::Type_Merge, "Merge", ":./menu-merge.png" }, + { CSMWorld::UniversalId::Class_Transient, CSMWorld::UniversalId::Type_ErrorLog, "Error Log", ":./error-log.png" }, + { CSMWorld::UniversalId::Class_Transient, CSMWorld::UniversalId::Type_Close, "Close", ":./menu-close.png" }, + { CSMWorld::UniversalId::Class_Transient, CSMWorld::UniversalId::Type_Exit, "Exit", ":./menu-exit.png" }, { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0, 0 } // end marker }; @@ -81,7 +94,7 @@ namespace { CSMWorld::UniversalId::Class_SubRecord, CSMWorld::UniversalId::Type_JournalInfo, "JournalInfo", ":./journal-topic-infos.png" }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Cell, "Cell", ":./cell.png" }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Cell_Missing, "Cell", ":./cell.png" }, - { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Referenceable, "Object", 0 }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Referenceable, "Object", ":./object.png" }, { CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Activator, "Activator", ":./activator.png" }, { CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Potion, "Potion", ":./potion.png" }, { CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Apparatus, "Apparatus", ":./apparatus.png" }, @@ -93,9 +106,9 @@ namespace { CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Door, "Door", ":./door.png" }, { CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Ingredient, "Ingredient", ":./ingredient.png" }, { CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_CreatureLevelledList, - "Creature Levelled List", ":./leveled-creature.png" }, + "Creature Levelled List", ":./levelled-creature.png" }, { CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_ItemLevelledList, - "Item Levelled List", ":./leveled-item.png" }, + "Item Levelled List", ":./levelled-item.png" }, { CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Light, "Light", ":./light.png" }, { CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Lockpick, "Lockpick", ":./lockpick.png" }, { CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Miscellaneous, @@ -105,35 +118,35 @@ namespace { CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Repair, "Repair", ":./repair.png" }, { CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Static, "Static", ":./static.png" }, { CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Weapon, "Weapon", ":./weapon.png" }, - { CSMWorld::UniversalId::Class_SubRecord, CSMWorld::UniversalId::Type_Reference, "Instance", 0 }, + { CSMWorld::UniversalId::Class_SubRecord, CSMWorld::UniversalId::Type_Reference, "Instance", ":./instance.png" }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Filter, "Filter", ":./filter.png" }, - { CSMWorld::UniversalId::Class_Collection, CSMWorld::UniversalId::Type_Scene, "Scene", 0 }, - { CSMWorld::UniversalId::Class_Collection, CSMWorld::UniversalId::Type_Preview, "Preview", 0 }, + { CSMWorld::UniversalId::Class_Collection, CSMWorld::UniversalId::Type_Scene, "Scene", ":./scene.png" }, + { CSMWorld::UniversalId::Class_Collection, CSMWorld::UniversalId::Type_Preview, "Preview", ":./record-preview.png" }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Enchantment, "Enchantment", ":./enchantment.png" }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_BodyPart, "Body Part", ":./body-part.png" }, - { CSMWorld::UniversalId::Class_Resource, CSMWorld::UniversalId::Type_Mesh, "Mesh", ":resources-mesh"}, - { CSMWorld::UniversalId::Class_Resource, CSMWorld::UniversalId::Type_Icon, "Icon", ":resources-icon"}, - { CSMWorld::UniversalId::Class_Resource, CSMWorld::UniversalId::Type_Music, "Music", ":resources-music" }, - { CSMWorld::UniversalId::Class_Resource, CSMWorld::UniversalId::Type_SoundRes, "Sound File", ":resources-sound" }, - { CSMWorld::UniversalId::Class_Resource, CSMWorld::UniversalId::Type_Texture, "Texture", ":resources-texture"}, - { CSMWorld::UniversalId::Class_Resource, CSMWorld::UniversalId::Type_Video, "Video", ":resources-video"}, - { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_DebugProfile, "Debug Profile", 0 }, + { CSMWorld::UniversalId::Class_Resource, CSMWorld::UniversalId::Type_Mesh, "Mesh", ":./resources-mesh"}, + { CSMWorld::UniversalId::Class_Resource, CSMWorld::UniversalId::Type_Icon, "Icon", ":./resources-icon"}, + { CSMWorld::UniversalId::Class_Resource, CSMWorld::UniversalId::Type_Music, "Music", ":./resources-music" }, + { CSMWorld::UniversalId::Class_Resource, CSMWorld::UniversalId::Type_SoundRes, "Sound File", ":./resources-sound" }, + { CSMWorld::UniversalId::Class_Resource, CSMWorld::UniversalId::Type_Texture, "Texture", ":./resources-texture" }, + { CSMWorld::UniversalId::Class_Resource, CSMWorld::UniversalId::Type_Video, "Video", ":./resources-video" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_DebugProfile, "Debug Profile", ":./debug-profile.png" }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_SoundGen, "Sound Generator", ":./sound-generator.png" }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_MagicEffect, "Magic Effect", ":./magic-effect.png" }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Land, "Land", ":./land-heightmap.png" }, - { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_LandTexture, "LandTexture", ":./land-texture.png" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_LandTexture, "Land Texture", ":./land-texture.png" }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Pathgrid, "Pathgrid", ":./pathgrid.png" }, - { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_StartScript, "Start Script", 0 }, - { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_MetaData, "Meta Data", 0 }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_StartScript, "Start Script", ":./start-script.png" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_MetaData, "Metadata", ":./metadata.png" }, { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0, 0 } // end marker }; static const TypeData sIndexArg[] = { - { CSMWorld::UniversalId::Class_Transient, CSMWorld::UniversalId::Type_VerificationResults, "Verification Results", 0 }, - { CSMWorld::UniversalId::Class_Transient, CSMWorld::UniversalId::Type_LoadErrorLog, "Load Error Log", 0 }, - { CSMWorld::UniversalId::Class_Transient, CSMWorld::UniversalId::Type_Search, "Global Search", 0 }, + { CSMWorld::UniversalId::Class_Transient, CSMWorld::UniversalId::Type_VerificationResults, "Verification Results", ":./menu-verify.png" }, + { CSMWorld::UniversalId::Class_Transient, CSMWorld::UniversalId::Type_LoadErrorLog, "Load Error Log", ":./error-log.png" }, + { CSMWorld::UniversalId::Class_Transient, CSMWorld::UniversalId::Type_Search, "Global Search", ":./menu-search.png" }, { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0, 0 } // end marker }; } diff --git a/apps/opencs/model/world/universalid.hpp b/apps/opencs/model/world/universalid.hpp index accd1b78d..aa5276ba7 100644 --- a/apps/opencs/model/world/universalid.hpp +++ b/apps/opencs/model/world/universalid.hpp @@ -137,10 +137,27 @@ namespace CSMWorld Type_Search, Type_MetaDatas, Type_MetaData, - Type_RunLog + Type_RunLog, + Type_RunGame, + Type_StopGame, + Type_Undo, + Type_Redo, + Type_Preferences, + Type_NewWindow, + Type_StatusBar, + Type_NewGame, + Type_NewAddon, + Type_Open, + Type_Save, + Type_Verify, + Type_Merge, + Type_ErrorLog, + Type_Close, + Type_Exit, + Type_Reload }; - enum { NumberOfTypes = Type_RunLog+1 }; + enum { NumberOfTypes = Type_Reload+1 }; private: diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 3ebefd69a..97aaac4d7 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -47,58 +47,40 @@ void CSVDoc::View::setupFileMenu() { QMenu *file = menuBar()->addMenu (tr ("File")); - QAction *newGame = new QAction (tr ("New Game"), this); + QAction* newGame = createMenuEntry(CSMWorld::UniversalId::Type_NewGame, file, "document-file-newgame"); connect (newGame, SIGNAL (triggered()), this, SIGNAL (newGameRequest())); - setupShortcut("document-file-newgame", newGame); - file->addAction (newGame); - - QAction *newAddon = new QAction (tr ("New Addon"), this); + QAction* newAddon = createMenuEntry(CSMWorld::UniversalId::Type_NewAddon, file, "document-file-newaddon"); connect (newAddon, SIGNAL (triggered()), this, SIGNAL (newAddonRequest())); - setupShortcut("document-file-newaddon", newAddon); - file->addAction (newAddon); - QAction *open = new QAction (tr ("Open"), this); + QAction* open = createMenuEntry(CSMWorld::UniversalId::Type_Open, file, "document-file-open"); connect (open, SIGNAL (triggered()), this, SIGNAL (loadDocumentRequest())); - setupShortcut("document-file-open", open); - file->addAction (open); - mSave = new QAction (tr ("Save"), this); - connect (mSave, SIGNAL (triggered()), this, SLOT (save())); - setupShortcut("document-file-save", mSave); - file->addAction (mSave); + QAction* save = createMenuEntry(CSMWorld::UniversalId::Type_Save, file, "document-file-save"); + connect (save, SIGNAL (triggered()), this, SLOT (save())); + mSave = save; - mVerify = new QAction (tr ("Verify"), this); - connect (mVerify, SIGNAL (triggered()), this, SLOT (verify())); - setupShortcut("document-file-verify", mVerify); - file->addAction (mVerify); + QAction* verify = createMenuEntry(CSMWorld::UniversalId::Type_Verify, file, "document-file-verify"); + connect (verify, SIGNAL (triggered()), this, SLOT (verify())); + mVerify = verify; - mMerge = new QAction (tr ("Merge"), this); - connect (mMerge, SIGNAL (triggered()), this, SLOT (merge())); - setupShortcut("document-file-merge", mMerge); - file->addAction (mMerge); + QAction* merge = createMenuEntry(CSMWorld::UniversalId::Type_Merge, file, "document-file-merge"); + connect (merge, SIGNAL (triggered()), this, SLOT (merge())); + mMerge = merge; - QAction *loadErrors = new QAction (tr ("Open Load Error Log"), this); + QAction* loadErrors = createMenuEntry(CSMWorld::UniversalId::Type_ErrorLog, file, "document-file-errorlog"); connect (loadErrors, SIGNAL (triggered()), this, SLOT (loadErrorLog())); - setupShortcut("document-file-errorlog", loadErrors); - file->addAction (loadErrors); - QAction *meta = new QAction (tr ("Meta Data"), this); + QAction* meta = createMenuEntry(CSMWorld::UniversalId::Type_MetaDatas, file, "document-file-metadata"); connect (meta, SIGNAL (triggered()), this, SLOT (addMetaDataSubView())); - setupShortcut("document-file-metadata", meta); - file->addAction (meta); - QAction *close = new QAction (tr ("Close Document"), this); + QAction* close = createMenuEntry(CSMWorld::UniversalId::Type_Close, file, "document-file-close"); connect (close, SIGNAL (triggered()), this, SLOT (close())); - setupShortcut("document-file-close", close); - file->addAction(close); - QAction *exit = new QAction (tr ("Exit Application"), this); + QAction* exit = createMenuEntry(CSMWorld::UniversalId::Type_Exit, file, "document-file-exit"); connect (exit, SIGNAL (triggered()), this, SLOT (exit())); - connect (this, SIGNAL(exitApplicationRequest(CSVDoc::View *)), &mViewManager, SLOT(exitApplication(CSVDoc::View *))); - setupShortcut("document-file-exit", exit); - file->addAction(exit); + connect (this, SIGNAL(exitApplicationRequest(CSVDoc::View *)), &mViewManager, SLOT(exitApplication(CSVDoc::View *))); } namespace @@ -130,251 +112,180 @@ void CSVDoc::View::setupEditMenu() mUndo = mDocument->getUndoStack().createUndoAction (this, tr("Undo")); setupShortcut("document-edit-undo", mUndo); connect(mUndo, SIGNAL (changed ()), this, SLOT (undoActionChanged ())); + std::string iconName = CSMWorld::UniversalId (CSMWorld::UniversalId::Type_Undo).getIcon(); + if (!iconName.empty() && iconName != ":placeholder") + mUndo->setIcon(QIcon(QString::fromStdString(iconName))); + edit->addAction (mUndo); mRedo = mDocument->getUndoStack().createRedoAction (this, tr("Redo")); connect(mRedo, SIGNAL (changed ()), this, SLOT (redoActionChanged ())); setupShortcut("document-edit-redo", mRedo); + iconName = CSMWorld::UniversalId (CSMWorld::UniversalId::Type_Redo).getIcon(); + if (!iconName.empty() && iconName != ":placeholder") + mRedo->setIcon(QIcon(QString::fromStdString(iconName))); + edit->addAction (mRedo); - QAction *userSettings = new QAction (tr ("Preferences"), this); + QAction* userSettings = createMenuEntry(CSMWorld::UniversalId::Type_Preferences, edit, "document-edit-preferences"); connect (userSettings, SIGNAL (triggered()), this, SIGNAL (editSettingsRequest())); - setupShortcut("document-edit-preferences", userSettings); - edit->addAction (userSettings); - QAction *search = new QAction (tr ("Search"), this); + QAction* search = createMenuEntry(CSMWorld::UniversalId::Type_Search, edit, "document-edit-search"); connect (search, SIGNAL (triggered()), this, SLOT (addSearchSubView())); - setupShortcut("document-edit-search", search); - edit->addAction (search); } void CSVDoc::View::setupViewMenu() { QMenu *view = menuBar()->addMenu (tr ("View")); - QAction *newWindow = new QAction (tr ("New View"), this); + QAction *newWindow = createMenuEntry(CSMWorld::UniversalId::Type_NewWindow, view, "document-view-newview"); connect (newWindow, SIGNAL (triggered()), this, SLOT (newView())); - setupShortcut("document-view-newview", newWindow); - view->addAction (newWindow); - mShowStatusBar = new QAction (tr ("Toggle Status Bar"), this); - mShowStatusBar->setCheckable (true); + mShowStatusBar = createMenuEntry(CSMWorld::UniversalId::Type_StatusBar, view, "document-view-statusbar"); connect (mShowStatusBar, SIGNAL (toggled (bool)), this, SLOT (toggleShowStatusBar (bool))); - setupShortcut("document-view-statusbar", mShowStatusBar); - + mShowStatusBar->setCheckable (true); mShowStatusBar->setChecked (CSMPrefs::get()["Windows"]["show-statusbar"].isTrue()); view->addAction (mShowStatusBar); - QAction *filters = new QAction (tr ("Filters"), this); + QAction *filters = createMenuEntry(CSMWorld::UniversalId::Type_Filters, view, "document-mechanics-filters"); connect (filters, SIGNAL (triggered()), this, SLOT (addFiltersSubView())); - setupShortcut("document-view-filters", filters); - view->addAction (filters); } void CSVDoc::View::setupWorldMenu() { QMenu *world = menuBar()->addMenu (tr ("World")); - QAction *regions = new QAction (tr ("Regions"), this); + QAction* regions = createMenuEntry(CSMWorld::UniversalId::Type_Regions, world, "document-world-regions"); connect (regions, SIGNAL (triggered()), this, SLOT (addRegionsSubView())); - setupShortcut("document-world-regions", regions); - world->addAction (regions); - QAction *cells = new QAction (tr ("Cells"), this); + QAction* cells = createMenuEntry(CSMWorld::UniversalId::Type_Cells, world, "document-world-cells"); connect (cells, SIGNAL (triggered()), this, SLOT (addCellsSubView())); - setupShortcut("document-world-cells", cells); - world->addAction (cells); - QAction *referenceables = new QAction (tr ("Objects"), this); + QAction* referenceables = createMenuEntry(CSMWorld::UniversalId::Type_Referenceables, world, "document-world-referencables"); connect (referenceables, SIGNAL (triggered()), this, SLOT (addReferenceablesSubView())); - setupShortcut("document-world-referencables", referenceables); - world->addAction (referenceables); - QAction *references = new QAction (tr ("Instances"), this); + QAction* references = createMenuEntry(CSMWorld::UniversalId::Type_References, world, "document-world-references"); connect (references, SIGNAL (triggered()), this, SLOT (addReferencesSubView())); - setupShortcut("document-world-references", references); - world->addAction (references); - QAction *lands = new QAction (tr ("Lands"), this); + QAction *lands = createMenuEntry(CSMWorld::UniversalId::Type_Lands, world, "document-world-lands"); connect (lands, SIGNAL (triggered()), this, SLOT (addLandsSubView())); - setupShortcut("document-world-lands", lands); - world->addAction (lands); - QAction *landTextures = new QAction (tr ("Land Textures"), this); + QAction *landTextures = createMenuEntry(CSMWorld::UniversalId::Type_LandTextures, world, "document-world-landtextures"); connect (landTextures, SIGNAL (triggered()), this, SLOT (addLandTexturesSubView())); - setupShortcut("document-world-landtextures", landTextures); - world->addAction (landTextures); - QAction *grid = new QAction (tr ("Pathgrid"), this); + QAction *grid = createMenuEntry(CSMWorld::UniversalId::Type_Pathgrids, world, "document-world-pathgrid"); connect (grid, SIGNAL (triggered()), this, SLOT (addPathgridSubView())); - setupShortcut("document-world-pathgrid", grid); - world->addAction (grid); world->addSeparator(); // items that don't represent single record lists follow here - QAction *regionMap = new QAction (tr ("Region Map"), this); + QAction *regionMap = createMenuEntry(CSMWorld::UniversalId::Type_RegionMap, world, "document-world-regionmap"); connect (regionMap, SIGNAL (triggered()), this, SLOT (addRegionMapSubView())); - setupShortcut("document-world-regionmap", regionMap); - world->addAction (regionMap); } void CSVDoc::View::setupMechanicsMenu() { QMenu *mechanics = menuBar()->addMenu (tr ("Mechanics")); - QAction *globals = new QAction (tr ("Globals"), this); + QAction* globals = createMenuEntry(CSMWorld::UniversalId::Type_Globals, mechanics, "document-mechanics-globals"); connect (globals, SIGNAL (triggered()), this, SLOT (addGlobalsSubView())); - setupShortcut("document-mechanics-globals", globals); - mechanics->addAction (globals); - QAction *gmsts = new QAction (tr ("Game Settings"), this); + QAction* gmsts = createMenuEntry(CSMWorld::UniversalId::Type_Gmsts, mechanics, "document-mechanics-gamesettings"); connect (gmsts, SIGNAL (triggered()), this, SLOT (addGmstsSubView())); - setupShortcut("document-mechanics-gamesettings", gmsts); - mechanics->addAction (gmsts); - QAction *scripts = new QAction (tr ("Scripts"), this); + QAction* scripts = createMenuEntry(CSMWorld::UniversalId::Type_Scripts, mechanics, "document-mechanics-scripts"); connect (scripts, SIGNAL (triggered()), this, SLOT (addScriptsSubView())); - setupShortcut("document-mechanics-scripts", scripts); - mechanics->addAction (scripts); - QAction *spells = new QAction (tr ("Spells"), this); + QAction* spells = createMenuEntry(CSMWorld::UniversalId::Type_Spells, mechanics, "document-mechanics-spells"); connect (spells, SIGNAL (triggered()), this, SLOT (addSpellsSubView())); - setupShortcut("document-mechanics-spells", spells); - mechanics->addAction (spells); - QAction *enchantments = new QAction (tr ("Enchantments"), this); + QAction* enchantments = createMenuEntry(CSMWorld::UniversalId::Type_Enchantments, mechanics, "document-mechanics-enchantments"); connect (enchantments, SIGNAL (triggered()), this, SLOT (addEnchantmentsSubView())); - setupShortcut("document-mechanics-enchantments", enchantments); - mechanics->addAction (enchantments); - QAction *effects = new QAction (tr ("Magic Effects"), this); - connect (effects, SIGNAL (triggered()), this, SLOT (addMagicEffectsSubView())); - setupShortcut("document-mechanics-magiceffects", effects); - mechanics->addAction (effects); + QAction* magicEffects = createMenuEntry(CSMWorld::UniversalId::Type_MagicEffects, mechanics, "document-mechanics-magiceffects"); + connect (magicEffects, SIGNAL (triggered()), this, SLOT (addMagicEffectsSubView())); - QAction *startScripts = new QAction (tr ("Start Scripts"), this); + QAction* startScripts = createMenuEntry(CSMWorld::UniversalId::Type_StartScripts, mechanics, "document-mechanics-startscripts"); connect (startScripts, SIGNAL (triggered()), this, SLOT (addStartScriptsSubView())); - setupShortcut("document-mechanics-startscripts", startScripts); - mechanics->addAction (startScripts); } void CSVDoc::View::setupCharacterMenu() { QMenu *characters = menuBar()->addMenu (tr ("Characters")); - QAction *skills = new QAction (tr ("Skills"), this); + QAction* skills = createMenuEntry(CSMWorld::UniversalId::Type_Skills, characters, "document-character-skills"); connect (skills, SIGNAL (triggered()), this, SLOT (addSkillsSubView())); - setupShortcut("document-character-skills", skills); - characters->addAction (skills); - QAction *classes = new QAction (tr ("Classes"), this); + QAction* classes = createMenuEntry(CSMWorld::UniversalId::Type_Classes, characters, "document-character-classes"); connect (classes, SIGNAL (triggered()), this, SLOT (addClassesSubView())); - setupShortcut("document-character-classes", classes); - characters->addAction (classes); - QAction *factions = new QAction (tr ("Factions"), this); + QAction* factions = createMenuEntry(CSMWorld::UniversalId::Type_Faction, characters, "document-character-factions"); connect (factions, SIGNAL (triggered()), this, SLOT (addFactionsSubView())); - setupShortcut("document-character-factions", factions); - characters->addAction (factions); - QAction *races = new QAction (tr ("Races"), this); + QAction* races = createMenuEntry(CSMWorld::UniversalId::Type_Races, characters, "document-character-races"); connect (races, SIGNAL (triggered()), this, SLOT (addRacesSubView())); - setupShortcut("document-character-races", races); - characters->addAction (races); - QAction *birthsigns = new QAction (tr ("Birthsigns"), this); + QAction* birthsigns = createMenuEntry(CSMWorld::UniversalId::Type_Birthsigns, characters, "document-character-birthsigns"); connect (birthsigns, SIGNAL (triggered()), this, SLOT (addBirthsignsSubView())); - setupShortcut("document-character-birthsigns", birthsigns); - characters->addAction (birthsigns); - QAction *topics = new QAction (tr ("Topics"), this); + QAction* topics = createMenuEntry(CSMWorld::UniversalId::Type_Topics, characters, "document-character-topics"); connect (topics, SIGNAL (triggered()), this, SLOT (addTopicsSubView())); - setupShortcut("document-character-topics", topics); - characters->addAction (topics); - QAction *journals = new QAction (tr ("Journals"), this); + QAction* journals = createMenuEntry(CSMWorld::UniversalId::Type_Journals, characters, "document-character-journals"); connect (journals, SIGNAL (triggered()), this, SLOT (addJournalsSubView())); - setupShortcut("document-character-journals", journals); - characters->addAction (journals); - QAction *topicInfos = new QAction (tr ("Topic Infos"), this); + QAction* topicInfos = createMenuEntry(CSMWorld::UniversalId::Type_TopicInfos, characters, "document-character-topicinfos"); connect (topicInfos, SIGNAL (triggered()), this, SLOT (addTopicInfosSubView())); - setupShortcut("document-character-topicinfos", topicInfos); - characters->addAction (topicInfos); - QAction *journalInfos = new QAction (tr ("Journal Infos"), this); + QAction* journalInfos = createMenuEntry(CSMWorld::UniversalId::Type_JournalInfos, characters, "document-character-journalinfos"); connect (journalInfos, SIGNAL (triggered()), this, SLOT (addJournalInfosSubView())); - setupShortcut("document-character-journalinfos", journalInfos); - characters->addAction (journalInfos); - QAction *bodyParts = new QAction (tr ("Body Parts"), this); + QAction* bodyParts = createMenuEntry(CSMWorld::UniversalId::Type_BodyParts, characters, "document-character-bodyparts"); connect (bodyParts, SIGNAL (triggered()), this, SLOT (addBodyPartsSubView())); - setupShortcut("document-character-bodyparts", bodyParts); - characters->addAction (bodyParts); } void CSVDoc::View::setupAssetsMenu() { QMenu *assets = menuBar()->addMenu (tr ("Assets")); - QAction *reload = new QAction (tr ("Reload"), this); + QAction* reload = createMenuEntry(CSMWorld::UniversalId::Type_Reload, assets, "document-assets-reload"); connect (reload, SIGNAL (triggered()), &mDocument->getData(), SLOT (assetsChanged())); - setupShortcut("document-assets-reload", reload); - assets->addAction (reload); assets->addSeparator(); - QAction *sounds = new QAction (tr ("Sounds"), this); + QAction* sounds = createMenuEntry(CSMWorld::UniversalId::Type_Sounds, assets, "document-assets-sounds"); connect (sounds, SIGNAL (triggered()), this, SLOT (addSoundsSubView())); - setupShortcut("document-assets-sounds", sounds); - assets->addAction (sounds); - QAction *soundGens = new QAction (tr ("Sound Generators"), this); + QAction* soundGens = createMenuEntry(CSMWorld::UniversalId::Type_SoundGens, assets, "document-assets-soundgens"); connect (soundGens, SIGNAL (triggered()), this, SLOT (addSoundGensSubView())); - setupShortcut("document-assets-soundgens", soundGens); - assets->addAction (soundGens); assets->addSeparator(); // resources follow here - QAction *meshes = new QAction (tr ("Meshes"), this); + QAction* meshes = createMenuEntry(CSMWorld::UniversalId::Type_Meshes, assets, "document-assets-meshes"); connect (meshes, SIGNAL (triggered()), this, SLOT (addMeshesSubView())); - setupShortcut("document-assets-meshes", meshes); - assets->addAction (meshes); - QAction *icons = new QAction (tr ("Icons"), this); + QAction* icons = createMenuEntry(CSMWorld::UniversalId::Type_Icons, assets, "document-assets-icons"); connect (icons, SIGNAL (triggered()), this, SLOT (addIconsSubView())); - setupShortcut("document-assets-icons", icons); - assets->addAction (icons); - QAction *musics = new QAction (tr ("Music"), this); + QAction* musics = createMenuEntry(CSMWorld::UniversalId::Type_Musics, assets, "document-assets-musics"); connect (musics, SIGNAL (triggered()), this, SLOT (addMusicsSubView())); - setupShortcut("document-assets-music", musics); - assets->addAction (musics); - QAction *soundsRes = new QAction (tr ("Sound Files"), this); - connect (soundsRes, SIGNAL (triggered()), this, SLOT (addSoundsResSubView())); - setupShortcut("document-assets-soundres", soundsRes); - assets->addAction (soundsRes); + QAction* soundFiles = createMenuEntry(CSMWorld::UniversalId::Type_SoundsRes, assets, "document-assets-soundres"); + connect (soundFiles, SIGNAL (triggered()), this, SLOT (addSoundsResSubView())); - QAction *textures = new QAction (tr ("Textures"), this); + QAction* textures = createMenuEntry(CSMWorld::UniversalId::Type_Textures, assets, "document-assets-textures"); connect (textures, SIGNAL (triggered()), this, SLOT (addTexturesSubView())); - setupShortcut("document-assets-textures", textures); - assets->addAction (textures); - QAction *videos = new QAction (tr ("Videos"), this); + QAction* videos = createMenuEntry(CSMWorld::UniversalId::Type_Videos, assets, "document-assets-videos"); connect (videos, SIGNAL (triggered()), this, SLOT (addVideosSubView())); - setupShortcut("document-assets-videos", videos); - assets->addAction (videos); } void CSVDoc::View::setupDebugMenu() { QMenu *debug = menuBar()->addMenu (tr ("Debug")); - QAction *profiles = new QAction (tr ("Debug Profiles"), this); + QAction* profiles = createMenuEntry(CSMWorld::UniversalId::Type_DebugProfiles, debug, "document-debug-profiles"); connect (profiles, SIGNAL (triggered()), this, SLOT (addDebugProfilesSubView())); - debug->addAction (profiles); debug->addSeparator(); @@ -387,18 +298,31 @@ void CSVDoc::View::setupDebugMenu() QAction *runDebug = debug->addMenu (mGlobalDebugProfileMenu); runDebug->setText (tr ("Run OpenMW")); - setupShortcut("document-debug-run", runDebug); + std::string iconName = CSMWorld::UniversalId (CSMWorld::UniversalId::Type_RunGame).getIcon(); + if (!iconName.empty() && iconName != ":placeholder") + runDebug->setIcon(QIcon(QString::fromStdString(iconName))); - mStopDebug = new QAction (tr ("Shutdown OpenMW"), this); - connect (mStopDebug, SIGNAL (triggered()), this, SLOT (stop())); - setupShortcut("document-debug-shutdown", mStopDebug); - debug->addAction (mStopDebug); + QAction* stopDebug = createMenuEntry(CSMWorld::UniversalId::Type_StopGame, debug, "document-debug-shutdown"); + connect (stopDebug, SIGNAL (triggered()), this, SLOT (stop())); + mStopDebug = stopDebug; - QAction *runLog = new QAction (tr ("Open Run Log"), this); + QAction* runLog = createMenuEntry(CSMWorld::UniversalId::Type_RunLog, debug, "document-debug-runlog"); connect (runLog, SIGNAL (triggered()), this, SLOT (addRunLogSubView())); - setupShortcut("document-debug-runlog", runLog); - debug->addAction (runLog); +} + +QAction* CSVDoc::View::createMenuEntry(CSMWorld::UniversalId::Type type, QMenu* menu, const char* shortcutName) +{ + const std::string title = CSMWorld::UniversalId (type).getTypeName(); + QAction *entry = new QAction(QString::fromStdString(title), this); + setupShortcut(shortcutName, entry); + const std::string iconName = CSMWorld::UniversalId (type).getIcon(); + if (!iconName.empty() && iconName != ":placeholder") + entry->setIcon(QIcon(QString::fromStdString(iconName))); + + menu->addAction (entry); + + return entry; } void CSVDoc::View::setupUi() diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp index 5418b7720..e767777d7 100644 --- a/apps/opencs/view/doc/view.hpp +++ b/apps/opencs/view/doc/view.hpp @@ -66,6 +66,8 @@ namespace CSVDoc void closeEvent (QCloseEvent *event); + QAction* createMenuEntry(CSMWorld::UniversalId::Type type, QMenu* menu, const char* shortcutName); + void setupFileMenu(); void setupEditMenu(); diff --git a/files/opencs/cell.png b/files/opencs/cell.png index 9127dd5e5c63b41333de5a564aef7c6f77808bf0..4c3fbe25154dfc8dfb1e6cbe8422c1dec6d932ce 100644 GIT binary patch delta 1172 zcmV;F1Z(@>0lW#2BYy+HdQ@0+Qek%>aB^>EX>4U6ba`-PAZ2)IW&i+q+O1Yuva2`@ z{nsjb36|t>ImSa(@1U38$KXp6LT(b?!v!*mCZ8jlQ2X!SPXFK%F`ldo(I@W>E}LwU zj7c=xwMjO1ea;v2GkMU{{)0fJkh;D4HtjR??&c8e)Gv>E3V&tBi8IhoStRZ&et0la;7z|Q2U*GDMG_-Wt|7)?F9bL>`x4y^rTe)u6q6U_Z}hh6VA_TIMDW$S^I zr@5$~rK~d;E`NYhS2vFla62-Axt7A`2!N|OL7 zQbbo>)F4U9N{StWy95wZ2^@(Qu%=MUUJI{z)0(evMCQt{6h<(H$J3xQ<(07q>V32> zvxz%as7pozqKv`Zc)|*VaG#jE72kExUEi2HVigR!6@TW41!l8sAr{BC-qMw4g`G2& z%+~H4>I?vgklUdcRxn^ZnwdSDAQG5?V+21Lm5W+gzyLcZm8pXp#ZCwkW#ooW;MG=~ zY-$`WAi}BF0BW#xK$f)*{S$0N4`rv$l5@_x;G#<|d-c{k?|ty&jLJcS4KDZ)LJTS7 zsL@6jeSZuw#uRgsq&UJ{@+nY?DW#l|G$V9|cZNmIi!8d>#VvjbOI*^D3)-jH;)*Y! z#F9#`Qnh0HS6>6wSX0f78(OK^=9+Jz#g{qBUXv6pUleM*~Yx3*X8lA9kr1o%{*B%*hjP90C|uT^xCh~8!T6|+Ca=<7gT z?SGiaQW<@Kk3`9@P@^|6e=O;He$H#BH;&!5b#eGmPs#o?7Tpx~-~mMZpY~DzxXwKr zebIH#-ghbKTToxsO0SFku2#AN>{&Fr0_<6BbOqS6lyn8yvs&p2uxGW>wVm}`D_sHh z#a{a!*t1&c`tEwHiLURi$CPw^cRkih?_-aw=M!r;?7AOb)Kc8e_tLa$)#k(fd2bG< z-R^kwqYoY5N_v;+MWUnKQ=q?A(WmlQ>1D9LuIN+DE`$BY7`;qHM_TcBGtvLJv`ovx ze0Gum000JJOGiWiO#n>*O(_oqIgue4e+P6)O+^Rd2?h%(5uJd2d;kCdeMv+?R5;7+ zlhFylAPht=(sc?hVzzOLZljA794P&0g(wkh{q6fScQJ4Y@Zd`nUm|AETBi%=eqffW zC10Xog%ASOv1UD5yXBl4BQpyC5K&_ixn(J(rm$H*^rF7G#$l1a!5{@@7Awa7Ce3Ux mig3jGD%Y#}y2|d&1zKE!{xaOcA~d)F0000 delta 178 zcmV;j08RhA3Eu&bBa;CH7JrdRL_t(I5$#ez4!|G?gJs{-$La%_CBrmmmfd!l2LWj- z0YvUoYqe6!5%H7VVh7otNStG=LJdh(6*F_o;Oqw`tPC{;h*dKw$BaFD@3R5`xgsXw zN1WE$DAxb<`1Ctn0Hr4nL!5K3y3T~`{{kZ0DWKatDl~2`PU_+m;3qjJ%n}9`iSJkW g$g8~6yLsULT$nUR2>SeoVgLXD07*qoM6N<$g2eAn82|tP diff --git a/files/opencs/debug-profile.png b/files/opencs/debug-profile.png new file mode 100644 index 0000000000000000000000000000000000000000..ddb01da4373c24e073eaa8780f2a1925d8e4c291 GIT binary patch literal 431 zcmV;g0Z{&lP)x>!fO`r}B#0U}7m4vO)L ze%-f*hFHKny78>*7F6o@9Wyw`w8k^_qV`xoD_*dn!6nV&UgIg6aviSFfm>|H0>X%5 zQd1npNnrg&n7}Hkw7k!d?}ls~p#o=dHZco_+K(su!yk}`Ij#M#W;5-=wLhRn(*6;! zg%6!v)B=)qB(|seE1ch2 z2}Yb(WEZv+3nAUa;B+8qvZK_S`?_ojxuzu|$ Zb6>EKPtoppBdGuY002ovPDHLkV1knC#qkSC&LBJ zfVRcM$?V1P3B6PcAX~#mZX7Dr0E-up6>u&Ai1M4+$6px*d6g)50zul{6fOZfD5 zx^(<(+NuITAZTdtF*`7sbB~Mx0Ae$D>fg&k;5u>{h0Ft(%sL2>YF!TkK|`BOGW-0q z$<55rD9F$#2!Mm7ygZedyZydz;2gN<0Fly!zty-=mBaVpcsEVu>hcW{d1#Z{npnGY zBY*fjmK0%?8^t(;YR@+XG=oH^Fxc%lEVS$r0NiT$nf{@pT|4*Ae2zV-96O_3`)`13 k>$j#pJbyuT?P=Bf1qBx3B`dxp6aWAK07*qoM6N<$g68)pi~s-t diff --git a/files/opencs/error-log.png b/files/opencs/error-log.png new file mode 100644 index 0000000000000000000000000000000000000000..df698d14531014feb9f4bd4b8f6cb7e0a6e79fe1 GIT binary patch literal 518 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCijSl0AZa85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP=d3- zBeIx*fm;ZK886+f`vVk|Dshb{3C>R|DNig)We7;j%q!9Ja}7}_GuAWJGc|_pf zf~Tj8V~B-+?_^)^!wv#%!mLx9az&?fami_EaEbY^tq9Ps@(eq|wP?W)Mx~~T&#%=v zUY(sRp0D)6-e}b$AYYtbYGHswzt4=u5fR32!1AmELWs z{eA3L=(WljtVdH$X{xm^V->5+IK=Sgkn)^^oHhsN-3>n1+t6rjvR{>XPL~|}@x%6T`X{OjY>=$&eym3zu zI(3&ND0F-5Ukg1WQH_M2m)$Dg|8G&?`1QNr_-kbx_wQRR0lw$cZUBRx!PC{xWt~$( F697;y!(jjb literal 0 HcmV?d00001 diff --git a/files/opencs/Info.png b/files/opencs/info.png similarity index 100% rename from files/opencs/Info.png rename to files/opencs/info.png diff --git a/files/opencs/instance.png b/files/opencs/instance.png new file mode 100644 index 0000000000000000000000000000000000000000..ce63e64ed66830118ed9c25e6b817be8d9f96909 GIT binary patch literal 618 zcmV-w0+s!VP)UGq2zJSnbXnj}@gMNyS!ybGM&f17qqb7rHS+D`Y8@40%+--0DA>#p^QU(d|223)fMBN$mC(w)k z4GvZmAEh}@Fb1OF2(ejk0HnZEnjQQCEEsFc_-E0<*y$JX(e8;4?*ff34gF>F=DUc>^9NrYBwnAHePvXegqyAk9fnD9R{FTuppn z(}j)$y~ah`(K!Qu0Ven-O30eiwe|+ZC-5(zmp~tw;HqP6`xZSy{wv%*KmnSxw(ghb z&ob;9JKJbI*%VEW;5KX9U~h&&@A0+jJdMG+d-I|G3k+|{pCe3}VE_OC07*qoM6N<$ Ef&wfNegFUf literal 0 HcmV?d00001 diff --git a/files/opencs/leveled-creature.png b/files/opencs/levelled-creature.png similarity index 100% rename from files/opencs/leveled-creature.png rename to files/opencs/levelled-creature.png diff --git a/files/opencs/leveled-item.png b/files/opencs/levelled-item.png similarity index 100% rename from files/opencs/leveled-item.png rename to files/opencs/levelled-item.png diff --git a/files/opencs/magic-effect.png b/files/opencs/magic-effect.png index 4901724c59a363d1ddffc137a17fa33a7c9712cc..44b682bf4ff359ce3c8076379cf27ccffa46f673 100644 GIT binary patch delta 309 zcmV-50m}Zx0^|aaIDY{aNklLCuHjy6z0As;Z-) zxq~wdyvXUgTfXz&J0^(G`?a`VoukVy{ww4o1>S55K4B{!_FZP zOGw}NUL@Hy`G@O!AGp451Pel(Q{==1D@~$!l)NT(Fs{x5aHKY|71*9DYA(}xN0D?ps*$%;ZIZLZ|NSq-Eppq5al4-Z1f{O$dr(g400000NkvXX Hu0mjf>~55q delta 278 zcmV+x0qOqa0>uK5IDY{5NklWd8N#j$ zZS9YnH2a)kVd}bK!!UHtxr9$jn?A;Pn&Cx7Hsrw&lT!zo6ze6RuLx`dC#}lJwe4Icz=Iua zkum>)5JKLdY*qaSg2^(1_1zL+KucCeDGFwB1!0C?$S6G_`HRp`7Miz+{jSojUE&u=k07*qoM6N<$f>i>0%K!iX diff --git a/files/opencs/menu-close.png b/files/opencs/menu-close.png new file mode 100644 index 0000000000000000000000000000000000000000..81bc986775089a2ab8b8113096c890a47785e84f GIT binary patch literal 438 zcmV;n0ZIOeP)_eP4v08QYouW`+TlKHqY~h g-$r@ga{kZ#4H#~PogGl%VgLXD07*qoM6N<$f?Wu@<^TWy literal 0 HcmV?d00001 diff --git a/files/opencs/menu-exit.png b/files/opencs/menu-exit.png new file mode 100644 index 0000000000000000000000000000000000000000..f583536fb695627bb749c8e742df32f37e845995 GIT binary patch literal 257 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`oCO|{#S9GG!XV7ZFl&wkP;j%S zi(`m|;L)Iif`<%vyo1~x&RF8ZkbH=3ZcCYHl8VLdecLiWy^yWD(y6Q2cS+!%Y#@8Z zSM!a%V%(O;BsO`JOV0bbL}HSw`BWdBlPzbN0#X;7xgOJ;J>z9nzN|tI-)sxE$?|lw*K7*&LpUXO@geCy5 CkYic^ literal 0 HcmV?d00001 diff --git a/files/opencs/menu-merge.png b/files/opencs/menu-merge.png new file mode 100644 index 0000000000000000000000000000000000000000..c76288ae168580eb28605cca6c82876f8a467639 GIT binary patch literal 219 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`oCO|{#S9GG!XV7ZFl&wkP_Wn2 z#WBP}@Mw@DUxNY<^VjMR;fMaatbV!a%-QCPCsLE&TJ4%}>Aw1B#;w;HZPGQD8ukf2 zx>Fs0vQ(K>N8;+q*)wc$cFN$M5XTG67GU&z$gXm3P*ne%c33&Br`ObTm(;sHX z2B&I1pA?od-|(3E`}>h>Z^Seb*T(MsKJ(4qc=OsMf!R|g86B&sI-#?mfc442-en9I zTI(~MChy4*O3V4?((D$wvpkC_sD5|Xw)DRo5Obi@&TU?oclyq6(>vU+-;`lY>2dcjb9C=}__=+$ cM*mmV)hqqBP323C1p14?)78&qol`;+0L{H`dH?_b literal 0 HcmV?d00001 diff --git a/files/opencs/menu-new-game.png b/files/opencs/menu-new-game.png new file mode 100644 index 0000000000000000000000000000000000000000..701daf34b179e4c2e507788fd38366f9d83c9c07 GIT binary patch literal 230 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`oCO|{#S9GG!XV7ZFl&wkP;iE) zi(`m|;M?Fpz6J#j*K1#|%-&+5~5+}}`+Zp=FKa9hVk!j1d-CNBj$lkWtcHpe!-tP?^(cYK51uD5Gc}kTEZqVBl zDLgA>p=XQoO?FjSQZyelF{r5}E+txm0xk literal 0 HcmV?d00001 diff --git a/files/opencs/menu-new-window.png b/files/opencs/menu-new-window.png new file mode 100644 index 0000000000000000000000000000000000000000..4a42da0d1288678a5bc4bd01a4713834f3aba7a0 GIT binary patch literal 213 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`oCO|{#S9GG!XV7ZFl&wkP_W(8 z#WBP}@a&{$p#}vGSHs)$^uoTgA7tmVnEGvoX1z%3>!%tAt}Cx-oFeqH%A{SOp(AOn zXt?jRv)ayGv32JvZ#ABcopUPXz_;0VuQ|n6A9K0&wD|l2aS6jfwst<34O1?yxy3DK zydi13!awf=jv^LL@`8(RT)7eT%${Ml{*m{uI=*idtt{Qkm|Cl~`N^Y5DWH=WJYD@< J);T3K0RY~_Pj&zR literal 0 HcmV?d00001 diff --git a/files/opencs/menu-open.png b/files/opencs/menu-open.png new file mode 100644 index 0000000000000000000000000000000000000000..3766e17549830ca741e42055f9de51faa0263226 GIT binary patch literal 241 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`oCO|{#S9GG!XV7ZFl&wkP;jxQ zi(`m|;M-tFp#}vGm)F(5Ch65K@NVz>D)x6iTdze%m~rV@Zk-L%icB>&T|bV^hKmsy{PJL1`?c#)bIR|DNig)We7;j%q!9Ja}7}_GuAWJGc|_p9 zb;Q%fF~q`u=_FgeLk2vplYKfC7fe@ae<-uT$iT3~EtJho@4%^2p+9SuczMr`2zYsN z?VtZwt(GqNkg;~^)^E8zmPaJcE4CzmEOdCk@QL=zR*Oykm)1@{T=zVtY0vl0No6|^ z$lX7BeG^x*)07%TTaOBPkK~VA-{g21IGArL|M+i`-ckvvC!zkq>6wkDCt@O)RmGa8<0ehNE3bfxb Z|CL*E(BR zh$s~OY9M~d^p1;H?c&h7l=#PCS+ z#x9>|~QaJOhytpOOywJKnq=q3<%szi> TOZHS?05EvE`njxgN@xNAl(>K= literal 0 HcmV?d00001 diff --git a/files/opencs/menu-reload.png b/files/opencs/menu-reload.png new file mode 100644 index 0000000000000000000000000000000000000000..2b780598c4162eed952e978ae557e465278f0085 GIT binary patch literal 447 zcmV;w0YLtVP)PGS7Qaa1b3$&sEeJkZubf1&Oe51JYd%SmYmz3wBv^o(wk+$D21{nnZwrGZXc+SW z?9#EOUGQ_ZZSO}>RD<6Z{?7v9$co&fRtdfkP6Xa(l2fKC!{2Ih3qDMZ0v}@AU{6Bz z4(jNO1#)#r3uRV}v;g-K{YpLs<(!;BrWnu@NS^$@qVk*tsTRUcr#b)47VhEL^(1Fbv;Z*HtX0>tt#fj9#%sAm8G002ovPDHLkV1nW%zJve( literal 0 HcmV?d00001 diff --git a/files/opencs/menu-save.png b/files/opencs/menu-save.png new file mode 100644 index 0000000000000000000000000000000000000000..4be88765bef48fc5b571e98b8c942dcca95934f8 GIT binary patch literal 302 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`oCO|{#S9GG!XV7ZFl&wkQ1F4L zi(`m|;Mw44p=Jf1Cl_Bo42|*+dhL7Uv*KOXLjgznjQ?h)nJCWA;Sg9_Cvx^rqJ+}c zYf(pM_~> zlD$gAKoo`NXTd`Jc>ocFP49~&C^lABR^qz&11?yp zm59X#wel4#Oav`$7oWhqf`y2}HYV|#T@ohljE!EHopaB*_vG$Pg!p4fyFU!WE2Y#{ zS(ZXdDT<=FNYnJduK9^oMbP{VUZ$y?B#Gn>$mii-sv7T2QOvn>6~I4mZd{t-TIPpw zJB&STup`#sJ~*2WZA?W`RC+~(-}KQA%+eTh#$^IOi~i-(3|B4j41DV;I)(3fG*Q1s zp7cu56K8{0HzZ#GpKGnx^E~gsU6M~kZD16dj<`-(sxp6z*yb!@vX4m@lh}}UGz@IP z#u)c8*>Ra@yU>TTEPGsR2Xj*`eH;YA8~LEBt(GW04_C@zZ*?@c3lHwoJtl~mq|ZdV z69!sIKBzJ6!tY4zpo_^h(CnreJhk434>vphDfrf1ZvFO7F0=P1S)EDdcINxOnVs8R&-+XBegA~lT!yPk5k(d9JH8IX@Flsj zIBh_&LUh9?6d%h9vbZUVjRqH`RNEx13Hbd+QS>C-(RgkVB$kpUSFj<%vlN1N$TxTo zt}D4*jQD|%as&YQ0bfYY9GYe9&;(c^tXo8qOj(u%xH}XCftKpr1d`0gOx4g@za{=t z0}A)JbraSt$j&lm=N9=E?{h{2$)yiTf+nWOyodOI8QVZJipM5!Hkvq1=-jYK_yOTy VK0Na~gXjPN002ovPDHLkV1lPsh4=sf literal 0 HcmV?d00001 diff --git a/files/opencs/menu-verify.png b/files/opencs/menu-verify.png new file mode 100644 index 0000000000000000000000000000000000000000..a7878ebb3f6c4c77230f8c080c0115dd7aefb765 GIT binary patch literal 487 zcmVQSK@^4eAtF{Hh@^M-7uZ;7z)DyvLBUEPpkRpF z2qM7;f{l%!2o|vj+KO8UHnC8_GL;ZWIxPf=g&`np*6&U-i&;|`yl`gbo_o%n$F5=g zGt9W(^SnX0ZPPT|9HtCNVdxbO(-+ev*uz{F?$1HP dUz_|ie*;IC(~hX{6SDvS002ovPDHLkV1m_N&5r;8 literal 0 HcmV?d00001 diff --git a/files/opencs/metadata.png b/files/opencs/metadata.png new file mode 100644 index 0000000000000000000000000000000000000000..34c78ffd61e30acaef3cc30960d59fe30979cc50 GIT binary patch literal 389 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCijSl0AZa85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP=d3- zBeIx*fm;ZK886+f`vVk|Dshb{3C>R|DNig)We7;j%q!9Ja}7}_GuAWJGc|_p9 zb;8rdF~q`uYVbkc!wNh-S6BXe!Er$1XZhB5lilTFn|}$k$2?+bN|AK`_H##Y%0=Pi zGbfaqOl&Nte{=o3IEKSujtOtQv4#^z&}Z)2DEnZqRMCC6Ep$|)Sbu~y#5zhbWEi_K ztmey;%ICH@yCCoX4PA+OX$h@+&Mqi-oPY6NuH=Kdf`h@*dKZdWwa+U};AYTX&E{Hb z794Q)wJO7WhcEkXcD*$Ez~FEU%PZr9_qKJsy8l!9 b=5OW&4^?AKLb7;(eq!)+^>bP0l+XkK>c5Fr literal 0 HcmV?d00001 diff --git a/files/opencs/object.png b/files/opencs/object.png new file mode 100644 index 0000000000000000000000000000000000000000..4f552151dbd78992f83ed7939f25356e38fc4f79 GIT binary patch literal 447 zcmV;w0YLtVP)7PS= z*9Sq+2ez%0S|W<&BuVxuw!$#{C_oa&ED+Zm$9V#)q-nZ_$RkFGD%iN|y6VL5Km^w4^@K7r`^EyY56&bcZxpns_ca?oa) zMDuE1;wh>l8)eQ}WImHzx3JEu8KkGNoX~NCGXr-RLQP27?L|@a;`_ehVj7<3wW;ra zb3i-_M_%Iw$G;Iy@g+(Dp$=h({#uj=#D(CDDPn=OA=c&)A7?0!F9rf);xR1~RRmpv pA(9{HoY+O&6wG>H_+t}O{0UfliPDznHH!cM002ovPDHLkV1iEIw{idg literal 0 HcmV?d00001 diff --git a/files/opencs/placeholder.png b/files/opencs/placeholder.png index 1d3df3c47d76bd213e958a44e752e4693e537f32..b9db9f18886fbefe5068cadfd31409136f20af42 100644 GIT binary patch delta 2140 zcmV-i2&4DU65bGy8Gix*007uvZqNV#00v@9M??Vs0RI60puMM)00009a7bBm000XU z000XU0RWnu7ytkO2XskIMF-*q1`!-LIsNgF0000PbVXQnLvL+uWo~o;Lvm$dbY)~9 zcWHEJAV*0}P*;Ht7XSbU#z{m$R9M69m~Bi_T^zs<2wegR5PuY3P?r>%S(=$S$O@f^ zIYBcuo%W&8hrX13uvSZ(%k{DxYpbm-O?#V_OIvDbsl%a}D{YBdzNFckpr}b^aRKr9 zaJRer0P)h(p7pfn|LNZIKm7UKbN+AV;Igx`!S5t^@SDk>4s`VB(Ty87{w_dbu{ba= zaCmt5pBN#yFn^Um005XwCYxFaf|8Syo12^G=jW}pL?V&FV7R%txw*MbOiY-~=3fAm zk&&@s!-m6$58Kr4-Me>gZmy=L#$tT?_U+Np(ZRvNI2>+iX$b%T!*FkJZ$m@Fr%#{$ z5zyw%o4?4VF6OiN265{Z3%eSfD((t>wwye9 zvcA6l-o1N22_%t7yu7>y2M29xckSBM*Vp&@^=ot_D=SMR5)BOv$>nm3T~;cUN~JPB zK7RM^-7pM4eE9HZoSM()tJP|oD-;UeH9*-vyi53?ZZ{NP%(9rPt z^Jkq-XUDQyt!A^?t^uW|r$Z1_U0qG5)3sWyg?~0NF|o6=6A5(!fgqE~mMvS>*x1reJY zqtUnql%1VzG#YDaY9I(AlgVi4A`%xD*WTU^!!Yt16B7f&@QoWcoKGcYvl)-aI}1dm zQh#G(V;?eo^}=} zFE3B6RzH6H7y#hy?QIcad_KRwzaK@6jEn>TJbn7qrOL%*GG}IHoC4x-I8jkiXen5} ze7VtRM73lxIV21+MoC3+6f%L5BiCPaA06Suh*m6sHiBNPG>(UTgbkB`?OkZXJ@AaAP9mI5)xWlThZ)-2-?j6 z0764U+uPeMeABwB*pZx^oY2tFix)3CZejQA*`w3xtlJcHh4_5F$z*!|{5e)jB9ROR zgOfA~2?=p=ag~*oHZ#`Wfc*UYVt-;{YHMq)=NXMg2!ap?8XFt4(0=*yg-j+pLnD<+ zGcz+EJa}O7Nw$IV^73B2dezg@V?A$bYKl&$0|2;O?#Rf9bgnkj9v;rm&u1_gHh)WyOeQ;j z{yd#dKXKwjb91vDZXEU~ZINs&e5j(LLa9^+1qB^He%$5)6ciM2x!lpw(b?JAg@px! z!N6j%*lf0skI(q{cw1YWMJPBvb^M41Da#)|d=Ll()|mql7=}wqN&*4`ghC;eO7-#a zfgoshcDA>-x2&w}-Me?c{(oH7+}yl#=T7^b*ZcSHf3)dN3hw{gkN-N*xpU`2LPCBc zpziMO@$vD0?eB|YuCasTwh;5 zF);xEkjZ3Eo;(qWM00aP;^JZog;HK#UQ|@%AP-3- z5(0s6?AS4EOW)PiRexDo2>>{A=1h8edRbW+4u?}H6fG?+EEY>Hm%F>WqfJPEe}7n5 zSY2IRbab?vn_Eju%Y_RU6beOcZEav+;HgumNF>tPvuDf8%Vjdzw{PDZ05KR0i{6{b zWTM$tqtUQfEaZ7$U;qFxJw1)X;XFJ%P@u-f#^T~)5{a~F(|@MH!9hG8&tNbT6B9)u z5dgqoFmN~=WZ#|2)G!RYySrmY^m;v$$wZzh6w1QFg8gdq@#DvdiHVey6dsRv=gu9o z*$l(*-Me?OmDOg)VmlA@_4RpqdBw%W0RX(byZ`{BqoZrqtfA3p>(;H~a5zIlLk=TI zrBX#iMBs2Zq<>Ex8yky>i9wu?$KxR%xwyE<<#O!-nM|gorKJ}yUMLibyu7@!va*7L z0sz3(t5@-Oyj(8N&(Bw>RE>>|0D#5CMeGkPOx4xZd3$@Kw^$Vw6+|Mjw6yf{<;%Ib zxk$lQsZ@s!9XfL4h_kf}>!-Fdf!a=pS zXx*Kp!Q=5B9v*3FX_J$aSQ^BFg%NCsxz>I-FH|bEu&{7$ZVpKk|F<81Hqc+BEpsT* S7HYBp0000DsmHZ}0aX5fB&{$e=-k zc>etPZ|_^~=!;V6ckT7{^^Ff8m!s3^*uH%`b#-+%{bVv3EnBukDwQIYN_qG09cFXW z@x@^QTCJAxTrrc9YaRaF)F`T3&l{{H@q9Xl4SR*O_BrM|u%v)N2dO%2D7 zALrDmQ@nfk?)M9rI&~`V-@k9vr+xeOOrAWM`1p9MwqCt@k(88#i;D|-y`GsfXY%63 z3!&Z5&yR@{Cvy1kVUm-RxpwWE=ok+D14D)k!OzdHNdYrw&gA6DlNbyJ3;T!>BiOQK z3wQ6{B_<|@%*;#+@&Ki!rEJ)+0i8}qQc@BF2M+vw0;WxyMsaa5A3l7r>C>f47lscX z&Vd65EbOtdu_Pxa)3$9}#*7(5L_|cRV-*z@v1!vL7A;yN{CCX~5EvMUr>7@3Z{BQl z24>BgMOIc8A3uH+Y~kVIBqStITU*PbMT>}visI6xOHGcMpPx@{Z7o4TLCqJCkdVOc z-Mdk#RJ?liO4P^S-=BW{`jMTTE!aFgJ<;iOm`o;?EnCK|TeqmKt>x3FPj-!4TwIK| zw|DadgocKqR4Tc6@giPcUQ|_8iTcf%Gl$H~Od)JarBYU}UX4G zm6g$@OBcrlNTpH|5)#PB$e_Ny9xpF1s;jH5{DOjl@bdEF#EBDvO{>)s7#PUWqenS^ z{`@bK2PiKuZ=QhBqeoL$SI6bcmyyfmxVpMpMGk=3vuBf$k-^umUj^Ir>C>sHsUagH z!y)qUeZ!Q=WL9>&1Sk{=;^X5AO1(gd4}i;GoWyGjUzR!5io;@il zDza*8R6ys>ozZHwWM*bs*u`cbDk_STCr?`Sq0wlXEg(8Nn%vx6(QLL+0rTh2XWzbk zR_k4%P*`k0YPA|4A0Mtz2dh<#IXE(a{_|dQ`OCrT~pbgIcZT z$dMyfZ8DjRZ{NNN&ykUloH=s_lgVV^=k4u{!CN;5Bqk;@fByVN_YW%p?b@{?Ha51=lU7|_ z9W7h71YqdUp%fGpi2A*K`xcc-^{d>`Xf&)`xssHW6wwd!BdnIt?Afz9ckZ0%rqO_^ zsw&iKHSk@4t(kiH@+Ce#J}8w+yNJu>a^}vRi%zFw<;s;d`?V>cO`A3Z1qHEZ&z?qK zs;;g^tya^fO&ffDeYt)6wy0luc{zD`d8}HsN|-S*C=?1NO`62v!-w(m@**xSj{EoT zH%T5q@^fkN=LjSEl0?FpGiOLoPe-HCuypBCo4#_noE0lpFm&ip^7HelsHou0n>T#= z^a&pyAN>6M2nYz^#*G^sI&_Ffj~>}Y+@=6~v2o)@`u6S1u3fuq#^@iRQmGg=Y#1IM z9=N%=(W+G|Dl02_`0yb`MMb=R{n`;4jtlVf^CKxKiG>RnHY>|)E*uu{|AN28-9HUc z0cmMzbm-9GpXTBaLV-McrTp`jR!M)Z2UP=K8@X%bhiTw&a}aTp8+^78U5DtHQoLa2E*RB-ClDZyvJfB{G(5-YBvGY}USN9)$Dk;~7Gf986hR z8P3km00ajIvwr=0K7Ra2r%s(nPfr)pg~Y@}7B61RlP6E;-@iX=)~vDUyRNQ|QKLpN zXwV?RwqU^m;Ctn6!GZ;pmzNU~62h`&%K%78Nx{v{jojQ^)~#FD^b9m0BqRidLc!w2 zi!JQ2v9aviw@=u>cI?xqtzMk0|2$Hl8xuQFl61mS=3^z;P4WHMngneg!Nuus63FJCa5 z%~VuWkeZsxwr$%ucI+6NH*W@D@7}%0WHPd|vq?`+=fsHTL^Bsg#_Y z9OlfKV|9ZglgW_FlpYv1?F3dfp;iHt}kX!rUZtv1xl#xXO414!0&U0@qnv?^=M45CNIfjVPRmCG|D z=mLT^S;hHfLLl#18)`DqYXqKo*N)?uae^rU-w_jmXWp|$${Fe2eqvU#Q+!enb~CdV z>Fp&?Y0=FWStmpSrPGJYDWGKpkaKCBc{u%y41luSs=7vL&$5c%37?6htE z`_NyTN&o>+-#$39Yzk W4f$`6a&e*n0000004R> z004l5008;`004mK004C`008P>0026e000+ooVrmw00009a7bBm000XT000XT0n*)m z`~Uy|8gxZibW?9;ba!ELWdKlNX>N2bPDNB8b~7$DE-^7j^M67&0004?Nkl3&4Kk!Qef*>(s(8?|rTKK3e^m73jt?xw zF<~}L_cB}AWHM{*B;>as2xgJYK|UiWQ%4(pe062$w|`jX1Ntsd8QEwNPW>q-ThMA@ zqmTLq(F!iVqw)or_E6>qCVq@_i?YJXrQ++{QXiZ(2C@H7z!q4}Z(BeGt8ojJpAHe1 zy(fo=bJ_4I{`!o0o1gD-!AjM?e@)4Pr~QUVBwIK3>F)vQsWb&$S&^r&QW?aV;lvYE zu4git@ja1!AU!?f+FT$mk}i{#TY$^d;msq#$xNIH8O8}C;8g*c1MByk2>1lNhz?s& St*b}?0000;*Roco)Imd;0Jd^?ycU1meGlDguJ39An%? z$E1+#>$+A%j*2)edm{Kr;UK|Hr3j1u^a!kSOSNF48I-`Xk(sQ$%3{~vEX$(A&clothing.png container.png creature.png + debug-profile.png dialogue-info.png dialogue-journal.png dialogue-regular.png @@ -27,34 +28,60 @@ journal-topics.png door.png enchantment.png + error-log.png faction.png filter.png global-variable.png gmst.png - Info.png + info.png ingredient.png + instance.png land-heightmap.png land-texture.png - leveled-creature.png - leveled-item.png + levelled-creature.png + levelled-item.png light.png lockpick.png magic-effect.png magicrabbit.png map.png + probe.png + menu-close.png + menu-exit.png + menu-new-addon.png + menu-new-game.png + menu-new-window.png + menu-merge.png + menu-open.png + menu-preferences.png + menu-reload.png + menu-redo.png + menu-save.png + menu-search.png + menu-status-bar.png + menu-undo.png + menu-verify.png + metadata.png miscellaneous.png list-modified.png npc.png + object.png pathgrid.png potion.png - probe.png race.png random-item.png random.png list-removed.png + region.png + region-map.png repair.png + run-log.png + run-openmw.png + scene.png script.png skill.png + start-script.png + stop-openmw.png sound-generator.png sound.png spell.png @@ -64,7 +91,6 @@ record-next.png record-previous.png record-delete.png - record-revert.png record-preview.png record-clone.png record-add.png diff --git a/files/opencs/run-log.png b/files/opencs/run-log.png new file mode 100644 index 0000000000000000000000000000000000000000..463ead176d4c5e367262864fcbcf4e5a19d23ca8 GIT binary patch literal 294 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Ea{HEjtmSN`?>!lvI6;>1s;*b z3=G_YAk0{w5XjGVuN& z)o`BQMRLN785QCkyc;B4)-e8`JbCheX5LKZB)*j94l{-of+-9<%MbD>o@Q8)?Qn0C z;^~GZOH?L!-(%d!ZprqCHS3JxO>Rw1O@-*`OorT+jTHhb0;j&oP_b4FoFlGb#4yG3 k&)>hDhYYqVtY>04?6v!2)}vJ`fv#onboFyt=akR{0N)K>X#fBK literal 0 HcmV?d00001 diff --git a/files/opencs/run-openmw.png b/files/opencs/run-openmw.png new file mode 100644 index 0000000000000000000000000000000000000000..1033d62baa120ce5c3ae4e2da94d122f88051a7d GIT binary patch literal 388 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCijSl0AZa85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP=d3- zBeIx*fm;ZK886+f`vVk|Dshb{3C>R|DNig)We7;j%q!9Ja}7}_GuAWJGc|_p9 zb==d%F~q_@`Op9V_RKs6Mn;Ejwn!AzDzNdKKKJL0mxr>C+%oock}3-3zi-zsP&|7? zqUkEbf@l9X2{_+l*vM(uTp-P0#M1HfSq=Ne^2QqsvmIG@8FsU!T*%qrnCoz+F-PDc zTLbT`uc8?z#3wjrRxk^uY3oV7lA5qR$D^3>j`ahEI`$)SOC%Y-9eTdsVUF`6@qK@$ z&;BjEq*7C0^8}HO3mG;XS5|mMnK%gvaU7p8dBQ)%-;-sSTRKm&E0{(kGg@W~CkuGk ZGJNsgqSE=Fa~{x344$rjF6*2UngEJofxiF% literal 0 HcmV?d00001 diff --git a/files/opencs/scene.png b/files/opencs/scene.png new file mode 100644 index 0000000000000000000000000000000000000000..a9fc03f7699a715592edd31db78ad47ac514f006 GIT binary patch literal 401 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCijSl0AZa85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP=d3- zBeIx*fm;ZK886+f`vVk|Dshb{3C>R|DNig)We7;j%q!9Ja}7}_GuAWJGc|_p9 zb;Z-gF~q_@IYEL|Lh-@t*V$Z0!W(|@3;h57`SWl7MU6jL1fn1C7%foY7O>~x;9$^< zV?46nan?dM8J17ifB*j7{6vn)P~L3ze@4}JjVcW#`~vyxj{+3ZSROGu*l=r^OTSW5 z+@a{usPC|cS&bod0`rpcLq{C+94D=3J@wbg?14$Z0;WjA3G&=u&!s9@b3Lg^NoPKq zx442?}xUyxj@&tLlBR3uPh;*bY?0g_T;e2NvgD_{~i9UU^lm<3m=10dDY-l)k mC|qH;aK}@(V7oL928Qm_H3#l%PWuYpUXO@geCwN2ZUMx literal 0 HcmV?d00001 diff --git a/files/opencs/start-script.png b/files/opencs/start-script.png new file mode 100644 index 0000000000000000000000000000000000000000..73ed157b9ed2c2366388723f8e5b25fff4bc3b97 GIT binary patch literal 359 zcmV-t0hs=YP)Q%iD#FbuV^VUy_zGW14pjAq*dWSMD~X{RfgUV_h! zasz4tfSa9O0ryxh=a?XB zf=o_JY^ti7sR{sWwoTKF2s#(|144HJfK!Jo%YqE1X-W|M{1Zd~{5ylcrur;`3~-I8 zuIr0ees$m;`MIkGG46U-GxZ99s|LS>;vs3-Lt1pt{7g}-u;fDPya%O?-LK1jXrETj zY5{PM3os7K82hm0O4G9UrzV_I}Un^?hcdO-#kvH8dF z#R=Wh@(Uh6k0j)d-_HyP1Xtj^h`ff5tb+0Uij%io@C{lR|DNig)We7;j%q!9Ja}7}_GuAWJGc|_p9 zW$)?Y7-Hd{{OA9FduAR3Bcnq%TO Date: Thu, 13 Sep 2018 22:15:59 +0400 Subject: [PATCH 086/196] Do not use universal IDs for menu items --- apps/opencs/model/world/universalid.cpp | 17 -------- apps/opencs/model/world/universalid.hpp | 21 +--------- apps/opencs/view/doc/view.cpp | 54 +++++++++++++------------ apps/opencs/view/doc/view.hpp | 1 + 4 files changed, 32 insertions(+), 61 deletions(-) diff --git a/apps/opencs/model/world/universalid.cpp b/apps/opencs/model/world/universalid.cpp index 6f9eeb24f..486f3770a 100644 --- a/apps/opencs/model/world/universalid.cpp +++ b/apps/opencs/model/world/universalid.cpp @@ -48,8 +48,6 @@ namespace { CSMWorld::UniversalId::Class_ResourceList, CSMWorld::UniversalId::Type_Videos, "Videos", ":./resources-video" }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_DebugProfiles, "Debug Profiles", ":./debug-profile.png" }, { CSMWorld::UniversalId::Class_Transient, CSMWorld::UniversalId::Type_RunLog, "Run Log", ":./run-log.png" }, - { CSMWorld::UniversalId::Class_Transient, CSMWorld::UniversalId::Type_RunGame, "Run OpenMW", ":./run-openmw.png" }, - { CSMWorld::UniversalId::Class_Transient, CSMWorld::UniversalId::Type_StopGame, "Stop OpenMW", ":./stop-openmw.png" }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_SoundGens, "Sound Generators", ":./sound-generator.png" }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_MagicEffects, "Magic Effects", ":./magic-effect.png" }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Lands, "Lands", ":./land-heightmap.png" }, @@ -57,21 +55,6 @@ namespace { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Pathgrids, "Pathgrids", ":./pathgrid.png" }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_StartScripts, "Start Scripts", ":./start-script.png" }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_MetaDatas, "Metadata", ":./metadata.png" }, - { CSMWorld::UniversalId::Class_Transient, CSMWorld::UniversalId::Type_Redo, "Redo", ":./menu-redo.png" }, - { CSMWorld::UniversalId::Class_Transient, CSMWorld::UniversalId::Type_Undo, "Undo", ":./menu-undo.png" }, - { CSMWorld::UniversalId::Class_Transient, CSMWorld::UniversalId::Type_Preferences, "Preferences", ":./menu-preferences.png" }, - { CSMWorld::UniversalId::Class_Transient, CSMWorld::UniversalId::Type_Reload, "Reload", ":./menu-reload.png" }, - { CSMWorld::UniversalId::Class_Transient, CSMWorld::UniversalId::Type_NewWindow, "New View", ":./menu-new-window.png" }, - { CSMWorld::UniversalId::Class_Transient, CSMWorld::UniversalId::Type_StatusBar, "Toggle Status Bar", ":./menu-status-bar.png" }, - { CSMWorld::UniversalId::Class_Transient, CSMWorld::UniversalId::Type_NewGame, "New Game", ":./menu-new-game.png" }, - { CSMWorld::UniversalId::Class_Transient, CSMWorld::UniversalId::Type_NewAddon, "New Addon", ":./menu-new-addon.png" }, - { CSMWorld::UniversalId::Class_Transient, CSMWorld::UniversalId::Type_Open, "Open", ":./menu-open.png" }, - { CSMWorld::UniversalId::Class_Transient, CSMWorld::UniversalId::Type_Save, "Save", ":./menu-save.png" }, - { CSMWorld::UniversalId::Class_Transient, CSMWorld::UniversalId::Type_Verify, "Verify", ":./menu-verify.png" }, - { CSMWorld::UniversalId::Class_Transient, CSMWorld::UniversalId::Type_Merge, "Merge", ":./menu-merge.png" }, - { CSMWorld::UniversalId::Class_Transient, CSMWorld::UniversalId::Type_ErrorLog, "Error Log", ":./error-log.png" }, - { CSMWorld::UniversalId::Class_Transient, CSMWorld::UniversalId::Type_Close, "Close", ":./menu-close.png" }, - { CSMWorld::UniversalId::Class_Transient, CSMWorld::UniversalId::Type_Exit, "Exit", ":./menu-exit.png" }, { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0, 0 } // end marker }; diff --git a/apps/opencs/model/world/universalid.hpp b/apps/opencs/model/world/universalid.hpp index aa5276ba7..accd1b78d 100644 --- a/apps/opencs/model/world/universalid.hpp +++ b/apps/opencs/model/world/universalid.hpp @@ -137,27 +137,10 @@ namespace CSMWorld Type_Search, Type_MetaDatas, Type_MetaData, - Type_RunLog, - Type_RunGame, - Type_StopGame, - Type_Undo, - Type_Redo, - Type_Preferences, - Type_NewWindow, - Type_StatusBar, - Type_NewGame, - Type_NewAddon, - Type_Open, - Type_Save, - Type_Verify, - Type_Merge, - Type_ErrorLog, - Type_Close, - Type_Exit, - Type_Reload + Type_RunLog }; - enum { NumberOfTypes = Type_Reload+1 }; + enum { NumberOfTypes = Type_RunLog+1 }; private: diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 97aaac4d7..ca90b11ff 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -47,37 +47,37 @@ void CSVDoc::View::setupFileMenu() { QMenu *file = menuBar()->addMenu (tr ("File")); - QAction* newGame = createMenuEntry(CSMWorld::UniversalId::Type_NewGame, file, "document-file-newgame"); + QAction* newGame = createMenuEntry("New Game", ":./menu-new-game.png", file, "document-file-newgame"); connect (newGame, SIGNAL (triggered()), this, SIGNAL (newGameRequest())); - QAction* newAddon = createMenuEntry(CSMWorld::UniversalId::Type_NewAddon, file, "document-file-newaddon"); + QAction* newAddon = createMenuEntry("New Addon", ":./menu-new-addon.png", file, "document-file-newaddon"); connect (newAddon, SIGNAL (triggered()), this, SIGNAL (newAddonRequest())); - QAction* open = createMenuEntry(CSMWorld::UniversalId::Type_Open, file, "document-file-open"); + QAction* open = createMenuEntry("Open", ":./menu-open.png", file, "document-file-open"); connect (open, SIGNAL (triggered()), this, SIGNAL (loadDocumentRequest())); - QAction* save = createMenuEntry(CSMWorld::UniversalId::Type_Save, file, "document-file-save"); + QAction* save = createMenuEntry("Save", ":./menu-save.png", file, "document-file-save"); connect (save, SIGNAL (triggered()), this, SLOT (save())); mSave = save; - QAction* verify = createMenuEntry(CSMWorld::UniversalId::Type_Verify, file, "document-file-verify"); + QAction* verify = createMenuEntry("Verify", ":./menu-verify.png", file, "document-file-verify"); connect (verify, SIGNAL (triggered()), this, SLOT (verify())); mVerify = verify; - QAction* merge = createMenuEntry(CSMWorld::UniversalId::Type_Merge, file, "document-file-merge"); + QAction* merge = createMenuEntry("Merge", ":./menu-merge.png", file, "document-file-merge"); connect (merge, SIGNAL (triggered()), this, SLOT (merge())); mMerge = merge; - QAction* loadErrors = createMenuEntry(CSMWorld::UniversalId::Type_ErrorLog, file, "document-file-errorlog"); + QAction* loadErrors = createMenuEntry("Error Log", ":./error-log.png", file, "document-file-errorlog"); connect (loadErrors, SIGNAL (triggered()), this, SLOT (loadErrorLog())); QAction* meta = createMenuEntry(CSMWorld::UniversalId::Type_MetaDatas, file, "document-file-metadata"); connect (meta, SIGNAL (triggered()), this, SLOT (addMetaDataSubView())); - QAction* close = createMenuEntry(CSMWorld::UniversalId::Type_Close, file, "document-file-close"); + QAction* close = createMenuEntry("Close", ":./menu-close.png", file, "document-file-close"); connect (close, SIGNAL (triggered()), this, SLOT (close())); - QAction* exit = createMenuEntry(CSMWorld::UniversalId::Type_Exit, file, "document-file-exit"); + QAction* exit = createMenuEntry("Exit", ":./menu-exit.png", file, "document-file-exit"); connect (exit, SIGNAL (triggered()), this, SLOT (exit())); connect (this, SIGNAL(exitApplicationRequest(CSVDoc::View *)), &mViewManager, SLOT(exitApplication(CSVDoc::View *))); @@ -112,22 +112,16 @@ void CSVDoc::View::setupEditMenu() mUndo = mDocument->getUndoStack().createUndoAction (this, tr("Undo")); setupShortcut("document-edit-undo", mUndo); connect(mUndo, SIGNAL (changed ()), this, SLOT (undoActionChanged ())); - std::string iconName = CSMWorld::UniversalId (CSMWorld::UniversalId::Type_Undo).getIcon(); - if (!iconName.empty() && iconName != ":placeholder") - mUndo->setIcon(QIcon(QString::fromStdString(iconName))); - + mUndo->setIcon(QIcon(QString::fromStdString(":./menu-undo.png"))); edit->addAction (mUndo); mRedo = mDocument->getUndoStack().createRedoAction (this, tr("Redo")); connect(mRedo, SIGNAL (changed ()), this, SLOT (redoActionChanged ())); setupShortcut("document-edit-redo", mRedo); - iconName = CSMWorld::UniversalId (CSMWorld::UniversalId::Type_Redo).getIcon(); - if (!iconName.empty() && iconName != ":placeholder") - mRedo->setIcon(QIcon(QString::fromStdString(iconName))); - + mRedo->setIcon(QIcon(QString::fromStdString(":./menu-redo.png"))); edit->addAction (mRedo); - QAction* userSettings = createMenuEntry(CSMWorld::UniversalId::Type_Preferences, edit, "document-edit-preferences"); + QAction* userSettings = createMenuEntry("Preferences", ":./menu-preferences.png", edit, "document-edit-preferences"); connect (userSettings, SIGNAL (triggered()), this, SIGNAL (editSettingsRequest())); QAction* search = createMenuEntry(CSMWorld::UniversalId::Type_Search, edit, "document-edit-search"); @@ -138,10 +132,10 @@ void CSVDoc::View::setupViewMenu() { QMenu *view = menuBar()->addMenu (tr ("View")); - QAction *newWindow = createMenuEntry(CSMWorld::UniversalId::Type_NewWindow, view, "document-view-newview"); + QAction *newWindow = createMenuEntry("New View", ":./menu-new-window.png", view, "document-view-newview"); connect (newWindow, SIGNAL (triggered()), this, SLOT (newView())); - mShowStatusBar = createMenuEntry(CSMWorld::UniversalId::Type_StatusBar, view, "document-view-statusbar"); + mShowStatusBar = createMenuEntry("Toggle Status Bar", ":./menu-status-bar.png", view, "document-view-statusbar"); connect (mShowStatusBar, SIGNAL (toggled (bool)), this, SLOT (toggleShowStatusBar (bool))); mShowStatusBar->setCheckable (true); mShowStatusBar->setChecked (CSMPrefs::get()["Windows"]["show-statusbar"].isTrue()); @@ -248,7 +242,7 @@ void CSVDoc::View::setupAssetsMenu() { QMenu *assets = menuBar()->addMenu (tr ("Assets")); - QAction* reload = createMenuEntry(CSMWorld::UniversalId::Type_Reload, assets, "document-assets-reload"); + QAction* reload = createMenuEntry("Reload", ":./menu-reload.png", assets, "document-assets-reload"); connect (reload, SIGNAL (triggered()), &mDocument->getData(), SLOT (assetsChanged())); assets->addSeparator(); @@ -299,11 +293,9 @@ void CSVDoc::View::setupDebugMenu() QAction *runDebug = debug->addMenu (mGlobalDebugProfileMenu); runDebug->setText (tr ("Run OpenMW")); setupShortcut("document-debug-run", runDebug); - std::string iconName = CSMWorld::UniversalId (CSMWorld::UniversalId::Type_RunGame).getIcon(); - if (!iconName.empty() && iconName != ":placeholder") - runDebug->setIcon(QIcon(QString::fromStdString(iconName))); + runDebug->setIcon(QIcon(QString::fromStdString(":./run-openmw.png"))); - QAction* stopDebug = createMenuEntry(CSMWorld::UniversalId::Type_StopGame, debug, "document-debug-shutdown"); + QAction* stopDebug = createMenuEntry("Stop OpenMW", ":./stop-openmw.png", debug, "document-debug-shutdown"); connect (stopDebug, SIGNAL (triggered()), this, SLOT (stop())); mStopDebug = stopDebug; @@ -325,6 +317,18 @@ QAction* CSVDoc::View::createMenuEntry(CSMWorld::UniversalId::Type type, QMenu* return entry; } +QAction* CSVDoc::View::createMenuEntry(const std::string& title, const std::string& iconName, QMenu* menu, const char* shortcutName) +{ + QAction *entry = new QAction(QString::fromStdString(title), this); + setupShortcut(shortcutName, entry); + if (!iconName.empty() && iconName != ":placeholder") + entry->setIcon(QIcon(QString::fromStdString(iconName))); + + menu->addAction (entry); + + return entry; +} + void CSVDoc::View::setupUi() { setupFileMenu(); diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp index e767777d7..76c81b964 100644 --- a/apps/opencs/view/doc/view.hpp +++ b/apps/opencs/view/doc/view.hpp @@ -67,6 +67,7 @@ namespace CSVDoc void closeEvent (QCloseEvent *event); QAction* createMenuEntry(CSMWorld::UniversalId::Type type, QMenu* menu, const char* shortcutName); + QAction* createMenuEntry(const std::string& title, const std::string& iconName, QMenu* menu, const char* shortcutName); void setupFileMenu(); From 363516049d449d21c98f161705894192e858a112 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Fri, 14 Sep 2018 18:37:04 +0300 Subject: [PATCH 087/196] Actually fix General number formatting --- components/interpreter/miscopcodes.hpp | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/components/interpreter/miscopcodes.hpp b/components/interpreter/miscopcodes.hpp index 03b7e186f..77e5a0079 100644 --- a/components/interpreter/miscopcodes.hpp +++ b/components/interpreter/miscopcodes.hpp @@ -65,23 +65,18 @@ namespace Interpreter } else if (notation == ShortestNotation) { - std::string scientific; - std::string fixed; - - out << std::scientific << value; - - scientific = out.str(); + out << value; + std::string standard = out.str(); out.str(std::string()); out.clear(); - out << std::fixed << value; + out << std::scientific << value; + std::string scientific = out.str(); - fixed = out.str(); - - mFormattedMessage += fixed.length() < scientific.length() ? fixed : scientific; + mFormattedMessage += standard.length() < scientific.length() ? standard : scientific; } - else + else { out << std::scientific << value; mFormattedMessage += out.str(); From d3aa5840ec380fcb029e795f31f7158f46d195a7 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Fri, 24 Aug 2018 16:57:32 +0300 Subject: [PATCH 088/196] Refactor magic effect record verifying --- apps/opencs/model/tools/magiceffectcheck.cpp | 93 +++++++------------- apps/opencs/model/tools/magiceffectcheck.hpp | 11 +-- 2 files changed, 36 insertions(+), 68 deletions(-) diff --git a/apps/opencs/model/tools/magiceffectcheck.cpp b/apps/opencs/model/tools/magiceffectcheck.cpp index 531bd9e1d..448e4d28c 100644 --- a/apps/opencs/model/tools/magiceffectcheck.cpp +++ b/apps/opencs/model/tools/magiceffectcheck.cpp @@ -9,7 +9,7 @@ namespace { - void addMessageIfNotEmpty(CSMDoc::Messages &messages, const CSMWorld::UniversalId &id, const std::string& text) + void addMessage(CSMDoc::Messages &messages, const CSMWorld::UniversalId &id, const std::string& text) { if (!text.empty()) { @@ -18,42 +18,34 @@ namespace } } -bool CSMTools::MagicEffectCheckStage::isTextureExists(const std::string &texture, bool isIcon) const +std::string CSMTools::MagicEffectCheckStage::checkTexture(const std::string &texture, bool isIcon) const { + if (texture.empty()) return (isIcon ? "Icon is not specified" : std::string()); + const CSMWorld::Resources &textures = isIcon ? mIcons : mTextures; - bool exists = false; + if (textures.searchId(texture) != -1) return std::string(); - if (textures.searchId(texture) != -1) - { - exists = true; - } - else - { - std::string ddsTexture = texture; - if (Misc::ResourceHelpers::changeExtensionToDds(ddsTexture) && textures.searchId(ddsTexture) != -1) - { - exists = true; - } - } + std::string ddsTexture = texture; + if (Misc::ResourceHelpers::changeExtensionToDds(ddsTexture) && textures.searchId(ddsTexture) != -1) return std::string(); - return exists; + return (isIcon ? "Icon '" : "Particle '") + texture + "' does not exist"; } -std::string CSMTools::MagicEffectCheckStage::checkReferenceable(const std::string &id, +std::string CSMTools::MagicEffectCheckStage::checkObject(const std::string &id, const CSMWorld::UniversalId &type, const std::string &column) const { std::string error; if (!id.empty()) { - CSMWorld::RefIdData::LocalIndex index = mReferenceables.getDataSet().searchId(id); + CSMWorld::RefIdData::LocalIndex index = mObjects.getDataSet().searchId(id); if (index.first == -1) { - error = "No such " + column + " '" + id + "'"; + error = column + " '" + id + "' " + "does not exist"; } else if (index.second != type.getType()) { - error = column + " is not of type " + type.getTypeName(); + error = column + " '" + id + "' " + "does not have " + type.getTypeName() + " type"; } } return error; @@ -64,19 +56,19 @@ std::string CSMTools::MagicEffectCheckStage::checkSound(const std::string &id, c std::string error; if (!id.empty() && mSounds.searchId(id) == -1) { - error = "No such " + column + " '" + id + "'"; + error = column + " '" + id + "' " + "does not exist"; } return error; } CSMTools::MagicEffectCheckStage::MagicEffectCheckStage(const CSMWorld::IdCollection &effects, const CSMWorld::IdCollection &sounds, - const CSMWorld::RefIdCollection &referenceables, + const CSMWorld::RefIdCollection &objects, const CSMWorld::Resources &icons, const CSMWorld::Resources &textures) : mMagicEffects(effects), mSounds(sounds), - mReferenceables(referenceables), + mObjects(objects), mIcons(icons), mTextures(textures) { @@ -100,46 +92,25 @@ void CSMTools::MagicEffectCheckStage::perform(int stage, CSMDoc::Messages &messa ESM::MagicEffect effect = record.get(); CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_MagicEffect, effect.mId); - - if (effect.mData.mBaseCost < 0.0f) - { - messages.push_back(std::make_pair(id, "Base Cost is negative")); - } - - if (effect.mIcon.empty()) - { - messages.push_back(std::make_pair(id, "Icon is not specified")); - } - else if (!isTextureExists(effect.mIcon, true)) - { - messages.push_back(std::make_pair(id, "No such Icon '" + effect.mIcon + "'")); - } - - if (!effect.mParticle.empty() && !isTextureExists(effect.mParticle, false)) - { - messages.push_back(std::make_pair(id, "No such Particle '" + effect.mParticle + "'")); - } - - addMessageIfNotEmpty(messages, - id, - checkReferenceable(effect.mCasting, CSMWorld::UniversalId::Type_Static, "Casting Object")); - addMessageIfNotEmpty(messages, - id, - checkReferenceable(effect.mHit, CSMWorld::UniversalId::Type_Static, "Hit Object")); - addMessageIfNotEmpty(messages, - id, - checkReferenceable(effect.mArea, CSMWorld::UniversalId::Type_Static, "Area Object")); - addMessageIfNotEmpty(messages, - id, - checkReferenceable(effect.mBolt, CSMWorld::UniversalId::Type_Weapon, "Bolt Object")); - - addMessageIfNotEmpty(messages, id, checkSound(effect.mCastSound, "Casting Sound")); - addMessageIfNotEmpty(messages, id, checkSound(effect.mHitSound, "Hit Sound")); - addMessageIfNotEmpty(messages, id, checkSound(effect.mAreaSound, "Area Sound")); - addMessageIfNotEmpty(messages, id, checkSound(effect.mBoltSound, "Bolt Sound")); if (effect.mDescription.empty()) { - messages.push_back(std::make_pair(id, "Description is empty")); + addMessage(messages, id, "Description is missing"); } + + if (effect.mData.mBaseCost < 0.0f) + { + addMessage(messages, id, "Base cost is negative"); + } + + addMessage(messages, id, checkTexture(effect.mIcon, true)); + addMessage(messages, id, checkTexture(effect.mParticle, false)); + addMessage(messages, id, checkObject(effect.mCasting, CSMWorld::UniversalId::Type_Static, "Casting object")); + addMessage(messages, id, checkObject(effect.mHit, CSMWorld::UniversalId::Type_Static, "Hit object")); + addMessage(messages, id, checkObject(effect.mArea, CSMWorld::UniversalId::Type_Static, "Area object")); + addMessage(messages, id, checkObject(effect.mBolt, CSMWorld::UniversalId::Type_Weapon, "Bolt object")); + addMessage(messages, id, checkSound(effect.mCastSound, "Casting sound")); + addMessage(messages, id, checkSound(effect.mHitSound, "Hit sound")); + addMessage(messages, id, checkSound(effect.mAreaSound, "Area sound")); + addMessage(messages, id, checkSound(effect.mBoltSound, "Bolt sound")); } diff --git a/apps/opencs/model/tools/magiceffectcheck.hpp b/apps/opencs/model/tools/magiceffectcheck.hpp index 28a406283..3e45495c1 100644 --- a/apps/opencs/model/tools/magiceffectcheck.hpp +++ b/apps/opencs/model/tools/magiceffectcheck.hpp @@ -21,23 +21,20 @@ namespace CSMTools { const CSMWorld::IdCollection &mMagicEffects; const CSMWorld::IdCollection &mSounds; - const CSMWorld::RefIdCollection &mReferenceables; + const CSMWorld::RefIdCollection &mObjects; const CSMWorld::Resources &mIcons; const CSMWorld::Resources &mTextures; bool mIgnoreBaseRecords; private: - bool isTextureExists(const std::string &texture, bool isIcon) const; - - std::string checkReferenceable(const std::string &id, - const CSMWorld::UniversalId &type, - const std::string &column) const; + std::string checkTexture(const std::string &texture, bool isIcon) const; + std::string checkObject(const std::string &id, const CSMWorld::UniversalId &type, const std::string &column) const; std::string checkSound(const std::string &id, const std::string &column) const; public: MagicEffectCheckStage(const CSMWorld::IdCollection &effects, const CSMWorld::IdCollection &sounds, - const CSMWorld::RefIdCollection &referenceables, + const CSMWorld::RefIdCollection &objects, const CSMWorld::Resources &icons, const CSMWorld::Resources &textures); From 51fdb94e34427ca01a70228c41791f7e2e49684b Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Fri, 24 Aug 2018 17:37:07 +0300 Subject: [PATCH 089/196] Add texture check to birthsign verifier --- apps/opencs/model/tools/birthsigncheck.cpp | 42 +++++++++++++++++----- apps/opencs/model/tools/birthsigncheck.hpp | 14 ++++++-- apps/opencs/model/tools/tools.cpp | 2 +- 3 files changed, 46 insertions(+), 12 deletions(-) diff --git a/apps/opencs/model/tools/birthsigncheck.cpp b/apps/opencs/model/tools/birthsigncheck.cpp index fc2989307..4ef264f65 100644 --- a/apps/opencs/model/tools/birthsigncheck.cpp +++ b/apps/opencs/model/tools/birthsigncheck.cpp @@ -4,13 +4,41 @@ #include #include +#include #include "../prefs/state.hpp" +#include "../world/data.hpp" +#include "../world/resources.hpp" #include "../world/universalid.hpp" -CSMTools::BirthsignCheckStage::BirthsignCheckStage (const CSMWorld::IdCollection& birthsigns) -: mBirthsigns (birthsigns) +namespace +{ + void addMessage(CSMDoc::Messages &messages, const CSMWorld::UniversalId &id, const std::string& text) + { + if (!text.empty()) + { + messages.push_back(std::make_pair(id, text)); + } + } +} + + +std::string CSMTools::BirthsignCheckStage::checkTexture(const std::string &texture) const +{ + if (texture.empty()) return "Texture is missing"; + if (mTextures.searchId(texture) != -1) return std::string(); + + std::string ddsTexture = texture; + if (Misc::ResourceHelpers::changeExtensionToDds(ddsTexture) && mTextures.searchId(ddsTexture) != -1) return std::string(); + + return "Texture '" + texture + "' does not exist"; +} + +CSMTools::BirthsignCheckStage::BirthsignCheckStage (const CSMWorld::IdCollection& birthsigns, + const CSMWorld::Resources &textures) +: mBirthsigns(birthsigns), + mTextures(textures) { mIgnoreBaseRecords = false; } @@ -34,17 +62,13 @@ void CSMTools::BirthsignCheckStage::perform (int stage, CSMDoc::Messages& messag CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Birthsign, birthsign.mId); - // test for empty name, description and texture if (birthsign.mName.empty()) - messages.push_back (std::make_pair (id, birthsign.mId + " has an empty name")); + addMessage(messages, id, "Name is missing"); if (birthsign.mDescription.empty()) - messages.push_back (std::make_pair (id, birthsign.mId + " has an empty description")); + addMessage(messages, id, "Description is missing"); - if (birthsign.mTexture.empty()) - messages.push_back (std::make_pair (id, birthsign.mId + " is missing a texture")); - - /// \todo test if the texture exists + addMessage(messages, id, checkTexture(birthsign.mTexture)); /// \todo check data members that can't be edited in the table view } diff --git a/apps/opencs/model/tools/birthsigncheck.hpp b/apps/opencs/model/tools/birthsigncheck.hpp index a8a7a2c14..cd22fb6d0 100644 --- a/apps/opencs/model/tools/birthsigncheck.hpp +++ b/apps/opencs/model/tools/birthsigncheck.hpp @@ -7,17 +7,27 @@ #include "../doc/stage.hpp" +namespace CSMWorld +{ + class Resources; +} + namespace CSMTools { /// \brief VerifyStage: make sure that birthsign records are internally consistent class BirthsignCheckStage : public CSMDoc::Stage { - const CSMWorld::IdCollection& mBirthsigns; + const CSMWorld::IdCollection &mBirthsigns; + const CSMWorld::Resources &mTextures; bool mIgnoreBaseRecords; + private: + std::string checkTexture(const std::string &texture) const; + public: - BirthsignCheckStage (const CSMWorld::IdCollection& birthsigns); + BirthsignCheckStage (const CSMWorld::IdCollection &birthsigns, + const CSMWorld::Resources &textures); virtual int setup(); ///< \return number of steps diff --git a/apps/opencs/model/tools/tools.cpp b/apps/opencs/model/tools/tools.cpp index 445db53af..0946225cf 100644 --- a/apps/opencs/model/tools/tools.cpp +++ b/apps/opencs/model/tools/tools.cpp @@ -78,7 +78,7 @@ CSMDoc::OperationHolder *CSMTools::Tools::getVerifier() mVerifierOperation->appendStage (new RegionCheckStage (mData.getRegions())); - mVerifierOperation->appendStage (new BirthsignCheckStage (mData.getBirthsigns())); + mVerifierOperation->appendStage (new BirthsignCheckStage (mData.getBirthsigns(), mData.getResources (CSMWorld::UniversalId::Type_Textures))); mVerifierOperation->appendStage (new SpellCheckStage (mData.getSpells())); From 5249492a31f31f04d2acd16c691af82df61f3f05 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Fri, 24 Aug 2018 20:13:20 +0300 Subject: [PATCH 090/196] Update skill record verifier messages --- apps/opencs/model/tools/skillcheck.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/tools/skillcheck.cpp b/apps/opencs/model/tools/skillcheck.cpp index b34d18e2a..a2bf3ff03 100644 --- a/apps/opencs/model/tools/skillcheck.cpp +++ b/apps/opencs/model/tools/skillcheck.cpp @@ -38,11 +38,11 @@ void CSMTools::SkillCheckStage::perform (int stage, CSMDoc::Messages& messages) { std::ostringstream stream; - stream << "Use value #" << i << " of " << skill.mId << " is negative"; + stream << "Usage experience value #" << i << " is negative"; messages.push_back (std::make_pair (id, stream.str())); } if (skill.mDescription.empty()) - messages.push_back (std::make_pair (id, skill.mId + " has an empty description")); + messages.push_back (std::make_pair (id, "Description is missing")); } From cf7a8c5775a6dbf29536b6a1c1e7a9c91b6dc9a9 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Fri, 24 Aug 2018 20:20:27 +0300 Subject: [PATCH 091/196] Update soundgen record verifier messages --- apps/opencs/model/tools/soundgencheck.cpp | 12 ++++++------ apps/opencs/model/tools/soundgencheck.hpp | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/apps/opencs/model/tools/soundgencheck.cpp b/apps/opencs/model/tools/soundgencheck.cpp index 3692259ce..99a8c184c 100644 --- a/apps/opencs/model/tools/soundgencheck.cpp +++ b/apps/opencs/model/tools/soundgencheck.cpp @@ -9,10 +9,10 @@ CSMTools::SoundGenCheckStage::SoundGenCheckStage(const CSMWorld::IdCollection &soundGens, const CSMWorld::IdCollection &sounds, - const CSMWorld::RefIdCollection &referenceables) + const CSMWorld::RefIdCollection &objects) : mSoundGens(soundGens), mSounds(sounds), - mReferenceables(referenceables) + mObjects(objects) { mIgnoreBaseRecords = false; } @@ -37,10 +37,10 @@ void CSMTools::SoundGenCheckStage::perform(int stage, CSMDoc::Messages &messages if (!soundGen.mCreature.empty()) { - CSMWorld::RefIdData::LocalIndex creatureIndex = mReferenceables.getDataSet().searchId(soundGen.mCreature); + CSMWorld::RefIdData::LocalIndex creatureIndex = mObjects.getDataSet().searchId(soundGen.mCreature); if (creatureIndex.first == -1) { - messages.push_back(std::make_pair(id, "No such creature '" + soundGen.mCreature + "'")); + messages.push_back(std::make_pair(id, "Creature '" + soundGen.mCreature + "' doesn't exist")); } else if (creatureIndex.second != CSMWorld::UniversalId::Type_Creature) { @@ -50,10 +50,10 @@ void CSMTools::SoundGenCheckStage::perform(int stage, CSMDoc::Messages &messages if (soundGen.mSound.empty()) { - messages.push_back(std::make_pair(id, "Sound is not specified")); + messages.push_back(std::make_pair(id, "Sound is missing")); } else if (mSounds.searchId(soundGen.mSound) == -1) { - messages.push_back(std::make_pair(id, "No such sound '" + soundGen.mSound + "'")); + messages.push_back(std::make_pair(id, "Sound '" + soundGen.mSound + "' doesn't exist")); } } diff --git a/apps/opencs/model/tools/soundgencheck.hpp b/apps/opencs/model/tools/soundgencheck.hpp index 19388cb91..3c2a7f071 100644 --- a/apps/opencs/model/tools/soundgencheck.hpp +++ b/apps/opencs/model/tools/soundgencheck.hpp @@ -12,13 +12,13 @@ namespace CSMTools { const CSMWorld::IdCollection &mSoundGens; const CSMWorld::IdCollection &mSounds; - const CSMWorld::RefIdCollection &mReferenceables; + const CSMWorld::RefIdCollection &mObjects; bool mIgnoreBaseRecords; public: SoundGenCheckStage(const CSMWorld::IdCollection &soundGens, const CSMWorld::IdCollection &sounds, - const CSMWorld::RefIdCollection &referenceables); + const CSMWorld::RefIdCollection &objects); virtual int setup(); ///< \return number of steps From fd1a3ad88d1922246e19e667a1a5aac789fff078 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Fri, 24 Aug 2018 21:02:42 +0300 Subject: [PATCH 092/196] Update object and script record verifier messages --- .../opencs/model/tools/referenceablecheck.cpp | 164 ++++++++---------- apps/opencs/model/tools/scriptcheck.cpp | 9 +- apps/opencs/model/tools/soundcheck.cpp | 2 +- 3 files changed, 80 insertions(+), 95 deletions(-) diff --git a/apps/opencs/model/tools/referenceablecheck.cpp b/apps/opencs/model/tools/referenceablecheck.cpp index 3e8dc1188..6d06cce12 100644 --- a/apps/opencs/model/tools/referenceablecheck.cpp +++ b/apps/opencs/model/tools/referenceablecheck.cpp @@ -272,7 +272,7 @@ void CSMTools::ReferenceableCheckStage::activatorCheck( //Checking for model, IIRC all activators should have a model if (activator.mModel.empty()) - messages.push_back (std::make_pair (id, activator.mId + " has no model")); + messages.push_back (std::make_pair (id, "Model is missing")); // ADD CHECK HERE // Check that mentioned scripts exist scriptCheck(activator, messages, id.toString()); @@ -340,11 +340,11 @@ void CSMTools::ReferenceableCheckStage::armorCheck( //checking for armor class, armor should have poistive armor class, but 0 is considered legal if (armor.mData.mArmor < 0) - messages.push_back (std::make_pair (id, armor.mId + " has negative armor class")); + messages.push_back (std::make_pair (id, "Armor class is negative")); //checking for health. Only positive numbers are allowed, or 0 is illegal if (armor.mData.mHealth <= 0) - messages.push_back (std::make_pair (id, armor.mId + " has non positive health")); + messages.push_back (std::make_pair (id, "Durability is non-positive")); // Check that mentioned scripts exist scriptCheck(armor, messages, id.toString()); @@ -385,16 +385,15 @@ void CSMTools::ReferenceableCheckStage::containerCheck( //Checking for model, IIRC all containers should have a model if (container.mModel.empty()) - messages.push_back (std::make_pair (id, container.mId + " has no model")); + messages.push_back (std::make_pair (id, "Model is missing")); // ADD CHECK HERE //Checking for capacity (weight) if (container.mWeight < 0) //0 is allowed - messages.push_back (std::make_pair (id, - container.mId + " has negative weight (capacity)")); + messages.push_back (std::make_pair (id, "Capacity is negative")); //checking for name if (container.mName.empty()) - messages.push_back (std::make_pair (id, container.mId + " has an empty name")); + messages.push_back (std::make_pair (id, "Name is missing")); //checking contained items inventoryListCheck(container.mInventory.mList, messages, id.toString()); @@ -417,61 +416,60 @@ void CSMTools::ReferenceableCheckStage::creatureCheck ( CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_Creature, creature.mId); if (creature.mModel.empty()) - messages.push_back (std::make_pair (id, creature.mId + " has no model")); + messages.push_back (std::make_pair (id, "Model is missing")); // ADD CHECK HERE if (creature.mName.empty()) - messages.push_back (std::make_pair (id, creature.mId + " has an empty name")); + messages.push_back (std::make_pair (id, "Name is missing")); //stats checks if (creature.mData.mLevel < 1) - messages.push_back (std::make_pair (id, creature.mId + " has non-positive level")); + messages.push_back (std::make_pair (id, "Level is non-positive")); if (creature.mData.mStrength < 0) - messages.push_back (std::make_pair (id, creature.mId + " has negative strength")); + messages.push_back (std::make_pair (id, "Strength is negative")); if (creature.mData.mIntelligence < 0) - messages.push_back (std::make_pair (id, creature.mId + " has negative intelligence")); + messages.push_back (std::make_pair (id, "Intelligence is negative")); if (creature.mData.mWillpower < 0) - messages.push_back (std::make_pair (id, creature.mId + " has negative willpower")); + messages.push_back (std::make_pair (id, "Willpower is negative")); if (creature.mData.mAgility < 0) - messages.push_back (std::make_pair (id, creature.mId + " has negative agility")); + messages.push_back (std::make_pair (id, "Agility is negative")); if (creature.mData.mSpeed < 0) - messages.push_back (std::make_pair (id, creature.mId + " has negative speed")); + messages.push_back (std::make_pair (id, "Speed is negative")); if (creature.mData.mEndurance < 0) - messages.push_back (std::make_pair (id, creature.mId + " has negative endurance")); + messages.push_back (std::make_pair (id, "Endurance is negative")); if (creature.mData.mPersonality < 0) - messages.push_back (std::make_pair (id, creature.mId + " has negative personality")); + messages.push_back (std::make_pair (id, "Personality is negative")); if (creature.mData.mLuck < 0) - messages.push_back (std::make_pair (id, creature.mId + " has negative luck")); + messages.push_back (std::make_pair (id, "Luck is negative")); if (creature.mData.mHealth < 0) - messages.push_back (std::make_pair (id, creature.mId + " has negative health")); + messages.push_back (std::make_pair (id, "Health is negative")); if (creature.mData.mSoul < 0) - messages.push_back (std::make_pair (id, creature.mId + " has negative soul value")); + messages.push_back (std::make_pair (id, "Soul value is negative")); for (int i = 0; i < 6; ++i) { if (creature.mData.mAttack[i] < 0) { - messages.push_back (std::make_pair (id, - creature.mId + " has negative attack strength")); + messages.push_back (std::make_pair (id, "One of attacks has negative damage")); break; } } //TODO, find meaning of other values - if (creature.mData.mGold < 0) //It seems that this is for gold in merchant creatures - messages.push_back (std::make_pair (id, creature.mId + " has negative gold ")); + if (creature.mData.mGold < 0) + messages.push_back (std::make_pair (id, "Gold count is negative")); if (creature.mScale == 0) - messages.push_back (std::make_pair (id, creature.mId + " has zero scale value")); + messages.push_back (std::make_pair (id, "Scale is equal to zero")); // Check inventory inventoryListCheck(creature.mInventory.mList, messages, id.toString()); @@ -495,10 +493,10 @@ void CSMTools::ReferenceableCheckStage::doorCheck( //usual, name or model if (door.mName.empty()) - messages.push_back (std::make_pair (id, door.mId + " has an empty name")); + messages.push_back (std::make_pair (id, "Name is missing")); if (door.mModel.empty()) - messages.push_back (std::make_pair (id, door.mId + " has no model")); + messages.push_back (std::make_pair (id, "Model is missing")); // ADD CHECK HERE // Check that mentioned scripts exist scriptCheck(door, messages, id.toString()); @@ -572,7 +570,7 @@ void CSMTools::ReferenceableCheckStage::lightCheck( CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_Light, light.mId); if (light.mData.mRadius < 0) - messages.push_back (std::make_pair (id, light.mId + " has negative light radius")); + messages.push_back (std::make_pair (id, "Light radius is negative")); if (light.mData.mFlags & ESM::Light::Carry) inventoryItemCheck(light, messages, id.toString()); @@ -667,71 +665,69 @@ void CSMTools::ReferenceableCheckStage::npcCheck ( else { if (npc.mNpdt.mAgility == 0) - messages.push_back (std::make_pair (id, npc.mId + " agility has zero value")); + messages.push_back (std::make_pair (id, "Agility is equal to zero")); if (npc.mNpdt.mEndurance == 0) - messages.push_back (std::make_pair (id, npc.mId + " endurance has zero value")); + messages.push_back (std::make_pair (id, "Endurance is equal to zero")); if (npc.mNpdt.mIntelligence == 0) - messages.push_back (std::make_pair (id, npc.mId + " intelligence has zero value")); + messages.push_back (std::make_pair (id, "Intelligence is equal to zero")); if (npc.mNpdt.mLuck == 0) - messages.push_back (std::make_pair (id, npc.mId + " luck has zero value")); + messages.push_back (std::make_pair (id, "Luck is equal to zero")); if (npc.mNpdt.mPersonality == 0) - messages.push_back (std::make_pair (id, npc.mId + " personality has zero value")); + messages.push_back (std::make_pair (id, "Personality is equal to zero")); if (npc.mNpdt.mStrength == 0) - messages.push_back (std::make_pair (id, npc.mId + " strength has zero value")); + messages.push_back (std::make_pair (id, "Strength is equal to zero")); if (npc.mNpdt.mSpeed == 0) - messages.push_back (std::make_pair (id, npc.mId + " speed has zero value")); + messages.push_back (std::make_pair (id, "Speed is equal to zero")); if (npc.mNpdt.mWillpower == 0) - messages.push_back (std::make_pair (id, npc.mId + " willpower has zero value")); + messages.push_back (std::make_pair (id, "Willpower is equal to zero")); } - if (level < 1) - messages.push_back (std::make_pair (id, npc.mId + " level is non positive")); + if (level <= 0) + messages.push_back (std::make_pair (id, "Level is non-positive")); if (gold < 0) - messages.push_back (std::make_pair (id, npc.mId + " gold has negative value")); + messages.push_back (std::make_pair (id, "Gold count is negative")); if (npc.mName.empty()) - messages.push_back (std::make_pair (id, npc.mId + " has any empty name")); + messages.push_back (std::make_pair (id, "Name is missing")); if (npc.mClass.empty()) - messages.push_back (std::make_pair (id, npc.mId + " has an empty class")); + messages.push_back (std::make_pair (id, "Class is missing")); else if (mClasses.searchId (npc.mClass) == -1) - messages.push_back (std::make_pair (id, npc.mId + " has invalid class")); + messages.push_back (std::make_pair (id, "Class '" + npc.mClass + "' does not exist")); if (npc.mRace.empty()) - messages.push_back (std::make_pair (id, npc.mId + " has an empty race")); + messages.push_back (std::make_pair (id, "Race is missing")); else if (mRaces.searchId (npc.mRace) == -1) - messages.push_back (std::make_pair (id, npc.mId + " has invalid race")); + messages.push_back (std::make_pair (id, "Race '" + npc.mRace + "' does not exist")); if (disposition < 0) - messages.push_back (std::make_pair (id, npc.mId + " has negative disposition")); + messages.push_back (std::make_pair (id, "Disposition is negative")); - if (reputation < 0) //It seems that no character in Morrowind.esm have negative reputation. I'm assuming that negative reputation is invalid - { - messages.push_back (std::make_pair (id, npc.mId + " has negative reputation")); - } + if (reputation < 0) + messages.push_back (std::make_pair (id, "Reputation is negative")); if (!npc.mFaction.empty()) { if (rank < 0) - messages.push_back (std::make_pair (id, npc.mId + " has negative rank")); + messages.push_back (std::make_pair (id, "Faction rank is negative")); if (mFactions.searchId(npc.mFaction) == -1) - messages.push_back (std::make_pair (id, npc.mId + " has invalid faction")); + messages.push_back (std::make_pair (id, "Faction '" + npc.mFaction + "' does not exist")); } if (npc.mHead.empty()) - messages.push_back (std::make_pair (id, npc.mId + " has no head")); + messages.push_back (std::make_pair (id, "Head is missing")); // ADD CHECK HERE if (npc.mHair.empty()) - messages.push_back (std::make_pair (id, npc.mId + " has no hair")); + messages.push_back (std::make_pair (id, "Hair is missing")); // ADD CHECK HERE //TODO: reputation, Disposition, rank, everything else @@ -793,28 +789,25 @@ void CSMTools::ReferenceableCheckStage::weaponCheck( weapon.mData.mType == ESM::Weapon::Bolt)) { if (weapon.mData.mSlash[0] > weapon.mData.mSlash[1]) - messages.push_back (std::make_pair (id, - weapon.mId + " has minimum slash damage higher than maximum")); + messages.push_back (std::make_pair (id, "Minimum slash damage higher than maximum")); if (weapon.mData.mThrust[0] > weapon.mData.mThrust[1]) - messages.push_back (std::make_pair (id, - weapon.mId + " has minimum thrust damage higher than maximum")); + messages.push_back (std::make_pair (id, "Minimum thrust damage is higher than maximum")); } if (weapon.mData.mChop[0] > weapon.mData.mChop[1]) - messages.push_back (std::make_pair (id, - weapon.mId + " has minimum chop damage higher than maximum")); + messages.push_back (std::make_pair (id, "Minimum chop damage is higher than maximum")); if (!(weapon.mData.mType == ESM::Weapon::Arrow || weapon.mData.mType == ESM::Weapon::Bolt || weapon.mData.mType == ESM::Weapon::MarksmanThrown)) { //checking of health - if (weapon.mData.mHealth <= 0) - messages.push_back (std::make_pair (id, weapon.mId + " has non-positive health")); + if (weapon.mData.mHealth == 0) + messages.push_back (std::make_pair (id, "Durability is equal to zero")); if (weapon.mData.mReach < 0) - messages.push_back (std::make_pair (id, weapon.mId + " has negative reach")); + messages.push_back (std::make_pair (id, "Reach is negative")); } } @@ -877,7 +870,7 @@ void CSMTools::ReferenceableCheckStage::staticCheck ( CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Static, staticElement.mId); if (staticElement.mModel.empty()) - messages.push_back (std::make_pair (id, staticElement.mId + " has no model")); + messages.push_back (std::make_pair (id, "Model is missing")); } //final check @@ -886,7 +879,7 @@ void CSMTools::ReferenceableCheckStage::finalCheck (CSMDoc::Messages& messages) { if (!mPlayerPresent) messages.push_back (std::make_pair (CSMWorld::UniversalId::Type_Referenceables, - "There is no player record")); + "Player record is missing")); } void CSMTools::ReferenceableCheckStage::inventoryListCheck( @@ -900,8 +893,7 @@ void CSMTools::ReferenceableCheckStage::inventoryListCheck( CSMWorld::RefIdData::LocalIndex localIndex = mReferencables.searchId(itemName); if (localIndex.first == -1) - messages.push_back (std::make_pair (id, - id + " contains non-existing item (" + itemName + ")")); + messages.push_back (std::make_pair (id, "Item '" + itemName + "' does not exist")); else { // Needs to accommodate containers, creatures, and NPCs @@ -922,8 +914,7 @@ void CSMTools::ReferenceableCheckStage::inventoryListCheck( case CSMWorld::UniversalId::Type_ItemLevelledList: break; default: - messages.push_back (std::make_pair(id, - id + " contains item of invalid type (" + itemName + ")")); + messages.push_back (std::make_pair(id, "'" + itemName + "' is not an item")); } } } @@ -935,67 +926,66 @@ template void CSMTools::ReferenceableCheckStage::inventoryItemChe const Item& someItem, CSMDoc::Messages& messages, const std::string& someID, bool enchantable) { if (someItem.mName.empty()) - messages.push_back (std::make_pair (someID, someItem.mId + " has an empty name")); + messages.push_back (std::make_pair (someID, "Name is missing")); //Checking for weight if (someItem.mData.mWeight < 0) - messages.push_back (std::make_pair (someID, someItem.mId + " has negative weight")); + messages.push_back (std::make_pair (someID, "Weight is negative")); //Checking for value if (someItem.mData.mValue < 0) - messages.push_back (std::make_pair (someID, someItem.mId + " has negative value")); + messages.push_back (std::make_pair (someID, "Value is negative")); //checking for model if (someItem.mModel.empty()) - messages.push_back (std::make_pair (someID, someItem.mId + " has no model")); + messages.push_back (std::make_pair (someID, "Model is missing")); // ADD CHECK HERE //checking for icon if (someItem.mIcon.empty()) - messages.push_back (std::make_pair (someID, someItem.mId + " has no icon")); + messages.push_back (std::make_pair (someID, "Icon is missing")); // ADD CHECK HERE if (enchantable && someItem.mData.mEnchant < 0) - messages.push_back (std::make_pair (someID, someItem.mId + " has negative enchantment")); + messages.push_back (std::make_pair (someID, "Enchantment points number is negative")); } template void CSMTools::ReferenceableCheckStage::inventoryItemCheck ( const Item& someItem, CSMDoc::Messages& messages, const std::string& someID) { if (someItem.mName.empty()) - messages.push_back (std::make_pair (someID, someItem.mId + " has an empty name")); + messages.push_back (std::make_pair (someID, "Name is missing")); //Checking for weight if (someItem.mData.mWeight < 0) - messages.push_back (std::make_pair (someID, someItem.mId + " has negative weight")); + messages.push_back (std::make_pair (someID, "Weight is negative")); //Checking for value if (someItem.mData.mValue < 0) - messages.push_back (std::make_pair (someID, someItem.mId + " has negative value")); + messages.push_back (std::make_pair (someID, "Value is negative")); //checking for model if (someItem.mModel.empty()) - messages.push_back (std::make_pair (someID, someItem.mId + " has no model")); + messages.push_back (std::make_pair (someID, "Model is missing")); // ADD CHECK HERE //checking for icon if (someItem.mIcon.empty()) - messages.push_back (std::make_pair (someID, someItem.mId + " has no icon")); + messages.push_back (std::make_pair (someID, "Icon is missing")); // ADD CHECK HERE } template void CSMTools::ReferenceableCheckStage::toolCheck ( const Tool& someTool, CSMDoc::Messages& messages, const std::string& someID, bool canBeBroken) { if (someTool.mData.mQuality <= 0) - messages.push_back (std::make_pair (someID, someTool.mId + " has non-positive quality")); + messages.push_back (std::make_pair (someID, "Quality is non-positive")); if (canBeBroken && someTool.mData.mUses<=0) - messages.push_back (std::make_pair (someID, - someTool.mId + " has non-positive uses count")); + messages.push_back (std::make_pair (someID, "Number of uses is non-positive")); } template void CSMTools::ReferenceableCheckStage::toolCheck ( const Tool& someTool, CSMDoc::Messages& messages, const std::string& someID) { if (someTool.mData.mQuality <= 0) - messages.push_back (std::make_pair (someID, someTool.mId + " has non-positive quality")); + messages.push_back (std::make_pair (someID, "Quality is non-positive")); } template void CSMTools::ReferenceableCheckStage::listCheck ( @@ -1004,12 +994,10 @@ template void CSMTools::ReferenceableCheckStage::listCheck ( for (unsigned i = 0; i < someList.mList.size(); ++i) { if (mReferencables.searchId(someList.mList[i].mId).first == -1) - messages.push_back (std::make_pair (someID, - someList.mId + " contains item without referencable")); + messages.push_back (std::make_pair (someID, "Object '" + someList.mList[i].mId + "' does not exist")); if (someList.mList[i].mLevel < 1) - messages.push_back (std::make_pair (someID, - someList.mId + " contains item with non-positive level")); + messages.push_back (std::make_pair (someID, "Level of item '" + someList.mList[i].mId + "' is non-positive")); } } @@ -1019,6 +1007,6 @@ template void CSMTools::ReferenceableCheckStage::scriptCheck ( if (!someTool.mScript.empty()) { if (mScripts.searchId(someTool.mScript) == -1) - messages.push_back (std::make_pair (someID, someTool.mId + " refers to an unknown script \""+someTool.mScript+"\"")); + messages.push_back (std::make_pair (someID, "Script '"+someTool.mScript+"' does not exist")); } } diff --git a/apps/opencs/model/tools/scriptcheck.cpp b/apps/opencs/model/tools/scriptcheck.cpp index d3c6221cd..e62f9eb88 100644 --- a/apps/opencs/model/tools/scriptcheck.cpp +++ b/apps/opencs/model/tools/scriptcheck.cpp @@ -30,10 +30,7 @@ void CSMTools::ScriptCheckStage::report (const std::string& message, const Compi CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Script, mId); - stream - << "script " << mFile - << ", line " << loc.mLine << ", column " << loc.mColumn - << " (" << loc.mLiteral << "): " << message; + stream << "Line " << loc.mLine << ", column " << loc.mColumn << " (" << loc.mLiteral << "): " << message; std::ostringstream hintStream; @@ -47,7 +44,7 @@ void CSMTools::ScriptCheckStage::report (const std::string& message, Type type) CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Script, mId); std::ostringstream stream; - stream << "script " << mFile << ": " << message; + stream << message; mMessages->add (id, stream.str(), "", getSeverity (type)); } @@ -128,7 +125,7 @@ void CSMTools::ScriptCheckStage::perform (int stage, CSMDoc::Messages& messages) CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Script, mId); std::ostringstream stream; - stream << "script " << mFile << ": " << error.what(); + stream << error.what(); messages.add (id, stream.str(), "", CSMDoc::Message::Severity_SeriousError); } diff --git a/apps/opencs/model/tools/soundcheck.cpp b/apps/opencs/model/tools/soundcheck.cpp index b84453b5c..3fdbcc3bc 100644 --- a/apps/opencs/model/tools/soundcheck.cpp +++ b/apps/opencs/model/tools/soundcheck.cpp @@ -36,5 +36,5 @@ void CSMTools::SoundCheckStage::perform (int stage, CSMDoc::Messages& messages) if (sound.mData.mMinRange>sound.mData.mMaxRange) messages.push_back (std::make_pair (id, "Minimum range larger than maximum range")); - /// \todo check, if the sound file exists + /// \todo check, if the sound file exists ADD CHECK HERE } From 7535daa94da38e1259c4aeb61b21bb98e9c4e786 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Fri, 24 Aug 2018 21:15:43 +0300 Subject: [PATCH 093/196] Update class and race record verifier messages --- apps/opencs/model/tools/classcheck.cpp | 15 +++++++-------- apps/opencs/model/tools/racecheck.cpp | 12 ++++++------ 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/apps/opencs/model/tools/classcheck.cpp b/apps/opencs/model/tools/classcheck.cpp index 89923a398..157dfab7f 100644 --- a/apps/opencs/model/tools/classcheck.cpp +++ b/apps/opencs/model/tools/classcheck.cpp @@ -37,11 +37,11 @@ void CSMTools::ClassCheckStage::perform (int stage, CSMDoc::Messages& messages) // A class should have a name if (class_.mName.empty()) - messages.push_back (std::make_pair (id, class_.mId + " doesn't have a name")); + messages.push_back (std::make_pair (id, "Name is missing")); // A playable class should have a description if (class_.mData.mIsPlayable != 0 && class_.mDescription.empty()) - messages.push_back (std::make_pair (id, class_.mId + " doesn't have a description and it's playable")); + messages.push_back (std::make_pair (id, "Description of a playable class is missing")); // test for invalid attributes for (int i=0; i<2; ++i) @@ -49,14 +49,14 @@ void CSMTools::ClassCheckStage::perform (int stage, CSMDoc::Messages& messages) { std::ostringstream stream; - stream << "Attribute #" << i << " of " << class_.mId << " is not set"; + stream << "Attribute #" << i << " is not set"; messages.push_back (std::make_pair (id, stream.str())); } if (class_.mData.mAttribute[0]==class_.mData.mAttribute[1] && class_.mData.mAttribute[0]!=-1) { - messages.push_back (std::make_pair (id, "Class lists same attribute twice")); + messages.push_back (std::make_pair (id, "Same attribute is listed twice")); } // test for non-unique skill @@ -66,10 +66,9 @@ void CSMTools::ClassCheckStage::perform (int stage, CSMDoc::Messages& messages) for (int i2=0; i2<2; ++i2) ++skills[class_.mData.mSkills[i][i2]]; - for (std::map::const_iterator iter (skills.begin()); iter!=skills.end(); ++iter) - if (iter->second>1) + for (auto &skill : skills) + if (skill.second>1) { - messages.push_back (std::make_pair (id, - ESM::Skill::indexToId (iter->first) + " is listed more than once")); + messages.push_back (std::make_pair (id, "Skill " + ESM::Skill::indexToId (skill.first) + " is listed more than once")); } } diff --git a/apps/opencs/model/tools/racecheck.cpp b/apps/opencs/model/tools/racecheck.cpp index 38abfef18..7ce9a8869 100644 --- a/apps/opencs/model/tools/racecheck.cpp +++ b/apps/opencs/model/tools/racecheck.cpp @@ -29,24 +29,24 @@ void CSMTools::RaceCheckStage::performPerRecord (int stage, CSMDoc::Messages& me // test for empty name and description if (race.mName.empty()) - messages.push_back (std::make_pair (id, race.mId + " has an empty name")); + messages.push_back (std::make_pair (id, "Name is missing")); if (race.mDescription.empty()) - messages.push_back (std::make_pair (id, race.mId + " has an empty description")); + messages.push_back (std::make_pair (id, "Description is missing")); // test for positive height if (race.mData.mHeight.mMale<=0) - messages.push_back (std::make_pair (id, "male " + race.mId + " has non-positive height")); + messages.push_back (std::make_pair (id, "Male height is non-positive")); if (race.mData.mHeight.mFemale<=0) - messages.push_back (std::make_pair (id, "female " + race.mId + " has non-positive height")); + messages.push_back (std::make_pair (id, "Female height is non-positive")); // test for non-negative weight if (race.mData.mWeight.mMale<0) - messages.push_back (std::make_pair (id, "male " + race.mId + " has negative weight")); + messages.push_back (std::make_pair (id, "Male weight is negative")); if (race.mData.mWeight.mFemale<0) - messages.push_back (std::make_pair (id, "female " + race.mId + " has negative weight")); + messages.push_back (std::make_pair (id, "Female weight is negative")); /// \todo check data members that can't be edited in the table view } From a9ce155a7bdacabf351e4a4ec394046a4f0a09ee Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Fri, 24 Aug 2018 21:41:10 +0300 Subject: [PATCH 094/196] Update faction and body part record verifier messages --- apps/opencs/model/tools/bodypartcheck.cpp | 15 +++++++-------- apps/opencs/model/tools/factioncheck.cpp | 11 +++++------ 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/apps/opencs/model/tools/bodypartcheck.cpp b/apps/opencs/model/tools/bodypartcheck.cpp index b5bd78f6c..d33705cf6 100644 --- a/apps/opencs/model/tools/bodypartcheck.cpp +++ b/apps/opencs/model/tools/bodypartcheck.cpp @@ -34,25 +34,24 @@ void CSMTools::BodyPartCheckStage::perform (int stage, CSMDoc::Messages &message // Check BYDT if (bodyPart.mData.mPart > 14 ) - messages.push_back(std::make_pair( id, bodyPart.mId + " has out of range part value." )); + messages.push_back(std::make_pair(id, "Invalid mesh part")); if (bodyPart.mData.mFlags > 3 ) - messages.push_back(std::make_pair( id, bodyPart.mId + " has out of range flags value." )); + messages.push_back(std::make_pair(id, "Invalid flags")); if (bodyPart.mData.mType > 2 ) - messages.push_back(std::make_pair( id, bodyPart.mId + " has out of range type value." )); + messages.push_back(std::make_pair(id, "Invalid type")); // Check MODL if ( bodyPart.mModel.empty() ) - messages.push_back(std::make_pair( id, bodyPart.mId + " has no model." )); + messages.push_back(std::make_pair(id, "Model is missing" )); else if ( mMeshes.searchId( bodyPart.mModel ) == -1 ) - messages.push_back(std::make_pair( id, bodyPart.mId + " has invalid model." )); + messages.push_back(std::make_pair(id, "Model '" + bodyPart.mModel + "' does not exist")); // Check FNAM - if ( bodyPart.mRace.empty() ) - messages.push_back(std::make_pair( id, bodyPart.mId + " has no race." )); + messages.push_back(std::make_pair(id, "Race is missing" )); else if ( mRaces.searchId( bodyPart.mRace ) == -1 ) - messages.push_back(std::make_pair( id, bodyPart.mId + " has invalid race." )); + messages.push_back(std::make_pair(id, "Race '" + bodyPart.mRace + " does not exist")); } diff --git a/apps/opencs/model/tools/factioncheck.cpp b/apps/opencs/model/tools/factioncheck.cpp index 39073db5f..d19c0ae52 100644 --- a/apps/opencs/model/tools/factioncheck.cpp +++ b/apps/opencs/model/tools/factioncheck.cpp @@ -37,12 +37,12 @@ void CSMTools::FactionCheckStage::perform (int stage, CSMDoc::Messages& messages // test for empty name if (faction.mName.empty()) - messages.push_back (std::make_pair (id, faction.mId + " has an empty name")); + messages.push_back (std::make_pair (id, "Name is missing")); // test for invalid attributes if (faction.mData.mAttribute[0]==faction.mData.mAttribute[1] && faction.mData.mAttribute[0]!=-1) { - messages.push_back (std::make_pair (id , "Faction lists same attribute twice")); + messages.push_back (std::make_pair (id, "Same attribute is listed twice")); } // test for non-unique skill @@ -52,11 +52,10 @@ void CSMTools::FactionCheckStage::perform (int stage, CSMDoc::Messages& messages if (faction.mData.mSkills[i]!=-1) ++skills[faction.mData.mSkills[i]]; - for (std::map::const_iterator iter (skills.begin()); iter!=skills.end(); ++iter) - if (iter->second>1) + for (auto &skill : skills) + if (skill.second>1) { - messages.push_back (std::make_pair (id, - ESM::Skill::indexToId (iter->first) + " is listed more than once")); + messages.push_back (std::make_pair (id, "Skill " + ESM::Skill::indexToId (skill.first) + " is listed more than once")); } /// \todo check data members that can't be edited in the table view From 14ef145b3b83691e00c2d2c433ab76e069b5e4a2 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Fri, 24 Aug 2018 22:01:08 +0300 Subject: [PATCH 095/196] Update region and pathgrid record verifier messages --- apps/opencs/model/tools/pathgridcheck.cpp | 37 +++++++++++------------ apps/opencs/model/tools/regioncheck.cpp | 2 +- 2 files changed, 19 insertions(+), 20 deletions(-) diff --git a/apps/opencs/model/tools/pathgridcheck.cpp b/apps/opencs/model/tools/pathgridcheck.cpp index c25845885..e63e9122f 100644 --- a/apps/opencs/model/tools/pathgridcheck.cpp +++ b/apps/opencs/model/tools/pathgridcheck.cpp @@ -37,9 +37,9 @@ void CSMTools::PathgridCheckStage::perform (int stage, CSMDoc::Messages& message // check the number of pathgrid points if (pathgrid.mData.mS2 < static_cast(pathgrid.mPoints.size())) - messages.add (id, pathgrid.mId + " has less points than expected", "", CSMDoc::Message::Severity_Error); + messages.add (id, "Less points than expected", "", CSMDoc::Message::Severity_Error); else if (pathgrid.mData.mS2 > static_cast(pathgrid.mPoints.size())) - messages.add (id, pathgrid.mId + " has more points than expected", "", CSMDoc::Message::Severity_Error); + messages.add (id, "More points than expected", "", CSMDoc::Message::Severity_Error); std::vector pointList(pathgrid.mPoints.size()); std::vector duplList; @@ -56,9 +56,9 @@ void CSMTools::PathgridCheckStage::perform (int stage, CSMDoc::Messages& message if (pointList[pathgrid.mEdges[i].mV0].mOtherIndex[j] == pathgrid.mEdges[i].mV1) { std::ostringstream ss; - ss << "has a duplicate edge between points" << pathgrid.mEdges[i].mV0 - << " and " << pathgrid.mEdges[i].mV1; - messages.add (id, pathgrid.mId + ss.str(), "", CSMDoc::Message::Severity_Error); + ss << "Duplicate edge between points" + << pathgrid.mEdges[i].mV0 << " and " << pathgrid.mEdges[i].mV1; + messages.add (id, ss.str(), "", CSMDoc::Message::Severity_Error); break; } } @@ -70,8 +70,8 @@ void CSMTools::PathgridCheckStage::perform (int stage, CSMDoc::Messages& message else { std::ostringstream ss; - ss << " has an edge connecting a non-existent point " << pathgrid.mEdges[i].mV0; - messages.add (id, pathgrid.mId + ss.str(), "", CSMDoc::Message::Severity_Error); + ss << "An edge is connected to a non-existent point " << pathgrid.mEdges[i].mV0; + messages.add (id, ss.str(), "", CSMDoc::Message::Severity_Error); } } @@ -93,8 +93,8 @@ void CSMTools::PathgridCheckStage::perform (int stage, CSMDoc::Messages& message if (!foundReverse) { std::ostringstream ss; - ss << " has a missing edge between points " << i << " and " << pointList[i].mOtherIndex[j]; - messages.add (id, pathgrid.mId + ss.str(), "", CSMDoc::Message::Severity_Error); + ss << "Missing edge between points " << i << " and " << pointList[i].mOtherIndex[j]; + messages.add (id, ss.str(), "", CSMDoc::Message::Severity_Error); } } @@ -113,11 +113,9 @@ void CSMTools::PathgridCheckStage::perform (int stage, CSMDoc::Messages& message if (it == duplList.end()) { std::ostringstream ss; - ss << " has a duplicated point (" << i - << ") x=" << pathgrid.mPoints[i].mX - << ", y=" << pathgrid.mPoints[i].mY - << ", z=" << pathgrid.mPoints[i].mZ; - messages.add (id, pathgrid.mId + ss.str(), "", CSMDoc::Message::Severity_Warning); + ss << "Point " << i << " duplicates point " << j + << " (" << pathgrid.mPoints[i].mX << ", " << pathgrid.mPoints[i].mY << ", " << pathgrid.mPoints[i].mZ << ")"; + messages.add (id, ss.str(), "", CSMDoc::Message::Severity_Warning); duplList.push_back(i); break; @@ -132,11 +130,12 @@ void CSMTools::PathgridCheckStage::perform (int stage, CSMDoc::Messages& message if (pointList[i].mConnectionNum == 0) { std::ostringstream ss; - ss << " has an orphaned point (" << i - << ") x=" << pathgrid.mPoints[i].mX - << ", y=" << pathgrid.mPoints[i].mY - << ", z=" << pathgrid.mPoints[i].mZ; - messages.add (id, pathgrid.mId + ss.str(), "", CSMDoc::Message::Severity_Warning); + ss << "Point " << i << " (" + << pathgrid.mPoints[i].mX << ", " + << pathgrid.mPoints[i].mY << ", " + << pathgrid.mPoints[i].mZ << ") " + << "is disconnected from other points"; + messages.add (id, ss.str(), "", CSMDoc::Message::Severity_Warning); } } diff --git a/apps/opencs/model/tools/regioncheck.cpp b/apps/opencs/model/tools/regioncheck.cpp index f21253090..8375e3f0a 100644 --- a/apps/opencs/model/tools/regioncheck.cpp +++ b/apps/opencs/model/tools/regioncheck.cpp @@ -36,7 +36,7 @@ void CSMTools::RegionCheckStage::perform (int stage, CSMDoc::Messages& messages) // test for empty name if (region.mName.empty()) - messages.add(id, region.mId + " has an empty name", "", CSMDoc::Message::Severity_Error); + messages.add(id, "Name is missing", "", CSMDoc::Message::Severity_Error); /// \todo test that the ID in mSleeplist exists From a6d3cd919016c060bc1d2735e85f5653d0db53d1 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Fri, 24 Aug 2018 23:12:11 +0300 Subject: [PATCH 096/196] Update topic info verifier messages --- apps/opencs/model/tools/magiceffectcheck.cpp | 4 +- apps/opencs/model/tools/topicinfocheck.cpp | 109 ++++++++----------- apps/opencs/model/tools/topicinfocheck.hpp | 11 -- 3 files changed, 48 insertions(+), 76 deletions(-) diff --git a/apps/opencs/model/tools/magiceffectcheck.cpp b/apps/opencs/model/tools/magiceffectcheck.cpp index 448e4d28c..7e7a09aa5 100644 --- a/apps/opencs/model/tools/magiceffectcheck.cpp +++ b/apps/opencs/model/tools/magiceffectcheck.cpp @@ -20,7 +20,7 @@ namespace std::string CSMTools::MagicEffectCheckStage::checkTexture(const std::string &texture, bool isIcon) const { - if (texture.empty()) return (isIcon ? "Icon is not specified" : std::string()); + if (texture.empty()) return (isIcon ? "Icon is missing" : std::string()); const CSMWorld::Resources &textures = isIcon ? mIcons : mTextures; if (textures.searchId(texture) != -1) return std::string(); @@ -97,7 +97,7 @@ void CSMTools::MagicEffectCheckStage::perform(int stage, CSMDoc::Messages &messa { addMessage(messages, id, "Description is missing"); } - + if (effect.mData.mBaseCost < 0.0f) { addMessage(messages, id, "Base cost is negative"); diff --git a/apps/opencs/model/tools/topicinfocheck.cpp b/apps/opencs/model/tools/topicinfocheck.cpp index ac1f596ae..9a31db72b 100644 --- a/apps/opencs/model/tools/topicinfocheck.cpp +++ b/apps/opencs/model/tools/topicinfocheck.cpp @@ -134,7 +134,7 @@ void CSMTools::TopicInfoCheckStage::perform(int stage, CSMDoc::Messages& message if (topicInfo.mData.mGender < -1 || topicInfo.mData.mGender > 1) { std::ostringstream stream; - messages.add(id, "Gender: Value is invalid", "", CSMDoc::Message::Severity_Error); + messages.add(id, "Gender is invalid", "", CSMDoc::Message::Severity_Error); } if (!topicInfo.mRace.empty()) @@ -166,23 +166,28 @@ void CSMTools::TopicInfoCheckStage::perform(int stage, CSMDoc::Messages& message bool CSMTools::TopicInfoCheckStage::verifyActor(const std::string& actor, const CSMWorld::UniversalId& id, CSMDoc::Messages& messages) { - const std::string specifier = "Actor"; - CSMWorld::RefIdData::LocalIndex index = mReferencables.searchId(actor); if (index.first == -1) { - writeMissingIdError(specifier, actor, id, messages); + std::ostringstream stream; + stream << "Actor '" << actor << "' does not exist"; + messages.add(id, stream.str(), "", CSMDoc::Message::Severity_Error); return false; } else if (mReferencables.getRecord(index).isDeleted()) { - writeDeletedRecordError(specifier, actor, id, messages); + std::ostringstream stream; + stream << "Deleted actor '" << actor << "' is being referenced"; + messages.add(id, stream.str(), "", CSMDoc::Message::Severity_Error); return false; } else if (index.second != CSMWorld::UniversalId::Type_Npc && index.second != CSMWorld::UniversalId::Type_Creature) { - writeInvalidTypeError(specifier, actor, index.second, "NPC or Creature", id, messages); + CSMWorld::UniversalId tempId(index.second, actor); + std::ostringstream stream; + stream << "Object '" << actor << "' has invalid type " << tempId.getTypeName() << " (an actor must be an NPC or a creature)"; + messages.add(id, stream.str(), "", CSMDoc::Message::Severity_Error); return false; } @@ -192,11 +197,11 @@ bool CSMTools::TopicInfoCheckStage::verifyActor(const std::string& actor, const bool CSMTools::TopicInfoCheckStage::verifyCell(const std::string& cell, const CSMWorld::UniversalId& id, CSMDoc::Messages& messages) { - const std::string specifier = "Cell"; - if (mCellNames.find(cell) == mCellNames.end()) { - writeMissingIdError(specifier, cell, id, messages); + std::ostringstream stream; + stream << "Cell '" << cell << "' does not exist"; + messages.add(id, stream.str(), "", CSMDoc::Message::Severity_Error); return false; } @@ -209,9 +214,8 @@ bool CSMTools::TopicInfoCheckStage::verifyFactionRank(const std::string& faction if (rank < -1) { std::ostringstream stream; - stream << "Rank or PC Rank is set to " << rank << ", but should be set to -1 if no rank is required"; - - messages.add(id, stream.str(), "", CSMDoc::Message::Severity_Error); + stream << "Faction rank is set to " << rank << ", but it should be set to -1 if there are no rank requirements"; + messages.add(id, stream.str(), "", CSMDoc::Message::Severity_Warning); return false; } @@ -229,10 +233,10 @@ bool CSMTools::TopicInfoCheckStage::verifyFactionRank(const std::string& faction if (rank >= limit) { std::ostringstream stream; - stream << "Rank or PC Rank is set to " << rank << " which is more than the maximum of " << limit - 1 - << " for the " << factionName << " faction"; + stream << "Faction rank is set to " << rank << " which is more than the maximum of " << limit - 1 + << " for the '" << factionName << "' faction"; - messages.add(id, stream.str(), "", CSMDoc::Message::Severity_Error); + messages.add(id, stream.str(), "", CSMDoc::Message::Severity_Warning); return false; } @@ -242,18 +246,20 @@ bool CSMTools::TopicInfoCheckStage::verifyFactionRank(const std::string& faction bool CSMTools::TopicInfoCheckStage::verifyItem(const std::string& item, const CSMWorld::UniversalId& id, CSMDoc::Messages& messages) { - const std::string specifier = "Item"; - CSMWorld::RefIdData::LocalIndex index = mReferencables.searchId(item); if (index.first == -1) { - writeMissingIdError(specifier, item, id, messages); + std::ostringstream stream; + stream << "Item '" << item << "' does not exist"; + messages.add(id, stream.str(), "", CSMDoc::Message::Severity_Error); return false; } else if (mReferencables.getRecord(index).isDeleted()) { - writeDeletedRecordError(specifier, item, id, messages); + std::ostringstream stream; + stream << "Deleted item '" << item << "' is being referenced"; + messages.add(id, stream.str(), "", CSMDoc::Message::Severity_Error); return false; } else @@ -276,8 +282,13 @@ bool CSMTools::TopicInfoCheckStage::verifyItem(const std::string& item, const CS break; default: - writeInvalidTypeError(specifier, item, index.second, "Potion, Armor, Book, etc.", id, messages); + { + CSMWorld::UniversalId tempId(index.second, item); + std::ostringstream stream; + stream << "Object '" << item << "' has invalid type " << tempId.getTypeName() << " (an item can be a potion, an armor piece, a book and so on)"; + messages.add(id, stream.str(), "", CSMDoc::Message::Severity_Error); return false; + } } } @@ -291,13 +302,13 @@ bool CSMTools::TopicInfoCheckStage::verifySelectStruct(const ESM::DialInfo::Sele if (infoCondition.getFunctionName() == CSMWorld::ConstInfoSelectWrapper::Function_None) { - messages.add(id, "Invalid Info Condition: " + infoCondition.toString(), "", CSMDoc::Message::Severity_Error); + messages.add(id, "Invalid condition '" + infoCondition.toString() + "'", "", CSMDoc::Message::Severity_Error); return false; } else if (!infoCondition.variantTypeIsValid()) { std::ostringstream stream; - stream << "Info Condition: Value for \"" << infoCondition.toString() << "\" has a type of "; + stream << "Value of condition '" << infoCondition.toString() << "' has invalid "; switch (select.mValue.getType()) { @@ -307,8 +318,9 @@ bool CSMTools::TopicInfoCheckStage::verifySelectStruct(const ESM::DialInfo::Sele case ESM::VT_Long: stream << "Long"; break; case ESM::VT_Float: stream << "Float"; break; case ESM::VT_String: stream << "String"; break; - default: stream << "Unknown"; break; + default: stream << "unknown"; break; } + stream << " type"; messages.add(id, stream.str(), "", CSMDoc::Message::Severity_Error); return false; @@ -316,7 +328,7 @@ bool CSMTools::TopicInfoCheckStage::verifySelectStruct(const ESM::DialInfo::Sele else if (infoCondition.conditionIsAlwaysTrue()) { std::ostringstream stream; - stream << "Info Condition: " << infoCondition.toString() << " is always true"; + stream << "Condition '" << infoCondition.toString() << "' is always true"; messages.add(id, stream.str(), "", CSMDoc::Message::Severity_Warning); return false; @@ -324,7 +336,7 @@ bool CSMTools::TopicInfoCheckStage::verifySelectStruct(const ESM::DialInfo::Sele else if (infoCondition.conditionIsNeverTrue()) { std::ostringstream stream; - stream << "Info Condition: " << infoCondition.toString() << " is never true"; + stream << "Condition '" << infoCondition.toString() << "' is never true"; messages.add(id, stream.str(), "", CSMDoc::Message::Severity_Warning); return false; @@ -383,11 +395,11 @@ bool CSMTools::TopicInfoCheckStage::verifySelectStruct(const ESM::DialInfo::Sele bool CSMTools::TopicInfoCheckStage::verifySound(const std::string& sound, const CSMWorld::UniversalId& id, CSMDoc::Messages& messages) { - const std::string specifier = "Sound File"; - if (mSoundFiles.searchId(sound) == -1) { - writeMissingIdError(specifier, sound, id, messages); + std::ostringstream stream; + stream << "Sound file '" << sound << "' does not exist"; + messages.add(id, stream.str(), "", CSMDoc::Message::Severity_Error); return false; } @@ -402,47 +414,18 @@ bool CSMTools::TopicInfoCheckStage::verifyId(const std::string& name, const CSMW if (index == -1) { - writeMissingIdError(T::getRecordType(), name, id, messages); + std::ostringstream stream; + stream << T::getRecordType() + " '" << name << "' does not exist"; + messages.add(id, stream.str(), "", CSMDoc::Message::Severity_Error); return false; } else if (collection.getRecord(index).isDeleted()) { - writeDeletedRecordError(T::getRecordType(), name, id, messages); + std::ostringstream stream; + stream << "Deleted " << T::getRecordType() << " record '" << name << "' is being referenced"; + messages.add(id, stream.str(), "", CSMDoc::Message::Severity_Error); return false; } return true; } - -// Error functions - -void CSMTools::TopicInfoCheckStage::writeMissingIdError(const std::string& specifier, const std::string& missingId, - const CSMWorld::UniversalId& id, CSMDoc::Messages& messages) -{ - std::ostringstream stream; - stream << specifier << ": ID or name \"" << missingId << "\" could not be found"; - - messages.add(id, stream.str(), "", CSMDoc::Message::Severity_Error); -} - -void CSMTools::TopicInfoCheckStage::writeDeletedRecordError(const std::string& specifier, const std::string& recordId, - const CSMWorld::UniversalId& id, CSMDoc::Messages& messages) -{ - std::ostringstream stream; - stream << specifier << ": Deleted record with ID \"" << recordId << "\" is being referenced"; - - messages.add(id, stream.str(), "", CSMDoc::Message::Severity_Error); -} - -void CSMTools::TopicInfoCheckStage::writeInvalidTypeError(const std::string& specifier, const std::string& invalidId, - CSMWorld::UniversalId::Type invalidType, const std::string& expectedType, const CSMWorld::UniversalId& id, - CSMDoc::Messages& messages) -{ - CSMWorld::UniversalId tempId(invalidType, invalidId); - - std::ostringstream stream; - stream << specifier << ": invalid type of " << tempId.getTypeName() << " was found for referencable \"" - << invalidId << "\" (can be of type " << expectedType << ")"; - - messages.add(id, stream.str(), "", CSMDoc::Message::Severity_Error); -} diff --git a/apps/opencs/model/tools/topicinfocheck.hpp b/apps/opencs/model/tools/topicinfocheck.hpp index dbd5fe1c5..9575181b0 100644 --- a/apps/opencs/model/tools/topicinfocheck.hpp +++ b/apps/opencs/model/tools/topicinfocheck.hpp @@ -80,17 +80,6 @@ namespace CSMTools template bool verifyId(const std::string& name, const CSMWorld::IdCollection& collection, const CSMWorld::UniversalId& id, CSMDoc::Messages& messages); - - // Common error messages - void writeMissingIdError(const std::string& specifier, const std::string& missingId, - const CSMWorld::UniversalId& id, CSMDoc::Messages& messages); - - void writeDeletedRecordError(const std::string& specifier, const std::string& recordId, - const CSMWorld::UniversalId& id, CSMDoc::Messages& messages); - - void writeInvalidTypeError(const std::string& specifier, const std::string& invalidId, - CSMWorld::UniversalId::Type invalidType, const std::string& expectedType, - const CSMWorld::UniversalId& id, CSMDoc::Messages& messages); }; } From 1f717def35c32dfa78c356239dd0a32b83554e19 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Sat, 25 Aug 2018 00:27:42 +0300 Subject: [PATCH 097/196] Update journal, start script and spell verifiers messages --- apps/opencs/model/tools/journalcheck.cpp | 18 +++++------------- apps/opencs/model/tools/spellcheck.cpp | 4 ++-- apps/opencs/model/tools/startscriptcheck.cpp | 3 +-- 3 files changed, 8 insertions(+), 17 deletions(-) diff --git a/apps/opencs/model/tools/journalcheck.cpp b/apps/opencs/model/tools/journalcheck.cpp index 4a7ab7d66..bd77e95b6 100644 --- a/apps/opencs/model/tools/journalcheck.cpp +++ b/apps/opencs/model/tools/journalcheck.cpp @@ -33,6 +33,7 @@ void CSMTools::JournalCheckStage::perform(int stage, CSMDoc::Messages& messages) std::set questIndices; CSMWorld::InfoCollection::Range range = mJournalInfos.getTopicRange(journal.mId); + CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_Journal, journal.mId); for (CSMWorld::InfoCollection::RecordConstIterator it = range.first; it != range.second; ++it) { @@ -56,9 +57,7 @@ void CSMTools::JournalCheckStage::perform(int stage, CSMDoc::Messages& messages) if (journalInfo.mResponse.empty()) { - CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_JournalInfo, journalInfo.mId); - - messages.add(id, "Journal Info: missing description", "", CSMDoc::Message::Severity_Warning); + messages.add(id, "Missing journal entry text", "", CSMDoc::Message::Severity_Warning); } std::pair::iterator, bool> result = questIndices.insert(journalInfo.mData.mJournalIndex); @@ -66,25 +65,18 @@ void CSMTools::JournalCheckStage::perform(int stage, CSMDoc::Messages& messages) // Duplicate index if (result.second == false) { - CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_JournalInfo, journalInfo.mId); - std::ostringstream stream; - stream << "Journal: duplicated quest index " << journalInfo.mData.mJournalIndex; - + stream << "Duplicated quest index " << journalInfo.mData.mJournalIndex; messages.add(id, stream.str(), "", CSMDoc::Message::Severity_Error); } } if (totalInfoCount == 0) { - CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_Journal, journal.mId); - - messages.add(id, "Journal: no defined Journal Infos", "", CSMDoc::Message::Severity_Warning); + messages.add(id, "No related journal entry", "", CSMDoc::Message::Severity_Warning); } else if (statusNamedCount > 1) { - CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_Journal, journal.mId); - - messages.add(id, "Journal: multiple infos with quest status \"Named\"", "", CSMDoc::Message::Severity_Error); + messages.add(id, "Multiple entries with quest status 'Named'", "", CSMDoc::Message::Severity_Error); } } diff --git a/apps/opencs/model/tools/spellcheck.cpp b/apps/opencs/model/tools/spellcheck.cpp index 3e59f0d9a..6c08aca37 100644 --- a/apps/opencs/model/tools/spellcheck.cpp +++ b/apps/opencs/model/tools/spellcheck.cpp @@ -36,11 +36,11 @@ void CSMTools::SpellCheckStage::perform (int stage, CSMDoc::Messages& messages) // test for empty name and description if (spell.mName.empty()) - messages.push_back (std::make_pair (id, spell.mId + " has an empty name")); + messages.push_back (std::make_pair (id, "Name is missing")); // test for invalid cost values if (spell.mData.mCost<0) - messages.push_back (std::make_pair (id, spell.mId + " has a negative spell costs")); + messages.push_back (std::make_pair (id, "Spell cost is negative")); /// \todo check data members that can't be edited in the table view } diff --git a/apps/opencs/model/tools/startscriptcheck.cpp b/apps/opencs/model/tools/startscriptcheck.cpp index b1d92380b..5a9f63dc4 100644 --- a/apps/opencs/model/tools/startscriptcheck.cpp +++ b/apps/opencs/model/tools/startscriptcheck.cpp @@ -25,8 +25,7 @@ void CSMTools::StartScriptCheckStage::perform(int stage, CSMDoc::Messages& messa CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_StartScript, scriptId); if (mScripts.searchId (Misc::StringUtils::lowerCase (scriptId))==-1) - messages.push_back ( - std::make_pair (id, "Start script " + scriptId + " does not exist")); + messages.push_back (std::make_pair (id, "Start script " + scriptId + " does not exist")); } int CSMTools::StartScriptCheckStage::setup() From 38ea7928f54876755d30a732fd36ed2db547d039 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Sat, 25 Aug 2018 00:47:38 +0300 Subject: [PATCH 098/196] Add sound file checks to sound record verifier --- apps/opencs/model/tools/soundcheck.cpp | 17 ++++++++++++++--- apps/opencs/model/tools/soundcheck.hpp | 9 ++++++++- apps/opencs/model/tools/tools.cpp | 2 +- 3 files changed, 23 insertions(+), 5 deletions(-) diff --git a/apps/opencs/model/tools/soundcheck.cpp b/apps/opencs/model/tools/soundcheck.cpp index 3fdbcc3bc..5708a59d3 100644 --- a/apps/opencs/model/tools/soundcheck.cpp +++ b/apps/opencs/model/tools/soundcheck.cpp @@ -6,10 +6,14 @@ #include "../prefs/state.hpp" +#include "../world/data.hpp" +#include "../world/resources.hpp" #include "../world/universalid.hpp" -CSMTools::SoundCheckStage::SoundCheckStage (const CSMWorld::IdCollection& sounds) -: mSounds (sounds) +CSMTools::SoundCheckStage::SoundCheckStage (const CSMWorld::IdCollection &sounds, + const CSMWorld::Resources &soundfiles) + : mSounds (sounds), + mSoundFiles (soundfiles) { mIgnoreBaseRecords = false; } @@ -36,5 +40,12 @@ void CSMTools::SoundCheckStage::perform (int stage, CSMDoc::Messages& messages) if (sound.mData.mMinRange>sound.mData.mMaxRange) messages.push_back (std::make_pair (id, "Minimum range larger than maximum range")); - /// \todo check, if the sound file exists ADD CHECK HERE + if (sound.mSound.empty()) + { + messages.push_back(std::make_pair(id, "Sound file is missing")); + } + else if (mSoundFiles.searchId(sound.mSound) == -1) + { + messages.push_back(std::make_pair(id, "Sound file '" + sound.mSound + "' does not exist")); + } } diff --git a/apps/opencs/model/tools/soundcheck.hpp b/apps/opencs/model/tools/soundcheck.hpp index d6fff5263..47c3249ce 100644 --- a/apps/opencs/model/tools/soundcheck.hpp +++ b/apps/opencs/model/tools/soundcheck.hpp @@ -7,17 +7,24 @@ #include "../doc/stage.hpp" +namespace CSMWorld +{ + class Resources; +} + namespace CSMTools { /// \brief VerifyStage: make sure that sound records are internally consistent class SoundCheckStage : public CSMDoc::Stage { const CSMWorld::IdCollection& mSounds; + const CSMWorld::Resources &mSoundFiles; bool mIgnoreBaseRecords; public: - SoundCheckStage (const CSMWorld::IdCollection& sounds); + SoundCheckStage (const CSMWorld::IdCollection& sounds, + const CSMWorld::Resources &soundfiles); virtual int setup(); ///< \return number of steps diff --git a/apps/opencs/model/tools/tools.cpp b/apps/opencs/model/tools/tools.cpp index 0946225cf..dfa2ae202 100644 --- a/apps/opencs/model/tools/tools.cpp +++ b/apps/opencs/model/tools/tools.cpp @@ -74,7 +74,7 @@ CSMDoc::OperationHolder *CSMTools::Tools::getVerifier() mVerifierOperation->appendStage (new RaceCheckStage (mData.getRaces())); - mVerifierOperation->appendStage (new SoundCheckStage (mData.getSounds())); + mVerifierOperation->appendStage (new SoundCheckStage (mData.getSounds(), mData.getResources (CSMWorld::UniversalId::Type_SoundsRes))); mVerifierOperation->appendStage (new RegionCheckStage (mData.getRegions())); From d90940011f7c1bd5f25dedc9cae476b61b1f7b15 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Sat, 25 Aug 2018 01:22:41 +0300 Subject: [PATCH 099/196] Add model checks to object record verifier --- .../opencs/model/tools/referenceablecheck.cpp | 123 ++++++++++-------- .../opencs/model/tools/referenceablecheck.hpp | 7 +- apps/opencs/model/tools/tools.cpp | 3 +- 3 files changed, 75 insertions(+), 58 deletions(-) diff --git a/apps/opencs/model/tools/referenceablecheck.cpp b/apps/opencs/model/tools/referenceablecheck.cpp index 6d06cce12..8a1103c3d 100644 --- a/apps/opencs/model/tools/referenceablecheck.cpp +++ b/apps/opencs/model/tools/referenceablecheck.cpp @@ -11,13 +11,14 @@ CSMTools::ReferenceableCheckStage::ReferenceableCheckStage( const CSMWorld::RefIdData& referenceable, const CSMWorld::IdCollection& races, const CSMWorld::IdCollection& classes, const CSMWorld::IdCollection& faction, - const CSMWorld::IdCollection& scripts) - : - mReferencables(referenceable), + const CSMWorld::IdCollection& scripts, + const CSMWorld::Resources& models) + :mObjects(referenceable), mRaces(races), mClasses(classes), mFactions(faction), mScripts(scripts), + mModels(models), mPlayerPresent(false) { mIgnoreBaseRecords = false; @@ -26,201 +27,201 @@ CSMTools::ReferenceableCheckStage::ReferenceableCheckStage( void CSMTools::ReferenceableCheckStage::perform (int stage, CSMDoc::Messages& messages) { //Checks for books, than, when stage is above mBooksSize goes to other checks, with (stage - PrevSum) as stage. - const int bookSize(mReferencables.getBooks().getSize()); + const int bookSize(mObjects.getBooks().getSize()); if (stage < bookSize) { - bookCheck(stage, mReferencables.getBooks(), messages); + bookCheck(stage, mObjects.getBooks(), messages); return; } stage -= bookSize; - const int activatorSize(mReferencables.getActivators().getSize()); + const int activatorSize(mObjects.getActivators().getSize()); if (stage < activatorSize) { - activatorCheck(stage, mReferencables.getActivators(), messages); + activatorCheck(stage, mObjects.getActivators(), messages); return; } stage -= activatorSize; - const int potionSize(mReferencables.getPotions().getSize()); + const int potionSize(mObjects.getPotions().getSize()); if (stage < potionSize) { - potionCheck(stage, mReferencables.getPotions(), messages); + potionCheck(stage, mObjects.getPotions(), messages); return; } stage -= potionSize; - const int apparatusSize(mReferencables.getApparati().getSize()); + const int apparatusSize(mObjects.getApparati().getSize()); if (stage < apparatusSize) { - apparatusCheck(stage, mReferencables.getApparati(), messages); + apparatusCheck(stage, mObjects.getApparati(), messages); return; } stage -= apparatusSize; - const int armorSize(mReferencables.getArmors().getSize()); + const int armorSize(mObjects.getArmors().getSize()); if (stage < armorSize) { - armorCheck(stage, mReferencables.getArmors(), messages); + armorCheck(stage, mObjects.getArmors(), messages); return; } stage -= armorSize; - const int clothingSize(mReferencables.getClothing().getSize()); + const int clothingSize(mObjects.getClothing().getSize()); if (stage < clothingSize) { - clothingCheck(stage, mReferencables.getClothing(), messages); + clothingCheck(stage, mObjects.getClothing(), messages); return; } stage -= clothingSize; - const int containerSize(mReferencables.getContainers().getSize()); + const int containerSize(mObjects.getContainers().getSize()); if (stage < containerSize) { - containerCheck(stage, mReferencables.getContainers(), messages); + containerCheck(stage, mObjects.getContainers(), messages); return; } stage -= containerSize; - const int doorSize(mReferencables.getDoors().getSize()); + const int doorSize(mObjects.getDoors().getSize()); if (stage < doorSize) { - doorCheck(stage, mReferencables.getDoors(), messages); + doorCheck(stage, mObjects.getDoors(), messages); return; } stage -= doorSize; - const int ingredientSize(mReferencables.getIngredients().getSize()); + const int ingredientSize(mObjects.getIngredients().getSize()); if (stage < ingredientSize) { - ingredientCheck(stage, mReferencables.getIngredients(), messages); + ingredientCheck(stage, mObjects.getIngredients(), messages); return; } stage -= ingredientSize; - const int creatureLevListSize(mReferencables.getCreatureLevelledLists().getSize()); + const int creatureLevListSize(mObjects.getCreatureLevelledLists().getSize()); if (stage < creatureLevListSize) { - creaturesLevListCheck(stage, mReferencables.getCreatureLevelledLists(), messages); + creaturesLevListCheck(stage, mObjects.getCreatureLevelledLists(), messages); return; } stage -= creatureLevListSize; - const int itemLevelledListSize(mReferencables.getItemLevelledList().getSize()); + const int itemLevelledListSize(mObjects.getItemLevelledList().getSize()); if (stage < itemLevelledListSize) { - itemLevelledListCheck(stage, mReferencables.getItemLevelledList(), messages); + itemLevelledListCheck(stage, mObjects.getItemLevelledList(), messages); return; } stage -= itemLevelledListSize; - const int lightSize(mReferencables.getLights().getSize()); + const int lightSize(mObjects.getLights().getSize()); if (stage < lightSize) { - lightCheck(stage, mReferencables.getLights(), messages); + lightCheck(stage, mObjects.getLights(), messages); return; } stage -= lightSize; - const int lockpickSize(mReferencables.getLocpicks().getSize()); + const int lockpickSize(mObjects.getLocpicks().getSize()); if (stage < lockpickSize) { - lockpickCheck(stage, mReferencables.getLocpicks(), messages); + lockpickCheck(stage, mObjects.getLocpicks(), messages); return; } stage -= lockpickSize; - const int miscSize(mReferencables.getMiscellaneous().getSize()); + const int miscSize(mObjects.getMiscellaneous().getSize()); if (stage < miscSize) { - miscCheck(stage, mReferencables.getMiscellaneous(), messages); + miscCheck(stage, mObjects.getMiscellaneous(), messages); return; } stage -= miscSize; - const int npcSize(mReferencables.getNPCs().getSize()); + const int npcSize(mObjects.getNPCs().getSize()); if (stage < npcSize) { - npcCheck(stage, mReferencables.getNPCs(), messages); + npcCheck(stage, mObjects.getNPCs(), messages); return; } stage -= npcSize; - const int weaponSize(mReferencables.getWeapons().getSize()); + const int weaponSize(mObjects.getWeapons().getSize()); if (stage < weaponSize) { - weaponCheck(stage, mReferencables.getWeapons(), messages); + weaponCheck(stage, mObjects.getWeapons(), messages); return; } stage -= weaponSize; - const int probeSize(mReferencables.getProbes().getSize()); + const int probeSize(mObjects.getProbes().getSize()); if (stage < probeSize) { - probeCheck(stage, mReferencables.getProbes(), messages); + probeCheck(stage, mObjects.getProbes(), messages); return; } stage -= probeSize; - const int repairSize(mReferencables.getRepairs().getSize()); + const int repairSize(mObjects.getRepairs().getSize()); if (stage < repairSize) { - repairCheck(stage, mReferencables.getRepairs(), messages); + repairCheck(stage, mObjects.getRepairs(), messages); return; } stage -= repairSize; - const int staticSize(mReferencables.getStatics().getSize()); + const int staticSize(mObjects.getStatics().getSize()); if (stage < staticSize) { - staticCheck(stage, mReferencables.getStatics(), messages); + staticCheck(stage, mObjects.getStatics(), messages); return; } stage -= staticSize; - const int creatureSize(mReferencables.getCreatures().getSize()); + const int creatureSize(mObjects.getCreatures().getSize()); if (stage < creatureSize) { - creatureCheck(stage, mReferencables.getCreatures(), messages); + creatureCheck(stage, mObjects.getCreatures(), messages); return; } // if we come that far, we are about to perform our last, final check. @@ -233,7 +234,7 @@ int CSMTools::ReferenceableCheckStage::setup() mPlayerPresent = false; mIgnoreBaseRecords = CSMPrefs::get()["Reports"]["ignore-base-records"].isTrue(); - return mReferencables.getSize() + 1; + return mObjects.getSize() + 1; } void CSMTools::ReferenceableCheckStage::bookCheck( @@ -272,7 +273,9 @@ void CSMTools::ReferenceableCheckStage::activatorCheck( //Checking for model, IIRC all activators should have a model if (activator.mModel.empty()) - messages.push_back (std::make_pair (id, "Model is missing")); // ADD CHECK HERE + messages.push_back (std::make_pair (id, "Model is missing")); + else if (mModels.searchId(activator.mModel) == -1) + messages.push_back (std::make_pair (id, "Model '" + activator.mModel + "' does not exist")); // Check that mentioned scripts exist scriptCheck(activator, messages, id.toString()); @@ -383,9 +386,11 @@ void CSMTools::ReferenceableCheckStage::containerCheck( const ESM::Container& container = (dynamic_cast& >(baseRecord)).get(); CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_Container, container.mId); - //Checking for model, IIRC all containers should have a model + //Checking for model if (container.mModel.empty()) - messages.push_back (std::make_pair (id, "Model is missing")); // ADD CHECK HERE + messages.push_back (std::make_pair (id, "Model is missing")); + else if (mModels.searchId(container.mModel) == -1) + messages.push_back (std::make_pair (id, "Model '" + container.mModel + "' does not exist")); //Checking for capacity (weight) if (container.mWeight < 0) //0 is allowed @@ -416,7 +421,9 @@ void CSMTools::ReferenceableCheckStage::creatureCheck ( CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_Creature, creature.mId); if (creature.mModel.empty()) - messages.push_back (std::make_pair (id, "Model is missing")); // ADD CHECK HERE + messages.push_back (std::make_pair (id, "Model is missing")); + else if (mModels.searchId(creature.mModel) == -1) + messages.push_back (std::make_pair (id, "Model '" + creature.mModel + "' does not exist")); if (creature.mName.empty()) messages.push_back (std::make_pair (id, "Name is missing")); @@ -496,7 +503,9 @@ void CSMTools::ReferenceableCheckStage::doorCheck( messages.push_back (std::make_pair (id, "Name is missing")); if (door.mModel.empty()) - messages.push_back (std::make_pair (id, "Model is missing")); // ADD CHECK HERE + messages.push_back (std::make_pair (id, "Model is missing")); + else if (mModels.searchId(door.mModel) == -1) + messages.push_back (std::make_pair (id, "Model '" + door.mModel + "' does not exist")); // Check that mentioned scripts exist scriptCheck(door, messages, id.toString()); @@ -729,8 +738,6 @@ void CSMTools::ReferenceableCheckStage::npcCheck ( if (npc.mHair.empty()) messages.push_back (std::make_pair (id, "Hair is missing")); // ADD CHECK HERE - //TODO: reputation, Disposition, rank, everything else - // Check inventory inventoryListCheck(npc.mInventory.mList, messages, id.toString()); @@ -871,6 +878,8 @@ void CSMTools::ReferenceableCheckStage::staticCheck ( if (staticElement.mModel.empty()) messages.push_back (std::make_pair (id, "Model is missing")); + else if (mModels.searchId(staticElement.mModel) == -1) + messages.push_back (std::make_pair (id, "Model '" + staticElement.mModel + "' does not exist")); } //final check @@ -890,7 +899,7 @@ void CSMTools::ReferenceableCheckStage::inventoryListCheck( for (size_t i = 0; i < itemList.size(); ++i) { std::string itemName = itemList[i].mItem.toString(); - CSMWorld::RefIdData::LocalIndex localIndex = mReferencables.searchId(itemName); + CSMWorld::RefIdData::LocalIndex localIndex = mObjects.searchId(itemName); if (localIndex.first == -1) messages.push_back (std::make_pair (id, "Item '" + itemName + "' does not exist")); @@ -938,7 +947,9 @@ template void CSMTools::ReferenceableCheckStage::inventoryItemChe //checking for model if (someItem.mModel.empty()) - messages.push_back (std::make_pair (someID, "Model is missing")); // ADD CHECK HERE + messages.push_back (std::make_pair (someID, "Model is missing")); + else if (mModels.searchId(someItem.mModel) == -1) + messages.push_back(std::make_pair(someID, "Model '" + someItem.mModel + "' does not exist")); //checking for icon if (someItem.mIcon.empty()) @@ -964,7 +975,9 @@ template void CSMTools::ReferenceableCheckStage::inventoryItemChe //checking for model if (someItem.mModel.empty()) - messages.push_back (std::make_pair (someID, "Model is missing")); // ADD CHECK HERE + messages.push_back (std::make_pair (someID, "Model is missing")); + else if (mModels.searchId(someItem.mModel) == -1) + messages.push_back (std::make_pair (someID, "Model '" + someItem.mModel + "' does not exist")); //checking for icon if (someItem.mIcon.empty()) @@ -993,7 +1006,7 @@ template void CSMTools::ReferenceableCheckStage::listCheck ( { for (unsigned i = 0; i < someList.mList.size(); ++i) { - if (mReferencables.searchId(someList.mList[i].mId).first == -1) + if (mObjects.searchId(someList.mList[i].mId).first == -1) messages.push_back (std::make_pair (someID, "Object '" + someList.mList[i].mId + "' does not exist")); if (someList.mList[i].mLevel < 1) diff --git a/apps/opencs/model/tools/referenceablecheck.hpp b/apps/opencs/model/tools/referenceablecheck.hpp index f9341bd9c..24f73176c 100644 --- a/apps/opencs/model/tools/referenceablecheck.hpp +++ b/apps/opencs/model/tools/referenceablecheck.hpp @@ -5,6 +5,7 @@ #include "../doc/stage.hpp" #include "../world/data.hpp" #include "../world/refiddata.hpp" +#include "../world/resources.hpp" namespace CSMTools { @@ -16,7 +17,8 @@ namespace CSMTools const CSMWorld::IdCollection& races, const CSMWorld::IdCollection& classes, const CSMWorld::IdCollection& factions, - const CSMWorld::IdCollection& scripts); + const CSMWorld::IdCollection& scripts, + const CSMWorld::Resources& models); virtual void perform(int stage, CSMDoc::Messages& messages); virtual int setup(); @@ -76,11 +78,12 @@ namespace CSMTools CSMDoc::Messages& messages, const std::string& someID); - const CSMWorld::RefIdData& mReferencables; + const CSMWorld::RefIdData& mObjects; const CSMWorld::IdCollection& mRaces; const CSMWorld::IdCollection& mClasses; const CSMWorld::IdCollection& mFactions; const CSMWorld::IdCollection& mScripts; + const CSMWorld::Resources& mModels; bool mPlayerPresent; bool mIgnoreBaseRecords; }; diff --git a/apps/opencs/model/tools/tools.cpp b/apps/opencs/model/tools/tools.cpp index dfa2ae202..2e471d66f 100644 --- a/apps/opencs/model/tools/tools.cpp +++ b/apps/opencs/model/tools/tools.cpp @@ -82,7 +82,8 @@ CSMDoc::OperationHolder *CSMTools::Tools::getVerifier() mVerifierOperation->appendStage (new SpellCheckStage (mData.getSpells())); - mVerifierOperation->appendStage (new ReferenceableCheckStage (mData.getReferenceables().getDataSet(), mData.getRaces(), mData.getClasses(), mData.getFactions(), mData.getScripts())); + mVerifierOperation->appendStage (new ReferenceableCheckStage (mData.getReferenceables().getDataSet(), mData.getRaces(), mData.getClasses(), mData.getFactions(), mData.getScripts(), + mData.getResources (CSMWorld::UniversalId::Type_Meshes))); mVerifierOperation->appendStage (new ReferenceCheckStage(mData.getReferences(), mData.getReferenceables(), mData.getCells(), mData.getFactions())); From 34077a6987939791ffd5f62552eaf6b28194f781 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Sat, 25 Aug 2018 01:27:10 +0300 Subject: [PATCH 100/196] Purge unnecessary namespaces --- apps/opencs/model/tools/birthsigncheck.cpp | 1 - apps/opencs/model/tools/birthsigncheck.hpp | 6 +----- apps/opencs/model/tools/magiceffectcheck.cpp | 1 - apps/opencs/model/tools/magiceffectcheck.hpp | 6 +----- 4 files changed, 2 insertions(+), 12 deletions(-) diff --git a/apps/opencs/model/tools/birthsigncheck.cpp b/apps/opencs/model/tools/birthsigncheck.cpp index 4ef264f65..b61bf7421 100644 --- a/apps/opencs/model/tools/birthsigncheck.cpp +++ b/apps/opencs/model/tools/birthsigncheck.cpp @@ -9,7 +9,6 @@ #include "../prefs/state.hpp" #include "../world/data.hpp" -#include "../world/resources.hpp" #include "../world/universalid.hpp" namespace diff --git a/apps/opencs/model/tools/birthsigncheck.hpp b/apps/opencs/model/tools/birthsigncheck.hpp index cd22fb6d0..d032d3cef 100644 --- a/apps/opencs/model/tools/birthsigncheck.hpp +++ b/apps/opencs/model/tools/birthsigncheck.hpp @@ -4,14 +4,10 @@ #include #include "../world/idcollection.hpp" +#include "../world/resources.hpp" #include "../doc/stage.hpp" -namespace CSMWorld -{ - class Resources; -} - namespace CSMTools { /// \brief VerifyStage: make sure that birthsign records are internally consistent diff --git a/apps/opencs/model/tools/magiceffectcheck.cpp b/apps/opencs/model/tools/magiceffectcheck.cpp index 7e7a09aa5..77a26c596 100644 --- a/apps/opencs/model/tools/magiceffectcheck.cpp +++ b/apps/opencs/model/tools/magiceffectcheck.cpp @@ -4,7 +4,6 @@ #include "../prefs/state.hpp" -#include "../world/resources.hpp" #include "../world/data.hpp" namespace diff --git a/apps/opencs/model/tools/magiceffectcheck.hpp b/apps/opencs/model/tools/magiceffectcheck.hpp index 3e45495c1..22dad3db9 100644 --- a/apps/opencs/model/tools/magiceffectcheck.hpp +++ b/apps/opencs/model/tools/magiceffectcheck.hpp @@ -6,14 +6,10 @@ #include "../world/idcollection.hpp" #include "../world/refidcollection.hpp" +#include "../world/resources.hpp" #include "../doc/stage.hpp" -namespace CSMWorld -{ - class Resources; -} - namespace CSMTools { /// \brief VerifyStage: make sure that magic effect records are internally consistent From dc847dce09aeddbe7df925d305dc96969220538d Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Sat, 25 Aug 2018 01:44:46 +0300 Subject: [PATCH 101/196] Add item icon checks to object record verifier --- .../opencs/model/tools/referenceablecheck.cpp | 21 ++++++++++++++++--- .../opencs/model/tools/referenceablecheck.hpp | 4 +++- apps/opencs/model/tools/tools.cpp | 2 +- 3 files changed, 22 insertions(+), 5 deletions(-) diff --git a/apps/opencs/model/tools/referenceablecheck.cpp b/apps/opencs/model/tools/referenceablecheck.cpp index 8a1103c3d..d3901ac88 100644 --- a/apps/opencs/model/tools/referenceablecheck.cpp +++ b/apps/opencs/model/tools/referenceablecheck.cpp @@ -1,6 +1,7 @@ #include "referenceablecheck.hpp" #include +#include #include "../prefs/state.hpp" @@ -12,13 +13,15 @@ CSMTools::ReferenceableCheckStage::ReferenceableCheckStage( const CSMWorld::IdCollection& classes, const CSMWorld::IdCollection& faction, const CSMWorld::IdCollection& scripts, - const CSMWorld::Resources& models) + const CSMWorld::Resources& models, + const CSMWorld::Resources& icons) :mObjects(referenceable), mRaces(races), mClasses(classes), mFactions(faction), mScripts(scripts), mModels(models), + mIcons(icons), mPlayerPresent(false) { mIgnoreBaseRecords = false; @@ -953,7 +956,13 @@ template void CSMTools::ReferenceableCheckStage::inventoryItemChe //checking for icon if (someItem.mIcon.empty()) - messages.push_back (std::make_pair (someID, "Icon is missing")); // ADD CHECK HERE + messages.push_back (std::make_pair (someID, "Icon is missing")); + else if (mIcons.searchId(someItem.mIcon) == -1) + { + std::string ddsIcon = someItem.mIcon; + if (!(Misc::ResourceHelpers::changeExtensionToDds(ddsIcon) && mIcons.searchId(ddsIcon) != -1)) + messages.push_back(std::make_pair(someID, "Icon '" + someItem.mIcon + "' does not exist")); + } if (enchantable && someItem.mData.mEnchant < 0) messages.push_back (std::make_pair (someID, "Enchantment points number is negative")); @@ -981,7 +990,13 @@ template void CSMTools::ReferenceableCheckStage::inventoryItemChe //checking for icon if (someItem.mIcon.empty()) - messages.push_back (std::make_pair (someID, "Icon is missing")); // ADD CHECK HERE + messages.push_back (std::make_pair (someID, "Icon is missing")); + else if (mIcons.searchId(someItem.mIcon) == -1) + { + std::string ddsIcon = someItem.mIcon; + if (!(Misc::ResourceHelpers::changeExtensionToDds(ddsIcon) && mIcons.searchId(ddsIcon) != -1)) + messages.push_back(std::make_pair(someID, "Icon '" + someItem.mIcon + "' does not exist")); + } } template void CSMTools::ReferenceableCheckStage::toolCheck ( diff --git a/apps/opencs/model/tools/referenceablecheck.hpp b/apps/opencs/model/tools/referenceablecheck.hpp index 24f73176c..5da737875 100644 --- a/apps/opencs/model/tools/referenceablecheck.hpp +++ b/apps/opencs/model/tools/referenceablecheck.hpp @@ -18,7 +18,8 @@ namespace CSMTools const CSMWorld::IdCollection& classes, const CSMWorld::IdCollection& factions, const CSMWorld::IdCollection& scripts, - const CSMWorld::Resources& models); + const CSMWorld::Resources& models, + const CSMWorld::Resources& icons); virtual void perform(int stage, CSMDoc::Messages& messages); virtual int setup(); @@ -84,6 +85,7 @@ namespace CSMTools const CSMWorld::IdCollection& mFactions; const CSMWorld::IdCollection& mScripts; const CSMWorld::Resources& mModels; + const CSMWorld::Resources& mIcons; bool mPlayerPresent; bool mIgnoreBaseRecords; }; diff --git a/apps/opencs/model/tools/tools.cpp b/apps/opencs/model/tools/tools.cpp index 2e471d66f..87b5041e0 100644 --- a/apps/opencs/model/tools/tools.cpp +++ b/apps/opencs/model/tools/tools.cpp @@ -83,7 +83,7 @@ CSMDoc::OperationHolder *CSMTools::Tools::getVerifier() mVerifierOperation->appendStage (new SpellCheckStage (mData.getSpells())); mVerifierOperation->appendStage (new ReferenceableCheckStage (mData.getReferenceables().getDataSet(), mData.getRaces(), mData.getClasses(), mData.getFactions(), mData.getScripts(), - mData.getResources (CSMWorld::UniversalId::Type_Meshes))); + mData.getResources (CSMWorld::UniversalId::Type_Meshes), mData.getResources (CSMWorld::UniversalId::Type_Icons))); mVerifierOperation->appendStage (new ReferenceCheckStage(mData.getReferences(), mData.getReferenceables(), mData.getCells(), mData.getFactions())); From 5b8880c6fa24b65f6899a9141a0f64fd991368e9 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Sat, 25 Aug 2018 02:03:55 +0300 Subject: [PATCH 102/196] Update cell reference record verifier messages --- apps/opencs/model/tools/referencecheck.cpp | 42 +++++++++++----------- apps/opencs/model/tools/referencecheck.hpp | 2 +- 2 files changed, 21 insertions(+), 23 deletions(-) diff --git a/apps/opencs/model/tools/referencecheck.cpp b/apps/opencs/model/tools/referencecheck.cpp index 447238be4..dd93b4e9c 100644 --- a/apps/opencs/model/tools/referencecheck.cpp +++ b/apps/opencs/model/tools/referencecheck.cpp @@ -9,7 +9,7 @@ CSMTools::ReferenceCheckStage::ReferenceCheckStage( const CSMWorld::IdCollection& factions) : mReferences(references), - mReferencables(referencables), + mObjects(referencables), mDataSet(referencables.getDataSet()), mCells(cells), mFactions(factions) @@ -30,75 +30,73 @@ void CSMTools::ReferenceCheckStage::perform(int stage, CSMDoc::Messages &message // Check for empty reference id if (cellRef.mRefID.empty()) { - messages.push_back(std::make_pair(id, " is an empty instance (not based on an object)")); + messages.push_back(std::make_pair(id, "Instance is not based on an object")); } else { // Check for non existing referenced object - if (mReferencables.searchId(cellRef.mRefID) == -1) { - messages.push_back(std::make_pair(id, " is referencing non existing object " + cellRef.mRefID)); + if (mObjects.searchId(cellRef.mRefID) == -1) { + messages.push_back(std::make_pair(id, "Instance of a non-existent object '" + cellRef.mRefID + "'")); } else { // Check if reference charge is valid for it's proper referenced type CSMWorld::RefIdData::LocalIndex localIndex = mDataSet.searchId(cellRef.mRefID); bool isLight = localIndex.second == CSMWorld::UniversalId::Type_Light; if ((isLight && cellRef.mChargeFloat < -1) || (!isLight && cellRef.mChargeInt < -1)) { - std::string str = " has invalid charge "; + std::string str = "Invalid charge: "; if (localIndex.second == CSMWorld::UniversalId::Type_Light) str += std::to_string(cellRef.mChargeFloat); else str += std::to_string(cellRef.mChargeInt); - messages.push_back(std::make_pair(id, id.getId() + str)); + messages.push_back(std::make_pair(id, str)); } } } // If object have owner, check if that owner reference is valid - if (!cellRef.mOwner.empty() && mReferencables.searchId(cellRef.mOwner) == -1) - messages.push_back(std::make_pair(id, " has non existing owner " + cellRef.mOwner)); + if (!cellRef.mOwner.empty() && mObjects.searchId(cellRef.mOwner) == -1) + messages.push_back(std::make_pair(id, "Owner object '" + cellRef.mOwner + "' does not exist")); // If object have creature soul trapped, check if that creature reference is valid if (!cellRef.mSoul.empty()) - if (mReferencables.searchId(cellRef.mSoul) == -1) - messages.push_back(std::make_pair(id, " has non existing trapped soul " + cellRef.mSoul)); + if (mObjects.searchId(cellRef.mSoul) == -1) + messages.push_back(std::make_pair(id, "Trapped soul object '" + cellRef.mSoul + "' does not exist")); bool hasFaction = !cellRef.mFaction.empty(); // If object have faction, check if that faction reference is valid if (hasFaction) if (mFactions.searchId(cellRef.mFaction) == -1) - messages.push_back(std::make_pair(id, " has non existing faction " + cellRef.mFaction)); + messages.push_back(std::make_pair(id, "Faction '" + cellRef.mFaction + "' does not exist")); // Check item's faction rank - if (hasFaction && cellRef.mFactionRank < -1) - messages.push_back(std::make_pair(id, " has faction set but has invalid faction rank " + std::to_string(cellRef.mFactionRank))); - else if (!hasFaction && cellRef.mFactionRank != -2) - messages.push_back(std::make_pair(id, " has invalid faction rank " + std::to_string(cellRef.mFactionRank))); + if ((hasFaction && cellRef.mFactionRank < -1) || (!hasFaction && cellRef.mFactionRank != -2)) + messages.push_back(std::make_pair(id, "Invalid faction rank " + std::to_string(cellRef.mFactionRank))); // If door have destination cell, check if that reference is valid if (!cellRef.mDestCell.empty()) if (mCells.searchId(cellRef.mDestCell) == -1) - messages.push_back(std::make_pair(id, " has non existing destination cell " + cellRef.mDestCell)); + messages.push_back(std::make_pair(id, "Destination cell '" + cellRef.mDestCell + "' does not exist")); // Check if scale isn't negative if (cellRef.mScale < 0) { - std::string str = " has negative scale "; + std::string str = "Negative scale: "; str += std::to_string(cellRef.mScale); - messages.push_back(std::make_pair(id, id.getId() + str)); + messages.push_back(std::make_pair(id, str)); } // Check if enchantement points aren't negative or are at full (-1) if (cellRef.mEnchantmentCharge < 0 && cellRef.mEnchantmentCharge != -1) { - std::string str = " has negative enchantment points "; + std::string str = "Negative enchantment points: "; str += std::to_string(cellRef.mEnchantmentCharge); - messages.push_back(std::make_pair(id, id.getId() + str)); + messages.push_back(std::make_pair(id, str)); } // Check if gold value isn't negative if (cellRef.mGoldValue < 0) { - std::string str = " has negative gold value "; + std::string str = "Negative gold value: "; str += cellRef.mGoldValue; - messages.push_back(std::make_pair(id, id.getId() + str)); + messages.push_back(std::make_pair(id, str)); } } diff --git a/apps/opencs/model/tools/referencecheck.hpp b/apps/opencs/model/tools/referencecheck.hpp index 5e25924f3..7373903e6 100644 --- a/apps/opencs/model/tools/referencecheck.hpp +++ b/apps/opencs/model/tools/referencecheck.hpp @@ -19,7 +19,7 @@ namespace CSMTools private: const CSMWorld::RefCollection& mReferences; - const CSMWorld::RefIdCollection& mReferencables; + const CSMWorld::RefIdCollection& mObjects; const CSMWorld::RefIdData& mDataSet; const CSMWorld::IdCollection& mCells; const CSMWorld::IdCollection& mFactions; From 6b226eef8f53d06dfdb9bb0817614ee4db35077b Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Sat, 25 Aug 2018 02:38:02 +0300 Subject: [PATCH 103/196] Use Messages::add in magic effect record verifier --- apps/opencs/model/tools/magiceffectcheck.cpp | 128 ++++++++++++------- 1 file changed, 81 insertions(+), 47 deletions(-) diff --git a/apps/opencs/model/tools/magiceffectcheck.cpp b/apps/opencs/model/tools/magiceffectcheck.cpp index 77a26c596..917e358c3 100644 --- a/apps/opencs/model/tools/magiceffectcheck.cpp +++ b/apps/opencs/model/tools/magiceffectcheck.cpp @@ -4,23 +4,8 @@ #include "../prefs/state.hpp" -#include "../world/data.hpp" - -namespace -{ - void addMessage(CSMDoc::Messages &messages, const CSMWorld::UniversalId &id, const std::string& text) - { - if (!text.empty()) - { - messages.push_back(std::make_pair(id, text)); - } - } -} - std::string CSMTools::MagicEffectCheckStage::checkTexture(const std::string &texture, bool isIcon) const { - if (texture.empty()) return (isIcon ? "Icon is missing" : std::string()); - const CSMWorld::Resources &textures = isIcon ? mIcons : mTextures; if (textures.searchId(texture) != -1) return std::string(); @@ -34,30 +19,16 @@ std::string CSMTools::MagicEffectCheckStage::checkObject(const std::string &id, const CSMWorld::UniversalId &type, const std::string &column) const { - std::string error; - if (!id.empty()) - { - CSMWorld::RefIdData::LocalIndex index = mObjects.getDataSet().searchId(id); - if (index.first == -1) - { - error = column + " '" + id + "' " + "does not exist"; - } - else if (index.second != type.getType()) - { - error = column + " '" + id + "' " + "does not have " + type.getTypeName() + " type"; - } - } - return error; + CSMWorld::RefIdData::LocalIndex index = mObjects.getDataSet().searchId(id); + if (index.first == -1) return (column + " '" + id + "' " + "does not exist"); + else if (index.second != type.getType()) return (column + " '" + id + "' " + "does not have " + type.getTypeName() + " type"); + return std::string(); } std::string CSMTools::MagicEffectCheckStage::checkSound(const std::string &id, const std::string &column) const { - std::string error; - if (!id.empty() && mSounds.searchId(id) == -1) - { - error = column + " '" + id + "' " + "does not exist"; - } - return error; + if (!id.empty() && mSounds.searchId(id) == -1) return (column + " '" + id + "' " + "does not exist"); + return std::string(); } CSMTools::MagicEffectCheckStage::MagicEffectCheckStage(const CSMWorld::IdCollection &effects, @@ -94,22 +65,85 @@ void CSMTools::MagicEffectCheckStage::perform(int stage, CSMDoc::Messages &messa if (effect.mDescription.empty()) { - addMessage(messages, id, "Description is missing"); + messages.add(id, "Description is missing", "", CSMDoc::Message::Severity_Warning); } if (effect.mData.mBaseCost < 0.0f) { - addMessage(messages, id, "Base cost is negative"); + messages.add(id, "Base cost is negative", "", CSMDoc::Message::Severity_Error); } - addMessage(messages, id, checkTexture(effect.mIcon, true)); - addMessage(messages, id, checkTexture(effect.mParticle, false)); - addMessage(messages, id, checkObject(effect.mCasting, CSMWorld::UniversalId::Type_Static, "Casting object")); - addMessage(messages, id, checkObject(effect.mHit, CSMWorld::UniversalId::Type_Static, "Hit object")); - addMessage(messages, id, checkObject(effect.mArea, CSMWorld::UniversalId::Type_Static, "Area object")); - addMessage(messages, id, checkObject(effect.mBolt, CSMWorld::UniversalId::Type_Weapon, "Bolt object")); - addMessage(messages, id, checkSound(effect.mCastSound, "Casting sound")); - addMessage(messages, id, checkSound(effect.mHitSound, "Hit sound")); - addMessage(messages, id, checkSound(effect.mAreaSound, "Area sound")); - addMessage(messages, id, checkSound(effect.mBoltSound, "Bolt sound")); + if (effect.mIcon.empty()) + { + messages.add(id, "Icon is missing", "", CSMDoc::Message::Severity_Error); + } + else + { + const std::string error = checkTexture(effect.mIcon, true); + if (!error.empty()) + messages.add(id, error, "", CSMDoc::Message::Severity_Error); + } + + if (!effect.mParticle.empty()) + { + const std::string error = checkTexture(effect.mParticle, false); + if (!error.empty()) + messages.add(id, error, "", CSMDoc::Message::Severity_Error); + } + + if (!effect.mCasting.empty()) + { + const std::string error = checkObject(effect.mCasting, CSMWorld::UniversalId::Type_Static, "Casting object"); + if (!error.empty()) + messages.add(id, error, "", CSMDoc::Message::Severity_Error); + } + + if (!effect.mHit.empty()) + { + const std::string error = checkObject(effect.mHit, CSMWorld::UniversalId::Type_Static, "Hit object"); + if (!error.empty()) + messages.add(id, error, "", CSMDoc::Message::Severity_Error); + } + + if (!effect.mArea.empty()) + { + const std::string error = checkObject(effect.mArea, CSMWorld::UniversalId::Type_Static, "Area object"); + if (!error.empty()) + messages.add(id, error, "", CSMDoc::Message::Severity_Error); + } + + if (!effect.mBolt.empty()) + { + const std::string error = checkObject(effect.mBolt, CSMWorld::UniversalId::Type_Static, "Bolt object"); + if (!error.empty()) + messages.add(id, error, "", CSMDoc::Message::Severity_Error); + } + + if (!effect.mCastSound.empty()) + { + const std::string error = checkSound(effect.mCastSound, "Casting sound"); + if (!error.empty()) + messages.add(id, error, "", CSMDoc::Message::Severity_Error); + } + + if (!effect.mHitSound.empty()) + { + const std::string error = checkSound(effect.mHitSound, "Hit sound"); + if (!error.empty()) + messages.add(id, error, "", CSMDoc::Message::Severity_Error); + } + + if (!effect.mAreaSound.empty()) + { + const std::string error = checkSound(effect.mAreaSound, "Area sound"); + if (!error.empty()) + messages.add(id, error, "", CSMDoc::Message::Severity_Error); + } + + if (!effect.mBoltSound.empty()) + { + const std::string error = checkSound(effect.mBoltSound, "Bolt sound"); + if (!error.empty()) + messages.add(id, error, "", CSMDoc::Message::Severity_Error); + } } From d433929194578c477343df7a09183b5ed83dde20 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Sat, 25 Aug 2018 02:48:58 +0300 Subject: [PATCH 104/196] Use Messages::add in birthsign record verifier --- apps/opencs/model/tools/birthsigncheck.cpp | 37 ++++++++++------------ 1 file changed, 17 insertions(+), 20 deletions(-) diff --git a/apps/opencs/model/tools/birthsigncheck.cpp b/apps/opencs/model/tools/birthsigncheck.cpp index b61bf7421..c582da8e4 100644 --- a/apps/opencs/model/tools/birthsigncheck.cpp +++ b/apps/opencs/model/tools/birthsigncheck.cpp @@ -1,37 +1,21 @@ #include "birthsigncheck.hpp" -#include -#include - #include #include #include "../prefs/state.hpp" -#include "../world/data.hpp" #include "../world/universalid.hpp" -namespace -{ - void addMessage(CSMDoc::Messages &messages, const CSMWorld::UniversalId &id, const std::string& text) - { - if (!text.empty()) - { - messages.push_back(std::make_pair(id, text)); - } - } -} - std::string CSMTools::BirthsignCheckStage::checkTexture(const std::string &texture) const { - if (texture.empty()) return "Texture is missing"; if (mTextures.searchId(texture) != -1) return std::string(); std::string ddsTexture = texture; if (Misc::ResourceHelpers::changeExtensionToDds(ddsTexture) && mTextures.searchId(ddsTexture) != -1) return std::string(); - return "Texture '" + texture + "' does not exist"; + return "Image '" + texture + "' does not exist"; } CSMTools::BirthsignCheckStage::BirthsignCheckStage (const CSMWorld::IdCollection& birthsigns, @@ -62,12 +46,25 @@ void CSMTools::BirthsignCheckStage::perform (int stage, CSMDoc::Messages& messag CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Birthsign, birthsign.mId); if (birthsign.mName.empty()) - addMessage(messages, id, "Name is missing"); + { + messages.add(id, "Name is missing", "", CSMDoc::Message::Severity_Error); + } if (birthsign.mDescription.empty()) - addMessage(messages, id, "Description is missing"); + { + messages.add(id, "Description is missing", "", CSMDoc::Message::Severity_Warning); + } - addMessage(messages, id, checkTexture(birthsign.mTexture)); + if (birthsign.mTexture.empty()) + { + messages.add(id, "Image is missing", "", CSMDoc::Message::Severity_Error); + } + else + { + const std::string error = checkTexture(birthsign.mTexture); + if (!error.empty()) + messages.add(id, error, "", CSMDoc::Message::Severity_Error); + } /// \todo check data members that can't be edited in the table view } From 8dcb58d745839d87272446cb318565cc08756484 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Sat, 25 Aug 2018 03:49:10 +0300 Subject: [PATCH 105/196] Use Messages::add in Faction, Sound, Bodypart and Class record verifiers --- apps/opencs/model/tools/bodypartcheck.cpp | 15 +++++++-------- apps/opencs/model/tools/classcheck.cpp | 19 +++++++++---------- apps/opencs/model/tools/factioncheck.cpp | 6 +++--- apps/opencs/model/tools/soundcheck.cpp | 11 +++++------ 4 files changed, 24 insertions(+), 27 deletions(-) diff --git a/apps/opencs/model/tools/bodypartcheck.cpp b/apps/opencs/model/tools/bodypartcheck.cpp index d33705cf6..16dd9891e 100644 --- a/apps/opencs/model/tools/bodypartcheck.cpp +++ b/apps/opencs/model/tools/bodypartcheck.cpp @@ -34,24 +34,23 @@ void CSMTools::BodyPartCheckStage::perform (int stage, CSMDoc::Messages &message // Check BYDT if (bodyPart.mData.mPart > 14 ) - messages.push_back(std::make_pair(id, "Invalid mesh part")); + messages.add(id, "Invalid part", "", CSMDoc::Message::Severity_Error); if (bodyPart.mData.mFlags > 3 ) - messages.push_back(std::make_pair(id, "Invalid flags")); + messages.add(id, "Invalid flags", "", CSMDoc::Message::Severity_Error); if (bodyPart.mData.mType > 2 ) - messages.push_back(std::make_pair(id, "Invalid type")); + messages.add(id, "Invalid type", "", CSMDoc::Message::Severity_Error); // Check MODL - if ( bodyPart.mModel.empty() ) - messages.push_back(std::make_pair(id, "Model is missing" )); + messages.add(id, "Model is missing", "", CSMDoc::Message::Severity_Error); else if ( mMeshes.searchId( bodyPart.mModel ) == -1 ) - messages.push_back(std::make_pair(id, "Model '" + bodyPart.mModel + "' does not exist")); + messages.add(id, "Model '" + bodyPart.mModel + "' does not exist", "", CSMDoc::Message::Severity_Error); // Check FNAM if ( bodyPart.mRace.empty() ) - messages.push_back(std::make_pair(id, "Race is missing" )); + messages.add(id, "Race is missing", "", CSMDoc::Message::Severity_Error); else if ( mRaces.searchId( bodyPart.mRace ) == -1 ) - messages.push_back(std::make_pair(id, "Race '" + bodyPart.mRace + " does not exist")); + messages.add(id, "Race '" + bodyPart.mRace + " does not exist", "", CSMDoc::Message::Severity_Error); } diff --git a/apps/opencs/model/tools/classcheck.cpp b/apps/opencs/model/tools/classcheck.cpp index 157dfab7f..b409c4e06 100644 --- a/apps/opencs/model/tools/classcheck.cpp +++ b/apps/opencs/model/tools/classcheck.cpp @@ -1,6 +1,5 @@ #include "classcheck.hpp" -#include #include #include @@ -37,26 +36,24 @@ void CSMTools::ClassCheckStage::perform (int stage, CSMDoc::Messages& messages) // A class should have a name if (class_.mName.empty()) - messages.push_back (std::make_pair (id, "Name is missing")); + messages.add(id, "Name is missing", "", CSMDoc::Message::Severity_Warning); // A playable class should have a description if (class_.mData.mIsPlayable != 0 && class_.mDescription.empty()) - messages.push_back (std::make_pair (id, "Description of a playable class is missing")); + messages.add(id, "Description of a playable class is missing", "", CSMDoc::Message::Severity_Warning); // test for invalid attributes for (int i=0; i<2; ++i) + { if (class_.mData.mAttribute[i]==-1) { - std::ostringstream stream; - - stream << "Attribute #" << i << " is not set"; - - messages.push_back (std::make_pair (id, stream.str())); + messages.add(id, "Attribute #" + std::to_string(i) + " is not set", "", CSMDoc::Message::Severity_Error); } + } if (class_.mData.mAttribute[0]==class_.mData.mAttribute[1] && class_.mData.mAttribute[0]!=-1) { - messages.push_back (std::make_pair (id, "Same attribute is listed twice")); + messages.add(id, "Same attribute is listed twice", "", CSMDoc::Message::Severity_Warning); } // test for non-unique skill @@ -67,8 +64,10 @@ void CSMTools::ClassCheckStage::perform (int stage, CSMDoc::Messages& messages) ++skills[class_.mData.mSkills[i][i2]]; for (auto &skill : skills) + { if (skill.second>1) { - messages.push_back (std::make_pair (id, "Skill " + ESM::Skill::indexToId (skill.first) + " is listed more than once")); + messages.add(id, "Skill " + ESM::Skill::indexToId (skill.first) + " is listed more than once", "", CSMDoc::Message::Severity_Warning); } + } } diff --git a/apps/opencs/model/tools/factioncheck.cpp b/apps/opencs/model/tools/factioncheck.cpp index d19c0ae52..5bd613851 100644 --- a/apps/opencs/model/tools/factioncheck.cpp +++ b/apps/opencs/model/tools/factioncheck.cpp @@ -37,12 +37,12 @@ void CSMTools::FactionCheckStage::perform (int stage, CSMDoc::Messages& messages // test for empty name if (faction.mName.empty()) - messages.push_back (std::make_pair (id, "Name is missing")); + messages.add(id, "Name is missing", "", CSMDoc::Message::Severity_Warning); // test for invalid attributes if (faction.mData.mAttribute[0]==faction.mData.mAttribute[1] && faction.mData.mAttribute[0]!=-1) { - messages.push_back (std::make_pair (id, "Same attribute is listed twice")); + messages.add(id, "Same attribute is listed twice", "", CSMDoc::Message::Severity_Warning); } // test for non-unique skill @@ -55,7 +55,7 @@ void CSMTools::FactionCheckStage::perform (int stage, CSMDoc::Messages& messages for (auto &skill : skills) if (skill.second>1) { - messages.push_back (std::make_pair (id, "Skill " + ESM::Skill::indexToId (skill.first) + " is listed more than once")); + messages.add(id, "Skill " + ESM::Skill::indexToId (skill.first) + " is listed more than once", "", CSMDoc::Message::Severity_Warning); } /// \todo check data members that can't be edited in the table view diff --git a/apps/opencs/model/tools/soundcheck.cpp b/apps/opencs/model/tools/soundcheck.cpp index 5708a59d3..7bb27e984 100644 --- a/apps/opencs/model/tools/soundcheck.cpp +++ b/apps/opencs/model/tools/soundcheck.cpp @@ -1,12 +1,9 @@ #include "soundcheck.hpp" -#include - #include #include "../prefs/state.hpp" -#include "../world/data.hpp" #include "../world/resources.hpp" #include "../world/universalid.hpp" @@ -38,14 +35,16 @@ void CSMTools::SoundCheckStage::perform (int stage, CSMDoc::Messages& messages) CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Sound, sound.mId); if (sound.mData.mMinRange>sound.mData.mMaxRange) - messages.push_back (std::make_pair (id, "Minimum range larger than maximum range")); + { + messages.add(id, "Minimum range larger than maximum range", "", CSMDoc::Message::Severity_Warning); + } if (sound.mSound.empty()) { - messages.push_back(std::make_pair(id, "Sound file is missing")); + messages.add(id, "Sound file is missing", "", CSMDoc::Message::Severity_Error); } else if (mSoundFiles.searchId(sound.mSound) == -1) { - messages.push_back(std::make_pair(id, "Sound file '" + sound.mSound + "' does not exist")); + messages.add(id, "Sound file '" + sound.mSound + "' does not exist", "", CSMDoc::Message::Severity_Error); } } From b2b9bd94f09b817a20ac9cae3b54e7f174bd4f6d Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Sat, 25 Aug 2018 04:05:48 +0300 Subject: [PATCH 106/196] Fix bolt object type --- apps/opencs/model/tools/magiceffectcheck.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/model/tools/magiceffectcheck.cpp b/apps/opencs/model/tools/magiceffectcheck.cpp index 917e358c3..943d89cdc 100644 --- a/apps/opencs/model/tools/magiceffectcheck.cpp +++ b/apps/opencs/model/tools/magiceffectcheck.cpp @@ -114,7 +114,7 @@ void CSMTools::MagicEffectCheckStage::perform(int stage, CSMDoc::Messages &messa if (!effect.mBolt.empty()) { - const std::string error = checkObject(effect.mBolt, CSMWorld::UniversalId::Type_Static, "Bolt object"); + const std::string error = checkObject(effect.mBolt, CSMWorld::UniversalId::Type_Weapon, "Bolt object"); if (!error.empty()) messages.add(id, error, "", CSMDoc::Message::Severity_Error); } From 35281d7c3844b9c3b1af100fd7317d8ca9eebc78 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Sat, 25 Aug 2018 05:04:49 +0300 Subject: [PATCH 107/196] Use Messages::add in race, soundgen, spell and start script record verifiers --- apps/opencs/model/tools/racecheck.cpp | 18 ++++++++++-------- apps/opencs/model/tools/soundgencheck.cpp | 8 ++++---- apps/opencs/model/tools/spellcheck.cpp | 6 +++--- apps/opencs/model/tools/startscriptcheck.cpp | 2 +- 4 files changed, 18 insertions(+), 16 deletions(-) diff --git a/apps/opencs/model/tools/racecheck.cpp b/apps/opencs/model/tools/racecheck.cpp index 7ce9a8869..3b487b925 100644 --- a/apps/opencs/model/tools/racecheck.cpp +++ b/apps/opencs/model/tools/racecheck.cpp @@ -28,25 +28,27 @@ void CSMTools::RaceCheckStage::performPerRecord (int stage, CSMDoc::Messages& me CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Race, race.mId); // test for empty name and description - if (race.mName.empty()) - messages.push_back (std::make_pair (id, "Name is missing")); + if (race.mName.empty() && race.mData.mFlags & 0x1) + messages.add(id, "Name is missing", "", CSMDoc::Message::Severity_Error); + else if (race.mName.empty()) + messages.add(id, "Name is missing", "", CSMDoc::Message::Severity_Warning); if (race.mDescription.empty()) - messages.push_back (std::make_pair (id, "Description is missing")); + messages.add(id, "Description is missing", "", CSMDoc::Message::Severity_Warning); // test for positive height if (race.mData.mHeight.mMale<=0) - messages.push_back (std::make_pair (id, "Male height is non-positive")); + messages.add(id, "Male height is non-positive", "", CSMDoc::Message::Severity_Error); if (race.mData.mHeight.mFemale<=0) - messages.push_back (std::make_pair (id, "Female height is non-positive")); + messages.add(id, "Female height is non-positive", "", CSMDoc::Message::Severity_Error); // test for non-negative weight if (race.mData.mWeight.mMale<0) - messages.push_back (std::make_pair (id, "Male weight is negative")); + messages.add(id, "Male weight is negative", "", CSMDoc::Message::Severity_Error); if (race.mData.mWeight.mFemale<0) - messages.push_back (std::make_pair (id, "Female weight is negative")); + messages.add(id, "Female weight is negative", "", CSMDoc::Message::Severity_Error); /// \todo check data members that can't be edited in the table view } @@ -56,7 +58,7 @@ void CSMTools::RaceCheckStage::performFinal (CSMDoc::Messages& messages) CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Races); if (!mPlayable) - messages.push_back (std::make_pair (id, "No playable race")); + messages.add(id, "No playable race", "", CSMDoc::Message::Severity_SeriousError); } CSMTools::RaceCheckStage::RaceCheckStage (const CSMWorld::IdCollection& races) diff --git a/apps/opencs/model/tools/soundgencheck.cpp b/apps/opencs/model/tools/soundgencheck.cpp index 99a8c184c..7b6cf7a4b 100644 --- a/apps/opencs/model/tools/soundgencheck.cpp +++ b/apps/opencs/model/tools/soundgencheck.cpp @@ -40,20 +40,20 @@ void CSMTools::SoundGenCheckStage::perform(int stage, CSMDoc::Messages &messages CSMWorld::RefIdData::LocalIndex creatureIndex = mObjects.getDataSet().searchId(soundGen.mCreature); if (creatureIndex.first == -1) { - messages.push_back(std::make_pair(id, "Creature '" + soundGen.mCreature + "' doesn't exist")); + messages.add(id, "Creature '" + soundGen.mCreature + "' doesn't exist", "", CSMDoc::Message::Severity_Error); } else if (creatureIndex.second != CSMWorld::UniversalId::Type_Creature) { - messages.push_back(std::make_pair(id, "'" + soundGen.mCreature + "' is not a creature")); + messages.add(id, "'" + soundGen.mCreature + "' is not a creature", "", CSMDoc::Message::Severity_Error); } } if (soundGen.mSound.empty()) { - messages.push_back(std::make_pair(id, "Sound is missing")); + messages.add(id, "Sound is missing", "", CSMDoc::Message::Severity_Error); } else if (mSounds.searchId(soundGen.mSound) == -1) { - messages.push_back(std::make_pair(id, "Sound '" + soundGen.mSound + "' doesn't exist")); + messages.add(id, "Sound '" + soundGen.mSound + "' doesn't exist", "", CSMDoc::Message::Severity_Error); } } diff --git a/apps/opencs/model/tools/spellcheck.cpp b/apps/opencs/model/tools/spellcheck.cpp index 6c08aca37..dc9ce65c0 100644 --- a/apps/opencs/model/tools/spellcheck.cpp +++ b/apps/opencs/model/tools/spellcheck.cpp @@ -34,13 +34,13 @@ void CSMTools::SpellCheckStage::perform (int stage, CSMDoc::Messages& messages) CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Spell, spell.mId); - // test for empty name and description + // test for empty name if (spell.mName.empty()) - messages.push_back (std::make_pair (id, "Name is missing")); + messages.add(id, "Name is missing", "", CSMDoc::Message::Severity_Error); // test for invalid cost values if (spell.mData.mCost<0) - messages.push_back (std::make_pair (id, "Spell cost is negative")); + messages.add(id, "Spell cost is negative", "", CSMDoc::Message::Severity_Error); /// \todo check data members that can't be edited in the table view } diff --git a/apps/opencs/model/tools/startscriptcheck.cpp b/apps/opencs/model/tools/startscriptcheck.cpp index 5a9f63dc4..deb7d384f 100644 --- a/apps/opencs/model/tools/startscriptcheck.cpp +++ b/apps/opencs/model/tools/startscriptcheck.cpp @@ -25,7 +25,7 @@ void CSMTools::StartScriptCheckStage::perform(int stage, CSMDoc::Messages& messa CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_StartScript, scriptId); if (mScripts.searchId (Misc::StringUtils::lowerCase (scriptId))==-1) - messages.push_back (std::make_pair (id, "Start script " + scriptId + " does not exist")); + messages.add(id, "Start script " + scriptId + " does not exist", "", CSMDoc::Message::Severity_Error); } int CSMTools::StartScriptCheckStage::setup() From 1e5330d9da8577df523f7c51c9dda94bc036d27f Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Sat, 25 Aug 2018 05:16:49 +0300 Subject: [PATCH 108/196] Use Messages::add in skill record verifier --- apps/opencs/model/tools/skillcheck.cpp | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/apps/opencs/model/tools/skillcheck.cpp b/apps/opencs/model/tools/skillcheck.cpp index a2bf3ff03..ab7df51cb 100644 --- a/apps/opencs/model/tools/skillcheck.cpp +++ b/apps/opencs/model/tools/skillcheck.cpp @@ -1,7 +1,5 @@ #include "skillcheck.hpp" -#include - #include #include "../prefs/state.hpp" @@ -33,16 +31,14 @@ void CSMTools::SkillCheckStage::perform (int stage, CSMDoc::Messages& messages) CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Skill, skill.mId); + if (skill.mDescription.empty()) + messages.add(id, "Description is missing", "", CSMDoc::Message::Severity_Warning); + for (int i=0; i<4; ++i) + { if (skill.mData.mUseValue[i]<0) { - std::ostringstream stream; - - stream << "Usage experience value #" << i << " is negative"; - - messages.push_back (std::make_pair (id, stream.str())); + messages.add(id, "Usage experience value #" + std::to_string(i) + " is negative", "", CSMDoc::Message::Severity_Error); } - - if (skill.mDescription.empty()) - messages.push_back (std::make_pair (id, "Description is missing")); + } } From e1ae7a9b0e964154cc0a205ad1bc14364d0f7a27 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Sat, 25 Aug 2018 06:40:14 +0300 Subject: [PATCH 109/196] Avoid duplicate duplicate pathgrid point warnings --- apps/opencs/model/tools/pathgridcheck.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/apps/opencs/model/tools/pathgridcheck.cpp b/apps/opencs/model/tools/pathgridcheck.cpp index e63e9122f..88750ad7f 100644 --- a/apps/opencs/model/tools/pathgridcheck.cpp +++ b/apps/opencs/model/tools/pathgridcheck.cpp @@ -100,11 +100,8 @@ void CSMTools::PathgridCheckStage::perform (int stage, CSMDoc::Messages& message // check duplicate points // FIXME: how to do this efficiently? - for (unsigned int j = 0; j < pathgrid.mPoints.size(); ++j) + for (unsigned int j = 0; j != i; ++j) { - if (j == i) - continue; - if (pathgrid.mPoints[i].mX == pathgrid.mPoints[j].mX && pathgrid.mPoints[i].mY == pathgrid.mPoints[j].mY && pathgrid.mPoints[i].mZ == pathgrid.mPoints[j].mZ) From 85dc1e4ef2b43953fbade3294acb5a77a6242c28 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Sun, 26 Aug 2018 10:45:02 +0300 Subject: [PATCH 110/196] Revert unnecessary universalid changes in Journal record verifier --- apps/opencs/model/tools/journalcheck.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/opencs/model/tools/journalcheck.cpp b/apps/opencs/model/tools/journalcheck.cpp index bd77e95b6..dc15b26ee 100644 --- a/apps/opencs/model/tools/journalcheck.cpp +++ b/apps/opencs/model/tools/journalcheck.cpp @@ -33,7 +33,6 @@ void CSMTools::JournalCheckStage::perform(int stage, CSMDoc::Messages& messages) std::set questIndices; CSMWorld::InfoCollection::Range range = mJournalInfos.getTopicRange(journal.mId); - CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_Journal, journal.mId); for (CSMWorld::InfoCollection::RecordConstIterator it = range.first; it != range.second; ++it) { @@ -57,6 +56,7 @@ void CSMTools::JournalCheckStage::perform(int stage, CSMDoc::Messages& messages) if (journalInfo.mResponse.empty()) { + CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_JournalInfo, journalInfo.mId); messages.add(id, "Missing journal entry text", "", CSMDoc::Message::Severity_Warning); } @@ -65,6 +65,7 @@ void CSMTools::JournalCheckStage::perform(int stage, CSMDoc::Messages& messages) // Duplicate index if (result.second == false) { + CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_JournalInfo, journalInfo.mId); std::ostringstream stream; stream << "Duplicated quest index " << journalInfo.mData.mJournalIndex; messages.add(id, stream.str(), "", CSMDoc::Message::Severity_Error); @@ -73,10 +74,12 @@ void CSMTools::JournalCheckStage::perform(int stage, CSMDoc::Messages& messages) if (totalInfoCount == 0) { + CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_Journal, journal.mId); messages.add(id, "No related journal entry", "", CSMDoc::Message::Severity_Warning); } else if (statusNamedCount > 1) { + CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_Journal, journal.mId); messages.add(id, "Multiple entries with quest status 'Named'", "", CSMDoc::Message::Severity_Error); } } From d1b2fc11ef58594bacafe48b3191e9bf150f8983 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Sun, 26 Aug 2018 13:00:39 +0300 Subject: [PATCH 111/196] Use messages::add in object record verifiers Add NPC head and hair body part existence checks and expand creature record verifier, update playable class checks in class record verifier --- apps/opencs/model/tools/classcheck.cpp | 7 +- .../opencs/model/tools/referenceablecheck.cpp | 263 +++++++++--------- .../opencs/model/tools/referenceablecheck.hpp | 4 +- apps/opencs/model/tools/tools.cpp | 3 +- 4 files changed, 147 insertions(+), 130 deletions(-) diff --git a/apps/opencs/model/tools/classcheck.cpp b/apps/opencs/model/tools/classcheck.cpp index b409c4e06..9984c3287 100644 --- a/apps/opencs/model/tools/classcheck.cpp +++ b/apps/opencs/model/tools/classcheck.cpp @@ -36,7 +36,12 @@ void CSMTools::ClassCheckStage::perform (int stage, CSMDoc::Messages& messages) // A class should have a name if (class_.mName.empty()) - messages.add(id, "Name is missing", "", CSMDoc::Message::Severity_Warning); + { + if (class_.mData.mIsPlayable != 0) + messages.add(id, "Name of a playable class is missing", "", CSMDoc::Message::Severity_Error); + else + messages.add(id, "Name is missing", "", CSMDoc::Message::Severity_Warning); + } // A playable class should have a description if (class_.mData.mIsPlayable != 0 && class_.mDescription.empty()) diff --git a/apps/opencs/model/tools/referenceablecheck.cpp b/apps/opencs/model/tools/referenceablecheck.cpp index d3901ac88..c61d84d51 100644 --- a/apps/opencs/model/tools/referenceablecheck.cpp +++ b/apps/opencs/model/tools/referenceablecheck.cpp @@ -14,7 +14,8 @@ CSMTools::ReferenceableCheckStage::ReferenceableCheckStage( const CSMWorld::IdCollection& faction, const CSMWorld::IdCollection& scripts, const CSMWorld::Resources& models, - const CSMWorld::Resources& icons) + const CSMWorld::Resources& icons, + const CSMWorld::IdCollection& bodyparts) :mObjects(referenceable), mRaces(races), mClasses(classes), @@ -22,6 +23,7 @@ CSMTools::ReferenceableCheckStage::ReferenceableCheckStage( mScripts(scripts), mModels(models), mIcons(icons), + mBodyParts(bodyparts), mPlayerPresent(false) { mIgnoreBaseRecords = false; @@ -274,11 +276,10 @@ void CSMTools::ReferenceableCheckStage::activatorCheck( const ESM::Activator& activator = (dynamic_cast& >(baseRecord)).get(); CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_Activator, activator.mId); - //Checking for model, IIRC all activators should have a model if (activator.mModel.empty()) - messages.push_back (std::make_pair (id, "Model is missing")); + messages.add(id, "Model is missing", "", CSMDoc::Message::Severity_Error); else if (mModels.searchId(activator.mModel) == -1) - messages.push_back (std::make_pair (id, "Model '" + activator.mModel + "' does not exist")); + messages.add(id, "Model '" + activator.mModel + "' does not exist", "", CSMDoc::Message::Severity_Error); // Check that mentioned scripts exist scriptCheck(activator, messages, id.toString()); @@ -299,7 +300,6 @@ void CSMTools::ReferenceableCheckStage::potionCheck( CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_Potion, potion.mId); inventoryItemCheck(potion, messages, id.toString()); - //IIRC potion can have empty effects list just fine. // Check that mentioned scripts exist scriptCheck(potion, messages, id.toString()); @@ -344,13 +344,13 @@ void CSMTools::ReferenceableCheckStage::armorCheck( inventoryItemCheck(armor, messages, id.toString(), true); - //checking for armor class, armor should have poistive armor class, but 0 is considered legal + // Armor should have positive armor class, but 0 class is not an error if (armor.mData.mArmor < 0) - messages.push_back (std::make_pair (id, "Armor class is negative")); + messages.add(id, "Armor class is negative", "", CSMDoc::Message::Severity_Error); - //checking for health. Only positive numbers are allowed, or 0 is illegal + // Armor durability must be a positive number if (armor.mData.mHealth <= 0) - messages.push_back (std::make_pair (id, "Durability is non-positive")); + messages.add(id, "Durability is non-positive", "", CSMDoc::Message::Severity_Error); // Check that mentioned scripts exist scriptCheck(armor, messages, id.toString()); @@ -389,19 +389,19 @@ void CSMTools::ReferenceableCheckStage::containerCheck( const ESM::Container& container = (dynamic_cast& >(baseRecord)).get(); CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_Container, container.mId); + //checking for name + if (container.mName.empty()) + messages.add(id, "Name is missing", "", CSMDoc::Message::Severity_Error); + //Checking for model if (container.mModel.empty()) - messages.push_back (std::make_pair (id, "Model is missing")); + messages.add(id, "Model is missing", "", CSMDoc::Message::Severity_Error); else if (mModels.searchId(container.mModel) == -1) - messages.push_back (std::make_pair (id, "Model '" + container.mModel + "' does not exist")); + messages.add(id, "Model '" + container.mModel + "' does not exist", "", CSMDoc::Message::Severity_Error); //Checking for capacity (weight) if (container.mWeight < 0) //0 is allowed - messages.push_back (std::make_pair (id, "Capacity is negative")); - - //checking for name - if (container.mName.empty()) - messages.push_back (std::make_pair (id, "Name is missing")); + messages.add(id, "Capacity is negative", "", CSMDoc::Message::Severity_Error); //checking contained items inventoryListCheck(container.mInventory.mList, messages, id.toString()); @@ -423,69 +423,81 @@ void CSMTools::ReferenceableCheckStage::creatureCheck ( const ESM::Creature& creature = (dynamic_cast&>(baseRecord)).get(); CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_Creature, creature.mId); - if (creature.mModel.empty()) - messages.push_back (std::make_pair (id, "Model is missing")); - else if (mModels.searchId(creature.mModel) == -1) - messages.push_back (std::make_pair (id, "Model '" + creature.mModel + "' does not exist")); - if (creature.mName.empty()) - messages.push_back (std::make_pair (id, "Name is missing")); + messages.add(id, "Name is missing", "", CSMDoc::Message::Severity_Error); + + if (creature.mModel.empty()) + messages.add(id, "Model is missing", "", CSMDoc::Message::Severity_Error); + else if (mModels.searchId(creature.mModel) == -1) + messages.add(id, "Model '" + creature.mModel + "' does not exist", "", CSMDoc::Message::Severity_Error); //stats checks - if (creature.mData.mLevel < 1) - messages.push_back (std::make_pair (id, "Level is non-positive")); + if (creature.mData.mLevel <= 0) + messages.add(id, "Level is non-positive", "", CSMDoc::Message::Severity_Warning); if (creature.mData.mStrength < 0) - messages.push_back (std::make_pair (id, "Strength is negative")); - + messages.add(id, "Strength is negative", "", CSMDoc::Message::Severity_Warning); if (creature.mData.mIntelligence < 0) - messages.push_back (std::make_pair (id, "Intelligence is negative")); - + messages.add(id, "Intelligence is negative", "", CSMDoc::Message::Severity_Warning); if (creature.mData.mWillpower < 0) - messages.push_back (std::make_pair (id, "Willpower is negative")); - + messages.add(id, "Willpower is negative", "", CSMDoc::Message::Severity_Warning); if (creature.mData.mAgility < 0) - messages.push_back (std::make_pair (id, "Agility is negative")); - + messages.add(id, "Agility is negative", "", CSMDoc::Message::Severity_Warning); if (creature.mData.mSpeed < 0) - messages.push_back (std::make_pair (id, "Speed is negative")); - + messages.add(id, "Speed is negative", "", CSMDoc::Message::Severity_Warning); if (creature.mData.mEndurance < 0) - messages.push_back (std::make_pair (id, "Endurance is negative")); - + messages.add(id, "Endurance is negative", "", CSMDoc::Message::Severity_Warning); if (creature.mData.mPersonality < 0) - messages.push_back (std::make_pair (id, "Personality is negative")); - + messages.add(id, "Personality is negative", "", CSMDoc::Message::Severity_Warning); if (creature.mData.mLuck < 0) - messages.push_back (std::make_pair (id, "Luck is negative")); + messages.add(id, "Luck is negative", "", CSMDoc::Message::Severity_Warning); + + if (creature.mData.mCombat < 0) + messages.add(id, "Combat is negative", "", CSMDoc::Message::Severity_Warning); + if (creature.mData.mMagic < 0) + messages.add(id, "Magic is negative", "", CSMDoc::Message::Severity_Warning); + if (creature.mData.mStealth < 0) + messages.add(id, "Stealth is negative", "", CSMDoc::Message::Severity_Warning); if (creature.mData.mHealth < 0) - messages.push_back (std::make_pair (id, "Health is negative")); + messages.add(id, "Health is negative", "", CSMDoc::Message::Severity_Error); + if (creature.mData.mMana < 0) + messages.add(id, "Magicka is negative", "", CSMDoc::Message::Severity_Error); + if (creature.mData.mFatigue < 0) + messages.add(id, "Fatigue is negative", "", CSMDoc::Message::Severity_Error); if (creature.mData.mSoul < 0) - messages.push_back (std::make_pair (id, "Soul value is negative")); + messages.add(id, "Soul value is negative", "", CSMDoc::Message::Severity_Error); for (int i = 0; i < 6; ++i) { if (creature.mData.mAttack[i] < 0) - { - messages.push_back (std::make_pair (id, "One of attacks has negative damage")); - break; - } + messages.add(id, "Attack " + std::to_string(i/2 + 1) + " has negative" + (i % 2 == 0 ? " minimum " : " maximum ") + "damage", "", CSMDoc::Message::Severity_Error); + if (i % 2 == 0 && creature.mData.mAttack[i] > creature.mData.mAttack[i+1]) + messages.add(id, "Attack " + std::to_string(i/2 + 1) + " has minimum damage higher than maximum damage", "", CSMDoc::Message::Severity_Warning); } - //TODO, find meaning of other values if (creature.mData.mGold < 0) - messages.push_back (std::make_pair (id, "Gold count is negative")); + messages.add(id, "Gold count is negative", "", CSMDoc::Message::Severity_Error); if (creature.mScale == 0) - messages.push_back (std::make_pair (id, "Scale is equal to zero")); + messages.add(id, "Scale is equal to zero", "", CSMDoc::Message::Severity_Error); + + if (!creature.mOriginal.empty()) + { + CSMWorld::RefIdData::LocalIndex index = mObjects.searchId(creature.mOriginal); + if (index.first == -1) + messages.add(id, "Parent creature '" + creature.mOriginal + "' does not exist", "", CSMDoc::Message::Severity_Error); + else if (index.second != CSMWorld::UniversalId::Type_Creature) + messages.add(id, "'" + creature.mOriginal + "' is not a creature", "", CSMDoc::Message::Severity_Error); + } // Check inventory inventoryListCheck(creature.mInventory.mList, messages, id.toString()); // Check that mentioned scripts exist scriptCheck(creature, messages, id.toString()); + /// \todo Check spells, teleport table, AI data and AI packages for validity } void CSMTools::ReferenceableCheckStage::doorCheck( @@ -503,12 +515,12 @@ void CSMTools::ReferenceableCheckStage::doorCheck( //usual, name or model if (door.mName.empty()) - messages.push_back (std::make_pair (id, "Name is missing")); + messages.add(id, "Name is missing", "", CSMDoc::Message::Severity_Error); if (door.mModel.empty()) - messages.push_back (std::make_pair (id, "Model is missing")); + messages.add(id, "Model is missing", "", CSMDoc::Message::Severity_Error); else if (mModels.searchId(door.mModel) == -1) - messages.push_back (std::make_pair (id, "Model '" + door.mModel + "' does not exist")); + messages.add(id, "Model '" + door.mModel + "' does not exist", "", CSMDoc::Message::Severity_Error); // Check that mentioned scripts exist scriptCheck(door, messages, id.toString()); @@ -582,7 +594,7 @@ void CSMTools::ReferenceableCheckStage::lightCheck( CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_Light, light.mId); if (light.mData.mRadius < 0) - messages.push_back (std::make_pair (id, "Light radius is negative")); + messages.add(id, "Light radius is negative", "", CSMDoc::Message::Severity_Error); if (light.mData.mFlags & ESM::Light::Carry) inventoryItemCheck(light, messages, id.toString()); @@ -657,89 +669,87 @@ void CSMTools::ReferenceableCheckStage::npcCheck ( char disposition(npc.mNpdt.mDisposition); char reputation(npc.mNpdt.mReputation); char rank(npc.mNpdt.mRank); - //Don't know what unknown is for int gold(npc.mNpdt.mGold); if (npc.mNpdtType == ESM::NPC::NPC_WITH_AUTOCALCULATED_STATS) //12 = autocalculated { if ((npc.mFlags & ESM::NPC::Autocalc) == 0) //0x0010 = autocalculated flag { - messages.push_back (std::make_pair (id, npc.mId + " mNpdtType or flags mismatch!")); //should not happen? + messages.add(id, "NPC with autocalculated stats doesn't have autocalc flag turned on", "", CSMDoc::Message::Severity_Error); //should not happen? return; } - - level = npc.mNpdt.mLevel; - disposition = npc.mNpdt.mDisposition; - reputation = npc.mNpdt.mReputation; - rank = npc.mNpdt.mRank; - gold = npc.mNpdt.mGold; } else { - if (npc.mNpdt.mAgility == 0) - messages.push_back (std::make_pair (id, "Agility is equal to zero")); - - if (npc.mNpdt.mEndurance == 0) - messages.push_back (std::make_pair (id, "Endurance is equal to zero")); - - if (npc.mNpdt.mIntelligence == 0) - messages.push_back (std::make_pair (id, "Intelligence is equal to zero")); - - if (npc.mNpdt.mLuck == 0) - messages.push_back (std::make_pair (id, "Luck is equal to zero")); - - if (npc.mNpdt.mPersonality == 0) - messages.push_back (std::make_pair (id, "Personality is equal to zero")); - if (npc.mNpdt.mStrength == 0) - messages.push_back (std::make_pair (id, "Strength is equal to zero")); - - if (npc.mNpdt.mSpeed == 0) - messages.push_back (std::make_pair (id, "Speed is equal to zero")); - + messages.add(id, "Strength is equal to zero", "", CSMDoc::Message::Severity_Warning); + if (npc.mNpdt.mIntelligence == 0) + messages.add(id, "Intelligence is equal to zero", "", CSMDoc::Message::Severity_Warning); if (npc.mNpdt.mWillpower == 0) - messages.push_back (std::make_pair (id, "Willpower is equal to zero")); + messages.add(id, "Willpower is equal to zero", "", CSMDoc::Message::Severity_Warning); + if (npc.mNpdt.mAgility == 0) + messages.add(id, "Agility is equal to zero", "", CSMDoc::Message::Severity_Warning); + if (npc.mNpdt.mSpeed == 0) + messages.add(id, "Speed is equal to zero", "", CSMDoc::Message::Severity_Warning); + if (npc.mNpdt.mEndurance == 0) + messages.add(id, "Endurance is equal to zero", "", CSMDoc::Message::Severity_Warning); + if (npc.mNpdt.mPersonality == 0) + messages.add(id, "Personality is equal to zero", "", CSMDoc::Message::Severity_Warning); + if (npc.mNpdt.mLuck == 0) + messages.add(id, "Luck is equal to zero", "", CSMDoc::Message::Severity_Warning); } if (level <= 0) - messages.push_back (std::make_pair (id, "Level is non-positive")); + messages.add(id, "Level is non-positive", "", CSMDoc::Message::Severity_Warning); if (gold < 0) - messages.push_back (std::make_pair (id, "Gold count is negative")); + messages.add(id, "Gold count is negative", "", CSMDoc::Message::Severity_Error); if (npc.mName.empty()) - messages.push_back (std::make_pair (id, "Name is missing")); + messages.add(id, "Name is missing", "", CSMDoc::Message::Severity_Error); if (npc.mClass.empty()) - messages.push_back (std::make_pair (id, "Class is missing")); + messages.add(id, "Class is missing", "", CSMDoc::Message::Severity_Error); else if (mClasses.searchId (npc.mClass) == -1) - messages.push_back (std::make_pair (id, "Class '" + npc.mClass + "' does not exist")); + messages.add(id, "Class '" + npc.mClass + "' does not exist", "", CSMDoc::Message::Severity_Error); if (npc.mRace.empty()) - messages.push_back (std::make_pair (id, "Race is missing")); + messages.add(id, "Race is missing", "", CSMDoc::Message::Severity_Error); else if (mRaces.searchId (npc.mRace) == -1) - messages.push_back (std::make_pair (id, "Race '" + npc.mRace + "' does not exist")); + messages.add(id, "Race '" + npc.mRace + "' does not exist", "", CSMDoc::Message::Severity_Error); if (disposition < 0) - messages.push_back (std::make_pair (id, "Disposition is negative")); + messages.add(id, "Disposition is negative", "", CSMDoc::Message::Severity_Warning); if (reputation < 0) - messages.push_back (std::make_pair (id, "Reputation is negative")); + messages.add(id, "Reputation is negative", "", CSMDoc::Message::Severity_Warning); if (!npc.mFaction.empty()) { if (rank < 0) - messages.push_back (std::make_pair (id, "Faction rank is negative")); + messages.add(id, "Faction rank is negative", "", CSMDoc::Message::Severity_Warning); if (mFactions.searchId(npc.mFaction) == -1) - messages.push_back (std::make_pair (id, "Faction '" + npc.mFaction + "' does not exist")); + messages.add(id, "Faction '" + npc.mFaction + "' does not exist", "", CSMDoc::Message::Severity_Error); } if (npc.mHead.empty()) - messages.push_back (std::make_pair (id, "Head is missing")); // ADD CHECK HERE + messages.push_back (std::make_pair (id, "Head is missing")); + else + { + if (mBodyParts.searchId(npc.mHead) == -1) + messages.add(id, "Head body part '" + npc.mHead + "' does not exist", "", CSMDoc::Message::Severity_Error); + /// \todo Check gender, race and other body parts stuff validity for the specific NPC + } if (npc.mHair.empty()) - messages.push_back (std::make_pair (id, "Hair is missing")); // ADD CHECK HERE + messages.push_back (std::make_pair (id, "Hair is missing")); + else + { + if (mBodyParts.searchId(npc.mHair) == -1) + messages.add(id, "Hair body part '" + npc.mHair + "' does not exist", "", CSMDoc::Message::Severity_Error); + /// \todo Check gender, race and other body part stuff validity for the specific NPC + } // Check inventory inventoryListCheck(npc.mInventory.mList, messages, id.toString()); @@ -799,14 +809,14 @@ void CSMTools::ReferenceableCheckStage::weaponCheck( weapon.mData.mType == ESM::Weapon::Bolt)) { if (weapon.mData.mSlash[0] > weapon.mData.mSlash[1]) - messages.push_back (std::make_pair (id, "Minimum slash damage higher than maximum")); + messages.add(id, "Minimum slash damage higher than maximum", "", CSMDoc::Message::Severity_Warning); if (weapon.mData.mThrust[0] > weapon.mData.mThrust[1]) - messages.push_back (std::make_pair (id, "Minimum thrust damage is higher than maximum")); + messages.add(id, "Minimum thrust damage higher than maximum", "", CSMDoc::Message::Severity_Warning); } if (weapon.mData.mChop[0] > weapon.mData.mChop[1]) - messages.push_back (std::make_pair (id, "Minimum chop damage is higher than maximum")); + messages.add(id, "Minimum chop damage higher than maximum", "", CSMDoc::Message::Severity_Warning); if (!(weapon.mData.mType == ESM::Weapon::Arrow || weapon.mData.mType == ESM::Weapon::Bolt || @@ -814,10 +824,10 @@ void CSMTools::ReferenceableCheckStage::weaponCheck( { //checking of health if (weapon.mData.mHealth == 0) - messages.push_back (std::make_pair (id, "Durability is equal to zero")); + messages.add(id, "Durability is equal to zero", "", CSMDoc::Message::Severity_Warning); if (weapon.mData.mReach < 0) - messages.push_back (std::make_pair (id, "Reach is negative")); + messages.add(id, "Reach is negative", "", CSMDoc::Message::Severity_Error); } } @@ -880,9 +890,9 @@ void CSMTools::ReferenceableCheckStage::staticCheck ( CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Static, staticElement.mId); if (staticElement.mModel.empty()) - messages.push_back (std::make_pair (id, "Model is missing")); + messages.add(id, "Model is missing", "", CSMDoc::Message::Severity_Error); else if (mModels.searchId(staticElement.mModel) == -1) - messages.push_back (std::make_pair (id, "Model '" + staticElement.mModel + "' does not exist")); + messages.add(id, "Model '" + staticElement.mModel + "' does not exist", "", CSMDoc::Message::Severity_Error); } //final check @@ -890,8 +900,7 @@ void CSMTools::ReferenceableCheckStage::staticCheck ( void CSMTools::ReferenceableCheckStage::finalCheck (CSMDoc::Messages& messages) { if (!mPlayerPresent) - messages.push_back (std::make_pair (CSMWorld::UniversalId::Type_Referenceables, - "Player record is missing")); + messages.add(CSMWorld::UniversalId::Type_Referenceables, "Player record is missing", "", CSMDoc::Message::Severity_SeriousError); } void CSMTools::ReferenceableCheckStage::inventoryListCheck( @@ -905,7 +914,7 @@ void CSMTools::ReferenceableCheckStage::inventoryListCheck( CSMWorld::RefIdData::LocalIndex localIndex = mObjects.searchId(itemName); if (localIndex.first == -1) - messages.push_back (std::make_pair (id, "Item '" + itemName + "' does not exist")); + messages.add(id, "Item '" + itemName + "' does not exist", "", CSMDoc::Message::Severity_Error); else { // Needs to accommodate containers, creatures, and NPCs @@ -926,7 +935,7 @@ void CSMTools::ReferenceableCheckStage::inventoryListCheck( case CSMWorld::UniversalId::Type_ItemLevelledList: break; default: - messages.push_back (std::make_pair(id, "'" + itemName + "' is not an item")); + messages.add(id, "'" + itemName + "' is not an item", "", CSMDoc::Message::Severity_Error); } } } @@ -938,64 +947,64 @@ template void CSMTools::ReferenceableCheckStage::inventoryItemChe const Item& someItem, CSMDoc::Messages& messages, const std::string& someID, bool enchantable) { if (someItem.mName.empty()) - messages.push_back (std::make_pair (someID, "Name is missing")); + messages.add(someID, "Name is missing", "", CSMDoc::Message::Severity_Error); //Checking for weight if (someItem.mData.mWeight < 0) - messages.push_back (std::make_pair (someID, "Weight is negative")); + messages.add(someID, "Weight is negative", "", CSMDoc::Message::Severity_Error); //Checking for value if (someItem.mData.mValue < 0) - messages.push_back (std::make_pair (someID, "Value is negative")); + messages.add(someID, "Value is negative", "", CSMDoc::Message::Severity_Error); //checking for model if (someItem.mModel.empty()) - messages.push_back (std::make_pair (someID, "Model is missing")); + messages.add(someID, "Model is missing", "", CSMDoc::Message::Severity_Error); else if (mModels.searchId(someItem.mModel) == -1) - messages.push_back(std::make_pair(someID, "Model '" + someItem.mModel + "' does not exist")); + messages.add(someID, "Model '" + someItem.mModel + "' does not exist", "", CSMDoc::Message::Severity_Error); //checking for icon if (someItem.mIcon.empty()) - messages.push_back (std::make_pair (someID, "Icon is missing")); + messages.add(someID, "Icon is missing", "", CSMDoc::Message::Severity_Error); else if (mIcons.searchId(someItem.mIcon) == -1) { std::string ddsIcon = someItem.mIcon; if (!(Misc::ResourceHelpers::changeExtensionToDds(ddsIcon) && mIcons.searchId(ddsIcon) != -1)) - messages.push_back(std::make_pair(someID, "Icon '" + someItem.mIcon + "' does not exist")); + messages.add(someID, "Icon '" + someItem.mIcon + "' does not exist", "", CSMDoc::Message::Severity_Error); } if (enchantable && someItem.mData.mEnchant < 0) - messages.push_back (std::make_pair (someID, "Enchantment points number is negative")); + messages.add(someID, "Enchantment points number is negative", "", CSMDoc::Message::Severity_Error); } template void CSMTools::ReferenceableCheckStage::inventoryItemCheck ( const Item& someItem, CSMDoc::Messages& messages, const std::string& someID) { if (someItem.mName.empty()) - messages.push_back (std::make_pair (someID, "Name is missing")); + messages.add(someID, "Name is missing", "", CSMDoc::Message::Severity_Error); //Checking for weight if (someItem.mData.mWeight < 0) - messages.push_back (std::make_pair (someID, "Weight is negative")); + messages.add(someID, "Weight is negative", "", CSMDoc::Message::Severity_Error); //Checking for value if (someItem.mData.mValue < 0) - messages.push_back (std::make_pair (someID, "Value is negative")); + messages.add(someID, "Value is negative", "", CSMDoc::Message::Severity_Error); //checking for model if (someItem.mModel.empty()) - messages.push_back (std::make_pair (someID, "Model is missing")); + messages.add(someID, "Model is missing", "", CSMDoc::Message::Severity_Error); else if (mModels.searchId(someItem.mModel) == -1) - messages.push_back (std::make_pair (someID, "Model '" + someItem.mModel + "' does not exist")); + messages.add(someID, "Model '" + someItem.mModel + "' does not exist", "", CSMDoc::Message::Severity_Error); //checking for icon if (someItem.mIcon.empty()) - messages.push_back (std::make_pair (someID, "Icon is missing")); + messages.add(someID, "Icon is missing", "", CSMDoc::Message::Severity_Error); else if (mIcons.searchId(someItem.mIcon) == -1) { std::string ddsIcon = someItem.mIcon; if (!(Misc::ResourceHelpers::changeExtensionToDds(ddsIcon) && mIcons.searchId(ddsIcon) != -1)) - messages.push_back(std::make_pair(someID, "Icon '" + someItem.mIcon + "' does not exist")); + messages.add(someID, "Icon '" + someItem.mIcon + "' does not exist", "", CSMDoc::Message::Severity_Error); } } @@ -1003,17 +1012,17 @@ template void CSMTools::ReferenceableCheckStage::toolCheck ( const Tool& someTool, CSMDoc::Messages& messages, const std::string& someID, bool canBeBroken) { if (someTool.mData.mQuality <= 0) - messages.push_back (std::make_pair (someID, "Quality is non-positive")); + messages.add(someID, "Quality is non-positive", "", CSMDoc::Message::Severity_Error); if (canBeBroken && someTool.mData.mUses<=0) - messages.push_back (std::make_pair (someID, "Number of uses is non-positive")); + messages.add(someID, "Number of uses is non-positive", "", CSMDoc::Message::Severity_Error); } template void CSMTools::ReferenceableCheckStage::toolCheck ( const Tool& someTool, CSMDoc::Messages& messages, const std::string& someID) -{ +{ if (someTool.mData.mQuality <= 0) - messages.push_back (std::make_pair (someID, "Quality is non-positive")); + messages.add(someID, "Quality is non-positive", "", CSMDoc::Message::Severity_Error); } template void CSMTools::ReferenceableCheckStage::listCheck ( @@ -1022,10 +1031,10 @@ template void CSMTools::ReferenceableCheckStage::listCheck ( for (unsigned i = 0; i < someList.mList.size(); ++i) { if (mObjects.searchId(someList.mList[i].mId).first == -1) - messages.push_back (std::make_pair (someID, "Object '" + someList.mList[i].mId + "' does not exist")); + messages.add(someID, "Object '" + someList.mList[i].mId + "' does not exist", "", CSMDoc::Message::Severity_Error); if (someList.mList[i].mLevel < 1) - messages.push_back (std::make_pair (someID, "Level of item '" + someList.mList[i].mId + "' is non-positive")); + messages.add(someID, "Level of item '" + someList.mList[i].mId + "' is non-positive", "", CSMDoc::Message::Severity_Error); } } @@ -1035,6 +1044,6 @@ template void CSMTools::ReferenceableCheckStage::scriptCheck ( if (!someTool.mScript.empty()) { if (mScripts.searchId(someTool.mScript) == -1) - messages.push_back (std::make_pair (someID, "Script '"+someTool.mScript+"' does not exist")); + messages.add(someID, "Script '" + someTool.mScript + "' does not exist", "", CSMDoc::Message::Severity_Error); } } diff --git a/apps/opencs/model/tools/referenceablecheck.hpp b/apps/opencs/model/tools/referenceablecheck.hpp index 5da737875..d8682c907 100644 --- a/apps/opencs/model/tools/referenceablecheck.hpp +++ b/apps/opencs/model/tools/referenceablecheck.hpp @@ -19,7 +19,8 @@ namespace CSMTools const CSMWorld::IdCollection& factions, const CSMWorld::IdCollection& scripts, const CSMWorld::Resources& models, - const CSMWorld::Resources& icons); + const CSMWorld::Resources& icons, + const CSMWorld::IdCollection& bodyparts); virtual void perform(int stage, CSMDoc::Messages& messages); virtual int setup(); @@ -86,6 +87,7 @@ namespace CSMTools const CSMWorld::IdCollection& mScripts; const CSMWorld::Resources& mModels; const CSMWorld::Resources& mIcons; + const CSMWorld::IdCollection& mBodyParts; bool mPlayerPresent; bool mIgnoreBaseRecords; }; diff --git a/apps/opencs/model/tools/tools.cpp b/apps/opencs/model/tools/tools.cpp index 87b5041e0..b9a0abb75 100644 --- a/apps/opencs/model/tools/tools.cpp +++ b/apps/opencs/model/tools/tools.cpp @@ -83,7 +83,8 @@ CSMDoc::OperationHolder *CSMTools::Tools::getVerifier() mVerifierOperation->appendStage (new SpellCheckStage (mData.getSpells())); mVerifierOperation->appendStage (new ReferenceableCheckStage (mData.getReferenceables().getDataSet(), mData.getRaces(), mData.getClasses(), mData.getFactions(), mData.getScripts(), - mData.getResources (CSMWorld::UniversalId::Type_Meshes), mData.getResources (CSMWorld::UniversalId::Type_Icons))); + mData.getResources (CSMWorld::UniversalId::Type_Meshes), mData.getResources (CSMWorld::UniversalId::Type_Icons), + mData.getBodyParts())); mVerifierOperation->appendStage (new ReferenceCheckStage(mData.getReferences(), mData.getReferenceables(), mData.getCells(), mData.getFactions())); From 34ffaa2fe2cf6f85094289769cc788f55a9c4c03 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Sun, 26 Aug 2018 21:18:17 +0300 Subject: [PATCH 112/196] Make finishing touches to object record verifiers --- .../opencs/model/tools/referenceablecheck.cpp | 95 ++++++++++--------- .../opencs/model/tools/referenceablecheck.hpp | 2 +- 2 files changed, 49 insertions(+), 48 deletions(-) diff --git a/apps/opencs/model/tools/referenceablecheck.cpp b/apps/opencs/model/tools/referenceablecheck.cpp index c61d84d51..60d4a6b58 100644 --- a/apps/opencs/model/tools/referenceablecheck.cpp +++ b/apps/opencs/model/tools/referenceablecheck.cpp @@ -16,7 +16,7 @@ CSMTools::ReferenceableCheckStage::ReferenceableCheckStage( const CSMWorld::Resources& models, const CSMWorld::Resources& icons, const CSMWorld::IdCollection& bodyparts) - :mObjects(referenceable), + :mReferencables(referenceable), mRaces(races), mClasses(classes), mFactions(faction), @@ -32,201 +32,201 @@ CSMTools::ReferenceableCheckStage::ReferenceableCheckStage( void CSMTools::ReferenceableCheckStage::perform (int stage, CSMDoc::Messages& messages) { //Checks for books, than, when stage is above mBooksSize goes to other checks, with (stage - PrevSum) as stage. - const int bookSize(mObjects.getBooks().getSize()); + const int bookSize(mReferencables.getBooks().getSize()); if (stage < bookSize) { - bookCheck(stage, mObjects.getBooks(), messages); + bookCheck(stage, mReferencables.getBooks(), messages); return; } stage -= bookSize; - const int activatorSize(mObjects.getActivators().getSize()); + const int activatorSize(mReferencables.getActivators().getSize()); if (stage < activatorSize) { - activatorCheck(stage, mObjects.getActivators(), messages); + activatorCheck(stage, mReferencables.getActivators(), messages); return; } stage -= activatorSize; - const int potionSize(mObjects.getPotions().getSize()); + const int potionSize(mReferencables.getPotions().getSize()); if (stage < potionSize) { - potionCheck(stage, mObjects.getPotions(), messages); + potionCheck(stage, mReferencables.getPotions(), messages); return; } stage -= potionSize; - const int apparatusSize(mObjects.getApparati().getSize()); + const int apparatusSize(mReferencables.getApparati().getSize()); if (stage < apparatusSize) { - apparatusCheck(stage, mObjects.getApparati(), messages); + apparatusCheck(stage, mReferencables.getApparati(), messages); return; } stage -= apparatusSize; - const int armorSize(mObjects.getArmors().getSize()); + const int armorSize(mReferencables.getArmors().getSize()); if (stage < armorSize) { - armorCheck(stage, mObjects.getArmors(), messages); + armorCheck(stage, mReferencables.getArmors(), messages); return; } stage -= armorSize; - const int clothingSize(mObjects.getClothing().getSize()); + const int clothingSize(mReferencables.getClothing().getSize()); if (stage < clothingSize) { - clothingCheck(stage, mObjects.getClothing(), messages); + clothingCheck(stage, mReferencables.getClothing(), messages); return; } stage -= clothingSize; - const int containerSize(mObjects.getContainers().getSize()); + const int containerSize(mReferencables.getContainers().getSize()); if (stage < containerSize) { - containerCheck(stage, mObjects.getContainers(), messages); + containerCheck(stage, mReferencables.getContainers(), messages); return; } stage -= containerSize; - const int doorSize(mObjects.getDoors().getSize()); + const int doorSize(mReferencables.getDoors().getSize()); if (stage < doorSize) { - doorCheck(stage, mObjects.getDoors(), messages); + doorCheck(stage, mReferencables.getDoors(), messages); return; } stage -= doorSize; - const int ingredientSize(mObjects.getIngredients().getSize()); + const int ingredientSize(mReferencables.getIngredients().getSize()); if (stage < ingredientSize) { - ingredientCheck(stage, mObjects.getIngredients(), messages); + ingredientCheck(stage, mReferencables.getIngredients(), messages); return; } stage -= ingredientSize; - const int creatureLevListSize(mObjects.getCreatureLevelledLists().getSize()); + const int creatureLevListSize(mReferencables.getCreatureLevelledLists().getSize()); if (stage < creatureLevListSize) { - creaturesLevListCheck(stage, mObjects.getCreatureLevelledLists(), messages); + creaturesLevListCheck(stage, mReferencables.getCreatureLevelledLists(), messages); return; } stage -= creatureLevListSize; - const int itemLevelledListSize(mObjects.getItemLevelledList().getSize()); + const int itemLevelledListSize(mReferencables.getItemLevelledList().getSize()); if (stage < itemLevelledListSize) { - itemLevelledListCheck(stage, mObjects.getItemLevelledList(), messages); + itemLevelledListCheck(stage, mReferencables.getItemLevelledList(), messages); return; } stage -= itemLevelledListSize; - const int lightSize(mObjects.getLights().getSize()); + const int lightSize(mReferencables.getLights().getSize()); if (stage < lightSize) { - lightCheck(stage, mObjects.getLights(), messages); + lightCheck(stage, mReferencables.getLights(), messages); return; } stage -= lightSize; - const int lockpickSize(mObjects.getLocpicks().getSize()); + const int lockpickSize(mReferencables.getLocpicks().getSize()); if (stage < lockpickSize) { - lockpickCheck(stage, mObjects.getLocpicks(), messages); + lockpickCheck(stage, mReferencables.getLocpicks(), messages); return; } stage -= lockpickSize; - const int miscSize(mObjects.getMiscellaneous().getSize()); + const int miscSize(mReferencables.getMiscellaneous().getSize()); if (stage < miscSize) { - miscCheck(stage, mObjects.getMiscellaneous(), messages); + miscCheck(stage, mReferencables.getMiscellaneous(), messages); return; } stage -= miscSize; - const int npcSize(mObjects.getNPCs().getSize()); + const int npcSize(mReferencables.getNPCs().getSize()); if (stage < npcSize) { - npcCheck(stage, mObjects.getNPCs(), messages); + npcCheck(stage, mReferencables.getNPCs(), messages); return; } stage -= npcSize; - const int weaponSize(mObjects.getWeapons().getSize()); + const int weaponSize(mReferencables.getWeapons().getSize()); if (stage < weaponSize) { - weaponCheck(stage, mObjects.getWeapons(), messages); + weaponCheck(stage, mReferencables.getWeapons(), messages); return; } stage -= weaponSize; - const int probeSize(mObjects.getProbes().getSize()); + const int probeSize(mReferencables.getProbes().getSize()); if (stage < probeSize) { - probeCheck(stage, mObjects.getProbes(), messages); + probeCheck(stage, mReferencables.getProbes(), messages); return; } stage -= probeSize; - const int repairSize(mObjects.getRepairs().getSize()); + const int repairSize(mReferencables.getRepairs().getSize()); if (stage < repairSize) { - repairCheck(stage, mObjects.getRepairs(), messages); + repairCheck(stage, mReferencables.getRepairs(), messages); return; } stage -= repairSize; - const int staticSize(mObjects.getStatics().getSize()); + const int staticSize(mReferencables.getStatics().getSize()); if (stage < staticSize) { - staticCheck(stage, mObjects.getStatics(), messages); + staticCheck(stage, mReferencables.getStatics(), messages); return; } stage -= staticSize; - const int creatureSize(mObjects.getCreatures().getSize()); + const int creatureSize(mReferencables.getCreatures().getSize()); if (stage < creatureSize) { - creatureCheck(stage, mObjects.getCreatures(), messages); + creatureCheck(stage, mReferencables.getCreatures(), messages); return; } // if we come that far, we are about to perform our last, final check. @@ -239,7 +239,7 @@ int CSMTools::ReferenceableCheckStage::setup() mPlayerPresent = false; mIgnoreBaseRecords = CSMPrefs::get()["Reports"]["ignore-base-records"].isTrue(); - return mObjects.getSize() + 1; + return mReferencables.getSize() + 1; } void CSMTools::ReferenceableCheckStage::bookCheck( @@ -300,6 +300,7 @@ void CSMTools::ReferenceableCheckStage::potionCheck( CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_Potion, potion.mId); inventoryItemCheck(potion, messages, id.toString()); + /// \todo Check magic effects for validity // Check that mentioned scripts exist scriptCheck(potion, messages, id.toString()); @@ -485,7 +486,7 @@ void CSMTools::ReferenceableCheckStage::creatureCheck ( if (!creature.mOriginal.empty()) { - CSMWorld::RefIdData::LocalIndex index = mObjects.searchId(creature.mOriginal); + CSMWorld::RefIdData::LocalIndex index = mReferencables.searchId(creature.mOriginal); if (index.first == -1) messages.add(id, "Parent creature '" + creature.mOriginal + "' does not exist", "", CSMDoc::Message::Severity_Error); else if (index.second != CSMWorld::UniversalId::Type_Creature) @@ -892,7 +893,7 @@ void CSMTools::ReferenceableCheckStage::staticCheck ( if (staticElement.mModel.empty()) messages.add(id, "Model is missing", "", CSMDoc::Message::Severity_Error); else if (mModels.searchId(staticElement.mModel) == -1) - messages.add(id, "Model '" + staticElement.mModel + "' does not exist", "", CSMDoc::Message::Severity_Error); + messages.add(id, "Model '" + staticElement.mModel + "' does not exist", "", CSMDoc::Message::Severity_Error); } //final check @@ -911,7 +912,7 @@ void CSMTools::ReferenceableCheckStage::inventoryListCheck( for (size_t i = 0; i < itemList.size(); ++i) { std::string itemName = itemList[i].mItem.toString(); - CSMWorld::RefIdData::LocalIndex localIndex = mObjects.searchId(itemName); + CSMWorld::RefIdData::LocalIndex localIndex = mReferencables.searchId(itemName); if (localIndex.first == -1) messages.add(id, "Item '" + itemName + "' does not exist", "", CSMDoc::Message::Severity_Error); @@ -1020,7 +1021,7 @@ template void CSMTools::ReferenceableCheckStage::toolCheck ( template void CSMTools::ReferenceableCheckStage::toolCheck ( const Tool& someTool, CSMDoc::Messages& messages, const std::string& someID) -{ +{ if (someTool.mData.mQuality <= 0) messages.add(someID, "Quality is non-positive", "", CSMDoc::Message::Severity_Error); } @@ -1030,7 +1031,7 @@ template void CSMTools::ReferenceableCheckStage::listCheck ( { for (unsigned i = 0; i < someList.mList.size(); ++i) { - if (mObjects.searchId(someList.mList[i].mId).first == -1) + if (mReferencables.searchId(someList.mList[i].mId).first == -1) messages.add(someID, "Object '" + someList.mList[i].mId + "' does not exist", "", CSMDoc::Message::Severity_Error); if (someList.mList[i].mLevel < 1) diff --git a/apps/opencs/model/tools/referenceablecheck.hpp b/apps/opencs/model/tools/referenceablecheck.hpp index d8682c907..e55e5fad9 100644 --- a/apps/opencs/model/tools/referenceablecheck.hpp +++ b/apps/opencs/model/tools/referenceablecheck.hpp @@ -80,7 +80,7 @@ namespace CSMTools CSMDoc::Messages& messages, const std::string& someID); - const CSMWorld::RefIdData& mObjects; + const CSMWorld::RefIdData& mReferencables; const CSMWorld::IdCollection& mRaces; const CSMWorld::IdCollection& mClasses; const CSMWorld::IdCollection& mFactions; From 0bdb7ea92f77c695f90e10b0eda0d581561515cb Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Sun, 26 Aug 2018 21:40:07 +0300 Subject: [PATCH 113/196] Cleanup --- apps/opencs/model/tools/birthsigncheck.cpp | 26 ++----- apps/opencs/model/tools/birthsigncheck.hpp | 3 - apps/opencs/model/tools/classcheck.cpp | 4 -- apps/opencs/model/tools/magiceffectcheck.cpp | 70 ++++++------------- .../opencs/model/tools/referenceablecheck.cpp | 2 + 5 files changed, 28 insertions(+), 77 deletions(-) diff --git a/apps/opencs/model/tools/birthsigncheck.cpp b/apps/opencs/model/tools/birthsigncheck.cpp index c582da8e4..a0ae4b11f 100644 --- a/apps/opencs/model/tools/birthsigncheck.cpp +++ b/apps/opencs/model/tools/birthsigncheck.cpp @@ -7,17 +7,6 @@ #include "../world/universalid.hpp" - -std::string CSMTools::BirthsignCheckStage::checkTexture(const std::string &texture) const -{ - if (mTextures.searchId(texture) != -1) return std::string(); - - std::string ddsTexture = texture; - if (Misc::ResourceHelpers::changeExtensionToDds(ddsTexture) && mTextures.searchId(ddsTexture) != -1) return std::string(); - - return "Image '" + texture + "' does not exist"; -} - CSMTools::BirthsignCheckStage::BirthsignCheckStage (const CSMWorld::IdCollection& birthsigns, const CSMWorld::Resources &textures) : mBirthsigns(birthsigns), @@ -46,24 +35,21 @@ void CSMTools::BirthsignCheckStage::perform (int stage, CSMDoc::Messages& messag CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Birthsign, birthsign.mId); if (birthsign.mName.empty()) - { messages.add(id, "Name is missing", "", CSMDoc::Message::Severity_Error); - } if (birthsign.mDescription.empty()) - { messages.add(id, "Description is missing", "", CSMDoc::Message::Severity_Warning); - } if (birthsign.mTexture.empty()) - { messages.add(id, "Image is missing", "", CSMDoc::Message::Severity_Error); - } else { - const std::string error = checkTexture(birthsign.mTexture); - if (!error.empty()) - messages.add(id, error, "", CSMDoc::Message::Severity_Error); + if (mTextures.searchId(birthsign.mTexture) != -1) + return; + + std::string ddsTexture = birthsign.mTexture; + if (!(Misc::ResourceHelpers::changeExtensionToDds(ddsTexture) && mTextures.searchId(ddsTexture) != -1)) + messages.add(id, "Image '" + birthsign.mTexture + "' does not exist", "", CSMDoc::Message::Severity_Error); } /// \todo check data members that can't be edited in the table view diff --git a/apps/opencs/model/tools/birthsigncheck.hpp b/apps/opencs/model/tools/birthsigncheck.hpp index d032d3cef..9001c524c 100644 --- a/apps/opencs/model/tools/birthsigncheck.hpp +++ b/apps/opencs/model/tools/birthsigncheck.hpp @@ -17,9 +17,6 @@ namespace CSMTools const CSMWorld::Resources &mTextures; bool mIgnoreBaseRecords; - private: - std::string checkTexture(const std::string &texture) const; - public: BirthsignCheckStage (const CSMWorld::IdCollection &birthsigns, diff --git a/apps/opencs/model/tools/classcheck.cpp b/apps/opencs/model/tools/classcheck.cpp index 9984c3287..25cca8fcd 100644 --- a/apps/opencs/model/tools/classcheck.cpp +++ b/apps/opencs/model/tools/classcheck.cpp @@ -49,12 +49,10 @@ void CSMTools::ClassCheckStage::perform (int stage, CSMDoc::Messages& messages) // test for invalid attributes for (int i=0; i<2; ++i) - { if (class_.mData.mAttribute[i]==-1) { messages.add(id, "Attribute #" + std::to_string(i) + " is not set", "", CSMDoc::Message::Severity_Error); } - } if (class_.mData.mAttribute[0]==class_.mData.mAttribute[1] && class_.mData.mAttribute[0]!=-1) { @@ -69,10 +67,8 @@ void CSMTools::ClassCheckStage::perform (int stage, CSMDoc::Messages& messages) ++skills[class_.mData.mSkills[i][i2]]; for (auto &skill : skills) - { if (skill.second>1) { messages.add(id, "Skill " + ESM::Skill::indexToId (skill.first) + " is listed more than once", "", CSMDoc::Message::Severity_Warning); } - } } diff --git a/apps/opencs/model/tools/magiceffectcheck.cpp b/apps/opencs/model/tools/magiceffectcheck.cpp index 943d89cdc..b62e791a4 100644 --- a/apps/opencs/model/tools/magiceffectcheck.cpp +++ b/apps/opencs/model/tools/magiceffectcheck.cpp @@ -4,17 +4,6 @@ #include "../prefs/state.hpp" -std::string CSMTools::MagicEffectCheckStage::checkTexture(const std::string &texture, bool isIcon) const -{ - const CSMWorld::Resources &textures = isIcon ? mIcons : mTextures; - if (textures.searchId(texture) != -1) return std::string(); - - std::string ddsTexture = texture; - if (Misc::ResourceHelpers::changeExtensionToDds(ddsTexture) && textures.searchId(ddsTexture) != -1) return std::string(); - - return (isIcon ? "Icon '" : "Particle '") + texture + "' does not exist"; -} - std::string CSMTools::MagicEffectCheckStage::checkObject(const std::string &id, const CSMWorld::UniversalId &type, const std::string &column) const @@ -25,12 +14,6 @@ std::string CSMTools::MagicEffectCheckStage::checkObject(const std::string &id, return std::string(); } -std::string CSMTools::MagicEffectCheckStage::checkSound(const std::string &id, const std::string &column) const -{ - if (!id.empty() && mSounds.searchId(id) == -1) return (column + " '" + id + "' " + "does not exist"); - return std::string(); -} - CSMTools::MagicEffectCheckStage::MagicEffectCheckStage(const CSMWorld::IdCollection &effects, const CSMWorld::IdCollection &sounds, const CSMWorld::RefIdCollection &objects, @@ -79,16 +62,22 @@ void CSMTools::MagicEffectCheckStage::perform(int stage, CSMDoc::Messages &messa } else { - const std::string error = checkTexture(effect.mIcon, true); - if (!error.empty()) - messages.add(id, error, "", CSMDoc::Message::Severity_Error); + if (mIcons.searchId(effect.mIcon) == -1) + { + std::string ddsIcon = effect.mIcon; + if (!(Misc::ResourceHelpers::changeExtensionToDds(ddsIcon) && mIcons.searchId(ddsIcon) != -1)) + messages.add(id, "Icon '" + effect.mIcon + "' does not exist", "", CSMDoc::Message::Severity_Error); + } } if (!effect.mParticle.empty()) { - const std::string error = checkTexture(effect.mParticle, false); - if (!error.empty()) - messages.add(id, error, "", CSMDoc::Message::Severity_Error); + if (mTextures.searchId(effect.mParticle) == -1) + { + std::string ddsParticle = effect.mParticle; + if (!(Misc::ResourceHelpers::changeExtensionToDds(ddsParticle) && mTextures.searchId(ddsParticle) != -1)) + messages.add(id, "Particle texture '" + effect.mParticle + "' does not exist", "", CSMDoc::Message::Severity_Error); + } } if (!effect.mCasting.empty()) @@ -119,31 +108,12 @@ void CSMTools::MagicEffectCheckStage::perform(int stage, CSMDoc::Messages &messa messages.add(id, error, "", CSMDoc::Message::Severity_Error); } - if (!effect.mCastSound.empty()) - { - const std::string error = checkSound(effect.mCastSound, "Casting sound"); - if (!error.empty()) - messages.add(id, error, "", CSMDoc::Message::Severity_Error); - } - - if (!effect.mHitSound.empty()) - { - const std::string error = checkSound(effect.mHitSound, "Hit sound"); - if (!error.empty()) - messages.add(id, error, "", CSMDoc::Message::Severity_Error); - } - - if (!effect.mAreaSound.empty()) - { - const std::string error = checkSound(effect.mAreaSound, "Area sound"); - if (!error.empty()) - messages.add(id, error, "", CSMDoc::Message::Severity_Error); - } - - if (!effect.mBoltSound.empty()) - { - const std::string error = checkSound(effect.mBoltSound, "Bolt sound"); - if (!error.empty()) - messages.add(id, error, "", CSMDoc::Message::Severity_Error); - } + if (!effect.mCastSound.empty() && mSounds.searchId(effect.mCastSound) == -1) + messages.add(id, "Casting sound '" + effect.mCastSound + "' does not exist", "", CSMDoc::Message::Severity_Error); + if (!effect.mHitSound.empty() && mSounds.searchId(effect.mHitSound) == -1) + messages.add(id, "Hit sound '" + effect.mHitSound + "' does not exist", "", CSMDoc::Message::Severity_Error); + if (!effect.mAreaSound.empty() && mSounds.searchId(effect.mAreaSound) == -1) + messages.add(id, "Area sound '" + effect.mAreaSound + "' does not exist", "", CSMDoc::Message::Severity_Error); + if (!effect.mBoltSound.empty() && mSounds.searchId(effect.mBoltSound) == -1) + messages.add(id, "Bolt sound '" + effect.mBoltSound + "' does not exist", "", CSMDoc::Message::Severity_Error); } diff --git a/apps/opencs/model/tools/referenceablecheck.cpp b/apps/opencs/model/tools/referenceablecheck.cpp index 60d4a6b58..4d68c93cd 100644 --- a/apps/opencs/model/tools/referenceablecheck.cpp +++ b/apps/opencs/model/tools/referenceablecheck.cpp @@ -723,7 +723,9 @@ void CSMTools::ReferenceableCheckStage::npcCheck ( messages.add(id, "Disposition is negative", "", CSMDoc::Message::Severity_Warning); if (reputation < 0) + { messages.add(id, "Reputation is negative", "", CSMDoc::Message::Severity_Warning); + } if (!npc.mFaction.empty()) { From 47b9008743b9a2a4d824f0768035f2932f672dd7 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Sun, 26 Aug 2018 22:16:50 +0300 Subject: [PATCH 114/196] Renovate reference record verifier --- apps/opencs/model/tools/referencecheck.cpp | 81 +++++++++------------- apps/opencs/model/tools/skillcheck.cpp | 2 - apps/opencs/model/tools/soundcheck.cpp | 1 - apps/opencs/model/tools/soundcheck.hpp | 6 +- 4 files changed, 33 insertions(+), 57 deletions(-) diff --git a/apps/opencs/model/tools/referencecheck.cpp b/apps/opencs/model/tools/referencecheck.cpp index dd93b4e9c..76bfeb3ba 100644 --- a/apps/opencs/model/tools/referencecheck.cpp +++ b/apps/opencs/model/tools/referencecheck.cpp @@ -28,76 +28,59 @@ void CSMTools::ReferenceCheckStage::perform(int stage, CSMDoc::Messages &message const CSMWorld::CellRef& cellRef = record.get(); const CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_Reference, cellRef.mId); - // Check for empty reference id - if (cellRef.mRefID.empty()) { - messages.push_back(std::make_pair(id, "Instance is not based on an object")); - } else { + // Check reference id + if (cellRef.mRefID.empty()) + messages.add(id, "Instance is not based on an object", "", CSMDoc::Message::Severity_Error); + else + { // Check for non existing referenced object - if (mObjects.searchId(cellRef.mRefID) == -1) { - messages.push_back(std::make_pair(id, "Instance of a non-existent object '" + cellRef.mRefID + "'")); - } else { + if (mObjects.searchId(cellRef.mRefID) == -1) + messages.add(id, "Instance of a non-existent object '" + cellRef.mRefID + "'", "", CSMDoc::Message::Severity_Error); + else + { // Check if reference charge is valid for it's proper referenced type CSMWorld::RefIdData::LocalIndex localIndex = mDataSet.searchId(cellRef.mRefID); bool isLight = localIndex.second == CSMWorld::UniversalId::Type_Light; - if ((isLight && cellRef.mChargeFloat < -1) || (!isLight && cellRef.mChargeInt < -1)) { - std::string str = "Invalid charge: "; - if (localIndex.second == CSMWorld::UniversalId::Type_Light) - str += std::to_string(cellRef.mChargeFloat); - else - str += std::to_string(cellRef.mChargeInt); - messages.push_back(std::make_pair(id, str)); - } + if ((isLight && cellRef.mChargeFloat < -1) || (!isLight && cellRef.mChargeInt < -1)) + messages.add(id, "Invalid charge", "", CSMDoc::Message::Severity_Error); } } // If object have owner, check if that owner reference is valid if (!cellRef.mOwner.empty() && mObjects.searchId(cellRef.mOwner) == -1) - messages.push_back(std::make_pair(id, "Owner object '" + cellRef.mOwner + "' does not exist")); + messages.add(id, "Owner object '" + cellRef.mOwner + "' does not exist", "", CSMDoc::Message::Severity_Error); // If object have creature soul trapped, check if that creature reference is valid if (!cellRef.mSoul.empty()) if (mObjects.searchId(cellRef.mSoul) == -1) - messages.push_back(std::make_pair(id, "Trapped soul object '" + cellRef.mSoul + "' does not exist")); + messages.add(id, "Trapped soul object '" + cellRef.mOwner + "' does not exist", "", CSMDoc::Message::Severity_Error); - bool hasFaction = !cellRef.mFaction.empty(); - - // If object have faction, check if that faction reference is valid - if (hasFaction) - if (mFactions.searchId(cellRef.mFaction) == -1) - messages.push_back(std::make_pair(id, "Faction '" + cellRef.mFaction + "' does not exist")); - - // Check item's faction rank - if ((hasFaction && cellRef.mFactionRank < -1) || (!hasFaction && cellRef.mFactionRank != -2)) - messages.push_back(std::make_pair(id, "Invalid faction rank " + std::to_string(cellRef.mFactionRank))); - - // If door have destination cell, check if that reference is valid - if (!cellRef.mDestCell.empty()) - if (mCells.searchId(cellRef.mDestCell) == -1) - messages.push_back(std::make_pair(id, "Destination cell '" + cellRef.mDestCell + "' does not exist")); - - // Check if scale isn't negative - if (cellRef.mScale < 0) + if (cellRef.mFaction.empty()) { - std::string str = "Negative scale: "; - str += std::to_string(cellRef.mScale); - messages.push_back(std::make_pair(id, str)); + if (cellRef.mFactionRank != -2) + messages.add(id, "Reference without a faction has a faction rank", "", CSMDoc::Message::Severity_Error); } + else + { + if (mFactions.searchId(cellRef.mFaction) == -1) + messages.add(id, "Faction '" + cellRef.mFaction + "' does not exist", "", CSMDoc::Message::Severity_Error); + else if (cellRef.mFactionRank < -1) + messages.add(id, "Invalid faction rank", "", CSMDoc::Message::Severity_Error); + } + + if (!cellRef.mDestCell.empty() && mCells.searchId(cellRef.mDestCell) == -1) + messages.add(id, "Destination cell '" + cellRef.mDestCell + "' does not exist", "", CSMDoc::Message::Severity_Error); + + if (cellRef.mScale < 0) + messages.add(id, "Negative scale", "", CSMDoc::Message::Severity_Error); // Check if enchantement points aren't negative or are at full (-1) - if (cellRef.mEnchantmentCharge < 0 && cellRef.mEnchantmentCharge != -1) - { - std::string str = "Negative enchantment points: "; - str += std::to_string(cellRef.mEnchantmentCharge); - messages.push_back(std::make_pair(id, str)); - } + if (cellRef.mEnchantmentCharge < -1) + messages.add(id, "Negative number of enchantment points", "", CSMDoc::Message::Severity_Error); // Check if gold value isn't negative if (cellRef.mGoldValue < 0) - { - std::string str = "Negative gold value: "; - str += cellRef.mGoldValue; - messages.push_back(std::make_pair(id, str)); - } + messages.add(id, "Negative gold value", "", CSMDoc::Message::Severity_Error); } int CSMTools::ReferenceCheckStage::setup() diff --git a/apps/opencs/model/tools/skillcheck.cpp b/apps/opencs/model/tools/skillcheck.cpp index ab7df51cb..89eba011a 100644 --- a/apps/opencs/model/tools/skillcheck.cpp +++ b/apps/opencs/model/tools/skillcheck.cpp @@ -35,10 +35,8 @@ void CSMTools::SkillCheckStage::perform (int stage, CSMDoc::Messages& messages) messages.add(id, "Description is missing", "", CSMDoc::Message::Severity_Warning); for (int i=0; i<4; ++i) - { if (skill.mData.mUseValue[i]<0) { messages.add(id, "Usage experience value #" + std::to_string(i) + " is negative", "", CSMDoc::Message::Severity_Error); } - } } diff --git a/apps/opencs/model/tools/soundcheck.cpp b/apps/opencs/model/tools/soundcheck.cpp index 7bb27e984..09e5ecdbf 100644 --- a/apps/opencs/model/tools/soundcheck.cpp +++ b/apps/opencs/model/tools/soundcheck.cpp @@ -4,7 +4,6 @@ #include "../prefs/state.hpp" -#include "../world/resources.hpp" #include "../world/universalid.hpp" CSMTools::SoundCheckStage::SoundCheckStage (const CSMWorld::IdCollection &sounds, diff --git a/apps/opencs/model/tools/soundcheck.hpp b/apps/opencs/model/tools/soundcheck.hpp index 47c3249ce..fc5925717 100644 --- a/apps/opencs/model/tools/soundcheck.hpp +++ b/apps/opencs/model/tools/soundcheck.hpp @@ -3,15 +3,11 @@ #include +#include "../world/resources.hpp" #include "../world/idcollection.hpp" #include "../doc/stage.hpp" -namespace CSMWorld -{ - class Resources; -} - namespace CSMTools { /// \brief VerifyStage: make sure that sound records are internally consistent From dabdb0bfaf63d55ec72c678332e5153c19cdcc4b Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Wed, 29 Aug 2018 18:53:02 +0300 Subject: [PATCH 115/196] Get rid of deprecated Messages::push_back() --- apps/opencs/model/doc/messages.cpp | 5 ----- apps/opencs/model/doc/messages.hpp | 3 --- apps/opencs/model/tools/referenceablecheck.cpp | 4 ++-- 3 files changed, 2 insertions(+), 10 deletions(-) diff --git a/apps/opencs/model/doc/messages.cpp b/apps/opencs/model/doc/messages.cpp index 76bbb6f22..b70d44eda 100644 --- a/apps/opencs/model/doc/messages.cpp +++ b/apps/opencs/model/doc/messages.cpp @@ -35,11 +35,6 @@ void CSMDoc::Messages::add (const CSMWorld::UniversalId& id, const std::string& mMessages.push_back (Message (id, message, hint, severity)); } -void CSMDoc::Messages::push_back (const std::pair& data) -{ - add (data.first, data.second); -} - CSMDoc::Messages::Iterator CSMDoc::Messages::begin() const { return mMessages.begin(); diff --git a/apps/opencs/model/doc/messages.hpp b/apps/opencs/model/doc/messages.hpp index 4041e1a67..671ded82a 100644 --- a/apps/opencs/model/doc/messages.hpp +++ b/apps/opencs/model/doc/messages.hpp @@ -56,9 +56,6 @@ namespace CSMDoc const std::string& hint = "", Message::Severity severity = Message::Severity_Default); - /// \deprecated Use add instead. - void push_back (const std::pair& data); - Iterator begin() const; Iterator end() const; diff --git a/apps/opencs/model/tools/referenceablecheck.cpp b/apps/opencs/model/tools/referenceablecheck.cpp index 4d68c93cd..def6dece3 100644 --- a/apps/opencs/model/tools/referenceablecheck.cpp +++ b/apps/opencs/model/tools/referenceablecheck.cpp @@ -737,7 +737,7 @@ void CSMTools::ReferenceableCheckStage::npcCheck ( } if (npc.mHead.empty()) - messages.push_back (std::make_pair (id, "Head is missing")); + messages.add(id, "Head is missing", "", CSMDoc::Message::Severity_Error); else { if (mBodyParts.searchId(npc.mHead) == -1) @@ -746,7 +746,7 @@ void CSMTools::ReferenceableCheckStage::npcCheck ( } if (npc.mHair.empty()) - messages.push_back (std::make_pair (id, "Hair is missing")); + messages.add(id, "Hair is missing", "", CSMDoc::Message::Severity_Error); else { if (mBodyParts.searchId(npc.mHair) == -1) From 015cd6064faa44fd4969de80722b2f9ebaa79dbc Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Thu, 30 Aug 2018 01:21:27 +0300 Subject: [PATCH 116/196] Implement basic enchantment record verifier (feature #1617) --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/model/tools/enchantmentcheck.cpp | 42 ++++++++++++++++++++ apps/opencs/model/tools/enchantmentcheck.hpp | 30 ++++++++++++++ apps/opencs/model/tools/magiceffectcheck.cpp | 6 ++- apps/opencs/model/tools/tools.cpp | 3 ++ 5 files changed, 80 insertions(+), 3 deletions(-) create mode 100644 apps/opencs/model/tools/enchantmentcheck.cpp create mode 100644 apps/opencs/model/tools/enchantmentcheck.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index d1ebcde42..f2821f184 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -42,7 +42,7 @@ opencs_units_noqt (model/tools mandatoryid skillcheck classcheck factioncheck racecheck soundcheck regioncheck birthsigncheck spellcheck referencecheck referenceablecheck scriptcheck bodypartcheck startscriptcheck search searchoperation searchstage pathgridcheck soundgencheck magiceffectcheck - mergestages gmstcheck topicinfocheck journalcheck + mergestages gmstcheck topicinfocheck journalcheck enchantmentcheck ) opencs_hdrs_noqt (model/tools diff --git a/apps/opencs/model/tools/enchantmentcheck.cpp b/apps/opencs/model/tools/enchantmentcheck.cpp new file mode 100644 index 000000000..e1dca9331 --- /dev/null +++ b/apps/opencs/model/tools/enchantmentcheck.cpp @@ -0,0 +1,42 @@ +#include "enchantmentcheck.hpp" + +#include "../prefs/state.hpp" + +#include "../world/universalid.hpp" + +CSMTools::EnchantmentCheckStage::EnchantmentCheckStage (const CSMWorld::IdCollection& enchantments) + : mEnchantments (enchantments) +{ + mIgnoreBaseRecords = false; +} + +int CSMTools::EnchantmentCheckStage::setup() +{ + mIgnoreBaseRecords = CSMPrefs::get()["Reports"]["ignore-base-records"].isTrue(); + + return mEnchantments.getSize(); +} + +void CSMTools::EnchantmentCheckStage::perform (int stage, CSMDoc::Messages& messages) +{ + const CSMWorld::Record& record = mEnchantments.getRecord (stage); + + // Skip "Base" records (setting!) and "Deleted" records + if ((mIgnoreBaseRecords && record.mState == CSMWorld::RecordBase::State_BaseOnly) || record.isDeleted()) + return; + + const ESM::Enchantment& enchantment = record.get(); + + CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Enchantment, enchantment.mId); + + if (enchantment.mData.mType < 0 || enchantment.mData.mType > 3) + messages.add(id, "Invalid type", "", CSMDoc::Message::Severity_Error); + + if (enchantment.mData.mCost < 0) + messages.add(id, "Cost is negative", "", CSMDoc::Message::Severity_Error); + + if (enchantment.mData.mCharge < 0) + messages.add(id, "Charge is negative", "", CSMDoc::Message::Severity_Error); + + /// \todo Check effects list for validity +} diff --git a/apps/opencs/model/tools/enchantmentcheck.hpp b/apps/opencs/model/tools/enchantmentcheck.hpp new file mode 100644 index 000000000..ba8ae64aa --- /dev/null +++ b/apps/opencs/model/tools/enchantmentcheck.hpp @@ -0,0 +1,30 @@ +#ifndef CSM_TOOLS_ENCHANTMENTCHECK_H +#define CSM_TOOLS_ENCHANTMENTCHECK_H + +#include + +#include "../world/idcollection.hpp" + +#include "../doc/stage.hpp" + +namespace CSMTools +{ + /// \brief Make sure that enchantment records are correct + class EnchantmentCheckStage : public CSMDoc::Stage + { + const CSMWorld::IdCollection& mEnchantments; + bool mIgnoreBaseRecords; + + public: + + EnchantmentCheckStage (const CSMWorld::IdCollection& enchantments); + + virtual int setup(); + ///< \return number of steps + + virtual void perform (int stage, CSMDoc::Messages& messages); + ///< Messages resulting from this tage will be appended to \a messages. + }; +} + +#endif diff --git a/apps/opencs/model/tools/magiceffectcheck.cpp b/apps/opencs/model/tools/magiceffectcheck.cpp index b62e791a4..f55fb14ee 100644 --- a/apps/opencs/model/tools/magiceffectcheck.cpp +++ b/apps/opencs/model/tools/magiceffectcheck.cpp @@ -9,8 +9,10 @@ std::string CSMTools::MagicEffectCheckStage::checkObject(const std::string &id, const std::string &column) const { CSMWorld::RefIdData::LocalIndex index = mObjects.getDataSet().searchId(id); - if (index.first == -1) return (column + " '" + id + "' " + "does not exist"); - else if (index.second != type.getType()) return (column + " '" + id + "' " + "does not have " + type.getTypeName() + " type"); + if (index.first == -1) + return (column + " '" + id + "' does not exist"); + else if (index.second != type.getType()) + return (column + " '" + id + "' does not have " + type.getTypeName() + " type"); return std::string(); } diff --git a/apps/opencs/model/tools/tools.cpp b/apps/opencs/model/tools/tools.cpp index b9a0abb75..07a721e8e 100644 --- a/apps/opencs/model/tools/tools.cpp +++ b/apps/opencs/model/tools/tools.cpp @@ -32,6 +32,7 @@ #include "gmstcheck.hpp" #include "topicinfocheck.hpp" #include "journalcheck.hpp" +#include "enchantmentcheck.hpp" CSMDoc::OperationHolder *CSMTools::Tools::get (int type) { @@ -128,6 +129,8 @@ CSMDoc::OperationHolder *CSMTools::Tools::getVerifier() mVerifierOperation->appendStage (new JournalCheckStage(mData.getJournals(), mData.getJournalInfos())); + mVerifierOperation->appendStage (new EnchantmentCheckStage(mData.getEnchantments())); + mVerifier.setOperation (mVerifierOperation); } From 5d1c1f25f79ed21432503ebb3fdc6b4a935e3352 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Mon, 3 Sep 2018 16:57:01 +0300 Subject: [PATCH 117/196] Remove now redundant NPC fields checks --- .../opencs/model/tools/referenceablecheck.cpp | 21 ++----------------- 1 file changed, 2 insertions(+), 19 deletions(-) diff --git a/apps/opencs/model/tools/referenceablecheck.cpp b/apps/opencs/model/tools/referenceablecheck.cpp index def6dece3..d31b8b7d0 100644 --- a/apps/opencs/model/tools/referenceablecheck.cpp +++ b/apps/opencs/model/tools/referenceablecheck.cpp @@ -667,9 +667,6 @@ void CSMTools::ReferenceableCheckStage::npcCheck ( return; short level(npc.mNpdt.mLevel); - char disposition(npc.mNpdt.mDisposition); - char reputation(npc.mNpdt.mReputation); - char rank(npc.mNpdt.mRank); int gold(npc.mNpdt.mGold); if (npc.mNpdtType == ESM::NPC::NPC_WITH_AUTOCALCULATED_STATS) //12 = autocalculated @@ -719,22 +716,8 @@ void CSMTools::ReferenceableCheckStage::npcCheck ( else if (mRaces.searchId (npc.mRace) == -1) messages.add(id, "Race '" + npc.mRace + "' does not exist", "", CSMDoc::Message::Severity_Error); - if (disposition < 0) - messages.add(id, "Disposition is negative", "", CSMDoc::Message::Severity_Warning); - - if (reputation < 0) - { - messages.add(id, "Reputation is negative", "", CSMDoc::Message::Severity_Warning); - } - - if (!npc.mFaction.empty()) - { - if (rank < 0) - messages.add(id, "Faction rank is negative", "", CSMDoc::Message::Severity_Warning); - - if (mFactions.searchId(npc.mFaction) == -1) - messages.add(id, "Faction '" + npc.mFaction + "' does not exist", "", CSMDoc::Message::Severity_Error); - } + if (!npc.mFaction.empty() && mFactions.searchId(npc.mFaction) == -1) + messages.add(id, "Faction '" + npc.mFaction + "' does not exist", "", CSMDoc::Message::Severity_Error); if (npc.mHead.empty()) messages.add(id, "Head is missing", "", CSMDoc::Message::Severity_Error); From d6560d3f20dc5dd889088bc796e5bf0032610508 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Tue, 4 Sep 2018 16:08:09 +0300 Subject: [PATCH 118/196] Make several messages more strict and clean up topic info verifier --- apps/opencs/model/tools/classcheck.cpp | 11 ++--- apps/opencs/model/tools/factioncheck.cpp | 6 +-- .../opencs/model/tools/referenceablecheck.cpp | 2 +- apps/opencs/model/tools/topicinfocheck.cpp | 45 +++++-------------- 4 files changed, 18 insertions(+), 46 deletions(-) diff --git a/apps/opencs/model/tools/classcheck.cpp b/apps/opencs/model/tools/classcheck.cpp index 25cca8fcd..a82121597 100644 --- a/apps/opencs/model/tools/classcheck.cpp +++ b/apps/opencs/model/tools/classcheck.cpp @@ -36,12 +36,7 @@ void CSMTools::ClassCheckStage::perform (int stage, CSMDoc::Messages& messages) // A class should have a name if (class_.mName.empty()) - { - if (class_.mData.mIsPlayable != 0) - messages.add(id, "Name of a playable class is missing", "", CSMDoc::Message::Severity_Error); - else - messages.add(id, "Name is missing", "", CSMDoc::Message::Severity_Warning); - } + messages.add(id, "Name is missing", "", CSMDoc::Message::Severity_Error); // A playable class should have a description if (class_.mData.mIsPlayable != 0 && class_.mDescription.empty()) @@ -56,7 +51,7 @@ void CSMTools::ClassCheckStage::perform (int stage, CSMDoc::Messages& messages) if (class_.mData.mAttribute[0]==class_.mData.mAttribute[1] && class_.mData.mAttribute[0]!=-1) { - messages.add(id, "Same attribute is listed twice", "", CSMDoc::Message::Severity_Warning); + messages.add(id, "Same attribute is listed twice", "", CSMDoc::Message::Severity_Error); } // test for non-unique skill @@ -69,6 +64,6 @@ void CSMTools::ClassCheckStage::perform (int stage, CSMDoc::Messages& messages) for (auto &skill : skills) if (skill.second>1) { - messages.add(id, "Skill " + ESM::Skill::indexToId (skill.first) + " is listed more than once", "", CSMDoc::Message::Severity_Warning); + messages.add(id, "Skill " + ESM::Skill::indexToId (skill.first) + " is listed more than once", "", CSMDoc::Message::Severity_Error); } } diff --git a/apps/opencs/model/tools/factioncheck.cpp b/apps/opencs/model/tools/factioncheck.cpp index 5bd613851..0ee245ad4 100644 --- a/apps/opencs/model/tools/factioncheck.cpp +++ b/apps/opencs/model/tools/factioncheck.cpp @@ -37,12 +37,12 @@ void CSMTools::FactionCheckStage::perform (int stage, CSMDoc::Messages& messages // test for empty name if (faction.mName.empty()) - messages.add(id, "Name is missing", "", CSMDoc::Message::Severity_Warning); + messages.add(id, "Name is missing", "", CSMDoc::Message::Severity_Error); // test for invalid attributes if (faction.mData.mAttribute[0]==faction.mData.mAttribute[1] && faction.mData.mAttribute[0]!=-1) { - messages.add(id, "Same attribute is listed twice", "", CSMDoc::Message::Severity_Warning); + messages.add(id, "Same attribute is listed twice", "", CSMDoc::Message::Severity_Error); } // test for non-unique skill @@ -55,7 +55,7 @@ void CSMTools::FactionCheckStage::perform (int stage, CSMDoc::Messages& messages for (auto &skill : skills) if (skill.second>1) { - messages.add(id, "Skill " + ESM::Skill::indexToId (skill.first) + " is listed more than once", "", CSMDoc::Message::Severity_Warning); + messages.add(id, "Skill " + ESM::Skill::indexToId (skill.first) + " is listed more than once", "", CSMDoc::Message::Severity_Error); } /// \todo check data members that can't be edited in the table view diff --git a/apps/opencs/model/tools/referenceablecheck.cpp b/apps/opencs/model/tools/referenceablecheck.cpp index d31b8b7d0..fdbab7fd0 100644 --- a/apps/opencs/model/tools/referenceablecheck.cpp +++ b/apps/opencs/model/tools/referenceablecheck.cpp @@ -475,7 +475,7 @@ void CSMTools::ReferenceableCheckStage::creatureCheck ( if (creature.mData.mAttack[i] < 0) messages.add(id, "Attack " + std::to_string(i/2 + 1) + " has negative" + (i % 2 == 0 ? " minimum " : " maximum ") + "damage", "", CSMDoc::Message::Severity_Error); if (i % 2 == 0 && creature.mData.mAttack[i] > creature.mData.mAttack[i+1]) - messages.add(id, "Attack " + std::to_string(i/2 + 1) + " has minimum damage higher than maximum damage", "", CSMDoc::Message::Severity_Warning); + messages.add(id, "Attack " + std::to_string(i/2 + 1) + " has minimum damage higher than maximum damage", "", CSMDoc::Message::Severity_Error); } if (creature.mData.mGold < 0) diff --git a/apps/opencs/model/tools/topicinfocheck.cpp b/apps/opencs/model/tools/topicinfocheck.cpp index 9a31db72b..fe9bc991d 100644 --- a/apps/opencs/model/tools/topicinfocheck.cpp +++ b/apps/opencs/model/tools/topicinfocheck.cpp @@ -133,7 +133,6 @@ void CSMTools::TopicInfoCheckStage::perform(int stage, CSMDoc::Messages& message if (topicInfo.mData.mGender < -1 || topicInfo.mData.mGender > 1) { - std::ostringstream stream; messages.add(id, "Gender is invalid", "", CSMDoc::Message::Severity_Error); } @@ -170,16 +169,12 @@ bool CSMTools::TopicInfoCheckStage::verifyActor(const std::string& actor, const if (index.first == -1) { - std::ostringstream stream; - stream << "Actor '" << actor << "' does not exist"; - messages.add(id, stream.str(), "", CSMDoc::Message::Severity_Error); + messages.add(id, "Actor '" + actor + "' does not exist", "", CSMDoc::Message::Severity_Error); return false; } else if (mReferencables.getRecord(index).isDeleted()) { - std::ostringstream stream; - stream << "Deleted actor '" << actor << "' is being referenced"; - messages.add(id, stream.str(), "", CSMDoc::Message::Severity_Error); + messages.add(id, "Deleted actor '" + actor + "' is being referenced", "", CSMDoc::Message::Severity_Error); return false; } else if (index.second != CSMWorld::UniversalId::Type_Npc && index.second != CSMWorld::UniversalId::Type_Creature) @@ -199,9 +194,7 @@ bool CSMTools::TopicInfoCheckStage::verifyCell(const std::string& cell, const CS { if (mCellNames.find(cell) == mCellNames.end()) { - std::ostringstream stream; - stream << "Cell '" << cell << "' does not exist"; - messages.add(id, stream.str(), "", CSMDoc::Message::Severity_Error); + messages.add(id, "Cell '" + cell + "' does not exist", "", CSMDoc::Message::Severity_Error); return false; } @@ -236,7 +229,7 @@ bool CSMTools::TopicInfoCheckStage::verifyFactionRank(const std::string& faction stream << "Faction rank is set to " << rank << " which is more than the maximum of " << limit - 1 << " for the '" << factionName << "' faction"; - messages.add(id, stream.str(), "", CSMDoc::Message::Severity_Warning); + messages.add(id, stream.str(), "", CSMDoc::Message::Severity_Error); return false; } @@ -250,16 +243,12 @@ bool CSMTools::TopicInfoCheckStage::verifyItem(const std::string& item, const CS if (index.first == -1) { - std::ostringstream stream; - stream << "Item '" << item << "' does not exist"; - messages.add(id, stream.str(), "", CSMDoc::Message::Severity_Error); + messages.add(id, ("Item '" + item + "' does not exist"), "", CSMDoc::Message::Severity_Error); return false; } else if (mReferencables.getRecord(index).isDeleted()) { - std::ostringstream stream; - stream << "Deleted item '" << item << "' is being referenced"; - messages.add(id, stream.str(), "", CSMDoc::Message::Severity_Error); + messages.add(id, ("Deleted item '" + item + "' is being referenced"), "", CSMDoc::Message::Severity_Error); return false; } else @@ -327,18 +316,12 @@ bool CSMTools::TopicInfoCheckStage::verifySelectStruct(const ESM::DialInfo::Sele } else if (infoCondition.conditionIsAlwaysTrue()) { - std::ostringstream stream; - stream << "Condition '" << infoCondition.toString() << "' is always true"; - - messages.add(id, stream.str(), "", CSMDoc::Message::Severity_Warning); + messages.add(id, "Condition '" + infoCondition.toString() + "' is always true", "", CSMDoc::Message::Severity_Warning); return false; } else if (infoCondition.conditionIsNeverTrue()) { - std::ostringstream stream; - stream << "Condition '" << infoCondition.toString() << "' is never true"; - - messages.add(id, stream.str(), "", CSMDoc::Message::Severity_Warning); + messages.add(id, "Condition '" + infoCondition.toString() + "' is never true", "", CSMDoc::Message::Severity_Warning); return false; } @@ -397,9 +380,7 @@ bool CSMTools::TopicInfoCheckStage::verifySound(const std::string& sound, const { if (mSoundFiles.searchId(sound) == -1) { - std::ostringstream stream; - stream << "Sound file '" << sound << "' does not exist"; - messages.add(id, stream.str(), "", CSMDoc::Message::Severity_Error); + messages.add(id, "Sound file '" + sound + "' does not exist", "", CSMDoc::Message::Severity_Error); return false; } @@ -414,16 +395,12 @@ bool CSMTools::TopicInfoCheckStage::verifyId(const std::string& name, const CSMW if (index == -1) { - std::ostringstream stream; - stream << T::getRecordType() + " '" << name << "' does not exist"; - messages.add(id, stream.str(), "", CSMDoc::Message::Severity_Error); + messages.add(id, T::getRecordType() + " '" + name + "' does not exist", "", CSMDoc::Message::Severity_Error); return false; } else if (collection.getRecord(index).isDeleted()) { - std::ostringstream stream; - stream << "Deleted " << T::getRecordType() << " record '" << name << "' is being referenced"; - messages.add(id, stream.str(), "", CSMDoc::Message::Severity_Error); + messages.add(id, "Deleted " + T::getRecordType() + " record '" + name + "' is being referenced", "", CSMDoc::Message::Severity_Error); return false; } From c025427575e7279f2871a982f2a6213f3a4b9642 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Tue, 11 Sep 2018 21:40:41 +0300 Subject: [PATCH 119/196] Implement enchantment record effect list verification (feature #1617) --- apps/opencs/model/tools/enchantmentcheck.cpp | 42 +++++++++++++++++++- apps/opencs/model/tools/enchantmentcheck.hpp | 1 + 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/apps/opencs/model/tools/enchantmentcheck.cpp b/apps/opencs/model/tools/enchantmentcheck.cpp index e1dca9331..28f2b32cb 100644 --- a/apps/opencs/model/tools/enchantmentcheck.cpp +++ b/apps/opencs/model/tools/enchantmentcheck.cpp @@ -38,5 +38,45 @@ void CSMTools::EnchantmentCheckStage::perform (int stage, CSMDoc::Messages& mess if (enchantment.mData.mCharge < 0) messages.add(id, "Charge is negative", "", CSMDoc::Message::Severity_Error); - /// \todo Check effects list for validity + if (enchantment.mData.mCost > enchantment.mData.mCharge) + messages.add(id, "Cost is higher than charge", "", CSMDoc::Message::Severity_Error); + + if (enchantment.mEffects.mList.empty()) + { + messages.add(id, "Enchantment doesn't have any magic effects", "", CSMDoc::Message::Severity_Warning); + } + else + { + std::vector::const_iterator effect = enchantment.mEffects.mList.begin(); + + for (size_t i = 1; i <= enchantment.mEffects.mList.size(); i++) + { + const std::string number = std::to_string(i); + // At the time of writing this effects, attributes and skills are hardcoded + if (effect->mEffectID < 0 || effect->mEffectID > 142) + { + messages.add(id, "Effect #" + number + " is invalid", "", CSMDoc::Message::Severity_Error); + ++effect; + continue; + } + + if (effect->mSkill < -1 || effect->mSkill > 26) + messages.add(id, "Effect #" + number + " affected skill is invalid", "", CSMDoc::Message::Severity_Error); + if (effect->mAttribute < -1 || effect->mAttribute > 7) + messages.add(id, "Effect #" + number + " affected attribute is invalid", "", CSMDoc::Message::Severity_Error); + if (effect->mRange < 0 || effect->mRange > 2) + messages.add(id, "Effect #" + number + " range is invalid", "", CSMDoc::Message::Severity_Error); + if (effect->mArea < 0) + messages.add(id, "Effect #" + number + " area is negative", "", CSMDoc::Message::Severity_Error); + if (effect->mDuration < 0) + messages.add(id, "Effect #" + number + " duration is negative", "", CSMDoc::Message::Severity_Error); + if (effect->mMagnMin < 0) + messages.add(id, "Effect #" + number + " minimum magnitude is negative", "", CSMDoc::Message::Severity_Error); + if (effect->mMagnMax < 0) + messages.add(id, "Effect #" + number + " maximum magnitude is negative", "", CSMDoc::Message::Severity_Error); + if (effect->mMagnMin > effect->mMagnMax) + messages.add(id, "Effect #" + number + " minimum magnitude is higher than maximum magnitude", "", CSMDoc::Message::Severity_Error); + ++effect; + } + } } diff --git a/apps/opencs/model/tools/enchantmentcheck.hpp b/apps/opencs/model/tools/enchantmentcheck.hpp index ba8ae64aa..3bd85326f 100644 --- a/apps/opencs/model/tools/enchantmentcheck.hpp +++ b/apps/opencs/model/tools/enchantmentcheck.hpp @@ -24,6 +24,7 @@ namespace CSMTools virtual void perform (int stage, CSMDoc::Messages& messages); ///< Messages resulting from this tage will be appended to \a messages. + }; } From 5a86554f97f87c52add041865a4fdcd2a5dee6bd Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Fri, 14 Sep 2018 21:42:11 +0300 Subject: [PATCH 120/196] Cleanup --- apps/opencs/model/tools/birthsigncheck.cpp | 6 +----- apps/opencs/model/tools/factioncheck.cpp | 2 -- apps/opencs/model/tools/journalcheck.cpp | 7 ++----- apps/opencs/model/tools/magiceffectcheck.hpp | 2 -- apps/opencs/model/tools/racecheck.cpp | 10 ++-------- apps/opencs/model/tools/regioncheck.cpp | 5 ----- apps/opencs/model/tools/skillcheck.cpp | 4 +--- apps/opencs/model/tools/soundcheck.cpp | 4 +--- apps/opencs/model/tools/soundgencheck.cpp | 2 -- 9 files changed, 7 insertions(+), 35 deletions(-) diff --git a/apps/opencs/model/tools/birthsigncheck.cpp b/apps/opencs/model/tools/birthsigncheck.cpp index a0ae4b11f..f91fc22f6 100644 --- a/apps/opencs/model/tools/birthsigncheck.cpp +++ b/apps/opencs/model/tools/birthsigncheck.cpp @@ -1,6 +1,5 @@ #include "birthsigncheck.hpp" -#include #include #include "../prefs/state.hpp" @@ -42,11 +41,8 @@ void CSMTools::BirthsignCheckStage::perform (int stage, CSMDoc::Messages& messag if (birthsign.mTexture.empty()) messages.add(id, "Image is missing", "", CSMDoc::Message::Severity_Error); - else + else if (mTextures.searchId(birthsign.mTexture) == -1) { - if (mTextures.searchId(birthsign.mTexture) != -1) - return; - std::string ddsTexture = birthsign.mTexture; if (!(Misc::ResourceHelpers::changeExtensionToDds(ddsTexture) && mTextures.searchId(ddsTexture) != -1)) messages.add(id, "Image '" + birthsign.mTexture + "' does not exist", "", CSMDoc::Message::Severity_Error); diff --git a/apps/opencs/model/tools/factioncheck.cpp b/apps/opencs/model/tools/factioncheck.cpp index 0ee245ad4..8a198e953 100644 --- a/apps/opencs/model/tools/factioncheck.cpp +++ b/apps/opencs/model/tools/factioncheck.cpp @@ -1,9 +1,7 @@ #include "factioncheck.hpp" -#include #include -#include #include #include "../prefs/state.hpp" diff --git a/apps/opencs/model/tools/journalcheck.cpp b/apps/opencs/model/tools/journalcheck.cpp index dc15b26ee..ae83abfa0 100644 --- a/apps/opencs/model/tools/journalcheck.cpp +++ b/apps/opencs/model/tools/journalcheck.cpp @@ -1,7 +1,6 @@ #include "journalcheck.hpp" #include -#include #include "../prefs/state.hpp" @@ -63,12 +62,10 @@ void CSMTools::JournalCheckStage::perform(int stage, CSMDoc::Messages& messages) std::pair::iterator, bool> result = questIndices.insert(journalInfo.mData.mJournalIndex); // Duplicate index - if (result.second == false) + if (!result.second) { CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_JournalInfo, journalInfo.mId); - std::ostringstream stream; - stream << "Duplicated quest index " << journalInfo.mData.mJournalIndex; - messages.add(id, stream.str(), "", CSMDoc::Message::Severity_Error); + messages.add(id, "Duplicated quest index " + std::to_string(journalInfo.mData.mJournalIndex), "", CSMDoc::Message::Severity_Error); } } diff --git a/apps/opencs/model/tools/magiceffectcheck.hpp b/apps/opencs/model/tools/magiceffectcheck.hpp index 22dad3db9..a52723b0f 100644 --- a/apps/opencs/model/tools/magiceffectcheck.hpp +++ b/apps/opencs/model/tools/magiceffectcheck.hpp @@ -23,9 +23,7 @@ namespace CSMTools bool mIgnoreBaseRecords; private: - std::string checkTexture(const std::string &texture, bool isIcon) const; std::string checkObject(const std::string &id, const CSMWorld::UniversalId &type, const std::string &column) const; - std::string checkSound(const std::string &id, const std::string &column) const; public: MagicEffectCheckStage(const CSMWorld::IdCollection &effects, diff --git a/apps/opencs/model/tools/racecheck.cpp b/apps/opencs/model/tools/racecheck.cpp index 3b487b925..6585a31cc 100644 --- a/apps/opencs/model/tools/racecheck.cpp +++ b/apps/opencs/model/tools/racecheck.cpp @@ -1,9 +1,5 @@ #include "racecheck.hpp" -#include - -#include - #include "../prefs/state.hpp" #include "../world/universalid.hpp" @@ -28,10 +24,8 @@ void CSMTools::RaceCheckStage::performPerRecord (int stage, CSMDoc::Messages& me CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Race, race.mId); // test for empty name and description - if (race.mName.empty() && race.mData.mFlags & 0x1) - messages.add(id, "Name is missing", "", CSMDoc::Message::Severity_Error); - else if (race.mName.empty()) - messages.add(id, "Name is missing", "", CSMDoc::Message::Severity_Warning); + if (race.mName.empty()) + messages.add(id, "Name is missing", "", (race.mData.mFlags & 0x1) ? CSMDoc::Message::Severity_Error : CSMDoc::Message::Severity_Warning); if (race.mDescription.empty()) messages.add(id, "Description is missing", "", CSMDoc::Message::Severity_Warning); diff --git a/apps/opencs/model/tools/regioncheck.cpp b/apps/opencs/model/tools/regioncheck.cpp index 8375e3f0a..0b6537d7f 100644 --- a/apps/opencs/model/tools/regioncheck.cpp +++ b/apps/opencs/model/tools/regioncheck.cpp @@ -1,10 +1,5 @@ #include "regioncheck.hpp" -#include -#include - -#include - #include "../prefs/state.hpp" #include "../world/universalid.hpp" diff --git a/apps/opencs/model/tools/skillcheck.cpp b/apps/opencs/model/tools/skillcheck.cpp index 89eba011a..c5b38dc1e 100644 --- a/apps/opencs/model/tools/skillcheck.cpp +++ b/apps/opencs/model/tools/skillcheck.cpp @@ -1,7 +1,5 @@ #include "skillcheck.hpp" -#include - #include "../prefs/state.hpp" #include "../world/universalid.hpp" @@ -37,6 +35,6 @@ void CSMTools::SkillCheckStage::perform (int stage, CSMDoc::Messages& messages) for (int i=0; i<4; ++i) if (skill.mData.mUseValue[i]<0) { - messages.add(id, "Usage experience value #" + std::to_string(i) + " is negative", "", CSMDoc::Message::Severity_Error); + messages.add(id, "Use value #" + std::to_string(i) + " is negative", "", CSMDoc::Message::Severity_Error); } } diff --git a/apps/opencs/model/tools/soundcheck.cpp b/apps/opencs/model/tools/soundcheck.cpp index 09e5ecdbf..c0d893f1a 100644 --- a/apps/opencs/model/tools/soundcheck.cpp +++ b/apps/opencs/model/tools/soundcheck.cpp @@ -1,7 +1,5 @@ #include "soundcheck.hpp" -#include - #include "../prefs/state.hpp" #include "../world/universalid.hpp" @@ -35,7 +33,7 @@ void CSMTools::SoundCheckStage::perform (int stage, CSMDoc::Messages& messages) if (sound.mData.mMinRange>sound.mData.mMaxRange) { - messages.add(id, "Minimum range larger than maximum range", "", CSMDoc::Message::Severity_Warning); + messages.add(id, "Minimum range is larger than maximum range", "", CSMDoc::Message::Severity_Warning); } if (sound.mSound.empty()) diff --git a/apps/opencs/model/tools/soundgencheck.cpp b/apps/opencs/model/tools/soundgencheck.cpp index 7b6cf7a4b..ec29e23fe 100644 --- a/apps/opencs/model/tools/soundgencheck.cpp +++ b/apps/opencs/model/tools/soundgencheck.cpp @@ -1,7 +1,5 @@ #include "soundgencheck.hpp" -#include - #include "../prefs/state.hpp" #include "../world/refiddata.hpp" From 59092978091fba6e756408af80f9ad58de2a03b8 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Sat, 15 Sep 2018 23:20:28 +0300 Subject: [PATCH 121/196] Make underwater SFX always apply based on camera position (bug #4532) --- CHANGELOG.md | 1 + apps/openmw/mwworld/worldimp.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6bea04fcb..4c304ed9b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -93,6 +93,7 @@ Bug #4510: Division by zero in MWMechanics::CreatureStats::setAttribute Bug #4519: Knockdown does not discard movement in the 1st-person mode Bug #4531: Movement does not reset idle animations + Bug #4532: Underwater sfx isn't tied to 3rd person camera Bug #4539: Paper Doll is affected by GUI scaling Bug #4543: Picking cursed items through inventory (menumode) makes it disappear Bug #4545: Creatures flee from werewolves diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 9e08a2563..d1f274787 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1789,7 +1789,7 @@ namespace MWWorld osg::Vec3f forward = listenerOrient * osg::Vec3f(0,1,0); osg::Vec3f up = listenerOrient * osg::Vec3f(0,0,1); - bool underwater = isUnderwater(getPlayerPtr().getCell(), listenerPos); + bool underwater = isUnderwater(getPlayerPtr().getCell(), mRendering->getCameraPosition()); MWBase::Environment::get().getSoundManager()->setListenerPosDir(listenerPos, forward, up, underwater); } From ae1c054635b6268dc19aab85397ad884aa81a903 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sat, 15 Sep 2018 19:38:21 +0400 Subject: [PATCH 122/196] Make GetPCJumping return true only when jumping (bug #4641) --- CHANGELOG.md | 1 + apps/openmw/mwmechanics/character.cpp | 21 +++++++++++++-------- apps/openmw/mwmechanics/creaturestats.cpp | 6 +++++- apps/openmw/mwmechanics/creaturestats.hpp | 2 +- apps/openmw/mwphysics/physicssystem.cpp | 3 ++- apps/openmw/mwscript/miscextensions.cpp | 3 +-- apps/openmw/mwworld/actionteleport.cpp | 2 +- apps/openmw/mwworld/player.cpp | 14 +++++++++++++- apps/openmw/mwworld/player.hpp | 4 ++++ 9 files changed, 41 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a01e2c746..36c7e19c9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -119,6 +119,7 @@ Bug #4622: Recharging enchanted items with Soul Gems does not award experience if it fails Bug #4628: NPC record reputation, disposition and faction rank should have unsigned char type Bug #4633: Sneaking stance affects speed even if the actor is not able to crouch + Bug #4641: GetPCJumping is handled incorrectly Feature #912: Editor: Add missing icons to UniversalId tables Feature #1645: Casting effects from objects Feature #2606: Editor: Implemented (optional) case sensitive global search diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 123f7bf59..af8ed706d 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1850,7 +1850,8 @@ void CharacterController::update(float duration) if (isKnockedOut()) mTimeUntilWake -= duration; - bool godmode = mPtr == MWMechanics::getPlayer() && MWBase::Environment::get().getWorld()->getGodModeState(); + bool isPlayer = mPtr == MWMechanics::getPlayer(); + bool godmode = isPlayer && MWBase::Environment::get().getWorld()->getGodModeState(); if(!cls.isActor()) updateAnimQueue(); @@ -1915,7 +1916,7 @@ void CharacterController::update(float duration) isrunning = isrunning && mHasMovedInXY; // advance athletics - if(mHasMovedInXY && mPtr == getPlayer()) + if(mHasMovedInXY && isPlayer) { if(inwater) { @@ -2011,8 +2012,12 @@ void CharacterController::update(float duration) } // advance acrobatics - if (mPtr == getPlayer()) + // also set jumping flag to allow GetPCJumping works + if (isPlayer) + { cls.skillUsageSucceeded(mPtr, ESM::Skill::Acrobatics, 0); + MWBase::Environment::get().getWorld()->getPlayer().setJumping(true); + } // decrease fatigue const float fatigueJumpBase = gmst.find("fFatigueJumpBase")->mValue.getFloat(); @@ -2035,7 +2040,7 @@ void CharacterController::update(float duration) jumpstate = JumpState_Landing; vec.z() = 0.0f; - float height = cls.getCreatureStats(mPtr).land(); + float height = cls.getCreatureStats(mPtr).land(isPlayer); float healthLost = getFallDamage(mPtr, height); if (healthLost > 0.0f) @@ -2058,7 +2063,7 @@ void CharacterController::update(float duration) else { // report acrobatics progression - if (mPtr == getPlayer()) + if (isPlayer) cls.skillUsageSucceeded(mPtr, ESM::Skill::Acrobatics, 1); } } @@ -2080,7 +2085,7 @@ void CharacterController::update(float duration) // Do not play turning animation for player if rotation speed is very slow. // Actual threshold should take framerate in account. float rotationThreshold = 0; - if (mPtr == getPlayer()) + if (isPlayer) rotationThreshold = 0.015 * 60 * duration; if(std::abs(vec.x()/2.0f) > std::abs(vec.y())) @@ -2109,7 +2114,7 @@ void CharacterController::update(float duration) { // It seems only bipedal actors use turning animations. // Also do not use turning animations in the first-person view and when sneaking. - bool isFirstPlayer = mPtr == getPlayer() && MWBase::Environment::get().getWorld()->isFirstPerson(); + bool isFirstPlayer = isPlayer && MWBase::Environment::get().getWorld()->isFirstPerson(); if (!sneak && !isFirstPlayer && mPtr.getClass().isBipedal(mPtr)) { if(rot.z() > rotationThreshold) @@ -2121,7 +2126,7 @@ void CharacterController::update(float duration) } // Player can not use smooth turning as NPCs, so we play turning animation a bit to avoid jittering - if (mPtr == getPlayer()) + if (isPlayer) { float threshold = mCurrentMovement.find("swim") == std::string::npos ? 0.4f : 0.8f; float complete; diff --git a/apps/openmw/mwmechanics/creaturestats.cpp b/apps/openmw/mwmechanics/creaturestats.cpp index 2994eac28..7cc6ea784 100644 --- a/apps/openmw/mwmechanics/creaturestats.cpp +++ b/apps/openmw/mwmechanics/creaturestats.cpp @@ -7,6 +7,7 @@ #include #include "../mwworld/esmstore.hpp" +#include "../mwworld/player.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -387,8 +388,11 @@ namespace MWMechanics mFallHeight += height; } - float CreatureStats::land() + float CreatureStats::land(bool isPlayer) { + if (isPlayer) + MWBase::Environment::get().getWorld()->getPlayer().setJumping(false); + float height = mFallHeight; mFallHeight = 0; return height; diff --git a/apps/openmw/mwmechanics/creaturestats.hpp b/apps/openmw/mwmechanics/creaturestats.hpp index 057a6f602..503ac7d68 100644 --- a/apps/openmw/mwmechanics/creaturestats.hpp +++ b/apps/openmw/mwmechanics/creaturestats.hpp @@ -95,7 +95,7 @@ namespace MWMechanics /// Reset the fall height /// @return total fall height - float land(); + float land(bool isPlayer=false); const AttributeValue & getAttribute(int index) const; diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 90668914f..90d25ee3e 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -1394,6 +1394,7 @@ namespace MWPhysics mStandingCollisions.clear(); } + const MWWorld::Ptr player = MWMechanics::getPlayer(); const MWBase::World *world = MWBase::Environment::get().getWorld(); PtrVelocityList::iterator iter = mMovementQueue.begin(); for(;iter != mMovementQueue.end();++iter) @@ -1451,7 +1452,7 @@ namespace MWPhysics MWMechanics::CreatureStats& stats = iter->first.getClass().getCreatureStats(iter->first); if ((wasOnGround && physicActor->getOnGround()) || flying || world->isSwimming(iter->first) || slowFall < 1) - stats.land(); + stats.land(iter->first == player); else if (heightDiff < 0) stats.addToFallHeight(-heightDiff); diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index 8d592f29c..7250e9fcf 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -107,8 +107,7 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime) { MWBase::World* world = MWBase::Environment::get().getWorld(); - MWWorld::Ptr player = world->getPlayerPtr(); - runtime.push (!world->isOnGround(player) && !world->isFlying(player)); + runtime.push (world->getPlayer().getJumping()); } }; diff --git a/apps/openmw/mwworld/actionteleport.cpp b/apps/openmw/mwworld/actionteleport.cpp index 93705f005..f54edc8cb 100644 --- a/apps/openmw/mwworld/actionteleport.cpp +++ b/apps/openmw/mwworld/actionteleport.cpp @@ -36,7 +36,7 @@ namespace MWWorld void ActionTeleport::teleport(const Ptr &actor) { MWBase::World* world = MWBase::Environment::get().getWorld(); - actor.getClass().getCreatureStats(actor).land(); + actor.getClass().getCreatureStats(actor).land(actor == world->getPlayerPtr()); if(actor == world->getPlayerPtr()) { world->getPlayer().setTeleported(true); diff --git a/apps/openmw/mwworld/player.cpp b/apps/openmw/mwworld/player.cpp index 389f59983..49b7dd8bb 100644 --- a/apps/openmw/mwworld/player.cpp +++ b/apps/openmw/mwworld/player.cpp @@ -36,7 +36,8 @@ namespace MWWorld mTeleported(false), mCurrentCrimeId(-1), mPaidCrimeId(-1), - mAttackingOrSpell(false) + mAttackingOrSpell(false), + mJumping(false) { ESM::CellRef cellRef; cellRef.blank(); @@ -255,6 +256,16 @@ namespace MWWorld return mAttackingOrSpell; } + void Player::setJumping(bool jumping) + { + mJumping = jumping; + } + + bool Player::getJumping() const + { + return mJumping; + } + bool Player::isInCombat() { return MWBase::Environment::get().getMechanicsManager()->getActorsFighting(getPlayer()).size() != 0; } @@ -286,6 +297,7 @@ namespace MWWorld mForwardBackward = 0; mTeleported = false; mAttackingOrSpell = false; + mJumping = false; mCurrentCrimeId = -1; mPaidCrimeId = -1; mPreviousItems.clear(); diff --git a/apps/openmw/mwworld/player.hpp b/apps/openmw/mwworld/player.hpp index d4a9f6050..4b92fa396 100644 --- a/apps/openmw/mwworld/player.hpp +++ b/apps/openmw/mwworld/player.hpp @@ -56,6 +56,7 @@ namespace MWWorld MWMechanics::AttributeValue mSaveAttributes[ESM::Attribute::Length]; bool mAttackingOrSpell; + bool mJumping; public: @@ -111,6 +112,9 @@ namespace MWWorld void setAttackingOrSpell(bool attackingOrSpell); bool getAttackingOrSpell() const; + void setJumping(bool jumping); + bool getJumping() const; + ///Checks all nearby actors to see if anyone has an aipackage against you bool isInCombat(); From 09427d3f5ec05aaa00f31da272f725f1cdba6976 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sun, 16 Sep 2018 14:38:58 +0400 Subject: [PATCH 123/196] Take in account transformations of NiTriShape and NiSkinData in skinning (bug #4437) --- CHANGELOG.md | 1 + components/nifosg/nifloader.cpp | 6 +++++- components/sceneutil/riggeometry.cpp | 9 +++++++++ components/sceneutil/riggeometry.hpp | 2 ++ 4 files changed, 17 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6bea04fcb..9e8f04092 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -67,6 +67,7 @@ Bug #4431: "Lock 0" console command is a no-op Bug #4432: Guards behaviour is incorrect if they do not have AI packages Bug #4433: Guard behaviour is incorrect with Alarm = 0 + Bug #4437: Transformations for NiSkinInstance are ignored Bug #4451: Script fails to compile when using "Begin, [ScriptName]" syntax Bug #4452: Default terrain texture bleeds through texture transitions Bug #4453: Quick keys behaviour is invalid for equipment diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 3198e995c..81898e477 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -1082,7 +1082,10 @@ namespace NifOsg // Assign bone weights osg::ref_ptr map (new SceneUtil::RigGeometry::InfluenceMap); + // We should take in account transformation of NiTriShape and NiSkinData const Nif::NiSkinData *data = skin->data.getPtr(); + osg::Matrixf shapeTransforms = triShape->trafo.toMatrix() * data->trafo.toMatrix(); + const Nif::NodeList &bones = skin->bones; for(size_t i = 0;i < bones.length();i++) { @@ -1096,11 +1099,12 @@ namespace NifOsg influence.mWeights.insert(indexWeight); } influence.mInvBindMatrix = data->bones[i].trafo.toMatrix(); - influence.mBoundSphere = osg::BoundingSpheref(data->bones[i].boundSphereCenter, data->bones[i].boundSphereRadius); + influence.mBoundSphere = osg::BoundingSpheref(shapeTransforms * data->bones[i].boundSphereCenter, data->bones[i].boundSphereRadius); map->mMap.insert(std::make_pair(boneName, influence)); } rig->setInfluenceMap(map); + rig->setRigTransforms(*&shapeTransforms); parentNode->addChild(rig); } diff --git a/components/sceneutil/riggeometry.cpp b/components/sceneutil/riggeometry.cpp index c409bcd5c..94e4a3b3e 100644 --- a/components/sceneutil/riggeometry.cpp +++ b/components/sceneutil/riggeometry.cpp @@ -49,6 +49,7 @@ RigGeometry::RigGeometry(const RigGeometry ©, const osg::CopyOp ©op) : Drawable(copy, copyop) , mSkeleton(NULL) , mInfluenceMap(copy.mInfluenceMap) + , mRigTransforms(copy.mRigTransforms) , mLastFrameNumber(0) , mBoundsFirstFrame(true) { @@ -214,6 +215,9 @@ void RigGeometry::cull(osg::NodeVisitor* nv) if (mGeomToSkelMatrix) resultMat *= (*mGeomToSkelMatrix); + if (!mRigTransforms.isIdentity()) + resultMat *= mRigTransforms; + for (auto &vertex : pair.second) { (*positionDst)[vertex] = resultMat.preMult((*positionSrc)[vertex]); @@ -309,6 +313,11 @@ void RigGeometry::setInfluenceMap(osg::ref_ptr influenceMap) mInfluenceMap = influenceMap; } +void RigGeometry::setRigTransforms(osg::Matrixf& transform) +{ + mRigTransforms = transform; +} + void RigGeometry::accept(osg::NodeVisitor &nv) { if (!nv.validNodeMask(*this)) diff --git a/components/sceneutil/riggeometry.hpp b/components/sceneutil/riggeometry.hpp index 60b3edc9d..723455234 100644 --- a/components/sceneutil/riggeometry.hpp +++ b/components/sceneutil/riggeometry.hpp @@ -40,6 +40,7 @@ namespace SceneUtil }; void setInfluenceMap(osg::ref_ptr influenceMap); + void setRigTransforms(osg::Matrixf& transform); /// Initialize this geometry from the source geometry. /// @note The source geometry will not be modified. @@ -65,6 +66,7 @@ namespace SceneUtil osg::ref_ptr mGeomToSkelMatrix; osg::ref_ptr mInfluenceMap; + osg::Matrixf mRigTransforms; typedef std::pair BoneBindMatrixPair; From 95aa05e41be646c7ce556789f4c75619cfcfa6b6 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Sun, 16 Sep 2018 16:47:33 +0300 Subject: [PATCH 124/196] Tweaks to script parser messages and pathgrid warnings --- apps/opencs/model/tools/pathgridcheck.cpp | 18 ++++++++---------- apps/opencs/model/tools/scriptcheck.cpp | 2 +- components/compiler/declarationparser.cpp | 2 +- components/compiler/exprparser.cpp | 8 ++++---- components/compiler/junkparser.cpp | 4 ++-- components/compiler/lineparser.cpp | 18 +++++++++--------- 6 files changed, 25 insertions(+), 27 deletions(-) diff --git a/apps/opencs/model/tools/pathgridcheck.cpp b/apps/opencs/model/tools/pathgridcheck.cpp index 88750ad7f..febb79c64 100644 --- a/apps/opencs/model/tools/pathgridcheck.cpp +++ b/apps/opencs/model/tools/pathgridcheck.cpp @@ -56,8 +56,7 @@ void CSMTools::PathgridCheckStage::perform (int stage, CSMDoc::Messages& message if (pointList[pathgrid.mEdges[i].mV0].mOtherIndex[j] == pathgrid.mEdges[i].mV1) { std::ostringstream ss; - ss << "Duplicate edge between points" - << pathgrid.mEdges[i].mV0 << " and " << pathgrid.mEdges[i].mV1; + ss << "Duplicate edge between points #" << pathgrid.mEdges[i].mV0 << " and #" << pathgrid.mEdges[i].mV1; messages.add (id, ss.str(), "", CSMDoc::Message::Severity_Error); break; } @@ -70,7 +69,7 @@ void CSMTools::PathgridCheckStage::perform (int stage, CSMDoc::Messages& message else { std::ostringstream ss; - ss << "An edge is connected to a non-existent point " << pathgrid.mEdges[i].mV0; + ss << "An edge is connected to a non-existent point #" << pathgrid.mEdges[i].mV0; messages.add (id, ss.str(), "", CSMDoc::Message::Severity_Error); } } @@ -93,7 +92,7 @@ void CSMTools::PathgridCheckStage::perform (int stage, CSMDoc::Messages& message if (!foundReverse) { std::ostringstream ss; - ss << "Missing edge between points " << i << " and " << pointList[i].mOtherIndex[j]; + ss << "Missing edge between points #" << i << " and #" << pointList[i].mOtherIndex[j]; messages.add (id, ss.str(), "", CSMDoc::Message::Severity_Error); } } @@ -110,7 +109,7 @@ void CSMTools::PathgridCheckStage::perform (int stage, CSMDoc::Messages& message if (it == duplList.end()) { std::ostringstream ss; - ss << "Point " << i << " duplicates point " << j + ss << "Point #" << i << " duplicates point #" << j << " (" << pathgrid.mPoints[i].mX << ", " << pathgrid.mPoints[i].mY << ", " << pathgrid.mPoints[i].mZ << ")"; messages.add (id, ss.str(), "", CSMDoc::Message::Severity_Warning); @@ -127,11 +126,10 @@ void CSMTools::PathgridCheckStage::perform (int stage, CSMDoc::Messages& message if (pointList[i].mConnectionNum == 0) { std::ostringstream ss; - ss << "Point " << i << " (" - << pathgrid.mPoints[i].mX << ", " - << pathgrid.mPoints[i].mY << ", " - << pathgrid.mPoints[i].mZ << ") " - << "is disconnected from other points"; + ss << "Point #" << i << " (" + << pathgrid.mPoints[i].mX << ", " + << pathgrid.mPoints[i].mY << ", " + << pathgrid.mPoints[i].mZ << ") is disconnected from other points"; messages.add (id, ss.str(), "", CSMDoc::Message::Severity_Warning); } } diff --git a/apps/opencs/model/tools/scriptcheck.cpp b/apps/opencs/model/tools/scriptcheck.cpp index e62f9eb88..d3d9d1503 100644 --- a/apps/opencs/model/tools/scriptcheck.cpp +++ b/apps/opencs/model/tools/scriptcheck.cpp @@ -30,7 +30,7 @@ void CSMTools::ScriptCheckStage::report (const std::string& message, const Compi CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Script, mId); - stream << "Line " << loc.mLine << ", column " << loc.mColumn << " (" << loc.mLiteral << "): " << message; + stream << "line " << loc.mLine << ", column " << loc.mColumn << ": " << message << " (" << loc.mLiteral << ")"; std::ostringstream hintStream; diff --git a/components/compiler/declarationparser.cpp b/components/compiler/declarationparser.cpp index ffac252d5..e85c8c3ec 100644 --- a/components/compiler/declarationparser.cpp +++ b/components/compiler/declarationparser.cpp @@ -24,7 +24,7 @@ bool Compiler::DeclarationParser::parseName (const std::string& name, const Toke if (type!=' ') { /// \todo add option to make re-declared local variables an error - getErrorHandler().warning ("can't re-declare local variable (ignoring declaration)", + getErrorHandler().warning ("ignoring local variable re-declaration", loc); mState = State_End; diff --git a/components/compiler/exprparser.cpp b/components/compiler/exprparser.cpp index 7cb0abfd1..6b849ec3a 100644 --- a/components/compiler/exprparser.cpp +++ b/components/compiler/exprparser.cpp @@ -422,7 +422,7 @@ namespace Compiler { if (!hasExplicit) { - getErrorHandler().warning ("stray explicit reference (ignoring it)", loc); + getErrorHandler().warning ("ignoring stray explicit reference", loc); mExplicit.clear(); } @@ -791,7 +791,7 @@ namespace Compiler ++optionalCount; } else - getErrorHandler().warning ("Ignoring extra argument", + getErrorHandler().warning ("ignoring extra argument", stringParser.getTokenLoc()); } else if (*iter=='X') @@ -805,7 +805,7 @@ namespace Compiler if (parser.isEmpty()) break; else - getErrorHandler().warning("Ignoring extra argument", parser.getTokenLoc()); + getErrorHandler().warning("ignoring extra argument", parser.getTokenLoc()); } else if (*iter=='z') { @@ -817,7 +817,7 @@ namespace Compiler if (discardParser.isEmpty()) break; else - getErrorHandler().warning("Ignoring extra argument", discardParser.getTokenLoc()); + getErrorHandler().warning("ignoring extra argument", discardParser.getTokenLoc()); } else if (*iter=='j') { diff --git a/components/compiler/junkparser.cpp b/components/compiler/junkparser.cpp index 7608e9bab..5910cca43 100644 --- a/components/compiler/junkparser.cpp +++ b/components/compiler/junkparser.cpp @@ -29,7 +29,7 @@ bool Compiler::JunkParser::parseName (const std::string& name, const TokenLoc& l bool Compiler::JunkParser::parseKeyword (int keyword, const TokenLoc& loc, Scanner& scanner) { if (keyword==mIgnoreKeyword) - reportWarning ("found junk (ignoring it)", loc); + reportWarning ("ignoring found junk", loc); else scanner.putbackKeyword (keyword, loc); @@ -39,7 +39,7 @@ bool Compiler::JunkParser::parseKeyword (int keyword, const TokenLoc& loc, Scann bool Compiler::JunkParser::parseSpecial (int code, const TokenLoc& loc, Scanner& scanner) { if (code==Scanner::S_member) - reportWarning ("found junk (ignoring it)", loc); + reportWarning ("ignoring found junk", loc); else scanner.putbackSpecial (code, loc); diff --git a/components/compiler/lineparser.cpp b/components/compiler/lineparser.cpp index c2c1dff9b..3f9d2e790 100644 --- a/components/compiler/lineparser.cpp +++ b/components/compiler/lineparser.cpp @@ -88,7 +88,7 @@ namespace Compiler { if (mState==PotentialEndState) { - getErrorHandler().warning ("stray string argument (ignoring it)", loc); + getErrorHandler().warning ("ignoring stray string argument", loc); mState = EndState; return true; } @@ -233,7 +233,7 @@ namespace Compiler if (mState==SetPotentialMemberVarState && keyword==Scanner::K_to) { - getErrorHandler().warning ("unknown variable (ignoring set instruction)", loc); + getErrorHandler().warning ("unknown variable, ignoring set instruction", loc); SkipParser skip (getErrorHandler(), getContext()); scanner.scan (skip); return false; @@ -286,7 +286,7 @@ namespace Compiler { if (!hasExplicit && mState==ExplicitState) { - getErrorHandler().warning ("stray explicit reference (ignoring it)", loc); + getErrorHandler().warning ("ignoring stray explicit reference", loc); mExplicit.clear(); } @@ -344,7 +344,7 @@ namespace Compiler { if (!hasExplicit && !mExplicit.empty()) { - getErrorHandler().warning ("stray explicit reference (ignoring it)", loc); + getErrorHandler().warning ("ignoring stray explicit reference", loc); mExplicit.clear(); } @@ -360,7 +360,7 @@ namespace Compiler if (mState==ExplicitState) { // drop stray explicit reference - getErrorHandler().warning ("stray explicit reference (ignoring it)", loc); + getErrorHandler().warning ("ignoring stray explicit reference", loc); mState = BeginState; mExplicit.clear(); } @@ -412,19 +412,19 @@ namespace Compiler case Scanner::K_else: - getErrorHandler().warning ("stray else (ignoring it)", loc); + getErrorHandler().warning ("ignoring stray else", loc); mState = EndState; return true; case Scanner::K_endif: - getErrorHandler().warning ("stray endif (ignoring it)", loc); + getErrorHandler().warning ("ignoring stray endif", loc); mState = EndState; return true; case Scanner::K_begin: - getErrorHandler().warning ("stray begin (ignoring it)", loc); + getErrorHandler().warning ("ignoring stray begin", loc); mState = EndState; return true; } @@ -491,7 +491,7 @@ namespace Compiler { if (mState==EndState && code==Scanner::S_open) { - getErrorHandler().warning ("stray '[' or '(' at the end of the line (ignoring it)", + getErrorHandler().warning ("ignoring stray '[' or '(' at the end of the line", loc); return true; } From 2f054cc7a8f1f2c8196522419cb32a985f4ad653 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Sun, 16 Sep 2018 17:09:47 +0300 Subject: [PATCH 125/196] Update changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6bea04fcb..af29a67e5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -121,6 +121,7 @@ Bug #4628: NPC record reputation, disposition and faction rank should have unsigned char type Bug #4633: Sneaking stance affects speed even if the actor is not able to crouch Feature #912: Editor: Add missing icons to UniversalId tables + Feature #1617: Editor: Enchantment effect record verifier Feature #1645: Casting effects from objects Feature #2606: Editor: Implemented (optional) case sensitive global search Feature #3083: Play animation when NPC is casting spell via script @@ -155,6 +156,7 @@ Task #4606: Support Rapture3D's OpenAL driver Task #4613: Incomplete type errors when compiling with g++ on OSX 10.9 Task #4621: Optimize combat AI + Task #4643: Revise editor record verifying functionality 0.44.0 ------ From 2961f0d8109bb47d5ce3434988b0dcc97637f9b1 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sun, 16 Sep 2018 20:47:51 +0400 Subject: [PATCH 126/196] Allow to use the %Name for creatures (bug #4644) --- CHANGELOG.md | 1 + apps/openmw/mwscript/interpretercontext.cpp | 13 ++++++++++--- apps/openmw/mwscript/interpretercontext.hpp | 2 +- components/interpreter/context.hpp | 2 +- components/interpreter/defines.cpp | 2 +- 5 files changed, 14 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6bea04fcb..f37c5c4c2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -120,6 +120,7 @@ Bug #4622: Recharging enchanted items with Soul Gems does not award experience if it fails Bug #4628: NPC record reputation, disposition and faction rank should have unsigned char type Bug #4633: Sneaking stance affects speed even if the actor is not able to crouch + Bug #4644: %Name should be available for all actors, not just for NPCs Feature #912: Editor: Add missing icons to UniversalId tables Feature #1645: Casting effects from objects Feature #2606: Editor: Implemented (optional) case sensitive global search diff --git a/apps/openmw/mwscript/interpretercontext.cpp b/apps/openmw/mwscript/interpretercontext.cpp index f4e729da1..07b7a3bff 100644 --- a/apps/openmw/mwscript/interpretercontext.cpp +++ b/apps/openmw/mwscript/interpretercontext.cpp @@ -288,10 +288,17 @@ namespace MWScript return "None"; } - std::string InterpreterContext::getNPCName() const + std::string InterpreterContext::getActorName() const { - ESM::NPC npc = *getReferenceImp().get()->mBase; - return npc.mName; + const MWWorld::Ptr& ptr = getReferenceImp(); + if (ptr.getClass().isNpc()) + { + const ESM::NPC* npc = ptr.get()->mBase; + return npc->mName; + } + + const ESM::Creature* creature = ptr.get()->mBase; + return creature->mName; } std::string InterpreterContext::getNPCRace() const diff --git a/apps/openmw/mwscript/interpretercontext.hpp b/apps/openmw/mwscript/interpretercontext.hpp index ac8e1833b..5f1f4f7ab 100644 --- a/apps/openmw/mwscript/interpretercontext.hpp +++ b/apps/openmw/mwscript/interpretercontext.hpp @@ -93,7 +93,7 @@ namespace MWScript virtual std::string getActionBinding(const std::string& action) const; - virtual std::string getNPCName() const; + virtual std::string getActorName() const; virtual std::string getNPCRace() const; diff --git a/components/interpreter/context.hpp b/components/interpreter/context.hpp index 881687366..4c320879e 100644 --- a/components/interpreter/context.hpp +++ b/components/interpreter/context.hpp @@ -55,7 +55,7 @@ namespace Interpreter virtual std::string getActionBinding(const std::string& action) const = 0; - virtual std::string getNPCName() const = 0; + virtual std::string getActorName() const = 0; virtual std::string getNPCRace() const = 0; diff --git a/components/interpreter/defines.cpp b/components/interpreter/defines.cpp index 3c6226d9c..0ceed80d5 100644 --- a/components/interpreter/defines.cpp +++ b/components/interpreter/defines.cpp @@ -138,7 +138,7 @@ namespace Interpreter{ retval << context.getNPCRace(); } else if((found = check(temp, "name", &i, &start))){ - retval << context.getNPCName(); + retval << context.getActorName(); } } else { // In messagebox or book, not dialogue From 9c8fc0557a492b80dec644b07a9b1af101622fea Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Mon, 17 Sep 2018 13:35:22 +0400 Subject: [PATCH 127/196] Fix MSVC warning about possibly uninitialized movestate variable --- apps/openmw/mwmechanics/character.cpp | 47 ++++++++++++++------------- 1 file changed, 24 insertions(+), 23 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 123f7bf59..85e55ec38 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -415,37 +415,38 @@ void CharacterController::refreshJumpAnims(const WeaponInfo* weap, JumpingState void CharacterController::refreshMovementAnims(const WeaponInfo* weap, CharacterState movement, CharacterState& idle, bool force) { + if (movement == mMovementState && idle == mIdleState && !force) + return; + std::string movementAnimName; MWRender::Animation::BlendMask movemask; const StateInfo *movestate; - if(force || movement != mMovementState || idle != mIdleState) + + movemask = MWRender::Animation::BlendMask_All; + movestate = std::find_if(sMovementList, sMovementListEnd, FindCharState(movement)); + if(movestate != sMovementListEnd) { - movemask = MWRender::Animation::BlendMask_All; - movestate = std::find_if(sMovementList, sMovementListEnd, FindCharState(movement)); - if(movestate != sMovementListEnd) + movementAnimName = movestate->groupname; + if(weap != sWeaponTypeListEnd && movementAnimName.find("swim") == std::string::npos) { - movementAnimName = movestate->groupname; - if(weap != sWeaponTypeListEnd && movementAnimName.find("swim") == std::string::npos) + if (mWeaponType == WeapType_Spell && (movement == CharState_TurnLeft || movement == CharState_TurnRight)) // Spellcasting stance turning is a special case + movementAnimName = weap->shortgroup + movementAnimName; + else + movementAnimName += weap->shortgroup; + + if(!mAnimation->hasAnimation(movementAnimName)) { - if (mWeaponType == WeapType_Spell && (movement == CharState_TurnLeft || movement == CharState_TurnRight)) // Spellcasting stance turning is a special case - movementAnimName = weap->shortgroup + movementAnimName; - else - movementAnimName += weap->shortgroup; + movemask = MWRender::Animation::BlendMask_LowerBody; + movementAnimName = movestate->groupname; - if(!mAnimation->hasAnimation(movementAnimName)) - { - movemask = MWRender::Animation::BlendMask_LowerBody; - movementAnimName = movestate->groupname; + // Since we apply movement only for lower body, do not reset idle animations. + // For upper body there will be idle animation. + if (idle == CharState_None) + idle = CharState_Idle; - // Since we apply movement only for lower body, do not reset idle animations. - // For upper body there will be idle animation. - if (idle == CharState_None) - idle = CharState_Idle; - - // For crossbow animations use 1h ones as fallback - if (mWeaponType == WeapType_Crossbow) - movementAnimName += "1h"; - } + // For crossbow animations use 1h ones as fallback + if (mWeaponType == WeapType_Crossbow) + movementAnimName += "1h"; } } } From 70ed8fd1a97b93f360cb841cd1f276da0f632c42 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Mon, 17 Sep 2018 14:52:43 +0400 Subject: [PATCH 128/196] Use constants instead of widely used magic numbers (task #4645) --- CHANGELOG.md | 1 + apps/essimporter/converter.cpp | 10 ++++--- apps/essimporter/convertplayer.cpp | 6 ++--- apps/essimporter/importer.cpp | 7 ++--- apps/opencs/model/world/cellcoordinates.cpp | 6 ++--- apps/opencs/model/world/commands.cpp | 6 ++--- apps/opencs/view/render/cellarrow.cpp | 4 ++- apps/opencs/view/render/cellmarker.cpp | 4 ++- apps/opencs/view/render/instancemode.cpp | 4 +-- apps/opencs/view/render/object.cpp | 6 ++--- .../view/render/pagedworldspacewidget.cpp | 20 ++++++-------- apps/openmw/mwclass/door.cpp | 4 +-- apps/openmw/mwclass/npc.cpp | 3 ++- apps/openmw/mwclass/weapon.cpp | 5 ++-- apps/openmw/mwgui/mapwindow.cpp | 2 +- apps/openmw/mwgui/race.cpp | 2 +- apps/openmw/mwmechanics/aiavoiddoor.cpp | 6 ++--- apps/openmw/mwmechanics/aiwander.cpp | 3 +-- apps/openmw/mwphysics/physicssystem.cpp | 3 ++- apps/openmw/mwrender/globalmap.cpp | 4 +-- apps/openmw/mwrender/localmap.cpp | 3 ++- apps/openmw/mwrender/water.cpp | 7 +++-- apps/openmw/mwrender/water.hpp | 2 -- apps/openmw/mwsound/openal_output.cpp | 14 ++++------ apps/openmw/mwworld/projectilemanager.cpp | 4 ++- apps/openmw/mwworld/scene.cpp | 4 +-- apps/openmw/mwworld/worldimp.cpp | 17 ++++++------ components/CMakeLists.txt | 2 +- components/esm/loadland.hpp | 4 ++- components/esmterrain/storage.cpp | 22 +++++++-------- components/misc/constants.hpp | 27 +++++++++++++++++++ components/terrain/quadtreeworld.cpp | 4 ++- 32 files changed, 123 insertions(+), 93 deletions(-) create mode 100644 components/misc/constants.hpp diff --git a/CHANGELOG.md b/CHANGELOG.md index 1fb9837bd..9e2a71341 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -162,6 +162,7 @@ Task #4613: Incomplete type errors when compiling with g++ on OSX 10.9 Task #4621: Optimize combat AI Task #4643: Revise editor record verifying functionality + Task #4645: Use constants instead of widely used magic numbers 0.44.0 ------ diff --git a/apps/essimporter/converter.cpp b/apps/essimporter/converter.cpp index 2473daf95..900fbb05c 100644 --- a/apps/essimporter/converter.cpp +++ b/apps/essimporter/converter.cpp @@ -8,6 +8,8 @@ #include #include +#include + #include "convertcrec.hpp" #include "convertcntc.hpp" #include "convertscri.hpp" @@ -288,12 +290,12 @@ namespace ESSImport notepos[1] += 31.f; notepos[0] += 0.5; notepos[1] += 0.5; - notepos[0] = 8192 * notepos[0] / 32.f; - notepos[1] = 8192 * notepos[1] / 32.f; + notepos[0] = Constants::CellSizeInUnits * notepos[0] / 32.f; + notepos[1] = Constants::CellSizeInUnits * notepos[1] / 32.f; if (cell.isExterior()) { - notepos[0] += 8192 * cell.mData.mX; - notepos[1] += 8192 * cell.mData.mY; + notepos[0] += Constants::CellSizeInUnits * cell.mData.mX; + notepos[1] += Constants::CellSizeInUnits * cell.mData.mY; } // TODO: what encoding is this in? std::string note = esm.getHNString("MPNT"); diff --git a/apps/essimporter/convertplayer.cpp b/apps/essimporter/convertplayer.cpp index 4a4a9a573..5e2da2b03 100644 --- a/apps/essimporter/convertplayer.cpp +++ b/apps/essimporter/convertplayer.cpp @@ -1,5 +1,6 @@ #include "convertplayer.hpp" +#include #include namespace ESSImport @@ -78,9 +79,8 @@ namespace ESSImport if (pcdt.mHasENAM) { - const int cellSize = 8192; - out.mLastKnownExteriorPosition[0] = (pcdt.mENAM.mCellX + 0.5f) * cellSize; - out.mLastKnownExteriorPosition[1] = (pcdt.mENAM.mCellY + 0.5f) * cellSize; + out.mLastKnownExteriorPosition[0] = (pcdt.mENAM.mCellX + 0.5f) * Constants::CellSizeInUnits; + out.mLastKnownExteriorPosition[1] = (pcdt.mENAM.mCellY + 0.5f) * Constants::CellSizeInUnits; out.mLastKnownExteriorPosition[2] = 0.0f; } } diff --git a/apps/essimporter/importer.cpp b/apps/essimporter/importer.cpp index 4538d4e63..a54c13334 100644 --- a/apps/essimporter/importer.cpp +++ b/apps/essimporter/importer.cpp @@ -25,6 +25,8 @@ #include #include +#include + #include #include "importercontext.hpp" @@ -413,9 +415,8 @@ namespace ESSImport if (context.mPlayer.mCellId.mPaged) { // exterior cell -> determine cell coordinates based on position - const int cellSize = 8192; - int cellX = static_cast(std::floor(context.mPlayer.mObject.mPosition.pos[0]/cellSize)); - int cellY = static_cast(std::floor(context.mPlayer.mObject.mPosition.pos[1] / cellSize)); + int cellX = static_cast(std::floor(context.mPlayer.mObject.mPosition.pos[0] / Constants::CellSizeInUnits)); + int cellY = static_cast(std::floor(context.mPlayer.mObject.mPosition.pos[1] / Constants::CellSizeInUnits)); context.mPlayer.mCellId.mIndex.mX = cellX; context.mPlayer.mCellId.mIndex.mY = cellY; } diff --git a/apps/opencs/model/world/cellcoordinates.cpp b/apps/opencs/model/world/cellcoordinates.cpp index abb3bc82e..dbe90b906 100644 --- a/apps/opencs/model/world/cellcoordinates.cpp +++ b/apps/opencs/model/world/cellcoordinates.cpp @@ -5,6 +5,8 @@ #include #include +#include + CSMWorld::CellCoordinates::CellCoordinates() : mX (0), mY (0) {} CSMWorld::CellCoordinates::CellCoordinates (int x, int y) : mX (x), mY (y) {} @@ -61,9 +63,7 @@ std::pair CSMWorld::CellCoordinates::fromId ( std::pair CSMWorld::CellCoordinates::coordinatesToCellIndex (float x, float y) { - const int cellSize = 8192; - - return std::make_pair (std::floor (x/cellSize), std::floor (y/cellSize)); + return std::make_pair (std::floor (x / Constants::CellSizeInUnits), std::floor (y / Constants::CellSizeInUnits)); } bool CSMWorld::operator== (const CellCoordinates& left, const CellCoordinates& right) diff --git a/apps/opencs/model/world/commands.cpp b/apps/opencs/model/world/commands.cpp index 79900c6c4..4133b2050 100644 --- a/apps/opencs/model/world/commands.cpp +++ b/apps/opencs/model/world/commands.cpp @@ -445,16 +445,14 @@ void CSMWorld::UpdateCellCommand::redo() int cellColumn = mModel.searchColumnIndex (Columns::ColumnId_Cell); mIndex = mModel.index (mRow, cellColumn); - const int cellSize = 8192; - QModelIndex xIndex = mModel.index ( mRow, mModel.findColumnIndex (Columns::ColumnId_PositionXPos)); QModelIndex yIndex = mModel.index ( mRow, mModel.findColumnIndex (Columns::ColumnId_PositionYPos)); - int x = std::floor (mModel.data (xIndex).toFloat() / cellSize); - int y = std::floor (mModel.data (yIndex).toFloat() / cellSize); + int x = std::floor (mModel.data (xIndex).toFloat() / Constants::CellSizeInUnits); + int y = std::floor (mModel.data (yIndex).toFloat() / Constants::CellSizeInUnits); std::ostringstream stream; diff --git a/apps/opencs/view/render/cellarrow.cpp b/apps/opencs/view/render/cellarrow.cpp index b8c89c83d..b6fee1545 100644 --- a/apps/opencs/view/render/cellarrow.cpp +++ b/apps/opencs/view/render/cellarrow.cpp @@ -10,6 +10,8 @@ #include "../../model/prefs/state.hpp" #include "../../model/prefs/shortcutmanager.hpp" +#include + #include "mask.hpp" CSVRender::CellArrowTag::CellArrowTag (CellArrow *arrow) @@ -57,7 +59,7 @@ QString CSVRender::CellArrowTag::getToolTip (bool hideBasics) const void CSVRender::CellArrow::adjustTransform() { // position - const int cellSize = 8192; + const int cellSize = Constants::CellSizeInUnits; const int offset = cellSize / 2 + 800; int x = mCoordinates.getX()*cellSize + cellSize/2; diff --git a/apps/opencs/view/render/cellmarker.cpp b/apps/opencs/view/render/cellmarker.cpp index d0521a7b7..3de96ab02 100644 --- a/apps/opencs/view/render/cellmarker.cpp +++ b/apps/opencs/view/render/cellmarker.cpp @@ -5,6 +5,8 @@ #include #include +#include + CSVRender::CellMarkerTag::CellMarkerTag(CellMarker *marker) : TagBase(Mask_CellMarker), mMarker(marker) {} @@ -49,7 +51,7 @@ void CSVRender::CellMarker::buildMarker() void CSVRender::CellMarker::positionMarker() { - const int cellSize = 8192; + const int cellSize = Constants::CellSizeInUnits; const int markerHeight = 0; // Move marker to center of cell. diff --git a/apps/opencs/view/render/instancemode.cpp b/apps/opencs/view/render/instancemode.cpp index 4b14e29bf..1cf8a5698 100644 --- a/apps/opencs/view/render/instancemode.cpp +++ b/apps/opencs/view/render/instancemode.cpp @@ -29,15 +29,13 @@ int CSVRender::InstanceMode::getSubModeFromId (const std::string& id) const osg::Vec3f CSVRender::InstanceMode::quatToEuler(const osg::Quat& rot) const { - const float Pi = 3.14159265f; - float x, y, z; float test = 2 * (rot.w() * rot.y() + rot.x() * rot.z()); if (std::abs(test) >= 1.f) { x = atan2(rot.x(), rot.w()); - y = (test > 0) ? (Pi / 2) : (-Pi / 2); + y = (test > 0) ? (osg::PI / 2) : (-osg::PI / 2); z = 0; } else diff --git a/apps/opencs/view/render/object.cpp b/apps/opencs/view/render/object.cpp index 8301f4e9e..2b1e3adde 100644 --- a/apps/opencs/view/render/object.cpp +++ b/apps/opencs/view/render/object.cpp @@ -313,20 +313,18 @@ osg::ref_ptr CSVRender::Object::makeMoveOrScaleMarker (int axis) osg::ref_ptr CSVRender::Object::makeRotateMarker (int axis) { - const float Pi = 3.14159265f; - const float InnerRadius = std::max(MarkerShaftBaseLength, mBaseNode->getBound().radius()); const float OuterRadius = InnerRadius + MarkerShaftWidth; const float SegmentDistance = 100.f; - const size_t SegmentCount = std::min(64, std::max(24, (int)(OuterRadius * 2 * Pi / SegmentDistance))); + const size_t SegmentCount = std::min(64, std::max(24, (int)(OuterRadius * 2 * osg::PI / SegmentDistance))); const size_t VerticesPerSegment = 4; const size_t IndicesPerSegment = 24; const size_t VertexCount = SegmentCount * VerticesPerSegment; const size_t IndexCount = SegmentCount * IndicesPerSegment; - const float Angle = 2 * Pi / SegmentCount; + const float Angle = 2 * osg::PI / SegmentCount; const unsigned short IndexPattern[IndicesPerSegment] = { diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index 1d1a7cd17..ccea70761 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.cpp +++ b/apps/opencs/view/render/pagedworldspacewidget.cpp @@ -8,6 +8,8 @@ #include +#include + #include "../../model/prefs/shortcut.hpp" #include "../../model/world/tablemimedata.hpp" @@ -506,13 +508,11 @@ void CSVRender::PagedWorldspaceWidget::moveCellSelection (int x, int y) void CSVRender::PagedWorldspaceWidget::addCellToSceneFromCamera (int offsetX, int offsetY) { - const int CellSize = 8192; - osg::Vec3f eye, center, up; getCamera()->getViewMatrixAsLookAt(eye, center, up); - int cellX = (int)std::floor(center.x() / CellSize) + offsetX; - int cellY = (int)std::floor(center.y() / CellSize) + offsetY; + int cellX = (int)std::floor(center.x() / Constants::CellSizeInUnits) + offsetX; + int cellY = (int)std::floor(center.y() / Constants::CellSizeInUnits) + offsetY; CSMWorld::CellCoordinates cellCoordinates(cellX, cellY); @@ -738,22 +738,18 @@ void CSVRender::PagedWorldspaceWidget::selectAllWithSameParentId (int elementMas std::string CSVRender::PagedWorldspaceWidget::getCellId (const osg::Vec3f& point) const { - const int cellSize = 8192; - CSMWorld::CellCoordinates cellCoordinates ( - static_cast (std::floor (point.x()/cellSize)), - static_cast (std::floor (point.y()/cellSize))); + static_cast (std::floor (point.x() / Constants::CellSizeInUnits)), + static_cast (std::floor (point.y() / Constants::CellSizeInUnits))); return cellCoordinates.getId (mWorldspace); } CSVRender::Cell* CSVRender::PagedWorldspaceWidget::getCell(const osg::Vec3d& point) const { - const int cellSize = 8192; - CSMWorld::CellCoordinates coords( - static_cast (std::floor (point.x()/cellSize)), - static_cast (std::floor (point.y()/cellSize))); + static_cast (std::floor (point.x() / Constants::CellSizeInUnits)), + static_cast (std::floor (point.y() / Constants::CellSizeInUnits))); std::map::const_iterator searchResult = mCells.find(coords); if (searchResult != mCells.end()) diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index d738974dd..a26118029 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -213,7 +213,7 @@ namespace MWClass closeSound, 0.5f); // Doors rotate at 90 degrees per second, so start the sound at // where it would be at the current rotation. - float offset = doorRot/(3.14159265f * 0.5f); + float offset = doorRot/(osg::PI * 0.5f); action->setSoundOffset(offset); action->setSound(openSound); } @@ -221,7 +221,7 @@ namespace MWClass { MWBase::Environment::get().getSoundManager()->fadeOutSound3D(ptr, openSound, 0.5f); - float offset = 1.0f - doorRot/(3.14159265f * 0.5f); + float offset = 1.0f - doorRot/(osg::PI * 0.5f); action->setSoundOffset(std::max(offset, 0.0f)); action->setSound(closeSound); } diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 3d019ea90..4979db2fd 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -2,6 +2,7 @@ #include +#include #include #include @@ -1020,7 +1021,7 @@ namespace MWClass if(stats.getStance(MWMechanics::CreatureStats::Stance_Run)) x *= gmst.fJumpRunMultiplier->mValue.getFloat(); x *= npcdata->mNpcStats.getFatigueTerm(); - x -= -627.2f;/*gravity constant*/ + x -= -Constants::GravityConst * Constants::UnitsPerMeter; x /= 3.0f; return x; diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index 466ae4716..5e0f989a5 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -1,6 +1,7 @@ #include "weapon.hpp" #include +#include #include #include "../mwbase/environment.hpp" @@ -328,9 +329,9 @@ namespace MWClass // add reach and attack speed for melee weapon if (ref->mBase->mData.mType < 9 && Settings::Manager::getBool("show melee info", "Game")) { - // 64 game units = 1 yard = 3 ft, display value in feet + // display value in feet const float combatDistance = store.get().find("fCombatDistance")->mValue.getFloat() * ref->mBase->mData.mReach; - text += MWGui::ToolTips::getWeightString(combatDistance*3/64, "#{sRange}"); + text += MWGui::ToolTips::getWeightString(combatDistance / Constants::UnitsPerFoot, "#{sRange}"); text += " #{sFeet}"; text += MWGui::ToolTips::getPercentString(ref->mBase->mData.mSpeed, "#{sAttributeSpeed}"); diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index c1ff9510d..2c8ad0565 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -33,7 +33,7 @@ namespace { - const int cellSize = 8192; + const int cellSize = Constants::CellSizeInUnits; enum LocalMapWidgetDepth { diff --git a/apps/openmw/mwgui/race.cpp b/apps/openmw/mwgui/race.cpp index 96c0d7de4..ee058e02e 100644 --- a/apps/openmw/mwgui/race.cpp +++ b/apps/openmw/mwgui/race.cpp @@ -212,7 +212,7 @@ namespace MWGui void RaceDialog::onHeadRotate(MyGUI::ScrollBar* scroll, size_t _position) { - float angle = (float(_position) / (scroll->getScrollRange()-1) - 0.5f) * 3.14f * 2; + float angle = (float(_position) / (scroll->getScrollRange()-1) - 0.5f) * osg::PI * 2; mPreview->setAngle (angle); mCurrentAngle = angle; diff --git a/apps/openmw/mwmechanics/aiavoiddoor.cpp b/apps/openmw/mwmechanics/aiavoiddoor.cpp index bb03ff53b..e7d1ecee1 100644 --- a/apps/openmw/mwmechanics/aiavoiddoor.cpp +++ b/apps/openmw/mwmechanics/aiavoiddoor.cpp @@ -33,9 +33,9 @@ bool MWMechanics::AiAvoidDoor::execute (const MWWorld::Ptr& actor, CharacterCont float distance = x * x + y * y + z * z; if(distance < 10 * 10) { //Got stuck, didn't move if(mAdjAngle == 0) //Try going in various directions - mAdjAngle = 1.57079632679f; //pi/2 - else if (mAdjAngle == 1.57079632679f) - mAdjAngle = -1.57079632679f; + mAdjAngle = osg::PI / 2; + else if (mAdjAngle == osg::PI / 2) + mAdjAngle = -osg::PI / 2; else mAdjAngle = 0; mDuration = 1; //reset timer diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index d36c5930f..caacf8cb6 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -300,9 +300,8 @@ namespace MWMechanics bool isWaterCreature = actor.getClass().isPureWaterCreature(actor); do { // Determine a random location within radius of original position - const float pi = 3.14159265359f; const float wanderRadius = (0.2f + Misc::Rng::rollClosedProbability() * 0.8f) * wanderDistance; - const float randomDirection = Misc::Rng::rollClosedProbability() * 2.0f * pi; + const float randomDirection = Misc::Rng::rollClosedProbability() * 2.0f * osg::PI; const float destinationX = mInitialActorPosition.x() + wanderRadius * std::cos(randomDirection); const float destinationY = mInitialActorPosition.y() + wanderRadius * std::sin(randomDirection); const float destinationZ = mInitialActorPosition.z(); diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 90d25ee3e..31da729ea 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -486,7 +487,7 @@ namespace MWPhysics physicActor->setInertialForce(osg::Vec3f(0.f, 0.f, 0.f)); else { - inertia.z() += time * -627.2f; + inertia.z() -= time * Constants::GravityConst * Constants::UnitsPerMeter; if (inertia.z() < 0) inertia.z() *= slowFall; if (slowFall < 1.f) { diff --git a/apps/openmw/mwrender/globalmap.cpp b/apps/openmw/mwrender/globalmap.cpp index fae524faa..65820e577 100644 --- a/apps/openmw/mwrender/globalmap.cpp +++ b/apps/openmw/mwrender/globalmap.cpp @@ -273,9 +273,9 @@ namespace MWRender void GlobalMap::worldPosToImageSpace(float x, float z, float& imageX, float& imageY) { - imageX = float(x / 8192.f - mMinX) / (mMaxX - mMinX + 1); + imageX = float(x / float(Constants::CellSizeInUnits) - mMinX) / (mMaxX - mMinX + 1); - imageY = 1.f-float(z / 8192.f - mMinY) / (mMaxY - mMinY + 1); + imageY = 1.f-float(z / float(Constants::CellSizeInUnits) - mMinY) / (mMaxY - mMinY + 1); } void GlobalMap::cellTopLeftCornerToImageSpace(int x, int y, float& imageX, float& imageY) diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index 8ed3441de..8ea4e3991 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -71,7 +72,7 @@ namespace MWRender LocalMap::LocalMap(osg::Group* root) : mRoot(root) , mMapResolution(Settings::Manager::getInt("local map resolution", "Map")) - , mMapWorldSize(8192.f) + , mMapWorldSize(Constants::CellSizeInUnits) , mCellDistance(Settings::Manager::getInt("local map cell distance", "Map")) , mAngle(0.f) , mInterior(false) diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 52832ad87..8fd47d2c5 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -27,6 +27,8 @@ #include +#include + #include #include @@ -401,7 +403,7 @@ Water::Water(osg::Group *parent, osg::Group* sceneRoot, Resource::ResourceSystem { mSimulation.reset(new RippleSimulation(parent, resourceSystem, fallback)); - mWaterGeom = SceneUtil::createWaterGeometry(CELL_SIZE*150, 40, 900); + mWaterGeom = SceneUtil::createWaterGeometry(Constants::CellSizeInUnits*150, 40, 900); mWaterGeom->setDrawCallback(new DepthClampCallback); mWaterGeom->setNodeMask(Mask_Water); @@ -679,7 +681,8 @@ bool Water::isUnderwater(const osg::Vec3f &pos) const osg::Vec3f Water::getSceneNodeCoordinates(int gridX, int gridY) { - return osg::Vec3f(static_cast(gridX * CELL_SIZE + (CELL_SIZE / 2)), static_cast(gridY * CELL_SIZE + (CELL_SIZE / 2)), mTop); + return osg::Vec3f(static_cast(gridX * Constants::CellSizeInUnits + (Constants::CellSizeInUnits / 2)), + static_cast(gridY * Constants::CellSizeInUnits + (Constants::CellSizeInUnits / 2)), mTop); } void Water::addEmitter (const MWWorld::Ptr& ptr, float scale, float force) diff --git a/apps/openmw/mwrender/water.hpp b/apps/openmw/mwrender/water.hpp index e2413cfa0..32a7977d2 100644 --- a/apps/openmw/mwrender/water.hpp +++ b/apps/openmw/mwrender/water.hpp @@ -50,8 +50,6 @@ namespace MWRender /// Water rendering class Water { - static const int CELL_SIZE = 8192; - osg::ref_ptr mRainIntensityUniform; osg::ref_ptr mParent; diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index 833b40e38..cadcdc4ab 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -8,6 +8,7 @@ #include #include +#include #include #include @@ -34,10 +35,6 @@ namespace { -// The game uses 64 units per yard, or approximately 69.99125109 units per meter. -// Should this be defined publically somewhere? -const float UnitsPerMeter = 69.99125109f; - const int sLoudnessFPS = 20; // loudness values per second of audio ALCenum checkALCError(ALCdevice *device, const char *func, int line) @@ -818,13 +815,13 @@ bool OpenAL_Output::init(const std::string &devname, const std::string &hrtfname LoadEffect(mWaterEffect, EFX_REVERB_PRESET_UNDERWATER); } - alListenerf(AL_METERS_PER_UNIT, 1.0f / UnitsPerMeter); + alListenerf(AL_METERS_PER_UNIT, 1.0f / Constants::UnitsPerMeter); } skip_efx: alDistanceModel(AL_INVERSE_DISTANCE_CLAMPED); - // Speed of sound is in units per second. Given the default speed of sound is 343.3 (assumed + // Speed of sound is in units per second. Take the sound speed in air (assumed // meters per second), multiply by the units per meter to get the speed in u/s. - alSpeedOfSound(343.3f * UnitsPerMeter); + alSpeedOfSound(Constants::SoundSpeedInAir * Constants::UnitsPerMeter); alGetError(); mInitialized = true; @@ -1400,8 +1397,7 @@ void OpenAL_Output::updateListener(const osg::Vec3f &pos, const osg::Vec3f &atdi if(env != mListenerEnv) { - // Speed of sound in water is 1484m/s, and in air is 343.3m/s (roughly) - alSpeedOfSound(((env == Env_Underwater) ? 1484.0f : 343.3f) * UnitsPerMeter); + alSpeedOfSound(((env == Env_Underwater) ? Constants::SoundSpeedUnderwater : Constants::SoundSpeedInAir) * Constants::UnitsPerMeter); // Update active sources with the environment's direct filter if(mWaterFilter) diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index 21218fab0..4698ba011 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -10,6 +10,8 @@ #include #include +#include + #include #include @@ -460,7 +462,7 @@ namespace MWWorld { // gravity constant - must be way lower than the gravity affecting actors, since we're not // simulating aerodynamics at all - it->mVelocity -= osg::Vec3f(0, 0, 627.2f * 0.1f) * duration; + it->mVelocity -= osg::Vec3f(0, 0, Constants::GravityConst * Constants::UnitsPerMeter * 0.1f) * duration; osg::Vec3f pos(it->mNode->getPosition()); osg::Vec3f newPos = pos + it->mVelocity * duration; diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index ed6dde310..dc3d4fd30 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -345,7 +345,7 @@ namespace MWWorld getGridCenter(cellX, cellY); float centerX, centerY; MWBase::Environment::get().getWorld()->indexToPosition(cellX, cellY, centerX, centerY, true); - const float maxDistance = 8192/2 + mCellLoadingThreshold; // 1/2 cell size + threshold + const float maxDistance = Constants::CellSizeInUnits / 2 + mCellLoadingThreshold; // 1/2 cell size + threshold float distance = std::max(std::abs(centerX-pos.x()), std::abs(centerY-pos.y())); if (distance > maxDistance) { @@ -793,7 +793,7 @@ namespace MWWorld float dist = std::max(std::abs(thisCellCenterX - playerPos.x()), std::abs(thisCellCenterY - playerPos.y())); dist = std::min(dist,std::max(std::abs(thisCellCenterX - predictedPos.x()), std::abs(thisCellCenterY - predictedPos.y()))); - float loadDist = 8192/2 + 8192 - mCellLoadingThreshold + mPreloadDistance; + float loadDist = Constants::CellSizeInUnits / 2 + Constants::CellSizeInUnits - mCellLoadingThreshold + mPreloadDistance; if (dist < loadDist) preloadCell(MWBase::Environment::get().getWorld()->getExterior(cellX+dx, cellY+dy)); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index d1f274787..2afcdffc8 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -9,6 +9,7 @@ #include #include +#include #include #include @@ -260,7 +261,7 @@ namespace MWWorld if (!getPlayerPtr().isInCell()) { ESM::Position pos; - const int cellSize = 8192; + const int cellSize = Constants::CellSizeInUnits; pos.pos[0] = cellSize/2; pos.pos[1] = cellSize/2; pos.pos[2] = 0; @@ -1434,7 +1435,7 @@ namespace MWWorld void World::indexToPosition (int cellX, int cellY, float &x, float &y, bool centre) const { - const int cellSize = 8192; + const int cellSize = Constants::CellSizeInUnits; x = static_cast(cellSize * cellX); y = static_cast(cellSize * cellY); @@ -1448,10 +1449,8 @@ namespace MWWorld void World::positionToIndex (float x, float y, int &cellX, int &cellY) const { - const int cellSize = 8192; - - cellX = static_cast(std::floor(x / cellSize)); - cellY = static_cast(std::floor(y / cellSize)); + cellX = static_cast(std::floor(x / Constants::CellSizeInUnits)); + cellY = static_cast(std::floor(y / Constants::CellSizeInUnits)); } void World::queueMovement(const Ptr &ptr, const osg::Vec3f &velocity) @@ -3245,9 +3244,9 @@ namespace MWWorld float World::feetToGameUnits(float feet) { - // Looks like there is no GMST for this. This factor was determined in experiments - // with the Telekinesis effect. - return feet * 22; + // Original engine rounds size upward + static const int unitsPerFoot = ceil(Constants::UnitsPerFoot); + return feet * unitsPerFoot; } float World::getActivationDistancePlusTelekinesis() diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 8e798455f..2da7c80bf 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -85,7 +85,7 @@ add_component_dir (esmterrain ) add_component_dir (misc - utf8stream stringops resourcehelpers rng messageformatparser + constants utf8stream stringops resourcehelpers rng messageformatparser ) add_component_dir (debug diff --git a/components/esm/loadland.hpp b/components/esm/loadland.hpp index cccb472de..eaf766442 100644 --- a/components/esm/loadland.hpp +++ b/components/esm/loadland.hpp @@ -3,6 +3,8 @@ #include +#include + #include "esmcommon.hpp" namespace ESM @@ -53,7 +55,7 @@ struct Land static const int LAND_SIZE = 65; // cell terrain size in world coords - static const int REAL_SIZE = 8192; + static const int REAL_SIZE = Constants::CellSizeInUnits; // total number of vertices static const int LAND_NUM_VERTS = LAND_SIZE * LAND_SIZE; diff --git a/components/esmterrain/storage.cpp b/components/esmterrain/storage.cpp index f77e66276..0fa28cf0b 100644 --- a/components/esmterrain/storage.cpp +++ b/components/esmterrain/storage.cpp @@ -267,8 +267,8 @@ namespace ESMTerrain height = heightData->mHeights[col*ESM::Land::LAND_SIZE + row]; (*positions)[static_cast(vertX*numVerts + vertY)] - = osg::Vec3f((vertX / float(numVerts - 1) - 0.5f) * size * 8192, - (vertY / float(numVerts - 1) - 0.5f) * size * 8192, + = osg::Vec3f((vertX / float(numVerts - 1) - 0.5f) * size * Constants::CellSizeInUnits, + (vertY / float(numVerts - 1) - 0.5f) * size * Constants::CellSizeInUnits, height); if (normalData) @@ -477,8 +477,8 @@ namespace ESMTerrain float Storage::getHeightAt(const osg::Vec3f &worldPos) { - int cellX = static_cast(std::floor(worldPos.x() / 8192.f)); - int cellY = static_cast(std::floor(worldPos.y() / 8192.f)); + int cellX = static_cast(std::floor(worldPos.x() / float(Constants::CellSizeInUnits))); + int cellY = static_cast(std::floor(worldPos.y() / float(Constants::CellSizeInUnits))); osg::ref_ptr land = getLand(cellX, cellY); if (!land) @@ -491,8 +491,8 @@ namespace ESMTerrain // Mostly lifted from Ogre::Terrain::getHeightAtTerrainPosition // Normalized position in the cell - float nX = (worldPos.x() - (cellX * 8192))/8192.f; - float nY = (worldPos.y() - (cellY * 8192))/8192.f; + float nX = (worldPos.x() - (cellX * Constants::CellSizeInUnits)) / float(Constants::CellSizeInUnits); + float nY = (worldPos.y() - (cellY * Constants::CellSizeInUnits)) / float(Constants::CellSizeInUnits); // get left / bottom points (rounded down) float factor = ESM::Land::LAND_SIZE - 1.0f; @@ -524,10 +524,10 @@ namespace ESMTerrain */ // Build all 4 positions in normalized cell space, using point-sampled height - osg::Vec3f v0 (startXTS, startYTS, getVertexHeight(data, startX, startY) / 8192.f); - osg::Vec3f v1 (endXTS, startYTS, getVertexHeight(data, endX, startY) / 8192.f); - osg::Vec3f v2 (endXTS, endYTS, getVertexHeight(data, endX, endY) / 8192.f); - osg::Vec3f v3 (startXTS, endYTS, getVertexHeight(data, startX, endY) / 8192.f); + osg::Vec3f v0 (startXTS, startYTS, getVertexHeight(data, startX, startY) / float(Constants::CellSizeInUnits)); + osg::Vec3f v1 (endXTS, startYTS, getVertexHeight(data, endX, startY) / float(Constants::CellSizeInUnits)); + osg::Vec3f v2 (endXTS, endYTS, getVertexHeight(data, endX, endY) / float(Constants::CellSizeInUnits)); + osg::Vec3f v3 (startXTS, endYTS, getVertexHeight(data, startX, endY) / float(Constants::CellSizeInUnits)); // define this plane in terrain space osg::Plane plane; // FIXME: deal with differing triangle alignment @@ -555,7 +555,7 @@ namespace ESMTerrain // Solve plane equation for z return (-plane.getNormal().x() * nX -plane.getNormal().y() * nY - - plane[3]) / plane.getNormal().z() * 8192; + - plane[3]) / plane.getNormal().z() * Constants::CellSizeInUnits; } diff --git a/components/misc/constants.hpp b/components/misc/constants.hpp new file mode 100644 index 000000000..7174ae888 --- /dev/null +++ b/components/misc/constants.hpp @@ -0,0 +1,27 @@ +#ifndef OPENMW_CONSTANTS_H +#define OPENMW_CONSTANTS_H + +namespace Constants +{ + +// The game uses 64 units per yard +const float UnitsPerMeter = 69.99125109f; +const float UnitsPerFoot = 21.33333333f; + +// Sound speed in meters per second +const float SoundSpeedInAir = 343.3f; +const float SoundSpeedUnderwater = 1484.0f; + +// Gravity constant in m/sec^2 +// Note: 8.96 m/sec^2 = 9.8 yards/sec^2 +// Probaly original engine's developers just forgot +// that their engine uses yards instead of meters +// and used standart gravity value as it is +const float GravityConst = 8.96f; + +// Size of one exterior cell in game units +const int CellSizeInUnits = 8192; + +} + +#endif diff --git a/components/terrain/quadtreeworld.cpp b/components/terrain/quadtreeworld.cpp index e75deb2f7..9b9bbccd6 100644 --- a/components/terrain/quadtreeworld.cpp +++ b/components/terrain/quadtreeworld.cpp @@ -4,6 +4,8 @@ #include +#include + #include "quadtreenode.hpp" #include "storage.hpp" #include "viewdata.hpp" @@ -81,7 +83,7 @@ public: { float dist = distanceToBox(node->getBoundingBox(), eyePoint); int nativeLodLevel = Log2(static_cast(node->getSize()/mMinSize)); - int lodLevel = Log2(static_cast(dist/(8192*mMinSize))); + int lodLevel = Log2(static_cast(dist/(Constants::CellSizeInUnits*mMinSize))); return nativeLodLevel <= lodLevel; } From dda02bd69618fdf4e1d04a3e54c52c94718d7405 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Mon, 17 Sep 2018 19:56:36 +0400 Subject: [PATCH 129/196] Do not use book fonts for dialogue window --- apps/openmw/mwgui/bookpage.cpp | 25 ++++++++++--------------- apps/openmw/mwgui/bookpage.hpp | 2 +- apps/openmw/mwgui/dialogue.cpp | 10 +++++----- 3 files changed, 16 insertions(+), 21 deletions(-) diff --git a/apps/openmw/mwgui/bookpage.cpp b/apps/openmw/mwgui/bookpage.cpp index 8e264312e..c3b8935e8 100644 --- a/apps/openmw/mwgui/bookpage.cpp +++ b/apps/openmw/mwgui/bookpage.cpp @@ -264,29 +264,24 @@ struct TypesetBookImpl::Typesetter : BookTypesetter { } - Style * createStyle (const std::string& fontName, const Colour& fontColour) + Style * createStyle (const std::string& fontName, const Colour& fontColour, bool useBookFont) { - const std::string templateName = "Journalbook "; - std::string bookFont; + std::string fullFontName; if (fontName.empty()) - { - bookFont = MyGUI::FontManager::getInstance().getDefaultFont(); - bookFont = templateName + bookFont; - return createStyle(bookFont, fontColour); - } - - if (fontName.compare(0, templateName.size(), templateName) == 0) - bookFont = fontName; + fullFontName = MyGUI::FontManager::getInstance().getDefaultFont(); else - bookFont = templateName + bookFont; + fullFontName = fontName; + + if (useBookFont) + fullFontName = "Journalbook " + fullFontName; for (Styles::iterator i = mBook->mStyles.begin (); i != mBook->mStyles.end (); ++i) - if (i->match (bookFont.c_str(), fontColour, fontColour, fontColour, 0)) + if (i->match (fullFontName.c_str(), fontColour, fontColour, fontColour, 0)) return &*i; - MyGUI::IFont* font = MyGUI::FontManager::getInstance().getByName(bookFont); + MyGUI::IFont* font = MyGUI::FontManager::getInstance().getByName(fullFontName); if (!font) - throw std::runtime_error(std::string("can't find font ") + bookFont); + throw std::runtime_error(std::string("can't find font ") + fullFontName); StyleImpl & style = *mBook->mStyles.insert (mBook->mStyles.end (), StyleImpl ()); style.mFont = font; diff --git a/apps/openmw/mwgui/bookpage.hpp b/apps/openmw/mwgui/bookpage.hpp index c75f00ca4..4cf99794d 100644 --- a/apps/openmw/mwgui/bookpage.hpp +++ b/apps/openmw/mwgui/bookpage.hpp @@ -102,7 +102,7 @@ namespace MWGui static Ptr create (int pageWidth, int pageHeight); /// Create a simple text style consisting of a font and a text color. - virtual Style* createStyle (const std::string& fontName, const Colour& colour) = 0; + virtual Style* createStyle (const std::string& fontName, const Colour& colour, bool useBookFont=true) = 0; /// Create a hyper-link style with a user-defined identifier based on an /// existing style. The unique flag forces a new instance of this style diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 6aceccaff..3ac8839e2 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -137,7 +137,7 @@ namespace MWGui if (mTitle != "") { const MyGUI::Colour& headerColour = MWBase::Environment::get().getWindowManager()->getTextColours().header; - BookTypesetter::Style* title = typesetter->createStyle("", headerColour); + BookTypesetter::Style* title = typesetter->createStyle("", headerColour, false); typesetter->write(title, to_utf8_span(mTitle.c_str())); typesetter->sectionBreak(); } @@ -182,7 +182,7 @@ namespace MWGui { const TextColours& textColours = MWBase::Environment::get().getWindowManager()->getTextColours(); - BookTypesetter::Style* style = typesetter->createStyle("", textColours.normal); + BookTypesetter::Style* style = typesetter->createStyle("", textColours.normal, false); size_t formatted = 0; // points to the first character that is not laid out yet for (std::map::iterator it = hyperLinks.begin(); it != hyperLinks.end(); ++it) { @@ -223,7 +223,7 @@ namespace MWGui { const TextColours& textColours = MWBase::Environment::get().getWindowManager()->getTextColours(); - BookTypesetter::Style* style = typesetter->createStyle("", textColours.normal); + BookTypesetter::Style* style = typesetter->createStyle("", textColours.normal, false); if (topicId) @@ -239,7 +239,7 @@ namespace MWGui void Message::write(BookTypesetter::Ptr typesetter, KeywordSearchT* keywordSearch, std::map& topicLinks) const { const MyGUI::Colour& textColour = MWBase::Environment::get().getWindowManager()->getTextColours().notify; - BookTypesetter::Style* title = typesetter->createStyle("", textColour); + BookTypesetter::Style* title = typesetter->createStyle("", textColour, false); typesetter->sectionBreak(9); typesetter->write(title, to_utf8_span(mText.c_str())); } @@ -567,7 +567,7 @@ namespace MWGui (*it)->write(typesetter, &mKeywordSearch, mTopicLinks); - BookTypesetter::Style* body = typesetter->createStyle("", MyGUI::Colour::White); + BookTypesetter::Style* body = typesetter->createStyle("", MyGUI::Colour::White, false); typesetter->sectionBreak(9); // choices From 6d0e6ab01220438a80bede2fb56dc5a4537da592 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Mon, 17 Sep 2018 22:24:21 +0400 Subject: [PATCH 130/196] Use book font by default in the text formatter --- apps/openmw/mwgui/formatting.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/formatting.hpp b/apps/openmw/mwgui/formatting.hpp index 6d98d48b3..b16a4e57d 100644 --- a/apps/openmw/mwgui/formatting.hpp +++ b/apps/openmw/mwgui/formatting.hpp @@ -14,7 +14,7 @@ namespace MWGui { TextStyle() : mColour(0,0,0) - , mFont("") + , mFont("Journalbook Magic Cards") , mTextSize(16) { } From 989de05f8046105c15cb6aa49280841a037ecde6 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Tue, 18 Sep 2018 15:23:16 +0400 Subject: [PATCH 131/196] Do not show duration for infinite light sources as -1 --- apps/openmw/mwclass/light.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index 27a9f3f2b..3ee228013 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -161,7 +161,12 @@ namespace MWClass std::string text; if (Settings::Manager::getBool("show effect duration","Game")) - text += "\n#{sDuration}: " + MWGui::ToolTips::toString(ptr.getClass().getRemainingUsageTime(ptr)); + { + // -1 is infinite light source, so duration makes no sense here. Other negative values are treated as 0. + float remainingTime = ptr.getClass().getRemainingUsageTime(ptr); + if (remainingTime != -1.0f) + text += "\n#{sDuration}: " + MWGui::ToolTips::toString(std::max(0.f, remainingTime)); + } text += MWGui::ToolTips::getWeightString(ref->mBase->mData.mWeight, "#{sWeight}"); text += MWGui::ToolTips::getValueString(ref->mBase->mData.mValue, "#{sValue}"); From 62f6f174cf2a6648c6d0c0da71205b5a97295a44 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Tue, 18 Sep 2018 15:36:37 +0400 Subject: [PATCH 132/196] Show attack speed of ranged weapons --- apps/openmw/mwclass/weapon.cpp | 13 +++++++++---- docs/source/reference/modding/settings/game.rst | 2 +- files/settings-default.cfg | 2 +- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index 466ae4716..6776434ec 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -65,7 +65,7 @@ namespace MWClass { const MWWorld::LiveCellRef *ref = ptr.get(); - return (ref->mBase->mData.mType < 11); // thrown weapons and arrows/bolts don't have health, only quantity + return (ref->mBase->mData.mType < ESM::Weapon::MarksmanThrown); // thrown weapons and arrows/bolts don't have health, only quantity } int Weapon::getItemMaxHealth (const MWWorld::ConstPtr& ptr) const @@ -318,21 +318,26 @@ namespace MWClass } } - if (ref->mBase->mData.mType < 11) // thrown weapons and arrows/bolts don't have health, only quantity + if (hasItemHealth(ptr)) { int remainingHealth = getItemHealth(ptr); text += "\n#{sCondition}: " + MWGui::ToolTips::toString(remainingHealth) + "/" + MWGui::ToolTips::toString(ref->mBase->mData.mHealth); } - // add reach and attack speed for melee weapon - if (ref->mBase->mData.mType < 9 && Settings::Manager::getBool("show melee info", "Game")) + const bool verbose = Settings::Manager::getBool("show melee info", "Game"); + // add reach for melee weapon + if (ref->mBase->mData.mType < ESM::Weapon::MarksmanBow && verbose) { // 64 game units = 1 yard = 3 ft, display value in feet const float combatDistance = store.get().find("fCombatDistance")->mValue.getFloat() * ref->mBase->mData.mReach; text += MWGui::ToolTips::getWeightString(combatDistance*3/64, "#{sRange}"); text += " #{sFeet}"; + } + // add attack speed for any weapon excepts arrows and bolts + if (ref->mBase->mData.mType < ESM::Weapon::Arrow && verbose) + { text += MWGui::ToolTips::getPercentString(ref->mBase->mData.mSpeed, "#{sAttributeSpeed}"); } diff --git a/docs/source/reference/modding/settings/game.rst b/docs/source/reference/modding/settings/game.rst index b733cc7c4..baeac92b2 100644 --- a/docs/source/reference/modding/settings/game.rst +++ b/docs/source/reference/modding/settings/game.rst @@ -36,7 +36,7 @@ show melee info :Range: True/False :Default: False -If this setting is true, the reach and speed of melee weapons will show on their tooltip. +If this setting is true, the reach and speed of weapons will show on their tooltip. This setting can only be configured by editing the settings configuration file. diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 45cee0559..3344e6bb4 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -188,7 +188,7 @@ show owned = 0 # Show damage bonus of arrow and bolts. show projectile damage = false -# Show additional melee weapon info: reach and attack speed +# Show additional weapon info: reach and attack speed show melee info = false # Show success probability in self-enchant dialog From 6f4f6a155fc5293a16fb55d945a3f01ce197db40 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Wed, 19 Sep 2018 12:04:58 +0400 Subject: [PATCH 133/196] Combat AI: take ranged weapon speed in account --- apps/openmw/mwmechanics/weaponpriority.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/weaponpriority.cpp b/apps/openmw/mwmechanics/weaponpriority.cpp index 818065ae4..aaa06f6e4 100644 --- a/apps/openmw/mwmechanics/weaponpriority.cpp +++ b/apps/openmw/mwmechanics/weaponpriority.cpp @@ -119,7 +119,7 @@ namespace MWMechanics rating *= getHitChance(actor, enemy, value) / 100.f; - if (weapon->mData.mType < ESM::Weapon::MarksmanBow) + if (weapon->mData.mType < ESM::Weapon::Arrow) rating *= weapon->mData.mSpeed; return rating * ratingMult; From 276b7830a9f03cea95f3a3382648b9e34046ed1f Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Tue, 18 Sep 2018 14:57:21 +0400 Subject: [PATCH 134/196] Mass potion creation (feature #4642) --- CHANGELOG.md | 1 + apps/openmw/mwgui/alchemywindow.cpp | 90 +++++++++++++++++++++++- apps/openmw/mwgui/alchemywindow.hpp | 24 +++++++ apps/openmw/mwmechanics/alchemy.cpp | 64 +++++++++++++++-- apps/openmw/mwmechanics/alchemy.hpp | 16 ++++- components/widgets/numericeditbox.cpp | 5 ++ components/widgets/numericeditbox.hpp | 1 + files/mygui/openmw_alchemy_window.layout | 15 +++- 8 files changed, 206 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1fb9837bd..958ec0118 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -155,6 +155,7 @@ Feature #4626: Weapon priority: account for weapon speed Feature #4632: AI priority: utilize vanilla AI GMSTs for priority rating Feature #4636: Use sTo GMST in spellmaking menu + Feature #4642: Batching potion creation Task #2490: Don't open command prompt window on Release-mode builds automatically Task #4545: Enable is_pod string test Task #4605: Optimize skinning diff --git a/apps/openmw/mwgui/alchemywindow.cpp b/apps/openmw/mwgui/alchemywindow.cpp index 6fd3d3220..0aa98dc4a 100644 --- a/apps/openmw/mwgui/alchemywindow.cpp +++ b/apps/openmw/mwgui/alchemywindow.cpp @@ -1,5 +1,7 @@ #include "alchemywindow.hpp" +#include + #include #include #include @@ -25,6 +27,9 @@ namespace MWGui { + const float AlchemyWindow::sCountChangeInitialPause = 0.5f; + const float AlchemyWindow::sCountChangeInterval = 0.1f; + AlchemyWindow::AlchemyWindow() : WindowBase("openmw_alchemy_window.layout") , mSortModel(NULL) @@ -43,9 +48,21 @@ namespace MWGui getWidget(mApparatus[2], "Apparatus3"); getWidget(mApparatus[3], "Apparatus4"); getWidget(mEffectsBox, "CreatedEffects"); + getWidget(mBrewCountEdit, "BrewCount"); + getWidget(mIncreaseButton, "IncreaseButton"); + getWidget(mDecreaseButton, "DecreaseButton"); getWidget(mNameEdit, "NameEdit"); getWidget(mItemView, "ItemView"); + mBrewCountEdit->eventValueChanged += MyGUI::newDelegate(this, &AlchemyWindow::onCountValueChanged); + mBrewCountEdit->eventEditSelectAccept += MyGUI::newDelegate(this, &AlchemyWindow::onAccept); + mBrewCountEdit->setMinValue(1); + mBrewCountEdit->setValue(1); + + mIncreaseButton->eventMouseButtonPressed += MyGUI::newDelegate(this, &AlchemyWindow::onIncreaseButtonPressed); + mIncreaseButton->eventMouseButtonReleased += MyGUI::newDelegate(this, &AlchemyWindow::onCountButtonReleased); + mDecreaseButton->eventMouseButtonPressed += MyGUI::newDelegate(this, &AlchemyWindow::onDecreaseButtonPressed); + mDecreaseButton->eventMouseButtonReleased += MyGUI::newDelegate(this, &AlchemyWindow::onCountButtonReleased); mItemView->eventItemClicked += MyGUI::newDelegate(this, &AlchemyWindow::onSelectedItem); @@ -77,7 +94,15 @@ namespace MWGui void AlchemyWindow::onCreateButtonClicked(MyGUI::Widget* _sender) { - MWMechanics::Alchemy::Result result = mAlchemy->create (mNameEdit->getCaption ()); + mAlchemy->setPotionName(mNameEdit->getCaption()); + int count = mAlchemy->countPotionsToBrew(); + count = std::min(count, mBrewCountEdit->getValue()); + createPotions(count); + } + + void AlchemyWindow::createPotions(int count) + { + MWMechanics::Alchemy::Result result = mAlchemy->create(mNameEdit->getCaption(), count); MWBase::WindowManager *winMgr = MWBase::Environment::get().getWindowManager(); switch (result) @@ -92,8 +117,11 @@ namespace MWGui winMgr->messageBox("#{sNotifyMessage6a}"); break; case MWMechanics::Alchemy::Result_Success: - winMgr->messageBox("#{sPotionSuccess}"); winMgr->playSound("potion success"); + if (count == 1) + winMgr->messageBox("#{sPotionSuccess}"); + else + winMgr->messageBox("#{sPotionSuccess} "+mNameEdit->getCaption()+" ("+std::to_string(count)+")"); break; case MWMechanics::Alchemy::Result_NoEffects: case MWMechanics::Alchemy::Result_RandomFailure: @@ -126,6 +154,7 @@ namespace MWGui mItemView->resetScrollBars(); mNameEdit->setCaption(""); + mBrewCountEdit->setValue(1); int index = 0; for (MWMechanics::Alchemy::TToolsIterator iter (mAlchemy->beginTools()); @@ -250,4 +279,61 @@ namespace MWGui update(); } + + void AlchemyWindow::addRepeatController(MyGUI::Widget *widget) + { + MyGUI::ControllerItem* item = MyGUI::ControllerManager::getInstance().createItem(Controllers::ControllerRepeatEvent::getClassTypeName()); + Controllers::ControllerRepeatEvent* controller = item->castType(); + controller->eventRepeatClick += MyGUI::newDelegate(this, &AlchemyWindow::onRepeatClick); + controller->setRepeat(sCountChangeInitialPause, sCountChangeInterval); + MyGUI::ControllerManager::getInstance().addItem(widget, controller); + } + + void AlchemyWindow::onIncreaseButtonPressed(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id) + { + addRepeatController(_sender); + onIncreaseButtonTriggered(); + } + + void AlchemyWindow::onDecreaseButtonPressed(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id) + { + addRepeatController(_sender); + onDecreaseButtonTriggered(); + } + + void AlchemyWindow::onRepeatClick(MyGUI::Widget* widget, MyGUI::ControllerItem* controller) + { + if (widget == mIncreaseButton) + onIncreaseButtonTriggered(); + else if (widget == mDecreaseButton) + onDecreaseButtonTriggered(); + } + + void AlchemyWindow::onCountButtonReleased(MyGUI::Widget *_sender, int _left, int _top, MyGUI::MouseButton _id) + { + MyGUI::ControllerManager::getInstance().removeItem(_sender); + } + + void AlchemyWindow::onCountValueChanged(int value) + { + mBrewCountEdit->setValue(std::abs(value)); + } + + void AlchemyWindow::onIncreaseButtonTriggered() + { + int currentCount = mBrewCountEdit->getValue(); + + // prevent overflows, and prevent entering INT_MIN since abs(INT_MIN) is undefined + if (currentCount == INT_MAX || currentCount == INT_MIN+1) + return; + + mBrewCountEdit->setValue(currentCount+1); + } + + void AlchemyWindow::onDecreaseButtonTriggered() + { + int currentCount = mBrewCountEdit->getValue(); + if (currentCount > 1) + mBrewCountEdit->setValue(currentCount-1); + } } diff --git a/apps/openmw/mwgui/alchemywindow.hpp b/apps/openmw/mwgui/alchemywindow.hpp index d1e54241a..aa23fbaa5 100644 --- a/apps/openmw/mwgui/alchemywindow.hpp +++ b/apps/openmw/mwgui/alchemywindow.hpp @@ -3,8 +3,13 @@ #include +#include + #include "../mwmechanics/alchemy.hpp" +#include + +#include "controllers.hpp" #include "windowbase.hpp" namespace MWMechanics @@ -28,6 +33,10 @@ namespace MWGui void onResChange(int, int) { center(); } private: + + static const float sCountChangeInitialPause; // in seconds + static const float sCountChangeInterval; // in seconds + std::string mSuggestedPotionName; ItemView* mItemView; @@ -38,17 +47,32 @@ namespace MWGui MyGUI::Widget* mEffectsBox; + MyGUI::Button* mIncreaseButton; + MyGUI::Button* mDecreaseButton; MyGUI::EditBox* mNameEdit; + Gui::NumericEditBox* mBrewCountEdit; void onCancelButtonClicked(MyGUI::Widget* _sender); void onCreateButtonClicked(MyGUI::Widget* _sender); void onIngredientSelected(MyGUI::Widget* _sender); void onAccept(MyGUI::EditBox*); + void onIncreaseButtonPressed(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id); + void onDecreaseButtonPressed(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id); + void onCountButtonReleased(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id); + void onCountValueChanged(int value); + void onRepeatClick(MyGUI::Widget* widget, MyGUI::ControllerItem* controller); + + void addRepeatController(MyGUI::Widget* widget); + + void onIncreaseButtonTriggered(); + void onDecreaseButtonTriggered(); void onSelectedItem(int index); void removeIngredient(MyGUI::Widget* ingredient); + void createPotions(int count); + void update(); std::unique_ptr mAlchemy; diff --git a/apps/openmw/mwmechanics/alchemy.cpp b/apps/openmw/mwmechanics/alchemy.cpp index b8f820307..98860198b 100644 --- a/apps/openmw/mwmechanics/alchemy.cpp +++ b/apps/openmw/mwmechanics/alchemy.cpp @@ -30,6 +30,7 @@ MWMechanics::Alchemy::Alchemy() : mValue(0) + , mPotionName("") { } @@ -336,6 +337,25 @@ int MWMechanics::Alchemy::countIngredients() const return ingredients; } +int MWMechanics::Alchemy::countPotionsToBrew() const +{ + Result readyStatus = getReadyStatus(); + if (readyStatus != Result_Success) + return 0; + + int toBrew = -1; + + for (TIngredientsIterator iter (beginIngredients()); iter!=endIngredients(); ++iter) + if (!iter->isEmpty()) + { + int count = iter->getRefData().getCount(); + if ((count > 0 && count < toBrew) || toBrew < 0) + toBrew = count; + } + + return toBrew; +} + void MWMechanics::Alchemy::setAlchemist (const MWWorld::Ptr& npc) { mAlchemist = npc; @@ -396,6 +416,12 @@ void MWMechanics::Alchemy::clear() mTools.clear(); mIngredients.clear(); mEffects.clear(); + setPotionName(""); +} + +void MWMechanics::Alchemy::setPotionName(const std::string& name) +{ + mPotionName = name; } int MWMechanics::Alchemy::addIngredient (const MWWorld::Ptr& ingredient) @@ -456,7 +482,7 @@ bool MWMechanics::Alchemy::knownEffect(unsigned int potionEffectIndex, const MWW || (potionEffectIndex <= 7 && alchemySkill >= fWortChanceValue*4); } -MWMechanics::Alchemy::Result MWMechanics::Alchemy::create (const std::string& name) +MWMechanics::Alchemy::Result MWMechanics::Alchemy::getReadyStatus() const { if (mTools[ESM::Apparatus::MortarPestle].isEmpty()) return Result_NoMortarAndPestle; @@ -464,15 +490,43 @@ MWMechanics::Alchemy::Result MWMechanics::Alchemy::create (const std::string& na if (countIngredients()<2) return Result_LessThanTwoIngredients; - if (name.empty()) + if (mPotionName.empty()) return Result_NoName; if (listEffects().empty()) - { - removeIngredients(); return Result_NoEffects; + + return Result_Success; +} + +MWMechanics::Alchemy::Result MWMechanics::Alchemy::create (const std::string& name, int& count) +{ + setPotionName(name); + Result readyStatus = getReadyStatus(); + + if (readyStatus == Result_NoEffects) + removeIngredients(); + + if (readyStatus != Result_Success) + return readyStatus; + + Result result = Result_RandomFailure; + int brewedCount = 0; + for (int i = 0; i < count; ++i) + { + if (createSingle() == Result_Success) + { + result = Result_Success; + brewedCount++; + } } + count = brewedCount; + return result; +} + +MWMechanics::Alchemy::Result MWMechanics::Alchemy::createSingle () +{ if (beginEffects() == endEffects()) { // all effects were nullified due to insufficient skill @@ -486,7 +540,7 @@ MWMechanics::Alchemy::Result MWMechanics::Alchemy::create (const std::string& na return Result_RandomFailure; } - addPotion (name); + addPotion(mPotionName); removeIngredients(); diff --git a/apps/openmw/mwmechanics/alchemy.hpp b/apps/openmw/mwmechanics/alchemy.hpp index f351881e0..9f9f0b21c 100644 --- a/apps/openmw/mwmechanics/alchemy.hpp +++ b/apps/openmw/mwmechanics/alchemy.hpp @@ -51,11 +51,14 @@ namespace MWMechanics TIngredientsContainer mIngredients; TEffectsContainer mEffects; int mValue; + std::string mPotionName; void applyTools (int flags, float& value) const; void updateEffects(); + Result getReadyStatus() const; + 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 @@ -70,6 +73,10 @@ namespace MWMechanics void increaseSkill(); ///< Increase alchemist's skill. + Result createSingle (); + ///< Try to create a potion from the ingredients, place it in the inventory of the alchemist and + /// adjust the skills of the alchemist accordingly. + float getAlchemyFactor() const; int countIngredients() const; @@ -79,6 +86,8 @@ namespace MWMechanics TEffectsIterator endEffects() const; public: + int countPotionsToBrew() const; + ///< calculates maximum amount of potions, which you can make from selected ingredients static bool knownEffect (unsigned int potionEffectIndex, const MWWorld::Ptr& npc); ///< Does npc have sufficient alchemy skill to know about this potion effect? @@ -100,6 +109,9 @@ namespace MWMechanics void clear(); ///< Remove alchemist, tools and ingredients. + void setPotionName(const std::string& name); + ///< Set name of potion to create + std::set listEffects() const; ///< List all effects shared by at least two ingredients. @@ -115,8 +127,8 @@ namespace MWMechanics 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 + Result create (const std::string& name, int& count); + ///< Try to create potions from the ingredients, place them in the inventory of the alchemist and /// adjust the skills of the alchemist accordingly. /// \param name must not be an empty string, or Result_NoName is returned }; diff --git a/components/widgets/numericeditbox.cpp b/components/widgets/numericeditbox.cpp index efe480653..e8ba226f7 100644 --- a/components/widgets/numericeditbox.cpp +++ b/components/widgets/numericeditbox.cpp @@ -59,6 +59,11 @@ namespace Gui } } + int NumericEditBox::getValue() + { + return mValue; + } + void NumericEditBox::setMinValue(int minValue) { mMinValue = minValue; diff --git a/components/widgets/numericeditbox.hpp b/components/widgets/numericeditbox.hpp index 3edae2fc7..137583d37 100644 --- a/components/widgets/numericeditbox.hpp +++ b/components/widgets/numericeditbox.hpp @@ -30,6 +30,7 @@ namespace Gui /// @note Does not trigger eventValueChanged void setValue (int value); + int getValue(); void setMinValue(int minValue); void setMaxValue(int maxValue); diff --git a/files/mygui/openmw_alchemy_window.layout b/files/mygui/openmw_alchemy_window.layout index edc9a4c3d..714872fc3 100644 --- a/files/mygui/openmw_alchemy_window.layout +++ b/files/mygui/openmw_alchemy_window.layout @@ -74,7 +74,20 @@ - + + + + + + + + + + + + + + From bdd9eba2b822a913cf12bbaf53f543e6f5a71701 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Thu, 20 Sep 2018 16:02:26 +0400 Subject: [PATCH 135/196] Use C++ limits instead of C ones --- apps/opencs/view/world/util.cpp | 4 +--- apps/openmw/mwgui/alchemywindow.cpp | 6 ++---- apps/openmw/mwgui/tradewindow.cpp | 6 ++---- apps/openmw/mwmechanics/autocalcspell.cpp | 9 ++++----- apps/openmw/mwrender/globalmap.cpp | 2 -- 5 files changed, 9 insertions(+), 18 deletions(-) diff --git a/apps/opencs/view/world/util.cpp b/apps/opencs/view/world/util.cpp index eab37e1bf..b194e460d 100644 --- a/apps/opencs/view/world/util.cpp +++ b/apps/opencs/view/world/util.cpp @@ -1,8 +1,6 @@ #include "util.hpp" #include -#include -#include #include #include @@ -209,7 +207,7 @@ QWidget *CSVWorld::CommandDelegate::createEditor (QWidget *parent, const QStyleO case CSMWorld::ColumnBase::Display_Integer: { DialogueSpinBox *sb = new DialogueSpinBox(parent); - sb->setRange(INT_MIN, INT_MAX); + sb->setRange(std::numeric_limits::min(), std::numeric_limits::max()); return sb; } diff --git a/apps/openmw/mwgui/alchemywindow.cpp b/apps/openmw/mwgui/alchemywindow.cpp index 0aa98dc4a..a599e6c7b 100644 --- a/apps/openmw/mwgui/alchemywindow.cpp +++ b/apps/openmw/mwgui/alchemywindow.cpp @@ -1,7 +1,5 @@ #include "alchemywindow.hpp" -#include - #include #include #include @@ -323,8 +321,8 @@ namespace MWGui { int currentCount = mBrewCountEdit->getValue(); - // prevent overflows, and prevent entering INT_MIN since abs(INT_MIN) is undefined - if (currentCount == INT_MAX || currentCount == INT_MIN+1) + // prevent overflows + if (currentCount == std::numeric_limits::max()) return; mBrewCountEdit->setValue(currentCount+1); diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index f461d5f50..726c72b99 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -1,7 +1,5 @@ #include "tradewindow.hpp" -#include - #include #include #include @@ -96,7 +94,7 @@ namespace MWGui mTotalBalance->eventValueChanged += MyGUI::newDelegate(this, &TradeWindow::onBalanceValueChanged); mTotalBalance->eventEditSelectAccept += MyGUI::newDelegate(this, &TradeWindow::onAccept); - mTotalBalance->setMinValue(INT_MIN+1); // disallow INT_MIN since abs(INT_MIN) is undefined + mTotalBalance->setMinValue(std::numeric_limits::min()+1); // disallow INT_MIN since abs(INT_MIN) is undefined setCoord(400, 0, 400, 300); } @@ -431,7 +429,7 @@ namespace MWGui void TradeWindow::onIncreaseButtonTriggered() { // prevent overflows, and prevent entering INT_MIN since abs(INT_MIN) is undefined - if (mCurrentBalance == INT_MAX || mCurrentBalance == INT_MIN+1) + if (mCurrentBalance == std::numeric_limits::max() || mCurrentBalance == std::numeric_limits::min()+1) return; if (mCurrentBalance < 0) mCurrentBalance -= 1; else mCurrentBalance += 1; diff --git a/apps/openmw/mwmechanics/autocalcspell.cpp b/apps/openmw/mwmechanics/autocalcspell.cpp index a52fcc059..80ac14ddd 100644 --- a/apps/openmw/mwmechanics/autocalcspell.cpp +++ b/apps/openmw/mwmechanics/autocalcspell.cpp @@ -1,7 +1,6 @@ #include "autocalcspell.hpp" #include "spellcasting.hpp" -#include #include #include "../mwworld/esmstore.hpp" @@ -50,7 +49,7 @@ namespace MWMechanics caps.mCount = 0; caps.mLimit = iAutoSpellSchoolMax[i]; caps.mReachedLimit = iAutoSpellSchoolMax[i] <= 0; - caps.mMinCost = INT_MAX; + caps.mMinCost = std::numeric_limits::max(); caps.mWeakestSpell.clear(); schoolCaps[i] = caps; } @@ -101,7 +100,7 @@ namespace MWMechanics if (found != selectedSpells.end()) selectedSpells.erase(found); - cap.mMinCost = INT_MAX; + cap.mMinCost = std::numeric_limits::max(); for (std::vector::iterator weakIt = selectedSpells.begin(); weakIt != selectedSpells.end(); ++weakIt) { const ESM::Spell* testSpell = spells.find(*weakIt); @@ -151,7 +150,7 @@ namespace MWMechanics float baseMagicka = fPCbaseMagickaMult * actorAttributes[ESM::Attribute::Intelligence]; bool reachedLimit = false; const ESM::Spell* weakestSpell = NULL; - int minCost = INT_MAX; + int minCost = std::numeric_limits::max(); std::vector selectedSpells; @@ -188,7 +187,7 @@ namespace MWMechanics if (it != selectedSpells.end()) selectedSpells.erase(it); - minCost = INT_MAX; + minCost = std::numeric_limits::max(); for (std::vector::iterator weakIt = selectedSpells.begin(); weakIt != selectedSpells.end(); ++weakIt) { const ESM::Spell* testSpell = esmStore.get().find(*weakIt); diff --git a/apps/openmw/mwrender/globalmap.cpp b/apps/openmw/mwrender/globalmap.cpp index fae524faa..520bd3cb7 100644 --- a/apps/openmw/mwrender/globalmap.cpp +++ b/apps/openmw/mwrender/globalmap.cpp @@ -1,7 +1,5 @@ #include "globalmap.hpp" -#include - #include #include #include From 01b3f92f7eac5d792bf910b966b441605c01ea07 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Thu, 13 Sep 2018 13:21:38 +0400 Subject: [PATCH 136/196] Make coc and fixme console commands close to vanilla (bug #4292, bug #4217) --- apps/openmw/mwscript/cellextensions.cpp | 12 +-- .../mwscript/transformationextensions.cpp | 6 +- apps/openmw/mwworld/worldimp.cpp | 77 +++++++++++++++---- components/compiler/extensions0.cpp | 2 +- components/compiler/opcodes.hpp | 1 - 5 files changed, 71 insertions(+), 27 deletions(-) diff --git a/apps/openmw/mwscript/cellextensions.cpp b/apps/openmw/mwscript/cellextensions.cpp index 2cb76ef88..f01fed2ce 100644 --- a/apps/openmw/mwscript/cellextensions.cpp +++ b/apps/openmw/mwscript/cellextensions.cpp @@ -46,18 +46,19 @@ namespace MWScript ESM::Position pos; MWBase::World *world = MWBase::Environment::get().getWorld(); + const MWWorld::Ptr playerPtr = world->getPlayerPtr(); if (world->findExteriorPosition(cell, pos)) { - MWWorld::ActionTeleport("", pos, false).execute(world->getPlayerPtr()); - world->fixPosition(world->getPlayerPtr()); + MWWorld::ActionTeleport("", pos, false).execute(playerPtr); + world->adjustPosition(playerPtr, false); } else { // Change to interior even if findInteriorPosition() // yields false. In this case position will be zero-point. world->findInteriorPosition(cell, pos); - MWWorld::ActionTeleport(cell, pos, false).execute(world->getPlayerPtr()); + MWWorld::ActionTeleport(cell, pos, false).execute(playerPtr); } } }; @@ -76,14 +77,15 @@ namespace MWScript ESM::Position pos; MWBase::World *world = MWBase::Environment::get().getWorld(); + const MWWorld::Ptr playerPtr = world->getPlayerPtr(); world->indexToPosition (x, y, pos.pos[0], pos.pos[1], true); pos.pos[2] = 0; pos.rot[0] = pos.rot[1] = pos.rot[2] = 0; - MWWorld::ActionTeleport("", pos, false).execute(world->getPlayerPtr()); - world->fixPosition(world->getPlayerPtr()); + MWWorld::ActionTeleport("", pos, false).execute(playerPtr); + world->adjustPosition(playerPtr, false); } }; diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index 16d7e8036..9d7a5c6ed 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -732,14 +732,13 @@ namespace MWScript } }; - template class OpFixme : public Interpreter::Opcode0 { public: virtual void execute (Interpreter::Runtime& runtime) { - MWWorld::Ptr ptr = R()(runtime); + const MWWorld::Ptr ptr = MWMechanics::getPlayer(); MWBase::Environment::get().getWorld()->fixPosition(ptr); } }; @@ -784,8 +783,7 @@ namespace MWScript interpreter.installSegment5(Compiler::Transformation::opcodeGetStartingAngle, new OpGetStartingAngle); interpreter.installSegment5(Compiler::Transformation::opcodeGetStartingAngleExplicit, new OpGetStartingAngle); interpreter.installSegment5(Compiler::Transformation::opcodeResetActors, new OpResetActors); - interpreter.installSegment5(Compiler::Transformation::opcodeFixme, new OpFixme); - interpreter.installSegment5(Compiler::Transformation::opcodeFixmeExplicit, new OpFixme); + interpreter.installSegment5(Compiler::Transformation::opcodeFixme, new OpFixme); } } } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 2afcdffc8..29161c298 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -246,7 +246,7 @@ namespace MWWorld if (findExteriorPosition (mStartCell, pos)) { changeToExteriorCell (pos, true); - fixPosition(getPlayerPtr()); + adjustPosition(getPlayerPtr(), false); } else { @@ -1353,13 +1353,37 @@ namespace MWWorld void World::fixPosition(const Ptr &actor) { - const float dist = 8000; - osg::Vec3f pos (actor.getRefData().getPosition().asVec3()); - pos.z() += dist; + const float distance = 128.f; + ESM::Position esmPos = actor.getRefData().getPosition(); + osg::Quat orientation(esmPos.rot[2], osg::Vec3f(0,0,-1)); + osg::Vec3f pos (esmPos.asVec3()); - osg::Vec3f traced = mPhysics->traceDown(actor, pos, dist*1.1f); + int direction = 0; + int fallbackDirections[4] = {direction, (direction+3)%4, (direction+2)%4, (direction+1)%4}; + + osg::Vec3f targetPos = pos; + for (int i=0; i<4; ++i) + { + direction = fallbackDirections[i]; + if (direction == 0) targetPos = pos + (orientation * osg::Vec3f(0,1,0)) * distance; + else if(direction == 1) targetPos = pos - (orientation * osg::Vec3f(0,1,0)) * distance; + else if(direction == 2) targetPos = pos - (orientation * osg::Vec3f(1,0,0)) * distance; + else if(direction == 3) targetPos = pos + (orientation * osg::Vec3f(1,0,0)) * distance; + + // destination is free + if (!castRay(pos.x(), pos.y(), pos.z(), targetPos.x(), targetPos.y(), targetPos.z())) + break; + } + + targetPos.z() += distance / 2.f; // move up a bit to get out from geometry, will snap down later + osg::Vec3f traced = mPhysics->traceDown(actor, targetPos, Constants::CellSizeInUnits); if (traced != pos) - moveObject(actor, actor.getCell(), traced.x(), traced.y(), traced.z()); + { + esmPos.pos[0] = traced.x(); + esmPos.pos[1] = traced.y(); + esmPos.pos[2] = traced.z(); + MWWorld::ActionTeleport("", esmPos, false).execute(actor); + } } void World::rotateObject (const Ptr& ptr,float x,float y,float z, bool adjust) @@ -1429,7 +1453,7 @@ namespace MWWorld ipos.rot[2] = referenceObject.getRefData().getPosition().rot[2]; MWWorld::Ptr placed = copyObjectToCell(ptr, referenceCell, ipos, ptr.getRefData().getCount(), false); - placed.getClass().adjustPosition(placed, true); // snap to ground + adjustPosition(placed, true); // snap to ground return placed; } @@ -2604,31 +2628,52 @@ namespace MWWorld return false; } + std::vector sortedDoors; const DoorList &doors = cellStore->getReadOnlyDoors().mList; - for (DoorList::const_iterator it = doors.begin(); it != doors.end(); ++it) { - if (!it->mRef.getTeleport()) { + for (DoorList::const_iterator it = doors.begin(); it != doors.end(); ++it) + { + if (!it->mRef.getTeleport()) + { continue; } + sortedDoors.push_back(&it->mRef); + } + + // Sort teleporting doors alphabetically, first by ID, then by destination cell to make search consistent + std::sort(sortedDoors.begin(), sortedDoors.end(), [] (const MWWorld::CellRef *lhs, const MWWorld::CellRef *rhs) + { + if (lhs->getRefId() != rhs->getRefId()) + return lhs->getRefId() < rhs->getRefId(); + + return lhs->getDestCell() < rhs->getDestCell(); + }); + + for (std::vector::const_iterator it = sortedDoors.begin(); it != sortedDoors.end(); ++it) + { MWWorld::CellStore *source = 0; // door to exterior - if (it->mRef.getDestCell().empty()) { + if ((*it)->getDestCell().empty()) + { int x, y; - ESM::Position doorDest = it->mRef.getDoorDest(); + ESM::Position doorDest = (*it)->getDoorDest(); positionToIndex(doorDest.pos[0], doorDest.pos[1], x, y); source = getExterior(x, y); } // door to interior - else { - source = getInterior(it->mRef.getDestCell()); + else + { + source = getInterior((*it)->getDestCell()); } - if (0 != source) { + if (0 != source) + { // Find door leading to our current teleport door // and use its destination to position inside cell. const DoorList &destinationDoors = source->getReadOnlyDoors().mList; - for (DoorList::const_iterator jt = destinationDoors.begin(); jt != destinationDoors.end(); ++jt) { - if (it->mRef.getTeleport() && + for (DoorList::const_iterator jt = destinationDoors.begin(); jt != destinationDoors.end(); ++jt) + { + if ((*it)->getTeleport() && Misc::StringUtils::ciEqual(name, jt->mRef.getDestCell())) { /// \note Using _any_ door pointed to the interior, diff --git a/components/compiler/extensions0.cpp b/components/compiler/extensions0.cpp index 7638d0f78..7979f06b9 100644 --- a/components/compiler/extensions0.cpp +++ b/components/compiler/extensions0.cpp @@ -546,7 +546,7 @@ namespace Compiler extensions.registerInstruction("moveworld","cf",opcodeMoveWorld,opcodeMoveWorldExplicit); extensions.registerFunction("getstartingangle",'f',"c",opcodeGetStartingAngle,opcodeGetStartingAngleExplicit); extensions.registerInstruction("resetactors","",opcodeResetActors); - extensions.registerInstruction("fixme","",opcodeFixme, opcodeFixmeExplicit); + extensions.registerInstruction("fixme","",opcodeFixme); extensions.registerInstruction("ra","",opcodeResetActors); } } diff --git a/components/compiler/opcodes.hpp b/components/compiler/opcodes.hpp index aef92b311..c141eec68 100644 --- a/components/compiler/opcodes.hpp +++ b/components/compiler/opcodes.hpp @@ -504,7 +504,6 @@ namespace Compiler const int opcodeMoveWorldExplicit = 0x2000209; const int opcodeResetActors = 0x20002f4; const int opcodeFixme = 0x2000302; - const int opcodeFixmeExplicit = 0x2000303; } namespace User From fb484c6fde5b05bfaf2927bccd80caf037a53230 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Fri, 21 Sep 2018 19:02:28 +0400 Subject: [PATCH 137/196] Optimize AI loop a bit --- apps/openmw/mwmechanics/actors.cpp | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 0ee49ac45..e3b1ec791 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -1303,6 +1303,16 @@ namespace MWMechanics std::map > cachedAllies; // will be filled as engageCombat iterates + bool aiActive = MWBase::Environment::get().getMechanicsManager()->isAIActive(); + int attackedByPlayerId = player.getClass().getCreatureStats(player).getHitAttemptActorId(); + if (attackedByPlayerId != -1) + { + const MWWorld::Ptr playerHitAttemptActor = MWBase::Environment::get().getWorld()->searchPtrViaActorId(attackedByPlayerId); + + if (!playerHitAttemptActor.isInCell()) + player.getClass().getCreatureStats(player).setHitAttemptActorId(-1); + } + // AI and magic effects update for(PtrActorMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter) { @@ -1328,11 +1338,6 @@ namespace MWMechanics player.getClass().getCreatureStats(player).setHitAttemptActorId(-1); } - const MWWorld::Ptr playerHitAttemptActor = MWBase::Environment::get().getWorld()->searchPtrViaActorId(player.getClass().getCreatureStats(player).getHitAttemptActorId()); - - if (!playerHitAttemptActor.isInCell()) - player.getClass().getCreatureStats(player).setHitAttemptActorId(-1); - if (!iter->first.getClass().getCreatureStats(iter->first).isDead()) { bool cellChanged = MWBase::Environment::get().getWorld()->hasCellChanged(); @@ -1343,7 +1348,7 @@ namespace MWMechanics return; // for now abort update of the old cell when cell changes by teleportation magic effect // a better solution might be to apply cell changes at the end of the frame } - if (MWBase::Environment::get().getMechanicsManager()->isAIActive() && inProcessingRange) + if (aiActive && inProcessingRange) { if (timerUpdateAITargets == 0) { From b9346798c6bef7ec8b06d48853dd415d4e0dda91 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Fri, 21 Sep 2018 22:34:18 +0400 Subject: [PATCH 138/196] Optimize combat music update --- apps/openmw/mwmechanics/actors.cpp | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index e3b1ec791..0cd9912d0 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -1242,21 +1242,24 @@ namespace MWMechanics void Actors::updateCombatMusic () { MWWorld::Ptr player = getPlayer(); - int hostilesCount = 0; // need to know this to play Battle music + const osg::Vec3f playerPos = player.getRefData().getPosition().asVec3(); + bool hasHostiles = false; // need to know this to play Battle music + bool aiActive = MWBase::Environment::get().getMechanicsManager()->isAIActive(); - for(PtrActorMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter) + if (aiActive) { - if (!iter->first.getClass().getCreatureStats(iter->first).isDead()) + for(PtrActorMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter) { - bool inProcessingRange = (player.getRefData().getPosition().asVec3() - iter->first.getRefData().getPosition().asVec3()).length2() - <= sqrAiProcessingDistance; + if (iter->first == player) continue; - if (MWBase::Environment::get().getMechanicsManager()->isAIActive() && inProcessingRange) + bool inProcessingRange = (playerPos - iter->first.getRefData().getPosition().asVec3()).length2() <= sqrAiProcessingDistance; + if (inProcessingRange) { - if (iter->first != player) + MWMechanics::CreatureStats& stats = iter->first.getClass().getCreatureStats(iter->first); + if (!stats.isDead() && stats.getAiSequence().isInCombat()) { - MWMechanics::CreatureStats& stats = iter->first.getClass().getCreatureStats(iter->first); - if (stats.getAiSequence().isInCombat() && !stats.isDead()) hostilesCount++; + hasHostiles = true; + break; } } } @@ -1265,13 +1268,13 @@ namespace MWMechanics // check if we still have any player enemies to switch music static int currentMusic = 0; - if (currentMusic != 1 && hostilesCount == 0 && !(player.getClass().getCreatureStats(player).isDead() && + if (currentMusic != 1 && !hasHostiles && !(player.getClass().getCreatureStats(player).isDead() && MWBase::Environment::get().getSoundManager()->isMusicPlaying())) { MWBase::Environment::get().getSoundManager()->playPlaylist(std::string("Explore")); currentMusic = 1; } - else if (currentMusic != 2 && hostilesCount > 0) + else if (currentMusic != 2 && hasHostiles) { MWBase::Environment::get().getSoundManager()->playPlaylist(std::string("Battle")); currentMusic = 2; From 1634284739eb02715ca37c8c95f90695d3206dbb Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Fri, 21 Sep 2018 22:39:47 +0400 Subject: [PATCH 139/196] Cache player's position outside of loops --- apps/openmw/mwmechanics/actors.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 0cd9912d0..79622180f 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -1301,6 +1301,7 @@ namespace MWMechanics bool showTorches = MWBase::Environment::get().getWorld()->useTorches(); MWWorld::Ptr player = getPlayer(); + const osg::Vec3f playerPos = player.getRefData().getPosition().asVec3(); /// \todo move update logic to Actor class where appropriate @@ -1321,7 +1322,7 @@ namespace MWMechanics { bool isPlayer = iter->first == player; - float distSqr = (player.getRefData().getPosition().asVec3() - iter->first.getRefData().getPosition().asVec3()).length2(); + float distSqr = (playerPos - iter->first.getRefData().getPosition().asVec3()).length2(); // AI processing is only done within distance of 7168 units to the player. Note the "AI distance" slider doesn't affect this // (it only does some throttling for targets beyond the "AI distance", so doesn't give any guarantees as to whether AI will be enabled or not) // This distance could be made configurable later, but the setting must be marked with a big warning: @@ -1431,7 +1432,7 @@ namespace MWMechanics for(PtrActorMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter) { const float animationDistance = aiProcessingDistance + 400; // Slightly larger than AI distance so there is time to switch back to the idle animation. - const float distSqr = (player.getRefData().getPosition().asVec3() - iter->first.getRefData().getPosition().asVec3()).length2(); + const float distSqr = (playerPos - iter->first.getRefData().getPosition().asVec3()).length2(); bool isPlayer = iter->first == player; bool inAnimationRange = isPlayer || (animationDistance == 0 || distSqr <= animationDistance*animationDistance); int activeFlag = 1; // Can be changed back to '2' to keep updating bounding boxes off screen (more accurate, but slower) @@ -1520,7 +1521,7 @@ namespace MWMechanics continue; // is the player in range and can they be detected - if ((observer.getRefData().getPosition().asVec3() - player.getRefData().getPosition().asVec3()).length2() <= radius*radius + if ((observer.getRefData().getPosition().asVec3() - playerPos).length2() <= radius*radius && MWBase::Environment::get().getWorld()->getLOS(player, observer)) { if (MWBase::Environment::get().getMechanicsManager()->awarenessCheck(player, observer)) @@ -1664,7 +1665,8 @@ namespace MWMechanics void Actors::rest(bool sleep) { float duration = 3600.f / MWBase::Environment::get().getWorld()->getTimeScaleFactor(); - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + const MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + const osg::Vec3f playerPos = player.getRefData().getPosition().asVec3(); for(PtrActorMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter) { @@ -1674,7 +1676,7 @@ namespace MWMechanics restoreDynamicStats(iter->first, sleep); if ((!iter->first.getRefData().getBaseNode()) || - (player.getRefData().getPosition().asVec3() - iter->first.getRefData().getPosition().asVec3()).length2() > sqrAiProcessingDistance) + (playerPos - iter->first.getRefData().getPosition().asVec3()).length2() > sqrAiProcessingDistance) continue; adjustMagicEffects (iter->first); From b3fd173e007b62071baea8cc11e756adffcb1c68 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sat, 22 Sep 2018 06:51:56 +0400 Subject: [PATCH 140/196] Check if current weapon has health at all in HUD (bug #4648) --- CHANGELOG.md | 1 + apps/openmw/mwgui/windowmanagerimp.cpp | 7 +++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b45727939..22ff55bb2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -125,6 +125,7 @@ Bug #4633: Sneaking stance affects speed even if the actor is not able to crouch Bug #4641: GetPCJumping is handled incorrectly Bug #4644: %Name should be available for all actors, not just for NPCs + Bug #4648: Hud thinks that throwing weapons have condition Feature #912: Editor: Add missing icons to UniversalId tables Feature #1617: Editor: Enchantment effect record verifier Feature #1645: Casting effects from objects diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 98dbddaff..7fca0058f 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1383,8 +1383,11 @@ namespace MWGui void WindowManager::setSelectedWeapon(const MWWorld::Ptr& item) { mSelectedWeapon = item; - int durabilityPercent = - static_cast(item.getClass().getItemHealth(item) / static_cast(item.getClass().getItemMaxHealth(item)) * 100); + int durabilityPercent = 100; + if (item.getClass().hasItemHealth(item)) + { + durabilityPercent = static_cast(item.getClass().getItemHealth(item) / static_cast(item.getClass().getItemMaxHealth(item)) * 100); + } mHud->setSelectedWeapon(item, durabilityPercent); mInventoryWindow->setTitle(item.getClass().getName(item)); } From 90d35aaa8ff64cb9d3ef373fbcde56c5dce1f961 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sat, 22 Sep 2018 07:46:47 +0400 Subject: [PATCH 141/196] Handle current health level during levelup (bug #4649) --- CHANGELOG.md | 1 + apps/openmw/mwmechanics/npcstats.cpp | 7 ++++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b45727939..557848bb4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -125,6 +125,7 @@ Bug #4633: Sneaking stance affects speed even if the actor is not able to crouch Bug #4641: GetPCJumping is handled incorrectly Bug #4644: %Name should be available for all actors, not just for NPCs + Bug #4649: Levelup fully restores health Feature #912: Editor: Add missing icons to UniversalId tables Feature #1617: Editor: Enchantment effect record verifier Feature #1645: Casting effects from objects diff --git a/apps/openmw/mwmechanics/npcstats.cpp b/apps/openmw/mwmechanics/npcstats.cpp index cb9ef5477..47d886e3f 100644 --- a/apps/openmw/mwmechanics/npcstats.cpp +++ b/apps/openmw/mwmechanics/npcstats.cpp @@ -298,7 +298,12 @@ void MWMechanics::NpcStats::levelUp() // "When you gain a level, in addition to increasing three primary attributes, your Health // will automatically increase by 10% of your Endurance attribute. If you increased Endurance this level, // the Health increase is calculated from the increased Endurance" - setHealth(getHealth().getBase() + endurance * gmst.find("fLevelUpHealthEndMult")->mValue.getFloat()); + // Note: we should add bonus Health points to current level too. + float healthGain = endurance * gmst.find("fLevelUpHealthEndMult")->mValue.getFloat(); + MWMechanics::DynamicStat health(getHealth()); + health.setBase(getHealth().getBase() + healthGain); + health.setCurrent(std::max(1.f, getHealth().getCurrent() + healthGain)); + setHealth(health); setLevel(getLevel()+1); } From 2ac2d014322546ba3d6e86b27cb2ac41babde0cc Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sat, 22 Sep 2018 15:48:36 +0400 Subject: [PATCH 142/196] Optimize drowning state update --- apps/openmw/mwmechanics/actors.cpp | 27 +++++++++------------------ apps/openmw/mwmechanics/actors.hpp | 4 +--- 2 files changed, 10 insertions(+), 21 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 79622180f..9ea357f56 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -501,12 +501,6 @@ namespace MWMechanics } } - void Actors::updateNpc (const MWWorld::Ptr& ptr, float duration) - { - updateDrowning(ptr, duration); - calculateNpcStatModifiers(ptr, duration); - } - void Actors::adjustMagicEffects (const MWWorld::Ptr& creature) { CreatureStats& creatureStats = creature.getClass().getCreatureStats (creature); @@ -926,13 +920,8 @@ namespace MWMechanics return ctrl->isSneaking(); } - void Actors::updateDrowning(const MWWorld::Ptr& ptr, float duration) + void Actors::updateDrowning(const MWWorld::Ptr& ptr, float duration, bool isKnockedOut, bool isPlayer) { - PtrActorMap::iterator it = mActors.find(ptr); - if (it == mActors.end()) - return; - CharacterController* ctrl = it->second->getCharacterController(); - NpcStats &stats = ptr.getClass().getNpcStats(ptr); // When npc stats are just initialized, mTimeToStartDrowning == -1 and we should get value from GMST @@ -940,9 +929,10 @@ namespace MWMechanics if (stats.getTimeToStartDrowning() == -1.f) stats.setTimeToStartDrowning(fHoldBreathTime); - if (ptr.getClass().isNpc() && stats.getTimeToStartDrowning() < fHoldBreathTime / 2) + if (stats.getTimeToStartDrowning() < fHoldBreathTime / 2) { - if(ptr != MWMechanics::getPlayer() ) { + if(!isPlayer) + { MWMechanics::AiSequence& seq = ptr.getClass().getCreatureStats(ptr).getAiSequence(); if(seq.getTypeId() != MWMechanics::AiPackage::TypeIdBreathe) //Only add it once seq.stack(MWMechanics::AiBreathe(), ptr); @@ -950,7 +940,7 @@ namespace MWMechanics } MWBase::World *world = MWBase::Environment::get().getWorld(); - bool knockedOutUnderwater = (ctrl->isKnockedOut() && world->isUnderwater(ptr.getCell(), osg::Vec3f(ptr.getRefData().getPosition().asVec3()))); + bool knockedOutUnderwater = (isKnockedOut && world->isUnderwater(ptr.getCell(), osg::Vec3f(ptr.getRefData().getPosition().asVec3()))); if((world->isSubmerged(ptr) || knockedOutUnderwater) && stats.getMagicEffects().get(ESM::MagicEffect::WaterBreathing).getMagnitude() == 0) { @@ -965,7 +955,7 @@ namespace MWMechanics stats.setTimeToStartDrowning(timeLeft); } - bool godmode = ptr == MWMechanics::getPlayer() && MWBase::Environment::get().getWorld()->getGodModeState(); + bool godmode = isPlayer && MWBase::Environment::get().getWorld()->getGodModeState(); if(timeLeft == 0.0f && !godmode) { @@ -980,7 +970,7 @@ namespace MWMechanics if(!sndmgr->getSoundPlaying(ptr, "drown")) sndmgr->playSound3D(ptr, "drown", 1.0f, 1.0f); - if(ptr == world->getPlayerPtr()) + if(isPlayer) MWBase::Environment::get().getWindowManager()->activateHitOverlay(false); } } @@ -1406,7 +1396,8 @@ namespace MWMechanics if(iter->first.getTypeName() == typeid(ESM::NPC).name()) { - updateNpc(iter->first, duration); + updateDrowning(iter->first, duration, iter->second->getCharacterController()->isKnockedOut(), isPlayer); + calculateNpcStatModifiers(iter->first, duration); if (timerUpdateEquippedLight == 0) updateEquippedLight(iter->first, updateEquippedLightInterval, showTorches); diff --git a/apps/openmw/mwmechanics/actors.hpp b/apps/openmw/mwmechanics/actors.hpp index 8c94ce45f..a1e0e511d 100644 --- a/apps/openmw/mwmechanics/actors.hpp +++ b/apps/openmw/mwmechanics/actors.hpp @@ -28,8 +28,6 @@ namespace MWMechanics void addBoundItem (const std::string& itemId, const MWWorld::Ptr& actor); void removeBoundItem (const std::string& itemId, const MWWorld::Ptr& actor); - void updateNpc(const MWWorld::Ptr &ptr, float duration); - void adjustMagicEffects (const MWWorld::Ptr& creature); void calculateDynamicStats (const MWWorld::Ptr& ptr); @@ -39,7 +37,7 @@ namespace MWMechanics void calculateRestoration (const MWWorld::Ptr& ptr, float duration); - void updateDrowning (const MWWorld::Ptr& ptr, float duration); + void updateDrowning (const MWWorld::Ptr& ptr, float duration, bool isKnockedOut, bool isPlayer); void updateEquippedLight (const MWWorld::Ptr& ptr, float duration, bool mayEquip); From cd60d4fdf093b99e9ed30729e2e98c5949423ae4 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sat, 22 Sep 2018 15:57:58 +0400 Subject: [PATCH 143/196] Store character controller in the variable make code less bulk --- apps/openmw/mwmechanics/actors.cpp | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 9ea357f56..92f2ba34d 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -1311,6 +1311,7 @@ namespace MWMechanics for(PtrActorMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter) { bool isPlayer = iter->first == player; + CharacterController* ctrl = iter->second->getCharacterController(); float distSqr = (playerPos - iter->first.getRefData().getPosition().asVec3()).length2(); // AI processing is only done within distance of 7168 units to the player. Note the "AI distance" slider doesn't affect this @@ -1320,7 +1321,7 @@ namespace MWMechanics bool inProcessingRange = distSqr <= sqrAiProcessingDistance; if (isPlayer) - iter->second->getCharacterController()->setAttackingOrSpell(MWBase::Environment::get().getWorld()->getPlayer().getAttackingOrSpell()); + ctrl->setAttackingOrSpell(MWBase::Environment::get().getWorld()->getPlayer().getAttackingOrSpell()); // If dead or no longer in combat, no longer store any actors who attempted to hit us. Also remove for the player. if (iter->first != player && (iter->first.getClass().getCreatureStats(iter->first).isDead() @@ -1380,7 +1381,7 @@ namespace MWMechanics } } - iter->second->getCharacterController()->setHeadTrackTarget(headTrackTarget); + ctrl->setHeadTrackTarget(headTrackTarget); } if (iter->first.getClass().isNpc() && iter->first != player) @@ -1390,13 +1391,13 @@ namespace MWMechanics { CreatureStats &stats = iter->first.getClass().getCreatureStats(iter->first); if (isConscious(iter->first)) - stats.getAiSequence().execute(iter->first, *iter->second->getCharacterController(), duration); + stats.getAiSequence().execute(iter->first, *ctrl, duration); } } if(iter->first.getTypeName() == typeid(ESM::NPC).name()) { - updateDrowning(iter->first, duration, iter->second->getCharacterController()->isKnockedOut(), isPlayer); + updateDrowning(iter->first, duration, ctrl->isKnockedOut(), isPlayer); calculateNpcStatModifiers(iter->first, duration); if (timerUpdateEquippedLight == 0) @@ -1437,22 +1438,24 @@ namespace MWMechanics inAnimationRange = true; active = std::max(1, active); } - iter->second->getCharacterController()->setActive(active); + + CharacterController* ctrl = iter->second->getCharacterController(); + ctrl->setActive(active); if (!inAnimationRange) continue; if (iter->first.getClass().getCreatureStats(iter->first).isParalyzed()) - iter->second->getCharacterController()->skipAnim(); + ctrl->skipAnim(); // Handle player last, in case a cell transition occurs by casting a teleportation spell // (would invalidate the iterator) if (iter->first == getPlayer()) { - playerCharacter = iter->second->getCharacterController(); + playerCharacter = ctrl; continue; } - iter->second->getCharacterController()->update(duration); + ctrl->update(duration); } if (playerCharacter) From c50ee22772cb7cb4e8229fc5e0e73ff46df85ad2 Mon Sep 17 00:00:00 2001 From: Sergey Fukanchik Date: Sun, 23 Sep 2018 01:52:56 +0300 Subject: [PATCH 144/196] Wrap up World::canRest() implementation by moving enemiesNearby() from InputManager::rest() to World::canRest(). --- apps/openmw/mwbase/world.hpp | 16 ++++++++++------ apps/openmw/mwgui/waitdialog.cpp | 11 ++++++++--- apps/openmw/mwinput/inputmanagerimp.cpp | 4 ---- apps/openmw/mwworld/worldimp.cpp | 11 +++++++---- apps/openmw/mwworld/worldimp.hpp | 2 +- 5 files changed, 26 insertions(+), 18 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 72c4c3a2a..4e9e3f4a9 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -438,12 +438,16 @@ namespace MWBase virtual void enableActorCollision(const MWWorld::Ptr& actor, bool enable) = 0; - virtual int canRest() = 0; - ///< check if the player is allowed to rest \n - /// 0 - yes \n - /// 1 - only waiting \n - /// 2 - player is underwater \n - /// 3 - enemies are nearby (not implemented) + enum RestPermitted + { + Rest_Allowed = 0, + Rest_OnlyWaiting = 1, + Rest_PlayerIsUnderwater = 2, + Rest_EnemiesAreNearby = 3 + }; + + virtual RestPermitted canRest() = 0; + ///< check if the player is allowed to rest /// \todo Probably shouldn't be here virtual MWRender::Animation* getAnimation(const MWWorld::Ptr &ptr) = 0; diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index c5a06a12c..37cc9a59f 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -83,7 +83,7 @@ namespace MWGui void WaitDialog::setPtr(const MWWorld::Ptr &ptr) { - setCanRest(!ptr.isEmpty() || MWBase::Environment::get().getWorld ()->canRest () == 0); + setCanRest(!ptr.isEmpty() || MWBase::Environment::get().getWorld ()->canRest () == MWBase::World::Rest_Allowed); if (mUntilHealedButton->getVisible()) MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mUntilHealedButton); @@ -120,9 +120,14 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->popGuiMode (); } - int canRest = MWBase::Environment::get().getWorld ()->canRest (); + MWBase::World::RestPermitted canRest = MWBase::Environment::get().getWorld ()->canRest (); - if (canRest == 2) + if (canRest == MWBase::World::Rest_EnemiesAreNearby) + { + MWBase::Environment::get().getWindowManager()->messageBox("#{sNotifyMessage2}"); + MWBase::Environment::get().getWindowManager()->popGuiMode (); + } + else if (canRest == MWBase::World::Rest_PlayerIsUnderwater) { // resting underwater or mid-air not allowed MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage1}"); diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index ba9370122..101b4f2f7 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -1029,10 +1029,6 @@ namespace MWInput if (!MWBase::Environment::get().getWindowManager()->getRestEnabled () || MWBase::Environment::get().getWindowManager()->isGuiMode ()) return; - if(mPlayer->enemiesNearby()) {//Check if in combat - MWBase::Environment::get().getWindowManager()->messageBox("#{sNotifyMessage2}"); //Nope, - return; - } MWBase::Environment::get().getWindowManager()->pushGuiMode (MWGui::GM_Rest); //Open rest GUI } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 2afcdffc8..458ff3a01 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2297,7 +2297,7 @@ namespace MWWorld applyLoopingParticles(player); } - int World::canRest () + World::RestPermitted World::canRest () { CellStore *currentCell = mWorldScene->getCurrentCell(); @@ -2309,13 +2309,16 @@ namespace MWWorld if (!actor) throw std::runtime_error("can't find player"); + if(mPlayer->enemiesNearby()) + return Rest_EnemiesAreNearby; + if ((actor->getCollisionMode() && !mPhysics->isOnSolidGround(player)) || isUnderwater(currentCell, playerPos) || isWalkingOnWater(player)) - return 2; + return Rest_PlayerIsUnderwater; if((currentCell->getCell()->mData.mFlags&ESM::Cell::NoSleep) || player.getClass().getNpcStats(player).isWerewolf()) - return 1; + return Rest_OnlyWaiting; - return 0; + return Rest_Allowed; } MWRender::Animation* World::getAnimation(const MWWorld::Ptr &ptr) diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 536a40468..92fb091bf 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -551,7 +551,7 @@ namespace MWWorld void enableActorCollision(const MWWorld::Ptr& actor, bool enable) override; - int canRest() override; + World::RestPermitted canRest() override; ///< check if the player is allowed to rest \n /// 0 - yes \n /// 1 - only waiting \n From 44bcd9b25fa8c94da732de933e2465185d58673c Mon Sep 17 00:00:00 2001 From: Sergey Fukanchik Date: Sun, 23 Sep 2018 02:46:29 +0300 Subject: [PATCH 145/196] Fix tab characters --- apps/openmw/mwgui/waitdialog.cpp | 8 ++++---- apps/openmw/mwworld/worldimp.cpp | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index 37cc9a59f..db92b355c 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -120,14 +120,14 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->popGuiMode (); } - MWBase::World::RestPermitted canRest = MWBase::Environment::get().getWorld ()->canRest (); + MWBase::World::RestPermitted canRest = MWBase::Environment::get().getWorld ()->canRest (); - if (canRest == MWBase::World::Rest_EnemiesAreNearby) + if (canRest == MWBase::World::Rest_EnemiesAreNearby) { MWBase::Environment::get().getWindowManager()->messageBox("#{sNotifyMessage2}"); MWBase::Environment::get().getWindowManager()->popGuiMode (); - } - else if (canRest == MWBase::World::Rest_PlayerIsUnderwater) + } + else if (canRest == MWBase::World::Rest_PlayerIsUnderwater) { // resting underwater or mid-air not allowed MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage1}"); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 458ff3a01..1b3e3c3ef 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2309,8 +2309,8 @@ namespace MWWorld if (!actor) throw std::runtime_error("can't find player"); - if(mPlayer->enemiesNearby()) - return Rest_EnemiesAreNearby; + if(mPlayer->enemiesNearby()) + return Rest_EnemiesAreNearby; if ((actor->getCollisionMode() && !mPhysics->isOnSolidGround(player)) || isUnderwater(currentCell, playerPos) || isWalkingOnWater(player)) return Rest_PlayerIsUnderwater; From 52da65b776948f0119467add6072a41982993f1e Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Sun, 23 Sep 2018 03:28:30 +0300 Subject: [PATCH 146/196] Fix issues with sun specularity (bug #4527) --- CHANGELOG.md | 1 + apps/openmw/mwworld/weather.cpp | 11 +++++++---- files/shaders/water_fragment.glsl | 2 +- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b45727939..c4c446d72 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -94,6 +94,7 @@ Bug #4503: Cast and ExplodeSpell commands increase alteration skill Bug #4510: Division by zero in MWMechanics::CreatureStats::setAttribute Bug #4519: Knockdown does not discard movement in the 1st-person mode + Bug #4527: Sun renders on water shader in some situations where it shouldn't Bug #4531: Movement does not reset idle animations Bug #4532: Underwater sfx isn't tied to 3rd person camera Bug #4539: Paper Doll is affected by GUI scaling diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 2a9e8d7cc..ac885f429 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -752,12 +752,15 @@ void WeatherManager::update(float duration, bool paused, const TimeStamp& time, float underwaterFog = mUnderwaterFog.getValue(time.getHour(), mTimeSettings, "Fog"); float peakHour = mSunriseTime + (mSunsetTime - mSunriseTime) / 2; + float glareFade = 1.f; if (time.getHour() < mSunriseTime || time.getHour() > mSunsetTime) - mRendering.getSkyManager()->setGlareTimeOfDayFade(0); + glareFade = 0.f; else if (time.getHour() < peakHour) - mRendering.getSkyManager()->setGlareTimeOfDayFade(1 - (peakHour - time.getHour()) / (peakHour - mSunriseTime)); + glareFade -= (peakHour - time.getHour()) / (peakHour - mSunriseTime); else - mRendering.getSkyManager()->setGlareTimeOfDayFade(1 - (time.getHour() - peakHour) / (mSunsetTime - peakHour)); + glareFade -= (time.getHour() - peakHour) / (mSunsetTime - peakHour); + + mRendering.getSkyManager()->setGlareTimeOfDayFade(glareFade); mRendering.getSkyManager()->setMasserState(mMasser.calculateState(time)); mRendering.getSkyManager()->setSecundaState(mSecunda.calculateState(time)); @@ -765,7 +768,7 @@ void WeatherManager::update(float duration, bool paused, const TimeStamp& time, mRendering.configureFog(mResult.mFogDepth, underwaterFog, mResult.mDLFogFactor, mResult.mDLFogOffset/100.0f, mResult.mFogColor); mRendering.setAmbientColour(mResult.mAmbientColor); - mRendering.setSunColour(mResult.mSunColor, mResult.mSunColor * mResult.mGlareView); + mRendering.setSunColour(mResult.mSunColor, mResult.mSunColor * mResult.mGlareView * glareFade); mRendering.getSkyManager()->setWeather(mResult); diff --git a/files/shaders/water_fragment.glsl b/files/shaders/water_fragment.glsl index ee91df75f..4c4a253f1 100644 --- a/files/shaders/water_fragment.glsl +++ b/files/shaders/water_fragment.glsl @@ -286,6 +286,6 @@ void main(void) #if REFRACTION gl_FragData[0].w = 1.0; #else - gl_FragData[0].w = clamp(fresnel*6.0 + specular, 0.0, 1.0); //clamp(fresnel*2.0 + specular, 0.0, 1.0); + gl_FragData[0].w = clamp(fresnel*6.0 + specular * gl_LightSource[0].specular.w, 0.0, 1.0); //clamp(fresnel*2.0 + specular * gl_LightSource[0].specular.w, 0.0, 1.0); #endif } From f2e11e6def966680380267ab84169b3670e66237 Mon Sep 17 00:00:00 2001 From: Sergey Fukanchik Date: Sun, 23 Sep 2018 04:06:29 +0300 Subject: [PATCH 147/196] Fix MSVC C4596 illegal qualified name --- apps/openmw/mwworld/worldimp.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 92fb091bf..5c3eb30b3 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -551,7 +551,7 @@ namespace MWWorld void enableActorCollision(const MWWorld::Ptr& actor, bool enable) override; - World::RestPermitted canRest() override; + RestPermitted canRest() override; ///< check if the player is allowed to rest \n /// 0 - yes \n /// 1 - only waiting \n From f00f35ba86f719e2fa7615a3aab9e402acaa27b9 Mon Sep 17 00:00:00 2001 From: Sergey Fukanchik Date: Sun, 23 Sep 2018 06:25:20 +0300 Subject: [PATCH 148/196] Add const to canRest() --- apps/openmw/mwbase/world.hpp | 2 +- apps/openmw/mwworld/worldimp.cpp | 2 +- apps/openmw/mwworld/worldimp.hpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 4e9e3f4a9..330babf09 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -446,7 +446,7 @@ namespace MWBase Rest_EnemiesAreNearby = 3 }; - virtual RestPermitted canRest() = 0; + virtual RestPermitted canRest() const = 0; ///< check if the player is allowed to rest /// \todo Probably shouldn't be here diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 1b3e3c3ef..9b701d17b 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2297,7 +2297,7 @@ namespace MWWorld applyLoopingParticles(player); } - World::RestPermitted World::canRest () + World::RestPermitted World::canRest () const { CellStore *currentCell = mWorldScene->getCurrentCell(); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 5c3eb30b3..e694d9d84 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -551,7 +551,7 @@ namespace MWWorld void enableActorCollision(const MWWorld::Ptr& actor, bool enable) override; - RestPermitted canRest() override; + RestPermitted canRest() const override; ///< check if the player is allowed to rest \n /// 0 - yes \n /// 1 - only waiting \n From 92259c6cca4987d023de675b38781c98cd01db15 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Sun, 23 Sep 2018 22:30:06 +0300 Subject: [PATCH 149/196] Discard count arguments for AddSoulGem and RemoveSpell (bug #3762) --- CHANGELOG.md | 1 + components/compiler/extensions0.cpp | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b45727939..41db3b0eb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,7 @@ Bug #3591: Angled hit distance too low Bug #3629: DB assassin attack never triggers creature spawning Bug #3681: OpenMW-CS: Clicking Scripts in Preferences spawns many color pickers + Bug #3762: AddSoulGem and RemoveSpell redundant count arguments break script execution Bug #3788: GetPCInJail and GetPCTraveling do not work as in vanilla Bug #3836: Script fails to compile when command argument contains "\n" Bug #3876: Landscape texture painting is misaligned diff --git a/components/compiler/extensions0.cpp b/components/compiler/extensions0.cpp index 7638d0f78..9b74377f2 100644 --- a/components/compiler/extensions0.cpp +++ b/components/compiler/extensions0.cpp @@ -276,7 +276,7 @@ namespace Compiler extensions.registerInstruction ("gotojail", "", opcodeGoToJail); extensions.registerFunction ("getlocked", 'l', "", opcodeGetLocked, opcodeGetLockedExplicit); extensions.registerFunction ("geteffect", 'l', "S", opcodeGetEffect, opcodeGetEffectExplicit); - extensions.registerInstruction ("addsoulgem", "cc", opcodeAddSoulGem, opcodeAddSoulGemExplicit); + extensions.registerInstruction ("addsoulgem", "ccz", opcodeAddSoulGem, opcodeAddSoulGemExplicit); extensions.registerInstruction ("removesoulgem", "c/l", opcodeRemoveSoulGem, opcodeRemoveSoulGemExplicit); extensions.registerInstruction ("drop", "cl", opcodeDrop, opcodeDropExplicit); extensions.registerInstruction ("dropsoulgem", "c", opcodeDropSoulGem, opcodeDropSoulGemExplicit); @@ -463,7 +463,7 @@ namespace Compiler extensions.registerInstruction ("modpccrimelevel", "f", opcodeModPCCrimeLevel); extensions.registerInstruction ("addspell", "cz", opcodeAddSpell, opcodeAddSpellExplicit); - extensions.registerInstruction ("removespell", "c", opcodeRemoveSpell, + extensions.registerInstruction ("removespell", "cz", opcodeRemoveSpell, opcodeRemoveSpellExplicit); extensions.registerInstruction ("removespelleffects", "c", opcodeRemoveSpellEffects, opcodeRemoveSpellEffectsExplicit); From b2a52a5b6c1ba97ee3d5bab99cfb66a675e3ad78 Mon Sep 17 00:00:00 2001 From: Sergey Fukanchik Date: Mon, 24 Sep 2018 14:59:10 +0300 Subject: [PATCH 150/196] Change 'after function'-style doxygen comment to normal. --- apps/openmw/mwbase/world.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 330babf09..f44e6593b 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -446,8 +446,8 @@ namespace MWBase Rest_EnemiesAreNearby = 3 }; + /// check if the player is allowed to rest virtual RestPermitted canRest() const = 0; - ///< check if the player is allowed to rest /// \todo Probably shouldn't be here virtual MWRender::Animation* getAnimation(const MWWorld::Ptr &ptr) = 0; From 657d95a0bedc63e252139a28c6275e3b8ed86c27 Mon Sep 17 00:00:00 2001 From: Sergey Fukanchik Date: Mon, 24 Sep 2018 15:30:30 +0300 Subject: [PATCH 151/196] Paperwork for the pull request #1935 --- AUTHORS.md | 1 + CHANGELOG.md | 1 + 2 files changed, 2 insertions(+) diff --git a/AUTHORS.md b/AUTHORS.md index 5320a2462..074081876 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -148,6 +148,7 @@ Programmers Scott Howard scrawl Sebastian Wick (swick) + Sergey Fukanchik Sergey Shambir ShadowRadiance Siimacore diff --git a/CHANGELOG.md b/CHANGELOG.md index b45727939..7083fcdb7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -164,6 +164,7 @@ Task #4621: Optimize combat AI Task #4643: Revise editor record verifying functionality Task #4645: Use constants instead of widely used magic numbers + Task #4652: Move call to enemiesNearby() from InputManager::rest() to World::canRest() 0.44.0 ------ From 713330351bf1d8fa0867860266fce2de374e48d5 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Sun, 23 Sep 2018 00:08:16 +0300 Subject: [PATCH 152/196] Experimental animation regression fixes Don't unnecessarily start movement and jump animations from loop start Don't play movement animation until jumping animation finishes --- apps/openmw/mwmechanics/character.cpp | 104 +++++++++++++------------- apps/openmw/mwmechanics/character.hpp | 2 +- 2 files changed, 55 insertions(+), 51 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 749f908d2..8f14e0331 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -351,64 +351,69 @@ void CharacterController::refreshHitRecoilAnims(CharacterState& idle) idle = CharState_None; } -void CharacterController::refreshJumpAnims(const WeaponInfo* weap, JumpingState jump, CharacterState& idle, bool force) +void CharacterController::refreshJumpAnims(const WeaponInfo* weap, JumpingState jump, CharacterState& idle, CharacterState& movement, bool force) { - if(force || jump != mJumpState) + if (!force && jump == mJumpState && movement == CharState_None) + return; + + if (jump != JumpState_None) { - if (jump != JumpState_None) - idle = CharState_None; + idle = CharState_None; + movement = CharState_None; + } - bool startAtLoop = (jump == mJumpState); - mJumpState = jump; - - std::string jumpAnimName; - MWRender::Animation::BlendMask jumpmask = MWRender::Animation::BlendMask_All; - if(mJumpState != JumpState_None) + std::string jumpAnimName; + MWRender::Animation::BlendMask jumpmask = MWRender::Animation::BlendMask_All; + if (jump != JumpState_None) + { + jumpAnimName = "jump"; + if(weap != sWeaponTypeListEnd) { - jumpAnimName = "jump"; - if(weap != sWeaponTypeListEnd) + jumpAnimName += weap->shortgroup; + if(!mAnimation->hasAnimation(jumpAnimName)) { - jumpAnimName += weap->shortgroup; - if(!mAnimation->hasAnimation(jumpAnimName)) - { - jumpmask = MWRender::Animation::BlendMask_LowerBody; - jumpAnimName = "jump"; + jumpmask = MWRender::Animation::BlendMask_LowerBody; + jumpAnimName = "jump"; - // Since we apply movement only for lower body, do not reset idle animations. - // For upper body there will be idle animation. - if (idle == CharState_None) - idle = CharState_Idle; + // Since we apply movement only for lower body, do not reset idle animations. + // For upper body there will be idle animation. + if (idle == CharState_None) + idle = CharState_Idle; - // For crossbow animations use 1h ones as fallback - if (mWeaponType == WeapType_Crossbow) - jumpAnimName += "1h"; - } + // For crossbow animations use 1h ones as fallback + if (mWeaponType == WeapType_Crossbow) + jumpAnimName += "1h"; } } + } - if (!mCurrentJump.empty()) - { - mAnimation->disable(mCurrentJump); - mCurrentJump.clear(); - } + if (!force && jump == mJumpState) + return; - if(mJumpState == JumpState_InAir) + mJumpState = jump; + + if (!mCurrentJump.empty()) + { + mAnimation->disable(mCurrentJump); + mCurrentJump.clear(); + } + + if(mJumpState == JumpState_InAir) + { + if (mAnimation->hasAnimation(jumpAnimName)) { - if (mAnimation->hasAnimation(jumpAnimName)) - { - mAnimation->play(jumpAnimName, Priority_Jump, jumpmask, false, - 1.0f, (startAtLoop?"loop start":"start"), "stop", 0.0f, ~0ul); - mCurrentJump = jumpAnimName; - } + mAnimation->play(jumpAnimName, Priority_Jump, jumpmask, false, + 1.0f, "start", "stop", 0.f, ~0ul); + mCurrentJump = jumpAnimName; } - else if (mJumpState == JumpState_Landing) + } + else if (mJumpState == JumpState_Landing) + { + if (mAnimation->hasAnimation(jumpAnimName)) { - if (mAnimation->hasAnimation(jumpAnimName)) - { - mAnimation->play(jumpAnimName, Priority_Jump, jumpmask, true, - 1.0f, "loop stop", "stop", 0.0f, 0); - mCurrentJump = jumpAnimName; - } + mAnimation->play(jumpAnimName, Priority_Jump, jumpmask, true, + 1.0f, "loop stop", "stop", 0.0f, 0); + mCurrentJump = jumpAnimName; } } } @@ -494,10 +499,9 @@ void CharacterController::refreshMovementAnims(const WeaponInfo* weap, Character } // If we're playing the same animation, start it from the point it ended - bool sameAnim = (movementAnimName == mCurrentMovement); - float startPoint = 0.f; - if (sameAnim) - mAnimation->getInfo(mCurrentMovement, &startPoint); + float startpoint = 0.f; + if (!mCurrentMovement.empty() && movementAnimName == mCurrentMovement) + mAnimation->getInfo(mCurrentMovement, &startpoint); mMovementAnimationControlled = true; @@ -546,7 +550,7 @@ void CharacterController::refreshMovementAnims(const WeaponInfo* weap, Character } mAnimation->play(mCurrentMovement, Priority_Movement, movemask, false, - 1.f, (!sameAnim ? "start" : "loop start"), "stop", startPoint, ~0ul, true); + 1.f, "start", "stop", startpoint, ~0ul, true); } } } @@ -626,7 +630,7 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat if (!mPtr.getClass().hasInventoryStore(mPtr)) weap = sWeaponTypeListEnd; - refreshJumpAnims(weap, jump, idle, force); + refreshJumpAnims(weap, jump, idle, movement, force); refreshMovementAnims(weap, movement, idle, force); // idle handled last as it can depend on the other states diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 8b3c68048..1db497828 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -214,7 +214,7 @@ class CharacterController : public MWRender::Animation::TextKeyListener void refreshCurrentAnims(CharacterState idle, CharacterState movement, JumpingState jump, bool force=false); void refreshHitRecoilAnims(CharacterState& idle); - void refreshJumpAnims(const WeaponInfo* weap, JumpingState jump, CharacterState& idle, bool force=false); + void refreshJumpAnims(const WeaponInfo* weap, JumpingState jump, CharacterState& idle, CharacterState& movement, bool force=false); void refreshMovementAnims(const WeaponInfo* weap, CharacterState movement, CharacterState& idle, bool force=false); void refreshIdleAnims(const WeaponInfo* weap, CharacterState idle, bool force=false); From 56ef11b023299b64e6177c31a3af832b3b274d8c Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Sun, 23 Sep 2018 13:55:49 +0300 Subject: [PATCH 153/196] Reset sneak and swim idle animations when moving --- apps/openmw/mwmechanics/character.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 8f14e0331..c437a21d5 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -2168,12 +2168,12 @@ void CharacterController::update(float duration) if(mAnimQueue.empty() || inwater || sneak) { // Note: turning animations should not interrupt idle ones - if (inwater) + if (movestate != CharState_None && !isTurning()) + idlestate = CharState_None; + else if (inwater) idlestate = CharState_IdleSwim; else if (sneak && !inJump) idlestate = CharState_IdleSneak; - else if (movestate != CharState_None && !isTurning()) - idlestate = CharState_None; else idlestate = CharState_Idle; } From 77fb4d6dd2d8ea589e8befe55a5075fdfbad2b0c Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Sun, 23 Sep 2018 14:06:04 +0300 Subject: [PATCH 154/196] Make sure the idle animations are reset while jumping --- apps/openmw/mwmechanics/character.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index c437a21d5..27170d6a8 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -353,7 +353,7 @@ void CharacterController::refreshHitRecoilAnims(CharacterState& idle) void CharacterController::refreshJumpAnims(const WeaponInfo* weap, JumpingState jump, CharacterState& idle, CharacterState& movement, bool force) { - if (!force && jump == mJumpState && movement == CharState_None) + if (!force && jump == mJumpState && idle == CharState_None && movement == CharState_None) return; if (jump != JumpState_None) From d2cad229f897cfb1657095ac362708360e6bc688 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Tue, 25 Sep 2018 17:09:54 +0300 Subject: [PATCH 155/196] Ugly hack: don't reset player idle and movement animations in first person view --- apps/openmw/mwmechanics/character.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 27170d6a8..90f90e9e2 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -356,7 +356,7 @@ void CharacterController::refreshJumpAnims(const WeaponInfo* weap, JumpingState if (!force && jump == mJumpState && idle == CharState_None && movement == CharState_None) return; - if (jump != JumpState_None) + if (jump != JumpState_None && !(mPtr == MWMechanics::getPlayer() && MWBase::Environment::get().getWorld()->isFirstPerson())) // FIXME { idle = CharState_None; movement = CharState_None; From bce8de5fe9332d54221349648a4d1a7788ac7cc2 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Mon, 24 Sep 2018 14:09:24 +0400 Subject: [PATCH 156/196] Respect selected encoding in the content selector (bug #4467) --- CHANGELOG.md | 1 + apps/launcher/datafilespage.cpp | 4 +++- apps/opencs/editor.cpp | 5 +++-- apps/opencs/view/doc/filedialog.cpp | 5 +++++ apps/opencs/view/doc/filedialog.hpp | 1 + components/contentselector/view/contentselector.cpp | 7 ++++++- components/contentselector/view/contentselector.hpp | 1 + 7 files changed, 20 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6283d3f29..392bcf084 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -80,6 +80,7 @@ Bug #4460: Script function "Equip" doesn't bypass beast restrictions Bug #4461: "Open" spell from non-player caster isn't a crime Bug #4464: OpenMW keeps AiState cached storages even after we cancel AI packages + Bug #4467: Content selector: cyrillic characters are decoded incorrectly in plugin descriptions Bug #4469: Abot Silt Striders – Model turn 90 degrees on horizontal Bug #4470: Non-bipedal creatures with Weapon & Shield flag have inconsistent behaviour Bug #4474: No fallback when getVampireHead fails diff --git a/apps/launcher/datafilespage.cpp b/apps/launcher/datafilespage.cpp index 7b703a924..6f2389de3 100644 --- a/apps/launcher/datafilespage.cpp +++ b/apps/launcher/datafilespage.cpp @@ -36,6 +36,8 @@ Launcher::DataFilesPage::DataFilesPage(Files::ConfigurationManager &cfg, Config: ui.setupUi (this); setObjectName ("DataFilesPage"); mSelector = new ContentSelectorView::ContentSelector (ui.contentSelectorWidget); + const QString encoding = mGameSettings.value("encoding", "win1252"); + mSelector->setEncoding(encoding); mProfileDialog = new TextInputDialog(tr("New Content List"), tr("Content List name:"), this); @@ -357,4 +359,4 @@ void Launcher::DataFilesPage::reloadCells(QStringList selectedFiles) QStringList cellNamesList = QStringList::fromSet(cellNameLoader.getCellNames(selectedFiles)); std::sort(cellNamesList.begin(), cellNamesList.end()); emit signalLoadedCellsChanged(cellNamesList); -} \ No newline at end of file +} diff --git a/apps/opencs/editor.cpp b/apps/opencs/editor.cpp index e733d9924..f29c6aca8 100644 --- a/apps/opencs/editor.cpp +++ b/apps/opencs/editor.cpp @@ -108,8 +108,9 @@ std::pair > CS::Editor::readConfi mCfgMgr.readConfiguration(variables, desc, quiet); - mDocumentManager.setEncoding ( - ToUTF8::calculateEncoding (variables["encoding"].as().toStdString())); + const std::string encoding = variables["encoding"].as().toStdString(); + mDocumentManager.setEncoding (ToUTF8::calculateEncoding (encoding)); + mFileDialog.setEncoding (QString::fromUtf8(encoding.c_str())); mDocumentManager.setResourceDir (mResources = variables["resources"].as().toStdString()); diff --git a/apps/opencs/view/doc/filedialog.cpp b/apps/opencs/view/doc/filedialog.cpp index b6f4aaec3..3c5f20202 100644 --- a/apps/opencs/view/doc/filedialog.cpp +++ b/apps/opencs/view/doc/filedialog.cpp @@ -33,6 +33,11 @@ void CSVDoc::FileDialog::addFiles(const QString &path) mSelector->addFiles(path); } +void CSVDoc::FileDialog::setEncoding(const QString &encoding) +{ + mSelector->setEncoding(encoding); +} + void CSVDoc::FileDialog::clearFiles() { mSelector->clearFiles(); diff --git a/apps/opencs/view/doc/filedialog.hpp b/apps/opencs/view/doc/filedialog.hpp index ca6145b9c..69acfac3d 100644 --- a/apps/opencs/view/doc/filedialog.hpp +++ b/apps/opencs/view/doc/filedialog.hpp @@ -42,6 +42,7 @@ namespace CSVDoc void showDialog (ContentAction action); void addFiles (const QString &path); + void setEncoding (const QString &encoding); void clearFiles (); QString filename() const; diff --git a/components/contentselector/view/contentselector.cpp b/components/contentselector/view/contentselector.cpp index 5e16064f4..595be9f44 100644 --- a/components/contentselector/view/contentselector.cpp +++ b/components/contentselector/view/contentselector.cpp @@ -111,6 +111,11 @@ void ContentSelectorView::ContentSelector::clearCheckStates() mContentModel->uncheckAll(); } +void ContentSelectorView::ContentSelector::setEncoding(const QString &encoding) +{ + mContentModel->setEncoding(encoding); +} + void ContentSelectorView::ContentSelector::setContentList(const QStringList &list) { if (list.isEmpty()) @@ -239,4 +244,4 @@ void ContentSelectorView::ContentSelector::slotUncheckMultiSelectedItems() void ContentSelectorView::ContentSelector::slotCheckMultiSelectedItems() { setCheckStateForMultiSelectedItems(true); -} \ No newline at end of file +} diff --git a/components/contentselector/view/contentselector.hpp b/components/contentselector/view/contentselector.hpp index 323f926ed..9f9ad886c 100644 --- a/components/contentselector/view/contentselector.hpp +++ b/components/contentselector/view/contentselector.hpp @@ -32,6 +32,7 @@ namespace ContentSelectorView void setProfileContent (const QStringList &fileList); void clearCheckStates(); + void setEncoding (const QString &encoding); void setContentList(const QStringList &list); ContentSelectorModel::ContentFileList selectedFiles() const; From 0176ee389e1af840c2c73c701a865bcf12beffbf Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Tue, 25 Sep 2018 17:16:40 +0400 Subject: [PATCH 157/196] Handle length of UTF-8 strings properly in plugin metadata (bug #4653) --- CHANGELOG.md | 1 + apps/opencs/model/world/metadata.cpp | 4 ++-- components/esm/esmreader.hpp | 4 ++-- components/esm/loadtes3.cpp | 8 ++++---- components/esm/loadtes3.hpp | 4 ++-- 5 files changed, 11 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 392bcf084..93592dec4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -129,6 +129,7 @@ Bug #4644: %Name should be available for all actors, not just for NPCs Bug #4648: Hud thinks that throwing weapons have condition Bug #4649: Levelup fully restores health + Bug #4653: Length of non-ASCII strings is handled incorrectly in ESM reader Feature #912: Editor: Add missing icons to UniversalId tables Feature #1617: Editor: Enchantment effect record verifier Feature #1645: Casting effects from objects diff --git a/apps/opencs/model/world/metadata.cpp b/apps/opencs/model/world/metadata.cpp index 960fdc9e4..b2fa3487c 100644 --- a/apps/opencs/model/world/metadata.cpp +++ b/apps/opencs/model/world/metadata.cpp @@ -14,8 +14,8 @@ void CSMWorld::MetaData::blank() void CSMWorld::MetaData::load (ESM::ESMReader& esm) { mFormat = esm.getHeader().mFormat; - mAuthor = esm.getHeader().mData.author.toString(); - mDescription = esm.getHeader().mData.desc.toString(); + mAuthor = esm.getHeader().mData.author; + mDescription = esm.getHeader().mData.desc; } void CSMWorld::MetaData::save (ESM::ESMWriter& esm) const diff --git a/components/esm/esmreader.hpp b/components/esm/esmreader.hpp index 4772aeb6f..6e84fa7d4 100644 --- a/components/esm/esmreader.hpp +++ b/components/esm/esmreader.hpp @@ -33,8 +33,8 @@ public: int getVer() const { return mHeader.mData.version; } int getRecordCount() const { return mHeader.mData.records; } float getFVer() const { return (mHeader.mData.version == VER_12) ? 1.2f : 1.3f; } - const std::string getAuthor() const { return mHeader.mData.author.toString(); } - const std::string getDesc() const { return mHeader.mData.desc.toString(); } + const std::string getAuthor() const { return mHeader.mData.author; } + const std::string getDesc() const { return mHeader.mData.desc; } const std::vector &getGameFiles() const { return mHeader.mMaster; } const Header& getHeader() const { return mHeader; } int getFormat() const; diff --git a/components/esm/loadtes3.cpp b/components/esm/loadtes3.cpp index b16145467..d953f1dc2 100644 --- a/components/esm/loadtes3.cpp +++ b/components/esm/loadtes3.cpp @@ -32,8 +32,8 @@ void ESM::Header::load (ESMReader &esm) esm.getSubHeader(); esm.getT(mData.version); esm.getT(mData.type); - mData.author.assign( esm.getString(mData.author.data_size()) ); - mData.desc.assign( esm.getString(mData.desc.data_size()) ); + mData.author.assign( esm.getString(32) ); + mData.desc.assign( esm.getString(256) ); esm.getT(mData.records); } @@ -73,8 +73,8 @@ void ESM::Header::save (ESMWriter &esm) esm.startSubRecord("HEDR"); esm.writeT(mData.version); esm.writeT(mData.type); - esm.writeFixedSizeString(mData.author.toString(), mData.author.data_size()); - esm.writeFixedSizeString(mData.desc.toString(), mData.desc.data_size()); + esm.writeFixedSizeString(mData.author, 32); + esm.writeFixedSizeString(mData.desc, 256); esm.writeT(mData.records); esm.endRecord("HEDR"); diff --git a/components/esm/loadtes3.hpp b/components/esm/loadtes3.hpp index 896936cf5..5b26ac7d2 100644 --- a/components/esm/loadtes3.hpp +++ b/components/esm/loadtes3.hpp @@ -21,8 +21,8 @@ namespace ESM */ unsigned int version; int type; // 0=esp, 1=esm, 32=ess (unused) - NAME32 author; // Author's name - NAME256 desc; // File description + std::string author; // Author's name + std::string desc; // File description int records; // Number of records }; From 8af021d729de4b9d348a4aef5de7af6692a5143f Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sun, 23 Sep 2018 22:03:43 +0400 Subject: [PATCH 158/196] Restore dynamic stats for actors in inactive cells (bug #1875) --- CHANGELOG.md | 1 + apps/openmw/mwbase/mechanicsmanager.hpp | 2 ++ apps/openmw/mwbase/world.hpp | 2 ++ apps/openmw/mwmechanics/actors.cpp | 19 ++++++++------- .../mwmechanics/mechanicsmanagerimp.cpp | 8 +++++++ .../mwmechanics/mechanicsmanagerimp.hpp | 2 ++ apps/openmw/mwworld/cells.cpp | 13 ++++++++++ apps/openmw/mwworld/cells.hpp | 1 + apps/openmw/mwworld/cellstore.cpp | 24 +++++++++++++++++++ apps/openmw/mwworld/cellstore.hpp | 2 ++ apps/openmw/mwworld/worldimp.cpp | 4 ++++ apps/openmw/mwworld/worldimp.hpp | 8 +++---- 12 files changed, 72 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6283d3f29..1ef504003 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ 0.45.0 ------ + Bug #1875: Actors in inactive cells don't heal from resting Bug #1990: Sunrise/sunset not set correct Bug #2131: Lustidrike's spell misses the player every time Bug #2222: Fatigue's effect on selling price is backwards diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index fe3fc5721..8137bad95 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -90,6 +90,8 @@ namespace MWBase virtual void setPlayerClass (const ESM::Class& class_) = 0; ///< Set player class to custom class. + virtual void restoreDynamicStats(MWWorld::Ptr actor, bool sleep) = 0; + virtual void rest(bool sleep) = 0; ///< If the player is sleeping or waiting, this should be called every hour. /// @param sleep is the player sleeping or waiting? diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index f44e6593b..e17935abc 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -571,6 +571,8 @@ namespace MWBase virtual bool isPlayerInJail() const = 0; + virtual void rest() = 0; + virtual void setPlayerTraveling(bool traveling) = 0; virtual bool isPlayerTraveling() const = 0; diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 92f2ba34d..7f7355eef 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -545,10 +545,10 @@ namespace MWMechanics void Actors::restoreDynamicStats (const MWWorld::Ptr& ptr, bool sleep) { - if (ptr.getClass().getCreatureStats(ptr).isDead()) + MWMechanics::CreatureStats& stats = ptr.getClass().getCreatureStats (ptr); + if (stats.isDead()) return; - MWMechanics::CreatureStats& stats = ptr.getClass().getCreatureStats (ptr); const MWWorld::Store& settings = MWBase::Environment::get().getWorld()->getStore().get(); if (sleep) @@ -565,12 +565,6 @@ namespace MWMechanics stats.setMagicka(stat); } - int endurance = stats.getAttribute (ESM::Attribute::Endurance).getModified (); - - float normalizedEncumbrance = ptr.getClass().getNormalizedEncumbrance(ptr); - if (normalizedEncumbrance > 1) - normalizedEncumbrance = 1; - // Current fatigue can be above base value due to a fortify effect. // In that case stop here and don't try to restore. DynamicStat fatigue = stats.getFatigue(); @@ -582,6 +576,12 @@ namespace MWMechanics float fFatigueReturnMult = settings.find("fFatigueReturnMult")->mValue.getFloat (); float fEndFatigueMult = settings.find("fEndFatigueMult")->mValue.getFloat (); + int endurance = stats.getAttribute (ESM::Attribute::Endurance).getModified (); + + float normalizedEncumbrance = ptr.getClass().getNormalizedEncumbrance(ptr); + if (normalizedEncumbrance > 1) + normalizedEncumbrance = 1; + float x = fFatigueReturnBase + fFatigueReturnMult * (1 - normalizedEncumbrance); x *= fEndFatigueMult * endurance; @@ -1667,7 +1667,8 @@ namespace MWMechanics if (iter->first.getClass().getCreatureStats(iter->first).isDead()) continue; - restoreDynamicStats(iter->first, sleep); + if (!sleep || iter->first == player) + restoreDynamicStats(iter->first, sleep); if ((!iter->first.getRefData().getBaseNode()) || (playerPos - iter->first.getRefData().getPosition().asVec3()).length2() > sqrAiProcessingDistance) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 859b2e522..33357b79a 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -453,9 +453,17 @@ namespace MWMechanics void MechanicsManager::rest(bool sleep) { + if (sleep) + MWBase::Environment::get().getWorld()->rest(); + mActors.rest(sleep); } + void MechanicsManager::restoreDynamicStats(MWWorld::Ptr actor, bool sleep) + { + mActors.restoreDynamicStats(actor, sleep); + } + int MechanicsManager::getHoursToRest() const { return mActors.getHoursToRest(mWatched); diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index af12d4d98..3682e97ce 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -91,6 +91,8 @@ namespace MWMechanics virtual void setPlayerClass (const ESM::Class& class_); ///< Set player class to custom class. + virtual void restoreDynamicStats(MWWorld::Ptr actor, bool sleep); + virtual void rest(bool sleep); ///< If the player is sleeping or waiting, this should be called every hour. /// @param sleep is the player sleeping or waiting? diff --git a/apps/openmw/mwworld/cells.cpp b/apps/openmw/mwworld/cells.cpp index 5cac12b9c..8506cefa3 100644 --- a/apps/openmw/mwworld/cells.cpp +++ b/apps/openmw/mwworld/cells.cpp @@ -151,6 +151,19 @@ MWWorld::CellStore *MWWorld::Cells::getInterior (const std::string& name) return &result->second; } +void MWWorld::Cells::rest () +{ + for (auto &interior : mInteriors) + { + interior.second.rest(); + } + + for (auto &exterior : mExteriors) + { + exterior.second.rest(); + } +} + MWWorld::CellStore *MWWorld::Cells::getCell (const ESM::CellId& id) { if (id.mPaged) diff --git a/apps/openmw/mwworld/cells.hpp b/apps/openmw/mwworld/cells.hpp index 0b7d9444f..bd730329b 100644 --- a/apps/openmw/mwworld/cells.hpp +++ b/apps/openmw/mwworld/cells.hpp @@ -61,6 +61,7 @@ namespace MWWorld /// @note name must be lower case Ptr getPtr (const std::string& name); + void rest (); /// Get all Ptrs referencing \a name in exterior cells /// @note Due to the current implementation of getPtr this only supports one Ptr per cell. diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index 05ff1e326..5cd8346a7 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -17,6 +17,7 @@ #include #include "../mwbase/environment.hpp" +#include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/world.hpp" #include "../mwmechanics/creaturestats.hpp" @@ -954,6 +955,29 @@ namespace MWWorld } } + void CellStore::rest() + { + if (mState == State_Loaded) + { + for (CellRefList::List::iterator it (mCreatures.mList.begin()); it!=mCreatures.mList.end(); ++it) + { + Ptr ptr = getCurrentPtr(&*it); + if (!ptr.isEmpty() && ptr.getRefData().getCount() > 0) + { + MWBase::Environment::get().getMechanicsManager()->restoreDynamicStats(ptr, true); + } + } + for (CellRefList::List::iterator it (mNpcs.mList.begin()); it!=mNpcs.mList.end(); ++it) + { + Ptr ptr = getCurrentPtr(&*it); + if (!ptr.isEmpty() && ptr.getRefData().getCount() > 0) + { + MWBase::Environment::get().getMechanicsManager()->restoreDynamicStats(ptr, true); + } + } + } + } + void CellStore::respawn() { if (mState == State_Loaded) diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index dd54bdd6a..bcf4b4ada 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -183,6 +183,8 @@ namespace MWWorld /// @return updated MWWorld::Ptr with the new CellStore pointer set. MWWorld::Ptr moveTo(const MWWorld::Ptr& object, MWWorld::CellStore* cellToMoveTo); + void rest(); + /// Make a copy of the given object and insert it into this cell. /// @note If you get a linker error here, this means the given type can not be inserted into a cell. /// The supported types are defined at the bottom of this file. diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 9b701d17b..fe311f8fc 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -3118,6 +3118,10 @@ namespace MWWorld return closestMarker; } + void World::rest() + { + mCells.rest(); + } void World::teleportToClosestMarker (const MWWorld::Ptr& ptr, const std::string& id) diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index e694d9d84..7df8d1af5 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -552,11 +552,9 @@ namespace MWWorld void enableActorCollision(const MWWorld::Ptr& actor, bool enable) override; RestPermitted canRest() const override; - ///< check if the player is allowed to rest \n - /// 0 - yes \n - /// 1 - only waiting \n - /// 2 - player is underwater \n - /// 3 - enemies are nearby (not implemented) + ///< check if the player is allowed to rest + + void rest() override; /// \todo Probably shouldn't be here MWRender::Animation* getAnimation(const MWWorld::Ptr &ptr) override; From ba2fd8b7959f13d1f3f548d98a8711b03744212f Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Wed, 26 Sep 2018 21:16:57 +0300 Subject: [PATCH 159/196] Rename reflected absorb spells setting and add it to Advanced tab --- apps/launcher/advancedpage.cpp | 2 ++ apps/openmw/mwmechanics/spellcasting.cpp | 2 +- .../reference/modding/settings/game.rst | 34 +++++++++---------- files/settings-default.cfg | 4 +-- files/ui/advancedpage.ui | 12 ++++++- 5 files changed, 33 insertions(+), 21 deletions(-) diff --git a/apps/launcher/advancedpage.cpp b/apps/launcher/advancedpage.cpp index 102463085..41f546af4 100644 --- a/apps/launcher/advancedpage.cpp +++ b/apps/launcher/advancedpage.cpp @@ -72,6 +72,7 @@ bool Launcher::AdvancedPage::loadSettings() loadSettingBool(canLootDuringDeathAnimationCheckBox, "can loot during death animation", "Game"); loadSettingBool(followersAttackOnSightCheckBox, "followers attack on sight", "Game"); loadSettingBool(preventMerchantEquippingCheckBox, "prevent merchant equipping", "Game"); + loadSettingBool(classicReflectedAbsorbSpellsCheckBox, "classic reflected absorb spells behavior", "Game"); loadSettingBool(rebalanceSoulGemValuesCheckBox, "rebalance soul gem values", "Game"); loadSettingBool(chargeForEveryFollowerCheckBox, "charge for every follower travelling", "Game"); loadSettingBool(enchantedWeaponsMagicalCheckBox, "enchanted weapons are magical", "Game"); @@ -131,6 +132,7 @@ void Launcher::AdvancedPage::saveSettings() saveSettingBool(followersAttackOnSightCheckBox, "followers attack on sight", "Game"); saveSettingBool(preventMerchantEquippingCheckBox, "prevent merchant equipping", "Game"); saveSettingBool(rebalanceSoulGemValuesCheckBox, "rebalance soul gem values", "Game"); + saveSettingBool(classicReflectedAbsorbSpellsCheckBox, "classic reflected absorb spells behavior", "Game"); saveSettingBool(chargeForEveryFollowerCheckBox, "charge for every follower travelling", "Game"); saveSettingBool(enchantedWeaponsMagicalCheckBox, "enchanted weapons are magical", "Game"); saveSettingBool(permanentBarterDispositionChangeCheckBox, "barter disposition change is permanent", "Game"); diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 14dfac283..f1ee2520b 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -582,7 +582,7 @@ namespace MWMechanics ActiveSpells::ActiveEffect effect_ = effect; effect_.mMagnitude *= -1; absorbEffects.push_back(effect_); - if (reflected && Settings::Manager::getBool("classic reflect absorb attribute behavior", "Game")) + if (reflected && Settings::Manager::getBool("classic reflected absorb spells behavior", "Game")) target.getClass().getCreatureStats(target).getActiveSpells().addSpell("", true, absorbEffects, mSourceName, caster.getClass().getCreatureStats(caster).getActorId()); else diff --git a/docs/source/reference/modding/settings/game.rst b/docs/source/reference/modding/settings/game.rst index baeac92b2..4c3f4579f 100644 --- a/docs/source/reference/modding/settings/game.rst +++ b/docs/source/reference/modding/settings/game.rst @@ -16,7 +16,7 @@ If the setting is 2, the crosshair is the color of the color crosshair owned set If the setting is 3, both the tool tip background and the crosshair are colored. The crosshair is not visible if crosshair is false. -This setting can only be configured by editing the settings configuration file. +This setting can be configured in Advanced tab of the launcher. show projectile damage ---------------------- @@ -27,7 +27,7 @@ show projectile damage If this setting is true, the damage bonus of arrows and bolts will show on their tooltip. -This setting can only be configured by editing the settings configuration file. +This setting can be toggled in Advanced tab of the launcher. show melee info --------------- @@ -38,7 +38,7 @@ show melee info If this setting is true, the reach and speed of weapons will show on their tooltip. -This setting can only be configured by editing the settings configuration file. +This setting can be toggled in Advanced tab of the launcher. show enchant chance ------------------- @@ -49,7 +49,7 @@ show enchant chance Whether or not the chance of success will be displayed in the enchanting menu. -This setting can only be configured by editing the settings configuration file. +This setting can be toggled in Advanced tab of the launcher. best attack ----------- @@ -73,13 +73,13 @@ can loot during death animation If this setting is true, the player is allowed to loot actors (e.g. summoned creatures) during death animation, if they are not in combat. However disposing corpses during death animation is not recommended - death counter may not be incremented, and this behaviour can break quests. -This is how original Morrowind behaves. +This is how Morrowind behaves. If this setting is false, player has to wait until end of death animation in all cases. This case is more safe, but makes using of summoned creatures exploit (looting summoned Dremoras and Golden Saints for expensive weapons) a lot harder. Conflicts with mannequin mods, which use SkipAnim to prevent end of death animation. -This setting can only be configured by editing the settings configuration file. +This setting can be toggled in Advanced tab of the launcher. difficulty ---------- @@ -97,19 +97,19 @@ and values above 500 will result in the player inflicting no damage. This setting can be controlled in game with the Difficulty slider in the Prefs panel of the Options menu. -classic reflect absorb attribute behavior +classic reflected absorb spells behavior ----------------------------------------- :Type: boolean :Range: True/False :Default: True -If this setting is true, "Absorb Attribute" spells which were reflected by the target are not "mirrored", -and the caster will absorb their own attribute resulting in no effect on both the caster and the target. +If this setting is true, effects of Absorb spells which were reflected by the target are not mirrored, +and the caster will absorb their own stat resulting in no effect on either the caster and the target. This makes the gameplay as a mage easier, but these spells become imbalanced. -This is how the original Morrowind behaves. +This is how Morrowind behaves. -This setting can only be configured by editing the settings configuration file. +This setting can be toggled in Advanced tab of the launcher. show effect duration -------------------- @@ -121,7 +121,7 @@ show effect duration Show the remaining duration of magic effects and lights if this setting is true. The remaining duration is displayed in the tooltip by hovering over the magical effect. -This setting can only be configured by editing the settings configuration file. +This setting can be toggled in Advanced tab of the launcher. enchanted weapons are magical ----------------------------- @@ -131,9 +131,9 @@ enchanted weapons are magical :Default: True Make enchanted weapons without Magical flag bypass normal weapons resistance (and weakness) certain creatures have. -This is how original Morrowind behaves. +This is how Morrowind behaves. -This setting can only be configured by editing the settings configuration file. +This setting can be toggled in Advanced tab of the launcher. prevent merchant equipping -------------------------- @@ -144,7 +144,7 @@ prevent merchant equipping Prevent merchants from equipping items that are sold to them. -This setting can only be configured by editing the settings configuration file. +This setting can be toggled in Advanced tab of the launcher. followers attack on sight ------------------------- @@ -157,7 +157,7 @@ Make player followers and escorters start combat with enemies who have started c Otherwise they wait for the enemies or the player to do an attack first. Please note this setting has not been extensively tested and could have side effects with certain quests. -This setting can only be configured by editing the settings configuration file. +This setting can be toggled in Advanced tab of the launcher. use additional anim sources --------------------------- @@ -182,4 +182,4 @@ barter disposition change is permanent If this setting is true, disposition change of merchants caused by trading will be permanent and won't be discarded upon exiting dialogue with them. This imitates the option Morrowind Code Patch offers. -This setting can be toggled with a checkbox in Advanced tab of the launcher. +This setting can be toggled in Advanced tab of the launcher. diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 3344e6bb4..ea6f6e7b6 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -200,8 +200,8 @@ best attack = false # Difficulty. Expressed as damage dealt and received. (e.g. -100 to 100). difficulty = 0 -# Replicate how reflected "absorb attribute" spells do not have any effect in Morrowind engine. The caster absorbs the attribute from themselves. -classic reflect absorb attribute behavior = true +# Make reflected Absorb spells have no practical effect, like in Morrowind. +classic reflected absorb spells behavior = true # Show duration of magic effect and lights in the spells window. show effect duration = false diff --git a/files/ui/advancedpage.ui b/files/ui/advancedpage.ui index 8395d028f..0793345c8 100644 --- a/files/ui/advancedpage.ui +++ b/files/ui/advancedpage.ui @@ -73,7 +73,7 @@ Enchanted weapons are magical - + @@ -86,6 +86,16 @@ + + + + <html><head/><body><p>Effects of reflected Absorb spells are not mirrored -- like in Morrowind.</p></body></html> + + + Classic reflected Absorb spells behavior + + + From ee4ca87352fd8731e9cb96cf42e5f82beec527ba Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Wed, 26 Sep 2018 23:13:18 +0400 Subject: [PATCH 160/196] Traverse child nodes of cell node in the editor (bug #4654) --- CHANGELOG.md | 1 + apps/opencs/view/render/cell.cpp | 1 + 2 files changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6283d3f29..d5c7364b2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -128,6 +128,7 @@ Bug #4644: %Name should be available for all actors, not just for NPCs Bug #4648: Hud thinks that throwing weapons have condition Bug #4649: Levelup fully restores health + Bug #4654: Editor: UpdateVisitor does not initialize skeletons for animated objects Feature #912: Editor: Add missing icons to UniversalId tables Feature #1617: Editor: Enchantment effect record verifier Feature #1645: Casting effects from objects diff --git a/apps/opencs/view/render/cell.cpp b/apps/opencs/view/render/cell.cpp index 552a54ac2..a0c408df0 100644 --- a/apps/opencs/view/render/cell.cpp +++ b/apps/opencs/view/render/cell.cpp @@ -47,6 +47,7 @@ namespace CSVRender virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) { + traverse(node, nv); CellNodeContainer* container = static_cast(node->getUserData()); container->getCell()->updateLand(); } From 8444ee9981226e6f739b4df8ced94ef7bd9f7abe Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Fri, 13 Jul 2018 21:48:59 -0500 Subject: [PATCH 161/196] Start rendering npc's --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/view/render/actor.cpp | 196 +++++++++++++++++++++++++++++ apps/opencs/view/render/actor.hpp | 51 ++++++++ apps/opencs/view/render/object.cpp | 25 +++- apps/openmw/mwrender/animation.cpp | 34 +---- components/CMakeLists.txt | 2 +- components/esm/mappings.cpp | 134 ++++++++++++++++++++ components/esm/mappings.hpp | 16 +++ components/sceneutil/visitor.cpp | 19 ++- components/sceneutil/visitor.hpp | 30 +++++ 10 files changed, 471 insertions(+), 38 deletions(-) create mode 100644 apps/opencs/view/render/actor.cpp create mode 100644 apps/opencs/view/render/actor.hpp create mode 100644 components/esm/mappings.cpp create mode 100644 components/esm/mappings.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index f2821f184..26713f925 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -93,7 +93,7 @@ opencs_units (view/render opencs_units_noqt (view/render lighting lightingday lightingnight lightingbright object cell terrainstorage tagbase - cellarrow cellmarker cellborder pathgrid + cellarrow cellmarker cellborder pathgrid actor ) opencs_hdrs_noqt (view/render diff --git a/apps/opencs/view/render/actor.cpp b/apps/opencs/view/render/actor.cpp new file mode 100644 index 000000000..1273b94c6 --- /dev/null +++ b/apps/opencs/view/render/actor.cpp @@ -0,0 +1,196 @@ +#include "actor.hpp" + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "../../model/world/data.hpp" + +namespace CSVRender +{ + Actor::Actor(const std::string& id, int type, CSMWorld::Data& data) + : mId(id) + , mType(type) + , mData(data) + , mSkeleton(nullptr) + , mBaseNode(new osg::Group()) + { + } + + osg::Group* Actor::getBaseNode() + { + return mBaseNode; + } + + void Actor::update() + { + const std::string MeshPrefix = "meshes\\"; + const unsigned int FemaleFlag = ESM::BodyPart::BPF_Female; + + auto& bodyParts = mData.getBodyParts(); + auto& races = mData.getRaces(); + auto& referenceables = mData.getReferenceables(); + auto sceneMgr = mData.getResourceSystem()->getSceneManager(); + + + // Remove children + mBaseNode->removeChildren(0, mBaseNode->getNumChildren()); + + // Npcs and creatures are handled differently + if (mType == CSMWorld::UniversalId::Type_Npc) + { + auto& npc = dynamic_cast& >(referenceables.getRecord(mId)).get(); + + auto isBeast = [&](std::string race) -> bool { + int index = races.searchId(race); + if (index != -1 && !races.getRecord(index).isDeleted()) + return races.getRecord(index).get().mData.mFlags & ESM::Race::Beast; + else + return false; + }; + + // Load skeleton + std::string skeletonResource; + if (isBeast(npc.mRace)) { + std::cout << "is beast\n"; + skeletonResource = "base_animkna.nif"; + } + else if (npc.isMale()) { + std::cout << "is male\n"; + skeletonResource = "base_anim.nif"; + } + else { + std::cout << "is female\n"; + skeletonResource = "base_anim_female.nif"; + } + + std::string skeletonModel = MeshPrefix + skeletonResource; + skeletonModel = Misc::ResourceHelpers::correctActorModelPath(skeletonModel, mData.getResourceSystem()->getVFS()); + { + osg::ref_ptr temp = sceneMgr->getInstance(skeletonModel); + mSkeleton = dynamic_cast(temp.get()); + if (!mSkeleton) + { + mSkeleton = new SceneUtil::Skeleton(); + mSkeleton->addChild(temp); + } + mBaseNode->addChild(mSkeleton); + } + + // Map bone names to bones + SceneUtil::NodeMapVisitor::NodeMap nodeMap; + SceneUtil::NodeMapVisitor nmVisitor(nodeMap); + mSkeleton->accept(nmVisitor); + + if (!npc.isMale()) { + for (auto it : nodeMap) { + std::cout << it.first << "\n"; + } + } + + + // Female mesh has some drawables attached, get rid of them + SceneUtil::HideDrawablesVisitor hdVisitor; + mSkeleton->accept(hdVisitor); + + // Convenience method to retrieve the mesh name of a body part + auto getBodyPartMesh = [&](std::string bpName) -> std::string { + int index = bodyParts.searchId(bpName); + if (index != -1 && !bodyParts.getRecord(index).isDeleted()) + return MeshPrefix + bodyParts.getRecord(index).get().mModel; + else + return ""; + }; + + using BPRaceKey = std::tuple; + using RaceToBPMap = std::map; + // Convenience method to generate a map from body part + race to mesh name + auto genRaceToBodyPartMap = [&](RaceToBPMap& bpMap) { + int size = bodyParts.getSize(); + for (int i = 0; i < size; ++i) + { + auto& record = bodyParts.getRecord(i); + if (!record.isDeleted()) + { + auto& bodyPart = record.get(); + bpMap.emplace( + BPRaceKey(bodyPart.mData.mPart, bodyPart.mData.mFlags & FemaleFlag ? 1 : 0, bodyPart.mRace), + MeshPrefix + bodyPart.mModel); + } + } + }; + + // Generate mapping + RaceToBPMap r2bpMap; + genRaceToBodyPartMap(r2bpMap); + + // Convenience method to add a body part + auto addBodyPart = [&](ESM::PartReferenceType type, std::string mesh) { + // Retrieve mesh name if necessary + if (mesh.empty()) + { + auto meshResult = r2bpMap.find(BPRaceKey(ESM::getMeshPart(type), npc.isMale() ? 0 : 1, npc.mRace)); + if (meshResult != r2bpMap.end()) + { + mesh = meshResult->second; + } + } + + // Attach to skeleton + std::string boneName = ESM::getBoneName(type); + auto node = nodeMap.find(boneName); + if (!mesh.empty() && node != nodeMap.end()) + { + auto instance = sceneMgr->getInstance(mesh); + if (!npc.isMale() && type == ESM::PRT_LHand) { + SceneUtil::NodeMapVisitor::NodeMap handNodeMap; + SceneUtil::NodeMapVisitor nmVisitor(handNodeMap); + instance->accept(nmVisitor); + + std::cout << "Left hand\n"; + for (auto it : handNodeMap) { + std::cout << it.first << std::endl; + } + } + SceneUtil::attach(instance, mSkeleton, boneName, node->second); + } + }; + + // Add body parts + for (unsigned int i = 0; i < ESM::PRT_Count; ++i) + { + auto part = static_cast(i); + switch (part) + { + case ESM::PRT_Head: + addBodyPart(part, getBodyPartMesh(npc.mHead)); + break; + case ESM::PRT_Hair: + addBodyPart(part, getBodyPartMesh(npc.mHair)); + break; + case ESM::PRT_Skirt: + case ESM::PRT_Shield: + case ESM::PRT_RPauldron: + case ESM::PRT_LPauldron: + case ESM::PRT_Weapon: + // No body part mesh associated + break; + default: + addBodyPart(part, ""); + } + } + // Post setup + mSkeleton->markDirty(); + mSkeleton->setActive(SceneUtil::Skeleton::Active); + } + } +} diff --git a/apps/opencs/view/render/actor.hpp b/apps/opencs/view/render/actor.hpp new file mode 100644 index 000000000..10f4de558 --- /dev/null +++ b/apps/opencs/view/render/actor.hpp @@ -0,0 +1,51 @@ +#ifndef OPENCS_VIEW_RENDER_ACTOR_H +#define OPENCS_VIEW_RENDER_ACTOR_H + +#include + +#include + +namespace osg +{ + class Group; +} + +namespace CSMWorld +{ + class Data; +} + +namespace SceneUtil +{ + class Skeleton; +} + +namespace CSVRender +{ + /// Handles loading an npc or creature + class Actor + { + public: + /// Creates an actor. + /// \param id The referenceable id + /// \param type The record type + /// \param data The data store + Actor(const std::string& id, int type, CSMWorld::Data& data); + + /// Retrieves the base node that meshes are attached to + osg::Group* getBaseNode(); + + /// (Re)creates the npc or creature renderable + void update(); + + private: + std::string mId; + int mType; + CSMWorld::Data& mData; + + SceneUtil::Skeleton* mSkeleton; + osg::ref_ptr mBaseNode; + }; +} + +#endif diff --git a/apps/opencs/view/render/object.cpp b/apps/opencs/view/render/object.cpp index 2b1e3adde..b8e171650 100644 --- a/apps/opencs/view/render/object.cpp +++ b/apps/opencs/view/render/object.cpp @@ -1,6 +1,8 @@ #include "object.hpp" #include +#include +#include #include #include @@ -11,6 +13,7 @@ #include #include #include +#include #include @@ -28,7 +31,9 @@ #include #include #include +#include +#include "actor.hpp" #include "mask.hpp" @@ -84,6 +89,7 @@ void CSVRender::Object::update() const CSMWorld::RefIdCollection& referenceables = mData.getReferenceables(); int index = referenceables.searchId (mReferenceableId); + int recordType = -1; const ESM::Light* light = NULL; if (index==-1) @@ -96,7 +102,7 @@ void CSVRender::Object::update() referenceables.findColumnIndex (CSMWorld::Columns::ColumnId_Model)). toString().toUtf8().constData(); - int recordType = + recordType = referenceables.getData (index, referenceables.findColumnIndex(CSMWorld::Columns::ColumnId_RecordType)).toInt(); if (recordType == CSMWorld::UniversalId::Type_Light) @@ -112,7 +118,7 @@ void CSVRender::Object::update() model = "marker_creature.nif"; } - if (model.empty()) + if (recordType != CSMWorld::UniversalId::Type_Npc && model.empty()) error = 2; } @@ -126,9 +132,18 @@ void CSVRender::Object::update() { try { - std::string path = "meshes\\" + model; - - mResourceSystem->getSceneManager()->getInstance(path, mBaseNode); + if (recordType == CSMWorld::UniversalId::Type_Npc) + { + std::cout << "recordType: Npc\n"; + Actor actor(mReferenceableId, recordType, mData); + actor.update(); + mBaseNode->addChild(actor.getBaseNode()); + } + else + { + std::string path = "meshes\\" + model; + mResourceSystem->getSceneManager()->getInstance(path, mBaseNode); + } } catch (std::exception& e) { diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 7410dbf03..e4a7c94b3 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -91,32 +91,6 @@ namespace std::vector > mToRemove; }; - class NodeMapVisitor : public osg::NodeVisitor - { - public: - typedef std::map > NodeMap; - - NodeMapVisitor(NodeMap& map) - : osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN) - , mMap(map) - {} - - void apply(osg::MatrixTransform& trans) - { - // Take transformation for first found node in file - const std::string nodeName = Misc::StringUtils::lowerCase(trans.getName()); - if (mMap.find(nodeName) == mMap.end()) - { - mMap[nodeName] = &trans; - } - - traverse(trans); - } - - private: - NodeMap& mMap; - }; - NifOsg::TextKeyMap::const_iterator findGroupStart(const NifOsg::TextKeyMap &keys, const std::string &groupname) { NifOsg::TextKeyMap::const_iterator iter(keys.begin()); @@ -468,7 +442,7 @@ namespace MWRender } if (mDone) return; - + // Set the starting time to measure glow duration from if this is a temporary glow if ((mDuration >= 0) && mStartingTime == 0) mStartingTime = nv->getFrameStamp()->getSimulationTime(); @@ -1042,7 +1016,7 @@ namespace MWRender { if (!mNodeMapCreated && mObjectRoot) { - NodeMapVisitor visitor(mNodeMap); + SceneUtil::NodeMapVisitor visitor(mNodeMap); mObjectRoot->accept(visitor); mNodeMapCreated = true; } @@ -1313,7 +1287,7 @@ namespace MWRender if(state.getTime() >= state.mLoopStopTime) break; - } + } if(timepassed <= 0.0f) break; @@ -1528,7 +1502,7 @@ namespace MWRender osg::ref_ptr glowUpdater = new GlowUpdater(texUnit, glowColor, textures, node, glowDuration, mResourceSystem); mGlowUpdater = glowUpdater; node->addUpdateCallback(glowUpdater); - + // set a texture now so that the ShaderVisitor can find it osg::ref_ptr writableStateSet = NULL; if (!node->getStateSet()) diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 2da7c80bf..e7e0ea0da 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -77,7 +77,7 @@ add_component_dir (esm loadweap records aipackage effectlist spelllist variant variantimp loadtes3 cellref filter savedgame journalentry queststate locals globalscript player objectstate cellid cellstate globalmap inventorystate containerstate npcstate creaturestate dialoguestate statstate npcstats creaturestats weatherstate quickkeys fogstate spellstate activespells creaturelevliststate doorstate projectilestate debugprofile - aisequence magiceffects util custommarkerstate stolenitems transport animationstate controlsstate + aisequence magiceffects util custommarkerstate stolenitems transport animationstate controlsstate mappings ) add_component_dir (esmterrain diff --git a/components/esm/mappings.cpp b/components/esm/mappings.cpp new file mode 100644 index 000000000..440e73573 --- /dev/null +++ b/components/esm/mappings.cpp @@ -0,0 +1,134 @@ +#include "mappings.hpp" + +#include + +namespace ESM +{ + ESM::BodyPart::MeshPart getMeshPart(ESM::PartReferenceType type) + { + switch(type) + { + case ESM::PRT_Head: + return ESM::BodyPart::MP_Head; + case ESM::PRT_Hair: + return ESM::BodyPart::MP_Hair; + case ESM::PRT_Neck: + return ESM::BodyPart::MP_Neck; + case ESM::PRT_Cuirass: + return ESM::BodyPart::MP_Chest; + case ESM::PRT_Groin: + return ESM::BodyPart::MP_Groin; + case ESM::PRT_RHand: + return ESM::BodyPart::MP_Hand; + case ESM::PRT_LHand: + return ESM::BodyPart::MP_Hand; + case ESM::PRT_RWrist: + return ESM::BodyPart::MP_Wrist; + case ESM::PRT_LWrist: + return ESM::BodyPart::MP_Wrist; + case ESM::PRT_RForearm: + return ESM::BodyPart::MP_Forearm; + case ESM::PRT_LForearm: + return ESM::BodyPart::MP_Forearm; + case ESM::PRT_RUpperarm: + return ESM::BodyPart::MP_Upperarm; + case ESM::PRT_LUpperarm: + return ESM::BodyPart::MP_Upperarm; + case ESM::PRT_RFoot: + return ESM::BodyPart::MP_Foot; + case ESM::PRT_LFoot: + return ESM::BodyPart::MP_Foot; + case ESM::PRT_RAnkle: + return ESM::BodyPart::MP_Ankle; + case ESM::PRT_LAnkle: + return ESM::BodyPart::MP_Ankle; + case ESM::PRT_RKnee: + return ESM::BodyPart::MP_Knee; + case ESM::PRT_LKnee: + return ESM::BodyPart::MP_Knee; + case ESM::PRT_RLeg: + return ESM::BodyPart::MP_Upperleg; + case ESM::PRT_LLeg: + return ESM::BodyPart::MP_Upperleg; + case ESM::PRT_Tail: + return ESM::BodyPart::MP_Tail; + default: + throw std::runtime_error("PartReferenceType " + + std::to_string(type) + " not associated with a mesh part"); + } + } + + std::string getBoneName(ESM::PartReferenceType type) + { + switch(type) + { + case ESM::PRT_Head: + return "head"; + case ESM::PRT_Hair: + return "head"; // This is purposeful. + case ESM::PRT_Neck: + return "neck"; + case ESM::PRT_Cuirass: + return "chest"; + case ESM::PRT_Groin: + return "groin"; + case ESM::PRT_Skirt: + return "groin"; + case ESM::PRT_RHand: + return "right hand"; + case ESM::PRT_LHand: + return "left hand"; + case ESM::PRT_RWrist: + return "right wrist"; + case ESM::PRT_LWrist: + return "left wrist"; + case ESM::PRT_Shield: + return "shield bone"; + case ESM::PRT_RForearm: + return "right forearm"; + case ESM::PRT_LForearm: + return "left forearm"; + case ESM::PRT_RUpperarm: + return "right upper arm"; + case ESM::PRT_LUpperarm: + return "left upper arm"; + case ESM::PRT_RFoot: + return "right foot"; + case ESM::PRT_LFoot: + return "left foot"; + case ESM::PRT_RAnkle: + return "right ankle"; + case ESM::PRT_LAnkle: + return "left ankle"; + case ESM::PRT_RKnee: + return "right knee"; + case ESM::PRT_LKnee: + return "left knee"; + case ESM::PRT_RLeg: + return "right upper leg"; + case ESM::PRT_LLeg: + return "left upper leg"; + case ESM::PRT_RPauldron: + return "right clavicle"; + case ESM::PRT_LPauldron: + return "left clavicle"; + case ESM::PRT_Weapon: + return "weapon bone"; + case ESM::PRT_Tail: + return "tail"; + default: + throw std::runtime_error("unknown PartReferenceType"); + } + } + + std::string getMeshFilter(ESM::PartReferenceType type) + { + switch(type) + { + case ESM::PRT_Hair: + return "hair"; + default: + return getBoneName(type); + } + } +} diff --git a/components/esm/mappings.hpp b/components/esm/mappings.hpp new file mode 100644 index 000000000..f930fef15 --- /dev/null +++ b/components/esm/mappings.hpp @@ -0,0 +1,16 @@ +#ifndef OPENMW_ESM_MAPPINGS_H +#define OPENMW_ESM_MAPPINGS_H + +#include + +#include +#include + +namespace ESM +{ + ESM::BodyPart::MeshPart getMeshPart(ESM::PartReferenceType type); + std::string getBoneName(ESM::PartReferenceType type); + std::string getMeshFilter(ESM::PartReferenceType type); +} + +#endif diff --git a/components/sceneutil/visitor.cpp b/components/sceneutil/visitor.cpp index 2f6123e34..5aaeb459e 100644 --- a/components/sceneutil/visitor.cpp +++ b/components/sceneutil/visitor.cpp @@ -1,5 +1,6 @@ #include "visitor.hpp" +#include #include #include @@ -23,7 +24,7 @@ namespace SceneUtil { if (Misc::StringUtils::ciEqual(node.className(), mNameToFind)) mFoundNodes.push_back(&node); - + traverse(node); } @@ -54,4 +55,20 @@ namespace SceneUtil partsys->setFreezeOnCull(false); } + void NodeMapVisitor::apply(osg::MatrixTransform& trans) + { + // Take transformation for first found node in file + const std::string nodeName = Misc::StringUtils::lowerCase(trans.getName()); + if (mMap.find(nodeName) == mMap.end()) + { + mMap[nodeName] = &trans; + } + + traverse(trans); + } + + void HideDrawablesVisitor::apply(osg::Drawable& drawable) + { + drawable.setNodeMask(0); + } } diff --git a/components/sceneutil/visitor.hpp b/components/sceneutil/visitor.hpp index 265fd6d02..bd3945296 100644 --- a/components/sceneutil/visitor.hpp +++ b/components/sceneutil/visitor.hpp @@ -1,6 +1,7 @@ #ifndef OPENMW_COMPONENTS_SCENEUTIL_VISITOR_H #define OPENMW_COMPONENTS_SCENEUTIL_VISITOR_H +#include #include // Commonly used scene graph visitors @@ -58,6 +59,35 @@ namespace SceneUtil virtual void apply(osg::Drawable& drw); }; + /// Maps names to nodes + class NodeMapVisitor : public osg::NodeVisitor + { + public: + typedef std::map > NodeMap; + + NodeMapVisitor(NodeMap& map) + : osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN) + , mMap(map) + {} + + void apply(osg::MatrixTransform& trans); + + private: + NodeMap& mMap; + }; + + /// Hides all attached drawables + class HideDrawablesVisitor : public osg::NodeVisitor + { + public: + HideDrawablesVisitor() + : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) + { + } + + void apply(osg::Drawable& drawable) override; + }; + } #endif From e2ac392a4076c09aeb42d4a1f9213c83cb6d46ad Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Tue, 17 Jul 2018 21:28:05 -0500 Subject: [PATCH 162/196] Move common stuff to scene util, fix errors with 1st person meshes --- apps/opencs/view/render/actor.cpp | 247 ++++++++++++-------------- apps/openmw/mwrender/animation.cpp | 4 +- apps/openmw/mwrender/npcanimation.cpp | 33 +--- components/CMakeLists.txt | 1 + components/sceneutil/actorutil.cpp | 30 ++++ components/sceneutil/actorutil.hpp | 11 ++ components/sceneutil/visitor.cpp | 89 +++++++++- components/sceneutil/visitor.hpp | 40 ++++- 8 files changed, 290 insertions(+), 165 deletions(-) create mode 100644 components/sceneutil/actorutil.cpp create mode 100644 components/sceneutil/actorutil.hpp diff --git a/apps/opencs/view/render/actor.cpp b/apps/opencs/view/render/actor.cpp index 1273b94c6..93fff270a 100644 --- a/apps/opencs/view/render/actor.cpp +++ b/apps/opencs/view/render/actor.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -45,152 +46,140 @@ namespace CSVRender // Remove children mBaseNode->removeChildren(0, mBaseNode->getNumChildren()); - // Npcs and creatures are handled differently - if (mType == CSMWorld::UniversalId::Type_Npc) + try { - auto& npc = dynamic_cast& >(referenceables.getRecord(mId)).get(); - - auto isBeast = [&](std::string race) -> bool { - int index = races.searchId(race); - if (index != -1 && !races.getRecord(index).isDeleted()) - return races.getRecord(index).get().mData.mFlags & ESM::Race::Beast; - else - return false; - }; - - // Load skeleton - std::string skeletonResource; - if (isBeast(npc.mRace)) { - std::cout << "is beast\n"; - skeletonResource = "base_animkna.nif"; - } - else if (npc.isMale()) { - std::cout << "is male\n"; - skeletonResource = "base_anim.nif"; - } - else { - std::cout << "is female\n"; - skeletonResource = "base_anim_female.nif"; - } - - std::string skeletonModel = MeshPrefix + skeletonResource; - skeletonModel = Misc::ResourceHelpers::correctActorModelPath(skeletonModel, mData.getResourceSystem()->getVFS()); + // Npcs and creatures are handled differently + if (mType == CSMWorld::UniversalId::Type_Npc) { - osg::ref_ptr temp = sceneMgr->getInstance(skeletonModel); - mSkeleton = dynamic_cast(temp.get()); - if (!mSkeleton) + auto& npc = dynamic_cast& >(referenceables.getRecord(mId)).get(); + auto& race = dynamic_cast& >(races.getRecord(npc.mRace)).get(); + + bool is1stPerson = false; + bool isFemale = !npc.isMale(); + bool isBeast = race.mData.mFlags & ESM::Race::Beast; + bool isWerewolf = false; + + // Load skeleton + std::string skeletonModel = SceneUtil::getActorSkeleton(is1stPerson, isFemale, isBeast, isWerewolf); + skeletonModel = Misc::ResourceHelpers::correctActorModelPath(skeletonModel, mData.getResourceSystem()->getVFS()); { - mSkeleton = new SceneUtil::Skeleton(); - mSkeleton->addChild(temp); - } - mBaseNode->addChild(mSkeleton); - } - - // Map bone names to bones - SceneUtil::NodeMapVisitor::NodeMap nodeMap; - SceneUtil::NodeMapVisitor nmVisitor(nodeMap); - mSkeleton->accept(nmVisitor); - - if (!npc.isMale()) { - for (auto it : nodeMap) { - std::cout << it.first << "\n"; - } - } - - - // Female mesh has some drawables attached, get rid of them - SceneUtil::HideDrawablesVisitor hdVisitor; - mSkeleton->accept(hdVisitor); - - // Convenience method to retrieve the mesh name of a body part - auto getBodyPartMesh = [&](std::string bpName) -> std::string { - int index = bodyParts.searchId(bpName); - if (index != -1 && !bodyParts.getRecord(index).isDeleted()) - return MeshPrefix + bodyParts.getRecord(index).get().mModel; - else - return ""; - }; - - using BPRaceKey = std::tuple; - using RaceToBPMap = std::map; - // Convenience method to generate a map from body part + race to mesh name - auto genRaceToBodyPartMap = [&](RaceToBPMap& bpMap) { - int size = bodyParts.getSize(); - for (int i = 0; i < size; ++i) - { - auto& record = bodyParts.getRecord(i); - if (!record.isDeleted()) + osg::ref_ptr temp = sceneMgr->getInstance(skeletonModel); + mSkeleton = dynamic_cast(temp.get()); + if (!mSkeleton) { - auto& bodyPart = record.get(); - bpMap.emplace( - BPRaceKey(bodyPart.mData.mPart, bodyPart.mData.mFlags & FemaleFlag ? 1 : 0, bodyPart.mRace), - MeshPrefix + bodyPart.mModel); + mSkeleton = new SceneUtil::Skeleton(); + mSkeleton->addChild(temp); } + mBaseNode->addChild(mSkeleton); } - }; - // Generate mapping - RaceToBPMap r2bpMap; - genRaceToBodyPartMap(r2bpMap); + // Map bone names to bones + SceneUtil::NodeMapVisitor::NodeMap nodeMap; + SceneUtil::NodeMapVisitor nmVisitor(nodeMap); + mSkeleton->accept(nmVisitor); - // Convenience method to add a body part - auto addBodyPart = [&](ESM::PartReferenceType type, std::string mesh) { - // Retrieve mesh name if necessary - if (mesh.empty()) - { - auto meshResult = r2bpMap.find(BPRaceKey(ESM::getMeshPart(type), npc.isMale() ? 0 : 1, npc.mRace)); - if (meshResult != r2bpMap.end()) + // Female mesh has some drawables attached, get rid of them + SceneUtil::CleanObjectRootVisitor cleanVisitor; + mSkeleton->accept(cleanVisitor); + cleanVisitor.remove(); + + // Convenience method to retrieve the mesh name of a body part + auto getBodyPartMesh = [&](std::string bpName) -> std::string { + int index = bodyParts.searchId(bpName); + if (index != -1 && !bodyParts.getRecord(index).isDeleted()) + return MeshPrefix + bodyParts.getRecord(index).get().mModel; + else + return ""; + }; + + using BPRaceKey = std::tuple; + using RaceToBPMap = std::map; + // Convenience method to generate a map from body part + race to mesh name + auto genRaceToBodyPartMap = [&](RaceToBPMap& bpMap) { + int size = bodyParts.getSize(); + for (int i = 0; i < size; ++i) { - mesh = meshResult->second; - } - } + auto& record = bodyParts.getRecord(i); + if (!record.isDeleted()) + { + // Method to check if 1st person part or not + auto is1stPersonPart = [](std::string name) { + return name.size() >= 4 && name.find(".1st", name.size() - 4) != std::string::npos; + }; - // Attach to skeleton - std::string boneName = ESM::getBoneName(type); - auto node = nodeMap.find(boneName); - if (!mesh.empty() && node != nodeMap.end()) - { - auto instance = sceneMgr->getInstance(mesh); - if (!npc.isMale() && type == ESM::PRT_LHand) { - SceneUtil::NodeMapVisitor::NodeMap handNodeMap; - SceneUtil::NodeMapVisitor nmVisitor(handNodeMap); - instance->accept(nmVisitor); + auto& bodyPart = record.get(); + if (bodyPart.mData.mType != ESM::BodyPart::MT_Skin || is1stPersonPart(bodyPart.mId)) + continue; - std::cout << "Left hand\n"; - for (auto it : handNodeMap) { - std::cout << it.first << std::endl; + bpMap.emplace( + BPRaceKey(bodyPart.mData.mPart, bodyPart.mData.mFlags & FemaleFlag ? 1 : 0, bodyPart.mRace), + MeshPrefix + bodyPart.mModel); } } - SceneUtil::attach(instance, mSkeleton, boneName, node->second); - } - }; + }; - // Add body parts - for (unsigned int i = 0; i < ESM::PRT_Count; ++i) - { - auto part = static_cast(i); - switch (part) + // Generate mapping + RaceToBPMap r2bpMap; + genRaceToBodyPartMap(r2bpMap); + + // Convenience method to add a body part + auto addBodyPart = [&](ESM::PartReferenceType type, std::string mesh) { + // Retrieve mesh name if necessary + if (mesh.empty()) + { + auto meshResult = r2bpMap.find(BPRaceKey(ESM::getMeshPart(type), isFemale ? 1 : 0, npc.mRace)); + if (meshResult != r2bpMap.end()) + { + mesh = meshResult->second; + } + else if (isFemale){ + meshResult = r2bpMap.find(BPRaceKey(ESM::getMeshPart(type), 0, npc.mRace)); + if (meshResult != r2bpMap.end()) + mesh = meshResult->second; + } + } + + // Attach to skeleton + std::string boneName = ESM::getBoneName(type); + auto node = nodeMap.find(boneName); + if (!mesh.empty() && node != nodeMap.end()) + { + auto instance = sceneMgr->getInstance(mesh); + SceneUtil::attach(instance, mSkeleton, boneName, node->second); + } + }; + + // Add body parts + for (unsigned int i = 0; i < ESM::PRT_Count; ++i) { - case ESM::PRT_Head: - addBodyPart(part, getBodyPartMesh(npc.mHead)); - break; - case ESM::PRT_Hair: - addBodyPart(part, getBodyPartMesh(npc.mHair)); - break; - case ESM::PRT_Skirt: - case ESM::PRT_Shield: - case ESM::PRT_RPauldron: - case ESM::PRT_LPauldron: - case ESM::PRT_Weapon: - // No body part mesh associated - break; - default: - addBodyPart(part, ""); + auto part = static_cast(i); + switch (part) + { + case ESM::PRT_Head: + addBodyPart(part, getBodyPartMesh(npc.mHead)); + break; + case ESM::PRT_Hair: + addBodyPart(part, getBodyPartMesh(npc.mHair)); + break; + case ESM::PRT_Skirt: + case ESM::PRT_Shield: + case ESM::PRT_RPauldron: + case ESM::PRT_LPauldron: + case ESM::PRT_Weapon: + // No body part mesh associated + break; + default: + addBodyPart(part, ""); + } } + // Post setup + mSkeleton->markDirty(); + mSkeleton->setActive(SceneUtil::Skeleton::Active); } - // Post setup - mSkeleton->markDirty(); - mSkeleton->setActive(SceneUtil::Skeleton::Active); + } + catch (std::exception& e) + { + std::cout << "Caught exception: " << e.what() << std::endl; } } } diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index e4a7c94b3..484f90ab5 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -1339,7 +1339,7 @@ namespace MWRender { osg::ref_ptr created = sceneMgr->getInstance(model); - CleanObjectRootVisitor removeDrawableVisitor; + SceneUtil::CleanObjectRootVisitor removeDrawableVisitor; created->accept(removeDrawableVisitor); removeDrawableVisitor.remove(); @@ -1408,7 +1408,7 @@ namespace MWRender if (isCreature) { - RemoveTriBipVisitor removeTriBipVisitor; + SceneUtil::RemoveTriBipVisitor removeTriBipVisitor; mObjectRoot->accept(removeTriBipVisitor); removeTriBipVisitor.remove(); } diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 98f8ce892..2716ea19b 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -15,6 +15,7 @@ #include #include +#include #include #include #include @@ -304,7 +305,7 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, osg::ref_ptr par void NpcAnimation::setViewMode(NpcAnimation::ViewMode viewMode) { assert(viewMode != VM_HeadOnly); - if(mViewMode == viewMode) + if(mViewMode == viewMode) return; mViewMode = viewMode; @@ -451,37 +452,15 @@ void NpcAnimation::updateNpcBase() } } + bool is1stPerson = mViewMode == VM_FirstPerson; bool isBeast = (race->mData.mFlags & ESM::Race::Beast) != 0; - std::string smodel; - if (mViewMode != VM_FirstPerson) - { - if (isWerewolf) - smodel = "meshes\\wolf\\skin.nif"; - else if (isBeast) - smodel = "meshes\\base_animkna.nif"; - else if (isFemale) - smodel = "meshes\\base_anim_female.nif"; - else - smodel = "meshes\\base_anim.nif"; - } - else - { - if (isWerewolf) - smodel = "meshes\\wolf\\skin.1st.nif"; - else if (isBeast) - smodel = "meshes\\base_animkna.1st.nif"; - else if (isFemale) - smodel = "meshes\\base_anim_female.1st.nif"; - else - smodel = "meshes\\base_anim.1st.nif"; - } - + std::string smodel = SceneUtil::getActorSkeleton(is1stPerson, isFemale, isBeast, isWerewolf); smodel = Misc::ResourceHelpers::correctActorModelPath(smodel, mResourceSystem->getVFS()); setObjectRoot(smodel, true, true, false); - if(mViewMode != VM_FirstPerson) + if(!is1stPerson) { const std::string base = "meshes\\xbase_anim.nif"; if (smodel != base) @@ -675,7 +654,7 @@ PartHolderPtr NpcAnimation::insertBoundedPart(const std::string& model, const st } osg::Vec3f NpcAnimation::runAnimation(float timepassed) -{ +{ osg::Vec3f ret = Animation::runAnimation(timepassed); mHeadAnimationTime->update(timepassed); diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index e7e0ea0da..7af76137c 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -51,6 +51,7 @@ add_component_dir (shader add_component_dir (sceneutil clone attach visitor util statesetupdater controller skeleton riggeometry morphgeometry lightcontroller lightmanager lightutil positionattitudetransform workqueue unrefqueue pathgridutil waterutil writescene serialize optimizer + actorutil ) add_component_dir (nif diff --git a/components/sceneutil/actorutil.cpp b/components/sceneutil/actorutil.cpp new file mode 100644 index 000000000..988a61f60 --- /dev/null +++ b/components/sceneutil/actorutil.cpp @@ -0,0 +1,30 @@ +#include "actorutil.hpp" + +namespace SceneUtil +{ + std::string getActorSkeleton(bool firstPerson, bool isFemale, bool isBeast, bool isWerewolf) + { + if (!firstPerson) + { + if (isWerewolf) + return "meshes\\wolf\\skin.nif"; + else if (isBeast) + return "meshes\\base_animkna.nif"; + else if (isFemale) + return "meshes\\base_anim_female.nif"; + else + return "meshes\\base_anim.nif"; + } + else + { + if (isWerewolf) + return "meshes\\wolf\\skin.1st.nif"; + else if (isBeast) + return "meshes\\base_animkna.1st.nif"; + else if (isFemale) + return "meshes\\base_anim_female.1st.nif"; + else + return "meshes\\base_anim.1st.nif"; + } + } +} diff --git a/components/sceneutil/actorutil.hpp b/components/sceneutil/actorutil.hpp new file mode 100644 index 000000000..7bdbbaa92 --- /dev/null +++ b/components/sceneutil/actorutil.hpp @@ -0,0 +1,11 @@ +#ifndef OPENMW_COMPONENTS_SCENEUTIL_ACTORUTIL_HPP +#define OPENMW_COMPONENTS_SCENEUTIL_ACTORUTIL_HPP + +#include + +namespace SceneUtil +{ + std::string getActorSkeleton(bool firstPerson, bool female, bool beast, bool werewolf); +} + +#endif diff --git a/components/sceneutil/visitor.cpp b/components/sceneutil/visitor.cpp index 5aaeb459e..07be1608e 100644 --- a/components/sceneutil/visitor.cpp +++ b/components/sceneutil/visitor.cpp @@ -1,5 +1,7 @@ #include "visitor.hpp" +#include + #include #include @@ -67,8 +69,91 @@ namespace SceneUtil traverse(trans); } - void HideDrawablesVisitor::apply(osg::Drawable& drawable) + void RemoveVisitor::remove() { - drawable.setNodeMask(0); + for (RemoveVec::iterator it = mToRemove.begin(); it != mToRemove.end(); ++it) + { + if (!it->second->removeChild(it->first)) + std::cerr << "error removing " << it->first->getName() << std::endl; + } + } + + void CleanObjectRootVisitor::apply(osg::Drawable& drw) + { + applyDrawable(drw); + } + + void CleanObjectRootVisitor::apply(osg::Group& node) + { + applyNode(node); + } + + void CleanObjectRootVisitor::apply(osg::MatrixTransform& node) + { + applyNode(node); + } + + void CleanObjectRootVisitor::apply(osg::Node& node) + { + applyNode(node); + } + + void CleanObjectRootVisitor::applyNode(osg::Node& node) + { + if (node.getStateSet()) + node.setStateSet(NULL); + + if (node.getNodeMask() == 0x1 && node.getNumParents() == 1) + mToRemove.push_back(std::make_pair(&node, node.getParent(0))); + else + traverse(node); + } + + void CleanObjectRootVisitor::applyDrawable(osg::Node& node) + { + osg::NodePath::iterator parent = getNodePath().end()-2; + // We know that the parent is a Group because only Groups can have children. + osg::Group* parentGroup = static_cast(*parent); + + // Try to prune nodes that would be empty after the removal + if (parent != getNodePath().begin()) + { + // This could be extended to remove the parent's parent, and so on if they are empty as well. + // But for NIF files, there won't be a benefit since only TriShapes can be set to STATIC dataVariance. + osg::Group* parentParent = static_cast(*(parent - 1)); + if (parentGroup->getNumChildren() == 1 && parentGroup->getDataVariance() == osg::Object::STATIC) + { + mToRemove.push_back(std::make_pair(parentGroup, parentParent)); + return; + } + } + + mToRemove.push_back(std::make_pair(&node, parentGroup)); + } + + void RemoveTriBipVisitor::apply(osg::Drawable& drw) + { + applyImpl(drw); + } + + void RemoveTriBipVisitor::apply(osg::Group& node) + { + traverse(node); + } + + void RemoveTriBipVisitor::apply(osg::MatrixTransform& node) + { + traverse(node); + } + + void RemoveTriBipVisitor::applyImpl(osg::Node& node) + { + const std::string toFind = "tri bip"; + if (Misc::StringUtils::ciCompareLen(node.getName(), toFind, toFind.size()) == 0) + { + osg::Group* parent = static_cast(*(getNodePath().end()-2)); + // Not safe to remove in apply(), since the visitor is still iterating the child list + mToRemove.push_back(std::make_pair(&node, parent)); + } } } diff --git a/components/sceneutil/visitor.hpp b/components/sceneutil/visitor.hpp index bd3945296..3e9a565c0 100644 --- a/components/sceneutil/visitor.hpp +++ b/components/sceneutil/visitor.hpp @@ -68,7 +68,8 @@ namespace SceneUtil NodeMapVisitor(NodeMap& map) : osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN) , mMap(map) - {} + { + } void apply(osg::MatrixTransform& trans); @@ -76,18 +77,47 @@ namespace SceneUtil NodeMap& mMap; }; - /// Hides all attached drawables - class HideDrawablesVisitor : public osg::NodeVisitor + /// @brief Base class for visitors that remove nodes from a scene graph. + /// Subclasses need to fill the mToRemove vector. + /// To use, node->accept(removeVisitor); removeVisitor.remove(); + class RemoveVisitor : public osg::NodeVisitor { public: - HideDrawablesVisitor() + RemoveVisitor() : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) { } - void apply(osg::Drawable& drawable) override; + void remove(); + + protected: + // + typedef std::vector > RemoveVec; + std::vector > mToRemove; }; + // Removes all drawables from a graph. + class CleanObjectRootVisitor : public RemoveVisitor + { + public: + virtual void apply(osg::Drawable& drw); + virtual void apply(osg::Group& node); + virtual void apply(osg::MatrixTransform& node); + virtual void apply(osg::Node& node); + + void applyNode(osg::Node& node); + void applyDrawable(osg::Node& node); + }; + + class RemoveTriBipVisitor : public RemoveVisitor + { + public: + virtual void apply(osg::Drawable& drw); + virtual void apply(osg::Group& node); + virtual void apply(osg::MatrixTransform& node); + + void applyImpl(osg::Node& node); + }; } #endif From 6b42f37918271cdd41000e141e8f597b69b82f5b Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Sun, 22 Jul 2018 15:38:30 -0500 Subject: [PATCH 163/196] Handle creatures too --- apps/opencs/view/render/actor.cpp | 284 ++++++++++++++++------------- apps/opencs/view/render/actor.hpp | 8 + apps/opencs/view/render/object.cpp | 5 +- 3 files changed, 167 insertions(+), 130 deletions(-) diff --git a/apps/opencs/view/render/actor.cpp b/apps/opencs/view/render/actor.cpp index 93fff270a..3691085e3 100644 --- a/apps/opencs/view/render/actor.cpp +++ b/apps/opencs/view/render/actor.cpp @@ -18,6 +18,8 @@ namespace CSVRender { + const std::string Actor::MeshPrefix = "meshes\\"; + Actor::Actor(const std::string& id, int type, CSMWorld::Data& data) : mId(id) , mType(type) @@ -34,7 +36,42 @@ namespace CSVRender void Actor::update() { - const std::string MeshPrefix = "meshes\\"; + try + { + mBaseNode->removeChildren(0, mBaseNode->getNumChildren()); + + if (mType == CSMWorld::UniversalId::Type_Npc) + updateNpc(); + else if (mType == CSMWorld::UniversalId::Type_Creature) + updateCreature(); + } + catch (std::exception& e) + { + std::cout << "Caught exception: " << e.what() << std::endl; + } + } + + void Actor::updateCreature() + { + auto& referenceables = mData.getReferenceables(); + + auto& creature = dynamic_cast& >(referenceables.getRecord(mId)).get(); + + std::string skeletonModel = MeshPrefix + creature.mModel; + skeletonModel = Misc::ResourceHelpers::correctActorModelPath(skeletonModel, mData.getResourceSystem()->getVFS()); + loadSkeleton(skeletonModel); + + SceneUtil::RemoveTriBipVisitor removeTriBipVisitor; + mSkeleton->accept(removeTriBipVisitor); + removeTriBipVisitor.remove(); + + // Post setup + mSkeleton->markDirty(); + mSkeleton->setActive(SceneUtil::Skeleton::Active); + } + + void Actor::updateNpc() + { const unsigned int FemaleFlag = ESM::BodyPart::BPF_Female; auto& bodyParts = mData.getBodyParts(); @@ -42,144 +79,137 @@ namespace CSVRender auto& referenceables = mData.getReferenceables(); auto sceneMgr = mData.getResourceSystem()->getSceneManager(); + auto& npc = dynamic_cast& >(referenceables.getRecord(mId)).get(); + auto& race = dynamic_cast& >(races.getRecord(npc.mRace)).get(); - // Remove children - mBaseNode->removeChildren(0, mBaseNode->getNumChildren()); + bool is1stPerson = false; + bool isFemale = !npc.isMale(); + bool isBeast = race.mData.mFlags & ESM::Race::Beast; + bool isWerewolf = false; - try - { - // Npcs and creatures are handled differently - if (mType == CSMWorld::UniversalId::Type_Npc) + // Load skeleton + std::string skeletonModel = SceneUtil::getActorSkeleton(is1stPerson, isFemale, isBeast, isWerewolf); + skeletonModel = Misc::ResourceHelpers::correctActorModelPath(skeletonModel, mData.getResourceSystem()->getVFS()); + loadSkeleton(skeletonModel); + + // Get rid of the extra attachments + SceneUtil::CleanObjectRootVisitor cleanVisitor; + mSkeleton->accept(cleanVisitor); + cleanVisitor.remove(); + + // Map bone names to bones + SceneUtil::NodeMapVisitor::NodeMap nodeMap; + SceneUtil::NodeMapVisitor nmVisitor(nodeMap); + mSkeleton->accept(nmVisitor); + + using BPRaceKey = std::tuple; + using RaceToBPMap = std::map; + // Convenience method to generate a map from body part + race to mesh name + auto genRaceToBodyPartMap = [&](RaceToBPMap& bpMap) { + int size = bodyParts.getSize(); + for (int i = 0; i < size; ++i) { - auto& npc = dynamic_cast& >(referenceables.getRecord(mId)).get(); - auto& race = dynamic_cast& >(races.getRecord(npc.mRace)).get(); - - bool is1stPerson = false; - bool isFemale = !npc.isMale(); - bool isBeast = race.mData.mFlags & ESM::Race::Beast; - bool isWerewolf = false; - - // Load skeleton - std::string skeletonModel = SceneUtil::getActorSkeleton(is1stPerson, isFemale, isBeast, isWerewolf); - skeletonModel = Misc::ResourceHelpers::correctActorModelPath(skeletonModel, mData.getResourceSystem()->getVFS()); + auto& record = bodyParts.getRecord(i); + if (!record.isDeleted()) { - osg::ref_ptr temp = sceneMgr->getInstance(skeletonModel); - mSkeleton = dynamic_cast(temp.get()); - if (!mSkeleton) - { - mSkeleton = new SceneUtil::Skeleton(); - mSkeleton->addChild(temp); - } - mBaseNode->addChild(mSkeleton); + // Method to check if 1st person part or not + auto is1stPersonPart = [](std::string name) { + return name.size() >= 4 && name.find(".1st", name.size() - 4) != std::string::npos; + }; + + auto& bodyPart = record.get(); + if (bodyPart.mData.mType != ESM::BodyPart::MT_Skin || is1stPersonPart(bodyPart.mId)) + continue; + + bpMap.emplace( + BPRaceKey(bodyPart.mData.mPart, bodyPart.mData.mFlags & FemaleFlag ? 1 : 0, bodyPart.mRace), + MeshPrefix + bodyPart.mModel); } + } + }; - // Map bone names to bones - SceneUtil::NodeMapVisitor::NodeMap nodeMap; - SceneUtil::NodeMapVisitor nmVisitor(nodeMap); - mSkeleton->accept(nmVisitor); + // Generate mapping + RaceToBPMap r2bpMap; + genRaceToBodyPartMap(r2bpMap); - // Female mesh has some drawables attached, get rid of them - SceneUtil::CleanObjectRootVisitor cleanVisitor; - mSkeleton->accept(cleanVisitor); - cleanVisitor.remove(); - - // Convenience method to retrieve the mesh name of a body part - auto getBodyPartMesh = [&](std::string bpName) -> std::string { - int index = bodyParts.searchId(bpName); - if (index != -1 && !bodyParts.getRecord(index).isDeleted()) - return MeshPrefix + bodyParts.getRecord(index).get().mModel; - else - return ""; - }; - - using BPRaceKey = std::tuple; - using RaceToBPMap = std::map; - // Convenience method to generate a map from body part + race to mesh name - auto genRaceToBodyPartMap = [&](RaceToBPMap& bpMap) { - int size = bodyParts.getSize(); - for (int i = 0; i < size; ++i) - { - auto& record = bodyParts.getRecord(i); - if (!record.isDeleted()) - { - // Method to check if 1st person part or not - auto is1stPersonPart = [](std::string name) { - return name.size() >= 4 && name.find(".1st", name.size() - 4) != std::string::npos; - }; - - auto& bodyPart = record.get(); - if (bodyPart.mData.mType != ESM::BodyPart::MT_Skin || is1stPersonPart(bodyPart.mId)) - continue; - - bpMap.emplace( - BPRaceKey(bodyPart.mData.mPart, bodyPart.mData.mFlags & FemaleFlag ? 1 : 0, bodyPart.mRace), - MeshPrefix + bodyPart.mModel); - } - } - }; - - // Generate mapping - RaceToBPMap r2bpMap; - genRaceToBodyPartMap(r2bpMap); - - // Convenience method to add a body part - auto addBodyPart = [&](ESM::PartReferenceType type, std::string mesh) { - // Retrieve mesh name if necessary - if (mesh.empty()) - { - auto meshResult = r2bpMap.find(BPRaceKey(ESM::getMeshPart(type), isFemale ? 1 : 0, npc.mRace)); - if (meshResult != r2bpMap.end()) - { - mesh = meshResult->second; - } - else if (isFemale){ - meshResult = r2bpMap.find(BPRaceKey(ESM::getMeshPart(type), 0, npc.mRace)); - if (meshResult != r2bpMap.end()) - mesh = meshResult->second; - } - } - - // Attach to skeleton - std::string boneName = ESM::getBoneName(type); - auto node = nodeMap.find(boneName); - if (!mesh.empty() && node != nodeMap.end()) - { - auto instance = sceneMgr->getInstance(mesh); - SceneUtil::attach(instance, mSkeleton, boneName, node->second); - } - }; - - // Add body parts - for (unsigned int i = 0; i < ESM::PRT_Count; ++i) + // Convenience method to add a body part + auto addBodyPart = [&](ESM::PartReferenceType type, std::string mesh) { + // Retrieve mesh name if necessary + if (mesh.empty()) + { + auto meshResult = r2bpMap.find(BPRaceKey(ESM::getMeshPart(type), isFemale ? 1 : 0, npc.mRace)); + if (meshResult != r2bpMap.end()) { - auto part = static_cast(i); - switch (part) - { - case ESM::PRT_Head: - addBodyPart(part, getBodyPartMesh(npc.mHead)); - break; - case ESM::PRT_Hair: - addBodyPart(part, getBodyPartMesh(npc.mHair)); - break; - case ESM::PRT_Skirt: - case ESM::PRT_Shield: - case ESM::PRT_RPauldron: - case ESM::PRT_LPauldron: - case ESM::PRT_Weapon: - // No body part mesh associated - break; - default: - addBodyPart(part, ""); - } + mesh = meshResult->second; } - // Post setup - mSkeleton->markDirty(); - mSkeleton->setActive(SceneUtil::Skeleton::Active); + else if (isFemale){ + meshResult = r2bpMap.find(BPRaceKey(ESM::getMeshPart(type), 0, npc.mRace)); + if (meshResult != r2bpMap.end()) + mesh = meshResult->second; + } + } + + // Attach to skeleton + std::string boneName = ESM::getBoneName(type); + auto node = nodeMap.find(boneName); + if (!mesh.empty() && node != nodeMap.end()) + { + auto instance = sceneMgr->getInstance(mesh); + SceneUtil::attach(instance, mSkeleton, boneName, node->second); + } + }; + + // Add body parts + for (unsigned int i = 0; i < ESM::PRT_Count; ++i) + { + auto part = static_cast(i); + switch (part) + { + case ESM::PRT_Head: + addBodyPart(part, getBodyPartMesh(npc.mHead)); + break; + case ESM::PRT_Hair: + addBodyPart(part, getBodyPartMesh(npc.mHair)); + break; + case ESM::PRT_Skirt: + case ESM::PRT_Shield: + case ESM::PRT_RPauldron: + case ESM::PRT_LPauldron: + case ESM::PRT_Weapon: + // No body part mesh associated + break; + default: + addBodyPart(part, ""); } } - catch (std::exception& e) + + // Post setup + mSkeleton->markDirty(); + mSkeleton->setActive(SceneUtil::Skeleton::Active); + } + + void Actor::loadSkeleton(const std::string& model) + { + auto sceneMgr = mData.getResourceSystem()->getSceneManager(); + + osg::ref_ptr temp = sceneMgr->getInstance(model); + mSkeleton = dynamic_cast(temp.get()); + if (!mSkeleton) { - std::cout << "Caught exception: " << e.what() << std::endl; + mSkeleton = new SceneUtil::Skeleton(); + mSkeleton->addChild(temp); } + mBaseNode->addChild(mSkeleton); + } + + std::string Actor::getBodyPartMesh(const std::string& bodyPartId) + { + const auto& bodyParts = mData.getBodyParts(); + + int index = bodyParts.searchId(bodyPartId); + if (index != -1 && !bodyParts.getRecord(index).isDeleted()) + return MeshPrefix + bodyParts.getRecord(index).get().mModel; + else + return ""; } } diff --git a/apps/opencs/view/render/actor.hpp b/apps/opencs/view/render/actor.hpp index 10f4de558..b4e65ff2b 100644 --- a/apps/opencs/view/render/actor.hpp +++ b/apps/opencs/view/render/actor.hpp @@ -39,6 +39,14 @@ namespace CSVRender void update(); private: + void loadSkeleton(const std::string& model); + void updateCreature(); + void updateNpc(); + + std::string getBodyPartMesh(const std::string& bodyPartId); + + static const std::string MeshPrefix; + std::string mId; int mType; CSMWorld::Data& mData; diff --git a/apps/opencs/view/render/object.cpp b/apps/opencs/view/render/object.cpp index b8e171650..dbfd595b6 100644 --- a/apps/opencs/view/render/object.cpp +++ b/apps/opencs/view/render/object.cpp @@ -132,9 +132,8 @@ void CSVRender::Object::update() { try { - if (recordType == CSMWorld::UniversalId::Type_Npc) + if (recordType == CSMWorld::UniversalId::Type_Npc || recordType == CSMWorld::UniversalId::Type_Creature) { - std::cout << "recordType: Npc\n"; Actor actor(mReferenceableId, recordType, mData); actor.update(); mBaseNode->addChild(actor.getBaseNode()); @@ -147,8 +146,8 @@ void CSVRender::Object::update() } catch (std::exception& e) { - // TODO: use error marker mesh Log(Debug::Error) << e.what(); + mBaseNode->addChild(createErrorCube()); } } From 97ac0a92dd430c6a7b17a2b812fde52ecbc5b010 Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Sat, 28 Jul 2018 12:23:43 -0500 Subject: [PATCH 164/196] Move data handling out of rendering code, equip armor/clothes --- apps/opencs/CMakeLists.txt | 1 + apps/opencs/model/world/actoradapter.cpp | 242 +++++++++++++++++++++++ apps/opencs/model/world/actoradapter.hpp | 80 ++++++++ apps/opencs/model/world/data.cpp | 12 ++ apps/opencs/model/world/data.hpp | 7 + apps/opencs/view/render/actor.cpp | 129 ++++-------- apps/opencs/view/render/actor.hpp | 11 +- 7 files changed, 389 insertions(+), 93 deletions(-) create mode 100644 apps/opencs/model/world/actoradapter.cpp create mode 100644 apps/opencs/model/world/actoradapter.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 26713f925..999324c51 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -19,6 +19,7 @@ opencs_hdrs_noqt (model/doc opencs_units (model/world idtable idtableproxymodel regionmap data commanddispatcher idtablebase resourcetable nestedtableproxymodel idtree infotableproxymodel landtexturetableproxymodel + actoradapter ) diff --git a/apps/opencs/model/world/actoradapter.cpp b/apps/opencs/model/world/actoradapter.cpp new file mode 100644 index 000000000..249908bb0 --- /dev/null +++ b/apps/opencs/model/world/actoradapter.cpp @@ -0,0 +1,242 @@ +#include "actoradapter.hpp" + +#include + +#include +#include +#include +#include +#include + +#include "data.hpp" + +namespace CSMWorld +{ + ActorAdapter::ActorAdapter(CSMWorld::Data& data) + : mReferenceables(data.getReferenceables()) + , mRaces(data.getRaces()) + , mBodyParts(data.getBodyParts()) + { + connect(data.getTableModel(UniversalId::Type_Referenceable), SIGNAL(dataChanged(const QModelIndex&, const QModelIndex&)), + this, SLOT(handleReferenceableChanged(const QModelIndex&, const QModelIndex&))); + connect(data.getTableModel(UniversalId::Type_Race), SIGNAL(dataChanged(const QModelIndex&, const QModelIndex&)), + this, SLOT(handleRaceChanged(const QModelIndex&, const QModelIndex&))); + connect(data.getTableModel(UniversalId::Type_BodyPart), SIGNAL(dataChanged(const QModelIndex&, const QModelIndex&)), + this, SLOT(handleBodyPartChanged(const QModelIndex&, const QModelIndex&))); + } + + const ActorAdapter::ActorPartMap* ActorAdapter::getActorPartMap(const std::string& refId) + { + auto it = mActorPartMaps.find(refId); + if (it != mActorPartMaps.end()) + { + return &it->second; + } + else + { + updateActor(refId); + it = mActorPartMaps.find(refId); + if (it != mActorPartMaps.end()) + return &it->second; + } + + return nullptr; + } + + void ActorAdapter::handleReferenceableChanged(const QModelIndex& topLeft, const QModelIndex& botRight) + { + // TODO + } + + void ActorAdapter::handleRaceChanged(const QModelIndex& topLeft, const QModelIndex& botRight) + { + // TODO + } + + void ActorAdapter::handleBodyPartChanged(const QModelIndex& topLeft, const QModelIndex& botRight) + { + // TODO + } + + ActorAdapter::RacePartMap& ActorAdapter::getOrCreateRacePartMap(const std::string& raceId, bool isFemale) + { + auto key = std::make_pair(raceId, isFemale); + auto it = mRacePartMaps.find(key); + if (it != mRacePartMaps.end()) + { + return it->second; + } + else + { + // Create and find result + updateRaceParts(raceId); + return mRacePartMaps.find(key)->second; + } + } + + void ActorAdapter::updateRaceParts(const std::string& raceId) + { + // Convenience function to determine if part is for 1st person view + auto is1stPersonPart = [](std::string name) { + return name.size() >= 4 && name.find(".1st", name.size() - 4) != std::string::npos; + }; + + RacePartMap maleMap, femaleMap; + for (int i = 0; i < mBodyParts.getSize(); ++i) + { + auto& record = mBodyParts.getRecord(i); + if (!record.isDeleted() && record.get().mRace == raceId && record.get().mData.mType == ESM::BodyPart::MT_Skin && !is1stPersonPart(record.get().mId)) + { + auto& part = record.get(); + auto type = (ESM::BodyPart::MeshPart) part.mData.mPart; + // Note: Prefer the first part encountered for duplicates. emplace() does not overwrite + if (part.mData.mFlags & ESM::BodyPart::BPF_Female) + femaleMap.emplace(type, part.mId); + else + maleMap.emplace(type, part.mId); + } + } + + mRacePartMaps[std::make_pair(raceId, true)] = femaleMap; + mRacePartMaps[std::make_pair(raceId, false)] = maleMap; + } + + void ActorAdapter::updateActor(const std::string& refId) + { + int index = mReferenceables.searchId(refId); + if (index != -1) + { + int typeColumn = mReferenceables.findColumnIndex(CSMWorld::Columns::ColumnId_RecordType); + int recordType = mReferenceables.getData(index, typeColumn).toInt(); + if (recordType == CSMWorld::UniversalId::Type_Creature) + updateCreature(refId); + else if (recordType == CSMWorld::UniversalId::Type_Npc) + updateNpc(refId); + } + } + + void ActorAdapter::updateNpc(const std::string& refId) + { + auto& record = mReferenceables.getRecord(refId); + if (record.isDeleted()) + { + mActorPartMaps.erase(refId); + return; + } + + auto& npc = dynamic_cast&>(record).get(); + auto& femaleRacePartMap = getOrCreateRacePartMap(npc.mRace, true); + auto& maleRacePartMap = getOrCreateRacePartMap(npc.mRace, false); + + ActorPartMap npcMap; + + // Look at the npc's inventory first + for (auto& item : npc.mInventory.mList) + { + if (item.mCount > 0) + { + std::string itemId = item.mItem.toString(); + // Handle armor, weapons, and clothing + int index = mReferenceables.searchId(itemId); + if (index != -1 && !mReferenceables.getRecord(index).isDeleted()) + { + auto& itemRecord = mReferenceables.getRecord(index); + + int typeColumn = mReferenceables.findColumnIndex(CSMWorld::Columns::ColumnId_RecordType); + int recordType = mReferenceables.getData(index, typeColumn).toInt(); + if (recordType == CSMWorld::UniversalId::Type_Armor) + { + auto& armor = dynamic_cast&>(itemRecord).get(); + for (auto& part : armor.mParts.mParts) + { + std::string bodyPartId; + if (!npc.isMale()) + bodyPartId = part.mFemale; + if (bodyPartId.empty()) + bodyPartId = part.mMale; + + if (!bodyPartId.empty()) + npcMap.emplace(static_cast(part.mPart), bodyPartId); + } + } + else if (recordType == CSMWorld::UniversalId::Type_Clothing) + { + auto& clothing = dynamic_cast&>(itemRecord).get(); + for (auto& part : clothing.mParts.mParts) + { + std::string bodyPartId; + if (!npc.isMale()) + bodyPartId = part.mFemale; + if (bodyPartId.empty()) + bodyPartId = part.mMale; + + if (!bodyPartId.empty()) + npcMap.emplace(static_cast(part.mPart), bodyPartId); + } + } + else if (recordType == CSMWorld::UniversalId::Type_Weapon) + { + // TODO + } + } + } + } + + // Fill in the rest with body parts + for (int i = 0; i < ESM::PRT_Count; ++i) + { + auto type = static_cast(i); + if (npcMap.find(type) == npcMap.end()) + { + switch (type) + { + case ESM::PRT_Head: + npcMap.emplace(type, npc.mHead); + break; + case ESM::PRT_Hair: + npcMap.emplace(type, npc.mHair); + break; + case ESM::PRT_Skirt: + case ESM::PRT_Shield: + case ESM::PRT_RPauldron: + case ESM::PRT_LPauldron: + case ESM::PRT_Weapon: + // No body part associated + break; + default: + { + std::string bodyPartId; + // Check female map if applicable + if (!npc.isMale()) + { + auto partIt = femaleRacePartMap.find(ESM::getMeshPart(type)); + if (partIt != femaleRacePartMap.end()) + bodyPartId = partIt->second; + } + + // Check male map next + if (bodyPartId.empty() || npc.isMale()) + { + auto partIt = maleRacePartMap.find(ESM::getMeshPart(type)); + if (partIt != maleRacePartMap.end()) + bodyPartId = partIt->second; + } + + // Add to map + if (!bodyPartId.empty()) + { + npcMap.emplace(type, bodyPartId); + } + } + } + } + } + + mActorPartMaps[refId] = npcMap; + } + + void ActorAdapter::updateCreature(const std::string& refId) + { + // TODO + } +} diff --git a/apps/opencs/model/world/actoradapter.hpp b/apps/opencs/model/world/actoradapter.hpp new file mode 100644 index 000000000..2c94f9c2c --- /dev/null +++ b/apps/opencs/model/world/actoradapter.hpp @@ -0,0 +1,80 @@ +#ifndef CSM_WOLRD_ACTORADAPTER_H +#define CSM_WOLRD_ACTORADAPTER_H + +#include +#include +#include + +#include + +#include +#include + +#include "refidcollection.hpp" +#include "idcollection.hpp" + +namespace ESM +{ + struct Race; + enum PartReferenceType; +} + +namespace CSMWorld +{ + class Data; + + /// Quick and dirty hashing functor. + struct StringBoolPairHash + { + size_t operator()(const std::pair& value) const noexcept + { + auto stringHash = std::hash(); + return stringHash(value.first) + value.second; + } + }; + + class ActorAdapter : public QObject + { + Q_OBJECT + public: + + // Maps body part type to 'body part' id + using ActorPartMap = std::unordered_map; + // Maps mesh part type to 'body part' id + using RacePartMap = std::unordered_map; + + ActorAdapter(CSMWorld::Data& data); + + const ActorPartMap* getActorPartMap(const std::string& refId); + + signals: + + void actorChanged(const std::string& refId); + + public slots: + + void handleReferenceableChanged(const QModelIndex&, const QModelIndex&); + void handleRaceChanged(const QModelIndex&, const QModelIndex&); + void handleBodyPartChanged(const QModelIndex&, const QModelIndex&); + + private: + + RacePartMap& getOrCreateRacePartMap(const std::string& raceId, bool isFemale); + + void updateRaceParts(const std::string& raceId); + void updateActor(const std::string& refId); + void updateNpc(const std::string& refId); + void updateCreature(const std::string& refId); + + RefIdCollection& mReferenceables; + IdCollection& mRaces; + IdCollection& mBodyParts; + + // Key: referenceable id + std::unordered_map mActorPartMaps; + // Key: race id, is female + std::unordered_map, RacePartMap, StringBoolPairHash> mRacePartMaps; + }; +} + +#endif diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 053754943..f3f897a29 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -572,6 +572,8 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, bool fsStrict, const Files::Pat UniversalId::Type_Video); addModel (new IdTable (&mMetaData), UniversalId::Type_MetaData); + mActorAdapter.reset(new ActorAdapter(*this)); + mRefLoadCache.clear(); // clear here rather than startLoading() and continueLoading() for multiple content files } @@ -912,6 +914,16 @@ QAbstractItemModel *CSMWorld::Data::getTableModel (const CSMWorld::UniversalId& return iter->second; } +const CSMWorld::ActorAdapter* CSMWorld::Data::getActorAdapter() const +{ + return mActorAdapter.get(); +} + +CSMWorld::ActorAdapter* CSMWorld::Data::getActorAdapter() +{ + return mActorAdapter.get(); +} + void CSMWorld::Data::merge() { mGlobals.merge(); diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index 1b975f430..7c4d8885a 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -36,6 +36,7 @@ #include "../doc/stage.hpp" +#include "actoradapter.hpp" #include "idcollection.hpp" #include "nestedidcollection.hpp" #include "universalid.hpp" @@ -73,6 +74,7 @@ namespace ESM namespace CSMWorld { + class ActorAdapter; class ResourcesManager; class Resources; @@ -110,6 +112,7 @@ namespace CSMWorld RefCollection mRefs; IdCollection mFilters; Collection mMetaData; + std::unique_ptr mActorAdapter; const Fallback::Map* mFallbackMap; std::vector mModels; std::map mModelIndex; @@ -287,6 +290,10 @@ namespace CSMWorld /// \note The returned table may either be the model for the ID itself or the model that /// contains the record specified by the ID. + const ActorAdapter* getActorAdapter() const; + + ActorAdapter* getActorAdapter(); + void merge(); ///< Merge modified into base. diff --git a/apps/opencs/view/render/actor.cpp b/apps/opencs/view/render/actor.cpp index 3691085e3..b816c1504 100644 --- a/apps/opencs/view/render/actor.cpp +++ b/apps/opencs/view/render/actor.cpp @@ -12,7 +12,6 @@ #include #include #include -#include #include "../../model/world/data.hpp" @@ -24,8 +23,8 @@ namespace CSVRender : mId(id) , mType(type) , mData(data) - , mSkeleton(nullptr) , mBaseNode(new osg::Group()) + , mSkeleton(nullptr) { } @@ -57,6 +56,7 @@ namespace CSVRender auto& creature = dynamic_cast& >(referenceables.getRecord(mId)).get(); + // Load skeleton with meshes std::string skeletonModel = MeshPrefix + creature.mModel; skeletonModel = Misc::ResourceHelpers::correctActorModelPath(skeletonModel, mData.getResourceSystem()->getVFS()); loadSkeleton(skeletonModel); @@ -65,6 +65,9 @@ namespace CSVRender mSkeleton->accept(removeTriBipVisitor); removeTriBipVisitor.remove(); + // Attach weapons + loadBodyParts(creature.mId); + // Post setup mSkeleton->markDirty(); mSkeleton->setActive(SceneUtil::Skeleton::Active); @@ -72,12 +75,8 @@ namespace CSVRender void Actor::updateNpc() { - const unsigned int FemaleFlag = ESM::BodyPart::BPF_Female; - - auto& bodyParts = mData.getBodyParts(); auto& races = mData.getRaces(); auto& referenceables = mData.getReferenceables(); - auto sceneMgr = mData.getResourceSystem()->getSceneManager(); auto& npc = dynamic_cast& >(referenceables.getRecord(mId)).get(); auto& race = dynamic_cast& >(races.getRecord(npc.mRace)).get(); @@ -97,91 +96,8 @@ namespace CSVRender mSkeleton->accept(cleanVisitor); cleanVisitor.remove(); - // Map bone names to bones - SceneUtil::NodeMapVisitor::NodeMap nodeMap; - SceneUtil::NodeMapVisitor nmVisitor(nodeMap); - mSkeleton->accept(nmVisitor); - - using BPRaceKey = std::tuple; - using RaceToBPMap = std::map; - // Convenience method to generate a map from body part + race to mesh name - auto genRaceToBodyPartMap = [&](RaceToBPMap& bpMap) { - int size = bodyParts.getSize(); - for (int i = 0; i < size; ++i) - { - auto& record = bodyParts.getRecord(i); - if (!record.isDeleted()) - { - // Method to check if 1st person part or not - auto is1stPersonPart = [](std::string name) { - return name.size() >= 4 && name.find(".1st", name.size() - 4) != std::string::npos; - }; - - auto& bodyPart = record.get(); - if (bodyPart.mData.mType != ESM::BodyPart::MT_Skin || is1stPersonPart(bodyPart.mId)) - continue; - - bpMap.emplace( - BPRaceKey(bodyPart.mData.mPart, bodyPart.mData.mFlags & FemaleFlag ? 1 : 0, bodyPart.mRace), - MeshPrefix + bodyPart.mModel); - } - } - }; - - // Generate mapping - RaceToBPMap r2bpMap; - genRaceToBodyPartMap(r2bpMap); - - // Convenience method to add a body part - auto addBodyPart = [&](ESM::PartReferenceType type, std::string mesh) { - // Retrieve mesh name if necessary - if (mesh.empty()) - { - auto meshResult = r2bpMap.find(BPRaceKey(ESM::getMeshPart(type), isFemale ? 1 : 0, npc.mRace)); - if (meshResult != r2bpMap.end()) - { - mesh = meshResult->second; - } - else if (isFemale){ - meshResult = r2bpMap.find(BPRaceKey(ESM::getMeshPart(type), 0, npc.mRace)); - if (meshResult != r2bpMap.end()) - mesh = meshResult->second; - } - } - - // Attach to skeleton - std::string boneName = ESM::getBoneName(type); - auto node = nodeMap.find(boneName); - if (!mesh.empty() && node != nodeMap.end()) - { - auto instance = sceneMgr->getInstance(mesh); - SceneUtil::attach(instance, mSkeleton, boneName, node->second); - } - }; - - // Add body parts - for (unsigned int i = 0; i < ESM::PRT_Count; ++i) - { - auto part = static_cast(i); - switch (part) - { - case ESM::PRT_Head: - addBodyPart(part, getBodyPartMesh(npc.mHead)); - break; - case ESM::PRT_Hair: - addBodyPart(part, getBodyPartMesh(npc.mHair)); - break; - case ESM::PRT_Skirt: - case ESM::PRT_Shield: - case ESM::PRT_RPauldron: - case ESM::PRT_LPauldron: - case ESM::PRT_Weapon: - // No body part mesh associated - break; - default: - addBodyPart(part, ""); - } - } + // Attach parts to skeleton + loadBodyParts(npc.mId); // Post setup mSkeleton->markDirty(); @@ -200,6 +116,37 @@ namespace CSVRender mSkeleton->addChild(temp); } mBaseNode->addChild(mSkeleton); + + // Map bone names to bones + mNodeMap.clear(); + SceneUtil::NodeMapVisitor nmVisitor(mNodeMap); + mSkeleton->accept(nmVisitor); + + } + + void Actor::loadBodyParts(const std::string& actorId) + { + auto actorAdapter = mData.getActorAdapter(); + auto partMap = actorAdapter->getActorPartMap(actorId); + if (partMap) + { + for (auto& pair : *partMap) + attachBodyPart(pair.first, getBodyPartMesh(pair.second)); + } + } + + void Actor::attachBodyPart(ESM::PartReferenceType type, const std::string& mesh) + { + auto sceneMgr = mData.getResourceSystem()->getSceneManager(); + + // Attach to skeleton + std::string boneName = ESM::getBoneName(type); + auto node = mNodeMap.find(boneName); + if (!mesh.empty() && node != mNodeMap.end()) + { + auto instance = sceneMgr->getInstance(mesh); + SceneUtil::attach(instance, mSkeleton, boneName, node->second); + } } std::string Actor::getBodyPartMesh(const std::string& bodyPartId) diff --git a/apps/opencs/view/render/actor.hpp b/apps/opencs/view/render/actor.hpp index b4e65ff2b..4f809c172 100644 --- a/apps/opencs/view/render/actor.hpp +++ b/apps/opencs/view/render/actor.hpp @@ -5,6 +5,9 @@ #include +#include +#include + namespace osg { class Group; @@ -39,10 +42,13 @@ namespace CSVRender void update(); private: - void loadSkeleton(const std::string& model); void updateCreature(); void updateNpc(); + void loadSkeleton(const std::string& model); + void loadBodyParts(const std::string& actorId); + void attachBodyPart(ESM::PartReferenceType, const std::string& mesh); + std::string getBodyPartMesh(const std::string& bodyPartId); static const std::string MeshPrefix; @@ -51,8 +57,9 @@ namespace CSVRender int mType; CSMWorld::Data& mData; - SceneUtil::Skeleton* mSkeleton; osg::ref_ptr mBaseNode; + SceneUtil::Skeleton* mSkeleton; + SceneUtil::NodeMapVisitor::NodeMap mNodeMap; }; } From 6bece13a32ff40b69ed4d9acf380c210d00a70e8 Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Tue, 21 Aug 2018 15:41:05 -0400 Subject: [PATCH 165/196] Use new Log class for error message --- apps/opencs/view/render/actor.cpp | 5 ++--- components/sceneutil/visitor.cpp | 6 +++--- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/apps/opencs/view/render/actor.cpp b/apps/opencs/view/render/actor.cpp index b816c1504..a61d31de6 100644 --- a/apps/opencs/view/render/actor.cpp +++ b/apps/opencs/view/render/actor.cpp @@ -1,10 +1,9 @@ #include "actor.hpp" -#include - #include #include +#include #include #include #include @@ -46,7 +45,7 @@ namespace CSVRender } catch (std::exception& e) { - std::cout << "Caught exception: " << e.what() << std::endl; + Log(Debug::Error) << "Exception in Actor::update(): " << e.what(); } } diff --git a/components/sceneutil/visitor.cpp b/components/sceneutil/visitor.cpp index 07be1608e..536331132 100644 --- a/components/sceneutil/visitor.cpp +++ b/components/sceneutil/visitor.cpp @@ -1,12 +1,12 @@ #include "visitor.hpp" -#include - #include #include #include +#include + #include namespace SceneUtil @@ -74,7 +74,7 @@ namespace SceneUtil for (RemoveVec::iterator it = mToRemove.begin(); it != mToRemove.end(); ++it) { if (!it->second->removeChild(it->first)) - std::cerr << "error removing " << it->first->getName() << std::endl; + Log(Debug::Error) << "error removing " << it->first->getName(); } } From b2115b60e6710c07b6209e241036fc2e8e006748 Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Tue, 21 Aug 2018 15:54:21 -0400 Subject: [PATCH 166/196] Fix qt4 build --- apps/opencs/model/world/actoradapter.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/opencs/model/world/actoradapter.hpp b/apps/opencs/model/world/actoradapter.hpp index 2c94f9c2c..09bd2682b 100644 --- a/apps/opencs/model/world/actoradapter.hpp +++ b/apps/opencs/model/world/actoradapter.hpp @@ -6,6 +6,7 @@ #include #include +#include #include #include From 1276e0fa9b2e2f7ac5e1a67d288c79479e536fc8 Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Thu, 23 Aug 2018 22:40:43 -0400 Subject: [PATCH 167/196] Handle changes to race record when rendering actors --- apps/opencs/CMakeLists.txt | 4 +- apps/opencs/model/world/actoradapter.cpp | 66 ++++++++++++++++++++---- apps/opencs/model/world/actoradapter.hpp | 7 +++ apps/opencs/view/render/actor.cpp | 18 ++++++- apps/opencs/view/render/actor.hpp | 9 +++- apps/opencs/view/render/object.cpp | 7 +-- apps/opencs/view/render/object.hpp | 3 ++ 7 files changed, 98 insertions(+), 16 deletions(-) diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 999324c51..b0bd95eb9 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -89,12 +89,12 @@ opencs_units (view/render scenewidget worldspacewidget pagedworldspacewidget unpagedworldspacewidget previewwidget editmode instancemode instanceselectionmode instancemovemode orbitcameramode pathgridmode selectionmode pathgridselectionmode cameracontroller - cellwater terraintexturemode + cellwater terraintexturemode actor ) opencs_units_noqt (view/render lighting lightingday lightingnight lightingbright object cell terrainstorage tagbase - cellarrow cellmarker cellborder pathgrid actor + cellarrow cellmarker cellborder pathgrid ) opencs_hdrs_noqt (view/render diff --git a/apps/opencs/model/world/actoradapter.cpp b/apps/opencs/model/world/actoradapter.cpp index 249908bb0..9c397879e 100644 --- a/apps/opencs/model/world/actoradapter.cpp +++ b/apps/opencs/model/world/actoradapter.cpp @@ -1,7 +1,6 @@ #include "actoradapter.hpp" -#include - +#include #include #include #include @@ -45,17 +44,56 @@ namespace CSMWorld void ActorAdapter::handleReferenceableChanged(const QModelIndex& topLeft, const QModelIndex& botRight) { - // TODO + // Setup + const int TypeColumn = mReferenceables.findColumnIndex(CSMWorld::Columns::ColumnId_RecordType); + int rowStart = getHighestIndex(topLeft).row(); + int rowEnd = getHighestIndex(botRight).row(); + + // Handle each record + for (int row = rowStart; row <= rowEnd; ++row) + { + int type = mReferenceables.getData(row, TypeColumn).toInt(); + if (type == CSMWorld::UniversalId::Type_Creature || type == CSMWorld::UniversalId::Type_Npc) + { + // Update the cached npc or creature + std::string refId = mReferenceables.getId(row); + if (mActorPartMaps.find(refId) != mActorPartMaps.end()) + updateActor(refId); + } + else if (type == CSMWorld::UniversalId::Type_Armor) + { + // TODO update everything? + // store all items referenced when creating map and check against that here + } + else if (type == CSMWorld::UniversalId::Type_Clothing) + { + // TODO update everything? + } + } } void ActorAdapter::handleRaceChanged(const QModelIndex& topLeft, const QModelIndex& botRight) { - // TODO + int rowStart = getHighestIndex(topLeft).row(); + int rowEnd = getHighestIndex(botRight).row(); + for (int row = rowStart; row <= rowEnd; ++row) + { + std::string raceId = mRaces.getId(row); + updateNpcsWithRace(raceId); + } } void ActorAdapter::handleBodyPartChanged(const QModelIndex& topLeft, const QModelIndex& botRight) { // TODO + Log(Debug::Info) << "Body Part Changed (" << topLeft.row() << ", " << topLeft.column() << ") (" << botRight.row() << ", " << botRight.column() << ")"; + } + + QModelIndex ActorAdapter::getHighestIndex(QModelIndex index) const + { + while (index.parent().isValid()) + index = index.parent(); + return index; } ActorAdapter::RacePartMap& ActorAdapter::getOrCreateRacePartMap(const std::string& raceId, bool isFemale) @@ -174,10 +212,6 @@ namespace CSMWorld npcMap.emplace(static_cast(part.mPart), bodyPartId); } } - else if (recordType == CSMWorld::UniversalId::Type_Weapon) - { - // TODO - } } } } @@ -233,10 +267,24 @@ namespace CSMWorld } mActorPartMaps[refId] = npcMap; + emit actorChanged(refId); } void ActorAdapter::updateCreature(const std::string& refId) { - // TODO + emit actorChanged(refId); + } + + void ActorAdapter::updateNpcsWithRace(const std::string& raceId) + { + for (auto it : mActorPartMaps) + { + auto& refId = it.first; + auto& npc = dynamic_cast&>(mReferenceables.getRecord(refId)).get(); + if (npc.mRace == raceId) + { + updateNpc(refId); + } + } } } diff --git a/apps/opencs/model/world/actoradapter.hpp b/apps/opencs/model/world/actoradapter.hpp index 09bd2682b..ad308fc02 100644 --- a/apps/opencs/model/world/actoradapter.hpp +++ b/apps/opencs/model/world/actoradapter.hpp @@ -60,6 +60,11 @@ namespace CSMWorld private: + ActorAdapter(const ActorAdapter&) = delete; + ActorAdapter& operator=(const ActorAdapter&) = delete; + + QModelIndex getHighestIndex(QModelIndex) const; + RacePartMap& getOrCreateRacePartMap(const std::string& raceId, bool isFemale); void updateRaceParts(const std::string& raceId); @@ -67,6 +72,8 @@ namespace CSMWorld void updateNpc(const std::string& refId); void updateCreature(const std::string& refId); + void updateNpcsWithRace(const std::string& raceId); + RefIdCollection& mReferenceables; IdCollection& mRaces; IdCollection& mBodyParts; diff --git a/apps/opencs/view/render/actor.cpp b/apps/opencs/view/render/actor.cpp index a61d31de6..6d663ad5e 100644 --- a/apps/opencs/view/render/actor.cpp +++ b/apps/opencs/view/render/actor.cpp @@ -20,6 +20,7 @@ namespace CSVRender Actor::Actor(const std::string& id, int type, CSMWorld::Data& data) : mId(id) + , mInitialized(false) , mType(type) , mData(data) , mBaseNode(new osg::Group()) @@ -45,7 +46,22 @@ namespace CSVRender } catch (std::exception& e) { - Log(Debug::Error) << "Exception in Actor::update(): " << e.what(); + Log(Debug::Info) << "Exception in Actor::update(): " << e.what(); + } + + if (!mInitialized) + { + mInitialized = true; + connect(mData.getActorAdapter(), SIGNAL(actorChanged(const std::string&)), this, SLOT(handleActorChanged(const std::string&))); + } + } + + void Actor::handleActorChanged(const std::string& refId) + { + if (mId == refId) + { + Log(Debug::Info) << "Actor::actorChanged " << mId; + update(); } } diff --git a/apps/opencs/view/render/actor.hpp b/apps/opencs/view/render/actor.hpp index 4f809c172..42a6019ed 100644 --- a/apps/opencs/view/render/actor.hpp +++ b/apps/opencs/view/render/actor.hpp @@ -5,6 +5,8 @@ #include +#include + #include #include @@ -26,8 +28,9 @@ namespace SceneUtil namespace CSVRender { /// Handles loading an npc or creature - class Actor + class Actor : public QObject { + Q_OBJECT public: /// Creates an actor. /// \param id The referenceable id @@ -41,6 +44,9 @@ namespace CSVRender /// (Re)creates the npc or creature renderable void update(); + private slots: + void handleActorChanged(const std::string& refId); + private: void updateCreature(); void updateNpc(); @@ -54,6 +60,7 @@ namespace CSVRender static const std::string MeshPrefix; std::string mId; + bool mInitialized; int mType; CSMWorld::Data& mData; diff --git a/apps/opencs/view/render/object.cpp b/apps/opencs/view/render/object.cpp index dbfd595b6..63f1bc8a8 100644 --- a/apps/opencs/view/render/object.cpp +++ b/apps/opencs/view/render/object.cpp @@ -134,9 +134,10 @@ void CSVRender::Object::update() { if (recordType == CSMWorld::UniversalId::Type_Npc || recordType == CSMWorld::UniversalId::Type_Creature) { - Actor actor(mReferenceableId, recordType, mData); - actor.update(); - mBaseNode->addChild(actor.getBaseNode()); + if (!mActor) + mActor.reset(new Actor(mReferenceableId, recordType, mData)); + mActor->update(); + mBaseNode->addChild(mActor->getBaseNode()); } else { diff --git a/apps/opencs/view/render/object.hpp b/apps/opencs/view/render/object.hpp index 3e54093d3..10a46fc10 100644 --- a/apps/opencs/view/render/object.hpp +++ b/apps/opencs/view/render/object.hpp @@ -1,6 +1,7 @@ #ifndef OPENCS_VIEW_OBJECT_H #define OPENCS_VIEW_OBJECT_H +#include #include #include @@ -41,6 +42,7 @@ namespace CSMWorld namespace CSVRender { + class Actor; class Object; // An object to attach as user data to the osg::Node, allows us to get an Object back from a Node when we are doing a ray query @@ -98,6 +100,7 @@ namespace CSVRender osg::ref_ptr mMarker[3]; int mSubMode; float mMarkerTransparency; + std::unique_ptr mActor; /// Not implemented Object (const Object&); From 2a9ebac57225407d3ff991d81964d9e7ceeb0941 Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Fri, 24 Aug 2018 02:44:02 -0400 Subject: [PATCH 168/196] Simplify update logic, update when race parts are changed. --- apps/opencs/model/world/actoradapter.cpp | 207 +++++++++++++++-------- apps/opencs/model/world/actoradapter.hpp | 35 +++- apps/opencs/view/render/actor.cpp | 6 +- 3 files changed, 168 insertions(+), 80 deletions(-) diff --git a/apps/opencs/model/world/actoradapter.cpp b/apps/opencs/model/world/actoradapter.cpp index 9c397879e..4626d1642 100644 --- a/apps/opencs/model/world/actoradapter.cpp +++ b/apps/opencs/model/world/actoradapter.cpp @@ -24,22 +24,22 @@ namespace CSMWorld this, SLOT(handleBodyPartChanged(const QModelIndex&, const QModelIndex&))); } - const ActorAdapter::ActorPartMap* ActorAdapter::getActorPartMap(const std::string& refId) + const ActorAdapter::ActorPartMap* ActorAdapter::getActorParts(const std::string& refId, bool create) { - auto it = mActorPartMaps.find(refId); - if (it != mActorPartMaps.end()) + auto it = mCachedActors.find(refId); + if (it != mCachedActors.end()) { - return &it->second; + return &it->second.parts; + } + else if (create) + { + updateActor(refId); + return getActorParts(refId, false); } else { - updateActor(refId); - it = mActorPartMaps.find(refId); - if (it != mActorPartMaps.end()) - return &it->second; + return nullptr; } - - return nullptr; } void ActorAdapter::handleReferenceableChanged(const QModelIndex& topLeft, const QModelIndex& botRight) @@ -57,17 +57,13 @@ namespace CSMWorld { // Update the cached npc or creature std::string refId = mReferenceables.getId(row); - if (mActorPartMaps.find(refId) != mActorPartMaps.end()) + if (mCachedActors.find(refId) != mCachedActors.end()) updateActor(refId); } - else if (type == CSMWorld::UniversalId::Type_Armor) + else if (type == CSMWorld::UniversalId::Type_Armor || type == CSMWorld::UniversalId::Type_Clothing) { - // TODO update everything? - // store all items referenced when creating map and check against that here - } - else if (type == CSMWorld::UniversalId::Type_Clothing) - { - // TODO update everything? + std::string refId = mReferenceables.getId(row); + updateActorsWithDependency(refId); } } } @@ -79,14 +75,28 @@ namespace CSMWorld for (int row = rowStart; row <= rowEnd; ++row) { std::string raceId = mRaces.getId(row); - updateNpcsWithRace(raceId); + updateActorsWithDependency(raceId); } } void ActorAdapter::handleBodyPartChanged(const QModelIndex& topLeft, const QModelIndex& botRight) { - // TODO - Log(Debug::Info) << "Body Part Changed (" << topLeft.row() << ", " << topLeft.column() << ") (" << botRight.row() << ", " << botRight.column() << ")"; + int rowStart = getHighestIndex(topLeft).row(); + int rowEnd = getHighestIndex(botRight).row(); + for (int row = rowStart; row <= rowEnd; ++row) + { + // Manually update race specified by part + auto& record = mBodyParts.getRecord(row); + if (!record.isDeleted()) + { + updateRace(record.get().mRace); + } + + // Update entries with a tracked dependency + std::string partId = mBodyParts.getId(row); + updateRacesWithDependency(partId); + updateActorsWithDependency(partId); + } } QModelIndex ActorAdapter::getHighestIndex(QModelIndex index) const @@ -96,47 +106,66 @@ namespace CSMWorld return index; } - ActorAdapter::RacePartMap& ActorAdapter::getOrCreateRacePartMap(const std::string& raceId, bool isFemale) + bool ActorAdapter::is1stPersonPart(const std::string& name) const { - auto key = std::make_pair(raceId, isFemale); - auto it = mRacePartMaps.find(key); - if (it != mRacePartMaps.end()) + return name.size() >= 4 && name.find(".1st", name.size() - 4) != std::string::npos; + } + + ActorAdapter::RaceData& ActorAdapter::getRaceData(const std::string& raceId) + { + auto it = mCachedRaces.find(raceId); + if (it != mCachedRaces.end()) { return it->second; } else { // Create and find result - updateRaceParts(raceId); - return mRacePartMaps.find(key)->second; + updateRace(raceId); + return mCachedRaces.find(raceId)->second; } } - void ActorAdapter::updateRaceParts(const std::string& raceId) + void ActorAdapter::updateRace(const std::string& raceId) { - // Convenience function to determine if part is for 1st person view - auto is1stPersonPart = [](std::string name) { - return name.size() >= 4 && name.find(".1st", name.size() - 4) != std::string::npos; - }; + // Retrieve or create cache entry + auto raceDataIt = mCachedRaces.find(raceId); + if (raceDataIt == mCachedRaces.end()) + { + auto result = mCachedRaces.emplace(raceId, RaceData()); + raceDataIt = result.first; + } - RacePartMap maleMap, femaleMap; + auto& raceData = raceDataIt->second; + raceData.femaleParts.clear(); + raceData.maleParts.clear(); + raceData.dependencies.clear(); + + // Construct entry for (int i = 0; i < mBodyParts.getSize(); ++i) { auto& record = mBodyParts.getRecord(i); - if (!record.isDeleted() && record.get().mRace == raceId && record.get().mData.mType == ESM::BodyPart::MT_Skin && !is1stPersonPart(record.get().mId)) + if (!record.isDeleted() && record.get().mRace == raceId) { auto& part = record.get(); - auto type = (ESM::BodyPart::MeshPart) part.mData.mPart; - // Note: Prefer the first part encountered for duplicates. emplace() does not overwrite - if (part.mData.mFlags & ESM::BodyPart::BPF_Female) - femaleMap.emplace(type, part.mId); - else - maleMap.emplace(type, part.mId); + + // Part could affect race data + raceData.dependencies.emplace(part.mId, true); + + // Add base types + if (part.mData.mType == ESM::BodyPart::MT_Skin && !is1stPersonPart(part.mId)) + { + auto type = (ESM::BodyPart::MeshPart) part.mData.mPart; + // Note: Prefer the first part encountered for duplicates. emplace() does not overwrite + if (part.mData.mFlags & ESM::BodyPart::BPF_Female) + raceData.femaleParts.emplace(type, part.mId); + else + raceData.maleParts.emplace(type, part.mId); + } } } - mRacePartMaps[std::make_pair(raceId, true)] = femaleMap; - mRacePartMaps[std::make_pair(raceId, false)] = maleMap; + updateActorsWithDependency(raceId); } void ActorAdapter::updateActor(const std::string& refId) @@ -156,17 +185,28 @@ namespace CSMWorld void ActorAdapter::updateNpc(const std::string& refId) { auto& record = mReferenceables.getRecord(refId); + + // Retrieve record if possible if (record.isDeleted()) { - mActorPartMaps.erase(refId); + mCachedActors.erase(refId); + emit actorChanged(refId); return; } - auto& npc = dynamic_cast&>(record).get(); - auto& femaleRacePartMap = getOrCreateRacePartMap(npc.mRace, true); - auto& maleRacePartMap = getOrCreateRacePartMap(npc.mRace, false); - ActorPartMap npcMap; + // Create holder for cached data + auto actorIt = mCachedActors.find(refId); + if (actorIt == mCachedActors.end()) + { + auto result = mCachedActors.emplace(refId, ActorData()); + actorIt = result.first; + } + auto& actorData = actorIt->second; + + // Reset old data + actorData.parts.clear(); + actorData.dependencies.clear(); // Look at the npc's inventory first for (auto& item : npc.mInventory.mList) @@ -174,7 +214,7 @@ namespace CSMWorld if (item.mCount > 0) { std::string itemId = item.mItem.toString(); - // Handle armor, weapons, and clothing + // Handle armor and clothing int index = mReferenceables.searchId(itemId); if (index != -1 && !mReferenceables.getRecord(index).isDeleted()) { @@ -184,6 +224,10 @@ namespace CSMWorld int recordType = mReferenceables.getData(index, typeColumn).toInt(); if (recordType == CSMWorld::UniversalId::Type_Armor) { + // Changes here could affect the actor + actorData.dependencies.emplace(itemId, true); + + // Add any parts if there is room auto& armor = dynamic_cast&>(itemRecord).get(); for (auto& part : armor.mParts.mParts) { @@ -194,11 +238,18 @@ namespace CSMWorld bodyPartId = part.mMale; if (!bodyPartId.empty()) - npcMap.emplace(static_cast(part.mPart), bodyPartId); + { + actorData.parts.emplace(static_cast(part.mPart), bodyPartId); + actorData.dependencies.emplace(bodyPartId, true); + } } } else if (recordType == CSMWorld::UniversalId::Type_Clothing) { + // Changes here could affect the actor + actorData.dependencies.emplace(itemId, true); + + // Add any parts if there is room auto& clothing = dynamic_cast&>(itemRecord).get(); for (auto& part : clothing.mParts.mParts) { @@ -209,26 +260,37 @@ namespace CSMWorld bodyPartId = part.mMale; if (!bodyPartId.empty()) - npcMap.emplace(static_cast(part.mPart), bodyPartId); + { + actorData.parts.emplace(static_cast(part.mPart), bodyPartId); + actorData.dependencies.emplace(bodyPartId, true); + } } } } } } - // Fill in the rest with body parts + // Lookup cached race parts + auto& raceData = getRaceData(npc.mRace); + + // Changes to race could affect the actor + actorData.dependencies.emplace(npc.mRace, true); + + // Fill in the rest with race specific body parts for (int i = 0; i < ESM::PRT_Count; ++i) { auto type = static_cast(i); - if (npcMap.find(type) == npcMap.end()) + if (actorData.parts.find(type) == actorData.parts.end()) { switch (type) { case ESM::PRT_Head: - npcMap.emplace(type, npc.mHead); + actorData.parts.emplace(type, npc.mHead); + actorData.dependencies.emplace(npc.mHead, true); break; case ESM::PRT_Hair: - npcMap.emplace(type, npc.mHair); + actorData.parts.emplace(type, npc.mHair); + actorData.dependencies.emplace(npc.mHair, true); break; case ESM::PRT_Skirt: case ESM::PRT_Shield: @@ -243,48 +305,57 @@ namespace CSMWorld // Check female map if applicable if (!npc.isMale()) { - auto partIt = femaleRacePartMap.find(ESM::getMeshPart(type)); - if (partIt != femaleRacePartMap.end()) + auto partIt = raceData.femaleParts.find(ESM::getMeshPart(type)); + if (partIt != raceData.femaleParts.end()) bodyPartId = partIt->second; } // Check male map next if (bodyPartId.empty() || npc.isMale()) { - auto partIt = maleRacePartMap.find(ESM::getMeshPart(type)); - if (partIt != maleRacePartMap.end()) + auto partIt = raceData.maleParts.find(ESM::getMeshPart(type)); + if (partIt != raceData.maleParts.end()) bodyPartId = partIt->second; } // Add to map if (!bodyPartId.empty()) { - npcMap.emplace(type, bodyPartId); + actorData.parts.emplace(type, bodyPartId); + actorData.dependencies.emplace(bodyPartId, true); } } } } } - mActorPartMaps[refId] = npcMap; + // Signal change to actor emit actorChanged(refId); } void ActorAdapter::updateCreature(const std::string& refId) { + // Signal change to actor emit actorChanged(refId); } - void ActorAdapter::updateNpcsWithRace(const std::string& raceId) + void ActorAdapter::updateActorsWithDependency(const std::string& id) { - for (auto it : mActorPartMaps) + for (auto it : mCachedActors) { - auto& refId = it.first; - auto& npc = dynamic_cast&>(mReferenceables.getRecord(refId)).get(); - if (npc.mRace == raceId) - { - updateNpc(refId); - } + auto& deps = it.second.dependencies; + if (deps.find(id) != deps.end()) + updateActor(it.first); + } + } + + void ActorAdapter::updateRacesWithDependency(const std::string& id) + { + for (auto it : mCachedRaces) + { + auto& deps = it.second.dependencies; + if (deps.find(id) != deps.end()) + updateRace(it.first); } } } diff --git a/apps/opencs/model/world/actoradapter.hpp b/apps/opencs/model/world/actoradapter.hpp index ad308fc02..f1148199c 100644 --- a/apps/opencs/model/world/actoradapter.hpp +++ b/apps/opencs/model/world/actoradapter.hpp @@ -41,12 +41,10 @@ namespace CSMWorld // Maps body part type to 'body part' id using ActorPartMap = std::unordered_map; - // Maps mesh part type to 'body part' id - using RacePartMap = std::unordered_map; ActorAdapter(CSMWorld::Data& data); - const ActorPartMap* getActorPartMap(const std::string& refId); + const ActorPartMap* getActorParts(const std::string& refId, bool create=true); signals: @@ -59,29 +57,48 @@ namespace CSMWorld void handleBodyPartChanged(const QModelIndex&, const QModelIndex&); private: + // Maps mesh part type to 'body part' id + using RacePartMap = std::unordered_map; + // Stores ids that are referenced by the actor. Data part is meaningless. + using DependencyMap = std::unordered_map; + + struct ActorData + { + ActorPartMap parts; + DependencyMap dependencies; + }; + + struct RaceData + { + RacePartMap femaleParts; + RacePartMap maleParts; + DependencyMap dependencies; + }; ActorAdapter(const ActorAdapter&) = delete; ActorAdapter& operator=(const ActorAdapter&) = delete; QModelIndex getHighestIndex(QModelIndex) const; + bool is1stPersonPart(const std::string& id) const; - RacePartMap& getOrCreateRacePartMap(const std::string& raceId, bool isFemale); + RaceData& getRaceData(const std::string& raceId); - void updateRaceParts(const std::string& raceId); + void updateRace(const std::string& raceId); void updateActor(const std::string& refId); void updateNpc(const std::string& refId); void updateCreature(const std::string& refId); - void updateNpcsWithRace(const std::string& raceId); + void updateActorsWithDependency(const std::string& id); + void updateRacesWithDependency(const std::string& id); RefIdCollection& mReferenceables; IdCollection& mRaces; IdCollection& mBodyParts; // Key: referenceable id - std::unordered_map mActorPartMaps; - // Key: race id, is female - std::unordered_map, RacePartMap, StringBoolPairHash> mRacePartMaps; + std::unordered_map mCachedActors; + // Key: race id + std::unordered_map mCachedRaces; }; } diff --git a/apps/opencs/view/render/actor.cpp b/apps/opencs/view/render/actor.cpp index 6d663ad5e..b9979ae2c 100644 --- a/apps/opencs/view/render/actor.cpp +++ b/apps/opencs/view/render/actor.cpp @@ -142,10 +142,10 @@ namespace CSVRender void Actor::loadBodyParts(const std::string& actorId) { auto actorAdapter = mData.getActorAdapter(); - auto partMap = actorAdapter->getActorPartMap(actorId); - if (partMap) + auto parts = actorAdapter->getActorParts(actorId); + if (parts) { - for (auto& pair : *partMap) + for (auto& pair : *parts) attachBodyPart(pair.first, getBodyPartMesh(pair.second)); } } From 031502b2ab80216d9dc4ef475a1ad6cb9ad2092e Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Sun, 26 Aug 2018 01:13:50 -0400 Subject: [PATCH 169/196] Reorganize ActorAdapter data, use weak cache for sharing --- apps/opencs/model/world/actoradapter.cpp | 715 +++++++++++++++-------- apps/opencs/model/world/actoradapter.hpp | 187 ++++-- apps/opencs/view/render/actor.cpp | 14 +- apps/opencs/view/render/actor.hpp | 3 + components/CMakeLists.txt | 4 + components/cache/weakcache.hpp | 116 ++++ 6 files changed, 714 insertions(+), 325 deletions(-) create mode 100644 components/cache/weakcache.hpp diff --git a/apps/opencs/model/world/actoradapter.cpp b/apps/opencs/model/world/actoradapter.cpp index 4626d1642..b3a1216f7 100644 --- a/apps/opencs/model/world/actoradapter.cpp +++ b/apps/opencs/model/world/actoradapter.cpp @@ -11,72 +11,290 @@ namespace CSMWorld { - ActorAdapter::ActorAdapter(CSMWorld::Data& data) + const std::string& ActorAdapter::RaceData::getId() const + { + return mId; + } + + bool ActorAdapter::RaceData::handlesPart(ESM::PartReferenceType type) const + { + switch (type) + { + case ESM::PRT_Skirt: + case ESM::PRT_Shield: + case ESM::PRT_RPauldron: + case ESM::PRT_LPauldron: + case ESM::PRT_Weapon: + return false; + default: + return true; + } + } + + const std::string& ActorAdapter::RaceData::getFemalePart(ESM::PartReferenceType index) const + { + return mFemaleParts[ESM::getMeshPart(index)]; + } + + const std::string& ActorAdapter::RaceData::getMalePart(ESM::PartReferenceType index) const + { + return mMaleParts[ESM::getMeshPart(index)]; + } + + bool ActorAdapter::RaceData::hasDependency(const std::string& id) const + { + return mDependencies.find(id) != mDependencies.end(); + } + + void ActorAdapter::RaceData::setFemalePart(ESM::BodyPart::MeshPart index, const std::string& partId) + { + mFemaleParts[index] = partId; + addOtherDependency(partId); + } + + void ActorAdapter::RaceData::setMalePart(ESM::BodyPart::MeshPart index, const std::string& partId) + { + mMaleParts[index] = partId; + addOtherDependency(partId); + } + + void ActorAdapter::RaceData::addOtherDependency(const std::string& id) + { + if (!id.empty()) mDependencies.emplace(id); + } + + void ActorAdapter::RaceData::reset(const std::string& id) + { + mId = id; + for (auto& str : mFemaleParts) + str.clear(); + for (auto& str : mMaleParts) + str.clear(); + mDependencies.clear(); + + // Mark self as a dependency + addOtherDependency(id); + } + + + const std::string& ActorAdapter::ActorData::getId() const + { + return mId; + } + + bool ActorAdapter::ActorData::isFemale() const + { + return mFemale; + } + + const std::string& ActorAdapter::ActorData::getPart(ESM::PartReferenceType index) const + { + if (mParts[index].empty() && mRaceData && mRaceData->handlesPart(index)) + { + return mFemale ? mRaceData->getFemalePart(index) : mRaceData->getMalePart(index); + } + return mParts[index]; + } + + bool ActorAdapter::ActorData::hasDependency(const std::string& id) const + { + return mDependencies.find(id) != mDependencies.end(); + } + + void ActorAdapter::ActorData::setPart(ESM::PartReferenceType index, const std::string& partId) + { + mParts[index] = partId; + addOtherDependency(partId); + } + + void ActorAdapter::ActorData::addOtherDependency(const std::string& id) + { + if (!id.empty()) mDependencies.emplace(id); + } + + void ActorAdapter::ActorData::reset(const std::string& id, bool isFemale, RaceDataPtr raceData) + { + mId = id; + mFemale = isFemale; + mRaceData = raceData; + for (auto& str : mParts) + str.clear(); + mDependencies.clear(); + + // Mark self and race as a dependency + addOtherDependency(id); + if (raceData) addOtherDependency(raceData->getId()); + } + + + ActorAdapter::ActorAdapter(Data& data) : mReferenceables(data.getReferenceables()) , mRaces(data.getRaces()) , mBodyParts(data.getBodyParts()) { - connect(data.getTableModel(UniversalId::Type_Referenceable), SIGNAL(dataChanged(const QModelIndex&, const QModelIndex&)), + // Setup qt slots and signals + QAbstractItemModel* refModel = data.getTableModel(UniversalId::Type_Referenceable); + connect(refModel, SIGNAL(rowsInserted(const QModelIndex&, int, int)), + this, SLOT(handleReferenceablesInserted(const QModelIndex&, int, int))); + connect(refModel, SIGNAL(dataChanged(const QModelIndex&, const QModelIndex&)), this, SLOT(handleReferenceableChanged(const QModelIndex&, const QModelIndex&))); - connect(data.getTableModel(UniversalId::Type_Race), SIGNAL(dataChanged(const QModelIndex&, const QModelIndex&)), + connect(refModel, SIGNAL(rowsAboutToBeRemoved(const QModelIndex&, int, int)), + this, SLOT(handleReferenceablesAboutToBeRemoved(const QModelIndex&, int, int))); + + QAbstractItemModel* raceModel = data.getTableModel(UniversalId::Type_Race); + connect(raceModel, SIGNAL(rowsInserted(const QModelIndex&, int, int)), + this, SLOT(handleRacesAboutToBeRemoved(const QModelIndex&, int, int))); + connect(raceModel, SIGNAL(dataChanged(const QModelIndex&, const QModelIndex&)), this, SLOT(handleRaceChanged(const QModelIndex&, const QModelIndex&))); - connect(data.getTableModel(UniversalId::Type_BodyPart), SIGNAL(dataChanged(const QModelIndex&, const QModelIndex&)), + connect(raceModel, SIGNAL(rowsAboutToBeRemoved(const QModelIndex&, int, int)), + this, SLOT(handleRacesAboutToBeRemoved(const QModelIndex&, int, int))); + + QAbstractItemModel* partModel = data.getTableModel(UniversalId::Type_BodyPart); + connect(partModel, SIGNAL(rowsInserted(const QModelIndex&, int, int)), + this, SLOT(handleBodyPartsInserted(const QModelIndex&, int, int))); + connect(partModel, SIGNAL(dataChanged(const QModelIndex&, const QModelIndex&)), this, SLOT(handleBodyPartChanged(const QModelIndex&, const QModelIndex&))); + connect(partModel, SIGNAL(rowsAboutToBeRemoved(const QModelIndex&, int, int)), + this, SLOT(handleBodyPartsAboutToBeRemoved(const QModelIndex&, int, int))); } - const ActorAdapter::ActorPartMap* ActorAdapter::getActorParts(const std::string& refId, bool create) + ActorAdapter::ActorDataPtr ActorAdapter::getActorData(const std::string& id) { - auto it = mCachedActors.find(refId); - if (it != mCachedActors.end()) + // Return cached actor data if it exists + ActorDataPtr data = mCachedActors.get(id); + if (data) { - return &it->second.parts; + return data; } - else if (create) + + // Create the actor data + data.reset(new ActorData()); + setupActor(id, data); + mCachedActors.insert(id, data); + return data; + } + + void ActorAdapter::handleReferenceablesInserted(const QModelIndex& parent, int start, int end) + { + // Only rows added at the top level are pertinent. Others are caught by dataChanged handler. + if (!parent.isValid()) { - updateActor(refId); - return getActorParts(refId, false); - } - else - { - return nullptr; + for (int row = start; row <= end; ++row) + { + std::string refId = mReferenceables.getId(row); + markDirtyDependency(refId); + } } + + // Update affected + updateDirty(); } void ActorAdapter::handleReferenceableChanged(const QModelIndex& topLeft, const QModelIndex& botRight) { - // Setup - const int TypeColumn = mReferenceables.findColumnIndex(CSMWorld::Columns::ColumnId_RecordType); - int rowStart = getHighestIndex(topLeft).row(); - int rowEnd = getHighestIndex(botRight).row(); + int start = getHighestIndex(topLeft).row(); + int end = getHighestIndex(botRight).row(); // Handle each record - for (int row = rowStart; row <= rowEnd; ++row) + for (int row = start; row <= end; ++row) { - int type = mReferenceables.getData(row, TypeColumn).toInt(); - if (type == CSMWorld::UniversalId::Type_Creature || type == CSMWorld::UniversalId::Type_Npc) - { - // Update the cached npc or creature - std::string refId = mReferenceables.getId(row); - if (mCachedActors.find(refId) != mCachedActors.end()) - updateActor(refId); - } - else if (type == CSMWorld::UniversalId::Type_Armor || type == CSMWorld::UniversalId::Type_Clothing) + std::string refId = mReferenceables.getId(row); + markDirtyDependency(refId); + } + + // Update affected + updateDirty(); + } + + void ActorAdapter::handleReferenceablesAboutToBeRemoved(const QModelIndex& parent, int start, int end) + { + // Only rows at the top are pertinent. + if (!parent.isValid()) + { + for (int row = start; row <= end; ++row) { std::string refId = mReferenceables.getId(row); - updateActorsWithDependency(refId); + markDirtyDependency(refId); } } } + void ActorAdapter::handleReferenceablesRemoved(const QModelIndex& parent, int start, int end) + { + // Changes specified in handleReferenceablesAboutToBeRemoved + updateDirty(); + } + + void ActorAdapter::handleRacesInserted(const QModelIndex& parent, int start, int end) + { + // Only rows added at the top are pertinent. + if (!parent.isValid()) + { + for (int row = start; row <= end; ++row) + { + std::string raceId = mReferenceables.getId(row); + markDirtyDependency(raceId); + } + } + + // Update affected + updateDirty(); + } + void ActorAdapter::handleRaceChanged(const QModelIndex& topLeft, const QModelIndex& botRight) { - int rowStart = getHighestIndex(topLeft).row(); - int rowEnd = getHighestIndex(botRight).row(); - for (int row = rowStart; row <= rowEnd; ++row) + int start = getHighestIndex(topLeft).row(); + int end = getHighestIndex(botRight).row(); + for (int row = start; row <= end; ++row) { std::string raceId = mRaces.getId(row); - updateActorsWithDependency(raceId); + markDirtyDependency(raceId); } + + // Update affected + updateDirty(); + } + + void ActorAdapter::handleRacesAboutToBeRemoved(const QModelIndex& parent, int start, int end) + { + // Only changes at the top are pertinent. + if (!parent.isValid()) + { + for (int row = start; row <= end; ++row) + { + std::string raceId = mRaces.getId(row); + markDirtyDependency(raceId); + } + } + } + + void ActorAdapter::handleRacesRemoved(const QModelIndex& parent, int start, int end) + { + // Changes specified in handleRacesAboutToBeRemoved + updateDirty(); + } + + void ActorAdapter::handleBodyPartsInserted(const QModelIndex& parent, int start, int end) + { + // Only rows added at the top are pertinent. + if (!parent.isValid()) + { + for (int row = start; row <= end; ++row) + { + // Race specified by part may need update + auto& record = mBodyParts.getRecord(row); + if (!record.isDeleted()) + { + markDirtyDependency(record.get().mRace); + } + + std::string partId = mBodyParts.getId(row); + markDirtyDependency(partId); + } + } + + // Update affected + updateDirty(); } void ActorAdapter::handleBodyPartChanged(const QModelIndex& topLeft, const QModelIndex& botRight) @@ -85,18 +303,39 @@ namespace CSMWorld int rowEnd = getHighestIndex(botRight).row(); for (int row = rowStart; row <= rowEnd; ++row) { - // Manually update race specified by part + // Race specified by part may need update auto& record = mBodyParts.getRecord(row); if (!record.isDeleted()) { - updateRace(record.get().mRace); + markDirtyDependency(record.get().mRace); } // Update entries with a tracked dependency std::string partId = mBodyParts.getId(row); - updateRacesWithDependency(partId); - updateActorsWithDependency(partId); + markDirtyDependency(partId); } + + // Update affected + updateDirty(); + } + + void ActorAdapter::handleBodyPartsAboutToBeRemoved(const QModelIndex& parent, int start, int end) + { + // Only changes at the top are pertinent. + if (!parent.isValid()) + { + for (int row = start; row <= end; ++row) + { + std::string partId = mBodyParts.getId(row); + markDirtyDependency(partId); + } + } + } + + void ActorAdapter::handleBodyPartsRemoved(const QModelIndex& parent, int start, int end) + { + // Changes specified in handleBodyPartsAboutToBeRemoved + updateDirty(); } QModelIndex ActorAdapter::getHighestIndex(QModelIndex index) const @@ -111,251 +350,223 @@ namespace CSMWorld return name.size() >= 4 && name.find(".1st", name.size() - 4) != std::string::npos; } - ActorAdapter::RaceData& ActorAdapter::getRaceData(const std::string& raceId) + ActorAdapter::RaceDataPtr ActorAdapter::getRaceData(const std::string& id) { - auto it = mCachedRaces.find(raceId); - if (it != mCachedRaces.end()) + // Return cached race data if it exists + RaceDataPtr data = mCachedRaces.get(id); + if (data) return data; + + // Create the race data + data.reset(new RaceData()); + setupRace(id, data); + mCachedRaces.insert(id, data); + return data; + } + + void ActorAdapter::setupActor(const std::string& id, ActorDataPtr data) + { + int index = mReferenceables.searchId(id); + if (index == -1) { - return it->second; + // Record does not exist + data->reset(id); + emit actorChanged(id); + return; + } + + auto& record = mReferenceables.getRecord(index); + if (record.isDeleted()) + { + // Record is deleted and therefore not accessible + data->reset(id); + emit actorChanged(id); + return; + } + + const int TypeColumn = mReferenceables.findColumnIndex(Columns::ColumnId_RecordType); + int type = mReferenceables.getData(index, TypeColumn).toInt(); + if (type == UniversalId::Type_Creature) + { + // Valid creature record + setupCreature(id, data); + emit actorChanged(id); + } + else if (type == UniversalId::Type_Npc) + { + // Valid npc record + setupNpc(id, data); + emit actorChanged(id); } else { - // Create and find result - updateRace(raceId); - return mCachedRaces.find(raceId)->second; + // Wrong record type + data->reset(id); + emit actorChanged(id); } } - void ActorAdapter::updateRace(const std::string& raceId) + void ActorAdapter::setupRace(const std::string& id, RaceDataPtr data) { - // Retrieve or create cache entry - auto raceDataIt = mCachedRaces.find(raceId); - if (raceDataIt == mCachedRaces.end()) + // Common setup + data->reset(id); + + int index = mRaces.searchId(id); + if (index == -1) { - auto result = mCachedRaces.emplace(raceId, RaceData()); - raceDataIt = result.first; - } - - auto& raceData = raceDataIt->second; - raceData.femaleParts.clear(); - raceData.maleParts.clear(); - raceData.dependencies.clear(); - - // Construct entry - for (int i = 0; i < mBodyParts.getSize(); ++i) - { - auto& record = mBodyParts.getRecord(i); - if (!record.isDeleted() && record.get().mRace == raceId) - { - auto& part = record.get(); - - // Part could affect race data - raceData.dependencies.emplace(part.mId, true); - - // Add base types - if (part.mData.mType == ESM::BodyPart::MT_Skin && !is1stPersonPart(part.mId)) - { - auto type = (ESM::BodyPart::MeshPart) part.mData.mPart; - // Note: Prefer the first part encountered for duplicates. emplace() does not overwrite - if (part.mData.mFlags & ESM::BodyPart::BPF_Female) - raceData.femaleParts.emplace(type, part.mId); - else - raceData.maleParts.emplace(type, part.mId); - } - } - } - - updateActorsWithDependency(raceId); - } - - void ActorAdapter::updateActor(const std::string& refId) - { - int index = mReferenceables.searchId(refId); - if (index != -1) - { - int typeColumn = mReferenceables.findColumnIndex(CSMWorld::Columns::ColumnId_RecordType); - int recordType = mReferenceables.getData(index, typeColumn).toInt(); - if (recordType == CSMWorld::UniversalId::Type_Creature) - updateCreature(refId); - else if (recordType == CSMWorld::UniversalId::Type_Npc) - updateNpc(refId); - } - } - - void ActorAdapter::updateNpc(const std::string& refId) - { - auto& record = mReferenceables.getRecord(refId); - - // Retrieve record if possible - if (record.isDeleted()) - { - mCachedActors.erase(refId); - emit actorChanged(refId); + // Record does not exist return; } - auto& npc = dynamic_cast&>(record).get(); - // Create holder for cached data - auto actorIt = mCachedActors.find(refId); - if (actorIt == mCachedActors.end()) + auto& raceRecord = mRaces.getRecord(index); + if (raceRecord.isDeleted()) { - auto result = mCachedActors.emplace(refId, ActorData()); - actorIt = result.first; + // Record is deleted, so not accessible + return; } - auto& actorData = actorIt->second; - // Reset old data - actorData.parts.clear(); - actorData.dependencies.clear(); + // TODO move stuff in actor related to race here - // Look at the npc's inventory first + // Setup body parts + for (int i = 0; i < mBodyParts.getSize(); ++i) + { + std::string partId = mBodyParts.getId(i); + auto& partRecord = mBodyParts.getRecord(i); + + if (partRecord.isDeleted()) + { + // Record is deleted, so not accessible. + continue; + } + + auto& part = partRecord.get(); + if (part.mRace == id && part.mData.mType == ESM::BodyPart::MT_Skin && !is1stPersonPart(part.mId)) + { + auto type = (ESM::BodyPart::MeshPart) part.mData.mPart; + bool female = part.mData.mFlags & ESM::BodyPart::BPF_Female; + if (female) data->setFemalePart(type, part.mId); + else data->setMalePart(type, part.mId); + } + } + } + + void ActorAdapter::setupNpc(const std::string& id, ActorDataPtr data) + { + // Common setup, record is known to exist and is not deleted + int index = mReferenceables.searchId(id); + auto& npc = dynamic_cast&>(mReferenceables.getRecord(index)).get(); + + RaceDataPtr raceData = getRaceData(npc.mRace); + data->reset(id, !npc.isMale(), raceData); + + // Add inventory items for (auto& item : npc.mInventory.mList) { - if (item.mCount > 0) + if (item.mCount <= 0) continue; + std::string itemId = item.mItem.toString(); + addNpcItem(itemId, data); + } + + // Add head and hair + data->setPart(ESM::PRT_Head, npc.mHead); + data->setPart(ESM::PRT_Hair, npc.mHair); + } + + void ActorAdapter::addNpcItem(const std::string& itemId, ActorDataPtr data) + { + int index = mReferenceables.searchId(itemId); + if (index == -1) + { + // Item does not exist yet + data->addOtherDependency(itemId); + return; + } + + auto& record = mReferenceables.getRecord(index); + if (record.isDeleted()) + { + // Item cannot be accessed yet + data->addOtherDependency(itemId); + return; + } + + // Convenience function to add a parts list to actor data + auto addParts = [&](const ESM::PartReferenceList& list) { + for (auto& part : list.mParts) { - std::string itemId = item.mItem.toString(); - // Handle armor and clothing - int index = mReferenceables.searchId(itemId); - if (index != -1 && !mReferenceables.getRecord(index).isDeleted()) - { - auto& itemRecord = mReferenceables.getRecord(index); + std::string partId; + auto partType = (ESM::PartReferenceType) part.mPart; - int typeColumn = mReferenceables.findColumnIndex(CSMWorld::Columns::ColumnId_RecordType); - int recordType = mReferenceables.getData(index, typeColumn).toInt(); - if (recordType == CSMWorld::UniversalId::Type_Armor) - { - // Changes here could affect the actor - actorData.dependencies.emplace(itemId, true); + if (data->isFemale()) + partId = part.mFemale; + if (partId.empty()) + partId = part.mMale; - // Add any parts if there is room - auto& armor = dynamic_cast&>(itemRecord).get(); - for (auto& part : armor.mParts.mParts) - { - std::string bodyPartId; - if (!npc.isMale()) - bodyPartId = part.mFemale; - if (bodyPartId.empty()) - bodyPartId = part.mMale; + if (!partId.empty()) data->setPart(partType, partId); + } + }; - if (!bodyPartId.empty()) - { - actorData.parts.emplace(static_cast(part.mPart), bodyPartId); - actorData.dependencies.emplace(bodyPartId, true); - } - } - } - else if (recordType == CSMWorld::UniversalId::Type_Clothing) - { - // Changes here could affect the actor - actorData.dependencies.emplace(itemId, true); + int TypeColumn = mReferenceables.findColumnIndex(Columns::ColumnId_RecordType); + int type = mReferenceables.getData(index, TypeColumn).toInt(); + if (type == UniversalId::Type_Armor) + { + auto& armor = dynamic_cast&>(record).get(); + addParts(armor.mParts); - // Add any parts if there is room - auto& clothing = dynamic_cast&>(itemRecord).get(); - for (auto& part : clothing.mParts.mParts) - { - std::string bodyPartId; - if (!npc.isMale()) - bodyPartId = part.mFemale; - if (bodyPartId.empty()) - bodyPartId = part.mMale; + // Changing parts could affect what is picked for rendering + data->addOtherDependency(itemId); + } + else if (type == UniversalId::Type_Clothing) + { + auto& clothing = dynamic_cast&>(record).get(); + addParts(clothing.mParts); - if (!bodyPartId.empty()) - { - actorData.parts.emplace(static_cast(part.mPart), bodyPartId); - actorData.dependencies.emplace(bodyPartId, true); - } - } - } - } + // Changing parts could affect what is picked for rendering + data->addOtherDependency(itemId); + } + } + + void ActorAdapter::setupCreature(const std::string& id, ActorDataPtr data) + { + data->reset(id); + + // TODO move stuff from Actor here + } + + void ActorAdapter::markDirtyDependency(const std::string& dep) + { + for (auto raceIt : mCachedRaces) + { + if (raceIt->hasDependency(dep)) + mDirtyRaces.emplace(raceIt->getId()); + } + for (auto actorIt : mCachedActors) + { + if (actorIt->hasDependency(dep)) + mDirtyActors.emplace(actorIt->getId()); + } + } + + void ActorAdapter::updateDirty() + { + // Handle races before actors, since actors are dependent on race + for (auto& race : mDirtyRaces) + { + RaceDataPtr data = mCachedRaces.get(race); + if (data) + { + setupRace(race, data); } } + mDirtyRaces.clear(); - // Lookup cached race parts - auto& raceData = getRaceData(npc.mRace); - - // Changes to race could affect the actor - actorData.dependencies.emplace(npc.mRace, true); - - // Fill in the rest with race specific body parts - for (int i = 0; i < ESM::PRT_Count; ++i) + for (auto& actor : mDirtyActors) { - auto type = static_cast(i); - if (actorData.parts.find(type) == actorData.parts.end()) + ActorDataPtr data = mCachedActors.get(actor); + if (data) { - switch (type) - { - case ESM::PRT_Head: - actorData.parts.emplace(type, npc.mHead); - actorData.dependencies.emplace(npc.mHead, true); - break; - case ESM::PRT_Hair: - actorData.parts.emplace(type, npc.mHair); - actorData.dependencies.emplace(npc.mHair, true); - break; - case ESM::PRT_Skirt: - case ESM::PRT_Shield: - case ESM::PRT_RPauldron: - case ESM::PRT_LPauldron: - case ESM::PRT_Weapon: - // No body part associated - break; - default: - { - std::string bodyPartId; - // Check female map if applicable - if (!npc.isMale()) - { - auto partIt = raceData.femaleParts.find(ESM::getMeshPart(type)); - if (partIt != raceData.femaleParts.end()) - bodyPartId = partIt->second; - } - - // Check male map next - if (bodyPartId.empty() || npc.isMale()) - { - auto partIt = raceData.maleParts.find(ESM::getMeshPart(type)); - if (partIt != raceData.maleParts.end()) - bodyPartId = partIt->second; - } - - // Add to map - if (!bodyPartId.empty()) - { - actorData.parts.emplace(type, bodyPartId); - actorData.dependencies.emplace(bodyPartId, true); - } - } - } + setupActor(actor, data); } } - - // Signal change to actor - emit actorChanged(refId); - } - - void ActorAdapter::updateCreature(const std::string& refId) - { - // Signal change to actor - emit actorChanged(refId); - } - - void ActorAdapter::updateActorsWithDependency(const std::string& id) - { - for (auto it : mCachedActors) - { - auto& deps = it.second.dependencies; - if (deps.find(id) != deps.end()) - updateActor(it.first); - } - } - - void ActorAdapter::updateRacesWithDependency(const std::string& id) - { - for (auto it : mCachedRaces) - { - auto& deps = it.second.dependencies; - if (deps.find(id) != deps.end()) - updateRace(it.first); - } + mDirtyActors.clear(); } } diff --git a/apps/opencs/model/world/actoradapter.hpp b/apps/opencs/model/world/actoradapter.hpp index f1148199c..0e8b0c9fe 100644 --- a/apps/opencs/model/world/actoradapter.hpp +++ b/apps/opencs/model/world/actoradapter.hpp @@ -1,13 +1,13 @@ #ifndef CSM_WOLRD_ACTORADAPTER_H #define CSM_WOLRD_ACTORADAPTER_H -#include -#include -#include +#include +#include #include #include +#include #include #include @@ -17,88 +17,147 @@ namespace ESM { struct Race; - enum PartReferenceType; } namespace CSMWorld { class Data; - /// Quick and dirty hashing functor. - struct StringBoolPairHash - { - size_t operator()(const std::pair& value) const noexcept - { - auto stringHash = std::hash(); - return stringHash(value.first) + value.second; - } - }; - + /// Adapts multiple collections to provide the data needed to render + /// an npc or creature. class ActorAdapter : public QObject { - Q_OBJECT + Q_OBJECT + public: + + /// A list indexed by ESM::PartReferenceType + using ActorPartList = std::array; + /// A list indexed by ESM::BodyPart::MeshPart + using RacePartList = std::array; + /// Tracks unique strings + using StringSet = std::unordered_set; + + + /// Contains base race data shared between actors + class RaceData + { public: + /// Retrieves the id of the race represented + const std::string& getId() const; + /// Checks if a part could exist for the given type + bool handlesPart(ESM::PartReferenceType type) const; + /// Retrieves the associated body part + const std::string& getFemalePart(ESM::PartReferenceType index) const; + /// Retrieves the associated body part + const std::string& getMalePart(ESM::PartReferenceType index) const; + /// Checks if the race has a data dependency + bool hasDependency(const std::string& id) const; - // Maps body part type to 'body part' id - using ActorPartMap = std::unordered_map; - - ActorAdapter(CSMWorld::Data& data); - - const ActorPartMap* getActorParts(const std::string& refId, bool create=true); - - signals: - - void actorChanged(const std::string& refId); - - public slots: - - void handleReferenceableChanged(const QModelIndex&, const QModelIndex&); - void handleRaceChanged(const QModelIndex&, const QModelIndex&); - void handleBodyPartChanged(const QModelIndex&, const QModelIndex&); + /// Sets the associated part if it's empty and marks a dependency + void setFemalePart(ESM::BodyPart::MeshPart partIndex, const std::string& partId); + /// Sets the associated part if it's empty and marks a dependency + void setMalePart(ESM::BodyPart::MeshPart partIndex, const std::string& partId); + /// Marks an additional dependency + void addOtherDependency(const std::string& id); + /// Clears parts and dependencies + void reset(const std::string& raceId); private: - // Maps mesh part type to 'body part' id - using RacePartMap = std::unordered_map; - // Stores ids that are referenced by the actor. Data part is meaningless. - using DependencyMap = std::unordered_map; + bool handles(ESM::PartReferenceType type) const; + std::string mId; + RacePartList mFemaleParts; + RacePartList mMaleParts; + StringSet mDependencies; + }; + using RaceDataPtr = std::shared_ptr; - struct ActorData - { - ActorPartMap parts; - DependencyMap dependencies; - }; + /// Contains all the data needed to render an actor. Tracks dependencies + /// so that pertinent data changes can be checked. + class ActorData + { + public: + /// Retrieves the id of the actor represented + const std::string& getId() const; + /// Checks if the actor is female + bool isFemale() const; + /// Retrieves the associated actor part + const std::string& getPart(ESM::PartReferenceType index) const; + /// Checks if the actor has a data dependency + bool hasDependency(const std::string& id) const; - struct RaceData - { - RacePartMap femaleParts; - RacePartMap maleParts; - DependencyMap dependencies; - }; + /// Sets the actor part used and marks a dependency + void setPart(ESM::PartReferenceType partIndex, const std::string& partId); + /// Marks an additional dependency for the actor + void addOtherDependency(const std::string& id); + /// Clears race, parts, and dependencies + void reset(const std::string& actorId, bool female=true, RaceDataPtr raceData=nullptr); - ActorAdapter(const ActorAdapter&) = delete; - ActorAdapter& operator=(const ActorAdapter&) = delete; + private: + std::string mId; + bool mFemale; + RaceDataPtr mRaceData; + ActorPartList mParts; + StringSet mDependencies; + }; + using ActorDataPtr = std::shared_ptr; - QModelIndex getHighestIndex(QModelIndex) const; - bool is1stPersonPart(const std::string& id) const; - RaceData& getRaceData(const std::string& raceId); + ActorAdapter(Data& data); - void updateRace(const std::string& raceId); - void updateActor(const std::string& refId); - void updateNpc(const std::string& refId); - void updateCreature(const std::string& refId); + /// Obtains the shared data for a given actor + ActorDataPtr getActorData(const std::string& refId); - void updateActorsWithDependency(const std::string& id); - void updateRacesWithDependency(const std::string& id); + signals: - RefIdCollection& mReferenceables; - IdCollection& mRaces; - IdCollection& mBodyParts; + void actorChanged(const std::string& refId); - // Key: referenceable id - std::unordered_map mCachedActors; - // Key: race id - std::unordered_map mCachedRaces; + public slots: + + void handleReferenceablesInserted(const QModelIndex&, int, int); + void handleReferenceableChanged(const QModelIndex&, const QModelIndex&); + void handleReferenceablesAboutToBeRemoved(const QModelIndex&, int, int); + void handleReferenceablesRemoved(const QModelIndex&, int, int); + + void handleRacesInserted(const QModelIndex&, int, int); + void handleRaceChanged(const QModelIndex&, const QModelIndex&); + void handleRacesAboutToBeRemoved(const QModelIndex&, int, int); + void handleRacesRemoved(const QModelIndex&, int, int); + + void handleBodyPartsInserted(const QModelIndex&, int, int); + void handleBodyPartChanged(const QModelIndex&, const QModelIndex&); + void handleBodyPartsAboutToBeRemoved(const QModelIndex&, int, int); + void handleBodyPartsRemoved(const QModelIndex&, int, int); + + private: + + ActorAdapter(const ActorAdapter&) = delete; + ActorAdapter& operator=(const ActorAdapter&) = delete; + + QModelIndex getHighestIndex(QModelIndex) const; + bool is1stPersonPart(const std::string& id) const; + + RaceDataPtr getRaceData(const std::string& raceId); + + void setupActor(const std::string& id, ActorDataPtr data); + void setupRace(const std::string& id, RaceDataPtr data); + + void setupNpc(const std::string& id, ActorDataPtr data); + void addNpcItem(const std::string& itemId, ActorDataPtr data); + + void setupCreature(const std::string& id, ActorDataPtr data); + + void markDirtyDependency(const std::string& dependency); + void updateDirty(); + + RefIdCollection& mReferenceables; + IdCollection& mRaces; + IdCollection& mBodyParts; + + cache::WeakCache mCachedActors; // Key: referenceable id + cache::WeakCache mCachedRaces; // Key: race id + + StringSet mDirtyActors; // Actors that need updating + StringSet mDirtyRaces; // Races that need updating }; } diff --git a/apps/opencs/view/render/actor.cpp b/apps/opencs/view/render/actor.cpp index b9979ae2c..0a2519d0d 100644 --- a/apps/opencs/view/render/actor.cpp +++ b/apps/opencs/view/render/actor.cpp @@ -26,6 +26,7 @@ namespace CSVRender , mBaseNode(new osg::Group()) , mSkeleton(nullptr) { + mActorData = mData.getActorAdapter()->getActorData(mId); } osg::Group* Actor::getBaseNode() @@ -60,7 +61,6 @@ namespace CSVRender { if (mId == refId) { - Log(Debug::Info) << "Actor::actorChanged " << mId; update(); } } @@ -80,9 +80,6 @@ namespace CSVRender mSkeleton->accept(removeTriBipVisitor); removeTriBipVisitor.remove(); - // Attach weapons - loadBodyParts(creature.mId); - // Post setup mSkeleton->markDirty(); mSkeleton->setActive(SceneUtil::Skeleton::Active); @@ -141,12 +138,11 @@ namespace CSVRender void Actor::loadBodyParts(const std::string& actorId) { - auto actorAdapter = mData.getActorAdapter(); - auto parts = actorAdapter->getActorParts(actorId); - if (parts) + for (int i = 0; i < ESM::PRT_Count; ++i) { - for (auto& pair : *parts) - attachBodyPart(pair.first, getBodyPartMesh(pair.second)); + auto type = (ESM::PartReferenceType) i; + std::string partId = mActorData->getPart(type); + attachBodyPart(type, getBodyPartMesh(partId)); } } diff --git a/apps/opencs/view/render/actor.hpp b/apps/opencs/view/render/actor.hpp index 42a6019ed..d7cbb3067 100644 --- a/apps/opencs/view/render/actor.hpp +++ b/apps/opencs/view/render/actor.hpp @@ -10,6 +10,8 @@ #include #include +#include "../../model/world/actoradapter.hpp" + namespace osg { class Group; @@ -63,6 +65,7 @@ namespace CSVRender bool mInitialized; int mType; CSMWorld::Data& mData; + CSMWorld::ActorAdapter::ActorDataPtr mActorData; osg::ref_ptr mBaseNode; SceneUtil::Skeleton* mSkeleton; diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 7af76137c..494e1c5ce 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -150,6 +150,10 @@ add_component_dir (fallback fallback validate ) +add_component_dir(cache + weakcache + ) + if(NOT WIN32 AND NOT ANDROID) add_component_dir (crashcatcher crashcatcher diff --git a/components/cache/weakcache.hpp b/components/cache/weakcache.hpp new file mode 100644 index 000000000..9d940cd74 --- /dev/null +++ b/components/cache/weakcache.hpp @@ -0,0 +1,116 @@ +#ifndef OPENMW_COMPONENTS_WEAKCACHE_HPP +#define OPENMW_COMPONENTS_WEAKCACHE_HPP + +#include +#include + +namespace cache +{ + /// \class WeakCache + /// Provides a container to weakly store pointers to shared data. + template + class WeakCache + { + public: + using WeakPtr = std::weak_ptr; + using StrongPtr = std::shared_ptr; + using Map = std::unordered_map; + + class iterator + { + public: + iterator(typename Map::iterator current, typename Map::iterator end); + iterator& operator++(); + bool operator==(const iterator& other); + bool operator!=(const iterator& other); + StrongPtr operator*(); + private: + typename Map::iterator mCurrent, mEnd; + StrongPtr mPtr; + }; + + /// Stores a weak pointer to the item. + void insert(Key key, StrongPtr value); + + /// Retrieves the item associated with the key. + /// \return An item or null. + StrongPtr get(Key key); + + iterator begin(); + iterator end(); + + private: + Map mData; + }; + + + template + WeakCache::iterator::iterator(typename Map::iterator current, typename Map::iterator end) + : mCurrent(current) + , mEnd(end) + { + // Move to 1st available valid item + for ( ; mCurrent != mEnd; ++mCurrent) + { + mPtr = mCurrent->second.lock(); + if (mPtr) break; + } + } + + template + typename WeakCache::iterator& WeakCache::iterator::operator++() + { + auto next = mCurrent; + ++next; + return *this = iterator(next, mEnd); + } + + template + bool WeakCache::iterator::operator==(const iterator& other) + { + return mCurrent == other.mCurrent; + } + + template + bool WeakCache::iterator::operator!=(const iterator& other) + { + return !(*this == other); + } + + template + typename WeakCache::StrongPtr WeakCache::iterator::operator*() + { + return mPtr; + } + + + template + void WeakCache::insert(Key key, StrongPtr value) + { + mData[key] = WeakPtr(value); + } + + template + typename WeakCache::StrongPtr WeakCache::get(Key key) + { + auto searchIt = mData.find(key); + if (searchIt != mData.end()) + return searchIt->second.lock(); + else + return StrongPtr(); + } + + template + typename WeakCache::iterator WeakCache::begin() + { + return iterator(mData.begin(), mData.end()); + } + + template + typename WeakCache::iterator WeakCache::end() + { + return iterator(mData.end(), mData.end()); + } +} + +#endif From 1518d630caa7068e2cf405120a65680bd08ac3e5 Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Fri, 7 Sep 2018 22:00:02 -0400 Subject: [PATCH 170/196] Fix issue with body part events not propogating to actors --- apps/opencs/model/world/actoradapter.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/apps/opencs/model/world/actoradapter.cpp b/apps/opencs/model/world/actoradapter.cpp index b3a1216f7..6f564bac5 100644 --- a/apps/opencs/model/world/actoradapter.cpp +++ b/apps/opencs/model/world/actoradapter.cpp @@ -555,6 +555,14 @@ namespace CSMWorld if (data) { setupRace(race, data); + // Race was changed. Need to mark actor dependencies as dirty. + // Cannot use markDirtyDependency because that would invalidate + // the current iterator. + for (auto actorIt : mCachedActors) + { + if (actorIt->hasDependency(race)) + mDirtyActors.emplace(actorIt->getId()); + } } } mDirtyRaces.clear(); From c1ec926f4327c46dc98003ff90ecaf9205c665bf Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Fri, 7 Sep 2018 23:38:11 -0400 Subject: [PATCH 171/196] Workaround inconsistencies with record status changes --- apps/opencs/model/world/actoradapter.cpp | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/apps/opencs/model/world/actoradapter.cpp b/apps/opencs/model/world/actoradapter.cpp index 6f564bac5..d081f8a3e 100644 --- a/apps/opencs/model/world/actoradapter.cpp +++ b/apps/opencs/model/world/actoradapter.cpp @@ -195,6 +195,10 @@ namespace CSMWorld int start = getHighestIndex(topLeft).row(); int end = getHighestIndex(botRight).row(); + // A change to record status (ex. Deleted) returns an invalid botRight + if (end == -1) + end = start; + // Handle each record for (int row = start; row <= end; ++row) { @@ -245,6 +249,11 @@ namespace CSMWorld { int start = getHighestIndex(topLeft).row(); int end = getHighestIndex(botRight).row(); + + // A change to record status (ex. Deleted) returns an invalid botRight + if (end == -1) + end = start; + for (int row = start; row <= end; ++row) { std::string raceId = mRaces.getId(row); @@ -299,9 +308,14 @@ namespace CSMWorld void ActorAdapter::handleBodyPartChanged(const QModelIndex& topLeft, const QModelIndex& botRight) { - int rowStart = getHighestIndex(topLeft).row(); - int rowEnd = getHighestIndex(botRight).row(); - for (int row = rowStart; row <= rowEnd; ++row) + int start = getHighestIndex(topLeft).row(); + int end = getHighestIndex(botRight).row(); + + // A change to record status (ex. Deleted) returns an invalid botRight + if (end == -1) + end = start; + + for (int row = start; row <= end; ++row) { // Race specified by part may need update auto& record = mBodyParts.getRecord(row); From f43b70d77be6a21015c93db5076edcc118594c53 Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Sat, 8 Sep 2018 02:06:48 -0400 Subject: [PATCH 172/196] Centralize actor data, simplify logic --- apps/opencs/model/world/actoradapter.cpp | 52 ++++++++++--- apps/opencs/model/world/actoradapter.hpp | 13 +++- apps/opencs/view/render/actor.cpp | 97 +++++++----------------- apps/opencs/view/render/actor.hpp | 9 +-- apps/opencs/view/render/object.cpp | 88 +++++++++------------ 5 files changed, 116 insertions(+), 143 deletions(-) diff --git a/apps/opencs/model/world/actoradapter.cpp b/apps/opencs/model/world/actoradapter.cpp index d081f8a3e..47bc5f4da 100644 --- a/apps/opencs/model/world/actoradapter.cpp +++ b/apps/opencs/model/world/actoradapter.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include "data.hpp" @@ -16,6 +17,11 @@ namespace CSMWorld return mId; } + bool ActorAdapter::RaceData::isBeast() const + { + return mIsBeast; + } + bool ActorAdapter::RaceData::handlesPart(ESM::PartReferenceType type) const { switch (type) @@ -63,9 +69,10 @@ namespace CSMWorld if (!id.empty()) mDependencies.emplace(id); } - void ActorAdapter::RaceData::reset(const std::string& id) + void ActorAdapter::RaceData::reset_data(const std::string& id, bool isBeast) { mId = id; + mIsBeast = isBeast; for (auto& str : mFemaleParts) str.clear(); for (auto& str : mMaleParts) @@ -82,11 +89,28 @@ namespace CSMWorld return mId; } + bool ActorAdapter::ActorData::isCreature() const + { + return mCreature; + } + bool ActorAdapter::ActorData::isFemale() const { return mFemale; } + std::string ActorAdapter::ActorData::getSkeleton() const + { + if (mCreature || !mSkeletonOverride.empty()) + return "meshes\\" + mSkeletonOverride; + + bool firstPerson = false; + bool beast = mRaceData ? mRaceData->isBeast() : false; + bool werewolf = false; + + return SceneUtil::getActorSkeleton(firstPerson, mFemale, beast, werewolf); + } + const std::string& ActorAdapter::ActorData::getPart(ESM::PartReferenceType index) const { if (mParts[index].empty() && mRaceData && mRaceData->handlesPart(index)) @@ -112,10 +136,12 @@ namespace CSMWorld if (!id.empty()) mDependencies.emplace(id); } - void ActorAdapter::ActorData::reset(const std::string& id, bool isFemale, RaceDataPtr raceData) + void ActorAdapter::ActorData::reset_data(const std::string& id, const std::string& skeleton, bool isCreature, bool isFemale, RaceDataPtr raceData) { mId = id; + mCreature = isCreature; mFemale = isFemale; + mSkeletonOverride = skeleton; mRaceData = raceData; for (auto& str : mParts) str.clear(); @@ -383,7 +409,7 @@ namespace CSMWorld if (index == -1) { // Record does not exist - data->reset(id); + data->reset_data(id); emit actorChanged(id); return; } @@ -392,7 +418,7 @@ namespace CSMWorld if (record.isDeleted()) { // Record is deleted and therefore not accessible - data->reset(id); + data->reset_data(id); emit actorChanged(id); return; } @@ -414,20 +440,18 @@ namespace CSMWorld else { // Wrong record type - data->reset(id); + data->reset_data(id); emit actorChanged(id); } } void ActorAdapter::setupRace(const std::string& id, RaceDataPtr data) { - // Common setup - data->reset(id); - int index = mRaces.searchId(id); if (index == -1) { // Record does not exist + data->reset_data(id); return; } @@ -435,10 +459,12 @@ namespace CSMWorld if (raceRecord.isDeleted()) { // Record is deleted, so not accessible + data->reset_data(id); return; } - // TODO move stuff in actor related to race here + auto& race = raceRecord.get(); + data->reset_data(id, race.mData.mFlags & ESM::Race::Beast); // Setup body parts for (int i = 0; i < mBodyParts.getSize(); ++i) @@ -470,7 +496,7 @@ namespace CSMWorld auto& npc = dynamic_cast&>(mReferenceables.getRecord(index)).get(); RaceDataPtr raceData = getRaceData(npc.mRace); - data->reset(id, !npc.isMale(), raceData); + data->reset_data(id, "", false, !npc.isMale(), raceData); // Add inventory items for (auto& item : npc.mInventory.mList) @@ -541,9 +567,11 @@ namespace CSMWorld void ActorAdapter::setupCreature(const std::string& id, ActorDataPtr data) { - data->reset(id); + // Record is known to exist and is not deleted + int index = mReferenceables.searchId(id); + auto& creature = dynamic_cast&>(mReferenceables.getRecord(index)).get(); - // TODO move stuff from Actor here + data->reset_data(id, creature.mModel, true); } void ActorAdapter::markDirtyDependency(const std::string& dep) diff --git a/apps/opencs/model/world/actoradapter.hpp b/apps/opencs/model/world/actoradapter.hpp index 0e8b0c9fe..ba714e840 100644 --- a/apps/opencs/model/world/actoradapter.hpp +++ b/apps/opencs/model/world/actoradapter.hpp @@ -44,6 +44,8 @@ namespace CSMWorld public: /// Retrieves the id of the race represented const std::string& getId() const; + /// Checks if it's a beast race + bool isBeast() const; /// Checks if a part could exist for the given type bool handlesPart(ESM::PartReferenceType type) const; /// Retrieves the associated body part @@ -60,11 +62,12 @@ namespace CSMWorld /// Marks an additional dependency void addOtherDependency(const std::string& id); /// Clears parts and dependencies - void reset(const std::string& raceId); + void reset_data(const std::string& raceId, bool isBeast=false); private: bool handles(ESM::PartReferenceType type) const; std::string mId; + bool mIsBeast; RacePartList mFemaleParts; RacePartList mMaleParts; StringSet mDependencies; @@ -78,8 +81,12 @@ namespace CSMWorld public: /// Retrieves the id of the actor represented const std::string& getId() const; + /// Checks if the actor is a creature + bool isCreature() const; /// Checks if the actor is female bool isFemale() const; + /// Returns the skeleton the actor should use for attaching parts to + std::string getSkeleton() const; /// Retrieves the associated actor part const std::string& getPart(ESM::PartReferenceType index) const; /// Checks if the actor has a data dependency @@ -90,11 +97,13 @@ namespace CSMWorld /// Marks an additional dependency for the actor void addOtherDependency(const std::string& id); /// Clears race, parts, and dependencies - void reset(const std::string& actorId, bool female=true, RaceDataPtr raceData=nullptr); + void reset_data(const std::string& actorId, const std::string& skeleton="", bool isCreature=false, bool female=true, RaceDataPtr raceData=nullptr); private: std::string mId; + bool mCreature; bool mFemale; + std::string mSkeletonOverride; RaceDataPtr mRaceData; ActorPartList mParts; StringSet mDependencies; diff --git a/apps/opencs/view/render/actor.cpp b/apps/opencs/view/render/actor.cpp index 0a2519d0d..7238166fc 100644 --- a/apps/opencs/view/render/actor.cpp +++ b/apps/opencs/view/render/actor.cpp @@ -18,15 +18,15 @@ namespace CSVRender { const std::string Actor::MeshPrefix = "meshes\\"; - Actor::Actor(const std::string& id, int type, CSMWorld::Data& data) + Actor::Actor(const std::string& id, CSMWorld::Data& data) : mId(id) - , mInitialized(false) - , mType(type) , mData(data) , mBaseNode(new osg::Group()) , mSkeleton(nullptr) { mActorData = mData.getActorAdapter()->getActorData(mId); + connect(mData.getActorAdapter(), SIGNAL(actorChanged(const std::string&)), + this, SLOT(handleActorChanged(const std::string&))); } osg::Group* Actor::getBaseNode() @@ -36,25 +36,33 @@ namespace CSVRender void Actor::update() { - try - { - mBaseNode->removeChildren(0, mBaseNode->getNumChildren()); + mBaseNode->removeChildren(0, mBaseNode->getNumChildren()); - if (mType == CSMWorld::UniversalId::Type_Npc) - updateNpc(); - else if (mType == CSMWorld::UniversalId::Type_Creature) - updateCreature(); - } - catch (std::exception& e) + // Load skeleton + std::string skeletonModel = mActorData->getSkeleton(); + skeletonModel = Misc::ResourceHelpers::correctActorModelPath(skeletonModel, mData.getResourceSystem()->getVFS()); + loadSkeleton(skeletonModel); + + if (!mActorData->isCreature()) { - Log(Debug::Info) << "Exception in Actor::update(): " << e.what(); + // Get rid of the extra attachments + SceneUtil::CleanObjectRootVisitor cleanVisitor; + mSkeleton->accept(cleanVisitor); + cleanVisitor.remove(); + + // Attach parts to skeleton + loadBodyParts(); + } + else + { + SceneUtil::RemoveTriBipVisitor removeTriBipVisitor; + mSkeleton->accept(removeTriBipVisitor); + removeTriBipVisitor.remove(); } - if (!mInitialized) - { - mInitialized = true; - connect(mData.getActorAdapter(), SIGNAL(actorChanged(const std::string&)), this, SLOT(handleActorChanged(const std::string&))); - } + // Post setup + mSkeleton->markDirty(); + mSkeleton->setActive(SceneUtil::Skeleton::Active); } void Actor::handleActorChanged(const std::string& refId) @@ -65,57 +73,6 @@ namespace CSVRender } } - void Actor::updateCreature() - { - auto& referenceables = mData.getReferenceables(); - - auto& creature = dynamic_cast& >(referenceables.getRecord(mId)).get(); - - // Load skeleton with meshes - std::string skeletonModel = MeshPrefix + creature.mModel; - skeletonModel = Misc::ResourceHelpers::correctActorModelPath(skeletonModel, mData.getResourceSystem()->getVFS()); - loadSkeleton(skeletonModel); - - SceneUtil::RemoveTriBipVisitor removeTriBipVisitor; - mSkeleton->accept(removeTriBipVisitor); - removeTriBipVisitor.remove(); - - // Post setup - mSkeleton->markDirty(); - mSkeleton->setActive(SceneUtil::Skeleton::Active); - } - - void Actor::updateNpc() - { - auto& races = mData.getRaces(); - auto& referenceables = mData.getReferenceables(); - - auto& npc = dynamic_cast& >(referenceables.getRecord(mId)).get(); - auto& race = dynamic_cast& >(races.getRecord(npc.mRace)).get(); - - bool is1stPerson = false; - bool isFemale = !npc.isMale(); - bool isBeast = race.mData.mFlags & ESM::Race::Beast; - bool isWerewolf = false; - - // Load skeleton - std::string skeletonModel = SceneUtil::getActorSkeleton(is1stPerson, isFemale, isBeast, isWerewolf); - skeletonModel = Misc::ResourceHelpers::correctActorModelPath(skeletonModel, mData.getResourceSystem()->getVFS()); - loadSkeleton(skeletonModel); - - // Get rid of the extra attachments - SceneUtil::CleanObjectRootVisitor cleanVisitor; - mSkeleton->accept(cleanVisitor); - cleanVisitor.remove(); - - // Attach parts to skeleton - loadBodyParts(npc.mId); - - // Post setup - mSkeleton->markDirty(); - mSkeleton->setActive(SceneUtil::Skeleton::Active); - } - void Actor::loadSkeleton(const std::string& model) { auto sceneMgr = mData.getResourceSystem()->getSceneManager(); @@ -136,7 +93,7 @@ namespace CSVRender } - void Actor::loadBodyParts(const std::string& actorId) + void Actor::loadBodyParts() { for (int i = 0; i < ESM::PRT_Count; ++i) { diff --git a/apps/opencs/view/render/actor.hpp b/apps/opencs/view/render/actor.hpp index d7cbb3067..2f19454f7 100644 --- a/apps/opencs/view/render/actor.hpp +++ b/apps/opencs/view/render/actor.hpp @@ -38,7 +38,7 @@ namespace CSVRender /// \param id The referenceable id /// \param type The record type /// \param data The data store - Actor(const std::string& id, int type, CSMWorld::Data& data); + Actor(const std::string& id, CSMWorld::Data& data); /// Retrieves the base node that meshes are attached to osg::Group* getBaseNode(); @@ -50,11 +50,8 @@ namespace CSVRender void handleActorChanged(const std::string& refId); private: - void updateCreature(); - void updateNpc(); - void loadSkeleton(const std::string& model); - void loadBodyParts(const std::string& actorId); + void loadBodyParts(); void attachBodyPart(ESM::PartReferenceType, const std::string& mesh); std::string getBodyPartMesh(const std::string& bodyPartId); @@ -62,8 +59,6 @@ namespace CSVRender static const std::string MeshPrefix; std::string mId; - bool mInitialized; - int mType; CSMWorld::Data& mData; CSMWorld::ActorAdapter::ActorDataPtr mActorData; diff --git a/apps/opencs/view/render/object.cpp b/apps/opencs/view/render/object.cpp index 63f1bc8a8..6f0fb6606 100644 --- a/apps/opencs/view/render/object.cpp +++ b/apps/opencs/view/render/object.cpp @@ -83,74 +83,58 @@ void CSVRender::Object::update() { clear(); - std::string model; - int error = 0; // 1 referenceable does not exist, 2 referenceable does not specify a mesh - const CSMWorld::RefIdCollection& referenceables = mData.getReferenceables(); + const int TypeIndex = referenceables.findColumnIndex(CSMWorld::Columns::ColumnId_RecordType); + const int ModelIndex = referenceables.findColumnIndex (CSMWorld::Columns::ColumnId_Model); int index = referenceables.searchId (mReferenceableId); - int recordType = -1; const ESM::Light* light = NULL; - if (index==-1) - error = 1; - else - { - /// \todo check for Deleted state (error 1) - - model = referenceables.getData (index, - referenceables.findColumnIndex (CSMWorld::Columns::ColumnId_Model)). - toString().toUtf8().constData(); - - recordType = - referenceables.getData (index, - referenceables.findColumnIndex(CSMWorld::Columns::ColumnId_RecordType)).toInt(); - if (recordType == CSMWorld::UniversalId::Type_Light) - { - light = &dynamic_cast& >(referenceables.getRecord(index)).get(); - if (model.empty()) - model = "marker_light.nif"; - } - - if (recordType == CSMWorld::UniversalId::Type_CreatureLevelledList) - { - if (model.empty()) - model = "marker_creature.nif"; - } - - if (recordType != CSMWorld::UniversalId::Type_Npc && model.empty()) - error = 2; - } - mBaseNode->removeChildren(0, mBaseNode->getNumChildren()); - if (error) + if (index == -1) { mBaseNode->addChild(createErrorCube()); + return; } - else + + /// \todo check for Deleted state (error 1) + + int recordType = referenceables.getData(index, TypeIndex).toInt(); + std::string model = referenceables.getData(index, ModelIndex).toString().toUtf8().constData(); + + if (recordType == CSMWorld::UniversalId::Type_Light) { - try + light = &dynamic_cast& >(referenceables.getRecord(index)).get(); + if (model.empty()) + model = "marker_light.nif"; + } + + if (recordType == CSMWorld::UniversalId::Type_CreatureLevelledList) + { + if (model.empty()) + model = "marker_creature.nif"; + } + + try + { + if (recordType == CSMWorld::UniversalId::Type_Npc || recordType == CSMWorld::UniversalId::Type_Creature) { - if (recordType == CSMWorld::UniversalId::Type_Npc || recordType == CSMWorld::UniversalId::Type_Creature) - { - if (!mActor) - mActor.reset(new Actor(mReferenceableId, recordType, mData)); - mActor->update(); - mBaseNode->addChild(mActor->getBaseNode()); - } - else - { - std::string path = "meshes\\" + model; - mResourceSystem->getSceneManager()->getInstance(path, mBaseNode); - } + if (!mActor) mActor.reset(new Actor(mReferenceableId, mData)); + mActor->update(); + mBaseNode->addChild(mActor->getBaseNode()); } - catch (std::exception& e) + else { - Log(Debug::Error) << e.what(); - mBaseNode->addChild(createErrorCube()); + std::string path = "meshes\\" + model; + mResourceSystem->getSceneManager()->getInstance(path, mBaseNode); } } + catch (std::exception& e) + { + // TODO: use error marker mesh + Log(Debug::Error) << e.what(); + } if (light) { From 676fc488557453f1b49c2d0441221ac573de2efb Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Sat, 8 Sep 2018 02:24:33 -0400 Subject: [PATCH 173/196] Re-add logic for empty model --- apps/opencs/view/render/object.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/apps/opencs/view/render/object.cpp b/apps/opencs/view/render/object.cpp index 6f0fb6606..8b3b5ca25 100644 --- a/apps/opencs/view/render/object.cpp +++ b/apps/opencs/view/render/object.cpp @@ -124,11 +124,15 @@ void CSVRender::Object::update() mActor->update(); mBaseNode->addChild(mActor->getBaseNode()); } - else + else if (!model.empty()) { std::string path = "meshes\\" + model; mResourceSystem->getSceneManager()->getInstance(path, mBaseNode); } + else + { + throw std::runtime_error(mReferenceableId + " has no model"); + } } catch (std::exception& e) { From 0096951f2598df434e436000c994c1a3320179d7 Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Sat, 8 Sep 2018 02:32:47 -0400 Subject: [PATCH 174/196] cleanup --- apps/opencs/model/world/actoradapter.cpp | 1 - apps/opencs/model/world/data.hpp | 1 - apps/opencs/view/render/actor.cpp | 2 -- apps/opencs/view/render/object.cpp | 2 -- 4 files changed, 6 deletions(-) diff --git a/apps/opencs/model/world/actoradapter.cpp b/apps/opencs/model/world/actoradapter.cpp index 47bc5f4da..8c9e5bd1f 100644 --- a/apps/opencs/model/world/actoradapter.cpp +++ b/apps/opencs/model/world/actoradapter.cpp @@ -1,6 +1,5 @@ #include "actoradapter.hpp" -#include #include #include #include diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index 7c4d8885a..e50780f50 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -74,7 +74,6 @@ namespace ESM namespace CSMWorld { - class ActorAdapter; class ResourcesManager; class Resources; diff --git a/apps/opencs/view/render/actor.cpp b/apps/opencs/view/render/actor.cpp index 7238166fc..d6077a65a 100644 --- a/apps/opencs/view/render/actor.cpp +++ b/apps/opencs/view/render/actor.cpp @@ -3,12 +3,10 @@ #include #include -#include #include #include #include #include -#include #include #include diff --git a/apps/opencs/view/render/object.cpp b/apps/opencs/view/render/object.cpp index 8b3b5ca25..36d80fa4b 100644 --- a/apps/opencs/view/render/object.cpp +++ b/apps/opencs/view/render/object.cpp @@ -13,7 +13,6 @@ #include #include #include -#include #include @@ -31,7 +30,6 @@ #include #include #include -#include #include "actor.hpp" #include "mask.hpp" From 7eb1b14b21ba0122b1aac63c1b5a2be38249c6f7 Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Sat, 8 Sep 2018 03:13:03 -0400 Subject: [PATCH 175/196] Periodically prune empty elements in weak cache --- components/cache/weakcache.hpp | 38 +++++++++++++++++++++++++++------- 1 file changed, 30 insertions(+), 8 deletions(-) diff --git a/components/cache/weakcache.hpp b/components/cache/weakcache.hpp index 9d940cd74..976818cc2 100644 --- a/components/cache/weakcache.hpp +++ b/components/cache/weakcache.hpp @@ -3,6 +3,7 @@ #include #include +#include namespace cache { @@ -19,18 +20,19 @@ namespace cache class iterator { public: - iterator(typename Map::iterator current, typename Map::iterator end); + iterator(WeakCache* cache, typename Map::iterator current, typename Map::iterator end); iterator& operator++(); bool operator==(const iterator& other); bool operator!=(const iterator& other); StrongPtr operator*(); private: + WeakCache* mCache; typename Map::iterator mCurrent, mEnd; StrongPtr mPtr; }; /// Stores a weak pointer to the item. - void insert(Key key, StrongPtr value); + void insert(Key key, StrongPtr value, bool prune=true); /// Retrieves the item associated with the key. /// \return An item or null. @@ -39,14 +41,19 @@ namespace cache iterator begin(); iterator end(); + /// Removes known invalid entries + void prune(); + private: Map mData; + std::vector mDirty; }; template - WeakCache::iterator::iterator(typename Map::iterator current, typename Map::iterator end) - : mCurrent(current) + WeakCache::iterator::iterator(WeakCache* cache, typename Map::iterator current, typename Map::iterator end) + : mCache(cache) + , mCurrent(current) , mEnd(end) { // Move to 1st available valid item @@ -54,6 +61,7 @@ namespace cache { mPtr = mCurrent->second.lock(); if (mPtr) break; + else mCache->mDirty.push_back(mCurrent->first); } } @@ -62,7 +70,7 @@ namespace cache { auto next = mCurrent; ++next; - return *this = iterator(next, mEnd); + return *this = iterator(mCache, next, mEnd); } template @@ -85,9 +93,10 @@ namespace cache template - void WeakCache::insert(Key key, StrongPtr value) + void WeakCache::insert(Key key, StrongPtr value, bool shouldPrune) { mData[key] = WeakPtr(value); + if (shouldPrune) prune(); } template @@ -103,13 +112,26 @@ namespace cache template typename WeakCache::iterator WeakCache::begin() { - return iterator(mData.begin(), mData.end()); + return iterator(this, mData.begin(), mData.end()); } template typename WeakCache::iterator WeakCache::end() { - return iterator(mData.end(), mData.end()); + return iterator(this, mData.end(), mData.end()); + } + + template + void WeakCache::prune() + { + // Remove empty entries + for (auto& key : mDirty) + { + auto it = mData.find(key); + if (it != mData.end() && it->second.use_count() == 0) + mData.erase(it); + } + mDirty.clear(); } } From ac848b09028315850916bf644a22c965bd98581a Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Thu, 27 Sep 2018 13:14:34 +0400 Subject: [PATCH 176/196] Use male bodyparts as fallback for females in the editor --- apps/opencs/model/world/actoradapter.cpp | 12 ++++++++++-- apps/opencs/model/world/actoradapter.hpp | 2 +- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/apps/opencs/model/world/actoradapter.cpp b/apps/opencs/model/world/actoradapter.cpp index 8c9e5bd1f..425c4c804 100644 --- a/apps/opencs/model/world/actoradapter.cpp +++ b/apps/opencs/model/world/actoradapter.cpp @@ -110,11 +110,19 @@ namespace CSMWorld return SceneUtil::getActorSkeleton(firstPerson, mFemale, beast, werewolf); } - const std::string& ActorAdapter::ActorData::getPart(ESM::PartReferenceType index) const + const std::string ActorAdapter::ActorData::getPart(ESM::PartReferenceType index) const { if (mParts[index].empty() && mRaceData && mRaceData->handlesPart(index)) { - return mFemale ? mRaceData->getFemalePart(index) : mRaceData->getMalePart(index); + if (mFemale) + { + // Note: we should use male parts for females as fallback + const std::string femalePart = mRaceData->getFemalePart(index); + if (!femalePart.empty()) + return femalePart; + } + + return mRaceData->getMalePart(index); } return mParts[index]; } diff --git a/apps/opencs/model/world/actoradapter.hpp b/apps/opencs/model/world/actoradapter.hpp index ba714e840..d842bca35 100644 --- a/apps/opencs/model/world/actoradapter.hpp +++ b/apps/opencs/model/world/actoradapter.hpp @@ -88,7 +88,7 @@ namespace CSMWorld /// Returns the skeleton the actor should use for attaching parts to std::string getSkeleton() const; /// Retrieves the associated actor part - const std::string& getPart(ESM::PartReferenceType index) const; + const std::string getPart(ESM::PartReferenceType index) const; /// Checks if the actor has a data dependency bool hasDependency(const std::string& id) const; From 35abf7367cf85220c0117c270906661f73e8af76 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Thu, 27 Sep 2018 18:22:17 +0400 Subject: [PATCH 177/196] Implement wearing priority for editor --- CHANGELOG.md | 1 + apps/opencs/model/world/actoradapter.cpp | 83 ++++++++++++++++++++---- apps/opencs/model/world/actoradapter.hpp | 5 +- 3 files changed, 74 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 04547e249..c72ac7b9e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -132,6 +132,7 @@ Bug #4653: Length of non-ASCII strings is handled incorrectly in ESM reader Bug #4654: Editor: UpdateVisitor does not initialize skeletons for animated objects Feature #912: Editor: Add missing icons to UniversalId tables + Feature #1221: Editor: Creature/NPC rendering Feature #1617: Editor: Enchantment effect record verifier Feature #1645: Casting effects from objects Feature #2606: Editor: Implemented (optional) case sensitive global search diff --git a/apps/opencs/model/world/actoradapter.cpp b/apps/opencs/model/world/actoradapter.cpp index 425c4c804..ea40a1f8d 100644 --- a/apps/opencs/model/world/actoradapter.cpp +++ b/apps/opencs/model/world/actoradapter.cpp @@ -112,7 +112,8 @@ namespace CSMWorld const std::string ActorAdapter::ActorData::getPart(ESM::PartReferenceType index) const { - if (mParts[index].empty() && mRaceData && mRaceData->handlesPart(index)) + auto it = mParts.find(index); + if (it == mParts.end() && mRaceData && mRaceData->handlesPart(index)) { if (mFemale) { @@ -124,7 +125,9 @@ namespace CSMWorld return mRaceData->getMalePart(index); } - return mParts[index]; + + const std::string& partName = it->second.first; + return partName; } bool ActorAdapter::ActorData::hasDependency(const std::string& id) const @@ -132,9 +135,16 @@ namespace CSMWorld return mDependencies.find(id) != mDependencies.end(); } - void ActorAdapter::ActorData::setPart(ESM::PartReferenceType index, const std::string& partId) + void ActorAdapter::ActorData::setPart(ESM::PartReferenceType index, const std::string& partId, int priority) { - mParts[index] = partId; + auto it = mParts.find(index); + if (it != mParts.end()) + { + if (it->second.second >= priority) + return; + } + + mParts[index] = std::make_pair(partId, priority); addOtherDependency(partId); } @@ -150,8 +160,7 @@ namespace CSMWorld mFemale = isFemale; mSkeletonOverride = skeleton; mRaceData = raceData; - for (auto& str : mParts) - str.clear(); + mParts.clear(); mDependencies.clear(); // Mark self and race as a dependency @@ -514,8 +523,8 @@ namespace CSMWorld } // Add head and hair - data->setPart(ESM::PRT_Head, npc.mHead); - data->setPart(ESM::PRT_Hair, npc.mHair); + data->setPart(ESM::PRT_Head, npc.mHead, 0); + data->setPart(ESM::PRT_Hair, npc.mHair, 0); } void ActorAdapter::addNpcItem(const std::string& itemId, ActorDataPtr data) @@ -537,8 +546,8 @@ namespace CSMWorld } // Convenience function to add a parts list to actor data - auto addParts = [&](const ESM::PartReferenceList& list) { - for (auto& part : list.mParts) + auto addParts = [&](const std::vector& list, int priority) { + for (auto& part : list) { std::string partId; auto partType = (ESM::PartReferenceType) part.mPart; @@ -548,7 +557,7 @@ namespace CSMWorld if (partId.empty()) partId = part.mMale; - if (!partId.empty()) data->setPart(partType, partId); + data->setPart(partType, partId, priority); } }; @@ -557,15 +566,63 @@ namespace CSMWorld if (type == UniversalId::Type_Armor) { auto& armor = dynamic_cast&>(record).get(); - addParts(armor.mParts); + addParts(armor.mParts.mParts, 1); // Changing parts could affect what is picked for rendering data->addOtherDependency(itemId); } else if (type == UniversalId::Type_Clothing) { + int priority = 0; + // TODO: reserve bodyparts for robes and skirts auto& clothing = dynamic_cast&>(record).get(); - addParts(clothing.mParts); + + if (clothing.mData.mType == ESM::Clothing::Robe) + { + auto reservedList = std::vector(); + + ESM::PartReference pr; + pr.mMale = ""; + pr.mFemale = ""; + + ESM::PartReferenceType parts[] = { + ESM::PRT_Groin, ESM::PRT_Skirt, ESM::PRT_RLeg, ESM::PRT_LLeg, + ESM::PRT_RUpperarm, ESM::PRT_LUpperarm, ESM::PRT_RKnee, ESM::PRT_LKnee, + ESM::PRT_RForearm, ESM::PRT_LForearm + }; + size_t parts_size = sizeof(parts)/sizeof(parts[0]); + for(size_t p = 0;p < parts_size;++p) + { + pr.mPart = parts[p]; + reservedList.push_back(pr); + } + + priority = parts_size; + addParts(reservedList, priority); + } + else if (clothing.mData.mType == ESM::Clothing::Skirt) + { + auto reservedList = std::vector(); + + ESM::PartReference pr; + pr.mMale = ""; + pr.mFemale = ""; + + ESM::PartReferenceType parts[] = { + ESM::PRT_Groin, ESM::PRT_RLeg, ESM::PRT_LLeg + }; + size_t parts_size = sizeof(parts)/sizeof(parts[0]); + for(size_t p = 0;p < parts_size;++p) + { + pr.mPart = parts[p]; + reservedList.push_back(pr); + } + + priority = parts_size; + addParts(reservedList, priority); + } + + addParts(clothing.mParts.mParts, priority); // Changing parts could affect what is picked for rendering data->addOtherDependency(itemId); diff --git a/apps/opencs/model/world/actoradapter.hpp b/apps/opencs/model/world/actoradapter.hpp index d842bca35..b97c652a8 100644 --- a/apps/opencs/model/world/actoradapter.hpp +++ b/apps/opencs/model/world/actoradapter.hpp @@ -2,6 +2,7 @@ #define CSM_WOLRD_ACTORADAPTER_H #include +#include #include #include @@ -31,7 +32,7 @@ namespace CSMWorld public: /// A list indexed by ESM::PartReferenceType - using ActorPartList = std::array; + using ActorPartList = std::map>; /// A list indexed by ESM::BodyPart::MeshPart using RacePartList = std::array; /// Tracks unique strings @@ -93,7 +94,7 @@ namespace CSMWorld bool hasDependency(const std::string& id) const; /// Sets the actor part used and marks a dependency - void setPart(ESM::PartReferenceType partIndex, const std::string& partId); + void setPart(ESM::PartReferenceType partIndex, const std::string& partId, int priority); /// Marks an additional dependency for the actor void addOtherDependency(const std::string& id); /// Clears race, parts, and dependencies From 2e98cad895f48c30c03382a98f09b1d88af19ba7 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Thu, 27 Sep 2018 17:34:46 +0300 Subject: [PATCH 178/196] Fade out sun glare and specularity completely at night start, not sunset start --- apps/openmw/mwworld/weather.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index ac885f429..7d3f41894 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -751,14 +751,14 @@ void WeatherManager::update(float duration, bool paused, const TimeStamp& time, float underwaterFog = mUnderwaterFog.getValue(time.getHour(), mTimeSettings, "Fog"); - float peakHour = mSunriseTime + (mSunsetTime - mSunriseTime) / 2; + float peakHour = mSunriseTime + (mTimeSettings.mNightStart - mSunriseTime) / 2; float glareFade = 1.f; - if (time.getHour() < mSunriseTime || time.getHour() > mSunsetTime) + if (time.getHour() < mSunriseTime || time.getHour() > mTimeSettings.mNightStart) glareFade = 0.f; else if (time.getHour() < peakHour) - glareFade -= (peakHour - time.getHour()) / (peakHour - mSunriseTime); + glareFade = 1.f - (peakHour - time.getHour()) / (peakHour - mSunriseTime); else - glareFade -= (time.getHour() - peakHour) / (mSunsetTime - peakHour); + glareFade = 1.f - (time.getHour() - peakHour) / (mTimeSettings.mNightStart - peakHour); mRendering.getSkyManager()->setGlareTimeOfDayFade(glareFade); From 43c7438e8e9907cfc0e895f11a7176cd03837d61 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Fri, 28 Sep 2018 16:47:47 +0400 Subject: [PATCH 179/196] Move WeakCache to components/misc --- apps/opencs/model/world/actoradapter.hpp | 6 +++--- components/CMakeLists.txt | 6 +----- components/{cache => misc}/weakcache.hpp | 2 +- 3 files changed, 5 insertions(+), 9 deletions(-) rename components/{cache => misc}/weakcache.hpp (99%) diff --git a/apps/opencs/model/world/actoradapter.hpp b/apps/opencs/model/world/actoradapter.hpp index b97c652a8..1c9265be4 100644 --- a/apps/opencs/model/world/actoradapter.hpp +++ b/apps/opencs/model/world/actoradapter.hpp @@ -8,9 +8,9 @@ #include #include -#include #include #include +#include #include "refidcollection.hpp" #include "idcollection.hpp" @@ -163,8 +163,8 @@ namespace CSMWorld IdCollection& mRaces; IdCollection& mBodyParts; - cache::WeakCache mCachedActors; // Key: referenceable id - cache::WeakCache mCachedRaces; // Key: race id + Misc::WeakCache mCachedActors; // Key: referenceable id + Misc::WeakCache mCachedRaces; // Key: race id StringSet mDirtyActors; // Actors that need updating StringSet mDirtyRaces; // Races that need updating diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 494e1c5ce..5c245afd0 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -86,7 +86,7 @@ add_component_dir (esmterrain ) add_component_dir (misc - constants utf8stream stringops resourcehelpers rng messageformatparser + constants utf8stream stringops resourcehelpers rng messageformatparser weakcache ) add_component_dir (debug @@ -150,10 +150,6 @@ add_component_dir (fallback fallback validate ) -add_component_dir(cache - weakcache - ) - if(NOT WIN32 AND NOT ANDROID) add_component_dir (crashcatcher crashcatcher diff --git a/components/cache/weakcache.hpp b/components/misc/weakcache.hpp similarity index 99% rename from components/cache/weakcache.hpp rename to components/misc/weakcache.hpp index 976818cc2..022a722db 100644 --- a/components/cache/weakcache.hpp +++ b/components/misc/weakcache.hpp @@ -5,7 +5,7 @@ #include #include -namespace cache +namespace Misc { /// \class WeakCache /// Provides a container to weakly store pointers to shared data. From 2073218fc68e6a3799576aecdf624d76a4a1a284 Mon Sep 17 00:00:00 2001 From: elsid Date: Fri, 28 Sep 2018 22:28:54 +0300 Subject: [PATCH 180/196] Use specific googletest version --- CI/build_googletest.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CI/build_googletest.sh b/CI/build_googletest.sh index cd61379b5..ee89ebda6 100755 --- a/CI/build_googletest.sh +++ b/CI/build_googletest.sh @@ -1,6 +1,6 @@ #!/bin/sh -e -git clone https://github.com/google/googletest.git +git clone -b release-1.8.1 https://github.com/google/googletest.git cd googletest mkdir build cd build From f20f49daa6fb0f2c5ccc2f7ae5ad141e914ba332 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Sat, 29 Sep 2018 01:54:00 +0300 Subject: [PATCH 181/196] Content selector: allow to copy paths to clipboard (feature #2847) --- CHANGELOG.md | 1 + .../contentselector/model/contentmodel.hpp | 4 ++-- .../contentselector/view/contentselector.cpp | 19 +++++++++++++++++++ .../contentselector/view/contentselector.hpp | 1 + files/ui/datafilespage.ui | 2 +- 5 files changed, 24 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 04547e249..7539dcf17 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -135,6 +135,7 @@ Feature #1617: Editor: Enchantment effect record verifier Feature #1645: Casting effects from objects Feature #2606: Editor: Implemented (optional) case sensitive global search + Feature #2847: Content selector: allow to copy the path to a file by using the context menu Feature #3083: Play animation when NPC is casting spell via script Feature #3103: Provide option for disposition to get increased by successful trade Feature #3276: Editor: Search - Show number of (remaining) search results and indicate a search without any results diff --git a/components/contentselector/model/contentmodel.hpp b/components/contentselector/model/contentmodel.hpp index bc785a276..80cd6e4c3 100644 --- a/components/contentselector/model/contentmodel.hpp +++ b/components/contentselector/model/contentmodel.hpp @@ -48,6 +48,8 @@ namespace ContentSelectorModel QModelIndex indexFromItem(const EsmFile *item) const; const EsmFile *item(const QString &name) const; + const EsmFile *item(int row) const; + EsmFile *item(int row); QStringList gameFiles() const; bool isEnabled (QModelIndex index) const; @@ -65,8 +67,6 @@ namespace ContentSelectorModel private: void addFile(EsmFile *file); - const EsmFile *item(int row) const; - EsmFile *item(int row); void sortFiles(); diff --git a/components/contentselector/view/contentselector.cpp b/components/contentselector/view/contentselector.cpp index 595be9f44..e26f9a942 100644 --- a/components/contentselector/view/contentselector.cpp +++ b/components/contentselector/view/contentselector.cpp @@ -7,6 +7,7 @@ #include #include +#include #include #include #include @@ -67,6 +68,7 @@ void ContentSelectorView::ContentSelector::buildContextMenu() mContextMenu = new QMenu(ui.addonView); mContextMenu->addAction(tr("&Check Selected"), this, SLOT(slotCheckMultiSelectedItems())); mContextMenu->addAction(tr("&Uncheck Selected"), this, SLOT(slotUncheckMultiSelectedItems())); + mContextMenu->addAction(tr("&Copy Path(s) to Clipboard"), this, SLOT(slotCopySelectedItemsPaths())); } void ContentSelectorView::ContentSelector::setProfileContent(const QStringList &fileList) @@ -245,3 +247,20 @@ void ContentSelectorView::ContentSelector::slotCheckMultiSelectedItems() { setCheckStateForMultiSelectedItems(true); } + +void ContentSelectorView::ContentSelector::slotCopySelectedItemsPaths() +{ + QClipboard *clipboard = QApplication::clipboard(); + QString filepaths; + foreach (const QModelIndex& index, ui.addonView->selectionModel()->selectedIndexes()) + { + int row = mAddonProxyModel->mapToSource(index).row(); + const ContentSelectorModel::EsmFile *file = mContentModel->item(row); + filepaths += file->filePath() + "\n"; + } + + if (!filepaths.isEmpty()) + { + clipboard->setText(filepaths); + } +} diff --git a/components/contentselector/view/contentselector.hpp b/components/contentselector/view/contentselector.hpp index 9f9ad886c..bc47224e4 100644 --- a/components/contentselector/view/contentselector.hpp +++ b/components/contentselector/view/contentselector.hpp @@ -70,6 +70,7 @@ namespace ContentSelectorView void slotShowContextMenu(const QPoint& pos); void slotCheckMultiSelectedItems(); void slotUncheckMultiSelectedItems(); + void slotCopySelectedItemsPaths(); }; } diff --git a/files/ui/datafilespage.ui b/files/ui/datafilespage.ui index 5a6b7265a..5c26e1044 100644 --- a/files/ui/datafilespage.ui +++ b/files/ui/datafilespage.ui @@ -62,7 +62,7 @@ - Select a profiile + Select a content list From 87394f2ebbfdfa932b4a651fc0b39eb9ca2f2875 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sat, 29 Sep 2018 16:21:40 +0400 Subject: [PATCH 182/196] Revert "Take in account transformations of NiTriShape and NiSkinData in skinning (bug #4437)" This reverts commit 09427d3f5ec05aaa00f31da272f725f1cdba6976 since the fix is not entirely correct. --- CHANGELOG.md | 1 - components/nifosg/nifloader.cpp | 6 +----- components/sceneutil/riggeometry.cpp | 9 --------- components/sceneutil/riggeometry.hpp | 2 -- 4 files changed, 1 insertion(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bf1e9e5e0..d83d38fd7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -70,7 +70,6 @@ Bug #4431: "Lock 0" console command is a no-op Bug #4432: Guards behaviour is incorrect if they do not have AI packages Bug #4433: Guard behaviour is incorrect with Alarm = 0 - Bug #4437: Transformations for NiSkinInstance are ignored Bug #4451: Script fails to compile when using "Begin, [ScriptName]" syntax Bug #4452: Default terrain texture bleeds through texture transitions Bug #4453: Quick keys behaviour is invalid for equipment diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 81898e477..3198e995c 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -1082,10 +1082,7 @@ namespace NifOsg // Assign bone weights osg::ref_ptr map (new SceneUtil::RigGeometry::InfluenceMap); - // We should take in account transformation of NiTriShape and NiSkinData const Nif::NiSkinData *data = skin->data.getPtr(); - osg::Matrixf shapeTransforms = triShape->trafo.toMatrix() * data->trafo.toMatrix(); - const Nif::NodeList &bones = skin->bones; for(size_t i = 0;i < bones.length();i++) { @@ -1099,12 +1096,11 @@ namespace NifOsg influence.mWeights.insert(indexWeight); } influence.mInvBindMatrix = data->bones[i].trafo.toMatrix(); - influence.mBoundSphere = osg::BoundingSpheref(shapeTransforms * data->bones[i].boundSphereCenter, data->bones[i].boundSphereRadius); + influence.mBoundSphere = osg::BoundingSpheref(data->bones[i].boundSphereCenter, data->bones[i].boundSphereRadius); map->mMap.insert(std::make_pair(boneName, influence)); } rig->setInfluenceMap(map); - rig->setRigTransforms(*&shapeTransforms); parentNode->addChild(rig); } diff --git a/components/sceneutil/riggeometry.cpp b/components/sceneutil/riggeometry.cpp index 94e4a3b3e..c409bcd5c 100644 --- a/components/sceneutil/riggeometry.cpp +++ b/components/sceneutil/riggeometry.cpp @@ -49,7 +49,6 @@ RigGeometry::RigGeometry(const RigGeometry ©, const osg::CopyOp ©op) : Drawable(copy, copyop) , mSkeleton(NULL) , mInfluenceMap(copy.mInfluenceMap) - , mRigTransforms(copy.mRigTransforms) , mLastFrameNumber(0) , mBoundsFirstFrame(true) { @@ -215,9 +214,6 @@ void RigGeometry::cull(osg::NodeVisitor* nv) if (mGeomToSkelMatrix) resultMat *= (*mGeomToSkelMatrix); - if (!mRigTransforms.isIdentity()) - resultMat *= mRigTransforms; - for (auto &vertex : pair.second) { (*positionDst)[vertex] = resultMat.preMult((*positionSrc)[vertex]); @@ -313,11 +309,6 @@ void RigGeometry::setInfluenceMap(osg::ref_ptr influenceMap) mInfluenceMap = influenceMap; } -void RigGeometry::setRigTransforms(osg::Matrixf& transform) -{ - mRigTransforms = transform; -} - void RigGeometry::accept(osg::NodeVisitor &nv) { if (!nv.validNodeMask(*this)) diff --git a/components/sceneutil/riggeometry.hpp b/components/sceneutil/riggeometry.hpp index 723455234..60b3edc9d 100644 --- a/components/sceneutil/riggeometry.hpp +++ b/components/sceneutil/riggeometry.hpp @@ -40,7 +40,6 @@ namespace SceneUtil }; void setInfluenceMap(osg::ref_ptr influenceMap); - void setRigTransforms(osg::Matrixf& transform); /// Initialize this geometry from the source geometry. /// @note The source geometry will not be modified. @@ -66,7 +65,6 @@ namespace SceneUtil osg::ref_ptr mGeomToSkelMatrix; osg::ref_ptr mInfluenceMap; - osg::Matrixf mRigTransforms; typedef std::pair BoneBindMatrixPair; From 674e33170bcd8a5f725d727d37ad48729a6da8a8 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Sun, 30 Sep 2018 21:16:02 +0300 Subject: [PATCH 183/196] Fix quick key system regressions (bug #4662) --- apps/openmw/mwgui/quickkeysmenu.cpp | 35 +++++++++++++---------------- 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/apps/openmw/mwgui/quickkeysmenu.cpp b/apps/openmw/mwgui/quickkeysmenu.cpp index 8041c50c5..23ad87fd6 100644 --- a/apps/openmw/mwgui/quickkeysmenu.cpp +++ b/apps/openmw/mwgui/quickkeysmenu.cpp @@ -254,6 +254,8 @@ namespace MWGui MyGUI::Gui::getInstance().destroyWidget(mSelected->button->getChildAt(0)); mSelected->type = Type_MagicItem; + mSelected->id = item.getCellRef().getRefId(); + mSelected->name = item.getClass().getName(item); mSelected->button->setFrame("textures\\menu_icon_select_magic_magic.dds", MyGUI::IntCoord(2, 2, 40, 40)); mSelected->button->setIcon(item); @@ -271,20 +273,19 @@ namespace MWGui while (mSelected->button->getChildCount()) // Destroy number label MyGUI::Gui::getInstance().destroyWidget(mSelected->button->getChildAt(0)); + const MWWorld::ESMStore &esmStore = MWBase::Environment::get().getWorld()->getStore(); + const ESM::Spell* spell = esmStore.get().find(spellId); + mSelected->type = Type_Magic; mSelected->id = spellId; + mSelected->name = spell->mName; mSelected->button->setItem(MWWorld::Ptr()); mSelected->button->setUserString("ToolTipType", "Spell"); mSelected->button->setUserString("Spell", spellId); - const MWWorld::ESMStore &esmStore = MWBase::Environment::get().getWorld()->getStore(); - // use the icon of the first effect - const ESM::Spell* spell = esmStore.get().find(spellId); - - const ESM::MagicEffect* effect = - esmStore.get().find(spell->mEffects.mList.front().mEffectID); + const ESM::MagicEffect* effect = esmStore.get().find(spell->mEffects.mList.front().mEffectID); std::string path = effect->mIcon; int slashPos = path.rfind('\\'); @@ -423,9 +424,7 @@ namespace MWGui if (!spells.hasSpell(spellId)) { - const ESM::Spell* spell = - MWBase::Environment::get().getWorld()->getStore().get().find(spellId); - MWBase::Environment::get().getWindowManager()->messageBox("#{sQuickMenu5} " + spell->mName); + MWBase::Environment::get().getWindowManager()->messageBox("#{sQuickMenu5} " + key->name); return; } @@ -547,28 +546,26 @@ namespace MWGui return; mSelected = &mKey[i]; - mSelected->type = (QuickKeysMenu::QuickKeyType) it->mType; - mSelected->id = it->mId; - switch (mSelected->type) + switch (it->mType) { case Type_Magic: - if (MWBase::Environment::get().getWorld()->getStore().get().search(mSelected->id)) - onAssignMagic(mSelected->id); + if (MWBase::Environment::get().getWorld()->getStore().get().search(it->mId)) + onAssignMagic(it->mId); break; case Type_Item: case Type_MagicItem: { // Find the item by id - MWWorld::Ptr item = store.findReplacement(mSelected->id); + MWWorld::Ptr item = store.findReplacement(it->mId); if (item.isEmpty()) - unassign(&mKey[i]); + unassign(mSelected); else { - if (mSelected->type == Type_Item) + if (it->mType == Type_Item) onAssignItem(item); - else if (mSelected->type == Type_MagicItem) + else // if (it->mType == Type_MagicItem) onAssignMagicItem(item); } @@ -576,7 +573,7 @@ namespace MWGui } case Type_Unassigned: case Type_HandToHand: - unassign(&mKey[i]); + unassign(mSelected); break; } From 4dc424036f218dda617b98d4ff4218e072da31a9 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Fri, 28 Sep 2018 13:57:13 +0400 Subject: [PATCH 184/196] Cleanup magic effects, when create a new ActorAnimation --- apps/openmw/mwrender/actoranimation.cpp | 3 ++ apps/openmw/mwrender/animation.cpp | 69 ++++++++++++++++++++++--- apps/openmw/mwrender/animation.hpp | 1 + 3 files changed, 67 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwrender/actoranimation.cpp b/apps/openmw/mwrender/actoranimation.cpp index d92b95a71..e6aff8d19 100644 --- a/apps/openmw/mwrender/actoranimation.cpp +++ b/apps/openmw/mwrender/actoranimation.cpp @@ -40,6 +40,9 @@ ActorAnimation::ActorAnimation(const MWWorld::Ptr& ptr, osg::ref_ptr addHiddenItemLight(*iter, light); } } + + // Make sure we cleaned object from effects, just in cast if we re-use node + removeEffects(); } ActorAnimation::~ActorAnimation() diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 7410dbf03..e7c3f2200 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -213,14 +213,12 @@ namespace RemoveFinishedCallbackVisitor() : RemoveVisitor() , mHasMagicEffects(false) - , mEffectId(-1) { } RemoveFinishedCallbackVisitor(int effectId) : RemoveVisitor() , mHasMagicEffects(false) - , mEffectId(effectId) { } @@ -240,9 +238,63 @@ namespace MWRender::UpdateVfxCallback* vfxCallback = dynamic_cast(callback); if (vfxCallback) { - bool finished = vfxCallback->mFinished; - bool toRemove = mEffectId >= 0 && vfxCallback->mParams.mEffectId == mEffectId; - if (finished || toRemove) + if (vfxCallback->mFinished) + mToRemove.push_back(std::make_pair(group.asNode(), group.getParent(0))); + else + mHasMagicEffects = true; + } + } + } + + virtual void apply(osg::MatrixTransform &node) + { + traverse(node); + } + + virtual void apply(osg::Geometry&) + { + } + + private: + int mEffectId; + }; + + class RemoveCallbackVisitor : public RemoveVisitor + { + public: + bool mHasMagicEffects; + + RemoveCallbackVisitor() + : RemoveVisitor() + , mHasMagicEffects(false) + , mEffectId(-1) + { + } + + RemoveCallbackVisitor(int effectId) + : RemoveVisitor() + , mHasMagicEffects(false) + , mEffectId(effectId) + { + } + + virtual void apply(osg::Node &node) + { + traverse(node); + } + + virtual void apply(osg::Group &group) + { + traverse(group); + + osg::Callback* callback = group.getUpdateCallback(); + if (callback) + { + MWRender::UpdateVfxCallback* vfxCallback = dynamic_cast(callback); + if (vfxCallback) + { + bool toRemove = mEffectId < 0 || vfxCallback->mParams.mEffectId == mEffectId; + if (toRemove) mToRemove.push_back(std::make_pair(group.asNode(), group.getParent(0))); else mHasMagicEffects = true; @@ -1649,12 +1701,17 @@ namespace MWRender void Animation::removeEffect(int effectId) { - RemoveFinishedCallbackVisitor visitor(effectId); + RemoveCallbackVisitor visitor(effectId); mInsert->accept(visitor); visitor.remove(); mHasMagicEffects = visitor.mHasMagicEffects; } + void Animation::removeEffects() + { + removeEffect(-1); + } + void Animation::getLoopingEffects(std::vector &out) const { if (!mHasMagicEffects) diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index e10d2c995..5828bd52f 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -370,6 +370,7 @@ public: */ void addEffect (const std::string& model, int effectId, bool loop = false, const std::string& bonename = "", const std::string& texture = "", float scale = 1.0f); void removeEffect (int effectId); + void removeEffects (); void getLoopingEffects (std::vector& out) const; // Add a spell casting glow to an object. From measuring video taken from the original engine, From 632045e145c4162a5cc095a77db3ee498791b14b Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sun, 30 Sep 2018 10:35:01 +0400 Subject: [PATCH 185/196] Improve the 'part has no parents' warning --- apps/openmw/mwrender/animation.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index e7c3f2200..85d4aae9d 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -1975,12 +1975,12 @@ namespace MWRender PartHolder::~PartHolder() { if (mNode.get() && !mNode->getNumParents()) - Log(Debug::Verbose) << "Part has no parents" ; + Log(Debug::Verbose) << "Part \"" << mNode->getName() << "\" has no parents" ; if (mNode.get() && mNode->getNumParents()) { if (mNode->getNumParents() > 1) - Log(Debug::Verbose) << "Part has multiple (" << mNode->getNumParents() << ") parents"; + Log(Debug::Verbose) << "Part \"" << mNode->getName() << "\" has multiple (" << mNode->getNumParents() << ") parents"; mNode->getParent(0)->removeChild(mNode); } } From 3896a2eba6da63a227094b1cc38fd3a3e22c4c26 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sun, 30 Sep 2018 11:12:28 +0400 Subject: [PATCH 186/196] Do not use a PartHolder for spell effect node --- apps/openmw/mwrender/animation.cpp | 5 ++--- apps/openmw/mwrender/animation.hpp | 1 - 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 85d4aae9d..840e59290 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -624,8 +624,8 @@ namespace MWRender } else { - // Remove effect immediately - mParams.mObjects.reset(); + // Hide effect immediately + node->setNodeMask(0); mFinished = true; } } @@ -1686,7 +1686,6 @@ namespace MWRender params.mLoop = loop; params.mEffectId = effectId; params.mBoneName = bonename; - params.mObjects = PartHolderPtr(new PartHolder(node)); params.mAnimTime = std::shared_ptr(new EffectAnimationTime); trans->addUpdateCallback(new UpdateVfxCallback(params)); diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 5828bd52f..2d8ac152f 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -74,7 +74,6 @@ typedef std::shared_ptr PartHolderPtr; struct EffectParams { std::string mModelName; // Just here so we don't add the same effect twice - PartHolderPtr mObjects; std::shared_ptr mAnimTime; float mMaxControllerLength; int mEffectId; From 07ccc5abdb3f18d946a57d34ddd9161ef297bee2 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Mon, 1 Oct 2018 21:57:13 +0400 Subject: [PATCH 187/196] Remove non-looping effects after rest --- apps/openmw/mwmechanics/actors.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 92f2ba34d..4f051f40a 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -1683,7 +1683,10 @@ namespace MWMechanics MWRender::Animation* animation = MWBase::Environment::get().getWorld()->getAnimation(iter->first); if (animation) - animation->updateEffects(); + { + animation->removeEffects(); + MWBase::Environment::get().getWorld()->applyLoopingParticles(iter->first); + } } From 34e45efac3968850e1db2e3c88fcb0bffe78fcd3 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Fri, 5 Oct 2018 16:29:57 +0300 Subject: [PATCH 188/196] Fix first person swimming animations --- apps/openmw/mwmechanics/character.cpp | 35 ++++++++++++++++++--------- 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 90f90e9e2..c4975b308 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -432,26 +432,37 @@ void CharacterController::refreshMovementAnims(const WeaponInfo* weap, Character if(movestate != sMovementListEnd) { movementAnimName = movestate->groupname; - if(weap != sWeaponTypeListEnd && movementAnimName.find("swim") == std::string::npos) + if(weap != sWeaponTypeListEnd) { - if (mWeaponType == WeapType_Spell && (movement == CharState_TurnLeft || movement == CharState_TurnRight)) // Spellcasting stance turning is a special case - movementAnimName = weap->shortgroup + movementAnimName; - else - movementAnimName += weap->shortgroup; + std::string::size_type swimpos = movementAnimName.find("swim"); + if (swimpos == std::string::npos) + { + if (mWeaponType == WeapType_Spell && (movement == CharState_TurnLeft || movement == CharState_TurnRight)) // Spellcasting stance turning is a special case + movementAnimName = weap->shortgroup + movementAnimName; + else + movementAnimName += weap->shortgroup; + } if(!mAnimation->hasAnimation(movementAnimName)) { movemask = MWRender::Animation::BlendMask_LowerBody; movementAnimName = movestate->groupname; - // Since we apply movement only for lower body, do not reset idle animations. - // For upper body there will be idle animation. - if (idle == CharState_None) - idle = CharState_Idle; + if (swimpos == std::string::npos) + { + // Since we apply movement only for lower body, do not reset idle animations. + // For upper body there will be idle animation. + if (idle == CharState_None) + idle = CharState_Idle; - // For crossbow animations use 1h ones as fallback - if (mWeaponType == WeapType_Crossbow) - movementAnimName += "1h"; + // For crossbow animations use 1h ones as fallback + if (mWeaponType == WeapType_Crossbow) + movementAnimName += "1h"; + } + else if (idle == CharState_None) + { + idle = CharState_IdleSwim; + } } } } From 03788edd6399dc86ff5eee50f990c49ef1333260 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Fri, 5 Oct 2018 18:48:17 +0300 Subject: [PATCH 189/196] Fix redundant drag call in instance dragging (bug #4593) --- CHANGELOG.md | 1 + apps/opencs/view/render/worldspacewidget.cpp | 5 ----- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bf1e9e5e0..2214a4f20 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -115,6 +115,7 @@ Bug #4575: Weird result of attack animation blending with movement animations Bug #4576: Reset of idle animations when attack can not be started Bug #4591: Attack strength should be 0 if player did not hold the attack button + Bug #4593: Editor: Instance dragging is broken Bug #4597: <> operator causes a compile error Bug #4604: Picking up gold from the ground only makes 1 grabbed Bug #4607: Scaling for animated collision shapes is applied twice diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index 5b825fab1..7e405266e 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -648,11 +648,6 @@ void CSVRender::WorldspaceWidget::mouseMoveEvent (QMouseEvent *event) mDragX = event->posF().x(); mDragY = height() - event->posF().y(); #endif - - if (mDragMode == InteractionType_PrimaryEdit) - { - editMode.drag (event->pos(), mDragX, mDragY, mDragFactor); // note: terraintexturemode only uses pos - } } } else From 768c532b8f41bf9e98d5136edc11550bc58616ad Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Sun, 7 Oct 2018 19:41:59 +0300 Subject: [PATCH 190/196] Editor: display light source color as a color (bug #4668) --- CHANGELOG.md | 1 + apps/opencs/model/world/refidcollection.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e8c835a58..226f09374 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -133,6 +133,7 @@ Bug #4649: Levelup fully restores health Bug #4653: Length of non-ASCII strings is handled incorrectly in ESM reader Bug #4654: Editor: UpdateVisitor does not initialize skeletons for animated objects + Bug #4668: Editor: Light source color is displayed as an integer Feature #912: Editor: Add missing icons to UniversalId tables Feature #1221: Editor: Creature/NPC rendering Feature #1617: Editor: Enchantment effect record verifier diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index 6716c7240..272722f64 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -437,7 +437,7 @@ CSMWorld::RefIdCollection::RefIdCollection() mColumns.push_back (RefIdColumn (Columns::ColumnId_Radius, ColumnBase::Display_Integer)); lightColumns.mRadius = &mColumns.back(); - mColumns.push_back (RefIdColumn (Columns::ColumnId_Colour, ColumnBase::Display_Integer)); + mColumns.push_back (RefIdColumn (Columns::ColumnId_Colour, ColumnBase::Display_Colour)); lightColumns.mColor = &mColumns.back(); mColumns.push_back (RefIdColumn (Columns::ColumnId_Sound, ColumnBase::Display_Sound)); From e627f49df438b1cc7792f6d7fe080d991e5e0a57 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Sun, 7 Oct 2018 20:22:52 +0300 Subject: [PATCH 191/196] Fix AppVeyor build --- CI/before_script.msvc.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CI/before_script.msvc.sh b/CI/before_script.msvc.sh index 2c4fe6312..8ee4b7fd9 100644 --- a/CI/before_script.msvc.sh +++ b/CI/before_script.msvc.sh @@ -346,7 +346,7 @@ if [ -z $SKIP_DOWNLOAD ]; then # OpenAL download "OpenAL-Soft 1.17.2" \ - "http://kcat.strangesoft.net/openal-binaries/openal-soft-1.17.2-bin.zip" \ + "http://openal-soft.org/openal-binaries/openal-soft-1.17.2-bin.zip" \ "OpenAL-Soft-1.17.2.zip" # OSG From cae2e84ab45b70e5690666de9649fe3e08b5f888 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Mon, 8 Oct 2018 15:50:54 +0300 Subject: [PATCH 192/196] Trace the player down after enabling collision with TCL (bug #4669) --- CHANGELOG.md | 2 ++ apps/openmw/mwworld/worldimp.cpp | 10 ++++++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 226f09374..448009926 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ Bug #3049: Drain and Fortify effects are not properly applied on health, magicka and fatigue Bug #3059: Unable to hit with marksman weapons when too close to an enemy Bug #3072: Fatal error on AddItem that has a script containing Equip + Bug #3219: NPC and creature initial position tracing down limit is too small Bug #3249: Fixed revert function not updating views properly Bug #3288: TrueType fonts are handled incorrectly Bug #3374: Touch spells not hitting kwama foragers @@ -134,6 +135,7 @@ Bug #4653: Length of non-ASCII strings is handled incorrectly in ESM reader Bug #4654: Editor: UpdateVisitor does not initialize skeletons for animated objects Bug #4668: Editor: Light source color is displayed as an integer + Bug #4669: ToggleCollision should trace the player down after collision being enabled Feature #912: Editor: Add missing icons to UniversalId tables Feature #1221: Editor: Creature/NPC rendering Feature #1617: Editor: Enchantment effect record verifier diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 3cb6b3a59..78eddf28f 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1343,7 +1343,7 @@ namespace MWWorld if (force || !isFlying(ptr)) { - osg::Vec3f traced = mPhysics->traceDown(ptr, pos, 500); + osg::Vec3f traced = mPhysics->traceDown(ptr, pos, Constants::CellSizeInUnits); if (traced.z() < pos.z()) pos.z() = traced.z(); } @@ -1581,7 +1581,13 @@ namespace MWWorld bool World::toggleCollisionMode() { - return mPhysics->toggleCollisionMode(); + if (mPhysics->toggleCollisionMode()) + { + adjustPosition(getPlayerPtr(), true); + return true; + } + + return false; } bool World::toggleRenderMode (MWRender::RenderMode mode) From 09aecb955c5b526936f9102d792e0b189f9048c3 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Mon, 8 Oct 2018 17:06:30 +0300 Subject: [PATCH 193/196] getSkill usage cleanup (bug #4671) --- CHANGELOG.md | 1 + apps/openmw/mwclass/ingredient.cpp | 5 +---- apps/openmw/mwclass/npc.cpp | 8 ++++---- apps/openmw/mwgui/recharge.cpp | 4 +--- apps/openmw/mwgui/trainingwindow.cpp | 8 +++----- apps/openmw/mwmechanics/alchemy.cpp | 7 ++----- apps/openmw/mwmechanics/enchanting.cpp | 9 ++++----- apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 4 ++-- apps/openmw/mwmechanics/repair.cpp | 4 +--- apps/openmw/mwmechanics/security.cpp | 4 +--- apps/openmw/mwmechanics/spellcasting.cpp | 3 +-- apps/openmw/mwmechanics/spellpriority.cpp | 4 ++-- apps/openmw/mwworld/inventorystore.cpp | 5 ++--- 13 files changed, 25 insertions(+), 41 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 226f09374..8d8f539a7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -134,6 +134,7 @@ Bug #4653: Length of non-ASCII strings is handled incorrectly in ESM reader Bug #4654: Editor: UpdateVisitor does not initialize skeletons for animated objects Bug #4668: Editor: Light source color is displayed as an integer + Bug #4671: knownEffect functions should use modified Alchemy skill Feature #912: Editor: Add missing icons to UniversalId tables Feature #1221: Editor: Creature/NPC rendering Feature #1617: Editor: Enchantment effect record verifier diff --git a/apps/openmw/mwclass/ingredient.cpp b/apps/openmw/mwclass/ingredient.cpp index c133b6a26..70339564c 100644 --- a/apps/openmw/mwclass/ingredient.cpp +++ b/apps/openmw/mwclass/ingredient.cpp @@ -14,8 +14,6 @@ #include "../mwworld/actioneat.hpp" #include "../mwworld/nullaction.hpp" -#include "../mwmechanics/npcstats.hpp" - #include "../mwgui/tooltips.hpp" #include "../mwrender/objects.hpp" @@ -134,8 +132,7 @@ namespace MWClass } MWWorld::Ptr player = MWBase::Environment::get().getWorld ()->getPlayerPtr(); - MWMechanics::NpcStats& npcStats = player.getClass().getNpcStats (player); - int alchemySkill = npcStats.getSkill (ESM::Skill::Alchemy).getBase(); + int alchemySkill = player.getClass().getSkill(player, ESM::Skill::Alchemy); static const float fWortChanceValue = MWBase::Environment::get().getWorld()->getStore().get().find("fWortChanceValue")->mValue.getFloat(); diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 4979db2fd..c0f6eb64f 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -949,7 +949,7 @@ namespace MWClass if(sneaking) walkSpeed *= gmst.fSneakSpeedMultiplier->mValue.getFloat(); - float runSpeed = walkSpeed*(0.01f * npcdata->mNpcStats.getSkill(ESM::Skill::Athletics).getModified() * + float runSpeed = walkSpeed*(0.01f * getSkill(ptr, ESM::Skill::Athletics) * gmst.fAthleticsRunBonus->mValue.getFloat() + gmst.fBaseRunMultiplier->mValue.getFloat()); float moveSpeed; @@ -971,7 +971,7 @@ namespace MWClass if(running) swimSpeed = runSpeed; swimSpeed *= 1.0f + 0.01f * mageffects.get(ESM::MagicEffect::SwiftSwim).getMagnitude(); - swimSpeed *= gmst.fSwimRunBase->mValue.getFloat() + 0.01f*npcdata->mNpcStats.getSkill(ESM::Skill::Athletics).getModified()* + swimSpeed *= gmst.fSwimRunBase->mValue.getFloat() + 0.01f*getSkill(ptr, ESM::Skill::Athletics)* gmst.fSwimRunAthleticsMult->mValue.getFloat(); moveSpeed = swimSpeed; } @@ -1004,7 +1004,7 @@ namespace MWClass gmst.fJumpEncumbranceMultiplier->mValue.getFloat() * (1.0f - Npc::getNormalizedEncumbrance(ptr)); - float a = static_cast(npcdata->mNpcStats.getSkill(ESM::Skill::Acrobatics).getModified()); + float a = static_cast(getSkill(ptr, ESM::Skill::Acrobatics)); float b = 0.0f; if(a > 50.0f) { @@ -1129,7 +1129,7 @@ namespace MWClass float fUnarmoredBase1 = store.find("fUnarmoredBase1")->mValue.getFloat(); float fUnarmoredBase2 = store.find("fUnarmoredBase2")->mValue.getFloat(); - int unarmoredSkill = stats.getSkill(ESM::Skill::Unarmored).getModified(); + int unarmoredSkill = getSkill(ptr, ESM::Skill::Unarmored); float ratings[MWWorld::InventoryStore::Slots]; for(int i = 0;i < MWWorld::InventoryStore::Slots;i++) diff --git a/apps/openmw/mwgui/recharge.cpp b/apps/openmw/mwgui/recharge.cpp index a6ed16bd4..672db3e32 100644 --- a/apps/openmw/mwgui/recharge.cpp +++ b/apps/openmw/mwgui/recharge.cpp @@ -18,7 +18,6 @@ #include "../mwworld/esmstore.hpp" #include "../mwmechanics/creaturestats.hpp" -#include "../mwmechanics/npcstats.hpp" #include "../mwmechanics/actorutil.hpp" #include "itemwidget.hpp" @@ -139,7 +138,6 @@ void Recharge::onItemClicked(MyGUI::Widget *sender, const MWWorld::Ptr& item) MWWorld::Ptr player = MWMechanics::getPlayer(); MWMechanics::CreatureStats& stats = player.getClass().getCreatureStats(player); - MWMechanics::NpcStats& npcStats = player.getClass().getNpcStats(player); float luckTerm = 0.1f * stats.getAttribute(ESM::Attribute::Luck).getModified(); if (luckTerm < 1|| luckTerm > 10) @@ -152,7 +150,7 @@ void Recharge::onItemClicked(MyGUI::Widget *sender, const MWWorld::Ptr& item) if (intelligenceTerm < 1) intelligenceTerm = 1; - float x = (npcStats.getSkill(ESM::Skill::Enchant).getModified() + intelligenceTerm + luckTerm) * stats.getFatigueTerm(); + float x = (player.getClass().getSkill(player, ESM::Skill::Enchant) + intelligenceTerm + luckTerm) * stats.getFatigueTerm(); int roll = Misc::Rng::roll0to99(); if (roll < x) { diff --git a/apps/openmw/mwgui/trainingwindow.cpp b/apps/openmw/mwgui/trainingwindow.cpp index b309da27d..60e6584c7 100644 --- a/apps/openmw/mwgui/trainingwindow.cpp +++ b/apps/openmw/mwgui/trainingwindow.cpp @@ -73,14 +73,12 @@ namespace MWGui mPlayerGold->setCaptionWithReplacing("#{sGold}: " + MyGUI::utility::toString(playerGold)); - MWMechanics::NpcStats& npcStats = actor.getClass().getNpcStats (actor); - // NPC can train you in his best 3 skills std::vector< std::pair > skills; for (int i=0; i player.getClass().getContainerStore(player).count(MWWorld::ContainerStore::sGoldId)) return; - MWMechanics::NpcStats& npcStats = mPtr.getClass().getNpcStats (mPtr); - if (npcStats.getSkill (skillId).getModified () <= pcStats.getSkill (skillId).getBase ()) + if (mPtr.getClass().getSkill(mPtr, skillId) <= pcStats.getSkill (skillId).getBase ()) { MWBase::Environment::get().getWindowManager()->messageBox ("#{sServiceTrainingWords}"); return; @@ -168,6 +165,7 @@ namespace MWGui player.getClass().getContainerStore(player).remove(MWWorld::ContainerStore::sGoldId, price, player); // add gold to NPC trading gold pool + MWMechanics::NpcStats& npcStats = mPtr.getClass().getNpcStats(mPtr); npcStats.setGoldPool(npcStats.getGoldPool() + price); // advance time diff --git a/apps/openmw/mwmechanics/alchemy.cpp b/apps/openmw/mwmechanics/alchemy.cpp index 98860198b..c199bfb3f 100644 --- a/apps/openmw/mwmechanics/alchemy.cpp +++ b/apps/openmw/mwmechanics/alchemy.cpp @@ -26,7 +26,6 @@ #include "magiceffects.hpp" #include "creaturestats.hpp" -#include "npcstats.hpp" MWMechanics::Alchemy::Alchemy() : mValue(0) @@ -318,10 +317,9 @@ void MWMechanics::Alchemy::increaseSkill() float MWMechanics::Alchemy::getAlchemyFactor() const { const CreatureStats& creatureStats = mAlchemist.getClass().getCreatureStats (mAlchemist); - const NpcStats& npcStats = mAlchemist.getClass().getNpcStats (mAlchemist); return - (npcStats.getSkill (ESM::Skill::Alchemy).getModified() + + (mAlchemist.getClass().getSkill(mAlchemist, ESM::Skill::Alchemy) + 0.1f * creatureStats.getAttribute (ESM::Attribute::Intelligence).getModified() + 0.1f * creatureStats.getAttribute (ESM::Attribute::Luck).getModified()); } @@ -472,8 +470,7 @@ MWMechanics::Alchemy::TEffectsIterator MWMechanics::Alchemy::endEffects() const bool MWMechanics::Alchemy::knownEffect(unsigned int potionEffectIndex, const MWWorld::Ptr &npc) { - MWMechanics::NpcStats& npcStats = npc.getClass().getNpcStats(npc); - int alchemySkill = npcStats.getSkill (ESM::Skill::Alchemy).getBase(); + int alchemySkill = npc.getClass().getSkill (npc, ESM::Skill::Alchemy); static const float fWortChanceValue = MWBase::Environment::get().getWorld()->getStore().get().find("fWortChanceValue")->mValue.getFloat(); return (potionEffectIndex <= 1 && alchemySkill >= fWortChanceValue) diff --git a/apps/openmw/mwmechanics/enchanting.cpp b/apps/openmw/mwmechanics/enchanting.cpp index c0bffc4cb..e4bb0cf3f 100644 --- a/apps/openmw/mwmechanics/enchanting.cpp +++ b/apps/openmw/mwmechanics/enchanting.cpp @@ -10,7 +10,6 @@ #include "../mwbase/mechanicsmanager.hpp" #include "creaturestats.hpp" -#include "npcstats.hpp" #include "spellcasting.hpp" #include "actorutil.hpp" @@ -280,11 +279,11 @@ namespace MWMechanics float Enchanting::getEnchantChance() const { - const NpcStats& npcStats = mEnchanter.getClass().getNpcStats (mEnchanter); + const CreatureStats& stats = mEnchanter.getClass().getCreatureStats(mEnchanter); - float chance1 = (npcStats.getSkill (ESM::Skill::Enchant).getModified() + - (0.25f * npcStats.getAttribute (ESM::Attribute::Intelligence).getModified()) - + (0.125f * npcStats.getAttribute (ESM::Attribute::Luck).getModified())); + float chance1 = (mEnchanter.getClass().getSkill(mEnchanter, ESM::Skill::Enchant) + + (0.25f * stats.getAttribute (ESM::Attribute::Intelligence).getModified()) + + (0.125f * stats.getAttribute (ESM::Attribute::Luck).getModified())); const MWWorld::Store& gmst = MWBase::Environment::get().getWorld()->getStore().get(); diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 33357b79a..1ea40023b 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -639,10 +639,10 @@ namespace MWMechanics // I suppose the temporary disposition change (second param to getDerivedDisposition()) _has_ to be considered here, // otherwise one would get different prices when exiting and re-entering the dialogue window... int clampedDisposition = getDerivedDisposition(ptr); - float a = static_cast(std::min(playerStats.getSkill(ESM::Skill::Mercantile).getModified(), 100)); + float a = static_cast(std::min(playerPtr.getClass().getSkill(playerPtr, ESM::Skill::Mercantile), 100)); float b = std::min(0.1f * playerStats.getAttribute(ESM::Attribute::Luck).getModified(), 10.f); float c = std::min(0.2f * playerStats.getAttribute(ESM::Attribute::Personality).getModified(), 10.f); - float d = static_cast(std::min(sellerStats.getSkill(ESM::Skill::Mercantile).getModified(), 100)); + float d = static_cast(std::min(ptr.getClass().getSkill(ptr, ESM::Skill::Mercantile), 100)); float e = std::min(0.1f * sellerStats.getAttribute(ESM::Attribute::Luck).getModified(), 10.f); float f = std::min(0.2f * sellerStats.getAttribute(ESM::Attribute::Personality).getModified(), 10.f); float pcTerm = (clampedDisposition - 50 + a + b + c) * playerStats.getFatigueTerm(); diff --git a/apps/openmw/mwmechanics/repair.cpp b/apps/openmw/mwmechanics/repair.cpp index 3ebef36bf..8c5e69896 100644 --- a/apps/openmw/mwmechanics/repair.cpp +++ b/apps/openmw/mwmechanics/repair.cpp @@ -14,7 +14,6 @@ #include "../mwworld/esmstore.hpp" #include "creaturestats.hpp" -#include "npcstats.hpp" #include "actorutil.hpp" namespace MWMechanics @@ -34,12 +33,11 @@ void Repair::repair(const MWWorld::Ptr &itemToRepair) mTool.getCellRef().setCharge(uses-1); MWMechanics::CreatureStats& stats = player.getClass().getCreatureStats(player); - MWMechanics::NpcStats& npcStats = player.getClass().getNpcStats(player); float fatigueTerm = stats.getFatigueTerm(); int pcStrength = stats.getAttribute(ESM::Attribute::Strength).getModified(); int pcLuck = stats.getAttribute(ESM::Attribute::Luck).getModified(); - int armorerSkill = npcStats.getSkill(ESM::Skill::Armorer).getModified(); + int armorerSkill = player.getClass().getSkill(player, ESM::Skill::Armorer); float fRepairAmountMult = MWBase::Environment::get().getWorld()->getStore().get() .find("fRepairAmountMult")->mValue.getFloat(); diff --git a/apps/openmw/mwmechanics/security.cpp b/apps/openmw/mwmechanics/security.cpp index c8a4dd770..18d4ec2e5 100644 --- a/apps/openmw/mwmechanics/security.cpp +++ b/apps/openmw/mwmechanics/security.cpp @@ -11,7 +11,6 @@ #include "../mwbase/windowmanager.hpp" #include "../mwbase/mechanicsmanager.hpp" -#include "npcstats.hpp" #include "creaturestats.hpp" namespace MWMechanics @@ -21,10 +20,9 @@ namespace MWMechanics : mActor(actor) { CreatureStats& creatureStats = actor.getClass().getCreatureStats(actor); - NpcStats& npcStats = actor.getClass().getNpcStats(actor); mAgility = static_cast(creatureStats.getAttribute(ESM::Attribute::Agility).getModified()); mLuck = static_cast(creatureStats.getAttribute(ESM::Attribute::Luck).getModified()); - mSecuritySkill = static_cast(npcStats.getSkill(ESM::Skill::Security).getModified()); + mSecuritySkill = static_cast(actor.getClass().getSkill(actor, ESM::Skill::Security)); mFatigueTerm = creatureStats.getFatigueTerm(); } diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index f1ee2520b..f6eb497e7 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -964,10 +964,9 @@ namespace MWMechanics MWBase::Environment::get().getWorld()->getStore().get().find ( effect.mEffectID); - const MWMechanics::NpcStats& npcStats = mCaster.getClass().getNpcStats(mCaster); const MWMechanics::CreatureStats& creatureStats = mCaster.getClass().getCreatureStats(mCaster); - float x = (npcStats.getSkill (ESM::Skill::Alchemy).getModified() + + float x = (mCaster.getClass().getSkill(mCaster, ESM::Skill::Alchemy) + 0.2f * creatureStats.getAttribute (ESM::Attribute::Intelligence).getModified() + 0.1f * creatureStats.getAttribute (ESM::Attribute::Luck).getModified()) * creatureStats.getFatigueTerm(); diff --git a/apps/openmw/mwmechanics/spellpriority.cpp b/apps/openmw/mwmechanics/spellpriority.cpp index 807b56608..3b242266c 100644 --- a/apps/openmw/mwmechanics/spellpriority.cpp +++ b/apps/openmw/mwmechanics/spellpriority.cpp @@ -14,7 +14,7 @@ #include "../mwworld/actionequip.hpp" #include "../mwworld/cellstore.hpp" -#include "npcstats.hpp" +#include "creaturestats.hpp" #include "spellcasting.hpp" #include "combat.hpp" @@ -538,7 +538,7 @@ namespace MWMechanics case ESM::MagicEffect::DrainSkill: if (enemy.isEmpty() || !enemy.getClass().isNpc()) return 0.f; - if (enemy.getClass().getNpcStats(enemy).getSkill(effect.mSkill).getModified() <= 0) + if (enemy.getClass().getSkill(enemy, effect.mSkill) <= 0) return 0.f; break; diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index 7f3018c55..59ec6ab3e 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -250,11 +250,10 @@ void MWWorld::InventoryStore::autoEquip (const MWWorld::Ptr& actor) { const MWBase::World *world = MWBase::Environment::get().getWorld(); const MWWorld::Store &store = world->getStore().get(); - MWMechanics::NpcStats& stats = actor.getClass().getNpcStats(actor); static float fUnarmoredBase1 = store.find("fUnarmoredBase1")->mValue.getFloat(); static float fUnarmoredBase2 = store.find("fUnarmoredBase2")->mValue.getFloat(); - int unarmoredSkill = stats.getSkill(ESM::Skill::Unarmored).getModified(); + int unarmoredSkill = actor.getClass().getSkill(actor, ESM::Skill::Unarmored); float unarmoredRating = (fUnarmoredBase1 * unarmoredSkill) * (fUnarmoredBase2 * unarmoredSkill); @@ -384,7 +383,7 @@ void MWWorld::InventoryStore::autoEquip (const MWWorld::Ptr& actor) for (int j = 0; j < static_cast(weaponSkillsLength); ++j) { - int skillValue = stats.getSkill(static_cast(weaponSkills[j])).getModified(); + int skillValue = actor.getClass().getSkill(actor, static_cast(weaponSkills[j])); if (skillValue > max && !weaponSkillVisited[j]) { From e06f0b797a596c2773018ecf3ddf0a7981767ede Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Tue, 9 Oct 2018 10:21:12 +0400 Subject: [PATCH 194/196] Replace all NULLs to nullptr --- apps/opencs/editor.cpp | 4 +- apps/opencs/model/doc/operationholder.cpp | 2 +- apps/opencs/model/world/columnimp.cpp | 2 +- apps/opencs/model/world/commands.cpp | 2 +- .../model/world/idcompletionmanager.cpp | 2 +- apps/opencs/model/world/idtableproxymodel.cpp | 10 +-- .../model/world/infotableproxymodel.cpp | 6 +- apps/opencs/model/world/refidadapterimp.cpp | 34 ++++----- apps/opencs/model/world/resourcesmanager.cpp | 2 +- apps/opencs/view/doc/filedialog.cpp | 4 +- apps/opencs/view/doc/subview.hpp | 2 +- apps/opencs/view/doc/view.cpp | 10 +-- apps/opencs/view/doc/view.hpp | 2 +- apps/opencs/view/render/cameracontroller.cpp | 4 +- apps/opencs/view/render/object.cpp | 2 +- .../view/render/pagedworldspacewidget.cpp | 2 +- apps/opencs/view/render/scenewidget.cpp | 8 +- apps/opencs/view/render/terrainstorage.cpp | 2 +- apps/opencs/view/widget/colorpickerpopup.cpp | 2 +- apps/opencs/view/widget/completerpopup.cpp | 2 +- apps/opencs/view/world/cellcreator.cpp | 2 +- apps/opencs/view/world/dialoguesubview.cpp | 28 +++---- apps/opencs/view/world/dragdroputils.cpp | 2 +- apps/opencs/view/world/dragrecordtable.cpp | 2 +- apps/opencs/view/world/dragrecordtable.hpp | 2 +- .../world/extendedcommandconfigurator.cpp | 2 +- .../view/world/idcompletiondelegate.cpp | 2 +- apps/opencs/view/world/nestedtable.cpp | 6 +- apps/opencs/view/world/nestedtable.hpp | 2 +- apps/opencs/view/world/scenesubview.cpp | 10 +-- apps/opencs/view/world/util.cpp | 4 +- apps/openmw/android_main.c | 4 +- apps/openmw/engine.cpp | 12 +-- apps/openmw/mwclass/container.cpp | 2 +- apps/openmw/mwclass/creature.cpp | 4 +- apps/openmw/mwclass/light.cpp | 2 +- apps/openmw/mwclass/npc.cpp | 4 +- apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 2 +- apps/openmw/mwdialogue/filter.cpp | 2 +- apps/openmw/mwdialogue/journalentry.cpp | 2 +- apps/openmw/mwgui/alchemywindow.cpp | 2 +- apps/openmw/mwgui/backgroundimage.cpp | 2 +- apps/openmw/mwgui/backgroundimage.hpp | 2 +- apps/openmw/mwgui/bookpage.cpp | 68 ++++++++--------- apps/openmw/mwgui/class.cpp | 12 +-- apps/openmw/mwgui/companionwindow.cpp | 12 +-- apps/openmw/mwgui/container.cpp | 16 ++-- apps/openmw/mwgui/countdialog.cpp | 4 +- apps/openmw/mwgui/cursor.cpp | 4 +- apps/openmw/mwgui/draganddrop.cpp | 8 +- apps/openmw/mwgui/enchantingdialog.cpp | 2 +- apps/openmw/mwgui/exposedwindow.cpp | 2 +- apps/openmw/mwgui/formatting.cpp | 2 +- apps/openmw/mwgui/hud.cpp | 30 ++++---- apps/openmw/mwgui/inventorywindow.cpp | 14 ++-- apps/openmw/mwgui/itemchargeview.cpp | 4 +- apps/openmw/mwgui/itemmodel.cpp | 6 +- apps/openmw/mwgui/itemselection.cpp | 4 +- apps/openmw/mwgui/itemview.cpp | 6 +- apps/openmw/mwgui/itemwidget.cpp | 8 +- apps/openmw/mwgui/journalviewmodel.cpp | 2 +- apps/openmw/mwgui/loadingscreen.cpp | 4 +- apps/openmw/mwgui/mainmenu.cpp | 14 ++-- apps/openmw/mwgui/mapwindow.cpp | 18 ++--- apps/openmw/mwgui/messagebox.cpp | 22 +++--- apps/openmw/mwgui/race.cpp | 12 +-- apps/openmw/mwgui/recharge.cpp | 4 +- apps/openmw/mwgui/repair.cpp | 4 +- apps/openmw/mwgui/review.cpp | 2 +- apps/openmw/mwgui/savegamedialog.cpp | 24 +++--- apps/openmw/mwgui/spellcreationdialog.cpp | 12 +-- apps/openmw/mwgui/spellmodel.cpp | 2 +- apps/openmw/mwgui/spellview.cpp | 12 +-- apps/openmw/mwgui/spellwindow.cpp | 4 +- apps/openmw/mwgui/statswindow.cpp | 4 +- apps/openmw/mwgui/tradewindow.cpp | 12 +-- apps/openmw/mwgui/videowidget.cpp | 2 +- apps/openmw/mwgui/waitdialog.cpp | 2 +- apps/openmw/mwgui/widgets.cpp | 22 +++--- apps/openmw/mwgui/windowbase.cpp | 4 +- apps/openmw/mwgui/windowbase.hpp | 2 +- apps/openmw/mwgui/windowmanagerimp.cpp | 74 +++++++++---------- apps/openmw/mwgui/windowpinnablebase.cpp | 2 +- apps/openmw/mwinput/inputmanagerimp.cpp | 8 +- apps/openmw/mwmechanics/actors.cpp | 4 +- apps/openmw/mwmechanics/aicombat.cpp | 2 +- apps/openmw/mwmechanics/aicombat.hpp | 2 +- apps/openmw/mwmechanics/aicombataction.cpp | 2 +- apps/openmw/mwmechanics/aicombataction.hpp | 2 +- apps/openmw/mwmechanics/aipackage.cpp | 2 +- apps/openmw/mwmechanics/aipackage.hpp | 2 +- apps/openmw/mwmechanics/aistate.hpp | 8 +- apps/openmw/mwmechanics/aiwander.hpp | 2 +- apps/openmw/mwmechanics/autocalcspell.cpp | 2 +- apps/openmw/mwmechanics/character.cpp | 14 ++-- apps/openmw/mwmechanics/character.hpp | 4 +- .../mwmechanics/mechanicsmanagerimp.cpp | 2 +- apps/openmw/mwmechanics/objects.cpp | 2 +- apps/openmw/mwmechanics/obstacle.hpp | 2 +- apps/openmw/mwmechanics/pathfinding.cpp | 4 +- apps/openmw/mwmechanics/pathgrid.cpp | 4 +- apps/openmw/mwmechanics/spellcasting.cpp | 6 +- apps/openmw/mwmechanics/spellcasting.hpp | 8 +- apps/openmw/mwphysics/physicssystem.cpp | 16 ++-- apps/openmw/mwphysics/trace.cpp | 2 +- apps/openmw/mwrender/animation.cpp | 32 ++++---- apps/openmw/mwrender/animation.hpp | 4 +- apps/openmw/mwrender/bulletdebugdraw.cpp | 6 +- apps/openmw/mwrender/camera.cpp | 2 +- apps/openmw/mwrender/characterpreview.cpp | 6 +- apps/openmw/mwrender/creatureanimation.cpp | 4 +- apps/openmw/mwrender/globalmap.cpp | 2 +- apps/openmw/mwrender/landmanager.cpp | 4 +- apps/openmw/mwrender/landmanager.hpp | 2 +- apps/openmw/mwrender/npcanimation.cpp | 16 ++-- apps/openmw/mwrender/npcanimation.hpp | 8 +- apps/openmw/mwrender/objects.cpp | 14 ++-- apps/openmw/mwrender/pathgrid.cpp | 10 +-- apps/openmw/mwrender/renderingmanager.cpp | 10 +-- apps/openmw/mwrender/ripplesimulation.cpp | 2 +- apps/openmw/mwrender/sky.cpp | 30 ++++---- apps/openmw/mwrender/water.cpp | 10 +-- apps/openmw/mwrender/weaponanimation.cpp | 4 +- apps/openmw/mwscript/statsextensions.cpp | 2 +- .../mwscript/transformationextensions.cpp | 2 +- apps/openmw/mwsound/ffmpeg_decoder.cpp | 54 +++++++------- apps/openmw/mwsound/movieaudiofactory.cpp | 2 +- apps/openmw/mwsound/openal_output.cpp | 6 +- apps/openmw/mwsound/soundmanagerimp.cpp | 2 +- apps/openmw/mwstate/charactermanager.cpp | 4 +- apps/openmw/mwstate/quicksavemanager.cpp | 4 +- apps/openmw/mwstate/quicksavemanager.hpp | 2 +- apps/openmw/mwstate/statemanagerimp.cpp | 2 +- apps/openmw/mwworld/cellpreloader.cpp | 4 +- apps/openmw/mwworld/cells.cpp | 2 +- apps/openmw/mwworld/cellstore.cpp | 6 +- apps/openmw/mwworld/cellstore.hpp | 4 +- apps/openmw/mwworld/cellvisitors.hpp | 2 +- apps/openmw/mwworld/containerstore.cpp | 4 +- apps/openmw/mwworld/inventorystore.cpp | 2 +- apps/openmw/mwworld/livecellref.hpp | 4 +- apps/openmw/mwworld/player.cpp | 4 +- apps/openmw/mwworld/player.hpp | 2 +- apps/openmw/mwworld/scene.cpp | 6 +- apps/openmw/mwworld/store.cpp | 14 ++-- apps/openmw/mwworld/store.hpp | 2 +- apps/openmw/mwworld/worldimp.cpp | 10 +-- apps/openmw_test_suite/mwworld/test_store.cpp | 4 +- apps/wizard/existinginstallationpage.cpp | 2 +- .../contentselector/view/contentselector.cpp | 2 +- components/crashcatcher/crashcatcher.cpp | 24 +++--- components/debug/debugging.cpp | 2 +- components/esm/esmreader.cpp | 4 +- components/esm/esmwriter.cpp | 4 +- components/esm/loadland.cpp | 6 +- components/esm/loadland.hpp | 4 +- components/esmterrain/storage.cpp | 2 +- components/files/androidpath.cpp | 6 +- components/files/linuxpath.cpp | 6 +- components/files/lowlevelfile.cpp | 26 +++---- components/files/macospath.cpp | 6 +- components/files/windowspath.cpp | 6 +- components/myguiplatform/additivelayer.cpp | 2 +- components/myguiplatform/myguidatamanager.cpp | 2 +- .../myguiplatform/myguirendermanager.cpp | 14 ++-- .../myguiplatform/myguirendermanager.hpp | 2 +- components/myguiplatform/myguitexture.cpp | 2 +- components/nif/niffile.cpp | 6 +- components/nif/node.hpp | 4 +- components/nif/recordptr.hpp | 10 +-- components/nifbullet/bulletnifloader.cpp | 14 ++-- components/nifosg/nifloader.cpp | 28 +++---- components/nifosg/particle.cpp | 4 +- components/resource/bulletshape.cpp | 4 +- components/resource/bulletshapemanager.cpp | 2 +- components/resource/multiobjectcache.hpp | 2 +- components/sceneutil/clone.cpp | 2 +- components/sceneutil/controller.cpp | 2 +- components/sceneutil/lightmanager.cpp | 16 ++-- components/sceneutil/lightmanager.hpp | 2 +- components/sceneutil/lightutil.cpp | 2 +- components/sceneutil/optimizer.cpp | 8 +- components/sceneutil/riggeometry.cpp | 8 +- components/sceneutil/skeleton.cpp | 8 +- components/sceneutil/statesetupdater.cpp | 4 +- components/sceneutil/visitor.cpp | 2 +- components/sceneutil/visitor.hpp | 4 +- components/sceneutil/workqueue.cpp | 2 +- components/sceneutil/workqueue.hpp | 2 +- components/sdlutil/sdlcursormanager.cpp | 2 +- components/sdlutil/sdlgraphicswindow.cpp | 8 +- components/sdlutil/sdlinputwrapper.cpp | 10 +-- components/shader/shadermanager.cpp | 6 +- components/shader/shadermanager.hpp | 2 +- components/shader/shadervisitor.cpp | 22 +++--- components/terrain/chunkmanager.cpp | 2 +- components/terrain/compositemaprenderer.cpp | 2 +- components/terrain/quadtreenode.cpp | 4 +- components/terrain/quadtreeworld.cpp | 10 +-- components/terrain/terraindrawable.hpp | 2 +- components/terrain/terraingrid.cpp | 6 +- components/terrain/viewdata.cpp | 10 +-- components/terrain/world.hpp | 2 +- components/translation/translation.cpp | 2 +- components/widgets/windowcaption.cpp | 6 +- 205 files changed, 717 insertions(+), 721 deletions(-) diff --git a/apps/opencs/editor.cpp b/apps/opencs/editor.cpp index f29c6aca8..450b434e6 100644 --- a/apps/opencs/editor.cpp +++ b/apps/opencs/editor.cpp @@ -22,7 +22,7 @@ CS::Editor::Editor (int argc, char **argv) : mSettingsState (mCfgMgr), mDocumentManager (mCfgMgr), mViewManager (mDocumentManager), mPid(""), mLock(), mMerge (mDocumentManager), - mIpcServerName ("org.openmw.OpenCS"), mServer(NULL), mClientSocket(NULL) + mIpcServerName ("org.openmw.OpenCS"), mServer(nullptr), mClientSocket(nullptr) { std::pair > config = readConfig(); @@ -339,7 +339,7 @@ bool CS::Editor::makeIPCServer() } mServer->close(); - mServer = NULL; + mServer = nullptr; return false; } diff --git a/apps/opencs/model/doc/operationholder.cpp b/apps/opencs/model/doc/operationholder.cpp index ccbed6c8b..0fd2bef95 100644 --- a/apps/opencs/model/doc/operationholder.cpp +++ b/apps/opencs/model/doc/operationholder.cpp @@ -3,7 +3,7 @@ #include "operation.hpp" CSMDoc::OperationHolder::OperationHolder (Operation *operation) - : mOperation(NULL) + : mOperation(nullptr) , mRunning (false) { if (operation) diff --git a/apps/opencs/model/world/columnimp.cpp b/apps/opencs/model/world/columnimp.cpp index 49e4bebe6..b202a97d9 100644 --- a/apps/opencs/model/world/columnimp.cpp +++ b/apps/opencs/model/world/columnimp.cpp @@ -318,7 +318,7 @@ namespace CSMWorld QVariant BodyPartRaceColumn::get(const Record &record) const { - if (mMeshType != NULL && mMeshType->get(record) == ESM::BodyPart::MT_Skin) + if (mMeshType != nullptr && mMeshType->get(record) == ESM::BodyPart::MT_Skin) { return QString::fromUtf8(record.get().mRace.c_str()); } diff --git a/apps/opencs/model/world/commands.cpp b/apps/opencs/model/world/commands.cpp index 4133b2050..4c7096479 100644 --- a/apps/opencs/model/world/commands.cpp +++ b/apps/opencs/model/world/commands.cpp @@ -244,7 +244,7 @@ void CSMWorld::CreateCommand::applyModifications() if (!mNestedValues.empty()) { CSMWorld::IdTree *tree = dynamic_cast(&mModel); - if (tree == NULL) + if (tree == nullptr) { throw std::logic_error("CSMWorld::CreateCommand: Attempt to add nested values to the non-nested model"); } diff --git a/apps/opencs/model/world/idcompletionmanager.cpp b/apps/opencs/model/world/idcompletionmanager.cpp index 9fa6e3add..649a96038 100644 --- a/apps/opencs/model/world/idcompletionmanager.cpp +++ b/apps/opencs/model/world/idcompletionmanager.cpp @@ -92,7 +92,7 @@ void CSMWorld::IdCompletionManager::generateCompleters(CSMWorld::Data &data) { QAbstractItemModel *model = data.getTableModel(current->second); CSMWorld::IdTableBase *table = dynamic_cast(model); - if (table != NULL) + if (table != nullptr) { int idColumn = table->searchColumnIndex(CSMWorld::Columns::ColumnId_Id); if (idColumn != -1) diff --git a/apps/opencs/model/world/idtableproxymodel.cpp b/apps/opencs/model/world/idtableproxymodel.cpp index 6d50e9edb..534e5dd63 100644 --- a/apps/opencs/model/world/idtableproxymodel.cpp +++ b/apps/opencs/model/world/idtableproxymodel.cpp @@ -18,7 +18,7 @@ namespace void CSMWorld::IdTableProxyModel::updateColumnMap() { - Q_ASSERT(mSourceModel != NULL); + Q_ASSERT(mSourceModel != nullptr); mColumnMap.clear(); if (mFilter) @@ -33,7 +33,7 @@ void CSMWorld::IdTableProxyModel::updateColumnMap() bool CSMWorld::IdTableProxyModel::filterAcceptsRow (int sourceRow, const QModelIndex& sourceParent) const { - Q_ASSERT(mSourceModel != NULL); + Q_ASSERT(mSourceModel != nullptr); // It is not possible to use filterAcceptsColumn() and check for // sourceModel()->headerData (sourceColumn, Qt::Horizontal, CSMWorld::ColumnBase::Role_Flags) @@ -51,14 +51,14 @@ bool CSMWorld::IdTableProxyModel::filterAcceptsRow (int sourceRow, const QModelI CSMWorld::IdTableProxyModel::IdTableProxyModel (QObject *parent) : QSortFilterProxyModel (parent), - mSourceModel(NULL) + mSourceModel(nullptr) { setSortCaseSensitivity (Qt::CaseInsensitive); } QModelIndex CSMWorld::IdTableProxyModel::getModelIndex (const std::string& id, int column) const { - Q_ASSERT(mSourceModel != NULL); + Q_ASSERT(mSourceModel != nullptr); return mapFromSource(mSourceModel->getModelIndex (id, column)); } @@ -113,7 +113,7 @@ bool CSMWorld::IdTableProxyModel::lessThan(const QModelIndex &left, const QModel QString CSMWorld::IdTableProxyModel::getRecordId(int sourceRow) const { - Q_ASSERT(mSourceModel != NULL); + Q_ASSERT(mSourceModel != nullptr); int idColumn = mSourceModel->findColumnIndex(Columns::ColumnId_Id); return mSourceModel->data(mSourceModel->index(sourceRow, idColumn)).toString(); diff --git a/apps/opencs/model/world/infotableproxymodel.cpp b/apps/opencs/model/world/infotableproxymodel.cpp index 4f0b2e752..7c6a9c323 100644 --- a/apps/opencs/model/world/infotableproxymodel.cpp +++ b/apps/opencs/model/world/infotableproxymodel.cpp @@ -28,7 +28,7 @@ void CSMWorld::InfoTableProxyModel::setSourceModel(QAbstractItemModel *sourceMod { IdTableProxyModel::setSourceModel(sourceModel); - if (mSourceModel != NULL) + if (mSourceModel != nullptr) { mInfoColumnIndex = mSourceModel->findColumnIndex(mInfoColumnId); mFirstRowCache.clear(); @@ -37,7 +37,7 @@ void CSMWorld::InfoTableProxyModel::setSourceModel(QAbstractItemModel *sourceMod bool CSMWorld::InfoTableProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const { - Q_ASSERT(mSourceModel != NULL); + Q_ASSERT(mSourceModel != nullptr); QModelIndex first = mSourceModel->index(getFirstInfoRow(left.row()), left.column()); QModelIndex second = mSourceModel->index(getFirstInfoRow(right.row()), right.column()); @@ -52,7 +52,7 @@ bool CSMWorld::InfoTableProxyModel::lessThan(const QModelIndex &left, const QMod int CSMWorld::InfoTableProxyModel::getFirstInfoRow(int currentRow) const { - Q_ASSERT(mSourceModel != NULL); + Q_ASSERT(mSourceModel != nullptr); int row = currentRow; int column = mInfoColumnIndex; diff --git a/apps/opencs/model/world/refidadapterimp.cpp b/apps/opencs/model/world/refidadapterimp.cpp index 5ac9ecb18..1948a95cb 100644 --- a/apps/opencs/model/world/refidadapterimp.cpp +++ b/apps/opencs/model/world/refidadapterimp.cpp @@ -453,13 +453,13 @@ void CSMWorld::ContainerRefIdAdapter::setData (const RefIdColumn *column, RefIdD CSMWorld::CreatureColumns::CreatureColumns (const ActorColumns& actorColumns) : ActorColumns (actorColumns), - mType(NULL), - mScale(NULL), - mOriginal(NULL), - mAttributes(NULL), - mAttacks(NULL), - mMisc(NULL), - mBloodType(NULL) + mType(nullptr), + mScale(nullptr), + mOriginal(nullptr), + mAttributes(nullptr), + mAttacks(nullptr), + mMisc(nullptr), + mBloodType(nullptr) {} CSMWorld::CreatureRefIdAdapter::CreatureRefIdAdapter (const CreatureColumns& columns) @@ -748,16 +748,16 @@ void CSMWorld::MiscRefIdAdapter::setData (const RefIdColumn *column, RefIdData& CSMWorld::NpcColumns::NpcColumns (const ActorColumns& actorColumns) : ActorColumns (actorColumns), - mRace(NULL), - mClass(NULL), - mFaction(NULL), - mHair(NULL), - mHead(NULL), - mAttributes(NULL), - mSkills(NULL), - mMisc(NULL), - mBloodType(NULL), - mGender(NULL) + mRace(nullptr), + mClass(nullptr), + mFaction(nullptr), + mHair(nullptr), + mHead(nullptr), + mAttributes(nullptr), + mSkills(nullptr), + mMisc(nullptr), + mBloodType(nullptr), + mGender(nullptr) {} CSMWorld::NpcRefIdAdapter::NpcRefIdAdapter (const NpcColumns& columns) diff --git a/apps/opencs/model/world/resourcesmanager.cpp b/apps/opencs/model/world/resourcesmanager.cpp index 62dfe53a9..1af9c5e9b 100644 --- a/apps/opencs/model/world/resourcesmanager.cpp +++ b/apps/opencs/model/world/resourcesmanager.cpp @@ -3,7 +3,7 @@ #include CSMWorld::ResourcesManager::ResourcesManager() - : mVFS(NULL) + : mVFS(nullptr) { } diff --git a/apps/opencs/view/doc/filedialog.cpp b/apps/opencs/view/doc/filedialog.cpp index 3c5f20202..7693276c6 100644 --- a/apps/opencs/view/doc/filedialog.cpp +++ b/apps/opencs/view/doc/filedialog.cpp @@ -189,7 +189,7 @@ void CSVDoc::FileDialog::slotRejected() if(mFileWidget) { delete mFileWidget; - mFileWidget = NULL; + mFileWidget = nullptr; } close(); } @@ -200,7 +200,7 @@ void CSVDoc::FileDialog::slotNewFile() if(mFileWidget) { delete mFileWidget; - mFileWidget = NULL; + mFileWidget = nullptr; } disconnect (ui.projectButtonBox, SIGNAL (accepted()), this, SLOT (slotNewFile())); close(); diff --git a/apps/opencs/view/doc/subview.hpp b/apps/opencs/view/doc/subview.hpp index 8402bf79a..44b81743f 100644 --- a/apps/opencs/view/doc/subview.hpp +++ b/apps/opencs/view/doc/subview.hpp @@ -64,7 +64,7 @@ namespace CSVDoc void updateTitle(); - void updateSubViewIndices (SubView *view = NULL); + void updateSubViewIndices (SubView *view = nullptr); void universalIdChanged (const CSMWorld::UniversalId& universalId); diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index ca90b11ff..ed4dcff76 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -400,7 +400,7 @@ void CSVDoc::View::updateSubViewIndices(SubView *view) else { delete subView->titleBarWidget(); - subView->setTitleBarWidget (NULL); + subView->setTitleBarWidget (nullptr); } } } @@ -429,7 +429,7 @@ void CSVDoc::View::updateActions() CSVDoc::View::View (ViewManager& viewManager, CSMDoc::Document *document, int totalViews) : mViewManager (viewManager), mDocument (document), mViewIndex (totalViews-1), - mViewTotal (totalViews), mScroll(NULL), mScrollbarOnly(false) + mViewTotal (totalViews), mScroll(nullptr), mScrollbarOnly(false) { CSMPrefs::Category& windows = CSMPrefs::State::get()["Windows"]; @@ -563,7 +563,7 @@ void CSVDoc::View::addSubView (const CSMWorld::UniversalId& id, const std::strin return; } - SubView *view = NULL; + SubView *view = nullptr; if(isReferenceable) { view = mSubViewFactory.makeSubView (CSMWorld::UniversalId(CSMWorld::UniversalId::Type_Referenceable, id.getId()), *mDocument); @@ -631,7 +631,7 @@ void CSVDoc::View::moveScrollBarToEnd(int min, int max) void CSVDoc::View::settingChanged (const CSMPrefs::Setting *setting) { if (*setting=="Windows/hide-subview") - updateSubViewIndices (NULL); + updateSubViewIndices (nullptr); else if (*setting=="Windows/mainwindow-scrollbar") { if (setting->toString()!="Grow Only") @@ -659,7 +659,7 @@ void CSVDoc::View::settingChanged (const CSMPrefs::Setting *setting) mScroll->takeWidget(); setCentralWidget (&mSubViewWindow); mScroll->deleteLater(); - mScroll = NULL; + mScroll = nullptr; } } } diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp index 76c81b964..7a9a48b0f 100644 --- a/apps/opencs/view/doc/view.hpp +++ b/apps/opencs/view/doc/view.hpp @@ -149,7 +149,7 @@ namespace CSVDoc void updateTitle(); // called when subviews are added or removed - void updateSubViewIndices (SubView *view = NULL); + void updateSubViewIndices (SubView *view = nullptr); private slots: diff --git a/apps/opencs/view/render/cameracontroller.cpp b/apps/opencs/view/render/cameracontroller.cpp index 37f439fd3..524a79821 100644 --- a/apps/opencs/view/render/cameracontroller.cpp +++ b/apps/opencs/view/render/cameracontroller.cpp @@ -38,7 +38,7 @@ namespace CSVRender , mCameraSensitivity(1/650.f) , mSecondaryMoveMult(50) , mWheelMoveMult(8) - , mCamera(NULL) + , mCamera(nullptr) { } @@ -81,7 +81,7 @@ namespace CSVRender bool wasActive = mActive; mCamera = camera; - mActive = (mCamera != NULL); + mActive = (mCamera != nullptr); if (mActive != wasActive) { diff --git a/apps/opencs/view/render/object.cpp b/apps/opencs/view/render/object.cpp index 36d80fa4b..026625795 100644 --- a/apps/opencs/view/render/object.cpp +++ b/apps/opencs/view/render/object.cpp @@ -86,7 +86,7 @@ void CSVRender::Object::update() const int ModelIndex = referenceables.findColumnIndex (CSMWorld::Columns::ColumnId_Model); int index = referenceables.searchId (mReferenceableId); - const ESM::Light* light = NULL; + const ESM::Light* light = nullptr; mBaseNode->removeChildren(0, mBaseNode->getNumChildren()); diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index ccea70761..ff69656a2 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.cpp +++ b/apps/opencs/view/render/pagedworldspacewidget.cpp @@ -527,7 +527,7 @@ void CSVRender::PagedWorldspaceWidget::addCellToSceneFromCamera (int offsetX, in CSVRender::PagedWorldspaceWidget::PagedWorldspaceWidget (QWidget* parent, CSMDoc::Document& document) : WorldspaceWidget (document, parent), mDocument (document), mWorldspace ("std::default"), - mControlElements(NULL), mDisplayCellCoord(true) + mControlElements(nullptr), mDisplayCellCoord(true) { QAbstractItemModel *cells = document.getData().getTableModel (CSMWorld::UniversalId::Type_Cells); diff --git a/apps/opencs/view/render/scenewidget.cpp b/apps/opencs/view/render/scenewidget.cpp index 0d1780d57..6cc64f653 100644 --- a/apps/opencs/view/render/scenewidget.cpp +++ b/apps/opencs/view/render/scenewidget.cpp @@ -185,7 +185,7 @@ SceneWidget::SceneWidget(std::shared_ptr resourceSyste bool retrieveInput) : RenderWidget(parent, f) , mResourceSystem(resourceSystem) - , mLighting(NULL) + , mLighting(nullptr) , mHasDefaultAmbient(false) , mPrevMouseX(0) , mPrevMouseY(0) @@ -425,21 +425,21 @@ void SceneWidget::selectNavigationMode (const std::string& mode) { if (mode=="1st") { - mCurrentCamControl->setCamera(NULL); + mCurrentCamControl->setCamera(nullptr); mCurrentCamControl = mFreeCamControl; mFreeCamControl->setCamera(getCamera()); mFreeCamControl->fixUpAxis(CameraController::WorldUp); } else if (mode=="free") { - mCurrentCamControl->setCamera(NULL); + mCurrentCamControl->setCamera(nullptr); mCurrentCamControl = mFreeCamControl; mFreeCamControl->setCamera(getCamera()); mFreeCamControl->unfixUpAxis(); } else if (mode=="orbit") { - mCurrentCamControl->setCamera(NULL); + mCurrentCamControl->setCamera(nullptr); mCurrentCamControl = mOrbitCamControl; mOrbitCamControl->setCamera(getCamera()); mOrbitCamControl->reset(); diff --git a/apps/opencs/view/render/terrainstorage.cpp b/apps/opencs/view/render/terrainstorage.cpp index 51c9dd009..e0edae774 100644 --- a/apps/opencs/view/render/terrainstorage.cpp +++ b/apps/opencs/view/render/terrainstorage.cpp @@ -18,7 +18,7 @@ namespace CSVRender // has to wrap the vertices of the last row and column to the next cell, which may be a nonexisting cell int index = mData.getLand().searchId(CSMWorld::Land::createUniqueRecordId(cellX, cellY)); if (index == -1) - return NULL; + return nullptr; const ESM::Land& land = mData.getLand().getRecord(index).get(); return new ESMTerrain::LandObject(&land, ESM::Land::DATA_VHGT | ESM::Land::DATA_VNML | ESM::Land::DATA_VCLR | ESM::Land::DATA_VTEX); diff --git a/apps/opencs/view/widget/colorpickerpopup.cpp b/apps/opencs/view/widget/colorpickerpopup.cpp index 47aab8981..a38728ef3 100644 --- a/apps/opencs/view/widget/colorpickerpopup.cpp +++ b/apps/opencs/view/widget/colorpickerpopup.cpp @@ -45,7 +45,7 @@ void CSVWidget::ColorPickerPopup::showPicker(const QPoint &position, const QColo void CSVWidget::ColorPickerPopup::mousePressEvent(QMouseEvent *event) { QPushButton *button = qobject_cast(parentWidget()); - if (button != NULL) + if (button != nullptr) { QStyleOptionButton option; option.init(button); diff --git a/apps/opencs/view/widget/completerpopup.cpp b/apps/opencs/view/widget/completerpopup.cpp index 5777325c8..be509bcb9 100644 --- a/apps/opencs/view/widget/completerpopup.cpp +++ b/apps/opencs/view/widget/completerpopup.cpp @@ -11,7 +11,7 @@ CSVWidget::CompleterPopup::CompleterPopup(QWidget *parent) int CSVWidget::CompleterPopup::sizeHintForRow(int row) const { - if (model() == NULL) + if (model() == nullptr) { return -1; } diff --git a/apps/opencs/view/world/cellcreator.cpp b/apps/opencs/view/world/cellcreator.cpp index 2a710a940..a42e7ead4 100644 --- a/apps/opencs/view/world/cellcreator.cpp +++ b/apps/opencs/view/world/cellcreator.cpp @@ -25,7 +25,7 @@ std::string CSVWorld::CellCreator::getId() const void CSVWorld::CellCreator::configureCreateCommand(CSMWorld::CreateCommand& command) const { CSMWorld::IdTree *model = dynamic_cast(getData().getTableModel(getCollectionId())); - Q_ASSERT(model != NULL); + Q_ASSERT(model != nullptr); int parentIndex = model->findColumnIndex(CSMWorld::Columns::ColumnId_Cell); int index = model->findNestedColumnIndex(parentIndex, CSMWorld::Columns::ColumnId_Interior); command.addNestedValue(parentIndex, index, mType->currentIndex() == 0); diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index 7b198056c..b32e2c7a1 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -158,7 +158,7 @@ mNotEditableDelegate(table, parent) CSVWorld::CommandDelegate* CSVWorld::DialogueDelegateDispatcher::makeDelegate(CSMWorld::ColumnBase::Display display) { - CommandDelegate *delegate = NULL; + CommandDelegate *delegate = nullptr; std::map::const_iterator delegateIt(mDelegates.find(display)); if (delegateIt == mDelegates.end()) { @@ -251,11 +251,11 @@ QWidget* CSVWorld::DialogueDelegateDispatcher::makeEditor(CSMWorld::ColumnBase:: variant = index.data(Qt::DisplayRole); if (!variant.isValid()) { - return NULL; + return nullptr; } } - QWidget* editor = NULL; + QWidget* editor = nullptr; if (! (mTable->flags (index) & Qt::ItemIsEditable)) { return mNotEditableDelegate.createEditor(qobject_cast(mParent), @@ -325,7 +325,7 @@ CSVWorld::IdContextMenu::IdContextMenu(QWidget *widget, CSMWorld::ColumnBase::Di mWidget(widget), mIdType(CSMWorld::TableMimeData::convertEnums(display)) { - Q_ASSERT(mWidget != NULL); + Q_ASSERT(mWidget != nullptr); Q_ASSERT(CSMWorld::ColumnBase::isId(display)); Q_ASSERT(mIdType != CSMWorld::UniversalId::Type_None); @@ -339,7 +339,7 @@ CSVWorld::IdContextMenu::IdContextMenu(QWidget *widget, CSMWorld::ColumnBase::Di connect(mEditIdAction, SIGNAL(triggered()), this, SLOT(editIdRequest())); QLineEdit *lineEdit = qobject_cast(mWidget); - if (lineEdit != NULL) + if (lineEdit != nullptr) { mContextMenu = lineEdit->createStandardContextMenu(); } @@ -360,11 +360,11 @@ QString CSVWorld::IdContextMenu::getWidgetValue() const QLabel *label = qobject_cast(mWidget); QString value = ""; - if (lineEdit != NULL) + if (lineEdit != nullptr) { value = lineEdit->text(); } - else if (label != NULL) + else if (label != nullptr) { value = label->text(); } @@ -436,7 +436,7 @@ void CSVWorld::EditWidget::createEditorContextMenu(QWidget *editor, CSMWorld::ColumnBase::Display display, int currentRow) const { - Q_ASSERT(editor != NULL); + Q_ASSERT(editor != nullptr); if (CSMWorld::ColumnBase::isId(display) && CSMWorld::TableMimeData::convertEnums(display) != CSMWorld::UniversalId::Type_None) @@ -470,11 +470,11 @@ CSVWorld::EditWidget::EditWidget(QWidget *parent, int row, CSMWorld::IdTable* table, CSMWorld::CommandDispatcher& commandDispatcher, CSMDoc::Document& document, bool createAndDelete) : QScrollArea(parent), -mWidgetMapper(NULL), -mNestedTableMapper(NULL), -mDispatcher(NULL), -mNestedTableDispatcher(NULL), -mMainWidget(NULL), +mWidgetMapper(nullptr), +mNestedTableMapper(nullptr), +mDispatcher(nullptr), +mNestedTableDispatcher(nullptr), +mMainWidget(nullptr), mTable(table), mCommandDispatcher (commandDispatcher), mDocument (document) @@ -733,7 +733,7 @@ bool CSVWorld::SimpleDialogueSubView::isLocked() const CSVWorld::SimpleDialogueSubView::SimpleDialogueSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document) : SubView (id), mEditWidget(0), - mMainLayout(NULL), + mMainLayout(nullptr), mTable(dynamic_cast(document.getData().getTableModel(id))), mLocked(false), mDocument(document), diff --git a/apps/opencs/view/world/dragdroputils.cpp b/apps/opencs/view/world/dragdroputils.cpp index 7f3974e53..789d4f33d 100644 --- a/apps/opencs/view/world/dragdroputils.cpp +++ b/apps/opencs/view/world/dragdroputils.cpp @@ -12,7 +12,7 @@ const CSMWorld::TableMimeData *CSVWorld::DragDropUtils::getTableMimeData(const Q bool CSVWorld::DragDropUtils::canAcceptData(const QDropEvent &event, CSMWorld::ColumnBase::Display type) { const CSMWorld::TableMimeData *data = getTableMimeData(event); - return data != NULL && data->holdsType(type); + return data != nullptr && data->holdsType(type); } CSMWorld::UniversalId CSVWorld::DragDropUtils::getAcceptedData(const QDropEvent &event, diff --git a/apps/opencs/view/world/dragrecordtable.cpp b/apps/opencs/view/world/dragrecordtable.cpp index 6d980e171..d795bd5de 100644 --- a/apps/opencs/view/world/dragrecordtable.cpp +++ b/apps/opencs/view/world/dragrecordtable.cpp @@ -83,7 +83,7 @@ void CSVWorld::DragRecordTable::dropEvent(QDropEvent *event) CSMWorld::ColumnBase::Display CSVWorld::DragRecordTable::getIndexDisplayType(const QModelIndex &index) const { - Q_ASSERT(model() != NULL); + Q_ASSERT(model() != nullptr); if (index.isValid()) { diff --git a/apps/opencs/view/world/dragrecordtable.hpp b/apps/opencs/view/world/dragrecordtable.hpp index 560864ba5..9e29b6145 100644 --- a/apps/opencs/view/world/dragrecordtable.hpp +++ b/apps/opencs/view/world/dragrecordtable.hpp @@ -28,7 +28,7 @@ namespace CSVWorld bool mEditLock; public: - DragRecordTable(CSMDoc::Document& document, QWidget* parent = NULL); + DragRecordTable(CSMDoc::Document& document, QWidget* parent = nullptr); virtual std::vector getDraggedRecords() const = 0; diff --git a/apps/opencs/view/world/extendedcommandconfigurator.cpp b/apps/opencs/view/world/extendedcommandconfigurator.cpp index 2cf6222a6..894742024 100644 --- a/apps/opencs/view/world/extendedcommandconfigurator.cpp +++ b/apps/opencs/view/world/extendedcommandconfigurator.cpp @@ -95,7 +95,7 @@ void CSVWorld::ExtendedCommandConfigurator::setupGroupLayout() int divider = 1; do { - while (layout->itemAt(0) != NULL) + while (layout->itemAt(0) != nullptr) { layout->removeItem(layout->itemAt(0)); } diff --git a/apps/opencs/view/world/idcompletiondelegate.cpp b/apps/opencs/view/world/idcompletiondelegate.cpp index 7f0f4ae46..4ff850b9f 100644 --- a/apps/opencs/view/world/idcompletiondelegate.cpp +++ b/apps/opencs/view/world/idcompletiondelegate.cpp @@ -25,7 +25,7 @@ QWidget *CSVWorld::IdCompletionDelegate::createEditor(QWidget *parent, { if (!index.data(Qt::EditRole).isValid() && !index.data(Qt::DisplayRole).isValid()) { - return NULL; + return nullptr; } // The completer for InfoCondVar needs to return a completer based on the first column diff --git a/apps/opencs/view/world/nestedtable.cpp b/apps/opencs/view/world/nestedtable.cpp index 02bd93920..1b72211e8 100644 --- a/apps/opencs/view/world/nestedtable.cpp +++ b/apps/opencs/view/world/nestedtable.cpp @@ -23,9 +23,9 @@ CSVWorld::NestedTable::NestedTable(CSMDoc::Document& document, bool editable, bool fixedRows) : DragRecordTable(document, parent), - mAddNewRowAction(NULL), - mRemoveRowAction(NULL), - mEditIdAction(NULL), + mAddNewRowAction(nullptr), + mRemoveRowAction(nullptr), + mEditIdAction(nullptr), mModel(model) { mDispatcher = new CSMWorld::CommandDispatcher (document, id, this); diff --git a/apps/opencs/view/world/nestedtable.hpp b/apps/opencs/view/world/nestedtable.hpp index 765060ea5..b39c7e560 100644 --- a/apps/opencs/view/world/nestedtable.hpp +++ b/apps/opencs/view/world/nestedtable.hpp @@ -38,7 +38,7 @@ namespace CSVWorld NestedTable(CSMDoc::Document& document, CSMWorld::UniversalId id, CSMWorld::NestedTableProxyModel* model, - QWidget* parent = NULL, + QWidget* parent = nullptr, bool editable = true, bool fixedRows = false); diff --git a/apps/opencs/view/world/scenesubview.cpp b/apps/opencs/view/world/scenesubview.cpp index b14d708da..b03cf8fdb 100644 --- a/apps/opencs/view/world/scenesubview.cpp +++ b/apps/opencs/view/world/scenesubview.cpp @@ -27,7 +27,7 @@ #include "creator.hpp" CSVWorld::SceneSubView::SceneSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document) -: SubView (id), mScene(NULL), mLayout(new QHBoxLayout), mDocument(document), mToolbar(NULL) +: SubView (id), mScene(nullptr), mLayout(new QHBoxLayout), mDocument(document), mToolbar(nullptr) { QVBoxLayout *layout = new QVBoxLayout; @@ -35,7 +35,7 @@ CSVWorld::SceneSubView::SceneSubView (const CSMWorld::UniversalId& id, CSMDoc::D mLayout->setContentsMargins (QMargins (0, 0, 0, 0)); - CSVRender::WorldspaceWidget* worldspaceWidget = NULL; + CSVRender::WorldspaceWidget* worldspaceWidget = nullptr; widgetType whatWidget; if (id.getId()==ESM::CellId::sDefaultWorldspace) @@ -189,9 +189,9 @@ void CSVWorld::SceneSubView::cellSelectionChanged (const CSMWorld::CellSelection void CSVWorld::SceneSubView::handleDrop (const std::vector< CSMWorld::UniversalId >& universalIdData) { - CSVRender::PagedWorldspaceWidget* pagedNewWidget = NULL; - CSVRender::UnpagedWorldspaceWidget* unPagedNewWidget = NULL; - CSVWidget::SceneToolbar* toolbar = NULL; + CSVRender::PagedWorldspaceWidget* pagedNewWidget = nullptr; + CSVRender::UnpagedWorldspaceWidget* unPagedNewWidget = nullptr; + CSVWidget::SceneToolbar* toolbar = nullptr; CSVRender::WorldspaceWidget::DropType type = CSVRender::WorldspaceWidget::getDropType (universalIdData); diff --git a/apps/opencs/view/world/util.cpp b/apps/opencs/view/world/util.cpp index b194e460d..8cdb2d2db 100644 --- a/apps/opencs/view/world/util.cpp +++ b/apps/opencs/view/world/util.cpp @@ -129,7 +129,7 @@ void CSVWorld::CommandDelegate::setModelDataImp (QWidget *editor, QAbstractItemM // Color columns use a custom editor, so we need to fetch selected color from it. CSVWidget::ColorEditor *colorEditor = qobject_cast(editor); - if (colorEditor != NULL) + if (colorEditor != nullptr) { variant = colorEditor->colorInt(); } @@ -322,7 +322,7 @@ void CSVWorld::CommandDelegate::setEditorData (QWidget *editor, const QModelInde // Color columns use a custom editor, so we need explicitly set a data for it CSVWidget::ColorEditor *colorEditor = qobject_cast(editor); - if (colorEditor != NULL) + if (colorEditor != nullptr) { colorEditor->setColor(variant.toInt()); return; diff --git a/apps/openmw/android_main.c b/apps/openmw/android_main.c index d234a369d..9a7b6bc50 100644 --- a/apps/openmw/android_main.c +++ b/apps/openmw/android_main.c @@ -20,14 +20,14 @@ void releaseArgv(); int Java_org_libsdl_app_SDLActivity_getMouseX(JNIEnv *env, jclass cls, jobject obj) { int ret = 0; - SDL_GetMouseState(&ret, NULL); + SDL_GetMouseState(&ret, nullptr); return ret; } int Java_org_libsdl_app_SDLActivity_getMouseY(JNIEnv *env, jclass cls, jobject obj) { int ret = 0; - SDL_GetMouseState(NULL, &ret); + SDL_GetMouseState(nullptr, &ret); return ret; } diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 057113ba3..f5b4171d4 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -197,9 +197,9 @@ bool OMW::Engine::frame(float frametime) } OMW::Engine::Engine(Files::ConfigurationManager& configurationManager) - : mWindow(NULL) + : mWindow(nullptr) , mEncoding(ToUTF8::WINDOWS_1252) - , mEncoder(NULL) + , mEncoder(nullptr) , mScreenCaptureOperation(nullptr) , mSkipMenu (false) , mUseSound (true) @@ -237,18 +237,18 @@ OMW::Engine::~Engine() mEnvironment.cleanup(); delete mScriptContext; - mScriptContext = NULL; + mScriptContext = nullptr; - mWorkQueue = NULL; + mWorkQueue = nullptr; mResourceSystem.reset(); - mViewer = NULL; + mViewer = nullptr; if (mWindow) { SDL_DestroyWindow(mWindow); - mWindow = NULL; + mWindow = nullptr; } SDL_Quit(); diff --git a/apps/openmw/mwclass/container.cpp b/apps/openmw/mwclass/container.cpp index efe460b00..e1784d593 100644 --- a/apps/openmw/mwclass/container.cpp +++ b/apps/openmw/mwclass/container.cpp @@ -74,7 +74,7 @@ namespace MWClass if (ref->mBase->mFlags & ESM::Container::Respawn) { MWBase::Environment::get().getWorld()->removeContainerScripts(ptr); - ptr.getRefData().setCustomData(NULL); + ptr.getRefData().setCustomData(nullptr); } } diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 6999558ae..6d0b42bfe 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -298,7 +298,7 @@ namespace MWClass bool healthdmg = true; if (!weapon.isEmpty()) { - const unsigned char *attack = NULL; + const unsigned char *attack = nullptr; if(type == ESM::Weapon::AT_Chop) attack = weapon.get()->mBase->mData.mChop; else if(type == ESM::Weapon::AT_Slash) @@ -828,7 +828,7 @@ namespace MWClass ptr.getRefData().setCount(1); MWBase::Environment::get().getWorld()->removeContainerScripts(ptr); - ptr.getRefData().setCustomData(NULL); + ptr.getRefData().setCustomData(nullptr); // Reset to original position MWBase::Environment::get().getWorld()->moveObject(ptr, ptr.getCellRef().getPosition().pos[0], diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index 3ee228013..ea0abd6f6 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -41,7 +41,7 @@ namespace MWClass { MWWorld::LiveCellRef *ref = ptr.get(); - assert (ref->mBase != NULL); + assert (ref->mBase != nullptr); // TODO: add option somewhere to enable collision for placeable objects if (!model.empty() && (ref->mBase->mData.mFlags & ESM::Light::Carry) == 0) diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 4979db2fd..1daf28542 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -610,7 +610,7 @@ namespace MWClass float damage = 0.0f; if(!weapon.isEmpty()) { - const unsigned char *attack = NULL; + const unsigned char *attack = nullptr; if(type == ESM::Weapon::AT_Chop) attack = weapon.get()->mBase->mData.mChop; else if(type == ESM::Weapon::AT_Slash) @@ -1382,7 +1382,7 @@ namespace MWClass ptr.getRefData().setCount(1); MWBase::Environment::get().getWorld()->removeContainerScripts(ptr); - ptr.getRefData().setCustomData(NULL); + ptr.getRefData().setCustomData(nullptr); // Reset to original position MWBase::Environment::get().getWorld()->moveObject(ptr, ptr.getCellRef().getPosition().pos[0], diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index dcc33d1c3..17f69d69b 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -572,7 +572,7 @@ namespace MWDialogue const MWMechanics::CreatureStats& creatureStats = actor.getClass().getCreatureStats(actor); Filter filter(actor, 0, creatureStats.hasTalkedToPlayer()); const ESM::DialInfo *info = filter.search(*dial, false); - if(info != NULL) + if(info != nullptr) { MWBase::WindowManager *winMgr = MWBase::Environment::get().getWindowManager(); if(winMgr->getSubtitlesEnabled()) diff --git a/apps/openmw/mwdialogue/filter.cpp b/apps/openmw/mwdialogue/filter.cpp index 15020898f..042ccb019 100644 --- a/apps/openmw/mwdialogue/filter.cpp +++ b/apps/openmw/mwdialogue/filter.cpp @@ -621,7 +621,7 @@ const ESM::DialInfo* MWDialogue::Filter::search (const ESM::Dialogue& dialogue, std::vector suitableInfos = list (dialogue, fallbackToInfoRefusal, false); if (suitableInfos.empty()) - return NULL; + return nullptr; else return suitableInfos[0]; } diff --git a/apps/openmw/mwdialogue/journalentry.cpp b/apps/openmw/mwdialogue/journalentry.cpp index 9f74d0733..5eab6d5ca 100644 --- a/apps/openmw/mwdialogue/journalentry.cpp +++ b/apps/openmw/mwdialogue/journalentry.cpp @@ -30,7 +30,7 @@ namespace MWDialogue { if (actor.isEmpty()) { - MWScript::InterpreterContext interpreterContext(NULL,MWWorld::Ptr()); + MWScript::InterpreterContext interpreterContext(nullptr, MWWorld::Ptr()); mText = Interpreter::fixDefinesDialog(iter->mResponse, interpreterContext); } else diff --git a/apps/openmw/mwgui/alchemywindow.cpp b/apps/openmw/mwgui/alchemywindow.cpp index a599e6c7b..fa8a96185 100644 --- a/apps/openmw/mwgui/alchemywindow.cpp +++ b/apps/openmw/mwgui/alchemywindow.cpp @@ -30,7 +30,7 @@ namespace MWGui AlchemyWindow::AlchemyWindow() : WindowBase("openmw_alchemy_window.layout") - , mSortModel(NULL) + , mSortModel(nullptr) , mAlchemy(new MWMechanics::Alchemy()) , mApparatus (4) , mIngredients (4) diff --git a/apps/openmw/mwgui/backgroundimage.cpp b/apps/openmw/mwgui/backgroundimage.cpp index 98828a041..55c825ebb 100644 --- a/apps/openmw/mwgui/backgroundimage.cpp +++ b/apps/openmw/mwgui/backgroundimage.cpp @@ -10,7 +10,7 @@ void BackgroundImage::setBackgroundImage (const std::string& image, bool fixedRa if (mChild) { MyGUI::Gui::getInstance().destroyWidget(mChild); - mChild = NULL; + mChild = nullptr; } if (!stretch) { diff --git a/apps/openmw/mwgui/backgroundimage.hpp b/apps/openmw/mwgui/backgroundimage.hpp index 8c963b762..3db5bab16 100644 --- a/apps/openmw/mwgui/backgroundimage.hpp +++ b/apps/openmw/mwgui/backgroundimage.hpp @@ -14,7 +14,7 @@ namespace MWGui MYGUI_RTTI_DERIVED(BackgroundImage) public: - BackgroundImage() : mChild(NULL), mAspect(0) {} + BackgroundImage() : mChild(nullptr), mAspect(0) {} /** * @param fixedRatio Use a fixed ratio of 4:3, regardless of the image dimensions diff --git a/apps/openmw/mwgui/bookpage.cpp b/apps/openmw/mwgui/bookpage.cpp index c3b8935e8..29dfe7f3a 100644 --- a/apps/openmw/mwgui/bookpage.cpp +++ b/apps/openmw/mwgui/bookpage.cpp @@ -110,7 +110,7 @@ struct TypesetBookImpl : TypesetBook Contents::iterator i = mContents.insert (mContents.end (), Content (text.first, text.second)); if (i->empty()) - return Range (Utf8Point (NULL), Utf8Point (NULL)); + return Range (Utf8Point (nullptr), Utf8Point (nullptr)); Utf8Point begin = &i->front (); Utf8Point end = &i->front () + i->size (); @@ -148,7 +148,7 @@ struct TypesetBookImpl : TypesetBook template void visitRuns (int top, int bottom, Visitor const & visitor) const { - visitRuns (top, bottom, NULL, visitor); + visitRuns (top, bottom, nullptr, visitor); } /// hit test with a margin for error. only hits on interactive text fragments are reported. @@ -176,7 +176,7 @@ struct TypesetBookImpl : TypesetBook return hit; } } - return NULL; + return nullptr; } StyleImpl * hitTest (int left, int top) const @@ -213,7 +213,7 @@ struct TypesetBookImpl : TypesetBook for (Styles::iterator i = mStyles.begin (); i != mStyles.end (); ++i) if (&*i == style) return i->mFont; - return NULL; + return nullptr; } struct Typesetter; @@ -253,8 +253,8 @@ struct TypesetBookImpl::Typesetter : BookTypesetter Typesetter (size_t width, size_t height) : mPageWidth (width), mPageHeight(height), - mSection (NULL), mLine (NULL), mRun (NULL), - mCurrentContent (NULL), + mSection (nullptr), mLine (nullptr), mRun (nullptr), + mCurrentContent (nullptr), mCurrentAlignment (AlignLeft) { mBook = std::make_shared (); @@ -342,7 +342,7 @@ struct TypesetBookImpl::Typesetter : BookTypesetter void write (Style * style, size_t begin, size_t end) { - assert (mCurrentContent != NULL); + assert (mCurrentContent != nullptr); assert (end <= mCurrentContent->size ()); assert (begin <= mCurrentContent->size ()); @@ -358,8 +358,8 @@ struct TypesetBookImpl::Typesetter : BookTypesetter add_partial_text(); - mRun = NULL; - mLine = NULL; + mRun = nullptr; + mLine = nullptr; } void sectionBreak (int margin) @@ -368,9 +368,9 @@ struct TypesetBookImpl::Typesetter : BookTypesetter if (mBook->mSections.size () > 0) { - mRun = NULL; - mLine = NULL; - mSection = NULL; + mRun = nullptr; + mLine = nullptr; + mSection = nullptr; if (mBook->mRect.bottom < (mBook->mSections.back ().mRect.bottom + margin)) mBook->mRect.bottom = (mBook->mSections.back ().mRect.bottom + margin); @@ -381,7 +381,7 @@ struct TypesetBookImpl::Typesetter : BookTypesetter { add_partial_text(); - if (mSection != NULL) + if (mSection != nullptr) mSectionAlignment.back () = sectionAlignment; mCurrentAlignment = sectionAlignment; } @@ -491,7 +491,7 @@ struct TypesetBookImpl::Typesetter : BookTypesetter { add_partial_text(); stream.consume (); - mLine = NULL, mRun = NULL; + mLine = nullptr, mRun = nullptr; continue; } @@ -551,7 +551,7 @@ struct TypesetBookImpl::Typesetter : BookTypesetter if (left + space_width + word_width > mPageWidth) { - mLine = NULL, mRun = NULL, left = 0; + mLine = nullptr, mRun = nullptr, left = 0; } else { @@ -580,7 +580,7 @@ struct TypesetBookImpl::Typesetter : BookTypesetter void append_run (StyleImpl * style, Utf8Stream::Point begin, Utf8Stream::Point end, int pc, int right, int bottom) { - if (mSection == NULL) + if (mSection == nullptr) { mBook->mSections.push_back (Section ()); mSection = &mBook->mSections.back (); @@ -588,7 +588,7 @@ struct TypesetBookImpl::Typesetter : BookTypesetter mSectionAlignment.push_back (mCurrentAlignment); } - if (mLine == NULL) + if (mLine == nullptr) { mSection->mLines.push_back (Line ()); mLine = &mSection->mLines.back (); @@ -613,7 +613,7 @@ struct TypesetBookImpl::Typesetter : BookTypesetter if (mLine->mRect.bottom < bottom) mLine->mRect.bottom = bottom; - if (mRun == NULL || mRun->mStyle != style || mRun->mRange.second != begin) + if (mRun == nullptr || mRun->mStyle != style || mRun->mRange.second != begin) { int left = mRun ? mRun->mRight : mLine->mRect.left; @@ -843,17 +843,17 @@ protected: TextFormat (MyGUI::IFont* id, PageDisplay * display) : mFont (id), mCountVertex (0), - mTexture (NULL), - mRenderItem (NULL), + mTexture (nullptr), + mRenderItem (nullptr), mDisplay (display) { } void createDrawItem (MyGUI::ILayerNode* node) { - assert (mRenderItem == NULL); + assert (mRenderItem == nullptr); - if (mTexture != NULL) + if (mTexture != nullptr) { mRenderItem = node->addToRenderItem(mTexture, false, false); mRenderItem->addDrawItem(this, mCountVertex); @@ -862,12 +862,12 @@ protected: void destroyDrawItem (MyGUI::ILayerNode* node) { - assert (mTexture != NULL ? mRenderItem != NULL : mRenderItem == NULL); + assert (mTexture != nullptr ? mRenderItem != nullptr : mRenderItem == nullptr); - if (mTexture != NULL) + if (mTexture != nullptr) { mRenderItem->removeDrawItem (this); - mRenderItem = NULL; + mRenderItem = nullptr; } } @@ -920,9 +920,9 @@ public: resetPage (); mViewTop = 0; mViewBottom = 0; - mFocusItem = NULL; + mFocusItem = nullptr; mItemActive = false; - mNode = NULL; + mNode = nullptr; } void dirtyFocusItem () @@ -1053,7 +1053,7 @@ public: for (ActiveTextFormats::iterator i = mActiveTextFormats.begin (); i != mActiveTextFormats.end (); ++i) { - if (mNode != NULL) + if (mNode != nullptr) i->second->destroyDrawItem (mNode); i->second.reset(); } @@ -1089,7 +1089,7 @@ public: else if (mBook && isPageDifferent (newPage)) { - if (mNode != NULL) + if (mNode != nullptr) for (ActiveTextFormats::iterator i = mActiveTextFormats.begin (); i != mActiveTextFormats.end (); ++i) mNode->outOfDate(i->second->mRenderItem); @@ -1137,7 +1137,7 @@ public: { newBook->visitRuns (0, 0x7FFFFFFF, CreateActiveFormat (this)); - if (mNode != NULL) + if (mNode != nullptr) for (ActiveTextFormats::iterator i = mActiveTextFormats.begin (); i != mActiveTextFormats.end (); ++i) i->second->createDrawItem (mNode); } @@ -1238,7 +1238,7 @@ public: { _checkMargin(); - if (mNode != NULL) + if (mNode != nullptr) for (ActiveTextFormats::iterator i = mActiveTextFormats.begin (); i != mActiveTextFormats.end (); ++i) mNode->outOfDate (i->second->mRenderItem); } @@ -1247,7 +1247,7 @@ public: { _checkMargin (); - if (mNode != NULL) + if (mNode != nullptr) for (ActiveTextFormats::iterator i = mActiveTextFormats.begin (); i != mActiveTextFormats.end (); ++i) mNode->outOfDate (i->second->mRenderItem); @@ -1258,7 +1258,7 @@ public: for (ActiveTextFormats::iterator i = mActiveTextFormats.begin (); i != mActiveTextFormats.end (); ++i) i->second->destroyDrawItem (mNode); - mNode = NULL; + mNode = nullptr; } }; @@ -1269,7 +1269,7 @@ MYGUI_RTTI_DERIVED(BookPage) public: BookPageImpl() - : mPageDisplay(NULL) + : mPageDisplay(nullptr) { } diff --git a/apps/openmw/mwgui/class.cpp b/apps/openmw/mwgui/class.cpp index 6ed7a4491..45abe889e 100644 --- a/apps/openmw/mwgui/class.cpp +++ b/apps/openmw/mwgui/class.cpp @@ -399,12 +399,12 @@ namespace MWGui CreateClassDialog::CreateClassDialog() : WindowModal("openmw_chargen_create_class.layout") - , mSpecDialog(NULL) - , mAttribDialog(NULL) - , mSkillDialog(NULL) - , mDescDialog(NULL) - , mAffectedAttribute(NULL) - , mAffectedSkill(NULL) + , mSpecDialog(nullptr) + , mAttribDialog(nullptr) + , mSkillDialog(nullptr) + , mDescDialog(nullptr) + , mAffectedAttribute(nullptr) + , mAffectedSkill(nullptr) { // Centre dialog center(); diff --git a/apps/openmw/mwgui/companionwindow.cpp b/apps/openmw/mwgui/companionwindow.cpp index c6ef2890d..b2639e938 100644 --- a/apps/openmw/mwgui/companionwindow.cpp +++ b/apps/openmw/mwgui/companionwindow.cpp @@ -37,8 +37,8 @@ namespace MWGui CompanionWindow::CompanionWindow(DragAndDrop *dragAndDrop, MessageBoxManager* manager) : WindowBase("openmw_companion_window.layout") - , mSortModel(NULL) - , mModel(NULL) + , mSortModel(nullptr) + , mModel(nullptr) , mSelectedItem(-1) , mDragAndDrop(dragAndDrop) , mMessageBoxManager(manager) @@ -89,7 +89,7 @@ void CompanionWindow::onItemSelected(int index) dialog->eventOkClicked += MyGUI::newDelegate(this, &CompanionWindow::dragItem); } else - dragItem (NULL, count); + dragItem (nullptr, count); } void CompanionWindow::dragItem(MyGUI::Widget* sender, int count) @@ -179,9 +179,9 @@ void CompanionWindow::onReferenceUnavailable() void CompanionWindow::resetReference() { ReferenceInterface::resetReference(); - mItemView->setModel(NULL); - mModel = NULL; - mSortModel = NULL; + mItemView->setModel(nullptr); + mModel = nullptr; + mSortModel = nullptr; } diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 99d0ea0d1..2f9643f74 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -31,8 +31,8 @@ namespace MWGui ContainerWindow::ContainerWindow(DragAndDrop* dragAndDrop) : WindowBase("openmw_container_window.layout") , mDragAndDrop(dragAndDrop) - , mSortModel(NULL) - , mModel(NULL) + , mSortModel(nullptr) + , mModel(nullptr) , mSelectedItem(-1) { getWidget(mDisposeCorpseButton, "DisposeCorpseButton"); @@ -83,7 +83,7 @@ namespace MWGui dialog->eventOkClicked += MyGUI::newDelegate(this, &ContainerWindow::dragItem); } else - dragItem (NULL, count); + dragItem (nullptr, count); } void ContainerWindow::dragItem(MyGUI::Widget* sender, int count) @@ -151,9 +151,9 @@ namespace MWGui void ContainerWindow::resetReference() { ReferenceInterface::resetReference(); - mItemView->setModel(NULL); - mModel = NULL; - mSortModel = NULL; + mItemView->setModel(nullptr); + mModel = nullptr; + mSortModel = nullptr; } void ContainerWindow::onClose() @@ -171,7 +171,7 @@ namespace MWGui void ContainerWindow::onTakeAllButtonClicked(MyGUI::Widget* _sender) { - if(mDragAndDrop != NULL && mDragAndDrop->mIsOnDragAndDrop) + if(mDragAndDrop != nullptr && mDragAndDrop->mIsOnDragAndDrop) return; MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mCloseButton); @@ -219,7 +219,7 @@ namespace MWGui void ContainerWindow::onDisposeCorpseButtonClicked(MyGUI::Widget *sender) { - if(mDragAndDrop == NULL || !mDragAndDrop->mIsOnDragAndDrop) + if(mDragAndDrop == nullptr || !mDragAndDrop->mIsOnDragAndDrop) { MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mCloseButton); diff --git a/apps/openmw/mwgui/countdialog.cpp b/apps/openmw/mwgui/countdialog.cpp index 4292f2e04..baf3a43ab 100644 --- a/apps/openmw/mwgui/countdialog.cpp +++ b/apps/openmw/mwgui/countdialog.cpp @@ -63,7 +63,7 @@ namespace MWGui void CountDialog::onOkButtonClicked(MyGUI::Widget* _sender) { - eventOkClicked(NULL, mSlider->getScrollPosition()+1); + eventOkClicked(nullptr, mSlider->getScrollPosition()+1); setVisible(false); } @@ -72,7 +72,7 @@ namespace MWGui // Enter key void CountDialog::onEnterKeyPressed(MyGUI::EditBox* _sender) { - eventOkClicked(NULL, mSlider->getScrollPosition()+1); + eventOkClicked(nullptr, mSlider->getScrollPosition()+1); setVisible(false); // To do not spam onEnterKeyPressed() again and again diff --git a/apps/openmw/mwgui/cursor.cpp b/apps/openmw/mwgui/cursor.cpp index 82e0b9699..ed8a76eb8 100644 --- a/apps/openmw/mwgui/cursor.cpp +++ b/apps/openmw/mwgui/cursor.cpp @@ -10,7 +10,7 @@ namespace MWGui ResourceImageSetPointerFix::ResourceImageSetPointerFix() - : mImageSet(NULL) + : mImageSet(nullptr) , mRotation(0) { } @@ -47,7 +47,7 @@ namespace MWGui void ResourceImageSetPointerFix::setImage(MyGUI::ImageBox* _image) { - if (mImageSet != NULL) + if (mImageSet != nullptr) _image->setItemResourceInfo(mImageSet->getIndexInfo(0, 0)); } diff --git a/apps/openmw/mwgui/draganddrop.cpp b/apps/openmw/mwgui/draganddrop.cpp index d81b2ed00..daf9f6636 100644 --- a/apps/openmw/mwgui/draganddrop.cpp +++ b/apps/openmw/mwgui/draganddrop.cpp @@ -20,10 +20,10 @@ namespace MWGui DragAndDrop::DragAndDrop() : mIsOnDragAndDrop(false) - , mDraggedWidget(NULL) - , mSourceModel(NULL) - , mSourceView(NULL) - , mSourceSortModel(NULL) + , mDraggedWidget(nullptr) + , mSourceModel(nullptr) + , mSourceView(nullptr) + , mSourceSortModel(nullptr) , mDraggedCount(0) { } diff --git a/apps/openmw/mwgui/enchantingdialog.cpp b/apps/openmw/mwgui/enchantingdialog.cpp index 039377dee..98980e339 100644 --- a/apps/openmw/mwgui/enchantingdialog.cpp +++ b/apps/openmw/mwgui/enchantingdialog.cpp @@ -28,7 +28,7 @@ namespace MWGui EnchantingDialog::EnchantingDialog() : WindowBase("openmw_enchanting_dialog.layout") , EffectEditorBase(EffectEditorBase::Enchanting) - , mItemSelectionDialog(NULL) + , mItemSelectionDialog(nullptr) { getWidget(mName, "NameEdit"); getWidget(mCancelButton, "CancelButton"); diff --git a/apps/openmw/mwgui/exposedwindow.cpp b/apps/openmw/mwgui/exposedwindow.cpp index 150a8c893..1a0484e72 100644 --- a/apps/openmw/mwgui/exposedwindow.cpp +++ b/apps/openmw/mwgui/exposedwindow.cpp @@ -14,7 +14,7 @@ namespace MWGui if (widgets.empty()) { MYGUI_ASSERT( ! _throw, "widget name '" << _name << "' not found in skin of layout '" << getName() << "'"); - return NULL; + return nullptr; } else { diff --git a/apps/openmw/mwgui/formatting.cpp b/apps/openmw/mwgui/formatting.cpp index fd5ed4faa..78359608e 100644 --- a/apps/openmw/mwgui/formatting.cpp +++ b/apps/openmw/mwgui/formatting.cpp @@ -27,7 +27,7 @@ namespace MWGui BookTextParser::BookTextParser(const std::string & text) : mIndex(0), mText(text), mIgnoreNewlineTags(true), mIgnoreLineEndings(true), mClosingTag(false) { - MWScript::InterpreterContext interpreterContext(NULL, MWWorld::Ptr()); // empty arguments, because there is no locals or actor + MWScript::InterpreterContext interpreterContext(nullptr, MWWorld::Ptr()); // empty arguments, because there is no locals or actor mText = Interpreter::fixDefinesBook(mText, interpreterContext); boost::algorithm::replace_all(mText, "\r", ""); diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index 91467d490..6076c1c10 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -70,20 +70,20 @@ namespace MWGui HUD::HUD(CustomMarkerCollection &customMarkers, DragAndDrop* dragAndDrop, MWRender::LocalMap* localMapRender) : WindowBase("openmw_hud.layout") , LocalMapBase(customMarkers, localMapRender, Settings::Manager::getBool("local map hud fog of war", "Map")) - , mHealth(NULL) - , mMagicka(NULL) - , mStamina(NULL) - , mDrowning(NULL) - , mWeapImage(NULL) - , mSpellImage(NULL) - , mWeapStatus(NULL) - , mSpellStatus(NULL) - , mEffectBox(NULL) - , mMinimap(NULL) - , mCrosshair(NULL) - , mCellNameBox(NULL) - , mDrowningFrame(NULL) - , mDrowningFlash(NULL) + , mHealth(nullptr) + , mMagicka(nullptr) + , mStamina(nullptr) + , mDrowning(nullptr) + , mWeapImage(nullptr) + , mSpellImage(nullptr) + , mWeapStatus(nullptr) + , mSpellStatus(nullptr) + , mEffectBox(nullptr) + , mMinimap(nullptr) + , mCrosshair(nullptr) + , mCellNameBox(nullptr) + , mDrowningFrame(nullptr) + , mDrowningFlash(nullptr) , mHealthManaStaminaBaseLeft(0) , mWeapBoxBaseLeft(0) , mSpellBoxBaseLeft(0) @@ -247,7 +247,7 @@ namespace MWGui float mouseY = cursorPosition.top / float(viewSize.height); WorldItemModel drop (mouseX, mouseY); - mDragAndDrop->drop(&drop, NULL); + mDragAndDrop->drop(&drop, nullptr); MWBase::Environment::get().getWindowManager()->changePointer("arrow"); } diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 0d37bbff3..1877ef97d 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -60,8 +60,8 @@ namespace MWGui : WindowPinnableBase("openmw_inventory_window.layout") , mDragAndDrop(dragAndDrop) , mSelectedItem(-1) - , mSortModel(NULL) - , mTradeModel(NULL) + , mSortModel(nullptr) + , mTradeModel(nullptr) , mGuiMode(GM_Inventory) , mLastXSize(0) , mLastYSize(0) @@ -157,9 +157,9 @@ namespace MWGui void InventoryWindow::clear() { mPtr = MWWorld::Ptr(); - mTradeModel = NULL; - mSortModel = NULL; - mItemView->setModel(NULL); + mTradeModel = nullptr; + mSortModel = nullptr; + mItemView->setModel(nullptr); } void InventoryWindow::setGuiMode(GuiMode mode) @@ -296,9 +296,9 @@ namespace MWGui { mSelectedItem = index; if (mTrading) - sellItem (NULL, count); + sellItem (nullptr, count); else - dragItem (NULL, count); + dragItem (nullptr, count); } } diff --git a/apps/openmw/mwgui/itemchargeview.cpp b/apps/openmw/mwgui/itemchargeview.cpp index 3001b9ef2..10c36c73f 100644 --- a/apps/openmw/mwgui/itemchargeview.cpp +++ b/apps/openmw/mwgui/itemchargeview.cpp @@ -21,7 +21,7 @@ namespace MWGui { ItemChargeView::ItemChargeView() - : mScrollView(NULL), + : mScrollView(nullptr), mDisplayMode(DisplayMode_Health) { } @@ -36,7 +36,7 @@ namespace MWGui Base::initialiseOverride(); assignWidget(mScrollView, "ScrollView"); - if (mScrollView == NULL) + if (mScrollView == nullptr) throw std::runtime_error("Item charge view needs a scroll view"); mScrollView->setCanvasAlign(MyGUI::Align::Left | MyGUI::Align::Top); diff --git a/apps/openmw/mwgui/itemmodel.cpp b/apps/openmw/mwgui/itemmodel.cpp index e3f38a54c..c7c10e8e4 100644 --- a/apps/openmw/mwgui/itemmodel.cpp +++ b/apps/openmw/mwgui/itemmodel.cpp @@ -31,7 +31,7 @@ namespace MWGui ItemStack::ItemStack() : mType(Type_Normal) , mFlags(0) - , mCreator(NULL) + , mCreator(nullptr) , mCount(0) { } @@ -106,7 +106,7 @@ namespace MWGui ProxyItemModel::ProxyItemModel() - : mSourceModel(NULL) + : mSourceModel(nullptr) { } @@ -167,7 +167,7 @@ namespace MWGui if (mSourceModel) { delete mSourceModel; - mSourceModel = NULL; + mSourceModel = nullptr; } mSourceModel = sourceModel; diff --git a/apps/openmw/mwgui/itemselection.cpp b/apps/openmw/mwgui/itemselection.cpp index effd11d55..23f1398ea 100644 --- a/apps/openmw/mwgui/itemselection.cpp +++ b/apps/openmw/mwgui/itemselection.cpp @@ -12,8 +12,8 @@ namespace MWGui ItemSelectionDialog::ItemSelectionDialog(const std::string &label) : WindowModal("openmw_itemselection_dialog.layout") - , mSortModel(NULL) - , mModel(NULL) + , mSortModel(nullptr) + , mModel(nullptr) { getWidget(mItemView, "ItemView"); mItemView->eventItemClicked += MyGUI::newDelegate(this, &ItemSelectionDialog::onSelectedItem); diff --git a/apps/openmw/mwgui/itemview.cpp b/apps/openmw/mwgui/itemview.cpp index 2cdfcada4..94dcc77c5 100644 --- a/apps/openmw/mwgui/itemview.cpp +++ b/apps/openmw/mwgui/itemview.cpp @@ -18,8 +18,8 @@ namespace MWGui { ItemView::ItemView() - : mModel(NULL) - , mScrollView(NULL) + : mModel(nullptr) + , mScrollView(nullptr) { } @@ -44,7 +44,7 @@ void ItemView::initialiseOverride() Base::initialiseOverride(); assignWidget(mScrollView, "ScrollView"); - if (mScrollView == NULL) + if (mScrollView == nullptr) throw std::runtime_error("Item view needs a scroll view"); mScrollView->setCanvasAlign(MyGUI::Align::Left | MyGUI::Align::Top); diff --git a/apps/openmw/mwgui/itemwidget.cpp b/apps/openmw/mwgui/itemwidget.cpp index 6b5be0314..223bced4f 100644 --- a/apps/openmw/mwgui/itemwidget.cpp +++ b/apps/openmw/mwgui/itemwidget.cpp @@ -32,10 +32,10 @@ namespace MWGui { ItemWidget::ItemWidget() - : mItem(NULL) - , mItemShadow(NULL) - , mFrame(NULL) - , mText(NULL) + : mItem(nullptr) + , mItemShadow(nullptr) + , mFrame(nullptr) + , mText(nullptr) { } diff --git a/apps/openmw/mwgui/journalviewmodel.cpp b/apps/openmw/mwgui/journalviewmodel.cpp index 63b48eab1..3621656bc 100644 --- a/apps/openmw/mwgui/journalviewmodel.cpp +++ b/apps/openmw/mwgui/journalviewmodel.cpp @@ -39,7 +39,7 @@ struct JournalViewModelImpl : JournalViewModel static Utf8Span toUtf8Span (std::string const & str) { if (str.size () == 0) - return Utf8Span (Utf8Point (NULL), Utf8Point (NULL)); + return Utf8Span (Utf8Point (nullptr), Utf8Point (nullptr)); Utf8Point point = reinterpret_cast (str.c_str ()); diff --git a/apps/openmw/mwgui/loadingscreen.cpp b/apps/openmw/mwgui/loadingscreen.cpp index be3d477e1..38ab70d54 100644 --- a/apps/openmw/mwgui/loadingscreen.cpp +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -140,7 +140,7 @@ namespace MWGui // Callback removes itself when done if (renderInfo.getCurrentCamera()) - renderInfo.getCurrentCamera()->setInitialDrawCallback(NULL); + renderInfo.getCurrentCamera()->setInitialDrawCallback(nullptr); } private: @@ -208,7 +208,7 @@ namespace MWGui else mImportantLabel = false; // label was already shown on loading screen - mViewer->getSceneData()->setComputeBoundingSphereCallback(NULL); + mViewer->getSceneData()->setComputeBoundingSphereCallback(nullptr); mViewer->getSceneData()->dirtyBound(); //std::cout << "loading took " << mTimer.time_m() - mLoadingOnTime << std::endl; diff --git a/apps/openmw/mwgui/mainmenu.cpp b/apps/openmw/mwgui/mainmenu.cpp index 5017b8893..1b9e024ba 100644 --- a/apps/openmw/mwgui/mainmenu.cpp +++ b/apps/openmw/mwgui/mainmenu.cpp @@ -25,10 +25,10 @@ namespace MWGui : WindowBase("openmw_mainmenu.layout") , mWidth (w), mHeight (h) , mVFS(vfs), mButtonBox(0) - , mBackground(NULL) - , mVideoBackground(NULL) - , mVideo(NULL) - , mSaveGameDialog(NULL) + , mBackground(nullptr) + , mVideoBackground(nullptr) + , mVideo(nullptr) + , mSaveGameDialog(nullptr) { getWidget(mVersionText, "VersionText"); mVersionText->setCaption(versionDescription); @@ -147,13 +147,13 @@ namespace MWGui if (mVideo && !show) { MyGUI::Gui::getInstance().destroyWidget(mVideoBackground); - mVideoBackground = NULL; - mVideo = NULL; + mVideoBackground = nullptr; + mVideo = nullptr; } if (mBackground && !show) { MyGUI::Gui::getInstance().destroyWidget(mBackground); - mBackground = NULL; + mBackground = nullptr; } if (!show) diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index 2c8ad0565..b9b59965d 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -161,8 +161,8 @@ namespace MWGui , mCurX(0) , mCurY(0) , mInterior(false) - , mLocalMap(NULL) - , mCompass(NULL) + , mLocalMap(nullptr) + , mCompass(nullptr) , mChanged(true) , mFogOfWarToggled(true) , mFogOfWarEnabled(fogOfWarEnabled) @@ -388,7 +388,7 @@ namespace MWGui box->getSubWidgetMain()->_setUVSet(MyGUI::FloatRect(0.f, 0.f, 1.f, 1.f)); } else - box->setRenderItemTexture(NULL); + box->setRenderItemTexture(nullptr); } } mMapTextures.swap(textures); @@ -598,7 +598,7 @@ namespace MWGui addDetectionMarkers(MWBase::World::Detect_Enchantment); // Add marker for the spot marked with Mark magic effect - MWWorld::CellStore* markedCell = NULL; + MWWorld::CellStore* markedCell = nullptr; ESM::Position markedPosition; MWBase::Environment::get().getWorld()->getPlayer().getMarkedPosition(markedCell, markedPosition); if (markedCell && markedCell->isExterior() == !mInterior @@ -627,11 +627,11 @@ namespace MWGui , LocalMapBase(customMarkers, localMapRender) , NoDrop(drag, mMainWidget) , mGlobalMap(0) - , mGlobalMapImage(NULL) - , mGlobalMapOverlay(NULL) + , mGlobalMapImage(nullptr) + , mGlobalMapOverlay(nullptr) , mGlobal(Settings::Manager::getBool("global", "Map")) - , mEventBoxGlobal(NULL) - , mEventBoxLocal(NULL) + , mEventBoxGlobal(nullptr) + , mEventBoxLocal(nullptr) , mGlobalMapRender(new MWRender::GlobalMap(localMapRender->getRoot(), workQueue)) , mEditNoteDialog() { @@ -872,7 +872,7 @@ namespace MWGui if (!destNotes.empty()) { - MarkerUserData data (NULL); + MarkerUserData data (nullptr); data.notes = destNotes; data.caption = markerWidget->getUserString("Caption_TextOneLine"); markerWidget->setUserData(data); diff --git a/apps/openmw/mwgui/messagebox.cpp b/apps/openmw/mwgui/messagebox.cpp index 2fbce97d4..e83c4b238 100644 --- a/apps/openmw/mwgui/messagebox.cpp +++ b/apps/openmw/mwgui/messagebox.cpp @@ -20,8 +20,8 @@ namespace MWGui MessageBoxManager::MessageBoxManager (float timePerChar) { - mInterMessageBoxe = NULL; - mStaticMessageBox = NULL; + mInterMessageBoxe = nullptr; + mStaticMessageBox = nullptr; mLastButtonPressed = -1; mMessageBoxSpeed = timePerChar; } @@ -42,14 +42,14 @@ namespace MWGui mInterMessageBoxe->setVisible(false); delete mInterMessageBoxe; - mInterMessageBoxe = NULL; + mInterMessageBoxe = nullptr; } std::vector::iterator it(mMessageBoxes.begin()); for (; it != mMessageBoxes.end(); ++it) { if (*it == mStaticMessageBox) - mStaticMessageBox = NULL; + mStaticMessageBox = nullptr; delete *it; } mMessageBoxes.clear(); @@ -81,11 +81,11 @@ namespace MWGui ++it; } - if(mInterMessageBoxe != NULL && mInterMessageBoxe->mMarkedToDelete) { + if(mInterMessageBoxe != nullptr && mInterMessageBoxe->mMarkedToDelete) { mLastButtonPressed = mInterMessageBoxe->readPressedButton(); mInterMessageBoxe->setVisible(false); delete mInterMessageBoxe; - mInterMessageBoxe = NULL; + mInterMessageBoxe = nullptr; MWBase::Environment::get().getInputManager()->changeInputMode( MWBase::Environment::get().getWindowManager()->isGuiMode()); } @@ -119,17 +119,17 @@ namespace MWGui void MessageBoxManager::removeStaticMessageBox () { removeMessageBox(mStaticMessageBox); - mStaticMessageBox = NULL; + mStaticMessageBox = nullptr; } bool MessageBoxManager::createInteractiveMessageBox (const std::string& message, const std::vector& buttons) { - if (mInterMessageBoxe != NULL) + if (mInterMessageBoxe != nullptr) { Log(Debug::Warning) << "Warning: replacing an interactive message box that was not answered yet"; mInterMessageBoxe->setVisible(false); delete mInterMessageBoxe; - mInterMessageBoxe = NULL; + mInterMessageBoxe = nullptr; } mInterMessageBoxe = new InteractiveMessageBox(*this, message, buttons); @@ -140,7 +140,7 @@ namespace MWGui bool MessageBoxManager::isInteractiveMessageBox () { - return mInterMessageBoxe != NULL; + return mInterMessageBoxe != nullptr; } @@ -373,7 +373,7 @@ namespace MWGui } } } - return NULL; + return nullptr; } void InteractiveMessageBox::mousePressed (MyGUI::Widget* pressed) diff --git a/apps/openmw/mwgui/race.cpp b/apps/openmw/mwgui/race.cpp index ee058e02e..be0dff660 100644 --- a/apps/openmw/mwgui/race.cpp +++ b/apps/openmw/mwgui/race.cpp @@ -129,10 +129,10 @@ namespace MWGui updateSkills(); updateSpellPowers(); - mPreviewImage->setRenderItemTexture(NULL); + mPreviewImage->setRenderItemTexture(nullptr); - mPreview.reset(NULL); - mPreviewTexture.reset(NULL); + mPreview.reset(nullptr); + mPreviewTexture.reset(nullptr); mPreview.reset(new MWRender::RaceSelectionPreview(mParent, mResourceSystem)); mPreview->rebuild(); @@ -190,10 +190,10 @@ namespace MWGui { WindowModal::onClose(); - mPreviewImage->setRenderItemTexture(NULL); + mPreviewImage->setRenderItemTexture(nullptr); - mPreviewTexture.reset(NULL); - mPreview.reset(NULL); + mPreviewTexture.reset(nullptr); + mPreview.reset(nullptr); } // widget controls diff --git a/apps/openmw/mwgui/recharge.cpp b/apps/openmw/mwgui/recharge.cpp index a6ed16bd4..93047956a 100644 --- a/apps/openmw/mwgui/recharge.cpp +++ b/apps/openmw/mwgui/recharge.cpp @@ -31,7 +31,7 @@ namespace MWGui Recharge::Recharge() : WindowBase("openmw_recharge_dialog.layout") - , mItemSelectionDialog(NULL) + , mItemSelectionDialog(nullptr) { getWidget(mBox, "Box"); getWidget(mGemBox, "GemBox"); @@ -90,7 +90,7 @@ void Recharge::updateView() mBox->update(); Gui::Box* box = dynamic_cast(mMainWidget); - if (box == NULL) + if (box == nullptr) throw std::runtime_error("main widget must be a box"); box->notifyChildrenSizeChanged(); diff --git a/apps/openmw/mwgui/repair.cpp b/apps/openmw/mwgui/repair.cpp index 11a8aece2..ea79e0326 100644 --- a/apps/openmw/mwgui/repair.cpp +++ b/apps/openmw/mwgui/repair.cpp @@ -27,7 +27,7 @@ namespace MWGui Repair::Repair() : WindowBase("openmw_repair.layout") - , mItemSelectionDialog(NULL) + , mItemSelectionDialog(nullptr) { getWidget(mRepairBox, "RepairBox"); getWidget(mToolBox, "ToolBox"); @@ -99,7 +99,7 @@ void Repair::updateRepairView() mRepairBox->update(); Gui::Box* box = dynamic_cast(mMainWidget); - if (box == NULL) + if (box == nullptr) throw std::runtime_error("main widget must be a box"); box->notifyChildrenSizeChanged(); diff --git a/apps/openmw/mwgui/review.cpp b/apps/openmw/mwgui/review.cpp index b59b1582c..f2f1cf892 100644 --- a/apps/openmw/mwgui/review.cpp +++ b/apps/openmw/mwgui/review.cpp @@ -379,7 +379,7 @@ namespace MWGui // starting spells std::vector spells; - const ESM::Race* race = NULL; + const ESM::Race* race = nullptr; if (!mRaceId.empty()) race = MWBase::Environment::get().getWorld()->getStore().get().find(mRaceId); diff --git a/apps/openmw/mwgui/savegamedialog.cpp b/apps/openmw/mwgui/savegamedialog.cpp index 3264e5e33..2027210d7 100644 --- a/apps/openmw/mwgui/savegamedialog.cpp +++ b/apps/openmw/mwgui/savegamedialog.cpp @@ -37,8 +37,8 @@ namespace MWGui SaveGameDialog::SaveGameDialog() : WindowModal("openmw_savegame_dialog.layout") , mSaving(true) - , mCurrentCharacter(NULL) - , mCurrentSlot(NULL) + , mCurrentCharacter(nullptr) + , mCurrentSlot(nullptr) { getWidget(mScreenshot, "Screenshot"); getWidget(mCharacterSelection, "SelectCharacter"); @@ -99,7 +99,7 @@ namespace MWGui if (mSaveList->getItemCount() == 0) { size_t previousIndex = mCharacterSelection->getIndexSelected(); - mCurrentCharacter = NULL; + mCurrentCharacter = nullptr; mCharacterSelection->removeItemAt(previousIndex); if (mCharacterSelection->getItemCount()) { @@ -146,8 +146,8 @@ namespace MWGui mCharacterSelection->setCaption(""); mCharacterSelection->removeAllItems(); - mCurrentCharacter = NULL; - mCurrentSlot = NULL; + mCurrentCharacter = nullptr; + mCurrentSlot = nullptr; mSaveList->removeAllItems(); onSlotSelected(mSaveList, MyGUI::ITEM_NONE); @@ -250,12 +250,12 @@ namespace MWGui void SaveGameDialog::accept(bool reallySure) { // Remove for MyGUI 3.2.2 - MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(NULL); + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(nullptr); if (mSaving) { // If overwriting an existing slot, ask for confirmation first - if (mCurrentSlot != NULL && !reallySure) + if (mCurrentSlot != nullptr && !reallySure) { ConfirmationDialog* dialog = MWBase::Environment::get().getWindowManager()->getConfirmationDialog(); dialog->askForConfirmation("#{sMessage4}"); @@ -318,7 +318,7 @@ namespace MWGui MWBase::StateManager* mgr = MWBase::Environment::get().getStateManager(); unsigned int i=0; - const MWState::Character* character = NULL; + const MWState::Character* character = nullptr; for (MWBase::StateManager::CharacterIterator it = mgr->characterBegin(); it != mgr->characterEnd(); ++it, ++i) { if (i == pos) @@ -327,7 +327,7 @@ namespace MWGui assert(character && "Can't find selected character"); mCurrentCharacter = character; - mCurrentSlot = NULL; + mCurrentSlot = nullptr; fillSaveList(); } @@ -379,7 +379,7 @@ namespace MWGui if (pos == MyGUI::ITEM_NONE || !mCurrentCharacter) { - mCurrentSlot = NULL; + mCurrentSlot = nullptr; mInfoText->setCaption(""); mScreenshot->setImageTexture(""); return; @@ -388,7 +388,7 @@ namespace MWGui if (mSaving) mSaveNameEdit->setCaption(sender->getItemNameAt(pos)); - mCurrentSlot = NULL; + mCurrentSlot = nullptr; unsigned int i=0; for (MWState::Character::SlotIterator it = mCurrentCharacter->begin(); it != mCurrentCharacter->end(); ++it, ++i) { @@ -404,7 +404,7 @@ namespace MWGui timeinfo = localtime(&time); // Use system/environment locale settings for datetime formatting - char* oldLctime = setlocale(LC_TIME, NULL); + char* oldLctime = setlocale(LC_TIME, nullptr); setlocale(LC_TIME, ""); const int size=1024; diff --git a/apps/openmw/mwgui/spellcreationdialog.cpp b/apps/openmw/mwgui/spellcreationdialog.cpp index 206283133..46d8b38ec 100644 --- a/apps/openmw/mwgui/spellcreationdialog.cpp +++ b/apps/openmw/mwgui/spellcreationdialog.cpp @@ -55,7 +55,7 @@ namespace MWGui EditEffectDialog::EditEffectDialog() : WindowModal("openmw_edit_effect.layout") , mEditing(false) - , mMagicEffect(NULL) + , mMagicEffect(nullptr) , mConstantEffect(false) { init(mEffect); @@ -481,7 +481,7 @@ namespace MWGui mPriceLabel->setCaption(MyGUI::utility::toString(int(price))); - float chance = MWMechanics::calcSpellBaseSuccessChance(&mSpell, MWMechanics::getPlayer(), NULL); + float chance = MWMechanics::calcSpellBaseSuccessChance(&mSpell, MWMechanics::getPlayer(), nullptr); int intChance = std::min(100, int(chance)); mSuccessChance->setCaption(MyGUI::utility::toString(intChance)); @@ -491,11 +491,11 @@ namespace MWGui EffectEditorBase::EffectEditorBase(Type type) - : mAvailableEffectsList(NULL) - , mUsedEffectsView(NULL) + : mAvailableEffectsList(nullptr) + , mUsedEffectsView(nullptr) , mAddEffectDialog() - , mSelectAttributeDialog(NULL) - , mSelectSkillDialog(NULL) + , mSelectAttributeDialog(nullptr) + , mSelectSkillDialog(nullptr) , mSelectedEffect(0) , mSelectedKnownEffectId(0) , mConstantEffect(false) diff --git a/apps/openmw/mwgui/spellmodel.cpp b/apps/openmw/mwgui/spellmodel.cpp index 0933737ca..6dadebca2 100644 --- a/apps/openmw/mwgui/spellmodel.cpp +++ b/apps/openmw/mwgui/spellmodel.cpp @@ -71,7 +71,7 @@ namespace MWGui { newSpell.mType = Spell::Type_Spell; std::string cost = std::to_string(spell->mData.mCost); - std::string chance = std::to_string(int(MWMechanics::getSpellSuccessChance(spell, mActor, NULL, true, true))); + std::string chance = std::to_string(int(MWMechanics::getSpellSuccessChance(spell, mActor, nullptr, true, true))); newSpell.mCostColumn = cost + "/" + chance; } else diff --git a/apps/openmw/mwgui/spellview.cpp b/apps/openmw/mwgui/spellview.cpp index 702c2f840..879ce471f 100644 --- a/apps/openmw/mwgui/spellview.cpp +++ b/apps/openmw/mwgui/spellview.cpp @@ -24,7 +24,7 @@ namespace MWGui } SpellView::SpellView() - : mScrollView(NULL) + : mScrollView(nullptr) , mShowCostColumn(true) , mHighlightSelected(true) { @@ -35,7 +35,7 @@ namespace MWGui Base::initialiseOverride(); assignWidget(mScrollView, "ScrollView"); - if (mScrollView == NULL) + if (mScrollView == nullptr) throw std::runtime_error("Item view needs a scroll view"); mScrollView->setCanvasAlign(MyGUI::Align::Left | MyGUI::Align::Top); @@ -131,7 +131,7 @@ namespace MWGui mLines.push_back(LineInfo(t, costChance, i)); } else - mLines.push_back(LineInfo(t, (MyGUI::Widget*)NULL, i)); + mLines.push_back(LineInfo(t, (MyGUI::Widget*)nullptr, i)); t->setStateSelected(spell.mSelected); } @@ -177,7 +177,7 @@ namespace MWGui { maxSpellIndexFound = spellIndex; Gui::SharedStateButton* costButton = reinterpret_cast(it->mRightWidget); - if ((costButton != NULL) && (costButton->getCaption() != spell.mCostColumn)) + if ((costButton != nullptr) && (costButton->getCaption() != spell.mCostColumn)) { costButton->setCaption(spell.mCostColumn); } @@ -238,7 +238,7 @@ namespace MWGui MyGUI::IntCoord(0, 0, mScrollView->getWidth(), 18), MyGUI::Align::Left | MyGUI::Align::Top); separator->setNeedMouseFocus(false); - mLines.push_back(LineInfo(separator, (MyGUI::Widget*)NULL, NoSpellIndex)); + mLines.push_back(LineInfo(separator, (MyGUI::Widget*)nullptr, NoSpellIndex)); } MyGUI::TextBox* groupWidget = mScrollView->createWidget("SandBrightText", @@ -260,7 +260,7 @@ namespace MWGui mLines.push_back(LineInfo(groupWidget, groupWidget2, NoSpellIndex)); } else - mLines.push_back(LineInfo(groupWidget, (MyGUI::Widget*)NULL, NoSpellIndex)); + mLines.push_back(LineInfo(groupWidget, (MyGUI::Widget*)nullptr, NoSpellIndex)); } diff --git a/apps/openmw/mwgui/spellwindow.cpp b/apps/openmw/mwgui/spellwindow.cpp index 38de9288b..2177e9e2a 100644 --- a/apps/openmw/mwgui/spellwindow.cpp +++ b/apps/openmw/mwgui/spellwindow.cpp @@ -32,7 +32,7 @@ namespace MWGui SpellWindow::SpellWindow(DragAndDrop* drag) : WindowPinnableBase("openmw_spell_window.layout") , NoDrop(drag, mMainWidget) - , mSpellView(NULL) + , mSpellView(nullptr) , mUpdateTimer(0.0f) { mSpellIcons = new SpellIcons(); @@ -72,7 +72,7 @@ namespace MWGui // Reset the filter focus when opening the window MyGUI::Widget* focus = MyGUI::InputManager::getInstance().getKeyFocusWidget(); if (focus == mFilterEdit) - MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(NULL); + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(nullptr); updateSpells(); } diff --git a/apps/openmw/mwgui/statswindow.cpp b/apps/openmw/mwgui/statswindow.cpp index dfa029467..e58993a55 100644 --- a/apps/openmw/mwgui/statswindow.cpp +++ b/apps/openmw/mwgui/statswindow.cpp @@ -26,7 +26,7 @@ namespace MWGui StatsWindow::StatsWindow (DragAndDrop* drag) : WindowPinnableBase("openmw_stats_window.layout") , NoDrop(drag, mMainWidget) - , mSkillView(NULL) + , mSkillView(nullptr) , mMajorSkills() , mMinorSkills() , mMiscSkills() @@ -68,7 +68,7 @@ namespace MWGui for (int i = 0; i < ESM::Skill::Length; ++i) { mSkillValues.insert(std::make_pair(i, MWMechanics::SkillValue())); - mSkillWidgetMap.insert(std::make_pair(i, std::make_pair((MyGUI::TextBox*)NULL, (MyGUI::TextBox*)NULL))); + mSkillWidgetMap.insert(std::make_pair(i, std::make_pair((MyGUI::TextBox*)nullptr, (MyGUI::TextBox*)nullptr))); } MyGUI::Window* t = mMainWidget->castType(); diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index 726c72b99..4404b2b1a 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -50,8 +50,8 @@ namespace MWGui TradeWindow::TradeWindow() : WindowBase("openmw_trade_window.layout") - , mSortModel(NULL) - , mTradeModel(NULL) + , mSortModel(nullptr) + , mTradeModel(nullptr) , mItemToSell(-1) , mCurrentBalance(0) , mCurrentMerchantOffer(0) @@ -205,7 +205,7 @@ namespace MWGui else { mItemToSell = mSortModel->mapToSource(index); - sellItem (NULL, count); + sellItem (nullptr, count); } } @@ -514,8 +514,8 @@ namespace MWGui void TradeWindow::resetReference() { ReferenceInterface::resetReference(); - mItemView->setModel(NULL); - mTradeModel = NULL; - mSortModel = NULL; + mItemView->setModel(nullptr); + mTradeModel = nullptr; + mSortModel = nullptr; } } diff --git a/apps/openmw/mwgui/videowidget.cpp b/apps/openmw/mwgui/videowidget.cpp index 28432b811..5dec6e48a 100644 --- a/apps/openmw/mwgui/videowidget.cpp +++ b/apps/openmw/mwgui/videowidget.cpp @@ -16,7 +16,7 @@ namespace MWGui { VideoWidget::VideoWidget() - : mVFS(NULL) + : mVFS(nullptr) { mPlayer.reset(new Video::VideoPlayer()); setNeedKeyFocus(true); diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index db92b355c..037fcb19b 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -281,7 +281,7 @@ namespace MWGui mSleeping = canRest; Gui::Box* box = dynamic_cast(mMainWidget); - if (box == NULL) + if (box == nullptr) throw std::runtime_error("main widget must be a box"); box->notifyChildrenSizeChanged(); center(); diff --git a/apps/openmw/mwgui/widgets.cpp b/apps/openmw/mwgui/widgets.cpp index 024a91fc6..c3bc1ec19 100644 --- a/apps/openmw/mwgui/widgets.cpp +++ b/apps/openmw/mwgui/widgets.cpp @@ -23,8 +23,8 @@ namespace MWGui MWSkill::MWSkill() : mSkillId(ESM::Skill::Length) - , mSkillNameWidget(NULL) - , mSkillValueWidget(NULL) + , mSkillNameWidget(nullptr) + , mSkillValueWidget(nullptr) { } @@ -114,8 +114,8 @@ namespace MWGui MWAttribute::MWAttribute() : mId(-1) - , mAttributeNameWidget(NULL) - , mAttributeValueWidget(NULL) + , mAttributeNameWidget(nullptr) + , mAttributeValueWidget(nullptr) { } @@ -204,7 +204,7 @@ namespace MWGui /* MWSpell */ MWSpell::MWSpell() - : mSpellNameWidget(NULL) + : mSpellNameWidget(nullptr) { } @@ -286,7 +286,7 @@ namespace MWGui { // We don't know the width of all the elements beforehand, so we do it in // 2 steps: first, create all widgets and check their width.... - MWSpellEffectPtr effect = NULL; + MWSpellEffectPtr effect = nullptr; int maxwidth = coord.width; for (SpellEffectList::iterator it=mEffectList.begin(); @@ -359,8 +359,8 @@ namespace MWGui /* MWSpellEffect */ MWSpellEffect::MWSpellEffect() - : mImageWidget(NULL) - , mTextWidget(NULL) + : mImageWidget(nullptr) + , mTextWidget(nullptr) , mRequestedWidth(0) { } @@ -489,9 +489,9 @@ namespace MWGui MWDynamicStat::MWDynamicStat() : mValue(0) , mMax(1) - , mTextWidget(NULL) - , mBarWidget(NULL) - , mBarTextWidget(NULL) + , mTextWidget(nullptr) + , mBarWidget(nullptr) + , mBarTextWidget(nullptr) { } diff --git a/apps/openmw/mwgui/windowbase.cpp b/apps/openmw/mwgui/windowbase.cpp index 93440a50a..86c780325 100644 --- a/apps/openmw/mwgui/windowbase.cpp +++ b/apps/openmw/mwgui/windowbase.cpp @@ -33,11 +33,11 @@ void WindowBase::setVisible(bool visible) if (!visible) { MyGUI::Widget* keyFocus = MyGUI::InputManager::getInstance().getKeyFocusWidget(); - while (keyFocus != mMainWidget && keyFocus != NULL) + while (keyFocus != mMainWidget && keyFocus != nullptr) keyFocus = keyFocus->getParent(); if (keyFocus == mMainWidget) - MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(NULL); + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(nullptr); } } diff --git a/apps/openmw/mwgui/windowbase.hpp b/apps/openmw/mwgui/windowbase.hpp index fde1f2ac9..7d8fb2f1e 100644 --- a/apps/openmw/mwgui/windowbase.hpp +++ b/apps/openmw/mwgui/windowbase.hpp @@ -23,7 +23,7 @@ namespace MWGui public: WindowBase(const std::string& parLayout); - virtual MyGUI::Widget* getDefaultKeyFocus() { return NULL; } + virtual MyGUI::Widget* getDefaultKeyFocus() { return nullptr; } // Events typedef MyGUI::delegates::CMultiDelegate1 EventHandle_WindowBase; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 7fca0058f..e4515fdc3 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -134,44 +134,44 @@ namespace MWGui osgViewer::Viewer* viewer, osg::Group* guiRoot, Resource::ResourceSystem* resourceSystem, SceneUtil::WorkQueue* workQueue, const std::string& logpath, const std::string& resourcePath, bool consoleOnlyScripts, Translation::Storage& translationDataStorage, ToUTF8::FromType encoding, bool exportFonts, const std::map& fallbackMap, const std::string& versionDescription, const std::string& userDataPath) - : mStore(NULL) + : mStore(nullptr) , mResourceSystem(resourceSystem) , mWorkQueue(workQueue) , mViewer(viewer) , mConsoleOnlyScripts(consoleOnlyScripts) , mCurrentModals() - , mHud(NULL) - , mMap(NULL) - , mLocalMapRender(NULL) - , mToolTips(NULL) - , mStatsWindow(NULL) - , mMessageBoxManager(NULL) - , mConsole(NULL) - , mDialogueWindow(NULL) - , mDragAndDrop(NULL) - , mInventoryWindow(NULL) - , mScrollWindow(NULL) - , mBookWindow(NULL) - , mCountDialog(NULL) - , mTradeWindow(NULL) - , mSettingsWindow(NULL) - , mConfirmationDialog(NULL) - , mSpellWindow(NULL) - , mQuickKeysMenu(NULL) - , mLoadingScreen(NULL) - , mWaitDialog(NULL) - , mSoulgemDialog(NULL) - , mVideoBackground(NULL) - , mVideoWidget(NULL) - , mWerewolfFader(NULL) - , mBlindnessFader(NULL) - , mHitFader(NULL) - , mScreenFader(NULL) - , mDebugWindow(NULL) - , mJailScreen(NULL) + , mHud(nullptr) + , mMap(nullptr) + , mLocalMapRender(nullptr) + , mToolTips(nullptr) + , mStatsWindow(nullptr) + , mMessageBoxManager(nullptr) + , mConsole(nullptr) + , mDialogueWindow(nullptr) + , mDragAndDrop(nullptr) + , mInventoryWindow(nullptr) + , mScrollWindow(nullptr) + , mBookWindow(nullptr) + , mCountDialog(nullptr) + , mTradeWindow(nullptr) + , mSettingsWindow(nullptr) + , mConfirmationDialog(nullptr) + , mSpellWindow(nullptr) + , mQuickKeysMenu(nullptr) + , mLoadingScreen(nullptr) + , mWaitDialog(nullptr) + , mSoulgemDialog(nullptr) + , mVideoBackground(nullptr) + , mVideoWidget(nullptr) + , mWerewolfFader(nullptr) + , mBlindnessFader(nullptr) + , mHitFader(nullptr) + , mScreenFader(nullptr) + , mDebugWindow(nullptr) + , mJailScreen(nullptr) , mTranslationDataStorage (translationDataStorage) - , mCharGen(NULL) - , mInputBlocker(NULL) + , mCharGen(nullptr) + , mInputBlocker(nullptr) , mCrosshairEnabled(Settings::Manager::getBool ("crosshair", "HUD")) , mSubtitlesEnabled(Settings::Manager::getBool ("subtitles", "GUI")) , mHitFaderEnabled(Settings::Manager::getBool ("hit fader", "GUI")) @@ -185,9 +185,9 @@ namespace MWGui , mPlayerMajorSkills() , mPlayerMinorSkills() , mPlayerSkillValues() - , mGui(NULL) + , mGui(nullptr) , mGuiModes() - , mCursorManager(NULL) + , mCursorManager(nullptr) , mGarbageDialogs() , mShown(GW_ALL) , mForceHidden(GW_None) @@ -704,7 +704,7 @@ namespace MWGui setCursorVisible(!gameMode); if (gameMode) - setKeyFocusWidget (NULL); + setKeyFocusWidget (nullptr); // Icons of forced hidden windows are displayed setMinimapVisibility((mAllowed & GW_Map) && (!mMap->pinned() || (mForceHidden & GW_Map))); @@ -1651,7 +1651,7 @@ namespace MWGui // Remove this method for MyGUI 3.2.2 void WindowManager::setKeyFocusWidget(MyGUI::Widget *widget) { - if (widget == NULL) + if (widget == nullptr) MyGUI::InputManager::getInstance().resetKeyFocusWidget(); else MyGUI::InputManager::getInstance().setKeyFocusWidget(widget); @@ -1913,7 +1913,7 @@ namespace MWGui } if (mCurrentModals.empty()) { - mKeyboardNavigation->setModalWindow(NULL); + mKeyboardNavigation->setModalWindow(nullptr); mKeyboardNavigation->restoreFocus(getMode()); } else diff --git a/apps/openmw/mwgui/windowpinnablebase.cpp b/apps/openmw/mwgui/windowpinnablebase.cpp index a6984b5a4..271d4e3a8 100644 --- a/apps/openmw/mwgui/windowpinnablebase.cpp +++ b/apps/openmw/mwgui/windowpinnablebase.cpp @@ -14,7 +14,7 @@ namespace MWGui mPinButton->eventMouseButtonPressed += MyGUI::newDelegate(this, &WindowPinnableBase::onPinButtonPressed); - MyGUI::Button* button = NULL; + MyGUI::Button* button = nullptr; MyGUI::VectorWidgetPtr widgets = window->getSkinWidgetsByName("Action"); for (MyGUI::VectorWidgetPtr::iterator it = widgets.begin(); it != widgets.end(); ++it) { diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 101b4f2f7..b0a98bafc 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -46,9 +46,9 @@ namespace MWInput , mScreenCaptureHandler(screenCaptureHandler) , mScreenCaptureOperation(screenCaptureOperation) , mJoystickLastUsed(false) - , mPlayer(NULL) - , mInputManager(NULL) - , mVideoWrapper(NULL) + , mPlayer(nullptr) + , mInputManager(nullptr) + , mVideoWrapper(nullptr) , mUserFile(userFile) , mDragDrop(false) , mGrabCursor (Settings::Manager::getBool("grab cursor", "Input")) @@ -84,7 +84,7 @@ namespace MWInput Settings::Manager::getFloat("contrast", "Video")); std::string file = userFileExists ? userFile : ""; - mInputBinder = new ICS::InputControlSystem(file, true, this, NULL, A_Last); + mInputBinder = new ICS::InputControlSystem(file, true, this, nullptr, A_Last); loadKeyDefaults(); loadControllerDefaults(); diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index e18ba4119..2a68591a8 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -1420,7 +1420,7 @@ namespace MWMechanics iter->second->getCharacterController()->updateContinuousVfx(); // Animation/movement update - CharacterController* playerCharacter = NULL; + CharacterController* playerCharacter = nullptr; for(PtrActorMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter) { const float animationDistance = aiProcessingDistance + 400; // Slightly larger than AI distance so there is time to switch back to the idle animation. @@ -1987,7 +1987,7 @@ namespace MWMechanics for (; it != mActors.end(); ++it) { delete it->second; - it->second = NULL; + it->second = nullptr; } mActors.clear(); mDeathCount.clear(); diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index 9824347e3..8f9545f99 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -586,7 +586,7 @@ std::string chooseBestAttack(const ESM::Weapon* weapon) { std::string attackType; - if (weapon != NULL) + if (weapon != nullptr) { //the more damage attackType deals the more probability it has int slash = (weapon->mData.mSlash[0] + weapon->mData.mSlash[1])/2; diff --git a/apps/openmw/mwmechanics/aicombat.hpp b/apps/openmw/mwmechanics/aicombat.hpp index 88feba481..f89e71678 100644 --- a/apps/openmw/mwmechanics/aicombat.hpp +++ b/apps/openmw/mwmechanics/aicombat.hpp @@ -64,7 +64,7 @@ namespace MWMechanics mAttackRange(0.0f), mCombatMove(false), mLastTargetPos(0,0,0), - mCell(NULL), + mCell(nullptr), mCurrentAction(), mActionCooldown(0.0f), mStrength(), diff --git a/apps/openmw/mwmechanics/aicombataction.cpp b/apps/openmw/mwmechanics/aicombataction.cpp index 6fffff637..804e0dd05 100644 --- a/apps/openmw/mwmechanics/aicombataction.cpp +++ b/apps/openmw/mwmechanics/aicombataction.cpp @@ -138,7 +138,7 @@ namespace MWMechanics const ESM::Weapon* ActionWeapon::getWeapon() const { if (mWeapon.isEmpty()) - return NULL; + return nullptr; return mWeapon.get()->mBase; } diff --git a/apps/openmw/mwmechanics/aicombataction.hpp b/apps/openmw/mwmechanics/aicombataction.hpp index 466ae2dc4..cf7dc78fd 100644 --- a/apps/openmw/mwmechanics/aicombataction.hpp +++ b/apps/openmw/mwmechanics/aicombataction.hpp @@ -17,7 +17,7 @@ namespace MWMechanics virtual void prepare(const MWWorld::Ptr& actor) = 0; virtual float getCombatRange (bool& isRanged) const = 0; virtual float getActionCooldown() { return 0.f; } - virtual const ESM::Weapon* getWeapon() const { return NULL; }; + virtual const ESM::Weapon* getWeapon() const { return nullptr; }; virtual bool isAttackingOrSpell() const { return true; } virtual bool isFleeing() const { return false; } }; diff --git a/apps/openmw/mwmechanics/aipackage.cpp b/apps/openmw/mwmechanics/aipackage.cpp index e6cca0523..9a42f191e 100644 --- a/apps/openmw/mwmechanics/aipackage.cpp +++ b/apps/openmw/mwmechanics/aipackage.cpp @@ -275,7 +275,7 @@ bool MWMechanics::AiPackage::shortcutPath(const ESM::Pathgrid::Point& startPoint static_cast(startPoint.mX), static_cast(startPoint.mY), static_cast(startPoint.mZ), static_cast(endPoint.mX), static_cast(endPoint.mY), static_cast(endPoint.mZ)); - if (destInLOS != NULL) *destInLOS = isPathClear; + if (destInLOS != nullptr) *destInLOS = isPathClear; if (!isPathClear) return false; diff --git a/apps/openmw/mwmechanics/aipackage.hpp b/apps/openmw/mwmechanics/aipackage.hpp index f1941ff1d..5a468ae30 100644 --- a/apps/openmw/mwmechanics/aipackage.hpp +++ b/apps/openmw/mwmechanics/aipackage.hpp @@ -114,7 +114,7 @@ namespace MWMechanics /// Check if there aren't any obstacles along the path to make shortcut possible /// If a shortcut is possible then path will be cleared and filled with the destination point. - /// \param destInLOS If not NULL function will return ray cast check result + /// \param destInLOS If not nullptr function will return ray cast check result /// \return If can shortcut the path bool shortcutPath(const ESM::Pathgrid::Point& startPoint, const ESM::Pathgrid::Point& endPoint, const MWWorld::Ptr& actor, bool *destInLOS, bool isPathClear); diff --git a/apps/openmw/mwmechanics/aistate.hpp b/apps/openmw/mwmechanics/aistate.hpp index 19f0ecf99..40f4ab1d4 100644 --- a/apps/openmw/mwmechanics/aistate.hpp +++ b/apps/openmw/mwmechanics/aistate.hpp @@ -59,7 +59,7 @@ namespace MWMechanics bool empty() const { - return mStorage == NULL; + return mStorage == nullptr; } const std::type_info& getType() const @@ -67,16 +67,12 @@ namespace MWMechanics return typeid(mStorage); } - - DerivedClassStorage():mStorage(NULL){} + DerivedClassStorage():mStorage(nullptr){} ~DerivedClassStorage() { if(mStorage) delete mStorage; } - - - }; diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index 4a0811f50..479ed4869 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -77,7 +77,7 @@ namespace MWMechanics mReaction(0), mSaidGreeting(Greet_None), mGreetingTimer(0), - mCell(NULL), + mCell(nullptr), mState(Wander_ChooseAction), mIsWanderingManually(false), mCanWanderAlongPathGrid(true), diff --git a/apps/openmw/mwmechanics/autocalcspell.cpp b/apps/openmw/mwmechanics/autocalcspell.cpp index 80ac14ddd..144449cf0 100644 --- a/apps/openmw/mwmechanics/autocalcspell.cpp +++ b/apps/openmw/mwmechanics/autocalcspell.cpp @@ -149,7 +149,7 @@ namespace MWMechanics float baseMagicka = fPCbaseMagickaMult * actorAttributes[ESM::Attribute::Intelligence]; bool reachedLimit = false; - const ESM::Spell* weakestSpell = NULL; + const ESM::Spell* weakestSpell = nullptr; int minCost = std::numeric_limits::max(); std::vector selectedSpells; diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index c4975b308..9a0ffa67d 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -931,7 +931,7 @@ CharacterController::~CharacterController() if (mAnimation) { persistAnimationState(); - mAnimation->setTextKeyListener(NULL); + mAnimation->setTextKeyListener(nullptr); } } @@ -1159,7 +1159,7 @@ bool CharacterController::updateCreatureState() if (!spellid.empty() && canCast) { - MWMechanics::CastSpell cast(mPtr, NULL, false, mCastingManualSpell); + MWMechanics::CastSpell cast(mPtr, nullptr, false, mCastingManualSpell); cast.playSpellCastingEffects(spellid); if (!mAnimation->hasAnimation("spellcast")) @@ -1463,7 +1463,7 @@ bool CharacterController::updateWeaponState(CharacterState& idle) if(!spellid.empty() && canCast) { - MWMechanics::CastSpell cast(mPtr, NULL, false, mCastingManualSpell); + MWMechanics::CastSpell cast(mPtr, nullptr, false, mCastingManualSpell); cast.playSpellCastingEffects(spellid); const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); @@ -2319,7 +2319,7 @@ void CharacterController::persistAnimationState() { anim.mLoopCount = mAnimation->getCurrentLoopCount(anim.mGroup); float complete; - mAnimation->getInfo(anim.mGroup, &complete, NULL); + mAnimation->getInfo(anim.mGroup, &complete, nullptr); anim.mTime = complete; } else @@ -2451,7 +2451,7 @@ bool CharacterController::isPersistentAnimPlaying() bool CharacterController::isAnimPlaying(const std::string &groupName) { - if(mAnimation == NULL) + if(mAnimation == nullptr) return false; return mAnimation->isPlaying(groupName); } @@ -2748,9 +2748,9 @@ void CharacterController::updateHeadTracking(float duration) if (const MWRender::Animation* anim = MWBase::Environment::get().getWorld()->getAnimation(mHeadTrackTarget)) { const osg::Node* node = anim->getNode("Head"); - if (node == NULL) + if (node == nullptr) node = anim->getNode("Bip01 Head"); - if (node != NULL) + if (node != nullptr) { nodepaths = node->getParentalNodePaths(); if (!nodepaths.empty()) diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 1db497828..f97614ef4 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -240,8 +240,8 @@ class CharacterController : public MWRender::Animation::TextKeyListener void playRandomDeath(float startpoint = 0.0f); /// choose a random animation group with \a prefix and numeric suffix - /// @param num if non-NULL, the chosen animation number will be written here - std::string chooseRandomGroup (const std::string& prefix, int* num = NULL) const; + /// @param num if non-nullptr, the chosen animation number will be written here + std::string chooseRandomGroup (const std::string& prefix, int* num = nullptr) const; bool updateCarriedLeftVisible(WeaponType weaptype) const; diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 33357b79a..6cef45e28 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -203,7 +203,7 @@ namespace MWMechanics } // F_PCStart spells - const ESM::Race* race = NULL; + const ESM::Race* race = nullptr; if (mRaceSelected) race = esmStore.get().find(player->mRace); diff --git a/apps/openmw/mwmechanics/objects.cpp b/apps/openmw/mwmechanics/objects.cpp index d8821276e..e95c0a704 100644 --- a/apps/openmw/mwmechanics/objects.cpp +++ b/apps/openmw/mwmechanics/objects.cpp @@ -20,7 +20,7 @@ Objects::~Objects() for (; it != mObjects.end();++it) { delete it->second; - it->second = NULL; + it->second = nullptr; } } diff --git a/apps/openmw/mwmechanics/obstacle.hpp b/apps/openmw/mwmechanics/obstacle.hpp index 6a84e0ef9..c55374501 100644 --- a/apps/openmw/mwmechanics/obstacle.hpp +++ b/apps/openmw/mwmechanics/obstacle.hpp @@ -16,7 +16,7 @@ namespace MWMechanics bool proximityToDoor(const MWWorld::Ptr& actor, float minDist); /// Returns door pointer within range. No guarantee is given as to which one - /** \return Pointer to the door, or NULL if none exists **/ + /** \return Pointer to the door, or empty pointer if none exists **/ const MWWorld::Ptr getNearbyDoor(const MWWorld::Ptr& actor, float minDist); class ObstacleCheck diff --git a/apps/openmw/mwmechanics/pathfinding.cpp b/apps/openmw/mwmechanics/pathfinding.cpp index b1b04f304..1da97a645 100644 --- a/apps/openmw/mwmechanics/pathfinding.cpp +++ b/apps/openmw/mwmechanics/pathfinding.cpp @@ -120,8 +120,8 @@ namespace MWMechanics } PathFinder::PathFinder() - : mPathgrid(NULL) - , mCell(NULL) + : mPathgrid(nullptr) + , mCell(nullptr) { } diff --git a/apps/openmw/mwmechanics/pathgrid.cpp b/apps/openmw/mwmechanics/pathgrid.cpp index ea4c973b7..6b5db64ea 100644 --- a/apps/openmw/mwmechanics/pathgrid.cpp +++ b/apps/openmw/mwmechanics/pathgrid.cpp @@ -50,8 +50,8 @@ namespace namespace MWMechanics { PathgridGraph::PathgridGraph(const MWWorld::CellStore *cell) - : mCell(NULL) - , mPathgrid(NULL) + : mCell(nullptr) + , mPathgrid(nullptr) , mIsExterior(0) , mGraph(0) , mIsGraphConstructed(false) diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index f1ee2520b..22631ca3f 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -242,9 +242,9 @@ namespace MWMechanics // This makes spells that are easy to cast harder to resist and vice versa float castChance = 100.f; - if (spell != NULL && !caster.isEmpty() && caster.getClass().isActor()) + if (spell != nullptr && !caster.isEmpty() && caster.getClass().isActor()) { - castChance = getSpellSuccessChance(spell, caster, NULL, false); // Uncapped casting chance + castChance = getSpellSuccessChance(spell, caster, nullptr, false); // Uncapped casting chance } if (castChance > 0) x *= 50 / castChance; @@ -737,7 +737,7 @@ namespace MWMechanics } else if (effectId == ESM::MagicEffect::Recall) { - MWWorld::CellStore* markedCell = NULL; + MWWorld::CellStore* markedCell = nullptr; ESM::Position markedPosition; MWBase::Environment::get().getWorld()->getPlayer().getMarkedPosition(markedCell, markedPosition); diff --git a/apps/openmw/mwmechanics/spellcasting.hpp b/apps/openmw/mwmechanics/spellcasting.hpp index 2844e7f23..5ac406368 100644 --- a/apps/openmw/mwmechanics/spellcasting.hpp +++ b/apps/openmw/mwmechanics/spellcasting.hpp @@ -39,8 +39,8 @@ namespace MWMechanics * @note actor can be an NPC or a creature * @return success chance from 0 to 100 (in percent), if cap=false then chance above 100 may be returned. */ - float getSpellSuccessChance (const ESM::Spell* spell, const MWWorld::Ptr& actor, int* effectiveSchool = NULL, bool cap=true, bool checkMagicka=false); - float getSpellSuccessChance (const std::string& spellId, const MWWorld::Ptr& actor, int* effectiveSchool = NULL, bool cap=true, bool checkMagicka=false); + float getSpellSuccessChance (const ESM::Spell* spell, const MWWorld::Ptr& actor, int* effectiveSchool = nullptr, bool cap=true, bool checkMagicka=false); + float getSpellSuccessChance (const std::string& spellId, const MWWorld::Ptr& actor, int* effectiveSchool = nullptr, bool cap=true, bool checkMagicka=false); int getSpellSchool(const std::string& spellId, const MWWorld::Ptr& actor); int getSpellSchool(const ESM::Spell* spell, const MWWorld::Ptr& actor); @@ -58,14 +58,14 @@ namespace MWMechanics /// @param effects Override the actor's current magicEffects. Useful if there are effects currently /// being applied (but not applied yet) that should also be considered. float getEffectResistance (short effectId, const MWWorld::Ptr& actor, const MWWorld::Ptr& caster, - const ESM::Spell* spell = NULL, const MagicEffects* effects = NULL); + const ESM::Spell* spell = nullptr, const MagicEffects* effects = nullptr); /// Get an effect multiplier for applying an effect cast by the given actor in the given spell (optional). /// @return effect multiplier from 0 to 2. (100% net resistance to 100% net weakness) /// @param effects Override the actor's current magicEffects. Useful if there are effects currently /// being applied (but not applied yet) that should also be considered. float getEffectMultiplier(short effectId, const MWWorld::Ptr& actor, const MWWorld::Ptr& caster, - const ESM::Spell* spell = NULL, const MagicEffects* effects = NULL); + const ESM::Spell* spell = nullptr, const MagicEffects* effects = nullptr); bool checkEffectTarget (int effectId, const MWWorld::Ptr& target, const MWWorld::Ptr& caster, bool castByPlayer); diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 31da729ea..363f28e70 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -810,7 +810,7 @@ namespace MWPhysics btScalar mLeastDistSqr; DeepestNotMeContactTestResultCallback(const btCollisionObject* me, const std::vector& targets, const btVector3 &origin) - : mMe(me), mTargets(targets), mOrigin(origin), mObject(NULL), mContactPoint(0,0,0), + : mMe(me), mTargets(targets), mOrigin(origin), mObject(nullptr), mContactPoint(0,0,0), mLeastDistSqr(std::numeric_limits::max()) { } @@ -873,7 +873,7 @@ namespace MWPhysics object.setCollisionShape(&shape); object.setWorldTransform(btTransform(toBullet(orient), toBullet(center))); - const btCollisionObject* me = NULL; + const btCollisionObject* me = nullptr; std::vector targetCollisionObjects; const Actor* physactor = getActor(actor); @@ -906,7 +906,7 @@ namespace MWPhysics float PhysicsSystem::getHitDistance(const osg::Vec3f &point, const MWWorld::ConstPtr &target) const { - btCollisionObject* targetCollisionObj = NULL; + btCollisionObject* targetCollisionObj = nullptr; const Actor* actor = getActor(target); if (actor) targetCollisionObj = actor->getCollisionObject(); @@ -968,7 +968,7 @@ namespace MWPhysics btVector3 btFrom = toBullet(from); btVector3 btTo = toBullet(to); - const btCollisionObject* me = NULL; + const btCollisionObject* me = nullptr; std::vector targetCollisionObjects; if (!ignore.isEmpty()) @@ -1127,7 +1127,7 @@ namespace MWPhysics std::vector PhysicsSystem::getCollisions(const MWWorld::ConstPtr &ptr, int collisionGroup, int collisionMask) const { - btCollisionObject* me = NULL; + btCollisionObject* me = nullptr; ObjectMap::const_iterator found = mObjects.find(ptr); if (found != mObjects.end()) @@ -1255,7 +1255,7 @@ namespace MWPhysics ActorMap::iterator found = mActors.find(ptr); if (found != mActors.end()) return found->second; - return NULL; + return nullptr; } const Actor *PhysicsSystem::getActor(const MWWorld::ConstPtr &ptr) const @@ -1263,7 +1263,7 @@ namespace MWPhysics ActorMap::const_iterator found = mActors.find(ptr); if (found != mActors.end()) return found->second; - return NULL; + return nullptr; } const Object* PhysicsSystem::getObject(const MWWorld::ConstPtr &ptr) const @@ -1271,7 +1271,7 @@ namespace MWPhysics ObjectMap::const_iterator found = mObjects.find(ptr); if (found != mObjects.end()) return found->second; - return NULL; + return nullptr; } void PhysicsSystem::updateScale(const MWWorld::Ptr &ptr) diff --git a/apps/openmw/mwphysics/trace.cpp b/apps/openmw/mwphysics/trace.cpp index 14a5dac48..204ec1467 100644 --- a/apps/openmw/mwphysics/trace.cpp +++ b/apps/openmw/mwphysics/trace.cpp @@ -86,7 +86,7 @@ void ActorTracer::doTrace(const btCollisionObject *actor, const osg::Vec3f& star mPlaneNormal = osg::Vec3f(0.0f, 0.0f, 1.0f); mFraction = 1.0f; mHitPoint = end; - mHitObject = NULL; + mHitObject = nullptr; } } diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 2133f9835..6e2c76d1d 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -367,7 +367,7 @@ namespace void applyNode(osg::Node& node) { if (node.getStateSet()) - node.setStateSet(NULL); + node.setStateSet(nullptr); if (node.getNodeMask() == 0x1 && node.getNumParents() == 1) mToRemove.push_back(std::make_pair(&node, node.getParent(0))); @@ -635,12 +635,12 @@ namespace MWRender Animation::Animation(const MWWorld::Ptr &ptr, osg::ref_ptr parentNode, Resource::ResourceSystem* resourceSystem) : mInsert(parentNode) - , mSkeleton(NULL) + , mSkeleton(nullptr) , mNodeMapCreated(false) , mPtr(ptr) , mResourceSystem(resourceSystem) , mAccumulate(1.f, 1.f, 0.f) - , mTextKeyListener(NULL) + , mTextKeyListener(nullptr) , mHeadYawRadians(0.f) , mHeadPitchRadians(0.f) , mHasMagicEffects(false) @@ -826,7 +826,7 @@ namespace MWRender for(size_t i = 0;i < sNumBlendMasks;i++) mAnimationTimePtr[i]->setTimePtr(std::shared_ptr()); - mAccumCtrl = NULL; + mAccumCtrl = nullptr; mAnimSources.clear(); @@ -1084,12 +1084,12 @@ namespace MWRender node->removeUpdateCallback(it->second); // Should be no longer needed with OSG 3.4 - it->second->setNestedCallback(NULL); + it->second->setNestedCallback(nullptr); } mActiveControllers.clear(); - mAccumCtrl = NULL; + mAccumCtrl = nullptr; for(size_t blendMask = 0;blendMask < sNumBlendMasks;blendMask++) { @@ -1416,14 +1416,14 @@ namespace MWRender previousStateset = mObjectRoot->getStateSet(); mObjectRoot->getParent(0)->removeChild(mObjectRoot); } - mObjectRoot = NULL; - mSkeleton = NULL; + mObjectRoot = nullptr; + mSkeleton = nullptr; mNodeMap.clear(); mNodeMapCreated = false; mActiveControllers.clear(); - mAccumRoot = NULL; - mAccumCtrl = NULL; + mAccumRoot = nullptr; + mAccumCtrl = nullptr; if (!forceskeleton) { @@ -1556,7 +1556,7 @@ namespace MWRender node->addUpdateCallback(glowUpdater); // set a texture now so that the ShaderVisitor can find it - osg::ref_ptr writableStateSet = NULL; + osg::ref_ptr writableStateSet = nullptr; if (!node->getStateSet()) writableStateSet = node->getOrCreateStateSet(); else @@ -1735,7 +1735,7 @@ namespace MWRender std::string lowerName = Misc::StringUtils::lowerCase(name); NodeMap::const_iterator found = getNodeMap().find(lowerName); if (found == getNodeMap().end()) - return NULL; + return nullptr; else return found->second; } @@ -1766,7 +1766,7 @@ namespace MWRender } else { - mObjectRoot->setStateSet(NULL); + mObjectRoot->setStateSet(nullptr); mResourceSystem->getSceneManager()->recreateShaders(mObjectRoot); } @@ -1793,7 +1793,7 @@ namespace MWRender if (mGlowLight) { mInsert->removeChild(mGlowLight); - mGlowLight = NULL; + mGlowLight = nullptr; } } else @@ -1807,7 +1807,7 @@ namespace MWRender if (mGlowLight) { mInsert->removeChild(mGlowLight); - mGlowLight = NULL; + mGlowLight = nullptr; } osg::ref_ptr light (new osg::Light); @@ -1828,7 +1828,7 @@ namespace MWRender void Animation::addControllers() { - mHeadController = NULL; + mHeadController = nullptr; if (mPtr.getClass().isBipedal(mPtr)) { diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 2d8ac152f..47edbdc0b 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -425,7 +425,7 @@ public: * \param speedmult Stores the animation speed multiplier * \return True if the animation is active, false otherwise. */ - bool getInfo(const std::string &groupname, float *complete=NULL, float *speedmult=NULL) const; + bool getInfo(const std::string &groupname, float *complete=nullptr, float *speedmult=nullptr) const; /// Get the absolute position in the animation track of the first text key with the given group. float getStartTime(const std::string &groupname) const; @@ -453,7 +453,7 @@ public: /// This is typically called as part of runAnimation, but may be called manually if needed. void updateEffects(); - /// Return a node with the specified name, or NULL if not existing. + /// Return a node with the specified name, or nullptr if not existing. /// @note The matching is case-insensitive. const osg::Node* getNode(const std::string& name) const; diff --git a/apps/openmw/mwrender/bulletdebugdraw.cpp b/apps/openmw/mwrender/bulletdebugdraw.cpp index eb3775cb4..4cf76e473 100644 --- a/apps/openmw/mwrender/bulletdebugdraw.cpp +++ b/apps/openmw/mwrender/bulletdebugdraw.cpp @@ -54,9 +54,9 @@ void DebugDrawer::destroyGeometry() if (mGeometry) { mParentNode->removeChild(mGeometry); - mGeometry = NULL; - mVertices = NULL; - mDrawArrays = NULL; + mGeometry = nullptr; + mVertices = nullptr; + mDrawArrays = nullptr; } } diff --git a/apps/openmw/mwrender/camera.cpp b/apps/openmw/mwrender/camera.cpp index cb6188a54..74f2ba911 100644 --- a/apps/openmw/mwrender/camera.cpp +++ b/apps/openmw/mwrender/camera.cpp @@ -45,7 +45,7 @@ namespace MWRender Camera::Camera (osg::Camera* camera) : mHeightScale(1.f), mCamera(camera), - mAnimation(NULL), + mAnimation(nullptr), mFirstPersonView(true), mPreviewMode(false), mFreeLook(true), diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index 2e0249e60..075d2e03c 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -239,7 +239,7 @@ namespace MWRender void CharacterPreview::rebuild() { - mAnimation = NULL; + mAnimation = nullptr; mAnimation = new NpcAnimation(mCharacter, mNode, mResourceSystem, true, (renderHeadOnly() ? NpcAnimation::VM_HeadOnly : NpcAnimation::VM_Normal)); @@ -380,7 +380,7 @@ namespace MWRender void InventoryPreview::updatePtr(const MWWorld::Ptr &ptr) { - mCharacter = MWWorld::Ptr(ptr.getBase(), NULL); + mCharacter = MWWorld::Ptr(ptr.getBase(), nullptr); } void InventoryPreview::onSetup() @@ -403,7 +403,7 @@ namespace MWRender , mRef(&mBase) , mPitchRadians(osg::DegreesToRadians(6.f)) { - mCharacter = MWWorld::Ptr(&mRef, NULL); + mCharacter = MWWorld::Ptr(&mRef, nullptr); } RaceSelectionPreview::~RaceSelectionPreview() diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index 6db223bd5..a262d0021 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -170,7 +170,7 @@ void CreatureWeaponAnimation::releaseArrow(float attackStrength) osg::Group *CreatureWeaponAnimation::getArrowBone() { if (!mWeapon) - return NULL; + return nullptr; SceneUtil::FindByNameVisitor findVisitor ("ArrowBone"); mWeapon->getNode()->accept(findVisitor); @@ -180,7 +180,7 @@ osg::Group *CreatureWeaponAnimation::getArrowBone() osg::Node *CreatureWeaponAnimation::getWeaponNode() { - return mWeapon ? mWeapon->getNode().get() : NULL; + return mWeapon ? mWeapon->getNode().get() : nullptr; } Resource::ResourceSystem *CreatureWeaponAnimation::getResourceSystem() diff --git a/apps/openmw/mwrender/globalmap.cpp b/apps/openmw/mwrender/globalmap.cpp index 7712469e1..d1b6cd239 100644 --- a/apps/openmw/mwrender/globalmap.cpp +++ b/apps/openmw/mwrender/globalmap.cpp @@ -563,7 +563,7 @@ namespace MWRender requestOverlayTextureUpdate(0, 0, mWidth, mHeight, osg::ref_ptr(), true, false); - mWorkItem = NULL; + mWorkItem = nullptr; } } diff --git a/apps/openmw/mwrender/landmanager.cpp b/apps/openmw/mwrender/landmanager.cpp index 5edce2c3f..38c28a72a 100644 --- a/apps/openmw/mwrender/landmanager.cpp +++ b/apps/openmw/mwrender/landmanager.cpp @@ -14,7 +14,7 @@ namespace MWRender { LandManager::LandManager(int loadFlags) - : ResourceManager(NULL) + : ResourceManager(nullptr) , mLoadFlags(loadFlags) { } @@ -32,7 +32,7 @@ osg::ref_ptr LandManager::getLand(int x, int y) { const ESM::Land* land = MWBase::Environment::get().getWorld()->getStore().get().search(x,y); if (!land) - return NULL; + return nullptr; osg::ref_ptr landObj (new ESMTerrain::LandObject(land, mLoadFlags)); mCache->addEntryToObjectCache(idstr, landObj.get()); return landObj; diff --git a/apps/openmw/mwrender/landmanager.hpp b/apps/openmw/mwrender/landmanager.hpp index 392a8b406..81253bba3 100644 --- a/apps/openmw/mwrender/landmanager.hpp +++ b/apps/openmw/mwrender/landmanager.hpp @@ -19,7 +19,7 @@ namespace MWRender public: LandManager(int loadFlags); - /// @note Will return NULL if not found. + /// @note Will return nullptr if not found. osg::ref_ptr getLand(int x, int y); virtual void reportStats(unsigned int frameNumber, osg::Stats* stats) const; diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 2716ea19b..c7669f5e9 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -72,7 +72,7 @@ std::string getVampireHead(const std::string& race, bool female) } if (sVampireMapping.find(thisCombination) == sVampireMapping.end()) - sVampireMapping[thisCombination] = NULL; + sVampireMapping[thisCombination] = nullptr; const ESM::BodyPart* bodyPart = sVampireMapping[thisCombination]; if (!bodyPart) @@ -535,7 +535,7 @@ void NpcAnimation::updateParts() }; static const size_t slotlistsize = sizeof(slotlist)/sizeof(slotlist[0]); - bool wasArrowAttached = (mAmmunition.get() != NULL); + bool wasArrowAttached = (mAmmunition.get() != nullptr); mAmmunition.reset(); const MWWorld::InventoryStore& inv = mPtr.getClass().getInventoryStore(mPtr); @@ -823,7 +823,7 @@ void NpcAnimation::addPartGroup(int group, int priority, const std::vectormData.mPart == ESM::BodyPart::MP_Wrist || bodypart->mData.mPart == ESM::BodyPart::MP_Forearm || bodypart->mData.mPart == ESM::BodyPart::MP_Upperarm)) - bodypart = NULL; + bodypart = nullptr; } else if (!bodypart) Log(Debug::Warning) << "Warning: Failed to find body part '" << part->mFemale << "'"; @@ -838,7 +838,7 @@ void NpcAnimation::addPartGroup(int group, int priority, const std::vectormData.mPart == ESM::BodyPart::MP_Wrist || bodypart->mData.mPart == ESM::BodyPart::MP_Forearm || bodypart->mData.mPart == ESM::BodyPart::MP_Upperarm)) - bodypart = NULL; + bodypart = nullptr; } else if (!bodypart) Log(Debug::Warning) << "Warning: Failed to find body part '" << part->mMale << "'"; @@ -855,7 +855,7 @@ void NpcAnimation::addControllers() { Animation::addControllers(); - mFirstPersonNeckController = NULL; + mFirstPersonNeckController = nullptr; WeaponAnimation::deleteControllers(); if (mViewMode == VM_FirstPerson) @@ -947,7 +947,7 @@ osg::Group* NpcAnimation::getArrowBone() { PartHolderPtr part = mObjectParts[ESM::PRT_Weapon]; if (!part) - return NULL; + return nullptr; SceneUtil::FindByNameVisitor findVisitor ("ArrowBone"); part->getNode()->accept(findVisitor); @@ -959,7 +959,7 @@ osg::Node* NpcAnimation::getWeaponNode() { PartHolderPtr part = mObjectParts[ESM::PRT_Weapon]; if (!part) - return NULL; + return nullptr; return part->getNode(); } @@ -1083,7 +1083,7 @@ const std::vector& NpcAnimation::getBodyParts(const std:: sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Tail, ESM::PRT_Tail)); } - parts.resize(ESM::PRT_Count, NULL); + parts.resize(ESM::PRT_Count, nullptr); const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); const MWWorld::Store &partStore = store.get(); diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index 7f3a8da2d..335ca5d5a 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -75,16 +75,16 @@ private: void updateNpcBase(); PartHolderPtr insertBoundedPart(const std::string &model, const std::string &bonename, - const std::string &bonefilter, bool enchantedGlow, osg::Vec4f* glowColor=NULL); + const std::string &bonefilter, bool enchantedGlow, osg::Vec4f* glowColor=nullptr); void removeIndividualPart(ESM::PartReferenceType type); void reserveIndividualPart(ESM::PartReferenceType type, int group, int priority); bool addOrReplaceIndividualPart(ESM::PartReferenceType type, int group, int priority, const std::string &mesh, - bool enchantedGlow=false, osg::Vec4f* glowColor=NULL); + bool enchantedGlow=false, osg::Vec4f* glowColor=nullptr); void removePartGroup(int group); void addPartGroup(int group, int priority, const std::vector &parts, - bool enchantedGlow=false, osg::Vec4f* glowColor=NULL); + bool enchantedGlow=false, osg::Vec4f* glowColor=nullptr); virtual void setRenderBin(); @@ -155,7 +155,7 @@ public: virtual void updatePtr(const MWWorld::Ptr& updated); /// Get a list of body parts that may be used by an NPC of given race and gender. - /// @note This is a fixed size list, one list item for each ESM::PartReferenceType, may contain NULL body parts. + /// @note This is a fixed size list, one list item for each ESM::PartReferenceType, may contain nullptr body parts. static const std::vector& getBodyParts(const std::string& raceId, bool female, bool firstperson, bool werewolf); }; diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index db6772eaa..a0f48ad27 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -126,14 +126,14 @@ bool Objects::removeObject (const MWWorld::Ptr& ptr) if (ptr.getClass().isActor()) { if (ptr.getClass().hasInventoryStore(ptr)) - ptr.getClass().getInventoryStore(ptr).setInvListener(NULL, ptr); + ptr.getClass().getInventoryStore(ptr).setInvListener(nullptr, ptr); - ptr.getClass().getContainerStore(ptr).setContListener(NULL); + ptr.getClass().getContainerStore(ptr).setContListener(nullptr); } ptr.getRefData().getBaseNode()->getParent(0)->removeChild(ptr.getRefData().getBaseNode()); - ptr.getRefData().setBaseNode(NULL); + ptr.getRefData().setBaseNode(nullptr); return true; } return false; @@ -153,8 +153,8 @@ void Objects::removeCell(const MWWorld::CellStore* store) if (ptr.getClass().isNpc() && ptr.getRefData().getCustomData()) { MWWorld::InventoryStore& invStore = ptr.getClass().getInventoryStore(ptr); - invStore.setInvListener(NULL, ptr); - invStore.setContListener(NULL); + invStore.setInvListener(nullptr, ptr); + invStore.setContListener(nullptr); } mObjects.erase(iter++); @@ -218,7 +218,7 @@ Animation* Objects::getAnimation(const MWWorld::Ptr &ptr) if(iter != mObjects.end()) return iter->second; - return NULL; + return nullptr; } const Animation* Objects::getAnimation(const MWWorld::ConstPtr &ptr) const @@ -227,7 +227,7 @@ const Animation* Objects::getAnimation(const MWWorld::ConstPtr &ptr) const if(iter != mObjects.end()) return iter->second; - return NULL; + return nullptr; } } diff --git a/apps/openmw/mwrender/pathgrid.cpp b/apps/openmw/mwrender/pathgrid.cpp index aae97fe35..ee4120d6f 100644 --- a/apps/openmw/mwrender/pathgrid.cpp +++ b/apps/openmw/mwrender/pathgrid.cpp @@ -27,8 +27,8 @@ namespace MWRender Pathgrid::Pathgrid(osg::ref_ptr root) : mPathgridEnabled(false) , mRootNode(root) - , mPathGridRoot(NULL) - , mInteriorPathgridNode(NULL) + , mPathGridRoot(nullptr) + , mInteriorPathgridNode(nullptr) { } @@ -94,7 +94,7 @@ void Pathgrid::togglePathgrid() if (mPathGridRoot) { mRootNode->removeChild(mPathGridRoot); - mPathGridRoot = NULL; + mPathGridRoot = nullptr; } } } @@ -124,7 +124,7 @@ void Pathgrid::enableCellPathgrid(const MWWorld::CellStore *store) } else { - assert(mInteriorPathgridNode == NULL); + assert(mInteriorPathgridNode == nullptr); mInteriorPathgridNode = cellPathGrid; } } @@ -146,7 +146,7 @@ void Pathgrid::disableCellPathgrid(const MWWorld::CellStore *store) if (mInteriorPathgridNode) { mPathGridRoot->removeChild(mInteriorPathgridNode); - mInteriorPathgridNode = NULL; + mInteriorPathgridNode = nullptr; } } } diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index ce0a41c9a..bb0bb2f13 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -232,7 +232,7 @@ namespace MWRender mObjects.reset(new Objects(mResourceSystem, sceneRoot, mUnrefQueue.get())); - if (getenv("OPENMW_DONT_PRECOMPILE") == NULL) + if (getenv("OPENMW_DONT_PRECOMPILE") == nullptr) { mViewer->setIncrementalCompileOperation(new osgUtil::IncrementalCompileOperation); mViewer->getIncrementalCompileOperation()->setTargetFrameRate(Settings::Manager::getFloat("target framerate", "Cells")); @@ -336,7 +336,7 @@ namespace MWRender RenderingManager::~RenderingManager() { // let background loading thread finish before we delete anything else - mWorkQueue = NULL; + mWorkQueue = nullptr; } MWRender::Objects& RenderingManager::getObjects() @@ -832,7 +832,7 @@ namespace MWRender stateset->setTextureAttributeAndModes(0,cubeTexture,osg::StateAttribute::ON); quad->setStateSet(stateset); - quad->setUpdateCallback(NULL); + quad->setUpdateCallback(nullptr); screenshotCamera->addChild(quad); @@ -975,7 +975,7 @@ namespace MWRender result.mHitNormalWorld = intersection.getWorldIntersectNormal(); result.mRatio = intersection.ratio; - PtrHolder* ptrHolder = NULL; + PtrHolder* ptrHolder = nullptr; for (osg::NodePath::const_iterator it = intersection.nodePath.begin(); it != intersection.nodePath.end(); ++it) { osg::UserDataContainer* userDataContainer = (*it)->getUserDataContainer(); @@ -1113,7 +1113,7 @@ namespace MWRender void RenderingManager::rebuildPtr(const MWWorld::Ptr &ptr) { - NpcAnimation *anim = NULL; + NpcAnimation *anim = nullptr; if(ptr == mPlayerAnimation->getPtr()) anim = mPlayerAnimation.get(); else diff --git a/apps/openmw/mwrender/ripplesimulation.cpp b/apps/openmw/mwrender/ripplesimulation.cpp index 141a3eb87..21bd48d9a 100644 --- a/apps/openmw/mwrender/ripplesimulation.cpp +++ b/apps/openmw/mwrender/ripplesimulation.cpp @@ -196,7 +196,7 @@ void RippleSimulation::emitRipple(const osg::Vec3f &pos) { if (std::abs(pos.z() - mParticleNode->getPosition().z()) < 20) { - osgParticle::Particle* p = mParticleSystem->createParticle(NULL); + osgParticle::Particle* p = mParticleSystem->createParticle(nullptr); p->setPosition(osg::Vec3f(pos.x(), pos.y(), 0.f)); p->setAngle(osg::Vec3f(0,0, Misc::Rng::rollProbability() * osg::PI * 2 - osg::PI)); } diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 24769019b..d6a0b9f01 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -629,7 +629,7 @@ private: if (mSunFlashNode) { mSunFlashNode->removeCullCallback(mSunFlashCallback); - mSunFlashCallback = NULL; + mSunFlashCallback = nullptr; } } @@ -671,7 +671,7 @@ private: if (mSunGlareNode) { mSunGlareNode->removeCullCallback(mSunGlareCallback); - mSunGlareCallback = NULL; + mSunGlareCallback = nullptr; } } @@ -1095,8 +1095,8 @@ private: SkyManager::SkyManager(osg::Group* parentNode, Resource::SceneManager* sceneManager) : mSceneManager(sceneManager) - , mCamera(NULL) - , mRainIntensityUniform(NULL) + , mCamera(nullptr) + , mRainIntensityUniform(nullptr) , mAtmosphereNightRoll(0.f) , mCreated(false) , mIsStorm(false) @@ -1302,7 +1302,7 @@ public: { if (stateset->getAttribute(osg::StateAttribute::MATERIAL)) { - SceneUtil::CompositeStateSetUpdater* composite = NULL; + SceneUtil::CompositeStateSetUpdater* composite = nullptr; osg::Callback* callback = node.getUpdateCallback(); while (callback) @@ -1383,12 +1383,12 @@ public: virtual osg::Object *cloneType() const override { - return NULL; + return nullptr; } virtual osg::Object *clone(const osg::CopyOp &op) const override { - return NULL; + return nullptr; } virtual void operate(osgParticle::Particle *P, double dt) override @@ -1520,10 +1520,10 @@ void SkyManager::destroyRain() return; mRootNode->removeChild(mRainNode); - mRainNode = NULL; - mRainParticleSystem = NULL; - mRainShooter = NULL; - mRainFader = NULL; + mRainNode = nullptr; + mRainParticleSystem = nullptr; + mRainShooter = nullptr; + mRainFader = nullptr; } SkyManager::~SkyManager() @@ -1531,7 +1531,7 @@ SkyManager::~SkyManager() if (mRootNode) { mRootNode->getParent(0)->removeChild(mRootNode); - mRootNode = NULL; + mRootNode = nullptr; } } @@ -1554,7 +1554,7 @@ bool SkyManager::isEnabled() bool SkyManager::hasRain() { - return mRainNode != NULL; + return mRainNode != nullptr; } void SkyManager::update(float duration) @@ -1658,7 +1658,7 @@ void SkyManager::setWeather(const WeatherResult& weather) if (mParticleEffect) { mParticleNode->removeChild(mParticleEffect); - mParticleEffect = NULL; + mParticleEffect = nullptr; mParticleFaders.clear(); } @@ -1667,7 +1667,7 @@ void SkyManager::setWeather(const WeatherResult& weather) if (mParticleNode) { mRootNode->removeChild(mParticleNode); - mParticleNode = NULL; + mParticleNode = nullptr; } } else diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 8fd47d2c5..f668b0820 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -441,13 +441,13 @@ void Water::updateWaterMaterial() { mReflection->removeChildren(0, mReflection->getNumChildren()); mParent->removeChild(mReflection); - mReflection = NULL; + mReflection = nullptr; } if (mRefraction) { mRefraction->removeChildren(0, mRefraction->getNumChildren()); mParent->removeChild(mRefraction); - mRefraction = NULL; + mRefraction = nullptr; } if (Settings::Manager::getBool("shader", "Water")) @@ -579,7 +579,7 @@ void Water::createShaderWaterStateSet(osg::Node* node, Reflection* reflection, R shaderStateset->setAttributeAndModes(program, osg::StateAttribute::ON); node->setStateSet(shaderStateset); - node->setUpdateCallback(NULL); + node->setUpdateCallback(nullptr); } void Water::processChangedSettings(const Settings::CategorySettingVector& settings) @@ -595,13 +595,13 @@ Water::~Water() { mReflection->removeChildren(0, mReflection->getNumChildren()); mParent->removeChild(mReflection); - mReflection = NULL; + mReflection = nullptr; } if (mRefraction) { mRefraction->removeChildren(0, mRefraction->getNumChildren()); mParent->removeChild(mRefraction); - mRefraction = NULL; + mRefraction = nullptr; } } diff --git a/apps/openmw/mwrender/weaponanimation.cpp b/apps/openmw/mwrender/weaponanimation.cpp index 32990482a..d5a8cb10d 100644 --- a/apps/openmw/mwrender/weaponanimation.cpp +++ b/apps/openmw/mwrender/weaponanimation.cpp @@ -164,7 +164,7 @@ void WeaponAnimation::addControllers(const std::map >::const_iterator found = nodes.find(i == 0 ? "bip01 spine1" : "bip01 spine2"); if (found != nodes.end()) @@ -180,7 +180,7 @@ void WeaponAnimation::addControllers(const std::mapdisable(ptr); // resets runtime state such as inventory, stats and AI. does not reset position in the world - ptr.getRefData().setCustomData(NULL); + ptr.getRefData().setCustomData(nullptr); if (wasEnabled) MWBase::Environment::get().getWorld()->enable(ptr); } diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index 9d7a5c6ed..2695aed76 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -484,7 +484,7 @@ namespace MWScript if (!player.isInCell()) throw std::runtime_error("player not in a cell"); - MWWorld::CellStore* store = NULL; + MWWorld::CellStore* store = nullptr; if (player.getCell()->isExterior()) { int cx,cy; diff --git a/apps/openmw/mwsound/ffmpeg_decoder.cpp b/apps/openmw/mwsound/ffmpeg_decoder.cpp index 7dffd685a..53452c305 100644 --- a/apps/openmw/mwsound/ffmpeg_decoder.cpp +++ b/apps/openmw/mwsound/ffmpeg_decoder.cpp @@ -122,7 +122,7 @@ bool FFmpeg_Decoder::getAVAudioData() if(!mDataBuf || mDataBufLen < mFrame->nb_samples) { av_freep(&mDataBuf); - if(av_samples_alloc(&mDataBuf, NULL, av_get_channel_layout_nb_channels(mOutputChannelLayout), + if(av_samples_alloc(&mDataBuf, nullptr, av_get_channel_layout_nb_channels(mOutputChannelLayout), mFrame->nb_samples, mOutputSampleFormat, 0) < 0) return false; else @@ -181,34 +181,34 @@ void FFmpeg_Decoder::open(const std::string &fname) close(); mDataStream = mResourceMgr->get(fname); - if((mFormatCtx=avformat_alloc_context()) == NULL) + if((mFormatCtx=avformat_alloc_context()) == nullptr) throw std::runtime_error("Failed to allocate context"); try { - mFormatCtx->pb = avio_alloc_context(NULL, 0, 0, this, readPacket, writePacket, seek); - if(!mFormatCtx->pb || avformat_open_input(&mFormatCtx, fname.c_str(), NULL, NULL) != 0) + mFormatCtx->pb = avio_alloc_context(nullptr, 0, 0, this, readPacket, writePacket, seek); + if(!mFormatCtx->pb || avformat_open_input(&mFormatCtx, fname.c_str(), nullptr, nullptr) != 0) { // "Note that a user-supplied AVFormatContext will be freed on failure". if (mFormatCtx) { - if (mFormatCtx->pb != NULL) + if (mFormatCtx->pb != nullptr) { - if (mFormatCtx->pb->buffer != NULL) + if (mFormatCtx->pb->buffer != nullptr) { av_free(mFormatCtx->pb->buffer); - mFormatCtx->pb->buffer = NULL; + mFormatCtx->pb->buffer = nullptr; } av_free(mFormatCtx->pb); - mFormatCtx->pb = NULL; + mFormatCtx->pb = nullptr; } avformat_free_context(mFormatCtx); } - mFormatCtx = NULL; + mFormatCtx = nullptr; throw std::runtime_error("Failed to allocate input stream"); } - if(avformat_find_stream_info(mFormatCtx, NULL) < 0) + if(avformat_find_stream_info(mFormatCtx, nullptr) < 0) throw std::runtime_error("Failed to find stream info in "+fname); for(size_t j = 0;j < mFormatCtx->nb_streams;j++) @@ -231,7 +231,7 @@ void FFmpeg_Decoder::open(const std::string &fname) std::to_string((*mStream)->codec->codec_id); throw std::runtime_error(ss); } - if(avcodec_open2((*mStream)->codec, codec, NULL) < 0) + if(avcodec_open2((*mStream)->codec, codec, nullptr) < 0) throw std::runtime_error(std::string("Failed to open audio codec ") + codec->long_name); @@ -255,17 +255,17 @@ void FFmpeg_Decoder::open(const std::string &fname) { if(mStream) avcodec_close((*mStream)->codec); - mStream = NULL; + mStream = nullptr; - if (mFormatCtx != NULL) + if (mFormatCtx != nullptr) { - if (mFormatCtx->pb->buffer != NULL) + if (mFormatCtx->pb->buffer != nullptr) { av_free(mFormatCtx->pb->buffer); - mFormatCtx->pb->buffer = NULL; + mFormatCtx->pb->buffer = nullptr; } av_free(mFormatCtx->pb); - mFormatCtx->pb = NULL; + mFormatCtx->pb = nullptr; avformat_close_input(&mFormatCtx); } @@ -276,7 +276,7 @@ void FFmpeg_Decoder::close() { if(mStream) avcodec_close((*mStream)->codec); - mStream = NULL; + mStream = nullptr; av_free_packet(&mPacket); av_freep(&mFrame); @@ -285,20 +285,20 @@ void FFmpeg_Decoder::close() if(mFormatCtx) { - if (mFormatCtx->pb != NULL) + if (mFormatCtx->pb != nullptr) { // mFormatCtx->pb->buffer must be freed by hand, // if not, valgrind will show memleak, see: // // https://trac.ffmpeg.org/ticket/1357 // - if (mFormatCtx->pb->buffer != NULL) + if (mFormatCtx->pb->buffer != nullptr) { av_free(mFormatCtx->pb->buffer); - mFormatCtx->pb->buffer = NULL; + mFormatCtx->pb->buffer = nullptr; } av_free(mFormatCtx->pb); - mFormatCtx->pb = NULL; + mFormatCtx->pb = nullptr; } avformat_close_input(&mFormatCtx); } @@ -373,7 +373,7 @@ void FFmpeg_Decoder::getInfo(int *samplerate, ChannelConfig *chans, SampleType * (*mStream)->codec->sample_fmt, // input sample format (*mStream)->codec->sample_rate, // input sample rate 0, // logging level offset - NULL); // log context + nullptr); // log context if(!mSwr) throw std::runtime_error("Couldn't allocate SwrContext"); if(swr_init(mSwr) < 0) @@ -417,17 +417,17 @@ size_t FFmpeg_Decoder::getSampleOffset() FFmpeg_Decoder::FFmpeg_Decoder(const VFS::Manager* vfs) : Sound_Decoder(vfs) - , mFormatCtx(NULL) - , mStream(NULL) - , mFrame(NULL) + , mFormatCtx(nullptr) + , mStream(nullptr) + , mFrame(nullptr) , mFrameSize(0) , mFramePos(0) , mNextPts(0.0) , mSwr(0) , mOutputSampleFormat(AV_SAMPLE_FMT_NONE) , mOutputChannelLayout(0) - , mDataBuf(NULL) - , mFrameData(NULL) + , mDataBuf(nullptr) + , mFrameData(nullptr) , mDataBufLen(0) { memset(&mPacket, 0, sizeof(mPacket)); diff --git a/apps/openmw/mwsound/movieaudiofactory.cpp b/apps/openmw/mwsound/movieaudiofactory.cpp index 497562516..faa8d94ca 100644 --- a/apps/openmw/mwsound/movieaudiofactory.cpp +++ b/apps/openmw/mwsound/movieaudiofactory.cpp @@ -19,7 +19,7 @@ namespace MWSound { public: MWSoundDecoderBridge(MWSound::MovieAudioDecoder* decoder) - : Sound_Decoder(NULL) + : Sound_Decoder(nullptr) , mDecoder(decoder) { } diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index cadcdc4ab..39e872b0c 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -572,10 +572,10 @@ std::vector OpenAL_Output::enumerate() std::vector devlist; const ALCchar *devnames; - if(alcIsExtensionPresent(NULL, "ALC_ENUMERATE_ALL_EXT")) - devnames = alcGetString(NULL, ALC_ALL_DEVICES_SPECIFIER); + if(alcIsExtensionPresent(nullptr, "ALC_ENUMERATE_ALL_EXT")) + devnames = alcGetString(nullptr, ALC_ALL_DEVICES_SPECIFIER); else - devnames = alcGetString(NULL, ALC_DEVICE_SPECIFIER); + devnames = alcGetString(nullptr, ALC_DEVICE_SPECIFIER); while(devnames && *devnames) { devlist.push_back(devnames); diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 9c12584d7..8e3488906 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -819,7 +819,7 @@ namespace MWSound } const ESM::Region *regn = world->getStore().get().search(regionName); - if(regn == NULL) + if(regn == nullptr) return; if(total == 0) diff --git a/apps/openmw/mwstate/charactermanager.cpp b/apps/openmw/mwstate/charactermanager.cpp index a91bd4e8c..d440ba869 100644 --- a/apps/openmw/mwstate/charactermanager.cpp +++ b/apps/openmw/mwstate/charactermanager.cpp @@ -46,7 +46,7 @@ void MWState::CharacterManager::deleteSlot(const MWState::Character *character, // All slots deleted, cleanup and remove this character it->cleanup(); if (character == mCurrent) - mCurrent = NULL; + mCurrent = nullptr; mCharacters.erase(it); } } @@ -96,7 +96,7 @@ std::list::iterator MWState::CharacterManager::findCharacter void MWState::CharacterManager::setCurrentCharacter (const Character *character) { if (!character) - mCurrent = NULL; + mCurrent = nullptr; else { std::list::iterator it = findCharacter(character); diff --git a/apps/openmw/mwstate/quicksavemanager.cpp b/apps/openmw/mwstate/quicksavemanager.cpp index 59658ce6e..df078e026 100644 --- a/apps/openmw/mwstate/quicksavemanager.cpp +++ b/apps/openmw/mwstate/quicksavemanager.cpp @@ -20,7 +20,7 @@ void MWState::QuickSaveManager::visitSave(const Slot *saveSlot) bool MWState::QuickSaveManager::isOldestSave(const Slot *compare) { - if(mOldestSlotVisited == NULL) + if(mOldestSlotVisited == nullptr) return true; return (compare->mTimeStamp <= mOldestSlotVisited->mTimeStamp); } @@ -33,6 +33,6 @@ bool MWState::QuickSaveManager::shouldCreateNewSlot() const MWState::Slot *MWState::QuickSaveManager::getNextQuickSaveSlot() { if(shouldCreateNewSlot()) - return NULL; + return nullptr; return mOldestSlotVisited; } diff --git a/apps/openmw/mwstate/quicksavemanager.hpp b/apps/openmw/mwstate/quicksavemanager.hpp index e52cd609f..a5237d7c3 100644 --- a/apps/openmw/mwstate/quicksavemanager.hpp +++ b/apps/openmw/mwstate/quicksavemanager.hpp @@ -28,7 +28,7 @@ namespace MWState{ const Slot *getNextQuickSaveSlot(); ///< Get the slot that the next quicksave should use. /// - ///\return Either the oldest quicksave slot visited, or NULL if a new slot can be made + ///\return Either the oldest quicksave slot visited, or nullptr if a new slot can be made }; } diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index 560433820..9804531d7 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -55,7 +55,7 @@ void MWState::StateManager::cleanup (bool force) MWBase::Environment::get().getMechanicsManager()->clear(); mState = State_NoGame; - mCharacterManager.setCurrentCharacter(NULL); + mCharacterManager.setCurrentCharacter(nullptr); mTimePlayed = 0; MWMechanics::CreatureStats::cleanup(); diff --git a/apps/openmw/mwworld/cellpreloader.cpp b/apps/openmw/mwworld/cellpreloader.cpp index 9163f1f2e..a06c208b5 100644 --- a/apps/openmw/mwworld/cellpreloader.cpp +++ b/apps/openmw/mwworld/cellpreloader.cpp @@ -206,13 +206,13 @@ namespace MWWorld { mTerrainPreloadItem->abort(); mTerrainPreloadItem->waitTillDone(); - mTerrainPreloadItem = NULL; + mTerrainPreloadItem = nullptr; } if (mUpdateCacheItem) { mUpdateCacheItem->waitTillDone(); - mUpdateCacheItem = NULL; + mUpdateCacheItem = nullptr; } for (PreloadMap::iterator it = mPreloadCells.begin(); it != mPreloadCells.end();++it) diff --git a/apps/openmw/mwworld/cells.cpp b/apps/openmw/mwworld/cells.cpp index 8506cefa3..2b032e1d7 100644 --- a/apps/openmw/mwworld/cells.cpp +++ b/apps/openmw/mwworld/cells.cpp @@ -340,7 +340,7 @@ public: } catch (...) { - return NULL; + return nullptr; } } }; diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index 5cd8346a7..239d714a0 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -156,7 +156,7 @@ namespace ESM::RefNum mRefNumToFind; SearchByRefNumVisitor(const ESM::RefNum& toFind) - : mFound(NULL) + : mFound(nullptr) , mRefNumToFind(toFind) { } @@ -259,7 +259,7 @@ namespace MWWorld { MWWorld::Ptr copied = object.getClass().copyToCell(object, *cellToMoveTo, object.getRefData().getCount()); object.getRefData().setCount(0); - object.getRefData().setBaseNode(NULL); + object.getRefData().setBaseNode(nullptr); return copied; } @@ -901,7 +901,7 @@ namespace MWWorld CellStore* otherCell = callback->getCellStore(movedTo); - if (otherCell == NULL) + if (otherCell == nullptr) { Log(Debug::Warning) << "Warning: Dropping moved ref tag for " << movedRef->mRef.getRefId() << " (target cell " << movedTo.mWorldspace << " no longer exists). Reference moved back to its original location."; diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index bcf4b4ada..1c4d8f5d8 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -64,7 +64,7 @@ namespace MWWorld // Even though fog actually belongs to the player and not cells, // it makes sense to store it here since we need it once for each cell. - // Note this is NULL until the cell is explored to save some memory + // Note this is nullptr until the cell is explored to save some memory std::shared_ptr mFogState; const ESM::Cell *mCell; @@ -367,7 +367,7 @@ namespace MWWorld struct GetCellStoreCallback { public: - ///@note must return NULL if the cell is not found + ///@note must return nullptr if the cell is not found virtual CellStore* getCellStore(const ESM::CellId& cellId) = 0; }; diff --git a/apps/openmw/mwworld/cellvisitors.hpp b/apps/openmw/mwworld/cellvisitors.hpp index cfb07f749..e68b383b7 100644 --- a/apps/openmw/mwworld/cellvisitors.hpp +++ b/apps/openmw/mwworld/cellvisitors.hpp @@ -17,7 +17,7 @@ namespace MWWorld { if (ptr.getRefData().getBaseNode()) { - ptr.getRefData().setBaseNode(NULL); + ptr.getRefData().setBaseNode(nullptr); mObjects.push_back (ptr); } diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index 8fa16ff51..6a24ae4f0 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -114,7 +114,7 @@ void MWWorld::ContainerStore::storeStates (const CellRefList& collection, const std::string MWWorld::ContainerStore::sGoldId = "gold_001"; -MWWorld::ContainerStore::ContainerStore() : mListener(NULL), mCachedWeight (0), mWeightUpToDate (false) {} +MWWorld::ContainerStore::ContainerStore() : mListener(nullptr), mCachedWeight (0), mWeightUpToDate (false) {} MWWorld::ContainerStore::~ContainerStore() {} @@ -286,7 +286,7 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::add (const Ptr& itemPtr MWWorld::Ptr item = *it; // we may have copied an item from the world, so reset a few things first - item.getRefData().setBaseNode(NULL); // Especially important, otherwise scripts on the item could think that it's actually in a cell + item.getRefData().setBaseNode(nullptr); // Especially important, otherwise scripts on the item could think that it's actually in a cell ESM::Position pos; pos.rot[0] = 0; pos.rot[1] = 0; diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index 7f3018c55..2ca7b94ee 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -99,7 +99,7 @@ void MWWorld::InventoryStore::readEquipmentState(const MWWorld::ContainerStoreIt } MWWorld::InventoryStore::InventoryStore() - : mListener(NULL) + : mListener(nullptr) , mUpdatesEnabled (true) , mFirstAutoEquip(true) , mSelectedEnchantItem(end()) diff --git a/apps/openmw/mwworld/livecellref.hpp b/apps/openmw/mwworld/livecellref.hpp index 2631f513f..4b61c0a08 100644 --- a/apps/openmw/mwworld/livecellref.hpp +++ b/apps/openmw/mwworld/livecellref.hpp @@ -76,11 +76,11 @@ namespace MWWorld template struct LiveCellRef : public LiveCellRefBase { - LiveCellRef(const ESM::CellRef& cref, const X* b = NULL) + LiveCellRef(const ESM::CellRef& cref, const X* b = nullptr) : LiveCellRefBase(typeid(X).name(), cref), mBase(b) {} - LiveCellRef(const X* b = NULL) + LiveCellRef(const X* b = nullptr) : LiveCellRefBase(typeid(X).name()), mBase(b) {} diff --git a/apps/openmw/mwworld/player.cpp b/apps/openmw/mwworld/player.cpp index 49b7dd8bb..85181e998 100644 --- a/apps/openmw/mwworld/player.cpp +++ b/apps/openmw/mwworld/player.cpp @@ -30,7 +30,7 @@ namespace MWWorld Player::Player (const ESM::NPC *player) : mCellStore(0), mLastKnownExteriorPosition(0,0,0), - mMarkedCell(NULL), + mMarkedCell(nullptr), mAutoMove(false), mForwardBackward(0), mTeleported(false), @@ -406,7 +406,7 @@ namespace MWWorld { Log(Debug::Warning) << "Warning: Player cell '" << player.mCellId.mWorldspace << "' no longer exists"; // Cell no longer exists. The loader will have to choose a default cell. - mCellStore = NULL; + mCellStore = nullptr; } if (!player.mBirthsign.empty()) diff --git a/apps/openmw/mwworld/player.hpp b/apps/openmw/mwworld/player.hpp index 4b92fa396..7f37de010 100644 --- a/apps/openmw/mwworld/player.hpp +++ b/apps/openmw/mwworld/player.hpp @@ -38,7 +38,7 @@ namespace MWWorld osg::Vec3f mLastKnownExteriorPosition; ESM::Position mMarkedPosition; - // If no position was marked, this is NULL + // If no position was marked, this is nullptr CellStore* mMarkedCell; bool mAutoMove; diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index dc3d4fd30..30e73df58 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -94,7 +94,7 @@ namespace void updateObjectScale(const MWWorld::Ptr& ptr, MWPhysics::PhysicsSystem& physics, MWRender::RenderingManager& rendering) { - if (ptr.getRefData().getBaseNode() != NULL) + if (ptr.getRefData().getBaseNode() != nullptr) { float scale = ptr.getCellRef().getScale(); osg::Vec3f scaleVec (scale, scale, scale); @@ -330,7 +330,7 @@ namespace MWWorld while (active!=mActiveCells.end()) unloadCell (active++); assert(mActiveCells.empty()); - mCurrentCell = NULL; + mCurrentCell = nullptr; mPreloader->clear(); } @@ -519,7 +519,7 @@ namespace MWWorld void Scene::changeToInteriorCell (const std::string& cellName, const ESM::Position& position, bool adjustPlayerPos, bool changeEvent) { CellStore *cell = MWBase::Environment::get().getWorld()->getInterior(cellName); - bool loadcell = (mCurrentCell == NULL); + bool loadcell = (mCurrentCell == nullptr); if(!loadcell) loadcell = *mCurrentCell != *cell; diff --git a/apps/openmw/mwworld/store.cpp b/apps/openmw/mwworld/store.cpp index 2ac78bb85..b6bf2b7eb 100644 --- a/apps/openmw/mwworld/store.cpp +++ b/apps/openmw/mwworld/store.cpp @@ -96,7 +96,7 @@ namespace MWWorld typename Static::const_iterator it = mStatic.find(index); if (it != mStatic.end()) return &(it->second); - return NULL; + return nullptr; } template const T *IndexedStore::find(int index) const @@ -165,7 +165,7 @@ namespace MWWorld std::for_each(mShared.begin(), mShared.end(), GetRecords(id, &results)); if(!results.empty()) return results[Misc::Rng::rollDice(results.size())]; - return NULL; + return nullptr; } template const T *Store::find(const std::string &id) const @@ -358,7 +358,7 @@ namespace MWWorld const LandTextureList <exl = mStatic[plugin]; if (index >= ltexl.size()) - return NULL; + return nullptr; return <exl[index]; } const ESM::LandTexture *Store::find(size_t index, size_t plugin) const @@ -867,7 +867,7 @@ namespace MWWorld //========================================================================= Store::Store() - : mCells(NULL) + : mCells(nullptr) { } @@ -887,7 +887,7 @@ namespace MWWorld // mX and mY will be (0,0) for interior cells, but there is also an exterior cell with the coordinates of (0,0), so that doesn't help. // Check whether mCell is an interior cell. This isn't perfect, will break if a Region with the same name as an interior cell is created. // A proper fix should be made for future versions of the file format. - bool interior = mCells->search(pathgrid.mCell) != NULL; + bool interior = mCells->search(pathgrid.mCell) != nullptr; // Try to overwrite existing record if (interior) @@ -917,14 +917,14 @@ namespace MWWorld Exterior::const_iterator it = mExt.find(std::make_pair(x,y)); if (it != mExt.end()) return &(it->second); - return NULL; + return nullptr; } const ESM::Pathgrid *Store::search(const std::string& name) const { Interior::const_iterator it = mInt.find(name); if (it != mInt.end()) return &(it->second); - return NULL; + return nullptr; } const ESM::Pathgrid *Store::find(int x, int y) const { diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index 00ea6f66f..2ed81af48 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -166,7 +166,7 @@ namespace MWWorld */ bool isDynamic(const std::string &id) const; - /** Returns a random record that starts with the named ID, or NULL if not found. */ + /** Returns a random record that starts with the named ID, or nullptr if not found. */ const T *searchRandom(const std::string &id) const; const T *find(const std::string &id) const; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 3cb6b3a59..0dcdea131 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1111,7 +1111,7 @@ namespace MWWorld void World::deleteObject (const Ptr& ptr) { - if (!ptr.getRefData().isDeleted() && ptr.getContainerStore() == NULL) + if (!ptr.getRefData().isDeleted() && ptr.getContainerStore() == nullptr) { if (ptr == getPlayerPtr()) throw std::runtime_error("can not delete player object"); @@ -2192,7 +2192,7 @@ namespace MWWorld pos.z() += heightRatio*2*mPhysics->getRenderingHalfExtents(object).z(); - const CellStore *currCell = object.isInCell() ? object.getCell() : NULL; // currCell == NULL should only happen for player, during initial startup + const CellStore *currCell = object.isInCell() ? object.getCell() : nullptr; // currCell == nullptr should only happen for player, during initial startup return isUnderwater(currCell, pos); } @@ -2867,7 +2867,7 @@ namespace MWWorld // if the faced object can not be activated, do not use it if (!target.isEmpty() && !target.getClass().canBeActivated(target)) - target = NULL; + target = nullptr; if (target.isEmpty()) { @@ -2920,14 +2920,14 @@ namespace MWWorld target = result1.first; hitPosition = result1.second; if (dist1 > getMaxActivationDistance()) - target = NULL; + target = nullptr; } else if (result2.mHit) { target = result2.mHitObject; hitPosition = result2.mHitPointWorld; if (dist2 > getMaxActivationDistance() && !target.isEmpty() && !target.getClass().canBeActivated(target)) - target = NULL; + target = nullptr; } } } diff --git a/apps/openmw_test_suite/mwworld/test_store.cpp b/apps/openmw_test_suite/mwworld/test_store.cpp index ac21470de..63e4bd6af 100644 --- a/apps/openmw_test_suite/mwworld/test_store.cpp +++ b/apps/openmw_test_suite/mwworld/test_store.cpp @@ -28,7 +28,7 @@ struct ContentFileTest : public ::testing::Test for (std::vector::const_iterator it = mContentFiles.begin(); it != mContentFiles.end(); ++it) { ESM::ESMReader lEsm; - lEsm.setEncoder(NULL); + lEsm.setEncoder(nullptr); lEsm.setIndex(index); lEsm.setGlobalReaderList(&readerList); lEsm.open(it->string()); @@ -309,7 +309,7 @@ TEST_F(StoreTest, overwrite_test) // verify that changes were actually applied const RecordType* overwrittenRec = mEsmStore.get().search(recordId); - ASSERT_TRUE (overwrittenRec != NULL); + ASSERT_TRUE (overwrittenRec != nullptr); ASSERT_TRUE (overwrittenRec && overwrittenRec->mModel == "the_new_model"); } diff --git a/apps/wizard/existinginstallationpage.cpp b/apps/wizard/existinginstallationpage.cpp index a04e721d8..3ec98a935 100644 --- a/apps/wizard/existinginstallationpage.cpp +++ b/apps/wizard/existinginstallationpage.cpp @@ -96,7 +96,7 @@ void Wizard::ExistingInstallationPage::on_browseButton_clicked() tr("Select master file"), QDir::currentPath(), QString(tr("Morrowind master file (*.esm)")), - NULL, + nullptr, QFileDialog::DontResolveSymlinks); if (selectedFile.isEmpty()) diff --git a/components/contentselector/view/contentselector.cpp b/components/contentselector/view/contentselector.cpp index e26f9a942..4f95b7fe4 100644 --- a/components/contentselector/view/contentselector.cpp +++ b/components/contentselector/view/contentselector.cpp @@ -196,7 +196,7 @@ void ContentSelectorView::ContentSelector::setGameFileSelected(int index, bool s { QString fileName = ui.gameFileView->itemText(index); const ContentSelectorModel::EsmFile* file = mContentModel->item(fileName); - if (file != NULL) + if (file != nullptr) { QModelIndex index2(mContentModel->indexFromItem(file)); mContentModel->setData(index2, selected, Qt::UserRole + 1); diff --git a/components/crashcatcher/crashcatcher.cpp b/components/crashcatcher/crashcatcher.cpp index 64824b6b3..2e2ddd1f2 100644 --- a/components/crashcatcher/crashcatcher.cpp +++ b/components/crashcatcher/crashcatcher.cpp @@ -71,7 +71,7 @@ static const struct { { "Illegal instruction", SIGILL }, { "FPU exception", SIGFPE }, { "System BUS error", SIGBUS }, -{ NULL, 0 } +{ nullptr, 0 } }; static const struct { @@ -88,7 +88,7 @@ static const struct { { ILL_COPROC, "Coprocessor error" }, { ILL_BADSTK, "Internal stack error" }, #endif - { 0, NULL } + { 0, nullptr } }; static const struct { @@ -103,7 +103,7 @@ static const struct { { FPE_FLTRES, "Floating point inexact result" }, { FPE_FLTINV, "Floating point invalid operation" }, { FPE_FLTSUB, "Subscript out of range" }, - { 0, NULL } + { 0, nullptr } }; static const struct { @@ -114,7 +114,7 @@ static const struct { { SEGV_MAPERR, "Address not mapped to object" }, { SEGV_ACCERR, "Invalid permissions for mapped object" }, #endif - { 0, NULL } + { 0, nullptr } }; static const struct { @@ -126,7 +126,7 @@ static const struct { { BUS_ADRERR, "Non-existent physical address" }, { BUS_OBJERR, "Object specific hardware error" }, #endif - { 0, NULL } + { 0, nullptr } }; static int (*cc_user_info)(char*, char*); @@ -140,7 +140,7 @@ static void gdb_info(pid_t pid) /* Create a temp file to put gdb commands into */ strcpy(respfile, "/tmp/gdb-respfile-XXXXXX"); - if((fd=mkstemp(respfile)) >= 0 && (f=fdopen(fd, "w")) != NULL) + if((fd=mkstemp(respfile)) >= 0 && (f=fdopen(fd, "w")) != nullptr) { fprintf(f, "attach %d\n" "shell echo \"\"\n" @@ -267,7 +267,7 @@ static void crash_catcher(int signum, siginfo_t *siginfo, void *context) close(fd[0]); close(fd[1]); - execl(argv0, argv0, crash_switch, NULL); + execl(argv0, argv0, crash_switch, nullptr); safe_write(STDERR_FILENO, exec_err, sizeof(exec_err)-1); _exit(1); @@ -407,7 +407,7 @@ static void crash_handler(const char *logfile) if(logfile) { std::string message = "OpenMW has encountered a fatal error.\nCrash log saved to '" + std::string(logfile) + "'.\n Please report this to https://bugs.openmw.org !"; - SDL_ShowSimpleMessageBox(0, "Fatal Error", message.c_str(), NULL); + SDL_ShowSimpleMessageBox(0, "Fatal Error", message.c_str(), nullptr); } exit(0); @@ -444,7 +444,7 @@ int crashCatcherInstallHandlers(int argc, char **argv, int num_signals, int *sig altss.ss_sp = altstack; altss.ss_flags = 0; altss.ss_size = sizeof(altstack); - sigaltstack(&altss, NULL); + sigaltstack(&altss, nullptr); memset(&sa, 0, sizeof(sa)); sa.sa_sigaction = crash_catcher; @@ -455,7 +455,7 @@ int crashCatcherInstallHandlers(int argc, char **argv, int num_signals, int *sig while(num_signals--) { if((*signals != SIGSEGV && *signals != SIGILL && *signals != SIGFPE && *signals != SIGABRT && - *signals != SIGBUS) || sigaction(*signals, &sa, NULL) == -1) + *signals != SIGBUS) || sigaction(*signals, &sa, nullptr) == -1) { *signals = 0; retval = -1; @@ -502,7 +502,7 @@ static bool is_debugger_present() // Call sysctl. size = sizeof(info); - junk = sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, NULL, 0); + junk = sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, nullptr, 0); assert(junk == 0); // We're being debugged if the P_TRACED flag is set. @@ -516,7 +516,7 @@ void crashCatcherInstall(int argc, char **argv, const std::string &crashLogPath) if ((argc == 2 && strcmp(argv[1], "--cc-handle-crash") == 0) || !is_debugger_present()) { int s[5] = { SIGSEGV, SIGILL, SIGFPE, SIGBUS, SIGABRT }; - if (crashCatcherInstallHandlers(argc, argv, 5, s, crashLogPath.c_str(), NULL) == -1) + if (crashCatcherInstallHandlers(argc, argv, 5, s, crashLogPath.c_str(), nullptr) == -1) { Log(Debug::Warning) << "Installing crash handler failed"; } diff --git a/components/debug/debugging.cpp b/components/debug/debugging.cpp index a4c59c221..e89a65956 100644 --- a/components/debug/debugging.cpp +++ b/components/debug/debugging.cpp @@ -101,7 +101,7 @@ int wrapApplication(int (*innerApplication)(int argc, char *argv[]), int argc, c #if (defined(__APPLE__) || defined(__linux) || defined(__unix) || defined(__posix)) if (!isatty(fileno(stdin))) #endif - SDL_ShowSimpleMessageBox(0, (appName + ": Fatal error").c_str(), e.what(), NULL); + SDL_ShowSimpleMessageBox(0, (appName + ": Fatal error").c_str(), e.what(), nullptr); Log(Debug::Error) << "Error: " << e.what(); diff --git a/components/esm/esmreader.cpp b/components/esm/esmreader.cpp index 67b9d6a38..a6b947dd3 100644 --- a/components/esm/esmreader.cpp +++ b/components/esm/esmreader.cpp @@ -23,8 +23,8 @@ ESMReader::ESMReader() : mIdx(0) , mRecordFlags(0) , mBuffer(50*1024) - , mGlobalReaderList(NULL) - , mEncoder(NULL) + , mGlobalReaderList(nullptr) + , mEncoder(nullptr) , mFileSize(0) { } diff --git a/components/esm/esmwriter.cpp b/components/esm/esmwriter.cpp index b8c78a2b9..09fca4b26 100644 --- a/components/esm/esmwriter.cpp +++ b/components/esm/esmwriter.cpp @@ -10,9 +10,9 @@ namespace ESM { ESMWriter::ESMWriter() : mRecords() - , mStream(NULL) + , mStream(nullptr) , mHeaderPos() - , mEncoder(NULL) + , mEncoder(nullptr) , mRecordCount(0) , mCounting(true) , mHeader() diff --git a/components/esm/loadland.cpp b/components/esm/loadland.cpp index a91dfe3d3..9e5e9d07e 100644 --- a/components/esm/loadland.cpp +++ b/components/esm/loadland.cpp @@ -16,7 +16,7 @@ namespace ESM , mY(0) , mPlugin(0) , mDataTypes(0) - , mLandData(NULL) + , mLandData(nullptr) { } @@ -73,7 +73,7 @@ namespace ESM mContext = esm.getContext(); - mLandData = NULL; + mLandData = nullptr; // Skip the land data here. Load it when the cell is loaded. while (esm.hasMoreSubs()) @@ -298,7 +298,7 @@ namespace ESM if (mLandData) { delete mLandData; - mLandData = NULL; + mLandData = nullptr; } } diff --git a/components/esm/loadland.hpp b/components/esm/loadland.hpp index eaf766442..b4b66c601 100644 --- a/components/esm/loadland.hpp +++ b/components/esm/loadland.hpp @@ -129,9 +129,9 @@ struct Land /** * Actually loads data into target - * If target is NULL, assumed target is mLandData + * If target is nullptr, assumed target is mLandData */ - void loadData(int flags, LandData* target = NULL) const; + void loadData(int flags, LandData* target = nullptr) const; /** * Frees memory allocated for mLandData diff --git a/components/esmterrain/storage.cpp b/components/esmterrain/storage.cpp index 0fa28cf0b..dfdc9718d 100644 --- a/components/esmterrain/storage.cpp +++ b/components/esmterrain/storage.cpp @@ -50,7 +50,7 @@ namespace ESMTerrain const ESM::Land::LandData *LandObject::getData(int flags) const { if ((mData.mDataLoaded & flags) != flags) - return NULL; + return nullptr; return &mData; } diff --git a/components/files/androidpath.cpp b/components/files/androidpath.cpp index 84886f473..bf5c98577 100644 --- a/components/files/androidpath.cpp +++ b/components/files/androidpath.cpp @@ -40,15 +40,15 @@ namespace boost::filesystem::path getUserHome() { const char* dir = getenv("HOME"); - if (dir == NULL) + if (dir == nullptr) { struct passwd* pwd = getpwuid(getuid()); - if (pwd != NULL) + if (pwd != nullptr) { dir = pwd->pw_dir; } } - if (dir == NULL) + if (dir == nullptr) return boost::filesystem::path(); else return boost::filesystem::path(dir); diff --git a/components/files/linuxpath.cpp b/components/files/linuxpath.cpp index 1f6a3d913..3743eef4c 100644 --- a/components/files/linuxpath.cpp +++ b/components/files/linuxpath.cpp @@ -14,15 +14,15 @@ namespace boost::filesystem::path getUserHome() { const char* dir = getenv("HOME"); - if (dir == NULL) + if (dir == nullptr) { struct passwd* pwd = getpwuid(getuid()); - if (pwd != NULL) + if (pwd != nullptr) { dir = pwd->pw_dir; } } - if (dir == NULL) + if (dir == nullptr) return boost::filesystem::path(); else return boost::filesystem::path(dir); diff --git a/components/files/lowlevelfile.cpp b/components/files/lowlevelfile.cpp index 169a6f813..aff15777f 100644 --- a/components/files/lowlevelfile.cpp +++ b/components/files/lowlevelfile.cpp @@ -21,22 +21,22 @@ LowLevelFile::LowLevelFile () { - mHandle = NULL; + mHandle = nullptr; } LowLevelFile::~LowLevelFile () { - if (mHandle != NULL) + if (mHandle != nullptr) fclose (mHandle); } void LowLevelFile::open (char const * filename) { - assert (mHandle == NULL); + assert (mHandle == nullptr); mHandle = fopen (filename, "rb"); - if (mHandle == NULL) + if (mHandle == nullptr) { std::ostringstream os; os << "Failed to open '" << filename << "' for reading."; @@ -46,16 +46,16 @@ void LowLevelFile::open (char const * filename) void LowLevelFile::close () { - assert (mHandle != NULL); + assert (mHandle != nullptr); fclose (mHandle); - mHandle = NULL; + mHandle = nullptr; } size_t LowLevelFile::size () { - assert (mHandle != NULL); + assert (mHandle != nullptr); long oldPosition = ftell (mHandle); @@ -78,7 +78,7 @@ size_t LowLevelFile::size () void LowLevelFile::seek (size_t Position) { - assert (mHandle != NULL); + assert (mHandle != nullptr); if (fseek (mHandle, Position, SEEK_SET) != 0) throw std::runtime_error ("A seek operation on a file failed."); @@ -86,7 +86,7 @@ void LowLevelFile::seek (size_t Position) size_t LowLevelFile::tell () { - assert (mHandle != NULL); + assert (mHandle != nullptr); long Position = ftell (mHandle); @@ -98,7 +98,7 @@ size_t LowLevelFile::tell () size_t LowLevelFile::read (void * data, size_t size) { - assert (mHandle != NULL); + assert (mHandle != nullptr); int amount = fread (data, 1, size, mHandle); @@ -296,7 +296,7 @@ void LowLevelFile::seek (size_t Position) { assert (mHandle != INVALID_HANDLE_VALUE); - if (SetFilePointer (mHandle, Position, NULL, SEEK_SET) == INVALID_SET_FILE_POINTER) + if (SetFilePointer (mHandle, Position, nullptr, SEEK_SET) == INVALID_SET_FILE_POINTER) if (GetLastError () != NO_ERROR) throw std::runtime_error ("A seek operation on a file failed."); } @@ -305,7 +305,7 @@ size_t LowLevelFile::tell () { assert (mHandle != INVALID_HANDLE_VALUE); - DWORD value = SetFilePointer (mHandle, 0, NULL, SEEK_CUR); + DWORD value = SetFilePointer (mHandle, 0, nullptr, SEEK_CUR); if (value == INVALID_SET_FILE_POINTER && GetLastError () != NO_ERROR) throw std::runtime_error ("A query operation on a file failed."); @@ -319,7 +319,7 @@ size_t LowLevelFile::read (void * data, size_t size) DWORD read; - if (!ReadFile (mHandle, data, size, &read, NULL)) + if (!ReadFile (mHandle, data, size, &read, nullptr)) throw std::runtime_error ("A read operation on a file failed."); return read; diff --git a/components/files/macospath.cpp b/components/files/macospath.cpp index b49b72e46..32c35c98f 100644 --- a/components/files/macospath.cpp +++ b/components/files/macospath.cpp @@ -14,15 +14,15 @@ namespace boost::filesystem::path getUserHome() { const char* dir = getenv("HOME"); - if (dir == NULL) + if (dir == nullptr) { struct passwd* pwd = getpwuid(getuid()); - if (pwd != NULL) + if (pwd != nullptr) { dir = pwd->pw_dir; } } - if (dir == NULL) + if (dir == nullptr) return boost::filesystem::path(); else return boost::filesystem::path(dir); diff --git a/components/files/windowspath.cpp b/components/files/windowspath.cpp index 4b7c6c50a..2354e6f31 100644 --- a/components/files/windowspath.cpp +++ b/components/files/windowspath.cpp @@ -42,7 +42,7 @@ boost::filesystem::path WindowsPath::getUserConfigPath() const WCHAR path[MAX_PATH + 1]; memset(path, 0, sizeof(path)); - if(SUCCEEDED(SHGetFolderPathW(NULL, CSIDL_PERSONAL | CSIDL_FLAG_CREATE, NULL, 0, path))) + if(SUCCEEDED(SHGetFolderPathW(nullptr, CSIDL_PERSONAL | CSIDL_FLAG_CREATE, nullptr, 0, path))) { userPath = boost::filesystem::path(bconv::utf_to_utf(path)); } @@ -63,7 +63,7 @@ boost::filesystem::path WindowsPath::getGlobalConfigPath() const WCHAR path[MAX_PATH + 1]; memset(path, 0, sizeof(path)); - if(SUCCEEDED(SHGetFolderPathW(NULL, CSIDL_PROGRAM_FILES | CSIDL_FLAG_CREATE, NULL, 0, path))) + if(SUCCEEDED(SHGetFolderPathW(nullptr, CSIDL_PROGRAM_FILES | CSIDL_FLAG_CREATE, nullptr, 0, path))) { globalPath = boost::filesystem::path(bconv::utf_to_utf(path)); } @@ -99,7 +99,7 @@ boost::filesystem::path WindowsPath::getInstallPath() const std::vector buf(512); int len = 512; - if (RegQueryValueEx(hKey, TEXT("Installed Path"), NULL, NULL, (LPBYTE)&buf[0], (LPDWORD)&len) == ERROR_SUCCESS) + if (RegQueryValueEx(hKey, TEXT("Installed Path"), nullptr, nullptr, (LPBYTE)&buf[0], (LPDWORD)&len) == ERROR_SUCCESS) { installPath = &buf[0]; } diff --git a/components/myguiplatform/additivelayer.cpp b/components/myguiplatform/additivelayer.cpp index aa2ef08b3..49558cf8e 100644 --- a/components/myguiplatform/additivelayer.cpp +++ b/components/myguiplatform/additivelayer.cpp @@ -27,7 +27,7 @@ namespace osgMyGUI MyGUI::OverlappedLayer::renderToTarget(_target, _update); - renderManager.setInjectState(NULL); + renderManager.setInjectState(nullptr); } } diff --git a/components/myguiplatform/myguidatamanager.cpp b/components/myguiplatform/myguidatamanager.cpp index ddd7ca342..c90e09221 100644 --- a/components/myguiplatform/myguidatamanager.cpp +++ b/components/myguiplatform/myguidatamanager.cpp @@ -24,7 +24,7 @@ MyGUI::IDataStream *DataManager::getData(const std::string &name) if (stream->fail()) { Log(Debug::Error) << "DataManager::getData: Failed to open '" << name << "'"; - return NULL; + return nullptr; } return new MyGUI::DataFileStream(stream.release()); } diff --git a/components/myguiplatform/myguirendermanager.cpp b/components/myguiplatform/myguirendermanager.cpp index 5ab7ab736..845d0c484 100644 --- a/components/myguiplatform/myguirendermanager.cpp +++ b/components/myguiplatform/myguirendermanager.cpp @@ -52,7 +52,7 @@ public: { public: FrameUpdate() - : mRenderManager(NULL) + : mRenderManager(nullptr) { } @@ -76,7 +76,7 @@ public: { public: CollectDrawCalls() - : mRenderManager(NULL) + : mRenderManager(nullptr) { } @@ -134,9 +134,9 @@ public: { state->bindVertexBufferObject(bufferobject); - glVertexPointer(3, GL_FLOAT, sizeof(MyGUI::Vertex), (char*)NULL); - glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(MyGUI::Vertex), (char*)NULL + 12); - glTexCoordPointer(2, GL_FLOAT, sizeof(MyGUI::Vertex), (char*)NULL + 16); + glVertexPointer(3, GL_FLOAT, sizeof(MyGUI::Vertex), (char*)nullptr); + glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(MyGUI::Vertex), (char*)nullptr + 12); + glTexCoordPointer(2, GL_FLOAT, sizeof(MyGUI::Vertex), (char*)nullptr + 16); } else { @@ -355,7 +355,7 @@ RenderManager::RenderManager(osgViewer::Viewer *viewer, osg::Group *sceneroot, R , mUpdate(false) , mIsInitialise(false) , mInvScalingFactor(1.f) - , mInjectState(NULL) + , mInjectState(nullptr) { if (scalingFactor != 0.f) mInvScalingFactor = 1.f / scalingFactor; @@ -537,7 +537,7 @@ void RenderManager::destroyTexture(MyGUI::ITexture *texture) MyGUI::ITexture* RenderManager::getTexture(const std::string &name) { if (name.empty()) - return NULL; + return nullptr; MapTexture::const_iterator item = mTextures.find(name); if(item == mTextures.end()) diff --git a/components/myguiplatform/myguirendermanager.hpp b/components/myguiplatform/myguirendermanager.hpp index 4a0aae3cd..8c9e3e30f 100644 --- a/components/myguiplatform/myguirendermanager.hpp +++ b/components/myguiplatform/myguirendermanager.hpp @@ -98,7 +98,7 @@ public: /** @see IRenderTarget::doRender */ virtual void doRender(MyGUI::IVertexBuffer *buffer, MyGUI::ITexture *texture, size_t count); - /** specify a StateSet to inject for rendering. The StateSet will be used by future doRender calls until you reset it to NULL again. */ + /** specify a StateSet to inject for rendering. The StateSet will be used by future doRender calls until you reset it to nullptr again. */ void setInjectState(osg::StateSet* stateSet); /** @see IRenderTarget::getInfo */ diff --git a/components/myguiplatform/myguitexture.cpp b/components/myguiplatform/myguitexture.cpp index 6c53a9699..756893974 100644 --- a/components/myguiplatform/myguitexture.cpp +++ b/components/myguiplatform/myguitexture.cpp @@ -23,7 +23,7 @@ namespace osgMyGUI } OSGTexture::OSGTexture(osg::Texture2D *texture) - : mImageManager(NULL) + : mImageManager(nullptr) , mTexture(texture) , mFormat(MyGUI::PixelFormat::Unknow) , mUsage(MyGUI::TextureUsage::Default) diff --git a/components/nif/niffile.cpp b/components/nif/niffile.cpp index 4061247b5..66bbfdb65 100644 --- a/components/nif/niffile.cpp +++ b/components/nif/niffile.cpp @@ -162,7 +162,7 @@ void NIFFile::parse(Files::IStreamPtr stream) for(size_t i = 0;i < recNum;i++) { - Record *r = NULL; + Record *r = nullptr; std::string rec = nif.getString(); if(rec.empty()) @@ -182,7 +182,7 @@ void NIFFile::parse(Files::IStreamPtr stream) else fail("Unknown record type " + rec); - assert(r != NULL); + assert(r != nullptr); assert(r->recType != RC_MISSING); r->recName = rec; r->recIndex = i; @@ -203,7 +203,7 @@ void NIFFile::parse(Files::IStreamPtr stream) } else { - roots[i] = NULL; + roots[i] = nullptr; warn("Null Root found"); } } diff --git a/components/nif/node.hpp b/components/nif/node.hpp index c32969d1b..d9afbbed7 100644 --- a/components/nif/node.hpp +++ b/components/nif/node.hpp @@ -53,7 +53,7 @@ public: boundXYZ = nif->getVector3(); } - parent = NULL; + parent = nullptr; isBone = false; } @@ -64,7 +64,7 @@ public: props.post(nif); } - // Parent node, or NULL for the root node. As far as I'm aware, only + // Parent node, or nullptr for the root node. As far as I'm aware, only // NiNodes (or types derived from NiNodes) can be parents. NiNode *parent; diff --git a/components/nif/recordptr.hpp b/components/nif/recordptr.hpp index 09c380987..e8aa8cb5b 100644 --- a/components/nif/recordptr.hpp +++ b/components/nif/recordptr.hpp @@ -40,25 +40,25 @@ public: void post(NIFFile *nif) { if(index < 0) - ptr = NULL; + ptr = nullptr; else { Record *r = nif->getRecord(index); // And cast it ptr = dynamic_cast(r); - assert(ptr != NULL); + assert(ptr != nullptr); } } /// Look up the actual object from the index const X* getPtr() const { - assert(ptr != NULL); + assert(ptr != nullptr); return ptr; } X* getPtr() { - assert(ptr != NULL); + assert(ptr != nullptr); return ptr; } @@ -75,7 +75,7 @@ public: /// Pointers are allowed to be empty bool empty() const - { return ptr == NULL; } + { return ptr == nullptr; } }; /** A list of references to other records. These are read as a list, diff --git a/components/nifbullet/bulletnifloader.cpp b/components/nifbullet/bulletnifloader.cpp index 5239e93fc..7b206e40c 100644 --- a/components/nifbullet/bulletnifloader.cpp +++ b/components/nifbullet/bulletnifloader.cpp @@ -25,7 +25,7 @@ namespace osg::Matrixf getWorldTransform(const Nif::Node *node) { - if(node->parent != NULL) + if(node->parent != nullptr) return node->trafo.toMatrix() * getWorldTransform(node->parent); return node->trafo.toMatrix(); } @@ -61,8 +61,8 @@ osg::ref_ptr BulletNifLoader::load(const Nif::File& nif) { mShape = new Resource::BulletShape; - mCompoundShape = NULL; - mStaticMesh = NULL; + mCompoundShape = nullptr; + mStaticMesh = nullptr; if (nif.numRoots() < 1) { @@ -71,10 +71,10 @@ osg::ref_ptr BulletNifLoader::load(const Nif::File& nif) } Nif::Record *r = nif.getRoot(0); - assert(r != NULL); + assert(r != nullptr); Nif::Node *node = dynamic_cast(r); - if (node == NULL) + if (node == nullptr) { warn("First root in file was not a node, but a " + r->recName + ". Skipping file."); @@ -216,7 +216,7 @@ void BulletNifLoader::handleNode(const std::string& fileName, const Nif::Node *n { // Get the next extra data in the list e = e->extra.getPtr(); - assert(e != NULL); + assert(e != nullptr); if (e->recType == Nif::RC_NiStringExtraData) { @@ -263,7 +263,7 @@ void BulletNifLoader::handleNode(const std::string& fileName, const Nif::Node *n void BulletNifLoader::handleNiTriShape(const Nif::NiTriShape *shape, int flags, const osg::Matrixf &transform, bool isAnimated) { - assert(shape != NULL); + assert(shape != nullptr); // If the object was marked "NCO" earlier, it shouldn't collide with // anything. So don't do anything. diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 3198e995c..eb20b7702 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -200,7 +200,7 @@ namespace NifOsg } const Nif::Record *r = nif->getRoot(0); - assert(r != NULL); + assert(r != nullptr); if(r->recType != Nif::RC_NiSequenceStreamHelper) { @@ -257,12 +257,12 @@ namespace NifOsg const Nif::Record* r = nif->getRoot(0); const Nif::Node* nifNode = dynamic_cast(r); - if (nifNode == NULL) + if (nifNode == nullptr) nif->fail("First root was not a node, but a " + r->recName); osg::ref_ptr textkeys (new TextKeyMapHolder); - osg::ref_ptr created = handleNode(nifNode, NULL, imageManager, std::vector(), 0, false, false, false, &textkeys->mTextKeys); + osg::ref_ptr created = handleNode(nifNode, nullptr, imageManager, std::vector(), 0, false, false, false, &textkeys->mTextKeys); if (nif->getUseSkinning()) { @@ -297,7 +297,7 @@ namespace NifOsg { // Get the lowest numbered recIndex of the NiTexturingProperty root node. // This is what is overridden when a spell effect "particle texture" is used. - if (nifNode->parent == NULL && !mFoundFirstRootTexturingProperty && props[i].getPtr()->recType == Nif::RC_NiTexturingProperty) + if (nifNode->parent == nullptr && !mFoundFirstRootTexturingProperty && props[i].getPtr()->recType == Nif::RC_NiTexturingProperty) { mFirstRootTextureIndex = props[i].getPtr()->recIndex; mFoundFirstRootTexturingProperty = true; @@ -338,7 +338,7 @@ namespace NifOsg osg::ref_ptr handleSourceTexture(const Nif::NiSourceTexture* st, Resource::ImageManager* imageManager) { if (!st) - return NULL; + return nullptr; osg::ref_ptr image; if (!st->external && !st->data.empty()) @@ -464,10 +464,10 @@ namespace NifOsg } osg::ref_ptr handleNode(const Nif::Node* nifNode, osg::Group* parentNode, Resource::ImageManager* imageManager, - std::vector boundTextures, int animflags, bool skipMeshes, bool hasMarkers, bool isAnimated, TextKeyMap* textKeys, osg::Node* rootNode=NULL) + std::vector boundTextures, int animflags, bool skipMeshes, bool hasMarkers, bool isAnimated, TextKeyMap* textKeys, osg::Node* rootNode=nullptr) { - if (rootNode != NULL && Misc::StringUtils::ciEqual(nifNode->name, "Bounding Box")) - return NULL; + if (rootNode != nullptr && Misc::StringUtils::ciEqual(nifNode->name, "Bounding Box")) + return nullptr; osg::ref_ptr node = createNode(nifNode); @@ -791,7 +791,7 @@ namespace NifOsg // Load the initial state of the particle system, i.e. the initial particles and their positions, velocity and colors. void handleParticleInitialState(const Nif::Node* nifNode, osgParticle::ParticleSystem* partsys, const Nif::NiParticleSystemController* partctrl) { - const Nif::NiAutoNormalParticlesData *particledata = NULL; + const Nif::NiAutoNormalParticlesData *particledata = nullptr; if(nifNode->recType == Nif::RC_NiAutoNormalParticles) particledata = static_cast(nifNode)->data.getPtr(); else if(nifNode->recType == Nif::RC_NiRotatingParticles) @@ -873,7 +873,7 @@ namespace NifOsg osg::ref_ptr partsys (new ParticleSystem); partsys->setSortMode(osgParticle::ParticleSystem::SORT_BACK_TO_FRONT); - const Nif::NiParticleSystemController* partctrl = NULL; + const Nif::NiParticleSystemController* partctrl = nullptr; for (Nif::ControllerPtr ctrl = nifNode->controller; !ctrl.empty(); ctrl = ctrl->next) { if (!(ctrl->flags & Nif::NiNode::ControllerFlag_Active)) @@ -1193,11 +1193,11 @@ namespace NifOsg break; default: Log(Debug::Info) << "Unhandled internal pixel format " << pixelData->fmt << " in " << mFilename; - return NULL; + return nullptr; } if (pixelData->mipmaps.empty()) - return NULL; + return nullptr; int width = 0; int height = 0; @@ -1211,7 +1211,7 @@ namespace NifOsg if (mipSize + mip.dataOffset > pixelData->data.size()) { Log(Debug::Info) << "Internal texture's mipmap data out of bounds, ignoring texture"; - return NULL; + return nullptr; } if (i != 0) @@ -1226,7 +1226,7 @@ namespace NifOsg if (width <= 0 || height <= 0) { Log(Debug::Info) << "Internal Texture Width and height must be non zero, ignoring texture"; - return NULL; + return nullptr; } unsigned char* data = new unsigned char[pixelData->data.size()]; diff --git a/components/nifosg/particle.cpp b/components/nifosg/particle.cpp index 03e836a0f..f5c055a15 100644 --- a/components/nifosg/particle.cpp +++ b/components/nifosg/particle.cpp @@ -39,7 +39,7 @@ osgParticle::Particle* ParticleSystem::createParticle(const osgParticle::Particl { if (numParticles()-numDeadParticles() < mQuota) return osgParticle::ParticleSystem::createParticle(ptemplate); - return NULL; + return nullptr; } void InverseWorldMatrix::operator()(osg::Node *node, osg::NodeVisitor *nv) @@ -312,7 +312,7 @@ void Emitter::emitParticles(double dt) FindGroupByRecIndex::FindGroupByRecIndex(int recIndex) : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) - , mFound(NULL) + , mFound(nullptr) , mRecIndex(recIndex) { } diff --git a/components/resource/bulletshape.cpp b/components/resource/bulletshape.cpp index dbdbf0c6e..15a747dd3 100644 --- a/components/resource/bulletshape.cpp +++ b/components/resource/bulletshape.cpp @@ -12,7 +12,7 @@ namespace Resource { BulletShape::BulletShape() - : mCollisionShape(NULL) + : mCollisionShape(nullptr) { } @@ -32,7 +32,7 @@ BulletShape::~BulletShape() void BulletShape::deleteShape(btCollisionShape* shape) { - if(shape!=NULL) + if(shape!=nullptr) { if(shape->isCompound()) { diff --git a/components/resource/bulletshapemanager.cpp b/components/resource/bulletshapemanager.cpp index 622506d6b..4193cd5b4 100644 --- a/components/resource/bulletshapemanager.cpp +++ b/components/resource/bulletshapemanager.cpp @@ -24,7 +24,7 @@ namespace Resource struct GetTriangleFunctor { GetTriangleFunctor() - : mTriMesh(NULL) + : mTriMesh(nullptr) { } diff --git a/components/resource/multiobjectcache.hpp b/components/resource/multiobjectcache.hpp index 527247bf9..b73e29d50 100644 --- a/components/resource/multiobjectcache.hpp +++ b/components/resource/multiobjectcache.hpp @@ -30,7 +30,7 @@ namespace Resource void addEntryToObjectCache(const std::string& filename, osg::Object* object); - /** Take an Object from cache. Return NULL if no object found. */ + /** Take an Object from cache. Return nullptr if no object found. */ osg::ref_ptr takeFromObjectCache(const std::string& fileName); /** call releaseGLObjects on all objects attached to the object cache.*/ diff --git a/components/sceneutil/clone.cpp b/components/sceneutil/clone.cpp index 08f36cfcf..99dd7bad3 100644 --- a/components/sceneutil/clone.cpp +++ b/components/sceneutil/clone.cpp @@ -26,7 +26,7 @@ namespace SceneUtil osg::StateSet* CopyOp::operator ()(const osg::StateSet* stateset) const { if (!stateset) - return NULL; + return nullptr; if (stateset->getDataVariance() == osg::StateSet::DYNAMIC) return osg::clone(stateset, *this); return const_cast(stateset); diff --git a/components/sceneutil/controller.cpp b/components/sceneutil/controller.cpp index 8fef00333..dfc72918a 100644 --- a/components/sceneutil/controller.cpp +++ b/components/sceneutil/controller.cpp @@ -19,7 +19,7 @@ namespace SceneUtil bool Controller::hasInput() const { - return mSource.get() != NULL; + return mSource.get() != nullptr; } float Controller::getInputValue(osg::NodeVisitor* nv) diff --git a/components/sceneutil/lightmanager.cpp b/components/sceneutil/lightmanager.cpp index 018abeefc..e102653b9 100644 --- a/components/sceneutil/lightmanager.cpp +++ b/components/sceneutil/lightmanager.cpp @@ -102,7 +102,7 @@ namespace SceneUtil if (LightManager* lightManager = dynamic_cast(path[i])) return lightManager; } - return NULL; + return nullptr; } // Set on a LightSource. Adds the light source to its light manager for the current frame. @@ -299,7 +299,7 @@ namespace SceneUtil virtual osg::Object* cloneType() const { return new DisableLight(mIndex); } virtual osg::Object* clone(const osg::CopyOp& copyop) const { return new DisableLight(*this,copyop); } - virtual bool isSameKindAs(const osg::Object* obj) const { return dynamic_cast(obj)!=NULL; } + virtual bool isSameKindAs(const osg::Object* obj) const { return dynamic_cast(obj)!=nullptr; } virtual const char* libraryName() const { return "SceneUtil"; } virtual const char* className() const { return "DisableLight"; } virtual Type getType() const { return LIGHT; } @@ -323,17 +323,17 @@ namespace SceneUtil virtual void apply(osg::State& state) const { int lightNum = GL_LIGHT0 + mIndex; - glLightfv( lightNum, GL_AMBIENT, mNull.ptr() ); - glLightfv( lightNum, GL_DIFFUSE, mNull.ptr() ); - glLightfv( lightNum, GL_SPECULAR, mNull.ptr() ); + glLightfv( lightNum, GL_AMBIENT, mnullptr.ptr() ); + glLightfv( lightNum, GL_DIFFUSE, mnullptr.ptr() ); + glLightfv( lightNum, GL_SPECULAR, mnullptr.ptr() ); LightStateCache* cache = getLightStateCache(state.getContextID()); - cache->lastAppliedLight[mIndex] = NULL; + cache->lastAppliedLight[mIndex] = nullptr; } private: unsigned int mIndex; - osg::Vec4f mNull; + osg::Vec4f mnullptr; }; void LightManager::setStartLight(int start) @@ -447,7 +447,7 @@ namespace SceneUtil { unsigned int maxLights = static_cast (8 - mLightManager->getStartLight()); - osg::StateSet* stateset = NULL; + osg::StateSet* stateset = nullptr; if (mLightList.size() > maxLights) { diff --git a/components/sceneutil/lightmanager.hpp b/components/sceneutil/lightmanager.hpp index 55d0c69cd..d35aa6058 100644 --- a/components/sceneutil/lightmanager.hpp +++ b/components/sceneutil/lightmanager.hpp @@ -158,7 +158,7 @@ namespace SceneUtil { public: LightListCallback() - : mLightManager(NULL) + : mLightManager(nullptr) , mLastFrameNumber(0) {} LightListCallback(const LightListCallback& copy, const osg::CopyOp& copyop) diff --git a/components/sceneutil/lightutil.cpp b/components/sceneutil/lightutil.cpp index 5ad9bd6dc..d44724e8f 100644 --- a/components/sceneutil/lightutil.cpp +++ b/components/sceneutil/lightutil.cpp @@ -45,7 +45,7 @@ namespace SceneUtil SceneUtil::FindByNameVisitor visitor("AttachLight"); node->accept(visitor); - osg::Group* attachTo = NULL; + osg::Group* attachTo = nullptr; if (visitor.mFoundNode) { attachTo = visitor.mFoundNode; diff --git a/components/sceneutil/optimizer.cpp b/components/sceneutil/optimizer.cpp index b86744599..5d50c369d 100644 --- a/components/sceneutil/optimizer.cpp +++ b/components/sceneutil/optimizer.cpp @@ -166,7 +166,7 @@ class CollectLowestTransformsVisitor : public BaseOptimizerVisitor } else { - // for all current objects mark a NULL transform for them. + // for all current objects mark a nullptr transform for them. registerWithCurrentObjects(0); } } @@ -826,7 +826,7 @@ void Optimizer::RemoveRedundantNodesVisitor::apply(osg::Transform& transform) isOperationPermissible(transform)) { osg::Matrix matrix; - transform.computeWorldToLocalMatrix(matrix,NULL); + transform.computeWorldToLocalMatrix(matrix,nullptr); if (matrix.isIdentity()) { _redundantNodeList.insert(&transform); @@ -1000,7 +1000,7 @@ struct LessGeometryPrimitiveType }; -/// Shortcut to get size of an array, even if pointer is NULL. +/// Shortcut to get size of an array, even if pointer is nullptr. inline unsigned int getSize(const osg::Array * a) { return a ? a->getNumElements() : 0; } /// When merging geometries, tests if two arrays can be merged, regarding to their number of components, and the number of vertices. @@ -1170,7 +1170,7 @@ bool Optimizer::MergeGeometryVisitor::mergeGroup(osg::Group& group) MergeList::iterator eachMergeList=mergeListTmp.begin(); for(;eachMergeList!=mergeListTmp.end();++eachMergeList) { - if (!eachMergeList->empty() && eachMergeList->front()!=NULL + if (!eachMergeList->empty() && eachMergeList->front()!=nullptr && isAbleToMerge(*eachMergeList->front(),*geomToPush)) { eachMergeList->push_back(geomToPush); diff --git a/components/sceneutil/riggeometry.cpp b/components/sceneutil/riggeometry.cpp index c409bcd5c..30a3f076c 100644 --- a/components/sceneutil/riggeometry.cpp +++ b/components/sceneutil/riggeometry.cpp @@ -37,7 +37,7 @@ namespace SceneUtil { RigGeometry::RigGeometry() - : mSkeleton(NULL) + : mSkeleton(nullptr) , mLastFrameNumber(0) , mBoundsFirstFrame(true) { @@ -47,7 +47,7 @@ RigGeometry::RigGeometry() RigGeometry::RigGeometry(const RigGeometry ©, const osg::CopyOp ©op) : Drawable(copy, copyop) - , mSkeleton(NULL) + , mSkeleton(nullptr) , mInfluenceMap(copy.mInfluenceMap) , mLastFrameNumber(0) , mBoundsFirstFrame(true) @@ -98,7 +98,7 @@ void RigGeometry::setSourceGeometry(osg::ref_ptr sourceGeometry) to.setTexCoordArray(7, tangentArray, osg::Array::BIND_PER_VERTEX); } else - mSourceTangents = NULL; + mSourceTangents = nullptr; } } @@ -296,7 +296,7 @@ void RigGeometry::updateGeomToSkelMatrix(const osg::NodePath& nodePath) { if (!geomToSkelMatrix) geomToSkelMatrix = new osg::RefMatrix; - trans->computeWorldToLocalMatrix(*geomToSkelMatrix, NULL); + trans->computeWorldToLocalMatrix(*geomToSkelMatrix, nullptr); } } } diff --git a/components/sceneutil/skeleton.cpp b/components/sceneutil/skeleton.cpp index 58ed9a27c..9be440d93 100644 --- a/components/sceneutil/skeleton.cpp +++ b/components/sceneutil/skeleton.cpp @@ -64,7 +64,7 @@ Bone* Skeleton::getBone(const std::string &name) BoneCache::iterator found = mBoneCache.find(Misc::StringUtils::lowerCase(name)); if (found == mBoneCache.end()) - return NULL; + return nullptr; // find or insert in the bone hierarchy @@ -81,7 +81,7 @@ Bone* Skeleton::getBone(const std::string &name) if (!matrixTransform) continue; - Bone* child = NULL; + Bone* child = nullptr; for (unsigned int i=0; imChildren.size(); ++i) { if (bone->mChildren[i]->mNode == *it) @@ -117,7 +117,7 @@ void Skeleton::updateBoneMatrices(unsigned int traversalNumber) if (mRootBone.get()) { for (unsigned int i=0; imChildren.size(); ++i) - mRootBone->mChildren[i]->update(NULL); + mRootBone->mChildren[i]->update(nullptr); } mNeedToUpdateBoneMatrices = false; @@ -167,7 +167,7 @@ void Skeleton::childRemoved(unsigned int, unsigned int) } Bone::Bone() - : mNode(NULL) + : mNode(nullptr) { } diff --git a/components/sceneutil/statesetupdater.cpp b/components/sceneutil/statesetupdater.cpp index 5a5ecaded..121cdaca6 100644 --- a/components/sceneutil/statesetupdater.cpp +++ b/components/sceneutil/statesetupdater.cpp @@ -30,8 +30,8 @@ namespace SceneUtil void StateSetUpdater::reset() { - mStateSets[0] = NULL; - mStateSets[1] = NULL; + mStateSets[0] = nullptr; + mStateSets[1] = nullptr; } StateSetUpdater::StateSetUpdater() diff --git a/components/sceneutil/visitor.cpp b/components/sceneutil/visitor.cpp index 536331132..3c3559a08 100644 --- a/components/sceneutil/visitor.cpp +++ b/components/sceneutil/visitor.cpp @@ -101,7 +101,7 @@ namespace SceneUtil void CleanObjectRootVisitor::applyNode(osg::Node& node) { if (node.getStateSet()) - node.setStateSet(NULL); + node.setStateSet(nullptr); if (node.getNodeMask() == 0x1 && node.getNumParents() == 1) mToRemove.push_back(std::make_pair(&node, node.getParent(0))); diff --git a/components/sceneutil/visitor.hpp b/components/sceneutil/visitor.hpp index 3e9a565c0..02a351da7 100644 --- a/components/sceneutil/visitor.hpp +++ b/components/sceneutil/visitor.hpp @@ -9,14 +9,14 @@ namespace SceneUtil { // Find a Group by name, case-insensitive - // If not found, mFoundNode will be NULL + // If not found, mFoundNode will be nullptr class FindByNameVisitor : public osg::NodeVisitor { public: FindByNameVisitor(const std::string& nameToFind) : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) , mNameToFind(nameToFind) - , mFoundNode(NULL) + , mFoundNode(nullptr) { } diff --git a/components/sceneutil/workqueue.cpp b/components/sceneutil/workqueue.cpp index 37e8563e1..0ca5e4d3e 100644 --- a/components/sceneutil/workqueue.cpp +++ b/components/sceneutil/workqueue.cpp @@ -97,7 +97,7 @@ osg::ref_ptr WorkQueue::removeWorkItem() return item; } else - return NULL; + return nullptr; } unsigned int WorkQueue::getNumItems() const diff --git a/components/sceneutil/workqueue.hpp b/components/sceneutil/workqueue.hpp index 7de6a5af5..2084df328 100644 --- a/components/sceneutil/workqueue.hpp +++ b/components/sceneutil/workqueue.hpp @@ -57,7 +57,7 @@ namespace SceneUtil void addWorkItem(osg::ref_ptr item, bool front=false); /// Get the next work item from the front of the queue. If the queue is empty, waits until a new item is added. - /// If the workqueue is in the process of being destroyed, may return NULL. + /// If the workqueue is in the process of being destroyed, may return nullptr. /// @par Used internally by the WorkThread. osg::ref_ptr removeWorkItem(); diff --git a/components/sdlutil/sdlcursormanager.cpp b/components/sdlutil/sdlcursormanager.cpp index 1560b74b3..6d2117575 100644 --- a/components/sdlutil/sdlcursormanager.cpp +++ b/components/sdlutil/sdlcursormanager.cpp @@ -190,7 +190,7 @@ namespace CursorDecompression SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "1"); SDL_Texture *cursorTexture = SDL_CreateTextureFromSurface(renderer, cursorSurface); - SDL_RenderCopyEx(renderer, cursorTexture, NULL, NULL, -rotDegrees, NULL, SDL_FLIP_VERTICAL); + SDL_RenderCopyEx(renderer, cursorTexture, nullptr, nullptr, -rotDegrees, nullptr, SDL_FLIP_VERTICAL); SDL_DestroyTexture(cursorTexture); SDL_FreeSurface(cursorSurface); diff --git a/components/sdlutil/sdlgraphicswindow.cpp b/components/sdlutil/sdlgraphicswindow.cpp index f9767238f..dc6129e43 100644 --- a/components/sdlutil/sdlgraphicswindow.cpp +++ b/components/sdlutil/sdlgraphicswindow.cpp @@ -77,7 +77,7 @@ void GraphicsWindowSDL2::init() return; WindowData *inheritedWindowData = dynamic_cast(_traits->inheritedWindowData.get()); - mWindow = inheritedWindowData ? inheritedWindowData->mWindow : NULL; + mWindow = inheritedWindowData ? inheritedWindowData->mWindow : nullptr; mOwnsWindow = (mWindow == 0); if(mOwnsWindow) @@ -162,7 +162,7 @@ bool GraphicsWindowSDL2::releaseContextImplementation() return false; } - return SDL_GL_MakeCurrent(NULL, NULL)==0; + return SDL_GL_MakeCurrent(nullptr, nullptr)==0; } @@ -170,11 +170,11 @@ void GraphicsWindowSDL2::closeImplementation() { if(mContext) SDL_GL_DeleteContext(mContext); - mContext = NULL; + mContext = nullptr; if(mWindow && mOwnsWindow) SDL_DestroyWindow(mWindow); - mWindow = NULL; + mWindow = nullptr; mValid = false; mRealized = false; diff --git a/components/sdlutil/sdlinputwrapper.cpp b/components/sdlutil/sdlinputwrapper.cpp index 5fc828fb5..f7111fdf8 100644 --- a/components/sdlutil/sdlinputwrapper.cpp +++ b/components/sdlutil/sdlinputwrapper.cpp @@ -10,10 +10,10 @@ namespace SDLUtil InputWrapper::InputWrapper(SDL_Window* window, osg::ref_ptr viewer, bool grab) : mSDLWindow(window), mViewer(viewer), - mMouseListener(NULL), - mKeyboardListener(NULL), - mWindowListener(NULL), - mConListener(NULL), + mMouseListener(nullptr), + mKeyboardListener(nullptr), + mWindowListener(nullptr), + mConListener(nullptr), mWarpX(0), mWarpY(0), mWarpCompensate(false), @@ -234,7 +234,7 @@ InputWrapper::InputWrapper(SDL_Window* window, osg::ref_ptr v bool InputWrapper::isKeyDown(SDL_Scancode key) { - return (SDL_GetKeyboardState(NULL)[key]) != 0; + return (SDL_GetKeyboardState(nullptr)[key]) != 0; } /// \brief Moves the mouse to the specified point within the viewport diff --git a/components/shader/shadermanager.cpp b/components/shader/shadermanager.cpp index 28f4300c2..f3d52f5f0 100644 --- a/components/shader/shadermanager.cpp +++ b/components/shader/shadermanager.cpp @@ -115,7 +115,7 @@ namespace Shader if (stream.fail()) { Log(Debug::Error) << "Failed to open " << p.string(); - return NULL; + return nullptr; } std::stringstream buffer; buffer << stream.rdbuf(); @@ -123,7 +123,7 @@ namespace Shader // parse includes std::string source = buffer.str(); if (!parseIncludes(boost::filesystem::path(mPath), source)) - return NULL; + return nullptr; templateIt = mShaderTemplates.insert(std::make_pair(shaderTemplate, source)).first; } @@ -136,7 +136,7 @@ namespace Shader { // Add to the cache anyway to avoid logging the same error over and over. mShaders.insert(std::make_pair(std::make_pair(shaderTemplate, defines), nullptr)); - return NULL; + return nullptr; } osg::ref_ptr shader (new osg::Shader(shaderType)); diff --git a/components/shader/shadermanager.hpp b/components/shader/shadermanager.hpp index bd820a725..6b2e02124 100644 --- a/components/shader/shadermanager.hpp +++ b/components/shader/shadermanager.hpp @@ -26,7 +26,7 @@ namespace Shader /// @param shaderTemplate The filename of the shader template. /// @param defines Define values that can be retrieved by the shader template. /// @param shaderType The type of shader (usually vertex or fragment shader). - /// @note May return NULL on failure. + /// @note May return nullptr on failure. /// @note Thread safe. osg::ref_ptr getShader(const std::string& shaderTemplate, const DefineMap& defines, osg::Shader::Type shaderType); diff --git a/components/shader/shadervisitor.cpp b/components/shader/shadervisitor.cpp index cbd950ea3..a0a6832d0 100644 --- a/components/shader/shadervisitor.cpp +++ b/components/shader/shadervisitor.cpp @@ -28,7 +28,7 @@ namespace Shader , mMaterialOverridden(false) , mNormalHeight(false) , mTexStageRequiringTangents(-1) - , mNode(NULL) + , mNode(nullptr) { } @@ -102,15 +102,15 @@ namespace Shader void ShaderVisitor::applyStateSet(osg::ref_ptr stateset, osg::Node& node) { - osg::StateSet* writableStateSet = NULL; + osg::StateSet* writableStateSet = nullptr; if (mAllowedToModifyStateSets) writableStateSet = node.getStateSet(); const osg::StateSet::TextureAttributeList& texAttributes = stateset->getTextureAttributeList(); if (!texAttributes.empty()) { - const osg::Texture* diffuseMap = NULL; - const osg::Texture* normalMap = NULL; - const osg::Texture* specularMap = NULL; + const osg::Texture* diffuseMap = nullptr; + const osg::Texture* normalMap = nullptr; + const osg::Texture* specularMap = nullptr; for(unsigned int unit=0;unitgetTextureAttribute(unit, osg::StateAttribute::TEXTURE); @@ -153,7 +153,7 @@ namespace Shader } } - if (mAutoUseNormalMaps && diffuseMap != NULL && normalMap == NULL && diffuseMap->getImage(0)) + if (mAutoUseNormalMaps && diffuseMap != nullptr && normalMap == nullptr && diffuseMap->getImage(0)) { std::string normalMapFileName = diffuseMap->getImage(0)->getFileName(); @@ -195,7 +195,7 @@ namespace Shader mRequirements.back().mNormalHeight = normalHeight; } } - if (mAutoUseSpecularMaps && diffuseMap != NULL && specularMap == NULL && diffuseMap->getImage(0)) + if (mAutoUseSpecularMaps && diffuseMap != nullptr && specularMap == nullptr && diffuseMap->getImage(0)) { std::string specularMapFileName = diffuseMap->getImage(0)->getFileName(); boost::replace_last(specularMapFileName, ".", mSpecularMapPattern + "."); @@ -254,7 +254,7 @@ namespace Shader return; osg::Node& node = *reqs.mNode; - osg::StateSet* writableStateSet = NULL; + osg::StateSet* writableStateSet = nullptr; if (mAllowedToModifyStateSets) writableStateSet = node.getOrCreateStateSet(); else @@ -321,7 +321,7 @@ namespace Shader // make sure that all UV sets are there for (std::map::const_iterator it = reqs.mTextures.begin(); it != reqs.mTextures.end(); ++it) { - if (sourceGeometry.getTexCoordArray(it->first) == NULL) + if (sourceGeometry.getTexCoordArray(it->first) == nullptr) { sourceGeometry.setTexCoordArray(it->first, sourceGeometry.getTexCoordArray(0)); changed = true; @@ -342,7 +342,7 @@ namespace Shader void ShaderVisitor::apply(osg::Geometry& geometry) { - bool needPop = (geometry.getStateSet() != NULL); + bool needPop = (geometry.getStateSet() != nullptr); if (geometry.getStateSet()) // TODO: check if stateset affects shader permutation before pushing it { pushRequirements(geometry); @@ -365,7 +365,7 @@ namespace Shader void ShaderVisitor::apply(osg::Drawable& drawable) { // non-Geometry drawable (e.g. particle system) - bool needPop = (drawable.getStateSet() != NULL); + bool needPop = (drawable.getStateSet() != nullptr); if (drawable.getStateSet()) { diff --git a/components/terrain/chunkmanager.cpp b/components/terrain/chunkmanager.cpp index 7575113ef..b23b0b76c 100644 --- a/components/terrain/chunkmanager.cpp +++ b/components/terrain/chunkmanager.cpp @@ -22,7 +22,7 @@ namespace Terrain { ChunkManager::ChunkManager(Storage *storage, Resource::SceneManager *sceneMgr, TextureManager* textureManager, CompositeMapRenderer* renderer) - : ResourceManager(NULL) + : ResourceManager(nullptr) , mStorage(storage) , mSceneManager(sceneMgr) , mTextureManager(textureManager) diff --git a/components/terrain/compositemaprenderer.cpp b/components/terrain/compositemaprenderer.cpp index d3fdfa1f8..3dc0aa41c 100644 --- a/components/terrain/compositemaprenderer.cpp +++ b/components/terrain/compositemaprenderer.cpp @@ -45,7 +45,7 @@ void CompositeMapRenderer::drawImplementation(osg::RenderInfo &renderInfo) const CompositeMap* node = *mImmediateCompileSet.begin(); mCompiled.insert(node); - compile(*node, renderInfo, NULL); + compile(*node, renderInfo, nullptr); mImmediateCompileSet.erase(mImmediateCompileSet.begin()); } diff --git a/components/terrain/quadtreenode.cpp b/components/terrain/quadtreenode.cpp index f4fc8df89..2222cbb84 100644 --- a/components/terrain/quadtreenode.cpp +++ b/components/terrain/quadtreenode.cpp @@ -41,7 +41,7 @@ bool adjacent(ChildDirection dir, Direction dir2) QuadTreeNode* searchNeighbour (QuadTreeNode* currentNode, Direction dir) { if (currentNode->getDirection() == Root) - return NULL; // Arrived at root node, the root node does not have neighbours + return nullptr; // Arrived at root node, the root node does not have neighbours QuadTreeNode* nextNode; if (adjacent(currentNode->getDirection(), dir)) @@ -52,7 +52,7 @@ QuadTreeNode* searchNeighbour (QuadTreeNode* currentNode, Direction dir) if (nextNode && nextNode->getNumChildren()) return nextNode->getChild(reflect(currentNode->getDirection(), dir)); else - return NULL; + return nullptr; } QuadTreeNode::QuadTreeNode(QuadTreeNode* parent, ChildDirection direction, float size, const osg::Vec2f& center) diff --git a/components/terrain/quadtreeworld.cpp b/components/terrain/quadtreeworld.cpp index 9b9bbccd6..40f7a6fb0 100644 --- a/components/terrain/quadtreeworld.cpp +++ b/components/terrain/quadtreeworld.cpp @@ -96,8 +96,8 @@ class RootNode : public QuadTreeNode { public: RootNode(float size, const osg::Vec2f& center) - : QuadTreeNode(NULL, Root, size, center) - , mWorld(NULL) + : QuadTreeNode(nullptr, Root, size, center) + , mWorld(nullptr) { } @@ -317,7 +317,7 @@ void loadRenderingNode(ViewData::Entry& entry, ViewData* vd, ChunkManager* chunk unsigned int lodFlags = getLodFlags(entry.mNode, ourLod, vd); if (lodFlags != entry.mLodFlags) { - entry.mRenderingNode = NULL; + entry.mRenderingNode = nullptr; entry.mLodFlags = lodFlags; } } @@ -367,7 +367,7 @@ void QuadTreeWorld::accept(osg::NodeVisitor &nv) if (udc && udc->getUserData()) { mCompositeMapRenderer->setImmediate(static_cast(udc->getUserData())); - udc->setUserData(NULL); + udc->setUserData(nullptr); } entry.mRenderingNode->accept(nv); } @@ -430,7 +430,7 @@ void QuadTreeWorld::preload(View *view, const osg::Vec3f &eyePoint) ensureQuadTreeBuilt(); ViewData* vd = static_cast(view); - traverse(mRootNode.get(), vd, NULL, mRootNode->getLodCallback(), eyePoint, false); + traverse(mRootNode.get(), vd, nullptr, mRootNode->getLodCallback(), eyePoint, false); for (unsigned int i=0; igetNumEntries(); ++i) { diff --git a/components/terrain/terraindrawable.hpp b/components/terrain/terraindrawable.hpp index 79a28deeb..6bef60bc7 100644 --- a/components/terrain/terraindrawable.hpp +++ b/components/terrain/terraindrawable.hpp @@ -24,7 +24,7 @@ namespace Terrain public: virtual osg::Object* cloneType() const { return new TerrainDrawable (); } virtual osg::Object* clone(const osg::CopyOp& copyop) const { return new TerrainDrawable (*this,copyop); } - virtual bool isSameKindAs(const osg::Object* obj) const { return dynamic_cast(obj)!=NULL; } + virtual bool isSameKindAs(const osg::Object* obj) const { return dynamic_cast(obj)!=nullptr; } virtual const char* className() const { return "TerrainDrawable"; } virtual const char* libraryName() const { return "Terrain"; } diff --git a/components/terrain/terraingrid.cpp b/components/terrain/terraingrid.cpp index 74f683774..dbc1429da 100644 --- a/components/terrain/terraingrid.cpp +++ b/components/terrain/terraingrid.cpp @@ -34,7 +34,7 @@ TerrainGrid::~TerrainGrid() void TerrainGrid::cacheCell(View* view, int x, int y) { osg::Vec2f center(x+0.5f, y+0.5f); - static_cast(view)->mLoaded = buildTerrain(NULL, 1.f, center); + static_cast(view)->mLoaded = buildTerrain(nullptr, 1.f, center); } osg::ref_ptr TerrainGrid::buildTerrain (osg::Group* parent, float chunkSize, const osg::Vec2f& chunkCenter) @@ -57,7 +57,7 @@ osg::ref_ptr TerrainGrid::buildTerrain (osg::Group* parent, float chu { osg::ref_ptr node = mChunkManager->getChunk(chunkSize, chunkCenter, 0, 0); if (!node) - return NULL; + return nullptr; if (parent) parent->addChild(node); @@ -71,7 +71,7 @@ void TerrainGrid::loadCell(int x, int y) return; // already loaded osg::Vec2f center(x+0.5f, y+0.5f); - osg::ref_ptr terrainNode = buildTerrain(NULL, 1.f, center); + osg::ref_ptr terrainNode = buildTerrain(nullptr, 1.f, center); if (!terrainNode) return; // no terrain defined diff --git a/components/terrain/viewdata.cpp b/components/terrain/viewdata.cpp index 5c70f65f2..2f9cb6641 100644 --- a/components/terrain/viewdata.cpp +++ b/components/terrain/viewdata.cpp @@ -64,7 +64,7 @@ void ViewData::reset(unsigned int frame) { // clear any unused entries for (unsigned int i=mNumEntries; isecond; if (vd->getFrameLastUsed() + 2 < frame) { - vd->setViewer(NULL); + vd->setViewer(nullptr); vd->clear(); mUnusedViews.push_back(vd); mViews.erase(it++); diff --git a/components/terrain/world.hpp b/components/terrain/world.hpp index ae71693bd..da1004783 100644 --- a/components/terrain/world.hpp +++ b/components/terrain/world.hpp @@ -90,7 +90,7 @@ namespace Terrain /// Create a View to use with preload feature. The caller is responsible for deleting the view. /// @note Thread safe. - virtual View* createView() { return NULL; } + virtual View* createView() { return nullptr; } /// @note Thread safe, as long as you do not attempt to load into the same view from multiple threads. virtual void preload(View* view, const osg::Vec3f& eyePoint) {} diff --git a/components/translation/translation.cpp b/components/translation/translation.cpp index 14a32f178..ef0f43207 100644 --- a/components/translation/translation.cpp +++ b/components/translation/translation.cpp @@ -5,7 +5,7 @@ namespace Translation { Storage::Storage() - : mEncoder(NULL) + : mEncoder(nullptr) { } diff --git a/components/widgets/windowcaption.cpp b/components/widgets/windowcaption.cpp index 1c8fb5608..0fed4bead 100644 --- a/components/widgets/windowcaption.cpp +++ b/components/widgets/windowcaption.cpp @@ -6,9 +6,9 @@ namespace Gui { WindowCaption::WindowCaption() - : mLeft(NULL) - , mRight(NULL) - , mClient(NULL) + : mLeft(nullptr) + , mRight(nullptr) + , mClient(nullptr) { } From 5617bb3f0c0c70debcded2c00bdd12a642d5eb73 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Tue, 9 Oct 2018 11:29:57 +0400 Subject: [PATCH 195/196] Improve pitch factor handling for crossbow animations (bug #4672) --- CHANGELOG.md | 1 + apps/openmw/mwmechanics/character.cpp | 35 +++++++++------------------ 2 files changed, 12 insertions(+), 24 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 226f09374..99cc5eabd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -134,6 +134,7 @@ Bug #4653: Length of non-ASCII strings is handled incorrectly in ESM reader Bug #4654: Editor: UpdateVisitor does not initialize skeletons for animated objects Bug #4668: Editor: Light source color is displayed as an integer + Bug #4672: Pitch factor is handled incorrectly for crossbow animations Feature #912: Editor: Add missing icons to UniversalId tables Feature #1221: Editor: Creature/NPC rendering Feature #1617: Editor: Enchantment effect record verifier diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index c4975b308..a74e7a49b 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1666,7 +1666,9 @@ bool CharacterController::updateWeaponState(CharacterState& idle) } mAnimation->setPitchFactor(0.f); - if (mWeaponType == WeapType_BowAndArrow || mWeaponType == WeapType_Thrown) + if (mWeaponType == WeapType_BowAndArrow || + mWeaponType == WeapType_Thrown || + mWeaponType == WeapType_Crossbow) { switch (mUpperBodyState) { @@ -1680,29 +1682,14 @@ bool CharacterController::updateWeaponState(CharacterState& idle) break; case UpperCharState_FollowStartToFollowStop: if (animPlaying) - mAnimation->setPitchFactor(1.f-complete); - break; - default: - break; - } - } - else if (mWeaponType == WeapType_Crossbow) - { - switch (mUpperBodyState) - { - case UpperCharState_EquipingWeap: - mAnimation->setPitchFactor(complete); - break; - case UpperCharState_UnEquipingWeap: - mAnimation->setPitchFactor(1.f-complete); - break; - case UpperCharState_WeapEquiped: - case UpperCharState_StartToMinAttack: - case UpperCharState_MinAttackToMaxAttack: - case UpperCharState_MaxAttackToMinHit: - case UpperCharState_MinHitToHit: - case UpperCharState_FollowStartToFollowStop: - mAnimation->setPitchFactor(1.f); + { + // technically we do not need a pitch for crossbow reload animation, + // but we should avoid abrupt repositioning + if (mWeaponType == WeapType_Crossbow) + mAnimation->setPitchFactor(std::max(0.f, 1.f-complete*10.f)); + else + mAnimation->setPitchFactor(1.f-complete); + } break; default: break; From 4ec727c50b4a624b9b191a0b74294fb15d995f84 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Wed, 10 Oct 2018 18:33:56 +0300 Subject: [PATCH 196/196] Disallow to open the journal while settings window is open (bug #4674) --- CHANGELOG.md | 1 + apps/openmw/mwinput/inputmanagerimp.cpp | 1 + 2 files changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index aa877affb..3ad7e9aa6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -138,6 +138,7 @@ Bug #4669: ToggleCollision should trace the player down after collision being enabled Bug #4671: knownEffect functions should use modified Alchemy skill Bug #4672: Pitch factor is handled incorrectly for crossbow animations + Bug #4674: Journal can be opened when settings window is open Feature #912: Editor: Add missing icons to UniversalId tables Feature #1221: Editor: Creature/NPC rendering Feature #1617: Editor: Enchantment effect record verifier diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index b0a98bafc..0d017ba90 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -1107,6 +1107,7 @@ namespace MWInput if(MWBase::Environment::get().getWindowManager()->getMode() != MWGui::GM_Journal && MWBase::Environment::get().getWindowManager()->getMode() != MWGui::GM_MainMenu + && MWBase::Environment::get().getWindowManager()->getMode() != MWGui::GM_Settings && MWBase::Environment::get().getWindowManager ()->getJournalAllowed()) { MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Journal);