From a4d0068e2980800a3454ac83168e33d16b892b0e Mon Sep 17 00:00:00 2001 From: MiroslavR Date: Sun, 2 Nov 2014 15:35:14 +0100 Subject: [PATCH 01/16] Make forcegreeting no-op for disabled references (Fixes #2093) --- apps/openmw/mwscript/dialogueextensions.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwscript/dialogueextensions.cpp b/apps/openmw/mwscript/dialogueextensions.cpp index a88c5a1015..563a9dde3a 100644 --- a/apps/openmw/mwscript/dialogueextensions.cpp +++ b/apps/openmw/mwscript/dialogueextensions.cpp @@ -125,6 +125,9 @@ namespace MWScript { MWWorld::Ptr ptr = R()(runtime); + if (!ptr.getRefData().isEnabled()) + return; + MWBase::Environment::get().getDialogueManager()->startDialogue (ptr); } }; From 140013820ba858ac9d46df3f2e78ec1c9237ac87 Mon Sep 17 00:00:00 2001 From: MiroslavR Date: Sun, 2 Nov 2014 15:40:08 +0100 Subject: [PATCH 02/16] Fix invalidated iterator --- apps/openmw/mwmechanics/spells.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/spells.cpp b/apps/openmw/mwmechanics/spells.cpp index 681f01f04b..a1b73bc47c 100644 --- a/apps/openmw/mwmechanics/spells.cpp +++ b/apps/openmw/mwmechanics/spells.cpp @@ -70,11 +70,13 @@ namespace MWMechanics if (mPermanentSpellEffects.find(lower) != mPermanentSpellEffects.end()) { MagicEffects & effects = mPermanentSpellEffects[lower]; - for (MagicEffects::Collection::const_iterator effectIt = effects.begin(); effectIt != effects.end(); ++effectIt) + for (MagicEffects::Collection::const_iterator effectIt = effects.begin(); effectIt != effects.end();) { const ESM::MagicEffect * magicEffect = MWBase::Environment::get().getWorld()->getStore().get().find(effectIt->first.mId); if (magicEffect->mData.mFlags & ESM::MagicEffect::Harmful) - effects.remove(effectIt->first); + effects.remove((effectIt++)->first); + else + ++effectIt; } } mCorprusSpells.erase(corprusIt); From bf40a3bb5dd33538d81b03317af4093d30c8944d Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 3 Nov 2014 13:18:53 +0100 Subject: [PATCH 03/16] enhanced SceneToolBar tool handling (remove and insert at specific point) --- apps/opencs/view/widget/scenetoolbar.cpp | 15 +++++++++++++-- apps/opencs/view/widget/scenetoolbar.hpp | 6 +++++- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/apps/opencs/view/widget/scenetoolbar.cpp b/apps/opencs/view/widget/scenetoolbar.cpp index eac9bcec32..f7023b31f3 100644 --- a/apps/opencs/view/widget/scenetoolbar.cpp +++ b/apps/opencs/view/widget/scenetoolbar.cpp @@ -31,9 +31,20 @@ CSVWidget::SceneToolbar::SceneToolbar (int buttonSize, QWidget *parent) connect (focusScene, SIGNAL (activated()), this, SIGNAL (focusSceneRequest())); } -void CSVWidget::SceneToolbar::addTool (SceneTool *tool) +void CSVWidget::SceneToolbar::addTool (SceneTool *tool, SceneTool *insertPoint) { - mLayout->addWidget (tool, 0, Qt::AlignTop); + if (!insertPoint) + mLayout->addWidget (tool, 0, Qt::AlignTop); + else + { + int index = mLayout->indexOf (insertPoint); + mLayout->insertWidget (index+1, tool, 0, Qt::AlignTop); + } +} + +void CSVWidget::SceneToolbar::removeTool (SceneTool *tool) +{ + mLayout->removeWidget (tool); } int CSVWidget::SceneToolbar::getButtonSize() const diff --git a/apps/opencs/view/widget/scenetoolbar.hpp b/apps/opencs/view/widget/scenetoolbar.hpp index 1902ba2bed..8e2c8ab00b 100644 --- a/apps/opencs/view/widget/scenetoolbar.hpp +++ b/apps/opencs/view/widget/scenetoolbar.hpp @@ -25,7 +25,11 @@ namespace CSVWidget SceneToolbar (int buttonSize, QWidget *parent = 0); - void addTool (SceneTool *tool); + /// If insertPoint==0, insert \a tool at the end of the scrollbar. Otherwise + /// insert tool after \a insertPoint. + void addTool (SceneTool *tool, SceneTool *insertPoint = 0); + + void removeTool (SceneTool *tool); int getButtonSize() const; From d5768af952b81ff4d1c78eece4e3a7037838c7fc Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 6 Nov 2014 03:51:18 +0100 Subject: [PATCH 04/16] Fix INT_MIN trade exploit (Fixes #2096) --- apps/openmw/mwgui/tradewindow.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index 9ef926bd3b..0f98598fd8 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -89,6 +89,7 @@ namespace MWGui mDecreaseButton->eventMouseButtonReleased += MyGUI::newDelegate(this, &TradeWindow::onBalanceButtonReleased); mTotalBalance->eventValueChanged += MyGUI::newDelegate(this, &TradeWindow::onBalanceValueChanged); + mTotalBalance->setMinValue(INT_MIN+1); // disallow INT_MIN since abs(INT_MIN) is undefined setCoord(400, 0, 400, 300); } @@ -448,6 +449,9 @@ 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) + return; if(mCurrentBalance<=-1) mCurrentBalance -= 1; if(mCurrentBalance>=1) mCurrentBalance += 1; updateLabels(); From 4dd645559d69c1f19b80d4ccece830f8686736aa Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 6 Nov 2014 13:26:19 +0100 Subject: [PATCH 05/16] added ModeButton specialisation of PushButton for use in SceneToolMode --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/view/widget/modebutton.cpp | 10 ++++++++ apps/opencs/view/widget/modebutton.hpp | 28 +++++++++++++++++++++++ apps/opencs/view/widget/scenetoolmode.cpp | 28 +++++++++++++++-------- apps/opencs/view/widget/scenetoolmode.hpp | 8 ++++--- 5 files changed, 63 insertions(+), 13 deletions(-) create mode 100644 apps/opencs/view/widget/modebutton.cpp create mode 100644 apps/opencs/view/widget/modebutton.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index e2e5aa2e5a..9d8a22f7c6 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -72,7 +72,7 @@ opencs_units_noqt (view/world ) opencs_units (view/widget - scenetoolbar scenetool scenetoolmode pushbutton scenetooltoggle scenetoolrun + scenetoolbar scenetool scenetoolmode pushbutton scenetooltoggle scenetoolrun modebutton ) opencs_units (view/render diff --git a/apps/opencs/view/widget/modebutton.cpp b/apps/opencs/view/widget/modebutton.cpp new file mode 100644 index 0000000000..56896b4220 --- /dev/null +++ b/apps/opencs/view/widget/modebutton.cpp @@ -0,0 +1,10 @@ + +#include "modebutton.hpp" + +CSVWidget::ModeButton::ModeButton (const QIcon& icon, const QString& tooltip, QWidget *parent) +: PushButton (icon, Type_Mode, tooltip, parent) +{} + +void CSVWidget::ModeButton::activate (SceneToolbar *toolbar) {} + +void CSVWidget::ModeButton::deactivate (SceneToolbar *toolbar) {} diff --git a/apps/opencs/view/widget/modebutton.hpp b/apps/opencs/view/widget/modebutton.hpp new file mode 100644 index 0000000000..ac14afc952 --- /dev/null +++ b/apps/opencs/view/widget/modebutton.hpp @@ -0,0 +1,28 @@ +#ifndef CSV_WIDGET_MODEBUTTON_H +#define CSV_WIDGET_MODEBUTTON_H + +#include "pushbutton.hpp" + +namespace CSVWidget +{ + class SceneToolbar; + + /// \brief Specialist PushButton of Type_Mode for use in SceneToolMode + class ModeButton : public PushButton + { + Q_OBJECT + + public: + + ModeButton (const QIcon& icon, const QString& tooltip = "", + QWidget *parent = 0); + + /// Default-Implementation: do nothing + virtual void activate (SceneToolbar *toolbar); + + /// Default-Implementation: do nothing + virtual void deactivate (SceneToolbar *toolbar); + }; +} + +#endif diff --git a/apps/opencs/view/widget/scenetoolmode.cpp b/apps/opencs/view/widget/scenetoolmode.cpp index caedfa3ee8..fd3c34a2b9 100644 --- a/apps/opencs/view/widget/scenetoolmode.cpp +++ b/apps/opencs/view/widget/scenetoolmode.cpp @@ -6,9 +6,9 @@ #include #include "scenetoolbar.hpp" -#include "pushbutton.hpp" +#include "modebutton.hpp" -void CSVWidget::SceneToolMode::adjustToolTip (const PushButton *activeMode) +void CSVWidget::SceneToolMode::adjustToolTip (const ModeButton *activeMode) { QString toolTip = mToolTip; @@ -21,7 +21,7 @@ void CSVWidget::SceneToolMode::adjustToolTip (const PushButton *activeMode) CSVWidget::SceneToolMode::SceneToolMode (SceneToolbar *parent, const QString& toolTip) : SceneTool (parent), mButtonSize (parent->getButtonSize()), mIconSize (parent->getIconSize()), - mToolTip (toolTip), mFirst (0) + mToolTip (toolTip), mFirst (0), mCurrent (0), mToolbar (parent) { mPanel = new QFrame (this, Qt::Popup); @@ -44,8 +44,7 @@ void CSVWidget::SceneToolMode::showPanel (const QPoint& position) void CSVWidget::SceneToolMode::addButton (const std::string& icon, const std::string& id, const QString& tooltip) { - PushButton *button = new PushButton (QIcon (QPixmap (icon.c_str())), PushButton::Type_Mode, - tooltip, mPanel); + ModeButton *button = new ModeButton (QIcon (QPixmap (icon.c_str())), tooltip, mPanel); button->setSizePolicy (QSizePolicy (QSizePolicy::Fixed, QSizePolicy::Fixed)); button->setIconSize (QSize (mIconSize, mIconSize)); button->setFixedSize (mButtonSize, mButtonSize); @@ -58,29 +57,40 @@ void CSVWidget::SceneToolMode::addButton (const std::string& icon, const std::st if (mButtons.size()==1) { - mFirst = button; + mFirst = mCurrent = button; setIcon (button->icon()); button->setChecked (true); adjustToolTip (button); + mCurrent->activate (mToolbar); } } void CSVWidget::SceneToolMode::selected() { - std::map::const_iterator iter = - mButtons.find (dynamic_cast (sender())); + std::map::const_iterator iter = + mButtons.find (dynamic_cast (sender())); if (iter!=mButtons.end()) { if (!iter->first->hasKeepOpen()) mPanel->hide(); - for (std::map::const_iterator iter2 = mButtons.begin(); + for (std::map::const_iterator iter2 = mButtons.begin(); iter2!=mButtons.end(); ++iter2) iter2->first->setChecked (iter2==iter); setIcon (iter->first->icon()); adjustToolTip (iter->first); + + if (mCurrent!=iter->first) + { + if (mCurrent) + mCurrent->deactivate (mToolbar); + + mCurrent = iter->first; + mCurrent->activate (mToolbar); + } + emit modeChanged (iter->second); } } \ No newline at end of file diff --git a/apps/opencs/view/widget/scenetoolmode.hpp b/apps/opencs/view/widget/scenetoolmode.hpp index 9959f98355..7fb7586f2d 100644 --- a/apps/opencs/view/widget/scenetoolmode.hpp +++ b/apps/opencs/view/widget/scenetoolmode.hpp @@ -10,7 +10,7 @@ class QHBoxLayout; namespace CSVWidget { class SceneToolbar; - class PushButton; + class ModeButton; ///< \brief Mode selector tool class SceneToolMode : public SceneTool @@ -19,13 +19,15 @@ namespace CSVWidget QWidget *mPanel; QHBoxLayout *mLayout; - std::map mButtons; // widget, id + std::map mButtons; // widget, id int mButtonSize; int mIconSize; QString mToolTip; PushButton *mFirst; + ModeButton *mCurrent; + SceneToolbar *mToolbar; - void adjustToolTip (const PushButton *activeMode); + void adjustToolTip (const ModeButton *activeMode); public: From 07ea352e46634892d1d8d4a863aba7d043b5b0d9 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 7 Nov 2014 00:16:41 +0100 Subject: [PATCH 06/16] Fix button graphics preventing mouse clicks (Fixes #2104) --- files/mygui/openmw_button.skin.xml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/files/mygui/openmw_button.skin.xml b/files/mygui/openmw_button.skin.xml index 73c266818b..18055a7e59 100644 --- a/files/mygui/openmw_button.skin.xml +++ b/files/mygui/openmw_button.skin.xml @@ -3,6 +3,7 @@ + @@ -12,6 +13,7 @@ + @@ -21,6 +23,7 @@ + @@ -30,6 +33,7 @@ + @@ -39,21 +43,25 @@ + + + + From 9e67a07ad47af80fbb8b0f7bad27e572d3c2d5fd Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 7 Nov 2014 11:11:43 +0100 Subject: [PATCH 07/16] allow externally supplied ModeButtons in SceneToolMode --- apps/opencs/view/widget/scenetoolmode.cpp | 7 +++++++ apps/opencs/view/widget/scenetoolmode.hpp | 3 +++ 2 files changed, 10 insertions(+) diff --git a/apps/opencs/view/widget/scenetoolmode.cpp b/apps/opencs/view/widget/scenetoolmode.cpp index fd3c34a2b9..8d871cc5f4 100644 --- a/apps/opencs/view/widget/scenetoolmode.cpp +++ b/apps/opencs/view/widget/scenetoolmode.cpp @@ -45,6 +45,13 @@ void CSVWidget::SceneToolMode::addButton (const std::string& icon, const std::st const QString& tooltip) { ModeButton *button = new ModeButton (QIcon (QPixmap (icon.c_str())), tooltip, mPanel); + addButton (button, id); +} + +void CSVWidget::SceneToolMode::addButton (ModeButton *button, const std::string& id) +{ + button->setParent (mPanel); + button->setSizePolicy (QSizePolicy (QSizePolicy::Fixed, QSizePolicy::Fixed)); button->setIconSize (QSize (mIconSize, mIconSize)); button->setFixedSize (mButtonSize, mButtonSize); diff --git a/apps/opencs/view/widget/scenetoolmode.hpp b/apps/opencs/view/widget/scenetoolmode.hpp index 7fb7586f2d..e6f462cf89 100644 --- a/apps/opencs/view/widget/scenetoolmode.hpp +++ b/apps/opencs/view/widget/scenetoolmode.hpp @@ -38,6 +38,9 @@ namespace CSVWidget void addButton (const std::string& icon, const std::string& id, const QString& tooltip = ""); + /// The ownership of \a button is transferred to *this. + void addButton (ModeButton *button, const std::string& id); + signals: void modeChanged (const std::string& id); From b8d5a9486ac04270034126df753fe7e69d198b41 Mon Sep 17 00:00:00 2001 From: MiroslavR Date: Sun, 2 Nov 2014 18:01:12 +0100 Subject: [PATCH 08/16] Make Restore/Damage Attribute/Skill effects continuous --- apps/openmw/mwmechanics/actors.cpp | 12 +++++++++--- apps/openmw/mwmechanics/actors.hpp | 2 +- apps/openmw/mwmechanics/stat.hpp | 8 ++++---- components/esm/statstate.hpp | 14 ++++++++++---- 4 files changed, 24 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 02594258db..2e835d57e4 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -369,7 +369,7 @@ namespace MWMechanics void Actors::updateNpc (const MWWorld::Ptr& ptr, float duration) { updateDrowning(ptr, duration); - calculateNpcStatModifiers(ptr); + calculateNpcStatModifiers(ptr, duration); updateEquippedLight(ptr, duration); } @@ -499,6 +499,9 @@ namespace MWMechanics effects.get(EffectKey(ESM::MagicEffect::DrainAttribute, i)).getMagnitude() - effects.get(EffectKey(ESM::MagicEffect::AbsorbAttribute, i)).getMagnitude()); + stat.damage(effects.get(EffectKey(ESM::MagicEffect::DamageAttribute, i)).getMagnitude() * duration * 1.5); + stat.restore(effects.get(EffectKey(ESM::MagicEffect::RestoreAttribute, i)).getMagnitude() * duration * 1.5); + creatureStats.setAttribute(i, stat); } @@ -855,7 +858,7 @@ namespace MWMechanics } } - void Actors::calculateNpcStatModifiers (const MWWorld::Ptr& ptr) + void Actors::calculateNpcStatModifiers (const MWWorld::Ptr& ptr, float duration) { NpcStats &npcStats = ptr.getClass().getNpcStats(ptr); const MagicEffects &effects = npcStats.getMagicEffects(); @@ -867,6 +870,9 @@ namespace MWMechanics skill.setModifier(effects.get(EffectKey(ESM::MagicEffect::FortifySkill, i)).getMagnitude() - effects.get(EffectKey(ESM::MagicEffect::DrainSkill, i)).getMagnitude() - effects.get(EffectKey(ESM::MagicEffect::AbsorbSkill, i)).getMagnitude()); + + skill.damage(effects.get(EffectKey(ESM::MagicEffect::DamageSkill, i)).getMagnitude() * duration * 1.5); + skill.restore(effects.get(EffectKey(ESM::MagicEffect::RestoreSkill, i)).getMagnitude() * duration * 1.5); } } @@ -1534,6 +1540,6 @@ namespace MWMechanics adjustMagicEffects(ptr); calculateCreatureStatModifiers(ptr, 0.f); if (ptr.getClass().isNpc()) - calculateNpcStatModifiers(ptr); + calculateNpcStatModifiers(ptr, 0.f); } } diff --git a/apps/openmw/mwmechanics/actors.hpp b/apps/openmw/mwmechanics/actors.hpp index 55f1719f62..0ccfaad78a 100644 --- a/apps/openmw/mwmechanics/actors.hpp +++ b/apps/openmw/mwmechanics/actors.hpp @@ -34,7 +34,7 @@ namespace MWMechanics void calculateDynamicStats (const MWWorld::Ptr& ptr); void calculateCreatureStatModifiers (const MWWorld::Ptr& ptr, float duration); - void calculateNpcStatModifiers (const MWWorld::Ptr& ptr); + void calculateNpcStatModifiers (const MWWorld::Ptr& ptr, float duration); void calculateRestoration (const MWWorld::Ptr& ptr, float duration); diff --git a/apps/openmw/mwmechanics/stat.hpp b/apps/openmw/mwmechanics/stat.hpp index 0fb4c57328..1c33db0fd2 100644 --- a/apps/openmw/mwmechanics/stat.hpp +++ b/apps/openmw/mwmechanics/stat.hpp @@ -236,20 +236,20 @@ namespace MWMechanics { int mBase; int mModifier; - int mDamage; + float mDamage; // needs to be float to allow continuous damage public: AttributeValue() : mBase(0), mModifier(0), mDamage(0) {} - int getModified() const { return std::max(0, mBase - mDamage + mModifier); } + int getModified() const { return std::max(0, mBase - (int) mDamage + mModifier); } int getBase() const { return mBase; } int getModifier() const { return mModifier; } void setBase(int base) { mBase = std::max(0, base); } void setModifier(int mod) { mModifier = mod; } - void damage(int damage) { mDamage += damage; } - void restore(int amount) { mDamage -= std::min(mDamage, amount); } + void damage(float damage) { mDamage += damage; } + void restore(float amount) { mDamage -= std::min(mDamage, amount); } int getDamage() const { return mDamage; } void writeState (ESM::StatState& state) const; diff --git a/components/esm/statstate.hpp b/components/esm/statstate.hpp index f1a3b4d794..801d0ce826 100644 --- a/components/esm/statstate.hpp +++ b/components/esm/statstate.hpp @@ -15,7 +15,7 @@ namespace ESM T mMod; // Note: can either be the modifier, or the modified value. // A bit inconsistent, but we can't fix this without breaking compatibility. T mCurrent; - T mDamage; + float mDamage; float mProgress; StatState(); @@ -36,8 +36,14 @@ namespace ESM esm.getHNOT (mMod, "STMO"); mCurrent = 0; esm.getHNOT (mCurrent, "STCU"); - mDamage = 0; - esm.getHNOT (mDamage, "STDA"); + + // mDamage was changed to a float; ensure backwards compatibility + T oldDamage = 0; + esm.getHNOT(oldDamage, "STDA"); + mDamage = oldDamage; + + esm.getHNOT (mDamage, "STDF"); + mProgress = 0; esm.getHNOT (mProgress, "STPR"); } @@ -54,7 +60,7 @@ namespace ESM esm.writeHNT ("STCU", mCurrent); if (mDamage) - esm.writeHNT ("STDA", mDamage); + esm.writeHNT ("STDF", mDamage); if (mProgress) esm.writeHNT ("STPR", mProgress); From 92ab292e18ec0379c9218dc0fc1458a7823c1efd Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 9 Nov 2014 04:50:54 +0100 Subject: [PATCH 09/16] Make MODL subrecord for light records optional (Fixes #2114) --- components/esm/loadligh.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esm/loadligh.cpp b/components/esm/loadligh.cpp index c02bb46b69..f88ff09d6f 100644 --- a/components/esm/loadligh.cpp +++ b/components/esm/loadligh.cpp @@ -10,7 +10,7 @@ namespace ESM void Light::load(ESMReader &esm) { - mModel = esm.getHNString("MODL"); + mModel = esm.getHNOString("MODL"); mName = esm.getHNOString("FNAM"); mIcon = esm.getHNOString("ITEX"); assert(sizeof(mData) == 24); From b50fcd403bd8b74a2ebcb0d50c2271cb881cf7cd Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 9 Nov 2014 11:29:45 +0100 Subject: [PATCH 10/16] renamed getElementMask to getVisibilityMask --- apps/opencs/view/render/pagedworldspacewidget.cpp | 4 ++-- apps/opencs/view/render/pagedworldspacewidget.hpp | 2 +- apps/opencs/view/render/worldspacewidget.cpp | 4 ++-- apps/opencs/view/render/worldspacewidget.hpp | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index 8b143e93ff..9b42feb38f 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.cpp +++ b/apps/opencs/view/render/pagedworldspacewidget.cpp @@ -430,9 +430,9 @@ CSVRender::WorldspaceWidget::dropRequirments CSVRender::PagedWorldspaceWidget::g } -unsigned int CSVRender::PagedWorldspaceWidget::getElementMask() const +unsigned int CSVRender::PagedWorldspaceWidget::getVisibilityMask() const { - return WorldspaceWidget::getElementMask() | mControlElements->getSelection(); + return WorldspaceWidget::getVisibilityMask() | mControlElements->getSelection(); } CSVWidget::SceneToolToggle *CSVRender::PagedWorldspaceWidget::makeControlVisibilitySelector ( diff --git a/apps/opencs/view/render/pagedworldspacewidget.hpp b/apps/opencs/view/render/pagedworldspacewidget.hpp index 17b6d10c53..ec2d5dc240 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.hpp +++ b/apps/opencs/view/render/pagedworldspacewidget.hpp @@ -75,7 +75,7 @@ namespace CSVRender virtual CSVWidget::SceneToolToggle *makeControlVisibilitySelector ( CSVWidget::SceneToolbar *parent); - virtual unsigned int getElementMask() const; + virtual unsigned int getVisibilityMask() const; protected: diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index ebb15ea2ce..0a8d5e364e 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -216,7 +216,7 @@ bool CSVRender::WorldspaceWidget::handleDrop (const std::vectorgetSelection(); } @@ -311,7 +311,7 @@ void CSVRender::WorldspaceWidget::debugProfileAboutToBeRemoved (const QModelInde void CSVRender::WorldspaceWidget::elementSelectionChanged() { - setVisibilityMask (getElementMask()); + setVisibilityMask (getVisibilityMask()); flagAsModified(); updateOverlay(); } diff --git a/apps/opencs/view/render/worldspacewidget.hpp b/apps/opencs/view/render/worldspacewidget.hpp index 4830d772b9..fb2f61f9ca 100644 --- a/apps/opencs/view/render/worldspacewidget.hpp +++ b/apps/opencs/view/render/worldspacewidget.hpp @@ -80,7 +80,7 @@ namespace CSVRender virtual bool handleDrop (const std::vector& data, DropType type); - virtual unsigned int getElementMask() const; + virtual unsigned int getVisibilityMask() const; protected: From fe385214e4d45969ababbebe76d419f4af6e602a Mon Sep 17 00:00:00 2001 From: Evgenii Babinets Date: Mon, 10 Nov 2014 02:42:44 -0500 Subject: [PATCH 11/16] Added proper slow fall effect mechanics. --- apps/openmw/mwworld/physicssystem.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 80cccd063c..eecc4a02db 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -472,10 +472,9 @@ namespace MWWorld physicActor->setInertialForce(Ogre::Vector3(0.0f)); else { - float diff = time*-627.2f; + inertia.z += time * -627.2f; if (inertia.z < 0) - diff *= slowFall; - inertia.z += diff; + inertia.z *= slowFall; physicActor->setInertialForce(inertia); } physicActor->setOnGround(isOnGround); @@ -865,8 +864,8 @@ namespace MWWorld continue; physicActor->setCanWaterWalk(waterCollision); - // 100 points of slowfall reduce gravity by 90% (this is just a guess) - float slowFall = 1-std::min(std::max(0.f, (effects.get(ESM::MagicEffect::SlowFall).getMagnitude() / 100.f) * 0.9f), 0.9f); + // Slow fall reduces fall speed by a factor of (effect magnitude / 200) + float slowFall = 1.f - std::max(0.f, std::min(1.f, effects.get(ESM::MagicEffect::SlowFall).getMagnitude() * 0.005f)); Ogre::Vector3 newpos = MovementSolver::move(iter->first, iter->second, mTimeAccum, world->isFlying(iter->first), From 3828e3fae506d71488dd0065061815291067ff21 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 10 Nov 2014 16:37:31 +0100 Subject: [PATCH 12/16] updated credits file --- credits.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/credits.txt b/credits.txt index 10065b44d1..d7fe230c7c 100644 --- a/credits.txt +++ b/credits.txt @@ -46,6 +46,7 @@ Jannik Heller (scrawl) Jason Hooks (jhooks) jeaye Jeffrey Haines (Jyby) +Jengerer Joel Graff (graffy) John Blomberg (fstp) Jordan Ayers From 2acf446f18a042eb245febc87333a8eab16588b1 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 11 Nov 2014 15:58:22 +0100 Subject: [PATCH 13/16] added edit mode button to scene toolbar --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/view/render/editmode.cpp | 19 +++++++++++ apps/opencs/view/render/editmode.hpp | 28 ++++++++++++++++ apps/opencs/view/render/worldspacewidget.cpp | 34 +++++++++++++++++++- apps/opencs/view/render/worldspacewidget.hpp | 15 +++++++++ apps/opencs/view/world/scenesubview.cpp | 3 ++ 6 files changed, 99 insertions(+), 2 deletions(-) create mode 100644 apps/opencs/view/render/editmode.cpp create mode 100644 apps/opencs/view/render/editmode.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 9d8a22f7c6..5990c09420 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -77,7 +77,7 @@ opencs_units (view/widget opencs_units (view/render scenewidget worldspacewidget pagedworldspacewidget unpagedworldspacewidget - previewwidget + previewwidget editmode ) opencs_units_noqt (view/render diff --git a/apps/opencs/view/render/editmode.cpp b/apps/opencs/view/render/editmode.cpp new file mode 100644 index 0000000000..51a137d3b3 --- /dev/null +++ b/apps/opencs/view/render/editmode.cpp @@ -0,0 +1,19 @@ + +#include "editmode.hpp" + +#include "worldspacewidget.hpp" + +CSVRender::EditMode::EditMode (WorldspaceWidget *worldspaceWidget, const QIcon& icon, + unsigned int mask, const QString& tooltip, QWidget *parent) +: ModeButton (icon, tooltip, parent), mWorldspaceWidget (worldspaceWidget), mMask (mask) +{} + +unsigned int CSVRender::EditMode::getInteractionMask() const +{ + return mMask; +} + +void CSVRender::EditMode::activate (CSVWidget::SceneToolbar *toolbar) +{ + mWorldspaceWidget->setInteractionMask (mMask); +} \ No newline at end of file diff --git a/apps/opencs/view/render/editmode.hpp b/apps/opencs/view/render/editmode.hpp new file mode 100644 index 0000000000..c3192f8ea5 --- /dev/null +++ b/apps/opencs/view/render/editmode.hpp @@ -0,0 +1,28 @@ +#ifndef CSV_RENDER_EDITMODE_H +#define CSV_RENDER_EDITMODE_H + +#include "../widget/modebutton.hpp" + +namespace CSVRender +{ + class WorldspaceWidget; + + class EditMode : public CSVWidget::ModeButton + { + Q_OBJECT + + WorldspaceWidget *mWorldspaceWidget; + unsigned int mMask; + + public: + + EditMode (WorldspaceWidget *worldspaceWidget, const QIcon& icon, unsigned int mask, + const QString& tooltip = "", QWidget *parent = 0); + + unsigned int getInteractionMask() const; + + virtual void activate (CSVWidget::SceneToolbar *toolbar); + }; +} + +#endif diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index 0a8d5e364e..e70b456352 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -16,10 +16,11 @@ #include "../widget/scenetooltoggle.hpp" #include "../widget/scenetoolrun.hpp" +#include "editmode.hpp" #include "elements.hpp" CSVRender::WorldspaceWidget::WorldspaceWidget (CSMDoc::Document& document, QWidget* parent) -: SceneWidget (parent), mDocument(document), mSceneElements(0), mRun(0) +: SceneWidget (parent), mDocument(document), mSceneElements(0), mRun(0), mInteractionMask (0) { setAcceptDrops(true); @@ -162,6 +163,16 @@ CSVWidget::SceneToolRun *CSVRender::WorldspaceWidget::makeRunTool ( return mRun; } +CSVWidget::SceneToolMode *CSVRender::WorldspaceWidget::makeEditModeSelector ( + CSVWidget::SceneToolbar *parent) +{ + CSVWidget::SceneToolMode *tool = new CSVWidget::SceneToolMode (parent, "Edit Mode"); + + addEditModeSelectorButtons (tool); + + return tool; +} + CSVRender::WorldspaceWidget::DropType CSVRender::WorldspaceWidget::getDropType ( const std::vector< CSMWorld::UniversalId >& data) { @@ -221,6 +232,16 @@ unsigned int CSVRender::WorldspaceWidget::getVisibilityMask() const return mSceneElements->getSelection(); } +void CSVRender::WorldspaceWidget::setInteractionMask (unsigned int mask) +{ + mInteractionMask = mask | Element_CellMarker | Element_CellArrow; +} + +unsigned int CSVRender::WorldspaceWidget::getInteractionMask() const +{ + return mInteractionMask & getVisibilityMask(); +} + void CSVRender::WorldspaceWidget::addVisibilitySelectorButtons ( CSVWidget::SceneToolToggle *tool) { @@ -230,6 +251,17 @@ void CSVRender::WorldspaceWidget::addVisibilitySelectorButtons ( tool->addButton (":armor.png", Element_Pathgrid, ":armor.png", "Pathgrid"); } +void CSVRender::WorldspaceWidget::addEditModeSelectorButtons (CSVWidget::SceneToolMode *tool) +{ + /// \todo replace EditMode with suitable subclasses + tool->addButton ( + new EditMode (this, QIcon (":armor.png"), Element_Reference, "Reference editing"), + "object"); + tool->addButton ( + new EditMode (this, QIcon (":armor.png"), Element_Pathgrid, "Pathgrid editing"), + "pathgrid"); +} + CSMDoc::Document& CSVRender::WorldspaceWidget::getDocument() { return mDocument; diff --git a/apps/opencs/view/render/worldspacewidget.hpp b/apps/opencs/view/render/worldspacewidget.hpp index fb2f61f9ca..9477b29912 100644 --- a/apps/opencs/view/render/worldspacewidget.hpp +++ b/apps/opencs/view/render/worldspacewidget.hpp @@ -33,6 +33,7 @@ namespace CSVRender CSVWidget::SceneToolToggle *mSceneElements; CSVWidget::SceneToolRun *mRun; CSMDoc::Document& mDocument; + unsigned int mInteractionMask; public: @@ -67,6 +68,10 @@ namespace CSVRender /// that is the responsibility of the calling function. CSVWidget::SceneToolRun *makeRunTool (CSVWidget::SceneToolbar *parent); + /// \attention The created tool is not added to the toolbar (via addTool). Doing + /// that is the responsibility of the calling function. + CSVWidget::SceneToolMode *makeEditModeSelector (CSVWidget::SceneToolbar *parent); + void selectDefaultNavigationMode(); static DropType getDropType(const std::vector& data); @@ -82,10 +87,20 @@ namespace CSVRender virtual unsigned int getVisibilityMask() const; + /// \note This function will implicitly add elements that are independent of the + /// selected edit mode. + virtual void setInteractionMask (unsigned int mask); + + /// \note This function will only return those elements that are both visible and + /// marked for interaction. + unsigned int getInteractionMask() const; + protected: virtual void addVisibilitySelectorButtons (CSVWidget::SceneToolToggle *tool); + virtual void addEditModeSelectorButtons (CSVWidget::SceneToolMode *tool); + CSMDoc::Document& getDocument(); virtual void updateOverlay(); diff --git a/apps/opencs/view/world/scenesubview.cpp b/apps/opencs/view/world/scenesubview.cpp index ce68da3623..f2c987b0f7 100644 --- a/apps/opencs/view/world/scenesubview.cpp +++ b/apps/opencs/view/world/scenesubview.cpp @@ -125,6 +125,9 @@ CSVWidget::SceneToolbar* CSVWorld::SceneSubView::makeToolbar (CSVRender::Worldsp CSVWidget::SceneToolRun *runTool = widget->makeRunTool (toolbar); toolbar->addTool (runTool); + CSVWidget::SceneToolMode *editModeTool = widget->makeEditModeSelector (toolbar); + toolbar->addTool (editModeTool); + return toolbar; } From b86148411ba04167d847130553de4f84092a2302 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Wed, 12 Nov 2014 14:02:08 +1100 Subject: [PATCH 14/16] Fix for issue #2051. Not perfect (can get into a lock in some situations) but usable. --- apps/opencs/view/render/navigation1st.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/apps/opencs/view/render/navigation1st.cpp b/apps/opencs/view/render/navigation1st.cpp index 91f88634af..5d9a034688 100644 --- a/apps/opencs/view/render/navigation1st.cpp +++ b/apps/opencs/view/render/navigation1st.cpp @@ -44,10 +44,11 @@ bool CSVRender::Navigation1st::mouseMoved (const QPoint& delta, int mode) float deltaPitch = getFactor (true) * delta.y(); Ogre::Radian newPitch = oldPitch + Ogre::Degree (deltaPitch); - Ogre::Radian limit (Ogre::Math::PI/2-0.5); - - if ((deltaPitch>0 && newPitch-limit)) + if ((deltaPitch>0 && newPitchOgre::Radian(0.5))) + { mCamera->pitch (Ogre::Degree (deltaPitch)); + } } return true; From b7f8f848a8af3fa22843a501e26e6d55de720bfb Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 13 Nov 2014 10:45:59 +0100 Subject: [PATCH 15/16] added edit modes for exteriors --- .../view/render/pagedworldspacewidget.cpp | 22 +++++++++++++++++++ .../view/render/pagedworldspacewidget.hpp | 2 ++ 2 files changed, 24 insertions(+) diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index 9b42feb38f..a2360f9478 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.cpp +++ b/apps/opencs/view/render/pagedworldspacewidget.cpp @@ -21,7 +21,9 @@ #include "../../model/world/idtable.hpp" #include "../widget/scenetooltoggle.hpp" +#include "../widget/scenetoolmode.hpp" +#include "editmode.hpp" #include "elements.hpp" bool CSVRender::PagedWorldspaceWidget::adjustCells() @@ -194,6 +196,26 @@ void CSVRender::PagedWorldspaceWidget::mouseDoubleClickEvent (QMouseEvent *event } } +void CSVRender::PagedWorldspaceWidget::addEditModeSelectorButtons ( + CSVWidget::SceneToolMode *tool) +{ + WorldspaceWidget::addEditModeSelectorButtons (tool); + + /// \todo replace EditMode with suitable subclasses + tool->addButton ( + new EditMode (this, QIcon (":armor.png"), Element_Reference, "Terrain shape editing"), + "terrain-shape"); + tool->addButton ( + new EditMode (this, QIcon (":armor.png"), Element_Reference, "Terrain texture editing"), + "terrain-texture"); + tool->addButton ( + new EditMode (this, QIcon (":armor.png"), Element_Reference, "Terrain vertex paint editing"), + "terrain-vertex"); + tool->addButton ( + new EditMode (this, QIcon (":armor.png"), Element_Reference, "Terrain movement"), + "terrain-move"); +} + void CSVRender::PagedWorldspaceWidget::updateOverlay() { if(getCamera()->getViewport()) diff --git a/apps/opencs/view/render/pagedworldspacewidget.hpp b/apps/opencs/view/render/pagedworldspacewidget.hpp index ec2d5dc240..bc627ed422 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.hpp +++ b/apps/opencs/view/render/pagedworldspacewidget.hpp @@ -79,6 +79,8 @@ namespace CSVRender protected: + virtual void addEditModeSelectorButtons (CSVWidget::SceneToolMode *tool); + virtual void updateOverlay(); virtual void mouseReleaseEvent (QMouseEvent *event); From 5eb9fd81e1dc620bdf9c14cedd230ffa8813545b Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 13 Nov 2014 12:09:10 +0100 Subject: [PATCH 16/16] use placeholder icons in OpenCS when no proper icon is available --- apps/opencs/model/world/universalid.cpp | 2 +- .../view/render/pagedworldspacewidget.cpp | 16 ++++++++-------- apps/opencs/view/render/worldspacewidget.cpp | 16 ++++++++-------- credits.txt | 2 +- files/opencs/placeholder.png | Bin 0 -> 2383 bytes files/opencs/resources.qrc | 1 + 6 files changed, 19 insertions(+), 18 deletions(-) create mode 100644 files/opencs/placeholder.png diff --git a/apps/opencs/model/world/universalid.cpp b/apps/opencs/model/world/universalid.cpp index f2ed87d61a..190ea87d8a 100644 --- a/apps/opencs/model/world/universalid.cpp +++ b/apps/opencs/model/world/universalid.cpp @@ -328,7 +328,7 @@ std::string CSMWorld::UniversalId::getIcon() const for (int i=0; typeData[i].mName; ++i) if (typeData[i].mType==mType) - return typeData[i].mIcon ? typeData[i].mIcon : ""; + return typeData[i].mIcon ? typeData[i].mIcon : ":placeholder"; throw std::logic_error ("failed to retrieve UniversalId type icon"); } diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index 66ea26f11a..e5d5428581 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.cpp +++ b/apps/opencs/view/render/pagedworldspacewidget.cpp @@ -219,16 +219,16 @@ void CSVRender::PagedWorldspaceWidget::addEditModeSelectorButtons ( /// \todo replace EditMode with suitable subclasses tool->addButton ( - new EditMode (this, QIcon (":armor.png"), Element_Reference, "Terrain shape editing"), + new EditMode (this, QIcon (":placeholder"), Element_Reference, "Terrain shape editing"), "terrain-shape"); tool->addButton ( - new EditMode (this, QIcon (":armor.png"), Element_Reference, "Terrain texture editing"), + new EditMode (this, QIcon (":placeholder"), Element_Reference, "Terrain texture editing"), "terrain-texture"); tool->addButton ( - new EditMode (this, QIcon (":armor.png"), Element_Reference, "Terrain vertex paint editing"), + new EditMode (this, QIcon (":placeholder"), Element_Reference, "Terrain vertex paint editing"), "terrain-vertex"); tool->addButton ( - new EditMode (this, QIcon (":armor.png"), Element_Reference, "Terrain movement"), + new EditMode (this, QIcon (":placeholder"), Element_Reference, "Terrain movement"), "terrain-move"); } @@ -476,12 +476,12 @@ CSVWidget::SceneToolToggle *CSVRender::PagedWorldspaceWidget::makeControlVisibil CSVWidget::SceneToolbar *parent) { mControlElements = new CSVWidget::SceneToolToggle (parent, - "Controls & Guides Visibility", ":door.png"); + "Controls & Guides Visibility", ":placeholder"); - mControlElements->addButton (":activator.png", Element_CellMarker, ":activator.png", + mControlElements->addButton (":placeholder", Element_CellMarker, ":placeholder", "Cell marker"); - mControlElements->addButton (":armor.png", Element_CellArrow, ":armor.png", "Cell arrows"); - mControlElements->addButton (":armor.png", Element_CellBorder, ":armor.png", "Cell border"); + mControlElements->addButton (":placeholder", Element_CellArrow, ":placeholder", "Cell arrows"); + mControlElements->addButton (":placeholder", Element_CellBorder, ":placeholder", "Cell border"); mControlElements->setSelection (0xffffffff); diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index 534325e848..6c6acd22dc 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -130,7 +130,7 @@ CSVWidget::SceneToolMode *CSVRender::WorldspaceWidget::makeNavigationSelector ( CSVWidget::SceneToolToggle *CSVRender::WorldspaceWidget::makeSceneVisibilitySelector (CSVWidget::SceneToolbar *parent) { mSceneElements= new CSVWidget::SceneToolToggle (parent, - "Scene Element Visibility", ":door.png"); + "Scene Element Visibility", ":placeholder"); addVisibilitySelectorButtons (mSceneElements); @@ -172,7 +172,7 @@ CSVWidget::SceneToolRun *CSVRender::WorldspaceWidget::makeRunTool ( std::sort (profiles.begin(), profiles.end()); mRun = new CSVWidget::SceneToolRun (parent, "Run OpenMW from the current camera position", - ":door.png", ":faction.png", profiles); + ":placeholder", ":placeholder", profiles); connect (mRun, SIGNAL (runRequest (const std::string&)), this, SLOT (runRequest (const std::string&))); @@ -262,20 +262,20 @@ unsigned int CSVRender::WorldspaceWidget::getInteractionMask() const void CSVRender::WorldspaceWidget::addVisibilitySelectorButtons ( CSVWidget::SceneToolToggle *tool) { - tool->addButton (":activator.png", Element_Reference, ":activator.png", "References"); - tool->addButton (":armor.png", Element_Terrain, ":armor.png", "Terrain"); - tool->addButton (":armor.png", Element_Water, ":armor.png", "Water"); - tool->addButton (":armor.png", Element_Pathgrid, ":armor.png", "Pathgrid"); + tool->addButton (":placeholder", Element_Reference, ":placeholder", "References"); + tool->addButton (":placeholder", Element_Terrain, ":placeholder", "Terrain"); + tool->addButton (":placeholder", Element_Water, ":placeholder", "Water"); + tool->addButton (":placeholder", Element_Pathgrid, ":placeholder", "Pathgrid"); } void CSVRender::WorldspaceWidget::addEditModeSelectorButtons (CSVWidget::SceneToolMode *tool) { /// \todo replace EditMode with suitable subclasses tool->addButton ( - new EditMode (this, QIcon (":armor.png"), Element_Reference, "Reference editing"), + new EditMode (this, QIcon (":placeholder"), Element_Reference, "Reference editing"), "object"); tool->addButton ( - new EditMode (this, QIcon (":armor.png"), Element_Pathgrid, "Pathgrid editing"), + new EditMode (this, QIcon (":placeholder"), Element_Pathgrid, "Pathgrid editing"), "pathgrid"); } diff --git a/credits.txt b/credits.txt index d7fe230c7c..c6a5c71696 100644 --- a/credits.txt +++ b/credits.txt @@ -140,7 +140,7 @@ Sadler Artwork: Necrod - OpenMW Logo Mickey Lyle (raevol) - Wordpress Theme -Tom Koenderink (Okulo), SirHerrbatka, crysthala - OpenMW Editor Icons +Tom Koenderink (Okulo), SirHerrbatka, crysthala, Shnatsel - OpenMW Editor Icons Inactive Contributors: Ardekantur diff --git a/files/opencs/placeholder.png b/files/opencs/placeholder.png new file mode 100644 index 0000000000000000000000000000000000000000..1d3df3c47d76bd213e958a44e752e4693e537f32 GIT binary patch literal 2383 zcmV-V39$BwP)DsmHZ}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_Fedit-preview.png edit-clone.png add.png + placeholder.png raster/startup/big/create-addon.png