mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-02-01 02:15:32 +00:00
Merge remote-tracking branch 'refs/remotes/master/master' into NonTableFields
Conflicts: apps/opencs/CMakeLists.txt
This commit is contained in:
commit
cdac934315
135 changed files with 2109 additions and 827 deletions
|
@ -12,7 +12,7 @@ set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/)
|
||||||
message(STATUS "Configuring OpenMW...")
|
message(STATUS "Configuring OpenMW...")
|
||||||
|
|
||||||
set(OPENMW_VERSION_MAJOR 0)
|
set(OPENMW_VERSION_MAJOR 0)
|
||||||
set(OPENMW_VERSION_MINOR 30)
|
set(OPENMW_VERSION_MINOR 31)
|
||||||
set(OPENMW_VERSION_RELEASE 0)
|
set(OPENMW_VERSION_RELEASE 0)
|
||||||
|
|
||||||
set(OPENMW_VERSION_COMMITHASH "")
|
set(OPENMW_VERSION_COMMITHASH "")
|
||||||
|
@ -325,12 +325,14 @@ else ()
|
||||||
add_definitions(-DOGRE_PLUGIN_DEBUG_SUFFIX="_d")
|
add_definitions(-DOGRE_PLUGIN_DEBUG_SUFFIX="_d")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
add_definitions(-DOGRE_PLUGIN_DIR_REL="${OGRE_PLUGIN_DIR_REL}")
|
|
||||||
add_definitions(-DOGRE_PLUGIN_DIR_DBG="${OGRE_PLUGIN_DIR_DBG}")
|
|
||||||
if (APPLE AND OPENMW_OSX_DEPLOYMENT)
|
if (APPLE AND OPENMW_OSX_DEPLOYMENT)
|
||||||
# make it empty so plugin loading code can check this and try to find plugins inside app bundle
|
# make it empty so plugin loading code can check this and try to find plugins inside app bundle
|
||||||
add_definitions(-DOGRE_PLUGIN_DIR="")
|
add_definitions(-DOGRE_PLUGIN_DIR="")
|
||||||
else()
|
else()
|
||||||
|
if (NOT DEFINED ${OGRE_PLUGIN_DIR})
|
||||||
|
set(OGRE_PLUGIN_DIR ${OGRE_PLUGIN_DIR_REL})
|
||||||
|
endif()
|
||||||
|
|
||||||
add_definitions(-DOGRE_PLUGIN_DIR="${OGRE_PLUGIN_DIR}")
|
add_definitions(-DOGRE_PLUGIN_DIR="${OGRE_PLUGIN_DIR}")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
|
@ -249,6 +249,9 @@ void loadCell(ESM::Cell &cell, ESM::ESMReader &esm, Arguments& info)
|
||||||
std::cout << " Refnum: " << ref.mRefNum.mIndex << std::endl;
|
std::cout << " Refnum: " << ref.mRefNum.mIndex << std::endl;
|
||||||
std::cout << " ID: '" << ref.mRefID << "'\n";
|
std::cout << " ID: '" << ref.mRefID << "'\n";
|
||||||
std::cout << " Owner: '" << ref.mOwner << "'\n";
|
std::cout << " Owner: '" << ref.mOwner << "'\n";
|
||||||
|
std::cout << " Global: '" << ref.mGlobalVariable << "'" << std::endl;
|
||||||
|
std::cout << " Faction: '" << ref.mFaction << "'" << std::endl;
|
||||||
|
std::cout << " Faction rank: '" << ref.mFactionRank << "'" << std::endl;
|
||||||
std::cout << " Enchantment charge: '" << ref.mEnchantmentCharge << "'\n";
|
std::cout << " Enchantment charge: '" << ref.mEnchantmentCharge << "'\n";
|
||||||
std::cout << " Uses/health: '" << ref.mCharge << "'\n";
|
std::cout << " Uses/health: '" << ref.mCharge << "'\n";
|
||||||
std::cout << " Gold value: '" << ref.mGoldValue << "'\n";
|
std::cout << " Gold value: '" << ref.mGoldValue << "'\n";
|
||||||
|
|
|
@ -513,7 +513,7 @@ void Record<ESM::Cell>::print()
|
||||||
else
|
else
|
||||||
std::cout << " Map Color: " << boost::format("0x%08X") % mData.mMapColor << std::endl;
|
std::cout << " Map Color: " << boost::format("0x%08X") % mData.mMapColor << std::endl;
|
||||||
std::cout << " Water Level Int: " << mData.mWaterInt << std::endl;
|
std::cout << " Water Level Int: " << mData.mWaterInt << std::endl;
|
||||||
std::cout << " NAM0: " << mData.mNAM0 << std::endl;
|
std::cout << " RefId counter: " << mData.mRefIdCounter << std::endl;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -61,8 +61,13 @@ opencs_hdrs_noqt (view/doc
|
||||||
|
|
||||||
opencs_units (view/world
|
opencs_units (view/world
|
||||||
table tablesubview scriptsubview util regionmapsubview tablebottombox creator genericcreator
|
table tablesubview scriptsubview util regionmapsubview tablebottombox creator genericcreator
|
||||||
cellcreator referenceablecreator referencecreator scenesubview scenetoolbar scenetool
|
cellcreator referenceablecreator referencecreator scenesubview
|
||||||
scenetoolmode infocreator scriptedit dialoguesubview previewsubview regionmap dragrecordtable nestedtable
|
infocreator scriptedit dialoguesubview previewsubview regionmap dragrecordtable nestedtable
|
||||||
|
)
|
||||||
|
|
||||||
|
opencs_units_noqt (view/world
|
||||||
|
subviews enumdelegate vartypedelegate recordstatusdelegate idtypedelegate datadisplaydelegate
|
||||||
|
scripthighlighter idvalidator dialoguecreator
|
||||||
)
|
)
|
||||||
|
|
||||||
opencs_units (view/render
|
opencs_units (view/render
|
||||||
|
@ -75,12 +80,10 @@ opencs_units_noqt (view/render
|
||||||
lightingbright object cell
|
lightingbright object cell
|
||||||
)
|
)
|
||||||
|
|
||||||
opencs_units_noqt (view/world
|
opencs_units (view/widget
|
||||||
subviews enumdelegate vartypedelegate recordstatusdelegate idtypedelegate datadisplaydelegate
|
scenetoolbar scenetool scenetoolmode pushbutton
|
||||||
scripthighlighter idvalidator dialoguecreator
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
opencs_units (view/tools
|
opencs_units (view/tools
|
||||||
reportsubview
|
reportsubview
|
||||||
)
|
)
|
||||||
|
|
|
@ -977,13 +977,13 @@ namespace CSMWorld
|
||||||
|
|
||||||
virtual QVariant get (const Record<ESXRecordT>& record) const
|
virtual QVariant get (const Record<ESXRecordT>& record) const
|
||||||
{
|
{
|
||||||
return record.get().mFactIndex;
|
return record.get().mFactionRank;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void set (Record<ESXRecordT>& record, const QVariant& data)
|
virtual void set (Record<ESXRecordT>& record, const QVariant& data)
|
||||||
{
|
{
|
||||||
ESXRecordT record2 = record.get();
|
ESXRecordT record2 = record.get();
|
||||||
record2.mFactIndex = data.toInt();
|
record2.mFactionRank = data.toInt();
|
||||||
record.setModified (record2);
|
record.setModified (record2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -81,6 +81,7 @@ QWidget *CSVDoc::StartupDialogue::createTools()
|
||||||
|
|
||||||
config->setSizePolicy (QSizePolicy (QSizePolicy::Fixed, QSizePolicy::Fixed));
|
config->setSizePolicy (QSizePolicy (QSizePolicy::Fixed, QSizePolicy::Fixed));
|
||||||
config->setIcon (QIcon (":startup/configure"));
|
config->setIcon (QIcon (":startup/configure"));
|
||||||
|
config->setToolTip ("Open user settings");
|
||||||
|
|
||||||
layout->addWidget (config);
|
layout->addWidget (config);
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#include <QEvent>
|
#include <QEvent>
|
||||||
#include <QResizeEvent>
|
#include <QResizeEvent>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
|
#include <QShortcut>
|
||||||
|
|
||||||
#include <OgreRoot.h>
|
#include <OgreRoot.h>
|
||||||
#include <OgreRenderWindow.h>
|
#include <OgreRenderWindow.h>
|
||||||
|
@ -11,7 +12,7 @@
|
||||||
#include <OgreSceneNode.h>
|
#include <OgreSceneNode.h>
|
||||||
#include <OgreViewport.h>
|
#include <OgreViewport.h>
|
||||||
|
|
||||||
#include "../world/scenetoolmode.hpp"
|
#include "../widget/scenetoolmode.hpp"
|
||||||
|
|
||||||
#include "navigation.hpp"
|
#include "navigation.hpp"
|
||||||
#include "lighting.hpp"
|
#include "lighting.hpp"
|
||||||
|
@ -51,16 +52,34 @@ namespace CSVRender
|
||||||
QTimer *timer = new QTimer (this);
|
QTimer *timer = new QTimer (this);
|
||||||
|
|
||||||
connect (timer, SIGNAL (timeout()), this, SLOT (update()));
|
connect (timer, SIGNAL (timeout()), this, SLOT (update()));
|
||||||
timer->start (20); /// \todo make this configurable
|
timer->start (20); ///< \todo make this configurable
|
||||||
|
|
||||||
|
/// \todo make shortcut configurable
|
||||||
|
QShortcut *focusToolbar = new QShortcut (Qt::Key_T, this, 0, 0, Qt::WidgetWithChildrenShortcut);
|
||||||
|
connect (focusToolbar, SIGNAL (activated()), this, SIGNAL (focusToolbarRequest()));
|
||||||
}
|
}
|
||||||
|
|
||||||
CSVWorld::SceneToolMode *SceneWidget::makeLightingSelector (CSVWorld::SceneToolbar *parent)
|
CSVWidget::SceneToolMode *SceneWidget::makeLightingSelector (CSVWidget::SceneToolbar *parent)
|
||||||
{
|
{
|
||||||
CSVWorld::SceneToolMode *tool = new CSVWorld::SceneToolMode (parent);
|
CSVWidget::SceneToolMode *tool = new CSVWidget::SceneToolMode (parent, "Lighting Mode");
|
||||||
|
|
||||||
tool->addButton (":door.png", "day"); /// \todo replace icons
|
/// \todo replace icons
|
||||||
tool->addButton (":GMST.png", "night");
|
tool->addButton (":door.png", "day",
|
||||||
tool->addButton (":Info.png", "bright");
|
"Day"
|
||||||
|
"<ul><li>Cell specific ambient in interiors</li>"
|
||||||
|
"<li>Low ambient in exteriors</li>"
|
||||||
|
"<li>Strong directional light source/lir>"
|
||||||
|
"<li>This mode closely resembles day time in-game</li></ul>");
|
||||||
|
tool->addButton (":GMST.png", "night",
|
||||||
|
"Night"
|
||||||
|
"<ul><li>Cell specific ambient in interiors</li>"
|
||||||
|
"<li>Low ambient in exteriors</li>"
|
||||||
|
"<li>Weak directional light source</li>"
|
||||||
|
"<li>This mode closely resembles night time in-game</li></ul>");
|
||||||
|
tool->addButton (":Info.png", "bright",
|
||||||
|
"Bright"
|
||||||
|
"<ul><li>Maximum ambient</li>"
|
||||||
|
"<li>Strong directional light source</li></ul>");
|
||||||
|
|
||||||
connect (tool, SIGNAL (modeChanged (const std::string&)),
|
connect (tool, SIGNAL (modeChanged (const std::string&)),
|
||||||
this, SLOT (selectLightingMode (const std::string&)));
|
this, SLOT (selectLightingMode (const std::string&)));
|
||||||
|
@ -347,6 +366,9 @@ namespace CSVRender
|
||||||
|
|
||||||
mLighting = lighting;
|
mLighting = lighting;
|
||||||
mLighting->activate (mSceneMgr, mHasDefaultAmbient ? &mDefaultAmbient : 0);
|
mLighting->activate (mSceneMgr, mHasDefaultAmbient ? &mDefaultAmbient : 0);
|
||||||
|
|
||||||
|
if (mWindow)
|
||||||
|
mWindow->update();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneWidget::selectLightingMode (const std::string& mode)
|
void SceneWidget::selectLightingMode (const std::string& mode)
|
||||||
|
|
|
@ -16,7 +16,7 @@ namespace Ogre
|
||||||
class RenderWindow;
|
class RenderWindow;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace CSVWorld
|
namespace CSVWidget
|
||||||
{
|
{
|
||||||
class SceneToolMode;
|
class SceneToolMode;
|
||||||
class SceneToolbar;
|
class SceneToolbar;
|
||||||
|
@ -38,7 +38,7 @@ namespace CSVRender
|
||||||
|
|
||||||
QPaintEngine* paintEngine() const;
|
QPaintEngine* paintEngine() const;
|
||||||
|
|
||||||
CSVWorld::SceneToolMode *makeLightingSelector (CSVWorld::SceneToolbar *parent);
|
CSVWidget::SceneToolMode *makeLightingSelector (CSVWidget::SceneToolbar *parent);
|
||||||
///< \attention The created tool is not added to the toolbar (via addTool). Doing that
|
///< \attention The created tool is not added to the toolbar (via addTool). Doing that
|
||||||
/// is the responsibility of the calling function.
|
/// is the responsibility of the calling function.
|
||||||
|
|
||||||
|
@ -111,6 +111,10 @@ namespace CSVRender
|
||||||
void update();
|
void update();
|
||||||
|
|
||||||
void selectLightingMode (const std::string& mode);
|
void selectLightingMode (const std::string& mode);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
|
||||||
|
void focusToolbarRequest();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,8 +7,9 @@
|
||||||
|
|
||||||
#include <QtGui/qevent.h>
|
#include <QtGui/qevent.h>
|
||||||
|
|
||||||
#include "../world/scenetoolmode.hpp"
|
#include "../../model/world/universalid.hpp"
|
||||||
#include <apps/opencs/model/world/universalid.hpp>
|
|
||||||
|
#include "../widget/scenetoolmode.hpp"
|
||||||
|
|
||||||
CSVRender::WorldspaceWidget::WorldspaceWidget (CSMDoc::Document& document, QWidget* parent)
|
CSVRender::WorldspaceWidget::WorldspaceWidget (CSMDoc::Document& document, QWidget* parent)
|
||||||
: SceneWidget (parent), mDocument(document)
|
: SceneWidget (parent), mDocument(document)
|
||||||
|
@ -53,14 +54,39 @@ void CSVRender::WorldspaceWidget::selectDefaultNavigationMode()
|
||||||
setNavigation (&m1st);
|
setNavigation (&m1st);
|
||||||
}
|
}
|
||||||
|
|
||||||
CSVWorld::SceneToolMode *CSVRender::WorldspaceWidget::makeNavigationSelector (
|
CSVWidget::SceneToolMode *CSVRender::WorldspaceWidget::makeNavigationSelector (
|
||||||
CSVWorld::SceneToolbar *parent)
|
CSVWidget::SceneToolbar *parent)
|
||||||
{
|
{
|
||||||
CSVWorld::SceneToolMode *tool = new CSVWorld::SceneToolMode (parent);
|
CSVWidget::SceneToolMode *tool = new CSVWidget::SceneToolMode (parent, "Camera Mode");
|
||||||
|
|
||||||
tool->addButton (":door.png", "1st"); /// \todo replace icons
|
/// \todo replace icons
|
||||||
tool->addButton (":GMST.png", "free");
|
/// \todo consider user-defined button-mapping
|
||||||
tool->addButton (":Info.png", "orbit");
|
tool->addButton (":door.png", "1st",
|
||||||
|
"First Person"
|
||||||
|
"<ul><li>Mouse-Look while holding the left button</li>"
|
||||||
|
"<li>WASD movement keys</li>"
|
||||||
|
"<li>Mouse wheel moves the camera forawrd/backward</li>"
|
||||||
|
"<li>Stafing (also vertically) by holding the left mouse button and control</li>"
|
||||||
|
"<li>Camera is held upright</li>"
|
||||||
|
"<li>Hold shift to speed up movement</li>"
|
||||||
|
"</ul>");
|
||||||
|
tool->addButton (":GMST.png", "free",
|
||||||
|
"Free Camera"
|
||||||
|
"<ul><li>Mouse-Look while holding the left button</li>"
|
||||||
|
"<li>Stafing (also vertically) via WASD or by holding the left mouse button and control</li>"
|
||||||
|
"<li>Mouse wheel moves the camera forawrd/backward</li>"
|
||||||
|
"<li>Roll camera with Q and E keys</li>"
|
||||||
|
"<li>Hold shift to speed up movement</li>"
|
||||||
|
"</ul>");
|
||||||
|
tool->addButton (":Info.png", "orbit",
|
||||||
|
"Orbiting Camera"
|
||||||
|
"<ul><li>Always facing the centre point</li>"
|
||||||
|
"<li>Rotate around the centre point via WASD or by moving the mouse while holding the left button</li>"
|
||||||
|
"<li>Mouse wheel moves camera away or towards centre point but can not pass through it</li>"
|
||||||
|
"<li>Roll camera with Q and E keys</li>"
|
||||||
|
"<li>Stafing (also vertically) by holding the left mouse button and control (includes relocation of the centre point)</li>"
|
||||||
|
"<li>Hold shift to speed up movement</li>"
|
||||||
|
"</ul>");
|
||||||
|
|
||||||
connect (tool, SIGNAL (modeChanged (const std::string&)),
|
connect (tool, SIGNAL (modeChanged (const std::string&)),
|
||||||
this, SLOT (selectNavigationMode (const std::string&)));
|
this, SLOT (selectNavigationMode (const std::string&)));
|
||||||
|
|
|
@ -13,7 +13,7 @@ namespace CSMWorld
|
||||||
{
|
{
|
||||||
class UniversalId;
|
class UniversalId;
|
||||||
}
|
}
|
||||||
namespace CSVWorld
|
namespace CSVWidget
|
||||||
{
|
{
|
||||||
class SceneToolMode;
|
class SceneToolMode;
|
||||||
class SceneToolbar;
|
class SceneToolbar;
|
||||||
|
@ -49,7 +49,7 @@ namespace CSVRender
|
||||||
|
|
||||||
WorldspaceWidget (CSMDoc::Document& document, QWidget *parent = 0);
|
WorldspaceWidget (CSMDoc::Document& document, QWidget *parent = 0);
|
||||||
|
|
||||||
CSVWorld::SceneToolMode *makeNavigationSelector (CSVWorld::SceneToolbar *parent);
|
CSVWidget::SceneToolMode *makeNavigationSelector (CSVWidget::SceneToolbar *parent);
|
||||||
///< \attention The created tool is not added to the toolbar (via addTool). Doing that
|
///< \attention The created tool is not added to the toolbar (via addTool). Doing that
|
||||||
/// is the responsibility of the calling function.
|
/// is the responsibility of the calling function.
|
||||||
|
|
||||||
|
|
83
apps/opencs/view/widget/pushbutton.cpp
Normal file
83
apps/opencs/view/widget/pushbutton.cpp
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
|
||||||
|
#include "pushbutton.hpp"
|
||||||
|
|
||||||
|
#include <QMouseEvent>
|
||||||
|
#include <QKeyEvent>
|
||||||
|
|
||||||
|
void CSVWidget::PushButton::setExtendedToolTip (const QString& text)
|
||||||
|
{
|
||||||
|
QString tooltip = text;
|
||||||
|
|
||||||
|
if (tooltip.isEmpty())
|
||||||
|
tooltip = "(Tool tip not implemented yet)";
|
||||||
|
|
||||||
|
switch (mType)
|
||||||
|
{
|
||||||
|
case Type_TopMode:
|
||||||
|
|
||||||
|
tooltip +=
|
||||||
|
"<p>(left click to change mode)";
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Type_Mode:
|
||||||
|
|
||||||
|
tooltip +=
|
||||||
|
"<p>(left click to activate,"
|
||||||
|
"<br>shift-left click to activate and keep panel open)";
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
setToolTip (tooltip);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSVWidget::PushButton::keyPressEvent (QKeyEvent *event)
|
||||||
|
{
|
||||||
|
if (event->key()!=Qt::Key_Shift)
|
||||||
|
mKeepOpen = false;
|
||||||
|
|
||||||
|
QPushButton::keyPressEvent (event);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSVWidget::PushButton::keyReleaseEvent (QKeyEvent *event)
|
||||||
|
{
|
||||||
|
if (event->key()==Qt::Key_Return || event->key()==Qt::Key_Enter)
|
||||||
|
{
|
||||||
|
mKeepOpen = event->modifiers() & Qt::ShiftModifier;
|
||||||
|
emit clicked();
|
||||||
|
}
|
||||||
|
|
||||||
|
QPushButton::keyReleaseEvent (event);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSVWidget::PushButton::mouseReleaseEvent (QMouseEvent *event)
|
||||||
|
{
|
||||||
|
mKeepOpen = event->button()==Qt::LeftButton && (event->modifiers() & Qt::ShiftModifier);
|
||||||
|
QPushButton::mouseReleaseEvent (event);
|
||||||
|
}
|
||||||
|
|
||||||
|
CSVWidget::PushButton::PushButton (const QIcon& icon, Type type, const QString& tooltip,
|
||||||
|
QWidget *parent)
|
||||||
|
: QPushButton (icon, "", parent), mKeepOpen (false), mType (type), mToolTip (tooltip)
|
||||||
|
{
|
||||||
|
setCheckable (type==Type_Mode);
|
||||||
|
setExtendedToolTip (tooltip);
|
||||||
|
}
|
||||||
|
|
||||||
|
CSVWidget::PushButton::PushButton (Type type, const QString& tooltip, QWidget *parent)
|
||||||
|
: QPushButton (parent), mKeepOpen (false), mType (type), mToolTip (tooltip)
|
||||||
|
{
|
||||||
|
setCheckable (type==Type_Mode);
|
||||||
|
setExtendedToolTip (tooltip);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CSVWidget::PushButton::hasKeepOpen() const
|
||||||
|
{
|
||||||
|
return mKeepOpen;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString CSVWidget::PushButton::getBaseToolTip() const
|
||||||
|
{
|
||||||
|
return mToolTip;
|
||||||
|
}
|
55
apps/opencs/view/widget/pushbutton.hpp
Normal file
55
apps/opencs/view/widget/pushbutton.hpp
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
#ifndef CSV_WIDGET_PUSHBUTTON_H
|
||||||
|
#define CSV_WIDGET_PUSHBUTTON_H
|
||||||
|
|
||||||
|
#include <QPushButton>
|
||||||
|
|
||||||
|
namespace CSVWidget
|
||||||
|
{
|
||||||
|
class PushButton : public QPushButton
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
enum Type
|
||||||
|
{
|
||||||
|
Type_TopMode, // top level button for mode selector panel
|
||||||
|
Type_Mode // mode button
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
bool mKeepOpen;
|
||||||
|
Type mType;
|
||||||
|
QString mToolTip;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
void setExtendedToolTip (const QString& text);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
virtual void keyPressEvent (QKeyEvent *event);
|
||||||
|
|
||||||
|
virtual void keyReleaseEvent (QKeyEvent *event);
|
||||||
|
|
||||||
|
virtual void mouseReleaseEvent (QMouseEvent *event);
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
/// \param push Do not maintain a toggle state
|
||||||
|
PushButton (const QIcon& icon, Type type, const QString& tooltip = "",
|
||||||
|
QWidget *parent = 0);
|
||||||
|
|
||||||
|
/// \param push Do not maintain a toggle state
|
||||||
|
PushButton (Type type, const QString& tooltip = "",
|
||||||
|
QWidget *parent = 0);
|
||||||
|
|
||||||
|
bool hasKeepOpen() const;
|
||||||
|
|
||||||
|
/// Return tooltip used at construction (without any button-specific modifications)
|
||||||
|
QString getBaseToolTip() const;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -3,7 +3,8 @@
|
||||||
|
|
||||||
#include "scenetoolbar.hpp"
|
#include "scenetoolbar.hpp"
|
||||||
|
|
||||||
CSVWorld::SceneTool::SceneTool (SceneToolbar *parent) : QPushButton (parent)
|
CSVWidget::SceneTool::SceneTool (SceneToolbar *parent)
|
||||||
|
: PushButton (PushButton::Type_TopMode, "", parent)
|
||||||
{
|
{
|
||||||
setSizePolicy (QSizePolicy (QSizePolicy::Fixed, QSizePolicy::Fixed));
|
setSizePolicy (QSizePolicy (QSizePolicy::Fixed, QSizePolicy::Fixed));
|
||||||
setIconSize (QSize (parent->getIconSize(), parent->getIconSize()));
|
setIconSize (QSize (parent->getIconSize(), parent->getIconSize()));
|
||||||
|
@ -12,7 +13,7 @@ CSVWorld::SceneTool::SceneTool (SceneToolbar *parent) : QPushButton (parent)
|
||||||
connect (this, SIGNAL (clicked()), this, SLOT (openRequest()));
|
connect (this, SIGNAL (clicked()), this, SLOT (openRequest()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSVWorld::SceneTool::openRequest()
|
void CSVWidget::SceneTool::openRequest()
|
||||||
{
|
{
|
||||||
showPanel (parentWidget()->mapToGlobal (pos()));
|
showPanel (parentWidget()->mapToGlobal (pos()));
|
||||||
}
|
}
|
|
@ -1,14 +1,14 @@
|
||||||
#ifndef CSV_WORLD_SCENETOOL_H
|
#ifndef CSV_WIDGET_SCENETOOL_H
|
||||||
#define CSV_WORLD_SCENETOOL_H
|
#define CSV_WIDGET_SCENETOOL_H
|
||||||
|
|
||||||
#include <QPushButton>
|
#include "pushbutton.hpp"
|
||||||
|
|
||||||
namespace CSVWorld
|
namespace CSVWidget
|
||||||
{
|
{
|
||||||
class SceneToolbar;
|
class SceneToolbar;
|
||||||
|
|
||||||
///< \brief Tool base class
|
///< \brief Tool base class
|
||||||
class SceneTool : public QPushButton
|
class SceneTool : public PushButton
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
47
apps/opencs/view/widget/scenetoolbar.cpp
Normal file
47
apps/opencs/view/widget/scenetoolbar.cpp
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
|
||||||
|
#include "scenetoolbar.hpp"
|
||||||
|
|
||||||
|
#include <QVBoxLayout>
|
||||||
|
#include <QShortcut>
|
||||||
|
|
||||||
|
#include "scenetool.hpp"
|
||||||
|
|
||||||
|
void CSVWidget::SceneToolbar::focusInEvent (QFocusEvent *event)
|
||||||
|
{
|
||||||
|
QWidget::focusInEvent (event);
|
||||||
|
|
||||||
|
if (mLayout->count())
|
||||||
|
dynamic_cast<QWidgetItem&> (*mLayout->itemAt (0)).widget()->setFocus();
|
||||||
|
}
|
||||||
|
|
||||||
|
CSVWidget::SceneToolbar::SceneToolbar (int buttonSize, QWidget *parent)
|
||||||
|
: QWidget (parent), mButtonSize (buttonSize), mIconSize (buttonSize-6)
|
||||||
|
{
|
||||||
|
setFixedWidth (mButtonSize);
|
||||||
|
|
||||||
|
mLayout = new QVBoxLayout (this);
|
||||||
|
mLayout->setAlignment (Qt::AlignTop);
|
||||||
|
|
||||||
|
mLayout->setContentsMargins (QMargins (0, 0, 0, 0));
|
||||||
|
|
||||||
|
setLayout (mLayout);
|
||||||
|
|
||||||
|
/// \todo make shortcut configurable
|
||||||
|
QShortcut *focusScene = new QShortcut (Qt::Key_T, this, 0, 0, Qt::WidgetWithChildrenShortcut);
|
||||||
|
connect (focusScene, SIGNAL (activated()), this, SIGNAL (focusSceneRequest()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSVWidget::SceneToolbar::addTool (SceneTool *tool)
|
||||||
|
{
|
||||||
|
mLayout->addWidget (tool, 0, Qt::AlignTop);
|
||||||
|
}
|
||||||
|
|
||||||
|
int CSVWidget::SceneToolbar::getButtonSize() const
|
||||||
|
{
|
||||||
|
return mButtonSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CSVWidget::SceneToolbar::getIconSize() const
|
||||||
|
{
|
||||||
|
return mIconSize;
|
||||||
|
}
|
|
@ -1,11 +1,11 @@
|
||||||
#ifndef CSV_WORLD_SCENETOOLBAR_H
|
#ifndef CSV_WIDGET_SCENETOOLBAR_H
|
||||||
#define CSV_WORLD_SCENETOOLBAR_H
|
#define CSV_WIDGET_SCENETOOLBAR_H
|
||||||
|
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
|
|
||||||
class QVBoxLayout;
|
class QVBoxLayout;
|
||||||
|
|
||||||
namespace CSVWorld
|
namespace CSVWidget
|
||||||
{
|
{
|
||||||
class SceneTool;
|
class SceneTool;
|
||||||
|
|
||||||
|
@ -17,6 +17,10 @@ namespace CSVWorld
|
||||||
int mButtonSize;
|
int mButtonSize;
|
||||||
int mIconSize;
|
int mIconSize;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
virtual void focusInEvent (QFocusEvent *event);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
SceneToolbar (int buttonSize, QWidget *parent = 0);
|
SceneToolbar (int buttonSize, QWidget *parent = 0);
|
||||||
|
@ -26,6 +30,10 @@ namespace CSVWorld
|
||||||
int getButtonSize() const;
|
int getButtonSize() const;
|
||||||
|
|
||||||
int getIconSize() const;
|
int getIconSize() const;
|
||||||
|
|
||||||
|
signals:
|
||||||
|
|
||||||
|
void focusSceneRequest();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
86
apps/opencs/view/widget/scenetoolmode.cpp
Normal file
86
apps/opencs/view/widget/scenetoolmode.cpp
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
|
||||||
|
#include "scenetoolmode.hpp"
|
||||||
|
|
||||||
|
#include <QHBoxLayout>
|
||||||
|
#include <QFrame>
|
||||||
|
#include <QSignalMapper>
|
||||||
|
|
||||||
|
#include "scenetoolbar.hpp"
|
||||||
|
#include "pushbutton.hpp"
|
||||||
|
|
||||||
|
void CSVWidget::SceneToolMode::adjustToolTip (const PushButton *activeMode)
|
||||||
|
{
|
||||||
|
QString toolTip = mToolTip;
|
||||||
|
|
||||||
|
toolTip += "<p>Currently selected: " + activeMode->getBaseToolTip();
|
||||||
|
|
||||||
|
toolTip += "<p>(left click to change mode)";
|
||||||
|
|
||||||
|
setToolTip (toolTip);
|
||||||
|
}
|
||||||
|
|
||||||
|
CSVWidget::SceneToolMode::SceneToolMode (SceneToolbar *parent, const QString& toolTip)
|
||||||
|
: SceneTool (parent), mButtonSize (parent->getButtonSize()), mIconSize (parent->getIconSize()),
|
||||||
|
mToolTip (toolTip), mFirst (0)
|
||||||
|
{
|
||||||
|
mPanel = new QFrame (this, Qt::Popup);
|
||||||
|
|
||||||
|
mLayout = new QHBoxLayout (mPanel);
|
||||||
|
|
||||||
|
mLayout->setContentsMargins (QMargins (0, 0, 0, 0));
|
||||||
|
|
||||||
|
mPanel->setLayout (mLayout);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSVWidget::SceneToolMode::showPanel (const QPoint& position)
|
||||||
|
{
|
||||||
|
mPanel->move (position);
|
||||||
|
mPanel->show();
|
||||||
|
|
||||||
|
if (mFirst)
|
||||||
|
mFirst->setFocus (Qt::OtherFocusReason);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
button->setSizePolicy (QSizePolicy (QSizePolicy::Fixed, QSizePolicy::Fixed));
|
||||||
|
button->setIconSize (QSize (mIconSize, mIconSize));
|
||||||
|
button->setFixedSize (mButtonSize, mButtonSize);
|
||||||
|
|
||||||
|
mLayout->addWidget (button);
|
||||||
|
|
||||||
|
mButtons.insert (std::make_pair (button, id));
|
||||||
|
|
||||||
|
connect (button, SIGNAL (clicked()), this, SLOT (selected()));
|
||||||
|
|
||||||
|
if (mButtons.size()==1)
|
||||||
|
{
|
||||||
|
mFirst = button;
|
||||||
|
setIcon (button->icon());
|
||||||
|
button->setChecked (true);
|
||||||
|
adjustToolTip (button);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSVWidget::SceneToolMode::selected()
|
||||||
|
{
|
||||||
|
std::map<PushButton *, std::string>::const_iterator iter =
|
||||||
|
mButtons.find (dynamic_cast<PushButton *> (sender()));
|
||||||
|
|
||||||
|
if (iter!=mButtons.end())
|
||||||
|
{
|
||||||
|
if (!iter->first->hasKeepOpen())
|
||||||
|
mPanel->hide();
|
||||||
|
|
||||||
|
for (std::map<PushButton *, std::string>::const_iterator iter2 = mButtons.begin();
|
||||||
|
iter2!=mButtons.end(); ++iter2)
|
||||||
|
iter2->first->setChecked (iter2==iter);
|
||||||
|
|
||||||
|
setIcon (iter->first->icon());
|
||||||
|
adjustToolTip (iter->first);
|
||||||
|
emit modeChanged (iter->second);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
#ifndef CSV_WORLD_SCENETOOL_MODE_H
|
#ifndef CSV_WIDGET_SCENETOOL_MODE_H
|
||||||
#define CSV_WORLD_SCENETOOL_MODE_H
|
#define CSV_WIDGET_SCENETOOL_MODE_H
|
||||||
|
|
||||||
#include "scenetool.hpp"
|
#include "scenetool.hpp"
|
||||||
|
|
||||||
|
@ -7,9 +7,10 @@
|
||||||
|
|
||||||
class QHBoxLayout;
|
class QHBoxLayout;
|
||||||
|
|
||||||
namespace CSVWorld
|
namespace CSVWidget
|
||||||
{
|
{
|
||||||
class SceneToolbar;
|
class SceneToolbar;
|
||||||
|
class PushButton;
|
||||||
|
|
||||||
///< \brief Mode selector tool
|
///< \brief Mode selector tool
|
||||||
class SceneToolMode : public SceneTool
|
class SceneToolMode : public SceneTool
|
||||||
|
@ -18,17 +19,22 @@ namespace CSVWorld
|
||||||
|
|
||||||
QWidget *mPanel;
|
QWidget *mPanel;
|
||||||
QHBoxLayout *mLayout;
|
QHBoxLayout *mLayout;
|
||||||
std::map<QPushButton *, std::string> mButtons; // widget, id
|
std::map<PushButton *, std::string> mButtons; // widget, id
|
||||||
int mButtonSize;
|
int mButtonSize;
|
||||||
int mIconSize;
|
int mIconSize;
|
||||||
|
QString mToolTip;
|
||||||
|
PushButton *mFirst;
|
||||||
|
|
||||||
|
void adjustToolTip (const PushButton *activeMode);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
SceneToolMode (SceneToolbar *parent);
|
SceneToolMode (SceneToolbar *parent, const QString& toolTip);
|
||||||
|
|
||||||
virtual void showPanel (const QPoint& position);
|
virtual void showPanel (const QPoint& position);
|
||||||
|
|
||||||
void addButton (const std::string& icon, const std::string& id);
|
void addButton (const std::string& icon, const std::string& id,
|
||||||
|
const QString& tooltip = "");
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
|
|
@ -471,25 +471,32 @@ CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, CSM
|
||||||
QHBoxLayout *buttonsLayout = new QHBoxLayout;
|
QHBoxLayout *buttonsLayout = new QHBoxLayout;
|
||||||
QToolButton* prevButton = new QToolButton(mainWidget);
|
QToolButton* prevButton = new QToolButton(mainWidget);
|
||||||
prevButton->setIcon(QIcon(":/go-previous.png"));
|
prevButton->setIcon(QIcon(":/go-previous.png"));
|
||||||
|
prevButton->setToolTip ("Switch to previous record");
|
||||||
QToolButton* nextButton = new QToolButton(mainWidget);
|
QToolButton* nextButton = new QToolButton(mainWidget);
|
||||||
nextButton->setIcon(QIcon(":/go-next.png"));
|
nextButton->setIcon(QIcon(":/go-next.png"));
|
||||||
|
nextButton->setToolTip ("Switch to next record");
|
||||||
buttonsLayout->addWidget(prevButton, 0);
|
buttonsLayout->addWidget(prevButton, 0);
|
||||||
buttonsLayout->addWidget(nextButton, 1);
|
buttonsLayout->addWidget(nextButton, 1);
|
||||||
buttonsLayout->addStretch(2);
|
buttonsLayout->addStretch(2);
|
||||||
|
|
||||||
QToolButton* cloneButton = new QToolButton(mainWidget);
|
QToolButton* cloneButton = new QToolButton(mainWidget);
|
||||||
cloneButton->setIcon(QIcon(":/edit-clone.png"));
|
cloneButton->setIcon(QIcon(":/edit-clone.png"));
|
||||||
|
cloneButton->setToolTip ("Clone record");
|
||||||
QToolButton* addButton = new QToolButton(mainWidget);
|
QToolButton* addButton = new QToolButton(mainWidget);
|
||||||
addButton->setIcon(QIcon(":/add.png"));
|
addButton->setIcon(QIcon(":/add.png"));
|
||||||
|
addButton->setToolTip ("Add new record");
|
||||||
QToolButton* deleteButton = new QToolButton(mainWidget);
|
QToolButton* deleteButton = new QToolButton(mainWidget);
|
||||||
deleteButton->setIcon(QIcon(":/edit-delete.png"));
|
deleteButton->setIcon(QIcon(":/edit-delete.png"));
|
||||||
|
deleteButton->setToolTip ("Delete record");
|
||||||
QToolButton* revertButton = new QToolButton(mainWidget);
|
QToolButton* revertButton = new QToolButton(mainWidget);
|
||||||
revertButton->setIcon(QIcon(":/edit-undo.png"));
|
revertButton->setIcon(QIcon(":/edit-undo.png"));
|
||||||
|
revertButton->setToolTip ("Revert record");
|
||||||
|
|
||||||
if (mTable->getFeatures() & CSMWorld::IdTable::Feature_Preview)
|
if (mTable->getFeatures() & CSMWorld::IdTable::Feature_Preview)
|
||||||
{
|
{
|
||||||
QToolButton* previewButton = new QToolButton(mainWidget);
|
QToolButton* previewButton = new QToolButton(mainWidget);
|
||||||
previewButton->setIcon(QIcon(":/edit-preview.png"));
|
previewButton->setIcon(QIcon(":/edit-preview.png"));
|
||||||
|
previewButton->setToolTip ("Open a preview of this record");
|
||||||
buttonsLayout->addWidget(previewButton);
|
buttonsLayout->addWidget(previewButton);
|
||||||
connect(previewButton, SIGNAL(clicked()), this, SLOT(showPreview()));
|
connect(previewButton, SIGNAL(clicked()), this, SLOT(showPreview()));
|
||||||
}
|
}
|
||||||
|
@ -498,6 +505,7 @@ CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, CSM
|
||||||
{
|
{
|
||||||
QToolButton* viewButton = new QToolButton(mainWidget);
|
QToolButton* viewButton = new QToolButton(mainWidget);
|
||||||
viewButton->setIcon(QIcon(":/cell.png"));
|
viewButton->setIcon(QIcon(":/cell.png"));
|
||||||
|
viewButton->setToolTip ("Open a scene view of the cell this record is located in");
|
||||||
buttonsLayout->addWidget(viewButton);
|
buttonsLayout->addWidget(viewButton);
|
||||||
connect(viewButton, SIGNAL(clicked()), this, SLOT(viewRecord()));
|
connect(viewButton, SIGNAL(clicked()), this, SLOT(viewRecord()));
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,8 +5,8 @@
|
||||||
|
|
||||||
#include "../render/previewwidget.hpp"
|
#include "../render/previewwidget.hpp"
|
||||||
|
|
||||||
#include "scenetoolbar.hpp"
|
#include "../widget/scenetoolbar.hpp"
|
||||||
#include "scenetoolmode.hpp"
|
#include "../widget/scenetoolmode.hpp"
|
||||||
|
|
||||||
CSVWorld::PreviewSubView::PreviewSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document)
|
CSVWorld::PreviewSubView::PreviewSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document)
|
||||||
: SubView (id)
|
: SubView (id)
|
||||||
|
@ -28,9 +28,9 @@ CSVWorld::PreviewSubView::PreviewSubView (const CSMWorld::UniversalId& id, CSMDo
|
||||||
else
|
else
|
||||||
mScene = new CSVRender::PreviewWidget (document.getData(), id.getId(), true, this);
|
mScene = new CSVRender::PreviewWidget (document.getData(), id.getId(), true, this);
|
||||||
|
|
||||||
SceneToolbar *toolbar = new SceneToolbar (48+6, this);
|
CSVWidget::SceneToolbar *toolbar = new CSVWidget::SceneToolbar (48+6, this);
|
||||||
|
|
||||||
SceneToolMode *lightingTool = mScene->makeLightingSelector (toolbar);
|
CSVWidget::SceneToolMode *lightingTool = mScene->makeLightingSelector (toolbar);
|
||||||
toolbar->addTool (lightingTool);
|
toolbar->addTool (lightingTool);
|
||||||
|
|
||||||
layout->addWidget (toolbar, 0);
|
layout->addWidget (toolbar, 0);
|
||||||
|
@ -46,6 +46,8 @@ CSVWorld::PreviewSubView::PreviewSubView (const CSMWorld::UniversalId& id, CSMDo
|
||||||
connect (mScene, SIGNAL (closeRequest()), this, SLOT (closeRequest()));
|
connect (mScene, SIGNAL (closeRequest()), this, SLOT (closeRequest()));
|
||||||
connect (mScene, SIGNAL (referenceableIdChanged (const std::string&)),
|
connect (mScene, SIGNAL (referenceableIdChanged (const std::string&)),
|
||||||
this, SLOT (referenceableIdChanged (const std::string&)));
|
this, SLOT (referenceableIdChanged (const std::string&)));
|
||||||
|
connect (mScene, SIGNAL (focusToolbarRequest()), toolbar, SLOT (setFocus()));
|
||||||
|
connect (toolbar, SIGNAL (focusSceneRequest()), mScene, SLOT (setFocus()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSVWorld::PreviewSubView::setEditLock (bool locked) {}
|
void CSVWorld::PreviewSubView::setEditLock (bool locked) {}
|
||||||
|
|
|
@ -17,9 +17,11 @@
|
||||||
#include "../render/pagedworldspacewidget.hpp"
|
#include "../render/pagedworldspacewidget.hpp"
|
||||||
#include "../render/unpagedworldspacewidget.hpp"
|
#include "../render/unpagedworldspacewidget.hpp"
|
||||||
|
|
||||||
|
#include "../widget/scenetoolbar.hpp"
|
||||||
|
#include "../widget/scenetoolmode.hpp"
|
||||||
|
|
||||||
#include "tablebottombox.hpp"
|
#include "tablebottombox.hpp"
|
||||||
#include "creator.hpp"
|
#include "creator.hpp"
|
||||||
#include "scenetoolmode.hpp"
|
|
||||||
|
|
||||||
CSVWorld::SceneSubView::SceneSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document)
|
CSVWorld::SceneSubView::SceneSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document)
|
||||||
: SubView (id), mLayout(new QHBoxLayout), mDocument(document), mScene(NULL), mToolbar(NULL)
|
: SubView (id), mLayout(new QHBoxLayout), mDocument(document), mScene(NULL), mToolbar(NULL)
|
||||||
|
@ -95,14 +97,14 @@ void CSVWorld::SceneSubView::makeConnections (CSVRender::PagedWorldspaceWidget*
|
||||||
this, SLOT (cellSelectionChanged (const CSMWorld::CellSelection&)));
|
this, SLOT (cellSelectionChanged (const CSMWorld::CellSelection&)));
|
||||||
}
|
}
|
||||||
|
|
||||||
CSVWorld::SceneToolbar* CSVWorld::SceneSubView::makeToolbar (CSVRender::WorldspaceWidget* widget, widgetType type)
|
CSVWidget::SceneToolbar* CSVWorld::SceneSubView::makeToolbar (CSVRender::WorldspaceWidget* widget, widgetType type)
|
||||||
{
|
{
|
||||||
CSVWorld::SceneToolbar* toolbar = new SceneToolbar (48+6, this);
|
CSVWidget::SceneToolbar* toolbar = new CSVWidget::SceneToolbar (48+6, this);
|
||||||
|
|
||||||
SceneToolMode *navigationTool = widget->makeNavigationSelector (toolbar);
|
CSVWidget::SceneToolMode *navigationTool = widget->makeNavigationSelector (toolbar);
|
||||||
toolbar->addTool (navigationTool);
|
toolbar->addTool (navigationTool);
|
||||||
|
|
||||||
SceneToolMode *lightingTool = widget->makeLightingSelector (toolbar);
|
CSVWidget::SceneToolMode *lightingTool = widget->makeLightingSelector (toolbar);
|
||||||
toolbar->addTool (lightingTool);
|
toolbar->addTool (lightingTool);
|
||||||
|
|
||||||
/* Add buttons specific to the type. For now no need for it.
|
/* Add buttons specific to the type. For now no need for it.
|
||||||
|
@ -188,7 +190,7 @@ void CSVWorld::SceneSubView::handleDrop (const std::vector< CSMWorld::UniversalI
|
||||||
{
|
{
|
||||||
CSVRender::PagedWorldspaceWidget* pagedNewWidget = NULL;
|
CSVRender::PagedWorldspaceWidget* pagedNewWidget = NULL;
|
||||||
CSVRender::UnpagedWorldspaceWidget* unPagedNewWidget = NULL;
|
CSVRender::UnpagedWorldspaceWidget* unPagedNewWidget = NULL;
|
||||||
SceneToolbar* toolbar = NULL;
|
CSVWidget::SceneToolbar* toolbar = NULL;
|
||||||
|
|
||||||
switch (mScene->getDropRequirements(CSVRender::WorldspaceWidget::getDropType(data)))
|
switch (mScene->getDropRequirements(CSVRender::WorldspaceWidget::getDropType(data)))
|
||||||
{
|
{
|
||||||
|
@ -217,7 +219,7 @@ void CSVWorld::SceneSubView::handleDrop (const std::vector< CSMWorld::UniversalI
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSVWorld::SceneSubView::replaceToolbarAndWorldspace (CSVRender::WorldspaceWidget* widget, CSVWorld::SceneToolbar* toolbar)
|
void CSVWorld::SceneSubView::replaceToolbarAndWorldspace (CSVRender::WorldspaceWidget* widget, CSVWidget::SceneToolbar* toolbar)
|
||||||
{
|
{
|
||||||
assert(mLayout);
|
assert(mLayout);
|
||||||
|
|
||||||
|
@ -236,8 +238,12 @@ void CSVWorld::SceneSubView::replaceToolbarAndWorldspace (CSVRender::WorldspaceW
|
||||||
mScene = widget;
|
mScene = widget;
|
||||||
mToolbar = toolbar;
|
mToolbar = toolbar;
|
||||||
|
|
||||||
|
connect (mScene, SIGNAL (focusToolbarRequest()), mToolbar, SLOT (setFocus()));
|
||||||
|
connect (mToolbar, SIGNAL (focusSceneRequest()), mScene, SLOT (setFocus()));
|
||||||
|
|
||||||
mLayout->addWidget (mToolbar, 0);
|
mLayout->addWidget (mToolbar, 0);
|
||||||
mLayout->addWidget (mScene, 1);
|
mLayout->addWidget (mScene, 1);
|
||||||
|
|
||||||
mScene->selectDefaultNavigationMode();
|
mScene->selectDefaultNavigationMode();
|
||||||
|
setFocusProxy (mScene);
|
||||||
}
|
}
|
|
@ -4,7 +4,6 @@
|
||||||
#include <QHBoxLayout>
|
#include <QHBoxLayout>
|
||||||
|
|
||||||
#include "../doc/subview.hpp"
|
#include "../doc/subview.hpp"
|
||||||
#include "scenetoolbar.hpp"
|
|
||||||
|
|
||||||
class QModelIndex;
|
class QModelIndex;
|
||||||
|
|
||||||
|
@ -25,6 +24,11 @@ namespace CSVRender
|
||||||
class UnpagedWorldspaceWidget;
|
class UnpagedWorldspaceWidget;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace CSVWidget
|
||||||
|
{
|
||||||
|
class SceneToolbar;
|
||||||
|
}
|
||||||
|
|
||||||
namespace CSVWorld
|
namespace CSVWorld
|
||||||
{
|
{
|
||||||
class Table;
|
class Table;
|
||||||
|
@ -39,7 +43,7 @@ namespace CSVWorld
|
||||||
CSVRender::WorldspaceWidget *mScene;
|
CSVRender::WorldspaceWidget *mScene;
|
||||||
QHBoxLayout* mLayout;
|
QHBoxLayout* mLayout;
|
||||||
CSMDoc::Document& mDocument;
|
CSMDoc::Document& mDocument;
|
||||||
SceneToolbar* mToolbar;
|
CSVWidget::SceneToolbar* mToolbar;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
@ -59,14 +63,15 @@ namespace CSVWorld
|
||||||
|
|
||||||
void makeConnections(CSVRender::UnpagedWorldspaceWidget* widget);
|
void makeConnections(CSVRender::UnpagedWorldspaceWidget* widget);
|
||||||
|
|
||||||
void replaceToolbarAndWorldspace(CSVRender::WorldspaceWidget* widget, SceneToolbar* toolbar);
|
void replaceToolbarAndWorldspace(CSVRender::WorldspaceWidget* widget, CSVWidget::SceneToolbar* toolbar);
|
||||||
|
|
||||||
enum widgetType
|
enum widgetType
|
||||||
{
|
{
|
||||||
widget_Paged,
|
widget_Paged,
|
||||||
widget_Unpaged
|
widget_Unpaged
|
||||||
};
|
};
|
||||||
SceneToolbar* makeToolbar(CSVRender::WorldspaceWidget* widget, widgetType type);
|
|
||||||
|
CSVWidget::SceneToolbar* makeToolbar(CSVRender::WorldspaceWidget* widget, widgetType type);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
|
|
||||||
|
|
|
@ -1,34 +0,0 @@
|
||||||
|
|
||||||
#include "scenetoolbar.hpp"
|
|
||||||
|
|
||||||
#include <QVBoxLayout>
|
|
||||||
|
|
||||||
#include "scenetool.hpp"
|
|
||||||
|
|
||||||
CSVWorld::SceneToolbar::SceneToolbar (int buttonSize, QWidget *parent)
|
|
||||||
: QWidget (parent), mButtonSize (buttonSize), mIconSize (buttonSize-6)
|
|
||||||
{
|
|
||||||
setFixedWidth (mButtonSize);
|
|
||||||
|
|
||||||
mLayout = new QVBoxLayout (this);
|
|
||||||
mLayout->setAlignment (Qt::AlignTop);
|
|
||||||
|
|
||||||
mLayout->setContentsMargins (QMargins (0, 0, 0, 0));
|
|
||||||
|
|
||||||
setLayout (mLayout);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CSVWorld::SceneToolbar::addTool (SceneTool *tool)
|
|
||||||
{
|
|
||||||
mLayout->addWidget (tool, 0, Qt::AlignTop);
|
|
||||||
}
|
|
||||||
|
|
||||||
int CSVWorld::SceneToolbar::getButtonSize() const
|
|
||||||
{
|
|
||||||
return mButtonSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
int CSVWorld::SceneToolbar::getIconSize() const
|
|
||||||
{
|
|
||||||
return mIconSize;
|
|
||||||
}
|
|
|
@ -1,57 +0,0 @@
|
||||||
|
|
||||||
#include "scenetoolmode.hpp"
|
|
||||||
|
|
||||||
#include <QHBoxLayout>
|
|
||||||
#include <QFrame>
|
|
||||||
#include <QSignalMapper>
|
|
||||||
|
|
||||||
#include "scenetoolbar.hpp"
|
|
||||||
|
|
||||||
CSVWorld::SceneToolMode::SceneToolMode (SceneToolbar *parent)
|
|
||||||
: SceneTool (parent), mButtonSize (parent->getButtonSize()), mIconSize (parent->getIconSize())
|
|
||||||
{
|
|
||||||
mPanel = new QFrame (this, Qt::Popup);
|
|
||||||
|
|
||||||
mLayout = new QHBoxLayout (mPanel);
|
|
||||||
|
|
||||||
mLayout->setContentsMargins (QMargins (0, 0, 0, 0));
|
|
||||||
|
|
||||||
mPanel->setLayout (mLayout);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CSVWorld::SceneToolMode::showPanel (const QPoint& position)
|
|
||||||
{
|
|
||||||
mPanel->move (position);
|
|
||||||
mPanel->show();
|
|
||||||
}
|
|
||||||
|
|
||||||
void CSVWorld::SceneToolMode::addButton (const std::string& icon, const std::string& id)
|
|
||||||
{
|
|
||||||
QPushButton *button = new QPushButton (QIcon (QPixmap (icon.c_str())), "", mPanel);
|
|
||||||
button->setSizePolicy (QSizePolicy (QSizePolicy::Fixed, QSizePolicy::Fixed));
|
|
||||||
button->setIconSize (QSize (mIconSize, mIconSize));
|
|
||||||
button->setFixedSize (mButtonSize, mButtonSize);
|
|
||||||
|
|
||||||
mLayout->addWidget (button);
|
|
||||||
|
|
||||||
mButtons.insert (std::make_pair (button, id));
|
|
||||||
|
|
||||||
connect (button, SIGNAL (clicked()), this, SLOT (selected()));
|
|
||||||
|
|
||||||
if (mButtons.size()==1)
|
|
||||||
setIcon (button->icon());
|
|
||||||
}
|
|
||||||
|
|
||||||
void CSVWorld::SceneToolMode::selected()
|
|
||||||
{
|
|
||||||
std::map<QPushButton *, std::string>::const_iterator iter =
|
|
||||||
mButtons.find (dynamic_cast<QPushButton *> (sender()));
|
|
||||||
|
|
||||||
if (iter!=mButtons.end())
|
|
||||||
{
|
|
||||||
mPanel->hide();
|
|
||||||
|
|
||||||
setIcon (iter->first->icon());
|
|
||||||
emit modeChanged (iter->second);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -69,7 +69,7 @@ add_openmw_dir (mwmechanics
|
||||||
mechanicsmanagerimp stat character creaturestats magiceffects movement actors objects
|
mechanicsmanagerimp stat character creaturestats magiceffects movement actors objects
|
||||||
drawstate spells activespells npcstats aipackage aisequence aipursue alchemy aiwander aitravel aifollow aiavoiddoor
|
drawstate spells activespells npcstats aipackage aisequence aipursue alchemy aiwander aitravel aifollow aiavoiddoor
|
||||||
aiescort aiactivate aicombat repair enchanting pathfinding pathgrid security spellsuccess spellcasting
|
aiescort aiactivate aicombat repair enchanting pathfinding pathgrid security spellsuccess spellcasting
|
||||||
disease pickpocket levelledlist combat steering obstacle
|
disease pickpocket levelledlist combat steering obstacle autocalcspell difficultyscaling
|
||||||
)
|
)
|
||||||
|
|
||||||
add_openmw_dir (mwstate
|
add_openmw_dir (mwstate
|
||||||
|
|
|
@ -196,6 +196,10 @@ namespace MWBase
|
||||||
/// @param bias Can be used to add an additional aggression bias towards the target,
|
/// @param bias Can be used to add an additional aggression bias towards the target,
|
||||||
/// making it more likely for the function to return true.
|
/// making it more likely for the function to return true.
|
||||||
virtual bool isAggressive (const MWWorld::Ptr& ptr, const MWWorld::Ptr& target, int bias=0, bool ignoreDistance=false) = 0;
|
virtual bool isAggressive (const MWWorld::Ptr& ptr, const MWWorld::Ptr& target, int bias=0, bool ignoreDistance=false) = 0;
|
||||||
|
|
||||||
|
/// Usually done once a frame, but can be invoked manually in time-critical situations.
|
||||||
|
/// This will increase the death count for any actors that were killed.
|
||||||
|
virtual void killDeadActors() = 0;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -398,8 +398,9 @@ namespace MWBase
|
||||||
|
|
||||||
/// open or close a non-teleport door (depending on current state)
|
/// open or close a non-teleport door (depending on current state)
|
||||||
virtual void activateDoor(const MWWorld::Ptr& door) = 0;
|
virtual void activateDoor(const MWWorld::Ptr& door) = 0;
|
||||||
/// open or close a non-teleport door as specified
|
/// update movement state of a non-teleport door as specified
|
||||||
virtual void activateDoor(const MWWorld::Ptr& door, bool open) = 0;
|
/// @param state see MWClass::setDoorState
|
||||||
|
virtual void activateDoor(const MWWorld::Ptr& door, int state) = 0;
|
||||||
|
|
||||||
virtual bool getPlayerStandingOn (const MWWorld::Ptr& object) = 0; ///< @return true if the player is standing on \a object
|
virtual bool getPlayerStandingOn (const MWWorld::Ptr& object) = 0; ///< @return true if the player is standing on \a object
|
||||||
virtual bool getActorStandingOn (const MWWorld::Ptr& object) = 0; ///< @return true if any actor is standing on \a object
|
virtual bool getActorStandingOn (const MWWorld::Ptr& object) = 0; ///< @return true if any actor is standing on \a object
|
||||||
|
|
|
@ -97,8 +97,7 @@ namespace MWClass
|
||||||
std::string text;
|
std::string text;
|
||||||
if (MWBase::Environment::get().getWindowManager()->getFullHelp())
|
if (MWBase::Environment::get().getWindowManager()->getFullHelp())
|
||||||
{
|
{
|
||||||
text += MWGui::ToolTips::getMiscString(ptr.getCellRef().getOwner(), "Owner");
|
text += MWGui::ToolTips::getCellRefString(ptr.getCellRef());
|
||||||
text += MWGui::ToolTips::getMiscString(ptr.getCellRef().getFaction(), "Faction");
|
|
||||||
text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script");
|
text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script");
|
||||||
}
|
}
|
||||||
info.text = text;
|
info.text = text;
|
||||||
|
|
|
@ -127,8 +127,7 @@ namespace MWClass
|
||||||
text += MWGui::ToolTips::getValueString(ref->mBase->mData.mValue, "#{sValue}");
|
text += MWGui::ToolTips::getValueString(ref->mBase->mData.mValue, "#{sValue}");
|
||||||
|
|
||||||
if (MWBase::Environment::get().getWindowManager()->getFullHelp()) {
|
if (MWBase::Environment::get().getWindowManager()->getFullHelp()) {
|
||||||
text += MWGui::ToolTips::getMiscString(ptr.getCellRef().getOwner(), "Owner");
|
text += MWGui::ToolTips::getCellRefString(ptr.getCellRef());
|
||||||
text += MWGui::ToolTips::getMiscString(ptr.getCellRef().getFaction(), "Faction");
|
|
||||||
text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script");
|
text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script");
|
||||||
}
|
}
|
||||||
info.text = text;
|
info.text = text;
|
||||||
|
|
|
@ -247,8 +247,7 @@ namespace MWClass
|
||||||
text += MWGui::ToolTips::getValueString(ref->mBase->mData.mValue, "#{sValue}");
|
text += MWGui::ToolTips::getValueString(ref->mBase->mData.mValue, "#{sValue}");
|
||||||
|
|
||||||
if (MWBase::Environment::get().getWindowManager()->getFullHelp()) {
|
if (MWBase::Environment::get().getWindowManager()->getFullHelp()) {
|
||||||
text += MWGui::ToolTips::getMiscString(ptr.getCellRef().getOwner(), "Owner");
|
text += MWGui::ToolTips::getCellRefString(ptr.getCellRef());
|
||||||
text += MWGui::ToolTips::getMiscString(ptr.getCellRef().getFaction(), "Faction");
|
|
||||||
text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script");
|
text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -139,8 +139,7 @@ namespace MWClass
|
||||||
text += MWGui::ToolTips::getValueString(ref->mBase->mData.mValue, "#{sValue}");
|
text += MWGui::ToolTips::getValueString(ref->mBase->mData.mValue, "#{sValue}");
|
||||||
|
|
||||||
if (MWBase::Environment::get().getWindowManager()->getFullHelp()) {
|
if (MWBase::Environment::get().getWindowManager()->getFullHelp()) {
|
||||||
text += MWGui::ToolTips::getMiscString(ptr.getCellRef().getOwner(), "Owner");
|
text += MWGui::ToolTips::getCellRefString(ptr.getCellRef());
|
||||||
text += MWGui::ToolTips::getMiscString(ptr.getCellRef().getFaction(), "Faction");
|
|
||||||
text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script");
|
text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -193,8 +193,7 @@ namespace MWClass
|
||||||
text += MWGui::ToolTips::getValueString(ref->mBase->mData.mValue, "#{sValue}");
|
text += MWGui::ToolTips::getValueString(ref->mBase->mData.mValue, "#{sValue}");
|
||||||
|
|
||||||
if (MWBase::Environment::get().getWindowManager()->getFullHelp()) {
|
if (MWBase::Environment::get().getWindowManager()->getFullHelp()) {
|
||||||
text += MWGui::ToolTips::getMiscString(ptr.getCellRef().getOwner(), "Owner");
|
text += MWGui::ToolTips::getCellRefString(ptr.getCellRef());
|
||||||
text += MWGui::ToolTips::getMiscString(ptr.getCellRef().getFaction(), "Faction");
|
|
||||||
text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script");
|
text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -235,8 +235,7 @@ namespace MWClass
|
||||||
text += "\n#{sTrapped}";
|
text += "\n#{sTrapped}";
|
||||||
|
|
||||||
if (MWBase::Environment::get().getWindowManager()->getFullHelp()) {
|
if (MWBase::Environment::get().getWindowManager()->getFullHelp()) {
|
||||||
text += MWGui::ToolTips::getMiscString(ptr.getCellRef().getOwner(), "Owner");
|
text += MWGui::ToolTips::getCellRefString(ptr.getCellRef());
|
||||||
text += MWGui::ToolTips::getMiscString(ptr.getCellRef().getFaction(), "Faction");
|
|
||||||
text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script");
|
text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include "../mwmechanics/movement.hpp"
|
#include "../mwmechanics/movement.hpp"
|
||||||
#include "../mwmechanics/disease.hpp"
|
#include "../mwmechanics/disease.hpp"
|
||||||
#include "../mwmechanics/spellcasting.hpp"
|
#include "../mwmechanics/spellcasting.hpp"
|
||||||
|
#include "../mwmechanics/difficultyscaling.hpp"
|
||||||
|
|
||||||
#include "../mwbase/environment.hpp"
|
#include "../mwbase/environment.hpp"
|
||||||
#include "../mwbase/mechanicsmanager.hpp"
|
#include "../mwbase/mechanicsmanager.hpp"
|
||||||
|
@ -254,6 +255,23 @@ namespace MWClass
|
||||||
if((::rand()/(RAND_MAX+1.0)) > hitchance/100.0f)
|
if((::rand()/(RAND_MAX+1.0)) > hitchance/100.0f)
|
||||||
{
|
{
|
||||||
victim.getClass().onHit(victim, 0.0f, false, MWWorld::Ptr(), ptr, false);
|
victim.getClass().onHit(victim, 0.0f, false, MWWorld::Ptr(), ptr, false);
|
||||||
|
|
||||||
|
// Weapon health is reduced by 1 even if the attack misses
|
||||||
|
const bool weaphashealth = !weapon.isEmpty() && weapon.getClass().hasItemHealth(weapon);
|
||||||
|
if(weaphashealth)
|
||||||
|
{
|
||||||
|
int weaphealth = weapon.getClass().getItemHealth(weapon);
|
||||||
|
|
||||||
|
if (!MWBase::Environment::get().getWorld()->getGodModeState())
|
||||||
|
{
|
||||||
|
weaphealth -= std::min(1, weaphealth);
|
||||||
|
weapon.getCellRef().setCharge(weaphealth);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Weapon broken? unequip it
|
||||||
|
if (weapon.getCellRef().getCharge() == 0)
|
||||||
|
weapon = *getInventoryStore(ptr).unequipItem(weapon, ptr);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -290,13 +308,13 @@ namespace MWClass
|
||||||
attack = weapon.get<ESM::Weapon>()->mBase->mData.mThrust;
|
attack = weapon.get<ESM::Weapon>()->mBase->mData.mThrust;
|
||||||
if(attack)
|
if(attack)
|
||||||
{
|
{
|
||||||
float weaponDamage = attack[0] + ((attack[1]-attack[0])*stats.getAttackStrength());
|
damage = attack[0] + ((attack[1]-attack[0])*stats.getAttackStrength());
|
||||||
weaponDamage *= 0.5f + (stats.getAttribute(ESM::Attribute::Luck).getModified() / 100.0f);
|
damage *= 0.5f + (stats.getAttribute(ESM::Attribute::Luck).getModified() / 100.0f);
|
||||||
if(weaphashealth)
|
if(weaphashealth)
|
||||||
{
|
{
|
||||||
int weapmaxhealth = weapon.getClass().getItemMaxHealth(weapon);
|
int weapmaxhealth = weapon.getClass().getItemMaxHealth(weapon);
|
||||||
int weaphealth = weapon.getClass().getItemHealth(weapon);
|
int weaphealth = weapon.getClass().getItemHealth(weapon);
|
||||||
weaponDamage *= float(weaphealth) / weapmaxhealth;
|
damage *= float(weaphealth) / weapmaxhealth;
|
||||||
|
|
||||||
if (!MWBase::Environment::get().getWorld()->getGodModeState())
|
if (!MWBase::Environment::get().getWorld()->getGodModeState())
|
||||||
{
|
{
|
||||||
|
@ -311,8 +329,6 @@ namespace MWClass
|
||||||
if (weapon.getCellRef().getCharge() == 0)
|
if (weapon.getCellRef().getCharge() == 0)
|
||||||
weapon = *getInventoryStore(ptr).unequipItem(weapon, ptr);
|
weapon = *getInventoryStore(ptr).unequipItem(weapon, ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
damage += weaponDamage;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply "On hit" enchanted weapons
|
// Apply "On hit" enchanted weapons
|
||||||
|
@ -330,6 +346,8 @@ namespace MWClass
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MWMechanics::applyElementalShields(ptr, victim);
|
||||||
|
|
||||||
if (!weapon.isEmpty() && MWMechanics::blockMeleeAttack(ptr, victim, weapon, damage))
|
if (!weapon.isEmpty() && MWMechanics::blockMeleeAttack(ptr, victim, weapon, damage))
|
||||||
damage = 0;
|
damage = 0;
|
||||||
|
|
||||||
|
@ -376,6 +394,9 @@ namespace MWClass
|
||||||
if (damage > 0.0f && !object.isEmpty())
|
if (damage > 0.0f && !object.isEmpty())
|
||||||
MWMechanics::resistNormalWeapon(ptr, attacker, object, damage);
|
MWMechanics::resistNormalWeapon(ptr, attacker, object, damage);
|
||||||
|
|
||||||
|
if (damage < 0.001f)
|
||||||
|
damage = 0;
|
||||||
|
|
||||||
if (damage > 0.f)
|
if (damage > 0.f)
|
||||||
{
|
{
|
||||||
// Check for knockdown
|
// Check for knockdown
|
||||||
|
@ -391,8 +412,13 @@ namespace MWClass
|
||||||
else
|
else
|
||||||
getCreatureStats(ptr).setHitRecovery(true); // Is this supposed to always occur?
|
getCreatureStats(ptr).setHitRecovery(true); // Is this supposed to always occur?
|
||||||
|
|
||||||
|
damage = std::max(1.f, damage);
|
||||||
|
|
||||||
if(ishealth)
|
if(ishealth)
|
||||||
{
|
{
|
||||||
|
if (!attacker.isEmpty())
|
||||||
|
damage = scaleDamage(damage, attacker, ptr);
|
||||||
|
|
||||||
MWBase::Environment::get().getSoundManager()->playSound3D(ptr, "Health Damage", 1.0f, 1.0f);
|
MWBase::Environment::get().getSoundManager()->playSound3D(ptr, "Health Damage", 1.0f, 1.0f);
|
||||||
float health = getCreatureStats(ptr).getHealth().getCurrent() - damage;
|
float health = getCreatureStats(ptr).getHealth().getCurrent() - damage;
|
||||||
setActorHealth(ptr, health, attacker);
|
setActorHealth(ptr, health, attacker);
|
||||||
|
@ -618,8 +644,8 @@ namespace MWClass
|
||||||
|
|
||||||
float Creature::getArmorRating (const MWWorld::Ptr& ptr) const
|
float Creature::getArmorRating (const MWWorld::Ptr& ptr) const
|
||||||
{
|
{
|
||||||
/// \todo add Shield magic effect magnitude here, controlled by a GMST (Vanilla vs MCP behaviour)
|
// Note this is currently unused. Creatures do not use armor mitigation.
|
||||||
return 0.f;
|
return getCreatureStats(ptr).getMagicEffects().get(ESM::MagicEffect::Shield).mMagnitude;
|
||||||
}
|
}
|
||||||
|
|
||||||
float Creature::getCapacity (const MWWorld::Ptr& ptr) const
|
float Creature::getCapacity (const MWWorld::Ptr& ptr) const
|
||||||
|
|
|
@ -62,7 +62,7 @@ namespace MWClass
|
||||||
const DoorCustomData& customData = dynamic_cast<const DoorCustomData&>(*ptr.getRefData().getCustomData());
|
const DoorCustomData& customData = dynamic_cast<const DoorCustomData&>(*ptr.getRefData().getCustomData());
|
||||||
if (customData.mDoorState > 0)
|
if (customData.mDoorState > 0)
|
||||||
{
|
{
|
||||||
MWBase::Environment::get().getWorld()->activateDoor(ptr, customData.mDoorState == 1 ? true : false);
|
MWBase::Environment::get().getWorld()->activateDoor(ptr, customData.mDoorState);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -250,8 +250,10 @@ namespace MWClass
|
||||||
text += "\n#{sTrapped}";
|
text += "\n#{sTrapped}";
|
||||||
|
|
||||||
if (MWBase::Environment::get().getWindowManager()->getFullHelp())
|
if (MWBase::Environment::get().getWindowManager()->getFullHelp())
|
||||||
|
{
|
||||||
|
text += MWGui::ToolTips::getCellRefString(ptr.getCellRef());
|
||||||
text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script");
|
text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script");
|
||||||
|
}
|
||||||
info.text = text;
|
info.text = text;
|
||||||
|
|
||||||
return info;
|
return info;
|
||||||
|
|
|
@ -147,8 +147,7 @@ namespace MWClass
|
||||||
text += MWGui::ToolTips::getValueString(ref->mBase->mData.mValue, "#{sValue}");
|
text += MWGui::ToolTips::getValueString(ref->mBase->mData.mValue, "#{sValue}");
|
||||||
|
|
||||||
if (MWBase::Environment::get().getWindowManager()->getFullHelp()) {
|
if (MWBase::Environment::get().getWindowManager()->getFullHelp()) {
|
||||||
text += MWGui::ToolTips::getMiscString(ptr.getCellRef().getOwner(), "Owner");
|
text += MWGui::ToolTips::getCellRefString(ptr.getCellRef());
|
||||||
text += MWGui::ToolTips::getMiscString(ptr.getCellRef().getFaction(), "Faction");
|
|
||||||
text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script");
|
text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -187,8 +187,7 @@ namespace MWClass
|
||||||
text += MWGui::ToolTips::getValueString(ref->mBase->mData.mValue, "#{sValue}");
|
text += MWGui::ToolTips::getValueString(ref->mBase->mData.mValue, "#{sValue}");
|
||||||
|
|
||||||
if (MWBase::Environment::get().getWindowManager()->getFullHelp()) {
|
if (MWBase::Environment::get().getWindowManager()->getFullHelp()) {
|
||||||
text += MWGui::ToolTips::getMiscString(ptr.getCellRef().getOwner(), "Owner");
|
text += MWGui::ToolTips::getCellRefString(ptr.getCellRef());
|
||||||
text += MWGui::ToolTips::getMiscString(ptr.getCellRef().getFaction(), "Faction");
|
|
||||||
text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script");
|
text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -141,8 +141,7 @@ namespace MWClass
|
||||||
text += MWGui::ToolTips::getValueString(ref->mBase->mData.mValue, "#{sValue}");
|
text += MWGui::ToolTips::getValueString(ref->mBase->mData.mValue, "#{sValue}");
|
||||||
|
|
||||||
if (MWBase::Environment::get().getWindowManager()->getFullHelp()) {
|
if (MWBase::Environment::get().getWindowManager()->getFullHelp()) {
|
||||||
text += MWGui::ToolTips::getMiscString(ptr.getCellRef().getOwner(), "Owner");
|
text += MWGui::ToolTips::getCellRefString(ptr.getCellRef());
|
||||||
text += MWGui::ToolTips::getMiscString(ptr.getCellRef().getFaction(), "Faction");
|
|
||||||
text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script");
|
text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -182,8 +182,7 @@ namespace MWClass
|
||||||
}
|
}
|
||||||
|
|
||||||
if (MWBase::Environment::get().getWindowManager()->getFullHelp()) {
|
if (MWBase::Environment::get().getWindowManager()->getFullHelp()) {
|
||||||
text += MWGui::ToolTips::getMiscString(ptr.getCellRef().getOwner(), "Owner");
|
text += MWGui::ToolTips::getCellRefString(ptr.getCellRef());
|
||||||
text += MWGui::ToolTips::getMiscString(ptr.getCellRef().getFaction(), "Faction");
|
|
||||||
text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script");
|
text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,8 @@
|
||||||
#include "../mwmechanics/spellcasting.hpp"
|
#include "../mwmechanics/spellcasting.hpp"
|
||||||
#include "../mwmechanics/disease.hpp"
|
#include "../mwmechanics/disease.hpp"
|
||||||
#include "../mwmechanics/combat.hpp"
|
#include "../mwmechanics/combat.hpp"
|
||||||
|
#include "../mwmechanics/autocalcspell.hpp"
|
||||||
|
#include "../mwmechanics/difficultyscaling.hpp"
|
||||||
|
|
||||||
#include "../mwworld/ptr.hpp"
|
#include "../mwworld/ptr.hpp"
|
||||||
#include "../mwworld/actiontalk.hpp"
|
#include "../mwworld/actiontalk.hpp"
|
||||||
|
@ -53,6 +55,24 @@ namespace
|
||||||
return new NpcCustomData (*this);
|
return new NpcCustomData (*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int is_even(double d) {
|
||||||
|
double int_part;
|
||||||
|
modf(d / 2.0, &int_part);
|
||||||
|
return 2.0 * int_part == d;
|
||||||
|
}
|
||||||
|
|
||||||
|
int round_ieee_754(double d) {
|
||||||
|
double i = floor(d);
|
||||||
|
d -= i;
|
||||||
|
if(d < 0.5)
|
||||||
|
return i;
|
||||||
|
if(d > 0.5)
|
||||||
|
return i + 1.0;
|
||||||
|
if(is_even(i))
|
||||||
|
return i;
|
||||||
|
return i + 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
void autoCalculateAttributes (const ESM::NPC* npc, MWMechanics::CreatureStats& creatureStats)
|
void autoCalculateAttributes (const ESM::NPC* npc, MWMechanics::CreatureStats& creatureStats)
|
||||||
{
|
{
|
||||||
// race bonus
|
// race bonus
|
||||||
|
@ -108,8 +128,9 @@ namespace
|
||||||
}
|
}
|
||||||
modifierSum += add;
|
modifierSum += add;
|
||||||
}
|
}
|
||||||
creatureStats.setAttribute(attribute, std::min(creatureStats.getAttribute(attribute).getBase()
|
creatureStats.setAttribute(attribute, std::min(
|
||||||
+ static_cast<int>((level-1) * modifierSum+0.5), 100) );
|
round_ieee_754(creatureStats.getAttribute(attribute).getBase()
|
||||||
|
+ (level-1) * modifierSum), 100) );
|
||||||
}
|
}
|
||||||
|
|
||||||
// initial health
|
// initial health
|
||||||
|
@ -193,18 +214,6 @@ namespace
|
||||||
majorMultiplier = 1.0f;
|
majorMultiplier = 1.0f;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (class_->mData.mSkills[k][1] == skillIndex)
|
|
||||||
{
|
|
||||||
// Major skill -> add starting spells for this skill if existing
|
|
||||||
const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore();
|
|
||||||
MWWorld::Store<ESM::Spell>::iterator it = store.get<ESM::Spell>().begin();
|
|
||||||
for (; it != store.get<ESM::Spell>().end(); ++it)
|
|
||||||
{
|
|
||||||
if (it->mData.mFlags & ESM::Spell::F_Autocalc
|
|
||||||
&& MWMechanics::spellSchoolToSkill(MWMechanics::getSpellSchool(&*it, ptr)) == skillIndex)
|
|
||||||
npcStats.getSpells().add(it->mId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// is this skill in the same Specialization as the class?
|
// is this skill in the same Specialization as the class?
|
||||||
|
@ -217,12 +226,25 @@ namespace
|
||||||
|
|
||||||
npcStats.getSkill(skillIndex).setBase(
|
npcStats.getSkill(skillIndex).setBase(
|
||||||
std::min(
|
std::min(
|
||||||
npcStats.getSkill(skillIndex).getBase()
|
round_ieee_754(
|
||||||
|
npcStats.getSkill(skillIndex).getBase()
|
||||||
+ 5
|
+ 5
|
||||||
+ raceBonus
|
+ raceBonus
|
||||||
+ specBonus
|
+ specBonus
|
||||||
+ static_cast<int>((level-1) * (majorMultiplier + specMultiplier)), 100));
|
+(int(level)-1) * (majorMultiplier + specMultiplier)), 100)); // Must gracefully handle level 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int skills[ESM::Skill::Length];
|
||||||
|
for (int i=0; i<ESM::Skill::Length; ++i)
|
||||||
|
skills[i] = npcStats.getSkill(i).getBase();
|
||||||
|
|
||||||
|
int attributes[ESM::Attribute::Length];
|
||||||
|
for (int i=0; i<ESM::Attribute::Length; ++i)
|
||||||
|
attributes[i] = npcStats.getAttribute(i).getBase();
|
||||||
|
|
||||||
|
std::vector<std::string> spells = MWMechanics::autoCalcNpcSpells(skills, attributes, race);
|
||||||
|
for (std::vector<std::string>::iterator it = spells.begin(); it != spells.end(); ++it)
|
||||||
|
npcStats.getSpells().add(*it);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -258,6 +280,7 @@ namespace MWClass
|
||||||
gmst.iKnockDownOddsBase = store.find("iKnockDownOddsBase");
|
gmst.iKnockDownOddsBase = store.find("iKnockDownOddsBase");
|
||||||
gmst.fDamageStrengthBase = store.find("fDamageStrengthBase");
|
gmst.fDamageStrengthBase = store.find("fDamageStrengthBase");
|
||||||
gmst.fDamageStrengthMult = store.find("fDamageStrengthMult");
|
gmst.fDamageStrengthMult = store.find("fDamageStrengthMult");
|
||||||
|
gmst.fCombatArmorMinMult = store.find("fCombatArmorMinMult");
|
||||||
|
|
||||||
inited = true;
|
inited = true;
|
||||||
}
|
}
|
||||||
|
@ -506,6 +529,24 @@ namespace MWClass
|
||||||
if((::rand()/(RAND_MAX+1.0)) > hitchance/100.0f)
|
if((::rand()/(RAND_MAX+1.0)) > hitchance/100.0f)
|
||||||
{
|
{
|
||||||
othercls.onHit(victim, 0.0f, false, weapon, ptr, false);
|
othercls.onHit(victim, 0.0f, false, weapon, ptr, false);
|
||||||
|
|
||||||
|
// Weapon health is reduced by 1 even if the attack misses
|
||||||
|
const bool weaphashealth = !weapon.isEmpty() && weapon.getClass().hasItemHealth(weapon);
|
||||||
|
if(weaphashealth)
|
||||||
|
{
|
||||||
|
int weaphealth = weapon.getClass().getItemHealth(weapon);
|
||||||
|
|
||||||
|
if (!MWBase::Environment::get().getWorld()->getGodModeState())
|
||||||
|
{
|
||||||
|
weaphealth -= std::min(1, weaphealth);
|
||||||
|
weapon.getCellRef().setCharge(weaphealth);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Weapon broken? unequip it
|
||||||
|
if (weaphealth == 0)
|
||||||
|
weapon = *inv.unequipItem(weapon, ptr);
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -560,8 +601,8 @@ namespace MWClass
|
||||||
damage = stats.getSkill(weapskill).getModified();
|
damage = stats.getSkill(weapskill).getModified();
|
||||||
damage *= minstrike + ((maxstrike-minstrike)*stats.getAttackStrength());
|
damage *= minstrike + ((maxstrike-minstrike)*stats.getAttackStrength());
|
||||||
|
|
||||||
healthdmg = (otherstats.getFatigue().getCurrent() < 1.0f)
|
healthdmg = (otherstats.getMagicEffects().get(ESM::MagicEffect::Paralyze).mMagnitude > 0)
|
||||||
|| (otherstats.getMagicEffects().get(ESM::MagicEffect::Paralyze).mMagnitude > 0);
|
|| otherstats.getKnockedDown();
|
||||||
if(stats.isWerewolf())
|
if(stats.isWerewolf())
|
||||||
{
|
{
|
||||||
healthdmg = true;
|
healthdmg = true;
|
||||||
|
@ -583,15 +624,21 @@ namespace MWClass
|
||||||
sndMgr->playSound3D(victim, "Hand To Hand Hit", 1.0f, 1.0f);
|
sndMgr->playSound3D(victim, "Hand To Hand Hit", 1.0f, 1.0f);
|
||||||
}
|
}
|
||||||
if(ptr.getRefData().getHandle() == "player")
|
if(ptr.getRefData().getHandle() == "player")
|
||||||
|
{
|
||||||
skillUsageSucceeded(ptr, weapskill, 0);
|
skillUsageSucceeded(ptr, weapskill, 0);
|
||||||
|
|
||||||
bool detected = MWBase::Environment::get().getMechanicsManager()->awarenessCheck(ptr, victim);
|
const MWMechanics::AiSequence& seq = victim.getClass().getCreatureStats(victim).getAiSequence();
|
||||||
if(!detected)
|
|
||||||
{
|
bool unaware = !seq.isInCombat()
|
||||||
damage *= store.find("fCombatCriticalStrikeMult")->getFloat();
|
&& !MWBase::Environment::get().getMechanicsManager()->awarenessCheck(ptr, victim);
|
||||||
MWBase::Environment::get().getWindowManager()->messageBox("#{sTargetCriticalStrike}");
|
if(unaware)
|
||||||
MWBase::Environment::get().getSoundManager()->playSound3D(victim, "critical damage", 1.0f, 1.0f);
|
{
|
||||||
|
damage *= store.find("fCombatCriticalStrikeMult")->getFloat();
|
||||||
|
MWBase::Environment::get().getWindowManager()->messageBox("#{sTargetCriticalStrike}");
|
||||||
|
MWBase::Environment::get().getSoundManager()->playSound3D(victim, "critical damage", 1.0f, 1.0f);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (othercls.getCreatureStats(victim).getKnockedDown())
|
if (othercls.getCreatureStats(victim).getKnockedDown())
|
||||||
damage *= store.find("fCombatKODamageMult")->getFloat();
|
damage *= store.find("fCombatKODamageMult")->getFloat();
|
||||||
|
|
||||||
|
@ -609,6 +656,8 @@ namespace MWClass
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MWMechanics::applyElementalShields(ptr, victim);
|
||||||
|
|
||||||
if (!weapon.isEmpty() && MWMechanics::blockMeleeAttack(ptr, victim, weapon, damage))
|
if (!weapon.isEmpty() && MWMechanics::blockMeleeAttack(ptr, victim, weapon, damage))
|
||||||
damage = 0;
|
damage = 0;
|
||||||
|
|
||||||
|
@ -631,6 +680,14 @@ namespace MWClass
|
||||||
!MWBase::Environment::get().getMechanicsManager()->isAggressive(ptr, attacker))
|
!MWBase::Environment::get().getMechanicsManager()->isAggressive(ptr, attacker))
|
||||||
MWBase::Environment::get().getMechanicsManager()->commitCrime(attacker, ptr, MWBase::MechanicsManager::OT_Assault);
|
MWBase::Environment::get().getMechanicsManager()->commitCrime(attacker, ptr, MWBase::MechanicsManager::OT_Assault);
|
||||||
|
|
||||||
|
if (!attacker.isEmpty() && attacker.getClass().getCreatureStats(attacker).getAiSequence().isInCombat(ptr)
|
||||||
|
&& !ptr.getClass().getCreatureStats(ptr).getAiSequence().isInCombat(attacker))
|
||||||
|
{
|
||||||
|
// Attacker is in combat with us, but we are not in combat with the attacker yet. Time to fight back.
|
||||||
|
// Note: accidental or collateral damage attacks are ignored.
|
||||||
|
MWBase::Environment::get().getMechanicsManager()->startCombat(ptr, attacker);
|
||||||
|
}
|
||||||
|
|
||||||
bool wasDead = getCreatureStats(ptr).isDead();
|
bool wasDead = getCreatureStats(ptr).isDead();
|
||||||
|
|
||||||
getCreatureStats(ptr).setAttacked(true);
|
getCreatureStats(ptr).setAttacked(true);
|
||||||
|
@ -658,6 +715,9 @@ namespace MWClass
|
||||||
if (damage > 0.0f && !object.isEmpty())
|
if (damage > 0.0f && !object.isEmpty())
|
||||||
MWMechanics::resistNormalWeapon(ptr, attacker, object, damage);
|
MWMechanics::resistNormalWeapon(ptr, attacker, object, damage);
|
||||||
|
|
||||||
|
if (damage < 0.001f)
|
||||||
|
damage = 0;
|
||||||
|
|
||||||
if(damage > 0.0f)
|
if(damage > 0.0f)
|
||||||
{
|
{
|
||||||
// 'ptr' is losing health. Play a 'hit' voiced dialog entry if not already saying
|
// 'ptr' is losing health. Play a 'hit' voiced dialog entry if not already saying
|
||||||
|
@ -686,7 +746,7 @@ namespace MWClass
|
||||||
else
|
else
|
||||||
getCreatureStats(ptr).setHitRecovery(true); // Is this supposed to always occur?
|
getCreatureStats(ptr).setHitRecovery(true); // Is this supposed to always occur?
|
||||||
|
|
||||||
if(ishealth && !attacker.isEmpty()) // Don't use armor mitigation for fall damage
|
if(damage > 0 && ishealth && !attacker.isEmpty()) // Don't use armor mitigation for fall damage
|
||||||
{
|
{
|
||||||
// Hit percentages:
|
// Hit percentages:
|
||||||
// cuirass = 30%
|
// cuirass = 30%
|
||||||
|
@ -706,9 +766,12 @@ namespace MWClass
|
||||||
};
|
};
|
||||||
int hitslot = hitslots[(int)(::rand()/(RAND_MAX+1.0)*20.0)];
|
int hitslot = hitslots[(int)(::rand()/(RAND_MAX+1.0)*20.0)];
|
||||||
|
|
||||||
float damagediff = damage;
|
float unmitigatedDamage = damage;
|
||||||
damage /= std::min(1.0f + getArmorRating(ptr)/std::max(1.0f, damage), 4.0f);
|
float x = damage / (damage + getArmorRating(ptr));
|
||||||
damagediff -= damage;
|
damage *= std::max(gmst.fCombatArmorMinMult->getFloat(), x);
|
||||||
|
int damageDiff = unmitigatedDamage - damage;
|
||||||
|
if (damage < 1)
|
||||||
|
damage = 1;
|
||||||
|
|
||||||
MWWorld::InventoryStore &inv = getInventoryStore(ptr);
|
MWWorld::InventoryStore &inv = getInventoryStore(ptr);
|
||||||
MWWorld::ContainerStoreIterator armorslot = inv.getSlot(hitslot);
|
MWWorld::ContainerStoreIterator armorslot = inv.getSlot(hitslot);
|
||||||
|
@ -716,13 +779,13 @@ namespace MWClass
|
||||||
if(!armor.isEmpty() && armor.getTypeName() == typeid(ESM::Armor).name())
|
if(!armor.isEmpty() && armor.getTypeName() == typeid(ESM::Armor).name())
|
||||||
{
|
{
|
||||||
int armorhealth = armor.getClass().getItemHealth(armor);
|
int armorhealth = armor.getClass().getItemHealth(armor);
|
||||||
armorhealth -= std::min(std::max(1, (int)damagediff),
|
armorhealth -= std::min(std::max(1, damageDiff),
|
||||||
armorhealth);
|
armorhealth);
|
||||||
armor.getCellRef().setCharge(armorhealth);
|
armor.getCellRef().setCharge(armorhealth);
|
||||||
|
|
||||||
// Armor broken? unequip it
|
// Armor broken? unequip it
|
||||||
if (armorhealth == 0)
|
if (armorhealth == 0)
|
||||||
inv.unequipItem(armor, ptr);
|
armor = *inv.unequipItem(armor, ptr);
|
||||||
|
|
||||||
if (ptr.getRefData().getHandle() == "player")
|
if (ptr.getRefData().getHandle() == "player")
|
||||||
skillUsageSucceeded(ptr, armor.getClass().getEquipmentSkill(armor), 0);
|
skillUsageSucceeded(ptr, armor.getClass().getEquipmentSkill(armor), 0);
|
||||||
|
@ -747,6 +810,9 @@ namespace MWClass
|
||||||
|
|
||||||
if(ishealth)
|
if(ishealth)
|
||||||
{
|
{
|
||||||
|
if (!attacker.isEmpty())
|
||||||
|
damage = scaleDamage(damage, attacker, ptr);
|
||||||
|
|
||||||
if(damage > 0.0f)
|
if(damage > 0.0f)
|
||||||
sndMgr->playSound3D(ptr, "Health Damage", 1.0f, 1.0f);
|
sndMgr->playSound3D(ptr, "Health Damage", 1.0f, 1.0f);
|
||||||
float health = getCreatureStats(ptr).getHealth().getCurrent() - damage;
|
float health = getCreatureStats(ptr).getHealth().getCurrent() - damage;
|
||||||
|
@ -827,6 +893,7 @@ namespace MWClass
|
||||||
if(ptr.getRefData().getHandle() == "player")
|
if(ptr.getRefData().getHandle() == "player")
|
||||||
return boost::shared_ptr<MWWorld::Action>(new MWWorld::ActionTalk(actor));
|
return boost::shared_ptr<MWWorld::Action>(new MWWorld::ActionTalk(actor));
|
||||||
|
|
||||||
|
// Werewolfs can't activate NPCs
|
||||||
if(actor.getClass().isNpc() && actor.getClass().getNpcStats(actor).isWerewolf())
|
if(actor.getClass().isNpc() && actor.getClass().getNpcStats(actor).isWerewolf())
|
||||||
{
|
{
|
||||||
const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore();
|
const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore();
|
||||||
|
@ -837,6 +904,7 @@ namespace MWClass
|
||||||
|
|
||||||
return action;
|
return action;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(getCreatureStats(ptr).isDead())
|
if(getCreatureStats(ptr).isDead())
|
||||||
return boost::shared_ptr<MWWorld::Action>(new MWWorld::ActionOpen(ptr, true));
|
return boost::shared_ptr<MWWorld::Action>(new MWWorld::ActionOpen(ptr, true));
|
||||||
if(ptr.getClass().getCreatureStats(ptr).isHostile())
|
if(ptr.getClass().getCreatureStats(ptr).isHostile())
|
||||||
|
@ -844,8 +912,10 @@ namespace MWClass
|
||||||
if(getCreatureStats(actor).getStance(MWMechanics::CreatureStats::Stance_Sneak))
|
if(getCreatureStats(actor).getStance(MWMechanics::CreatureStats::Stance_Sneak))
|
||||||
return boost::shared_ptr<MWWorld::Action>(new MWWorld::ActionOpen(ptr)); // stealing
|
return boost::shared_ptr<MWWorld::Action>(new MWWorld::ActionOpen(ptr)); // stealing
|
||||||
|
|
||||||
|
// Can't talk to werewolfs
|
||||||
|
if(ptr.getClass().isNpc() && ptr.getClass().getNpcStats(ptr).isWerewolf())
|
||||||
|
return boost::shared_ptr<MWWorld::Action> (new MWWorld::FailedAction(""));
|
||||||
return boost::shared_ptr<MWWorld::Action>(new MWWorld::ActionTalk(ptr));
|
return boost::shared_ptr<MWWorld::Action>(new MWWorld::ActionTalk(ptr));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MWWorld::ContainerStore& Npc::getContainerStore (const MWWorld::Ptr& ptr)
|
MWWorld::ContainerStore& Npc::getContainerStore (const MWWorld::Ptr& ptr)
|
||||||
|
|
|
@ -40,6 +40,7 @@ namespace MWClass
|
||||||
const ESM::GameSetting *iKnockDownOddsBase;
|
const ESM::GameSetting *iKnockDownOddsBase;
|
||||||
const ESM::GameSetting *fDamageStrengthBase;
|
const ESM::GameSetting *fDamageStrengthBase;
|
||||||
const ESM::GameSetting *fDamageStrengthMult;
|
const ESM::GameSetting *fDamageStrengthMult;
|
||||||
|
const ESM::GameSetting *fCombatArmorMinMult;
|
||||||
};
|
};
|
||||||
|
|
||||||
static const GMST& getGmst();
|
static const GMST& getGmst();
|
||||||
|
|
|
@ -151,8 +151,7 @@ namespace MWClass
|
||||||
info.isPotion = true;
|
info.isPotion = true;
|
||||||
|
|
||||||
if (MWBase::Environment::get().getWindowManager()->getFullHelp()) {
|
if (MWBase::Environment::get().getWindowManager()->getFullHelp()) {
|
||||||
text += MWGui::ToolTips::getMiscString(ptr.getCellRef().getOwner(), "Owner");
|
text += MWGui::ToolTips::getCellRefString(ptr.getCellRef());
|
||||||
text += MWGui::ToolTips::getMiscString(ptr.getCellRef().getFaction(), "Faction");
|
|
||||||
text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script");
|
text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -140,8 +140,7 @@ namespace MWClass
|
||||||
text += MWGui::ToolTips::getValueString(ref->mBase->mData.mValue, "#{sValue}");
|
text += MWGui::ToolTips::getValueString(ref->mBase->mData.mValue, "#{sValue}");
|
||||||
|
|
||||||
if (MWBase::Environment::get().getWindowManager()->getFullHelp()) {
|
if (MWBase::Environment::get().getWindowManager()->getFullHelp()) {
|
||||||
text += MWGui::ToolTips::getMiscString(ptr.getCellRef().getOwner(), "Owner");
|
text += MWGui::ToolTips::getCellRefString(ptr.getCellRef());
|
||||||
text += MWGui::ToolTips::getMiscString(ptr.getCellRef().getFaction(), "Faction");
|
|
||||||
text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script");
|
text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -144,8 +144,7 @@ namespace MWClass
|
||||||
text += MWGui::ToolTips::getValueString(ref->mBase->mData.mValue, "#{sValue}");
|
text += MWGui::ToolTips::getValueString(ref->mBase->mData.mValue, "#{sValue}");
|
||||||
|
|
||||||
if (MWBase::Environment::get().getWindowManager()->getFullHelp()) {
|
if (MWBase::Environment::get().getWindowManager()->getFullHelp()) {
|
||||||
text += MWGui::ToolTips::getMiscString(ptr.getCellRef().getOwner(), "Owner");
|
text += MWGui::ToolTips::getCellRefString(ptr.getCellRef());
|
||||||
text += MWGui::ToolTips::getMiscString(ptr.getCellRef().getFaction(), "Faction");
|
|
||||||
text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script");
|
text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -351,8 +351,7 @@ namespace MWClass
|
||||||
info.remainingEnchantCharge = ptr.getCellRef().getEnchantmentCharge();
|
info.remainingEnchantCharge = ptr.getCellRef().getEnchantmentCharge();
|
||||||
|
|
||||||
if (MWBase::Environment::get().getWindowManager()->getFullHelp()) {
|
if (MWBase::Environment::get().getWindowManager()->getFullHelp()) {
|
||||||
text += MWGui::ToolTips::getMiscString(ptr.getCellRef().getOwner(), "Owner");
|
text += MWGui::ToolTips::getCellRefString(ptr.getCellRef());
|
||||||
text += MWGui::ToolTips::getMiscString(ptr.getCellRef().getFaction(), "Faction");
|
|
||||||
text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script");
|
text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -266,7 +266,7 @@ namespace MWDialogue
|
||||||
}
|
}
|
||||||
catch (const std::exception& error)
|
catch (const std::exception& error)
|
||||||
{
|
{
|
||||||
std::cerr << std::string ("Dialogue error: An exception has been thrown: ") + error.what();
|
std::cerr << std::string ("Dialogue error: An exception has been thrown: ") + error.what() << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -505,9 +505,10 @@ namespace MWDialogue
|
||||||
|
|
||||||
void DialogueManager::askQuestion (const std::string& question, int choice)
|
void DialogueManager::askQuestion (const std::string& question, int choice)
|
||||||
{
|
{
|
||||||
|
mIsInChoice = true;
|
||||||
|
|
||||||
MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow();
|
MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow();
|
||||||
win->addChoice(question, choice);
|
win->addChoice(question, choice);
|
||||||
mIsInChoice = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DialogueManager::goodbye()
|
void DialogueManager::goodbye()
|
||||||
|
|
|
@ -76,8 +76,18 @@ bool MWDialogue::Filter::testActor (const ESM::DialInfo& info) const
|
||||||
}
|
}
|
||||||
else if (info.mData.mRank != -1)
|
else if (info.mData.mRank != -1)
|
||||||
{
|
{
|
||||||
// if there is a rank condition, but the NPC is not in a faction, always fail
|
if (isCreature)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
// Rank requirement, but no faction given. Use the actor's faction, if there is one.
|
||||||
|
MWMechanics::NpcStats& stats = mActor.getClass().getNpcStats (mActor);
|
||||||
|
|
||||||
|
if (!stats.getFactionRanks().size())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// check rank
|
||||||
|
if (stats.getFactionRanks().begin()->second < info.mData.mRank)
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Gender
|
// Gender
|
||||||
|
|
|
@ -153,6 +153,13 @@ void CompanionWindow::onReferenceUnavailable()
|
||||||
MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Companion);
|
MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Companion);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CompanionWindow::resetReference()
|
||||||
|
{
|
||||||
|
ReferenceInterface::resetReference();
|
||||||
|
mItemView->setModel(NULL);
|
||||||
|
mModel = NULL;
|
||||||
|
mSortModel = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,8 @@ namespace MWGui
|
||||||
|
|
||||||
virtual void exit();
|
virtual void exit();
|
||||||
|
|
||||||
|
virtual void resetReference();
|
||||||
|
|
||||||
void open(const MWWorld::Ptr& npc);
|
void open(const MWWorld::Ptr& npc);
|
||||||
void onFrame ();
|
void onFrame ();
|
||||||
|
|
||||||
|
|
|
@ -195,15 +195,6 @@ namespace MWGui
|
||||||
{
|
{
|
||||||
if (mPtr.getTypeName() == typeid(ESM::Container).name())
|
if (mPtr.getTypeName() == typeid(ESM::Container).name())
|
||||||
{
|
{
|
||||||
// check that we don't exceed container capacity
|
|
||||||
MWWorld::Ptr item = mDragAndDrop->mItem.mBase;
|
|
||||||
float weight = item.getClass().getWeight(item) * mDragAndDrop->mDraggedCount;
|
|
||||||
if (mPtr.getClass().getCapacity(mPtr) < mPtr.getClass().getEncumbrance(mPtr) + weight)
|
|
||||||
{
|
|
||||||
MWBase::Environment::get().getWindowManager()->messageBox("#{sContentsMessage3}");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// check container organic flag
|
// check container organic flag
|
||||||
MWWorld::LiveCellRef<ESM::Container>* ref = mPtr.get<ESM::Container>();
|
MWWorld::LiveCellRef<ESM::Container>* ref = mPtr.get<ESM::Container>();
|
||||||
if (ref->mBase->mFlags & ESM::Container::Organic)
|
if (ref->mBase->mFlags & ESM::Container::Organic)
|
||||||
|
@ -212,6 +203,15 @@ namespace MWGui
|
||||||
messageBox("#{sContentsMessage2}");
|
messageBox("#{sContentsMessage2}");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// check that we don't exceed container capacity
|
||||||
|
MWWorld::Ptr item = mDragAndDrop->mItem.mBase;
|
||||||
|
float weight = item.getClass().getWeight(item) * mDragAndDrop->mDraggedCount;
|
||||||
|
if (mPtr.getClass().getCapacity(mPtr) < mPtr.getClass().getEncumbrance(mPtr) + weight)
|
||||||
|
{
|
||||||
|
MWBase::Environment::get().getWindowManager()->messageBox("#{sContentsMessage3}");
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mDragAndDrop->drop(mModel, mItemView);
|
mDragAndDrop->drop(mModel, mItemView);
|
||||||
|
@ -258,6 +258,14 @@ namespace MWGui
|
||||||
onTakeAllButtonClicked(mTakeButton);
|
onTakeAllButtonClicked(mTakeButton);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ContainerWindow::resetReference()
|
||||||
|
{
|
||||||
|
ReferenceInterface::resetReference();
|
||||||
|
mItemView->setModel(NULL);
|
||||||
|
mModel = NULL;
|
||||||
|
mSortModel = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
void ContainerWindow::close()
|
void ContainerWindow::close()
|
||||||
{
|
{
|
||||||
WindowBase::close();
|
WindowBase::close();
|
||||||
|
|
|
@ -54,6 +54,8 @@ namespace MWGui
|
||||||
void open(const MWWorld::Ptr& container, bool loot=false);
|
void open(const MWWorld::Ptr& container, bool loot=false);
|
||||||
virtual void close();
|
virtual void close();
|
||||||
|
|
||||||
|
virtual void resetReference();
|
||||||
|
|
||||||
virtual void exit();
|
virtual void exit();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -273,8 +273,13 @@ namespace MWGui
|
||||||
{
|
{
|
||||||
if ((!mEnabled || MWBase::Environment::get().getDialogueManager()->isInChoice())
|
if ((!mEnabled || MWBase::Environment::get().getDialogueManager()->isInChoice())
|
||||||
&& !mGoodbye)
|
&& !mGoodbye)
|
||||||
return;
|
{
|
||||||
MWBase::Environment::get().getDialogueManager()->goodbyeSelected();
|
// in choice, not allowed to escape, but give access to main menu to allow loading other saves
|
||||||
|
MWBase::Environment::get().getWindowManager()->pushGuiMode (MWGui::GM_MainMenu);
|
||||||
|
MWBase::Environment::get().getSoundManager()->pauseSounds (MWBase::SoundManager::Play_TypeSfx);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
MWBase::Environment::get().getDialogueManager()->goodbyeSelected();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DialogueWindow::onWindowResize(MyGUI::Window* _sender)
|
void DialogueWindow::onWindowResize(MyGUI::Window* _sender)
|
||||||
|
|
|
@ -260,21 +260,28 @@ namespace MWGui
|
||||||
|
|
||||||
// More hacks! The french game uses several win1252 characters that are not included
|
// More hacks! The french game uses several win1252 characters that are not included
|
||||||
// in the cp437 encoding of the font. Fall back to similar available characters.
|
// in the cp437 encoding of the font. Fall back to similar available characters.
|
||||||
// Same for U+2013
|
if (mEncoding == ToUTF8::CP437)
|
||||||
std::map<int, int> additional;
|
|
||||||
additional[39] = 0x2019; // apostrophe
|
|
||||||
additional[45] = 0x2013; // dash
|
|
||||||
if (additional.find(i) != additional.end() && mEncoding == ToUTF8::CP437)
|
|
||||||
{
|
{
|
||||||
MyGUI::xml::ElementPtr code = codes->createChild("Code");
|
std::multimap<int, int> additional;
|
||||||
code->addAttribute("index", additional[i]);
|
additional.insert(std::make_pair(39, 0x2019)); // apostrophe
|
||||||
code->addAttribute("coord", MyGUI::utility::toString(x1) + " "
|
additional.insert(std::make_pair(45, 0x2013)); // dash
|
||||||
+ MyGUI::utility::toString(y1) + " "
|
additional.insert(std::make_pair(34, 0x201D)); // right double quotation mark
|
||||||
+ MyGUI::utility::toString(w) + " "
|
additional.insert(std::make_pair(34, 0x201C)); // left double quotation mark
|
||||||
+ MyGUI::utility::toString(h));
|
for (std::multimap<int, int>::iterator it = additional.begin(); it != additional.end(); ++it)
|
||||||
code->addAttribute("advance", data[i].width);
|
{
|
||||||
code->addAttribute("bearing", MyGUI::utility::toString(data[i].kerning) + " "
|
if (it->first != i)
|
||||||
+ MyGUI::utility::toString((fontSize-data[i].ascent)));
|
continue;
|
||||||
|
|
||||||
|
MyGUI::xml::ElementPtr code = codes->createChild("Code");
|
||||||
|
code->addAttribute("index", it->second);
|
||||||
|
code->addAttribute("coord", MyGUI::utility::toString(x1) + " "
|
||||||
|
+ MyGUI::utility::toString(y1) + " "
|
||||||
|
+ MyGUI::utility::toString(w) + " "
|
||||||
|
+ MyGUI::utility::toString(h));
|
||||||
|
code->addAttribute("advance", data[i].width);
|
||||||
|
code->addAttribute("bearing", MyGUI::utility::toString(data[i].kerning) + " "
|
||||||
|
+ MyGUI::utility::toString((fontSize-data[i].ascent)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ASCII vertical bar, use this as text input cursor
|
// ASCII vertical bar, use this as text input cursor
|
||||||
|
|
|
@ -92,6 +92,7 @@ namespace MWGui
|
||||||
, mSpellVisible(true)
|
, mSpellVisible(true)
|
||||||
, mWorldMouseOver(false)
|
, mWorldMouseOver(false)
|
||||||
, mEnemyHealthTimer(-1)
|
, mEnemyHealthTimer(-1)
|
||||||
|
, mEnemyActorId(-1)
|
||||||
, mIsDrowning(false)
|
, mIsDrowning(false)
|
||||||
, mWeaponSpellTimer(0.f)
|
, mWeaponSpellTimer(0.f)
|
||||||
, mDrowningFlashTheta(0.f)
|
, mDrowningFlashTheta(0.f)
|
||||||
|
@ -609,7 +610,10 @@ namespace MWGui
|
||||||
|
|
||||||
void HUD::updateEnemyHealthBar()
|
void HUD::updateEnemyHealthBar()
|
||||||
{
|
{
|
||||||
MWMechanics::CreatureStats& stats = mEnemy.getClass().getCreatureStats(mEnemy);
|
MWWorld::Ptr enemy = MWBase::Environment::get().getWorld()->searchPtrViaActorId(mEnemyActorId);
|
||||||
|
if (enemy.isEmpty())
|
||||||
|
return;
|
||||||
|
MWMechanics::CreatureStats& stats = enemy.getClass().getCreatureStats(enemy);
|
||||||
mEnemyHealth->setProgressRange(100);
|
mEnemyHealth->setProgressRange(100);
|
||||||
// Health is usually cast to int before displaying. Actors die whenever they are < 1 health.
|
// Health is usually cast to int before displaying. Actors die whenever they are < 1 health.
|
||||||
// Therefore any value < 1 should show as an empty health bar. We do the same in statswindow :)
|
// Therefore any value < 1 should show as an empty health bar. We do the same in statswindow :)
|
||||||
|
@ -620,7 +624,7 @@ namespace MWGui
|
||||||
{
|
{
|
||||||
mSpellIcons->updateWidgets(mEffectBox, true);
|
mSpellIcons->updateWidgets(mEffectBox, true);
|
||||||
|
|
||||||
if (!mEnemy.isEmpty() && mEnemyHealth->getVisible())
|
if (mEnemyActorId != -1 && mEnemyHealth->getVisible())
|
||||||
{
|
{
|
||||||
updateEnemyHealthBar();
|
updateEnemyHealthBar();
|
||||||
}
|
}
|
||||||
|
@ -634,7 +638,7 @@ namespace MWGui
|
||||||
|
|
||||||
void HUD::setEnemy(const MWWorld::Ptr &enemy)
|
void HUD::setEnemy(const MWWorld::Ptr &enemy)
|
||||||
{
|
{
|
||||||
mEnemy = enemy;
|
mEnemyActorId = enemy.getClass().getCreatureStats(enemy).getActorId();
|
||||||
mEnemyHealthTimer = 5;
|
mEnemyHealthTimer = 5;
|
||||||
if (!mEnemyHealth->getVisible())
|
if (!mEnemyHealth->getVisible())
|
||||||
mWeaponSpellBox->setPosition(mWeaponSpellBox->getPosition() - MyGUI::IntPoint(0,20));
|
mWeaponSpellBox->setPosition(mWeaponSpellBox->getPosition() - MyGUI::IntPoint(0,20));
|
||||||
|
@ -644,7 +648,7 @@ namespace MWGui
|
||||||
|
|
||||||
void HUD::resetEnemy()
|
void HUD::resetEnemy()
|
||||||
{
|
{
|
||||||
mEnemy = MWWorld::Ptr();
|
mEnemyActorId = -1;
|
||||||
mEnemyHealthTimer = -1;
|
mEnemyHealthTimer = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -104,7 +104,7 @@ namespace MWGui
|
||||||
|
|
||||||
SpellIcons* mSpellIcons;
|
SpellIcons* mSpellIcons;
|
||||||
|
|
||||||
MWWorld::Ptr mEnemy;
|
int mEnemyActorId;
|
||||||
float mEnemyHealthTimer;
|
float mEnemyHealthTimer;
|
||||||
|
|
||||||
bool mIsDrowning;
|
bool mIsDrowning;
|
||||||
|
|
|
@ -140,26 +140,28 @@ void ItemView::onMouseWheel(MyGUI::Widget *_sender, int _rel)
|
||||||
|
|
||||||
void ItemView::setSize(const MyGUI::IntSize &_value)
|
void ItemView::setSize(const MyGUI::IntSize &_value)
|
||||||
{
|
{
|
||||||
|
bool changed = (_value.width != getWidth() || _value.height != getHeight());
|
||||||
Base::setSize(_value);
|
Base::setSize(_value);
|
||||||
update();
|
if (changed)
|
||||||
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ItemView::setSize(int _width, int _height)
|
void ItemView::setSize(int _width, int _height)
|
||||||
{
|
{
|
||||||
Base::setSize(_width, _height);
|
setSize(MyGUI::IntSize(_width, _height));
|
||||||
update();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ItemView::setCoord(const MyGUI::IntCoord &_value)
|
void ItemView::setCoord(const MyGUI::IntCoord &_value)
|
||||||
{
|
{
|
||||||
|
bool changed = (_value.width != getWidth() || _value.height != getHeight());
|
||||||
Base::setCoord(_value);
|
Base::setCoord(_value);
|
||||||
update();
|
if (changed)
|
||||||
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ItemView::setCoord(int _left, int _top, int _width, int _height)
|
void ItemView::setCoord(int _left, int _top, int _width, int _height)
|
||||||
{
|
{
|
||||||
Base::setCoord(_left, _top, _width, _height);
|
setCoord(MyGUI::IntCoord(_left, _top, _width, _height));
|
||||||
update();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ItemView::registerComponents()
|
void ItemView::registerComponents()
|
||||||
|
|
|
@ -259,7 +259,7 @@ struct JournalViewModelImpl : JournalViewModel
|
||||||
os
|
os
|
||||||
<< itr->mDayOfMonth << ' '
|
<< itr->mDayOfMonth << ' '
|
||||||
<< MWBase::Environment::get().getWorld()->getMonthName (itr->mMonth)
|
<< MWBase::Environment::get().getWorld()->getMonthName (itr->mMonth)
|
||||||
<< " (" << dayStr << " " << (itr->mDay + 1) << ')';
|
<< " (" << dayStr << " " << (itr->mDay) << ')';
|
||||||
|
|
||||||
timestamp_buffer = os.str ();
|
timestamp_buffer = os.str ();
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,9 +16,10 @@
|
||||||
|
|
||||||
namespace MWGui
|
namespace MWGui
|
||||||
{
|
{
|
||||||
|
const unsigned int LevelupDialog::sMaxCoins = 3;
|
||||||
LevelupDialog::LevelupDialog()
|
LevelupDialog::LevelupDialog()
|
||||||
: WindowBase("openmw_levelup_dialog.layout")
|
: WindowBase("openmw_levelup_dialog.layout"),
|
||||||
|
mCoinCount(sMaxCoins)
|
||||||
{
|
{
|
||||||
getWidget(mOkButton, "OkButton");
|
getWidget(mOkButton, "OkButton");
|
||||||
getWidget(mClassImage, "ClassImage");
|
getWidget(mClassImage, "ClassImage");
|
||||||
|
@ -46,12 +47,10 @@ namespace MWGui
|
||||||
mAttributeMultipliers.push_back(t);
|
mAttributeMultipliers.push_back(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
int curX = mMainWidget->getWidth()/2 - (16 + 2) * 1.5;
|
for (unsigned int i = 0; i < mCoinCount; ++i)
|
||||||
for (int i=0; i<3; ++i)
|
|
||||||
{
|
{
|
||||||
MyGUI::ImageBox* image = mMainWidget->createWidget<MyGUI::ImageBox>("ImageBox", MyGUI::IntCoord(curX,250,16,16), MyGUI::Align::Default);
|
MyGUI::ImageBox* image = mCoinBox->createWidget<MyGUI::ImageBox>("ImageBox", MyGUI::IntCoord(0,0,16,16), MyGUI::Align::Default);
|
||||||
image->setImageTexture ("icons\\tx_goldicon.dds");
|
image->setImageTexture ("icons\\tx_goldicon.dds");
|
||||||
curX += 24+2;
|
|
||||||
mCoins.push_back(image);
|
mCoins.push_back(image);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,15 +60,15 @@ namespace MWGui
|
||||||
void LevelupDialog::setAttributeValues()
|
void LevelupDialog::setAttributeValues()
|
||||||
{
|
{
|
||||||
MWWorld::Ptr player = MWBase::Environment::get().getWorld ()->getPlayerPtr();
|
MWWorld::Ptr player = MWBase::Environment::get().getWorld ()->getPlayerPtr();
|
||||||
MWMechanics::CreatureStats& creatureStats = player.getClass().getCreatureStats (player);
|
MWMechanics::CreatureStats& creatureStats = player.getClass().getCreatureStats(player);
|
||||||
MWMechanics::NpcStats& pcStats = player.getClass().getNpcStats (player);
|
MWMechanics::NpcStats& pcStats = player.getClass().getNpcStats (player);
|
||||||
|
|
||||||
for (int i=0; i<8; ++i)
|
for (int i = 0; i < 8; ++i)
|
||||||
{
|
{
|
||||||
int val = creatureStats.getAttribute (i).getBase ();
|
int val = creatureStats.getAttribute(i).getBase();
|
||||||
if (std::find(mSpentAttributes.begin(), mSpentAttributes.end(), i) != mSpentAttributes.end())
|
if (std::find(mSpentAttributes.begin(), mSpentAttributes.end(), i) != mSpentAttributes.end())
|
||||||
{
|
{
|
||||||
val += pcStats.getLevelupAttributeMultiplier (i);
|
val += pcStats.getLevelupAttributeMultiplier(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (val >= 100)
|
if (val >= 100)
|
||||||
|
@ -80,20 +79,21 @@ namespace MWGui
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void LevelupDialog::resetCoins ()
|
void LevelupDialog::resetCoins()
|
||||||
{
|
{
|
||||||
int curX = 0;
|
const int coinSpacing = 10;
|
||||||
for (int i=0; i<3; ++i)
|
int curX = mCoinBox->getWidth()/2 - (coinSpacing*(mCoinCount - 1) + 16*mCoinCount)/2;
|
||||||
|
for (unsigned int i=0; i<mCoinCount; ++i)
|
||||||
{
|
{
|
||||||
MyGUI::ImageBox* image = mCoins[i];
|
MyGUI::ImageBox* image = mCoins[i];
|
||||||
image->detachFromWidget();
|
image->detachFromWidget();
|
||||||
image->attachToWidget(mCoinBox);
|
image->attachToWidget(mCoinBox);
|
||||||
image->setCoord(MyGUI::IntCoord(curX,0,16,16));
|
image->setCoord(MyGUI::IntCoord(curX,0,16,16));
|
||||||
curX += 24+2;
|
curX += 16+coinSpacing;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void LevelupDialog::assignCoins ()
|
void LevelupDialog::assignCoins()
|
||||||
{
|
{
|
||||||
resetCoins();
|
resetCoins();
|
||||||
for (unsigned int i=0; i<mSpentAttributes.size(); ++i)
|
for (unsigned int i=0; i<mSpentAttributes.size(); ++i)
|
||||||
|
@ -118,13 +118,8 @@ namespace MWGui
|
||||||
{
|
{
|
||||||
MWBase::World *world = MWBase::Environment::get().getWorld();
|
MWBase::World *world = MWBase::Environment::get().getWorld();
|
||||||
MWWorld::Ptr player = world->getPlayerPtr();
|
MWWorld::Ptr player = world->getPlayerPtr();
|
||||||
MWMechanics::CreatureStats& creatureStats = player.getClass().getCreatureStats (player);
|
MWMechanics::CreatureStats& creatureStats = player.getClass().getCreatureStats(player);
|
||||||
MWMechanics::NpcStats& pcStats = player.getClass().getNpcStats (player);
|
MWMechanics::NpcStats& pcStats = player.getClass().getNpcStats(player);
|
||||||
|
|
||||||
mSpentAttributes.clear();
|
|
||||||
resetCoins();
|
|
||||||
|
|
||||||
setAttributeValues();
|
|
||||||
|
|
||||||
const ESM::NPC *playerData = player.get<ESM::NPC>()->mBase;
|
const ESM::NPC *playerData = player.get<ESM::NPC>()->mBase;
|
||||||
|
|
||||||
|
@ -132,82 +127,111 @@ namespace MWGui
|
||||||
const ESM::Class *cls =
|
const ESM::Class *cls =
|
||||||
world->getStore().get<ESM::Class>().find(playerData->mClass);
|
world->getStore().get<ESM::Class>().find(playerData->mClass);
|
||||||
|
|
||||||
// Vanilla uses thief.dds for custom classes. A player with a custom class
|
|
||||||
// doesn't have mId set, see mwworld/esmstore.hpp where it is initialised as
|
|
||||||
// "$dynamic0". This check should resolve bug #1260.
|
|
||||||
// Choosing Stealth specialization and Speed/Agility as attributes.
|
|
||||||
if(world->getStore().get<ESM::Class>().isDynamic(cls->mId))
|
if(world->getStore().get<ESM::Class>().isDynamic(cls->mId))
|
||||||
{
|
{
|
||||||
|
// Vanilla uses thief.dds for custom classes.
|
||||||
|
// Choosing Stealth specialization and Speed/Agility as attributes, if possible. Otherwise fall back to first class found.
|
||||||
MWWorld::SharedIterator<ESM::Class> it = world->getStore().get<ESM::Class>().begin();
|
MWWorld::SharedIterator<ESM::Class> it = world->getStore().get<ESM::Class>().begin();
|
||||||
for(; it != world->getStore().get<ESM::Class>().end(); it++)
|
for(; it != world->getStore().get<ESM::Class>().end(); it++)
|
||||||
{
|
{
|
||||||
if(it->mData.mIsPlayable && it->mData.mSpecialization == 2 && it->mData.mAttribute[0] == 4 && it->mData.mAttribute[1] == 3)
|
if(it->mData.mIsPlayable && it->mData.mSpecialization == 2 && it->mData.mAttribute[0] == 4 && it->mData.mAttribute[1] == 3)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
mClassImage->setImageTexture ("textures\\levelup\\" + it->mId + ".dds");
|
if (it == world->getStore().get<ESM::Class>().end())
|
||||||
|
it = world->getStore().get<ESM::Class>().begin();
|
||||||
|
if (it != world->getStore().get<ESM::Class>().end())
|
||||||
|
cls = &*it;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
mClassImage->setImageTexture ("textures\\levelup\\" + cls->mId + ".dds");
|
mClassImage->setImageTexture ("textures\\levelup\\" + cls->mId + ".dds");
|
||||||
|
|
||||||
int level = creatureStats.getLevel ()+1;
|
int level = creatureStats.getLevel ()+1;
|
||||||
mLevelText->setCaptionWithReplacing("#{sLevelUpMenu1} " + boost::lexical_cast<std::string>(level));
|
mLevelText->setCaptionWithReplacing("#{sLevelUpMenu1} " + boost::lexical_cast<std::string>(level));
|
||||||
|
|
||||||
std::string levelupdescription;
|
std::string levelupdescription;
|
||||||
if(level>20)
|
if(level > 20)
|
||||||
levelupdescription=world->getFallback()->getFallbackString("Level_Up_Default");
|
levelupdescription=world->getFallback()->getFallbackString("Level_Up_Default");
|
||||||
else
|
else
|
||||||
levelupdescription=world->getFallback()->getFallbackString("Level_Up_Level"+boost::lexical_cast<std::string>(level));
|
levelupdescription=world->getFallback()->getFallbackString("Level_Up_Level"+boost::lexical_cast<std::string>(level));
|
||||||
|
|
||||||
mLevelDescription->setCaption (levelupdescription);
|
mLevelDescription->setCaption (levelupdescription);
|
||||||
|
|
||||||
for (int i=0; i<8; ++i)
|
unsigned int availableAttributes = 0;
|
||||||
|
for (int i = 0; i < 8; ++i)
|
||||||
{
|
{
|
||||||
MyGUI::TextBox* text = mAttributeMultipliers[i];
|
MyGUI::TextBox* text = mAttributeMultipliers[i];
|
||||||
int mult = pcStats.getLevelupAttributeMultiplier (i);
|
if (pcStats.getAttribute(i).getBase() < 100)
|
||||||
text->setCaption(mult <= 1 ? "" : "x" + boost::lexical_cast<std::string>(mult));
|
{
|
||||||
|
mAttributes[i]->setEnabled(true);
|
||||||
|
availableAttributes++;
|
||||||
|
|
||||||
|
int mult = pcStats.getLevelupAttributeMultiplier (i);
|
||||||
|
text->setCaption(mult <= 1 ? "" : "x" + boost::lexical_cast<std::string>(mult));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mAttributes[i]->setEnabled(false);
|
||||||
|
|
||||||
|
text->setCaption("");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mCoinCount = std::min(sMaxCoins, availableAttributes);
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < sMaxCoins; i++)
|
||||||
|
{
|
||||||
|
if (i < mCoinCount)
|
||||||
|
mCoins[i]->attachToWidget(mCoinBox);
|
||||||
|
else
|
||||||
|
mCoins[i]->detachFromWidget();
|
||||||
|
}
|
||||||
|
|
||||||
|
mSpentAttributes.clear();
|
||||||
|
resetCoins();
|
||||||
|
|
||||||
|
setAttributeValues();
|
||||||
|
|
||||||
center();
|
center();
|
||||||
}
|
}
|
||||||
|
|
||||||
void LevelupDialog::onOkButtonClicked (MyGUI::Widget* sender)
|
void LevelupDialog::onOkButtonClicked(MyGUI::Widget* sender)
|
||||||
{
|
{
|
||||||
MWWorld::Ptr player = MWBase::Environment::get().getWorld ()->getPlayerPtr();
|
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
|
||||||
MWMechanics::NpcStats& pcStats = player.getClass().getNpcStats (player);
|
MWMechanics::NpcStats& pcStats = player.getClass().getNpcStats (player);
|
||||||
|
|
||||||
if (mSpentAttributes.size() < 3)
|
if (mSpentAttributes.size() < mCoinCount)
|
||||||
MWBase::Environment::get().getWindowManager ()->messageBox("#{sNotifyMessage36}");
|
MWBase::Environment::get().getWindowManager()->messageBox("#{sNotifyMessage36}");
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// increase attributes
|
// increase attributes
|
||||||
for (int i=0; i<3; ++i)
|
for (unsigned int i = 0; i < mCoinCount; ++i)
|
||||||
{
|
{
|
||||||
MWMechanics::AttributeValue attribute = pcStats.getAttribute(mSpentAttributes[i]);
|
MWMechanics::AttributeValue attribute = pcStats.getAttribute(mSpentAttributes[i]);
|
||||||
attribute.setBase (attribute.getBase () + pcStats.getLevelupAttributeMultiplier (mSpentAttributes[i]));
|
attribute.setBase(attribute.getBase() + pcStats.getLevelupAttributeMultiplier(mSpentAttributes[i]));
|
||||||
|
|
||||||
if (attribute.getBase() >= 100)
|
if (attribute.getBase() >= 100)
|
||||||
attribute.setBase(100);
|
attribute.setBase(100);
|
||||||
pcStats.setAttribute(mSpentAttributes[i], attribute);
|
pcStats.setAttribute(mSpentAttributes[i], attribute);
|
||||||
}
|
}
|
||||||
|
|
||||||
pcStats.levelUp ();
|
pcStats.levelUp();
|
||||||
|
|
||||||
MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_Levelup);
|
MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Levelup);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void LevelupDialog::onAttributeClicked (MyGUI::Widget *sender)
|
void LevelupDialog::onAttributeClicked(MyGUI::Widget *sender)
|
||||||
{
|
{
|
||||||
int attribute = *sender->getUserData<int>();
|
int attribute = *sender->getUserData<int>();
|
||||||
|
|
||||||
std::vector<int>::iterator found = std::find(mSpentAttributes.begin(), mSpentAttributes.end(), attribute);
|
std::vector<int>::iterator found = std::find(mSpentAttributes.begin(), mSpentAttributes.end(), attribute);
|
||||||
if (found != mSpentAttributes.end())
|
if (found != mSpentAttributes.end())
|
||||||
mSpentAttributes.erase (found);
|
mSpentAttributes.erase(found);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (mSpentAttributes.size() == 3)
|
if (mSpentAttributes.size() == mCoinCount)
|
||||||
mSpentAttributes[2] = attribute;
|
mSpentAttributes[mCoinCount - 1] = attribute;
|
||||||
else
|
else
|
||||||
mSpentAttributes.push_back(attribute);
|
mSpentAttributes.push_back(attribute);
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,8 +28,11 @@ namespace MWGui
|
||||||
|
|
||||||
std::vector<int> mSpentAttributes;
|
std::vector<int> mSpentAttributes;
|
||||||
|
|
||||||
void onOkButtonClicked (MyGUI::Widget* sender);
|
unsigned int mCoinCount;
|
||||||
void onAttributeClicked (MyGUI::Widget* sender);
|
static const unsigned int sMaxCoins;
|
||||||
|
|
||||||
|
void onOkButtonClicked(MyGUI::Widget* sender);
|
||||||
|
void onAttributeClicked(MyGUI::Widget* sender);
|
||||||
|
|
||||||
void assignCoins();
|
void assignCoins();
|
||||||
void resetCoins();
|
void resetCoins();
|
||||||
|
|
|
@ -117,15 +117,18 @@ void MerchantRepair::exit()
|
||||||
|
|
||||||
void MerchantRepair::onRepairButtonClick(MyGUI::Widget *sender)
|
void MerchantRepair::onRepairButtonClick(MyGUI::Widget *sender)
|
||||||
{
|
{
|
||||||
|
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
|
||||||
|
|
||||||
// repair
|
// repair
|
||||||
MWWorld::Ptr item = *sender->getUserData<MWWorld::Ptr>();
|
MWWorld::Ptr item = *sender->getUserData<MWWorld::Ptr>();
|
||||||
item.getCellRef().setCharge(item.getClass().getItemMaxHealth(item));
|
item.getCellRef().setCharge(item.getClass().getItemMaxHealth(item));
|
||||||
|
|
||||||
|
player.getClass().getContainerStore(player).restack(item);
|
||||||
|
|
||||||
MWBase::Environment::get().getSoundManager()->playSound("Repair",1,1);
|
MWBase::Environment::get().getSoundManager()->playSound("Repair",1,1);
|
||||||
|
|
||||||
int price = boost::lexical_cast<int>(sender->getUserString("Price"));
|
int price = boost::lexical_cast<int>(sender->getUserString("Price"));
|
||||||
|
|
||||||
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
|
|
||||||
player.getClass().getContainerStore(player).remove(MWWorld::ContainerStore::sGoldId, price, player);
|
player.getClass().getContainerStore(player).remove(MWWorld::ContainerStore::sGoldId, price, player);
|
||||||
|
|
||||||
startRepair(mActor);
|
startRepair(mActor);
|
||||||
|
|
|
@ -165,6 +165,8 @@ void Recharge::onItemClicked(MyGUI::Widget *sender)
|
||||||
item.getCellRef().setEnchantmentCharge(
|
item.getCellRef().setEnchantmentCharge(
|
||||||
std::min(item.getCellRef().getEnchantmentCharge() + restored, static_cast<float>(enchantment->mData.mCharge)));
|
std::min(item.getCellRef().getEnchantmentCharge() + restored, static_cast<float>(enchantment->mData.mCharge)));
|
||||||
|
|
||||||
|
player.getClass().getContainerStore(player).restack(item);
|
||||||
|
|
||||||
player.getClass().skillUsageSucceeded (player, ESM::Skill::Enchant, 0);
|
player.getClass().skillUsageSucceeded (player, ESM::Skill::Enchant, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -157,6 +157,8 @@ namespace MWGui
|
||||||
{
|
{
|
||||||
configureWidgets(mMainWidget);
|
configureWidgets(mMainWidget);
|
||||||
|
|
||||||
|
setTitle("#{sOptions}");
|
||||||
|
|
||||||
getWidget(mOkButton, "OkButton");
|
getWidget(mOkButton, "OkButton");
|
||||||
getWidget(mResolutionList, "ResolutionList");
|
getWidget(mResolutionList, "ResolutionList");
|
||||||
getWidget(mFullscreenButton, "FullscreenButton");
|
getWidget(mFullscreenButton, "FullscreenButton");
|
||||||
|
@ -174,6 +176,7 @@ namespace MWGui
|
||||||
getWidget(mControlsBox, "ControlsBox");
|
getWidget(mControlsBox, "ControlsBox");
|
||||||
getWidget(mResetControlsButton, "ResetControlsButton");
|
getWidget(mResetControlsButton, "ResetControlsButton");
|
||||||
getWidget(mRefractionButton, "RefractionButton");
|
getWidget(mRefractionButton, "RefractionButton");
|
||||||
|
getWidget(mDifficultySlider, "DifficultySlider");
|
||||||
|
|
||||||
mOkButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onOkButtonClicked);
|
mOkButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onOkButtonClicked);
|
||||||
mShaderModeButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onShaderModeToggled);
|
mShaderModeButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onShaderModeToggled);
|
||||||
|
@ -227,6 +230,10 @@ namespace MWGui
|
||||||
MyGUI::TextBox* fovText;
|
MyGUI::TextBox* fovText;
|
||||||
getWidget(fovText, "FovText");
|
getWidget(fovText, "FovText");
|
||||||
fovText->setCaption("Field of View (" + boost::lexical_cast<std::string>(int(Settings::Manager::getInt("field of view", "General"))) + ")");
|
fovText->setCaption("Field of View (" + boost::lexical_cast<std::string>(int(Settings::Manager::getInt("field of view", "General"))) + ")");
|
||||||
|
|
||||||
|
MyGUI::TextBox* diffText;
|
||||||
|
getWidget(diffText, "DifficultyText");
|
||||||
|
diffText->setCaptionWithReplacing("#{sDifficulty} (" + boost::lexical_cast<std::string>(int(Settings::Manager::getInt("difficulty", "Game"))) + ")");
|
||||||
}
|
}
|
||||||
|
|
||||||
void SettingsWindow::onOkButtonClicked(MyGUI::Widget* _sender)
|
void SettingsWindow::onOkButtonClicked(MyGUI::Widget* _sender)
|
||||||
|
@ -406,6 +413,12 @@ namespace MWGui
|
||||||
getWidget(fovText, "FovText");
|
getWidget(fovText, "FovText");
|
||||||
fovText->setCaption("Field of View (" + boost::lexical_cast<std::string>(int(value)) + ")");
|
fovText->setCaption("Field of View (" + boost::lexical_cast<std::string>(int(value)) + ")");
|
||||||
}
|
}
|
||||||
|
if (scroller == mDifficultySlider)
|
||||||
|
{
|
||||||
|
MyGUI::TextBox* diffText;
|
||||||
|
getWidget(diffText, "DifficultyText");
|
||||||
|
diffText->setCaptionWithReplacing("#{sDifficulty} (" + boost::lexical_cast<std::string>(int(value)) + ")");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -30,6 +30,7 @@ namespace MWGui
|
||||||
MyGUI::Button* mVSyncButton;
|
MyGUI::Button* mVSyncButton;
|
||||||
MyGUI::Button* mFPSButton;
|
MyGUI::Button* mFPSButton;
|
||||||
MyGUI::ScrollBar* mFOVSlider;
|
MyGUI::ScrollBar* mFOVSlider;
|
||||||
|
MyGUI::ScrollBar* mDifficultySlider;
|
||||||
MyGUI::ScrollBar* mAnisotropySlider;
|
MyGUI::ScrollBar* mAnisotropySlider;
|
||||||
MyGUI::ComboBox* mTextureFilteringButton;
|
MyGUI::ComboBox* mTextureFilteringButton;
|
||||||
MyGUI::TextBox* mAnisotropyLabel;
|
MyGUI::TextBox* mAnisotropyLabel;
|
||||||
|
|
|
@ -321,6 +321,11 @@ namespace MWGui
|
||||||
skillValueWidget->_setWidgetState(state);
|
skillValueWidget->_setWidgetState(state);
|
||||||
skillValueWidget->eventMouseWheel += MyGUI::newDelegate(this, &StatsWindow::onMouseWheel);
|
skillValueWidget->eventMouseWheel += MyGUI::newDelegate(this, &StatsWindow::onMouseWheel);
|
||||||
|
|
||||||
|
// resize dynamically according to text size
|
||||||
|
int textWidthPlusMargin = skillValueWidget->getTextSize().width + 12;
|
||||||
|
skillValueWidget->setCoord(coord2.left + coord2.width - textWidthPlusMargin, coord2.top, textWidthPlusMargin, coord2.height);
|
||||||
|
skillNameWidget->setSize(skillNameWidget->getSize() + MyGUI::IntSize(coord2.width - textWidthPlusMargin, 0));
|
||||||
|
|
||||||
mSkillWidgets.push_back(skillNameWidget);
|
mSkillWidgets.push_back(skillNameWidget);
|
||||||
mSkillWidgets.push_back(skillValueWidget);
|
mSkillWidgets.push_back(skillValueWidget);
|
||||||
|
|
||||||
|
|
|
@ -547,6 +547,17 @@ namespace MWGui
|
||||||
return " (" + boost::lexical_cast<std::string>(value) + ")";
|
return " (" + boost::lexical_cast<std::string>(value) + ")";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string ToolTips::getCellRefString(const MWWorld::CellRef& cellref)
|
||||||
|
{
|
||||||
|
std::string ret;
|
||||||
|
ret += getMiscString(cellref.getOwner(), "Owner");
|
||||||
|
ret += getMiscString(cellref.getFaction(), "Faction");
|
||||||
|
if (cellref.getFactionRank() > 0)
|
||||||
|
ret += getValueString(cellref.getFactionRank(), "Rank");
|
||||||
|
ret += getMiscString(cellref.getGlobalVariable(), "Global");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
bool ToolTips::toggleFullHelp()
|
bool ToolTips::toggleFullHelp()
|
||||||
{
|
{
|
||||||
mFullHelp = !mFullHelp;
|
mFullHelp = !mFullHelp;
|
||||||
|
|
|
@ -66,6 +66,9 @@ namespace MWGui
|
||||||
static std::string getCountString(const int value);
|
static std::string getCountString(const int value);
|
||||||
///< @return blank string if count is 1, or else " (value)"
|
///< @return blank string if count is 1, or else " (value)"
|
||||||
|
|
||||||
|
static std::string getCellRefString(const MWWorld::CellRef& cellref);
|
||||||
|
///< Returns a string containing debug tooltip information about the given cellref.
|
||||||
|
|
||||||
// these do not create an actual tooltip, but they fill in the data that is required so the tooltip
|
// these do not create an actual tooltip, but they fill in the data that is required so the tooltip
|
||||||
// system knows what to show in case this widget is hovered
|
// system knows what to show in case this widget is hovered
|
||||||
static void createSkillToolTip(MyGUI::Widget* widget, int skillId);
|
static void createSkillToolTip(MyGUI::Widget* widget, int skillId);
|
||||||
|
|
|
@ -531,4 +531,12 @@ namespace MWGui
|
||||||
sellerStats.setLastRestockTime(MWBase::Environment::get().getWorld()->getTimeStamp());
|
sellerStats.setLastRestockTime(MWBase::Environment::get().getWorld()->getTimeStamp());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TradeWindow::resetReference()
|
||||||
|
{
|
||||||
|
ReferenceInterface::resetReference();
|
||||||
|
mItemView->setModel(NULL);
|
||||||
|
mTradeModel = NULL;
|
||||||
|
mSortModel = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,6 +37,7 @@ namespace MWGui
|
||||||
|
|
||||||
virtual void exit();
|
virtual void exit();
|
||||||
|
|
||||||
|
virtual void resetReference();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ItemView* mItemView;
|
ItemView* mItemView;
|
||||||
|
|
|
@ -268,7 +268,7 @@ namespace MWGui
|
||||||
mCompanionWindow = new CompanionWindow(mDragAndDrop, mMessageBoxManager);
|
mCompanionWindow = new CompanionWindow(mDragAndDrop, mMessageBoxManager);
|
||||||
trackWindow(mCompanionWindow, "companion");
|
trackWindow(mCompanionWindow, "companion");
|
||||||
|
|
||||||
mInputBlocker = mGui->createWidget<MyGUI::Widget>("",0,0,w,h,MyGUI::Align::Default,"Windows");
|
mInputBlocker = mGui->createWidget<MyGUI::Widget>("",0,0,w,h,MyGUI::Align::Default,"Overlay");
|
||||||
|
|
||||||
mHud->setVisible(mHudEnabled);
|
mHud->setVisible(mHudEnabled);
|
||||||
|
|
||||||
|
@ -1529,6 +1529,8 @@ namespace MWGui
|
||||||
mCompanionWindow->resetReference();
|
mCompanionWindow->resetReference();
|
||||||
mConsole->resetReference();
|
mConsole->resetReference();
|
||||||
|
|
||||||
|
mSelectedSpell.clear();
|
||||||
|
|
||||||
mGuiModes.clear();
|
mGuiModes.clear();
|
||||||
MWBase::Environment::get().getInputManager()->changeInputMode(false);
|
MWBase::Environment::get().getInputManager()->changeInputMode(false);
|
||||||
updateVisible();
|
updateVisible();
|
||||||
|
|
|
@ -686,14 +686,6 @@ namespace MWInput
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(MWBase::Environment::get().getWindowManager()->getMode() == MWGui::GM_Dialogue) { //Give access to the main menu when at a choice in dialogue
|
|
||||||
if(MWBase::Environment::get().getDialogueManager()->isInChoice()) {
|
|
||||||
MWBase::Environment::get().getWindowManager()->pushGuiMode (MWGui::GM_MainMenu);
|
|
||||||
MWBase::Environment::get().getSoundManager()->pauseSounds (MWBase::SoundManager::Play_TypeSfx);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!MWBase::Environment::get().getWindowManager()->isGuiMode()) //No open GUIs, open up the MainMenu
|
if(!MWBase::Environment::get().getWindowManager()->isGuiMode()) //No open GUIs, open up the MainMenu
|
||||||
{
|
{
|
||||||
MWBase::Environment::get().getWindowManager()->pushGuiMode (MWGui::GM_MainMenu);
|
MWBase::Environment::get().getWindowManager()->pushGuiMode (MWGui::GM_MainMenu);
|
||||||
|
@ -707,11 +699,13 @@ namespace MWInput
|
||||||
}
|
}
|
||||||
|
|
||||||
void InputManager::quickLoad() {
|
void InputManager::quickLoad() {
|
||||||
MWBase::Environment::get().getStateManager()->quickLoad();
|
if (!MyGUI::InputManager::getInstance().isModalAny())
|
||||||
|
MWBase::Environment::get().getStateManager()->quickLoad();
|
||||||
}
|
}
|
||||||
|
|
||||||
void InputManager::quickSave() {
|
void InputManager::quickSave() {
|
||||||
MWBase::Environment::get().getStateManager()->quickSave();
|
if (!MyGUI::InputManager::getInstance().isModalAny())
|
||||||
|
MWBase::Environment::get().getStateManager()->quickSave();
|
||||||
}
|
}
|
||||||
void InputManager::toggleSpell()
|
void InputManager::toggleSpell()
|
||||||
{
|
{
|
||||||
|
|
|
@ -184,7 +184,7 @@ namespace MWMechanics
|
||||||
|
|
||||||
calculateCreatureStatModifiers (ptr, duration);
|
calculateCreatureStatModifiers (ptr, duration);
|
||||||
// fatigue restoration
|
// fatigue restoration
|
||||||
calculateRestoration(ptr, duration, false);
|
calculateRestoration(ptr, duration);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Actors::engageCombat (const MWWorld::Ptr& actor1, const MWWorld::Ptr& actor2, bool againstPlayer)
|
void Actors::engageCombat (const MWWorld::Ptr& actor1, const MWWorld::Ptr& actor2, bool againstPlayer)
|
||||||
|
@ -293,7 +293,7 @@ namespace MWMechanics
|
||||||
creatureStats.setFatigue(fatigue);
|
creatureStats.setFatigue(fatigue);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Actors::calculateRestoration (const MWWorld::Ptr& ptr, float duration, bool sleep)
|
void Actors::restoreDynamicStats (const MWWorld::Ptr& ptr, bool sleep)
|
||||||
{
|
{
|
||||||
if (ptr.getClass().getCreatureStats(ptr).isDead())
|
if (ptr.getClass().getCreatureStats(ptr).isDead())
|
||||||
return;
|
return;
|
||||||
|
@ -331,10 +331,30 @@ namespace MWMechanics
|
||||||
float x = fFatigueReturnBase + fFatigueReturnMult * (1 - normalizedEncumbrance);
|
float x = fFatigueReturnBase + fFatigueReturnMult * (1 - normalizedEncumbrance);
|
||||||
x *= fEndFatigueMult * endurance;
|
x *= fEndFatigueMult * endurance;
|
||||||
|
|
||||||
|
DynamicStat<float> fatigue = stats.getFatigue();
|
||||||
|
fatigue.setCurrent (fatigue.getCurrent() + 3600 * x);
|
||||||
|
stats.setFatigue (fatigue);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Actors::calculateRestoration (const MWWorld::Ptr& ptr, float duration)
|
||||||
|
{
|
||||||
|
if (ptr.getClass().getCreatureStats(ptr).isDead())
|
||||||
|
return;
|
||||||
|
|
||||||
|
MWMechanics::CreatureStats& stats = ptr.getClass().getCreatureStats (ptr);
|
||||||
|
const MWWorld::Store<ESM::GameSetting>& settings = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
|
||||||
|
|
||||||
|
int endurance = stats.getAttribute (ESM::Attribute::Endurance).getModified ();
|
||||||
|
|
||||||
|
// restore fatigue
|
||||||
|
float fFatigueReturnBase = settings.find("fFatigueReturnBase")->getFloat ();
|
||||||
|
float fFatigueReturnMult = settings.find("fFatigueReturnMult")->getFloat ();
|
||||||
|
|
||||||
|
float x = fFatigueReturnBase + fFatigueReturnMult * endurance;
|
||||||
|
|
||||||
DynamicStat<float> fatigue = stats.getFatigue();
|
DynamicStat<float> fatigue = stats.getFatigue();
|
||||||
fatigue.setCurrent (fatigue.getCurrent() + duration * x);
|
fatigue.setCurrent (fatigue.getCurrent() + duration * x);
|
||||||
stats.setFatigue (fatigue);
|
stats.setFatigue (fatigue);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Actors::calculateCreatureStatModifiers (const MWWorld::Ptr& ptr, float duration)
|
void Actors::calculateCreatureStatModifiers (const MWWorld::Ptr& ptr, float duration)
|
||||||
|
@ -840,7 +860,7 @@ namespace MWMechanics
|
||||||
if (ptr.getClass().isClass(ptr, "Guard") && creatureStats.getAiSequence().getTypeId() != AiPackage::TypeIdPursue && !creatureStats.isHostile())
|
if (ptr.getClass().isClass(ptr, "Guard") && creatureStats.getAiSequence().getTypeId() != AiPackage::TypeIdPursue && !creatureStats.isHostile())
|
||||||
{
|
{
|
||||||
const MWWorld::ESMStore& esmStore = MWBase::Environment::get().getWorld()->getStore();
|
const MWWorld::ESMStore& esmStore = MWBase::Environment::get().getWorld()->getStore();
|
||||||
float cutoff = float(esmStore.get<ESM::GameSetting>().find("iCrimeThreshold")->getInt());
|
int cutoff = esmStore.get<ESM::GameSetting>().find("iCrimeThreshold")->getInt();
|
||||||
// Force dialogue on sight if bounty is greater than the cutoff
|
// 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)
|
// 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
|
if ( player.getClass().getNpcStats(player).getBounty() >= cutoff
|
||||||
|
@ -848,7 +868,11 @@ namespace MWMechanics
|
||||||
&& MWBase::Environment::get().getWorld()->getLOS(ptr, player)
|
&& MWBase::Environment::get().getWorld()->getLOS(ptr, player)
|
||||||
&& MWBase::Environment::get().getMechanicsManager()->awarenessCheck(player, ptr))
|
&& MWBase::Environment::get().getMechanicsManager()->awarenessCheck(player, ptr))
|
||||||
{
|
{
|
||||||
creatureStats.getAiSequence().stack(AiPursue(player), ptr);
|
static int iCrimeThresholdMultiplier = esmStore.get<ESM::GameSetting>().find("iCrimeThresholdMultiplier")->getInt();
|
||||||
|
if (player.getClass().getNpcStats(player).getBounty() >= cutoff * iCrimeThresholdMultiplier)
|
||||||
|
MWBase::Environment::get().getMechanicsManager()->startCombat(ptr, player);
|
||||||
|
else
|
||||||
|
creatureStats.getAiSequence().stack(AiPursue(player), ptr);
|
||||||
creatureStats.setAlarmed(true);
|
creatureStats.setAlarmed(true);
|
||||||
npcStats.setCrimeId(MWBase::Environment::get().getWorld()->getPlayer().getNewCrimeId());
|
npcStats.setCrimeId(MWBase::Environment::get().getWorld()->getPlayer().getNewCrimeId());
|
||||||
}
|
}
|
||||||
|
@ -1029,10 +1053,6 @@ namespace MWMechanics
|
||||||
iter->second->update(duration);
|
iter->second->update(duration);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Kill dead actors, update some variables
|
|
||||||
|
|
||||||
int hostilesCount = 0; // need to know this to play Battle music
|
|
||||||
|
|
||||||
for(PtrControllerMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter)
|
for(PtrControllerMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter)
|
||||||
{
|
{
|
||||||
const MWWorld::Class &cls = iter->first.getClass();
|
const MWWorld::Class &cls = iter->first.getClass();
|
||||||
|
@ -1048,68 +1068,23 @@ namespace MWMechanics
|
||||||
stats.setKnockedDownOneFrame(false);
|
stats.setKnockedDownOneFrame(false);
|
||||||
stats.setKnockedDownOverOneFrame(true);
|
stats.setKnockedDownOverOneFrame(true);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int hostilesCount = 0; // need to know this to play Battle music
|
||||||
|
|
||||||
|
for(PtrControllerMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter)
|
||||||
|
{
|
||||||
|
const MWWorld::Class &cls = iter->first.getClass();
|
||||||
|
CreatureStats &stats = cls.getCreatureStats(iter->first);
|
||||||
|
|
||||||
if(!stats.isDead())
|
if(!stats.isDead())
|
||||||
{
|
{
|
||||||
if (stats.isHostile()) hostilesCount++;
|
if (stats.isHostile()) hostilesCount++;
|
||||||
|
|
||||||
if(iter->second->isDead())
|
|
||||||
{
|
|
||||||
// Actor has been resurrected. Notify the CharacterController and re-enable collision.
|
|
||||||
MWBase::Environment::get().getWorld()->enableActorCollision(iter->first, true);
|
|
||||||
iter->second->resurrect();
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!stats.isDead())
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If it's the player and God Mode is turned on, keep it alive
|
|
||||||
if (iter->first.getRefData().getHandle()=="player" &&
|
|
||||||
MWBase::Environment::get().getWorld()->getGodModeState())
|
|
||||||
{
|
|
||||||
MWMechanics::DynamicStat<float> stat (stats.getHealth());
|
|
||||||
|
|
||||||
if (stat.getModified()<1)
|
|
||||||
{
|
|
||||||
stat.setModified(1, 0);
|
|
||||||
stats.setHealth(stat);
|
|
||||||
}
|
|
||||||
stats.resurrect();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (iter->second->kill())
|
|
||||||
{
|
|
||||||
++mDeathCount[cls.getId(iter->first)];
|
|
||||||
|
|
||||||
// Make sure spell effects with CasterLinked flag are removed
|
|
||||||
for (PtrControllerMap::iterator iter2(mActors.begin());iter2 != mActors.end();++iter2)
|
|
||||||
{
|
|
||||||
MWMechanics::ActiveSpells& spells = iter2->first.getClass().getCreatureStats(iter2->first).getActiveSpells();
|
|
||||||
spells.purge(stats.getActorId());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Apply soultrap
|
|
||||||
if (iter->first.getTypeName() == typeid(ESM::Creature).name())
|
|
||||||
{
|
|
||||||
SoulTrap soulTrap (iter->first);
|
|
||||||
stats.getActiveSpells().visitEffectSources(soulTrap);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reset magic effects and recalculate derived effects
|
|
||||||
// One case where we need this is to make sure bound items are removed upon death
|
|
||||||
stats.setMagicEffects(MWMechanics::MagicEffects());
|
|
||||||
stats.getActiveSpells().clear();
|
|
||||||
calculateCreatureStatModifiers(iter->first, 0);
|
|
||||||
|
|
||||||
MWBase::Environment::get().getWorld()->enableActorCollision(iter->first, false);
|
|
||||||
|
|
||||||
if (cls.isEssential(iter->first))
|
|
||||||
MWBase::Environment::get().getWindowManager()->messageBox("#{sKilledEssential}");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
killDeadActors();
|
||||||
|
|
||||||
// check if we still have any player enemies to switch music
|
// check if we still have any player enemies to switch music
|
||||||
static bool isBattleMusic = false;
|
static bool isBattleMusic = false;
|
||||||
|
|
||||||
|
@ -1184,10 +1159,78 @@ namespace MWMechanics
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Actors::killDeadActors()
|
||||||
|
{
|
||||||
|
for(PtrControllerMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter)
|
||||||
|
{
|
||||||
|
const MWWorld::Class &cls = iter->first.getClass();
|
||||||
|
CreatureStats &stats = cls.getCreatureStats(iter->first);
|
||||||
|
|
||||||
|
if(!stats.isDead())
|
||||||
|
{
|
||||||
|
if(iter->second->isDead())
|
||||||
|
{
|
||||||
|
// Actor has been resurrected. Notify the CharacterController and re-enable collision.
|
||||||
|
MWBase::Environment::get().getWorld()->enableActorCollision(iter->first, true);
|
||||||
|
iter->second->resurrect();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!stats.isDead())
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If it's the player and God Mode is turned on, keep it alive
|
||||||
|
if (iter->first.getRefData().getHandle()=="player" &&
|
||||||
|
MWBase::Environment::get().getWorld()->getGodModeState())
|
||||||
|
{
|
||||||
|
MWMechanics::DynamicStat<float> stat (stats.getHealth());
|
||||||
|
|
||||||
|
if (stat.getModified()<1)
|
||||||
|
{
|
||||||
|
stat.setModified(1, 0);
|
||||||
|
stats.setHealth(stat);
|
||||||
|
}
|
||||||
|
stats.resurrect();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (iter->second->kill())
|
||||||
|
{
|
||||||
|
++mDeathCount[Misc::StringUtils::lowerCase(iter->first.getCellRef().getRefId())];
|
||||||
|
|
||||||
|
// Make sure spell effects with CasterLinked flag are removed
|
||||||
|
for (PtrControllerMap::iterator iter2(mActors.begin());iter2 != mActors.end();++iter2)
|
||||||
|
{
|
||||||
|
MWMechanics::ActiveSpells& spells = iter2->first.getClass().getCreatureStats(iter2->first).getActiveSpells();
|
||||||
|
spells.purge(stats.getActorId());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply soultrap
|
||||||
|
if (iter->first.getTypeName() == typeid(ESM::Creature).name())
|
||||||
|
{
|
||||||
|
SoulTrap soulTrap (iter->first);
|
||||||
|
stats.getActiveSpells().visitEffectSources(soulTrap);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset magic effects and recalculate derived effects
|
||||||
|
// One case where we need this is to make sure bound items are removed upon death
|
||||||
|
stats.setMagicEffects(MWMechanics::MagicEffects());
|
||||||
|
stats.getActiveSpells().clear();
|
||||||
|
calculateCreatureStatModifiers(iter->first, 0);
|
||||||
|
|
||||||
|
MWBase::Environment::get().getWorld()->enableActorCollision(iter->first, false);
|
||||||
|
|
||||||
|
if (cls.isEssential(iter->first))
|
||||||
|
MWBase::Environment::get().getWindowManager()->messageBox("#{sKilledEssential}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Actors::restoreDynamicStats(bool sleep)
|
void Actors::restoreDynamicStats(bool sleep)
|
||||||
{
|
{
|
||||||
for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter)
|
for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter)
|
||||||
calculateRestoration(iter->first, 3600, sleep);
|
restoreDynamicStats(iter->first, sleep);
|
||||||
}
|
}
|
||||||
|
|
||||||
int Actors::getHoursToRest(const MWWorld::Ptr &ptr) const
|
int Actors::getHoursToRest(const MWWorld::Ptr &ptr) const
|
||||||
|
@ -1281,12 +1324,8 @@ namespace MWMechanics
|
||||||
{
|
{
|
||||||
const MWWorld::Class &cls = iter->getClass();
|
const MWWorld::Class &cls = iter->getClass();
|
||||||
CreatureStats &stats = cls.getCreatureStats(*iter);
|
CreatureStats &stats = cls.getCreatureStats(*iter);
|
||||||
if(!stats.isDead() && stats.getAiSequence().getTypeId() == AiPackage::TypeIdCombat)
|
if (!stats.isDead() && stats.getAiSequence().isInCombat(actor))
|
||||||
{
|
list.push_front(*iter);
|
||||||
MWMechanics::AiCombat* package = static_cast<MWMechanics::AiCombat*>(stats.getAiSequence().getActivePackage());
|
|
||||||
if(package->getTarget() == actor)
|
|
||||||
list.push_front(*iter);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,7 +36,7 @@ namespace MWMechanics
|
||||||
void calculateCreatureStatModifiers (const MWWorld::Ptr& ptr, float duration);
|
void calculateCreatureStatModifiers (const MWWorld::Ptr& ptr, float duration);
|
||||||
void calculateNpcStatModifiers (const MWWorld::Ptr& ptr);
|
void calculateNpcStatModifiers (const MWWorld::Ptr& ptr);
|
||||||
|
|
||||||
void calculateRestoration (const MWWorld::Ptr& ptr, float duration, bool sleep);
|
void calculateRestoration (const MWWorld::Ptr& ptr, float duration);
|
||||||
|
|
||||||
void updateDrowning (const MWWorld::Ptr& ptr, float duration);
|
void updateDrowning (const MWWorld::Ptr& ptr, float duration);
|
||||||
|
|
||||||
|
@ -90,12 +90,17 @@ namespace MWMechanics
|
||||||
void restoreDynamicStats(bool sleep);
|
void restoreDynamicStats(bool sleep);
|
||||||
///< If the player is sleeping, this should be called every hour.
|
///< If the player is sleeping, this should be called every hour.
|
||||||
|
|
||||||
|
void restoreDynamicStats(const MWWorld::Ptr& actor, bool sleep);
|
||||||
|
|
||||||
int getHoursToRest(const MWWorld::Ptr& ptr) const;
|
int getHoursToRest(const MWWorld::Ptr& ptr) const;
|
||||||
///< Calculate how many hours the given actor needs to rest in order to be fully healed
|
///< Calculate how many hours the given actor needs to rest in order to be fully healed
|
||||||
|
|
||||||
int countDeaths (const std::string& id) const;
|
int countDeaths (const std::string& id) const;
|
||||||
///< Return the number of deaths for actors with the given ID.
|
///< Return the number of deaths for actors with the given ID.
|
||||||
|
|
||||||
|
///@see MechanicsManager::killDeadActors
|
||||||
|
void killDeadActors ();
|
||||||
|
|
||||||
void forceStateUpdate(const MWWorld::Ptr &ptr);
|
void forceStateUpdate(const MWWorld::Ptr &ptr);
|
||||||
|
|
||||||
void playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number);
|
void playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number);
|
||||||
|
|
|
@ -265,7 +265,7 @@ namespace MWMechanics
|
||||||
|
|
||||||
const ESM::Weapon *weapon = NULL;
|
const ESM::Weapon *weapon = NULL;
|
||||||
MWMechanics::WeaponType weaptype;
|
MWMechanics::WeaponType weaptype;
|
||||||
float weapRange;
|
float weapRange = 1.0f;
|
||||||
|
|
||||||
actorClass.getCreatureStats(actor).setMovementFlag(CreatureStats::Flag_Run, true);
|
actorClass.getCreatureStats(actor).setMovementFlag(CreatureStats::Flag_Run, true);
|
||||||
|
|
||||||
|
@ -300,7 +300,7 @@ namespace MWMechanics
|
||||||
else //is creature
|
else //is creature
|
||||||
{
|
{
|
||||||
weaptype = WeapType_HandToHand; //doesn't matter, should only reflect if it is melee or distant weapon
|
weaptype = WeapType_HandToHand; //doesn't matter, should only reflect if it is melee or distant weapon
|
||||||
weapRange = 150; //TODO: use true attack range (the same problem in Creature::hit)
|
weapRange = 150.0f; //TODO: use true attack range (the same problem in Creature::hit)
|
||||||
}
|
}
|
||||||
|
|
||||||
float rangeAttack;
|
float rangeAttack;
|
||||||
|
|
|
@ -72,6 +72,30 @@ bool AiSequence::getCombatTarget(MWWorld::Ptr &targetActor) const
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool AiSequence::isInCombat() const
|
||||||
|
{
|
||||||
|
for(std::list<AiPackage*>::const_iterator it = mPackages.begin(); it != mPackages.end(); ++it)
|
||||||
|
{
|
||||||
|
if ((*it)->getTypeId() == AiPackage::TypeIdCombat)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AiSequence::isInCombat(const MWWorld::Ptr &actor) const
|
||||||
|
{
|
||||||
|
for(std::list<AiPackage*>::const_iterator it = mPackages.begin(); it != mPackages.end(); ++it)
|
||||||
|
{
|
||||||
|
if ((*it)->getTypeId() == AiPackage::TypeIdCombat)
|
||||||
|
{
|
||||||
|
const AiCombat *combat = static_cast<const AiCombat *>(*it);
|
||||||
|
if (combat->getTarget() == actor)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool AiSequence::canAddTarget(const ESM::Position& actorPos, float distToTarget) const
|
bool AiSequence::canAddTarget(const ESM::Position& actorPos, float distToTarget) const
|
||||||
{
|
{
|
||||||
bool firstCombatFound = false;
|
bool firstCombatFound = false;
|
||||||
|
|
|
@ -63,6 +63,12 @@ namespace MWMechanics
|
||||||
/// Return true and assign target if combat package is currently active, return false otherwise
|
/// Return true and assign target if combat package is currently active, return false otherwise
|
||||||
bool getCombatTarget (MWWorld::Ptr &targetActor) const;
|
bool getCombatTarget (MWWorld::Ptr &targetActor) const;
|
||||||
|
|
||||||
|
/// Is there any combat package?
|
||||||
|
bool isInCombat () const;
|
||||||
|
|
||||||
|
/// Are we in combat with this particular actor?
|
||||||
|
bool isInCombat (const MWWorld::Ptr& actor) const;
|
||||||
|
|
||||||
bool canAddTarget(const ESM::Position& actorPos, float distToTarget) const;
|
bool canAddTarget(const ESM::Position& actorPos, float distToTarget) const;
|
||||||
///< Function assumes that actor can have only 1 target apart player
|
///< Function assumes that actor can have only 1 target apart player
|
||||||
|
|
||||||
|
|
232
apps/openmw/mwmechanics/autocalcspell.cpp
Normal file
232
apps/openmw/mwmechanics/autocalcspell.cpp
Normal file
|
@ -0,0 +1,232 @@
|
||||||
|
#include "autocalcspell.hpp"
|
||||||
|
|
||||||
|
#include <climits>
|
||||||
|
|
||||||
|
#include "../mwworld/esmstore.hpp"
|
||||||
|
|
||||||
|
#include "../mwbase/world.hpp"
|
||||||
|
#include "../mwbase/environment.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
namespace MWMechanics
|
||||||
|
{
|
||||||
|
|
||||||
|
struct SchoolCaps
|
||||||
|
{
|
||||||
|
int mCount;
|
||||||
|
int mLimit;
|
||||||
|
bool mReachedLimit;
|
||||||
|
int mMinCost;
|
||||||
|
std::string mWeakestSpell;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<std::string> autoCalcNpcSpells(const int *actorSkills, const int *actorAttributes, const ESM::Race* race)
|
||||||
|
{
|
||||||
|
const MWWorld::Store<ESM::GameSetting>& gmst = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
|
||||||
|
static const float fNPCbaseMagickaMult = gmst.find("fNPCbaseMagickaMult")->getFloat();
|
||||||
|
float baseMagicka = fNPCbaseMagickaMult * actorAttributes[ESM::Attribute::Intelligence];
|
||||||
|
|
||||||
|
static const std::string schools[] = {
|
||||||
|
"alteration", "conjuration", "destruction", "illusion", "mysticism", "restoration"
|
||||||
|
};
|
||||||
|
static int iAutoSpellSchoolMax[6];
|
||||||
|
static bool init = false;
|
||||||
|
if (!init)
|
||||||
|
{
|
||||||
|
for (int i=0; i<6; ++i)
|
||||||
|
{
|
||||||
|
const std::string& gmstName = "iAutoSpell" + schools[i] + "Max";
|
||||||
|
iAutoSpellSchoolMax[i] = gmst.find(gmstName)->getInt();
|
||||||
|
}
|
||||||
|
init = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::map<int, SchoolCaps> schoolCaps;
|
||||||
|
for (int i=0; i<6; ++i)
|
||||||
|
{
|
||||||
|
SchoolCaps caps;
|
||||||
|
caps.mCount = 0;
|
||||||
|
caps.mLimit = iAutoSpellSchoolMax[i];
|
||||||
|
caps.mReachedLimit = iAutoSpellSchoolMax[i] <= 0;
|
||||||
|
caps.mMinCost = INT_MAX;
|
||||||
|
caps.mWeakestSpell.clear();
|
||||||
|
schoolCaps[i] = caps;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> selectedSpells;
|
||||||
|
|
||||||
|
const MWWorld::Store<ESM::Spell> &spells =
|
||||||
|
MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>();
|
||||||
|
|
||||||
|
// Note: the algorithm heavily depends on the traversal order of the spells. For vanilla-compatible results the
|
||||||
|
// Store must preserve the record ordering as it was in the content files.
|
||||||
|
for (MWWorld::Store<ESM::Spell>::iterator iter = spells.begin(); iter != spells.end(); ++iter)
|
||||||
|
{
|
||||||
|
const ESM::Spell* spell = &*iter;
|
||||||
|
|
||||||
|
if (spell->mData.mType != ESM::Spell::ST_Spell)
|
||||||
|
continue;
|
||||||
|
if (!(spell->mData.mFlags & ESM::Spell::F_Autocalc))
|
||||||
|
continue;
|
||||||
|
static const int iAutoSpellTimesCanCast = gmst.find("iAutoSpellTimesCanCast")->getInt();
|
||||||
|
if (baseMagicka < iAutoSpellTimesCanCast * spell->mData.mCost)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (race && std::find(race->mPowers.mList.begin(), race->mPowers.mList.end(), spell->mId) != race->mPowers.mList.end())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!attrSkillCheck(spell, actorSkills, actorAttributes))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
int school;
|
||||||
|
float skillTerm;
|
||||||
|
calcWeakestSchool(spell, actorSkills, school, skillTerm);
|
||||||
|
assert(school >= 0 && school < 6);
|
||||||
|
SchoolCaps& cap = schoolCaps[school];
|
||||||
|
|
||||||
|
if (cap.mReachedLimit && spell->mData.mCost <= cap.mMinCost)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
static const float fAutoSpellChance = gmst.find("fAutoSpellChance")->getFloat();
|
||||||
|
if (calcAutoCastChance(spell, actorSkills, actorAttributes, school) < fAutoSpellChance)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
selectedSpells.push_back(spell->mId);
|
||||||
|
|
||||||
|
if (cap.mReachedLimit)
|
||||||
|
{
|
||||||
|
std::vector<std::string>::iterator found = std::find(selectedSpells.begin(), selectedSpells.end(), cap.mWeakestSpell);
|
||||||
|
if (found != selectedSpells.end())
|
||||||
|
selectedSpells.erase(found);
|
||||||
|
|
||||||
|
cap.mMinCost = INT_MAX;
|
||||||
|
for (std::vector<std::string>::iterator weakIt = selectedSpells.begin(); weakIt != selectedSpells.end(); ++weakIt)
|
||||||
|
{
|
||||||
|
const ESM::Spell* testSpell = spells.find(*weakIt);
|
||||||
|
|
||||||
|
//int testSchool;
|
||||||
|
//float dummySkillTerm;
|
||||||
|
//calcWeakestSchool(testSpell, actorSkills, testSchool, dummySkillTerm);
|
||||||
|
|
||||||
|
// Note: if there are multiple spells with the same cost, we pick the first one we found.
|
||||||
|
// So the algorithm depends on the iteration order of the outer loop.
|
||||||
|
if (
|
||||||
|
// There is a huge bug here. It is not checked that weakestSpell is of the correct school.
|
||||||
|
// As result multiple SchoolCaps could have the same mWeakestSpell. Erasing the weakest spell would then fail if another school
|
||||||
|
// already erased it, and so the number of spells would often exceed the sum of limits.
|
||||||
|
// This bug cannot be fixed without significantly changing the results of the spell autocalc, which will not have been playtested.
|
||||||
|
//testSchool == school &&
|
||||||
|
testSpell->mData.mCost < cap.mMinCost)
|
||||||
|
{
|
||||||
|
cap.mMinCost = testSpell->mData.mCost;
|
||||||
|
cap.mWeakestSpell = testSpell->mId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cap.mCount += 1;
|
||||||
|
if (cap.mCount == cap.mLimit)
|
||||||
|
cap.mReachedLimit = true;
|
||||||
|
|
||||||
|
if (spell->mData.mCost < cap.mMinCost)
|
||||||
|
{
|
||||||
|
cap.mWeakestSpell = spell->mId;
|
||||||
|
cap.mMinCost = spell->mData.mCost;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return selectedSpells;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool attrSkillCheck (const ESM::Spell* spell, const int* actorSkills, const int* actorAttributes)
|
||||||
|
{
|
||||||
|
const std::vector<ESM::ENAMstruct>& effects = spell->mEffects.mList;
|
||||||
|
for (std::vector<ESM::ENAMstruct>::const_iterator effectIt = effects.begin(); effectIt != effects.end(); ++effectIt)
|
||||||
|
{
|
||||||
|
const ESM::MagicEffect* magicEffect = MWBase::Environment::get().getWorld()->getStore().get<ESM::MagicEffect>().find(effectIt->mEffectID);
|
||||||
|
static const int iAutoSpellAttSkillMin = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("iAutoSpellAttSkillMin")->getInt();
|
||||||
|
|
||||||
|
if ((magicEffect->mData.mFlags & ESM::MagicEffect::TargetSkill))
|
||||||
|
{
|
||||||
|
assert (effectIt->mSkill >= 0 && effectIt->mSkill < ESM::Skill::Length);
|
||||||
|
if (actorSkills[effectIt->mSkill] < iAutoSpellAttSkillMin)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((magicEffect->mData.mFlags & ESM::MagicEffect::TargetAttribute))
|
||||||
|
{
|
||||||
|
assert (effectIt->mAttribute >= 0 && effectIt->mAttribute < ESM::Attribute::Length);
|
||||||
|
if (actorAttributes[effectIt->mAttribute] < iAutoSpellAttSkillMin)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
ESM::Skill::SkillEnum mapSchoolToSkill(int school)
|
||||||
|
{
|
||||||
|
std::map<int, ESM::Skill::SkillEnum> 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;
|
||||||
|
assert(schoolSkillMap.find(school) != schoolSkillMap.end());
|
||||||
|
return schoolSkillMap[school];
|
||||||
|
}
|
||||||
|
|
||||||
|
void calcWeakestSchool (const ESM::Spell* spell, const int* actorSkills, int& effectiveSchool, float& skillTerm)
|
||||||
|
{
|
||||||
|
float minChance = FLT_MAX;
|
||||||
|
|
||||||
|
const ESM::EffectList& effects = spell->mEffects;
|
||||||
|
for (std::vector<ESM::ENAMstruct>::const_iterator it = effects.mList.begin(); it != effects.mList.end(); ++it)
|
||||||
|
{
|
||||||
|
const ESM::ENAMstruct& effect = *it;
|
||||||
|
float x = effect.mDuration;
|
||||||
|
|
||||||
|
const ESM::MagicEffect* magicEffect = MWBase::Environment::get().getWorld()->getStore().get<ESM::MagicEffect>().find(effect.mEffectID);
|
||||||
|
if (!(magicEffect->mData.mFlags & ESM::MagicEffect::UncappedDamage))
|
||||||
|
x = std::max(1.f, x);
|
||||||
|
|
||||||
|
x *= 0.1f * magicEffect->mData.mBaseCost;
|
||||||
|
x *= 0.5f * (effect.mMagnMin + effect.mMagnMax);
|
||||||
|
x += effect.mArea * 0.05f * magicEffect->mData.mBaseCost;
|
||||||
|
if (effect.mRange == ESM::RT_Target)
|
||||||
|
x *= 1.5f;
|
||||||
|
|
||||||
|
static const float fEffectCostMult = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fEffectCostMult")->getFloat();
|
||||||
|
x *= fEffectCostMult;
|
||||||
|
|
||||||
|
float s = 2.f * actorSkills[mapSchoolToSkill(magicEffect->mData.mSchool)];
|
||||||
|
if (s - x < minChance)
|
||||||
|
{
|
||||||
|
minChance = s - x;
|
||||||
|
effectiveSchool = magicEffect->mData.mSchool;
|
||||||
|
skillTerm = s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float calcAutoCastChance(const ESM::Spell *spell, const int *actorSkills, const int *actorAttributes, int effectiveSchool)
|
||||||
|
{
|
||||||
|
if (spell->mData.mType != ESM::Spell::ST_Spell)
|
||||||
|
return 100.f;
|
||||||
|
|
||||||
|
if (spell->mData.mFlags & ESM::Spell::F_Always)
|
||||||
|
return 100.f;
|
||||||
|
|
||||||
|
float skillTerm;
|
||||||
|
if (effectiveSchool != -1)
|
||||||
|
skillTerm = 2.f * actorSkills[mapSchoolToSkill(effectiveSchool)];
|
||||||
|
else
|
||||||
|
calcWeakestSchool(spell, actorSkills, effectiveSchool, skillTerm); // Note effectiveSchool is unused after this
|
||||||
|
|
||||||
|
float castChance = skillTerm - spell->mData.mCost + 0.2f * actorAttributes[ESM::Attribute::Willpower] + 0.1f * actorAttributes[ESM::Attribute::Luck];
|
||||||
|
return castChance;
|
||||||
|
}
|
||||||
|
}
|
31
apps/openmw/mwmechanics/autocalcspell.hpp
Normal file
31
apps/openmw/mwmechanics/autocalcspell.hpp
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
#ifndef OPENMW_AUTOCALCSPELL_H
|
||||||
|
#define OPENMW_AUTOCALCSPELL_H
|
||||||
|
|
||||||
|
#include <cfloat>
|
||||||
|
#include <set>
|
||||||
|
|
||||||
|
#include <components/esm/loadspel.hpp>
|
||||||
|
#include <components/esm/loadskil.hpp>
|
||||||
|
#include <components/esm/loadrace.hpp>
|
||||||
|
|
||||||
|
namespace MWMechanics
|
||||||
|
{
|
||||||
|
|
||||||
|
/// Contains algorithm for calculating an NPC's spells based on stats
|
||||||
|
/// @note We might want to move this code to a component later, so the editor can use it for preview purposes
|
||||||
|
|
||||||
|
std::vector<std::string> autoCalcNpcSpells(const int* actorSkills, const int* actorAttributes, const ESM::Race* race);
|
||||||
|
|
||||||
|
// Helpers
|
||||||
|
|
||||||
|
bool attrSkillCheck (const ESM::Spell* spell, const int* actorSkills, const int* actorAttributes);
|
||||||
|
|
||||||
|
ESM::Skill::SkillEnum mapSchoolToSkill(int school);
|
||||||
|
|
||||||
|
void calcWeakestSchool(const ESM::Spell* spell, const int* actorSkills, int& effectiveSchool, float& skillTerm);
|
||||||
|
|
||||||
|
float calcAutoCastChance(const ESM::Spell* spell, const int* actorSkills, const int* actorAttributes, int effectiveSchool);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -361,9 +361,10 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat
|
||||||
* beginning. */
|
* beginning. */
|
||||||
int mode = ((movement == mCurrentMovement) ? 2 : 1);
|
int mode = ((movement == mCurrentMovement) ? 2 : 1);
|
||||||
|
|
||||||
|
mMovementAnimationControlled = true;
|
||||||
|
|
||||||
mAnimation->disable(mCurrentMovement);
|
mAnimation->disable(mCurrentMovement);
|
||||||
mCurrentMovement = movement;
|
mCurrentMovement = movement;
|
||||||
mMovementAnimVelocity = 0.0f;
|
|
||||||
if(!mCurrentMovement.empty())
|
if(!mCurrentMovement.empty())
|
||||||
{
|
{
|
||||||
float vel, speedmult = 1.0f;
|
float vel, speedmult = 1.0f;
|
||||||
|
@ -383,16 +384,18 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat
|
||||||
|
|
||||||
if(mMovementSpeed > 0.0f && (vel=mAnimation->getVelocity(anim)) > 1.0f)
|
if(mMovementSpeed > 0.0f && (vel=mAnimation->getVelocity(anim)) > 1.0f)
|
||||||
{
|
{
|
||||||
mMovementAnimVelocity = vel;
|
|
||||||
speedmult = mMovementSpeed / vel;
|
speedmult = mMovementSpeed / vel;
|
||||||
}
|
}
|
||||||
else if (mMovementState == CharState_TurnLeft || mMovementState == CharState_TurnRight)
|
else if (mMovementState == CharState_TurnLeft || mMovementState == CharState_TurnRight)
|
||||||
speedmult = 1.f; // TODO: should get a speed mult depending on the current turning speed
|
speedmult = 1.f; // TODO: should get a speed mult depending on the current turning speed
|
||||||
else if (mMovementSpeed > 0.0f)
|
else if (mMovementSpeed > 0.0f)
|
||||||
|
{
|
||||||
// The first person anims don't have any velocity to calculate a speed multiplier from.
|
// The first person anims don't have any velocity to calculate a speed multiplier from.
|
||||||
// We use the third person velocities instead.
|
// We use the third person velocities instead.
|
||||||
// FIXME: should be pulled from the actual animation, but it is not presently loaded.
|
// FIXME: should be pulled from the actual animation, but it is not presently loaded.
|
||||||
speedmult = mMovementSpeed / (isrunning ? 222.857f : 154.064f);
|
speedmult = mMovementSpeed / (isrunning ? 222.857f : 154.064f);
|
||||||
|
mMovementAnimationControlled = false;
|
||||||
|
}
|
||||||
mAnimation->play(mCurrentMovement, Priority_Movement, movegroup, false,
|
mAnimation->play(mCurrentMovement, Priority_Movement, movegroup, false,
|
||||||
speedmult, ((mode!=2)?"start":"loop start"), "stop", 0.0f, ~0ul);
|
speedmult, ((mode!=2)?"start":"loop start"), "stop", 0.0f, ~0ul);
|
||||||
}
|
}
|
||||||
|
@ -506,6 +509,7 @@ void CharacterController::playDeath(float startpoint, CharacterState death)
|
||||||
mJumpState = JumpState_None;
|
mJumpState = JumpState_None;
|
||||||
mAnimation->disable(mCurrentJump);
|
mAnimation->disable(mCurrentJump);
|
||||||
mCurrentJump = "";
|
mCurrentJump = "";
|
||||||
|
mMovementAnimationControlled = true;
|
||||||
|
|
||||||
mAnimation->play(mCurrentDeath, Priority_Death, MWRender::Animation::Group_All,
|
mAnimation->play(mCurrentDeath, Priority_Death, MWRender::Animation::Group_All,
|
||||||
false, 1.0f, "start", "stop", startpoint, 0);
|
false, 1.0f, "start", "stop", startpoint, 0);
|
||||||
|
@ -547,7 +551,7 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim
|
||||||
, mIdleState(CharState_None)
|
, mIdleState(CharState_None)
|
||||||
, mMovementState(CharState_None)
|
, mMovementState(CharState_None)
|
||||||
, mMovementSpeed(0.0f)
|
, mMovementSpeed(0.0f)
|
||||||
, mMovementAnimVelocity(0.0f)
|
, mMovementAnimationControlled(true)
|
||||||
, mDeathState(CharState_None)
|
, mDeathState(CharState_None)
|
||||||
, mHitState(CharState_None)
|
, mHitState(CharState_None)
|
||||||
, mUpperBodyState(UpperCharState_Nothing)
|
, mUpperBodyState(UpperCharState_Nothing)
|
||||||
|
@ -570,10 +574,14 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim
|
||||||
if (cls.hasInventoryStore(mPtr))
|
if (cls.hasInventoryStore(mPtr))
|
||||||
{
|
{
|
||||||
getActiveWeapon(cls.getCreatureStats(mPtr), cls.getInventoryStore(mPtr), &mWeaponType);
|
getActiveWeapon(cls.getCreatureStats(mPtr), cls.getInventoryStore(mPtr), &mWeaponType);
|
||||||
|
if (mWeaponType != WeapType_None)
|
||||||
|
{
|
||||||
|
mUpperBodyState = UpperCharState_WeapEquiped;
|
||||||
|
getWeaponGroup(mWeaponType, mCurrentWeapon);
|
||||||
|
}
|
||||||
|
|
||||||
if(mWeaponType != WeapType_None && mWeaponType != WeapType_Spell && mWeaponType != WeapType_HandToHand)
|
if(mWeaponType != WeapType_None && mWeaponType != WeapType_Spell && mWeaponType != WeapType_HandToHand)
|
||||||
{
|
{
|
||||||
getWeaponGroup(mWeaponType, mCurrentWeapon);
|
|
||||||
mUpperBodyState = UpperCharState_WeapEquiped;
|
|
||||||
mAnimation->showWeapons(true);
|
mAnimation->showWeapons(true);
|
||||||
mAnimation->setWeaponGroup(mCurrentWeapon);
|
mAnimation->setWeaponGroup(mCurrentWeapon);
|
||||||
}
|
}
|
||||||
|
@ -599,6 +607,8 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim
|
||||||
|
|
||||||
if(mDeathState == CharState_None)
|
if(mDeathState == CharState_None)
|
||||||
refreshCurrentAnims(mIdleState, mMovementState, true);
|
refreshCurrentAnims(mIdleState, mMovementState, true);
|
||||||
|
|
||||||
|
mAnimation->runAnimation(0.f);
|
||||||
}
|
}
|
||||||
|
|
||||||
CharacterController::~CharacterController()
|
CharacterController::~CharacterController()
|
||||||
|
@ -1241,6 +1251,7 @@ void CharacterController::update(float duration)
|
||||||
if (inwater || flying)
|
if (inwater || flying)
|
||||||
cls.getCreatureStats(mPtr).land();
|
cls.getCreatureStats(mPtr).land();
|
||||||
|
|
||||||
|
bool inJump = true;
|
||||||
if(!onground && !flying && !inwater)
|
if(!onground && !flying && !inwater)
|
||||||
{
|
{
|
||||||
// In the air (either getting up —ascending part of jump— or falling).
|
// In the air (either getting up —ascending part of jump— or falling).
|
||||||
|
@ -1330,6 +1341,8 @@ void CharacterController::update(float duration)
|
||||||
mJumpState = JumpState_None;
|
mJumpState = JumpState_None;
|
||||||
vec.z = 0.0f;
|
vec.z = 0.0f;
|
||||||
|
|
||||||
|
inJump = false;
|
||||||
|
|
||||||
if(std::abs(vec.x/2.0f) > std::abs(vec.y))
|
if(std::abs(vec.x/2.0f) > std::abs(vec.y))
|
||||||
{
|
{
|
||||||
if(vec.x > 0.0f)
|
if(vec.x > 0.0f)
|
||||||
|
@ -1391,6 +1404,8 @@ void CharacterController::update(float duration)
|
||||||
forcestateupdate = updateCreatureState() || forcestateupdate;
|
forcestateupdate = updateCreatureState() || forcestateupdate;
|
||||||
|
|
||||||
refreshCurrentAnims(idlestate, movestate, forcestateupdate);
|
refreshCurrentAnims(idlestate, movestate, forcestateupdate);
|
||||||
|
if (inJump)
|
||||||
|
mMovementAnimationControlled = false;
|
||||||
|
|
||||||
if (!mSkipAnim)
|
if (!mSkipAnim)
|
||||||
{
|
{
|
||||||
|
@ -1402,7 +1417,7 @@ void CharacterController::update(float duration)
|
||||||
else //avoid z-rotating for knockdown
|
else //avoid z-rotating for knockdown
|
||||||
world->rotateObject(mPtr, rot.x, rot.y, 0.0f, true);
|
world->rotateObject(mPtr, rot.x, rot.y, 0.0f, true);
|
||||||
|
|
||||||
if (mMovementAnimVelocity == 0)
|
if (!mMovementAnimationControlled)
|
||||||
world->queueMovement(mPtr, vec);
|
world->queueMovement(mPtr, vec);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -1446,7 +1461,7 @@ void CharacterController::update(float duration)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update movement
|
// Update movement
|
||||||
if(mMovementAnimVelocity > 0)
|
if(mMovementAnimationControlled && mPtr.getClass().isActor())
|
||||||
world->queueMovement(mPtr, moved);
|
world->queueMovement(mPtr, moved);
|
||||||
}
|
}
|
||||||
else if (mAnimation)
|
else if (mAnimation)
|
||||||
|
|
|
@ -147,7 +147,7 @@ class CharacterController
|
||||||
CharacterState mMovementState;
|
CharacterState mMovementState;
|
||||||
std::string mCurrentMovement;
|
std::string mCurrentMovement;
|
||||||
float mMovementSpeed;
|
float mMovementSpeed;
|
||||||
float mMovementAnimVelocity;
|
bool mMovementAnimationControlled;
|
||||||
|
|
||||||
CharacterState mDeathState;
|
CharacterState mDeathState;
|
||||||
std::string mCurrentDeath;
|
std::string mCurrentDeath;
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include "../mwmechanics/npcstats.hpp"
|
#include "../mwmechanics/npcstats.hpp"
|
||||||
#include "../mwmechanics/movement.hpp"
|
#include "../mwmechanics/movement.hpp"
|
||||||
#include "../mwmechanics/spellcasting.hpp"
|
#include "../mwmechanics/spellcasting.hpp"
|
||||||
|
#include "../mwmechanics/difficultyscaling.hpp"
|
||||||
|
|
||||||
#include "../mwworld/class.hpp"
|
#include "../mwworld/class.hpp"
|
||||||
#include "../mwworld/inventorystore.hpp"
|
#include "../mwworld/inventorystore.hpp"
|
||||||
|
@ -54,11 +55,24 @@ namespace MWMechanics
|
||||||
if (!blocker.getClass().hasInventoryStore(blocker))
|
if (!blocker.getClass().hasInventoryStore(blocker))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (blocker.getClass().getCreatureStats(blocker).getKnockedDown()
|
MWMechanics::CreatureStats& blockerStats = blocker.getClass().getCreatureStats(blocker);
|
||||||
|| blocker.getClass().getCreatureStats(blocker).getHitRecovery())
|
|
||||||
|
if (blockerStats.getKnockedDown() // Used for both knockout or knockdown
|
||||||
|
|| blockerStats.getHitRecovery()
|
||||||
|
|| blockerStats.getMagicEffects().get(ESM::MagicEffect::Paralyze).mMagnitude > 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Don't block when in spellcasting state (shield is equipped, but not visible)
|
||||||
|
if (blockerStats.getDrawState() == DrawState_Spell)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
MWWorld::InventoryStore& inv = blocker.getClass().getInventoryStore(blocker);
|
MWWorld::InventoryStore& inv = blocker.getClass().getInventoryStore(blocker);
|
||||||
|
|
||||||
|
// Don't block when in hand-to-hand combat (shield is equipped, but not visible)
|
||||||
|
if (blockerStats.getDrawState() == DrawState_Weapon &&
|
||||||
|
inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight) == inv.end())
|
||||||
|
return false;
|
||||||
|
|
||||||
MWWorld::ContainerStoreIterator shield = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedLeft);
|
MWWorld::ContainerStoreIterator shield = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedLeft);
|
||||||
if (shield == inv.end() || shield->getTypeName() != typeid(ESM::Armor).name())
|
if (shield == inv.end() || shield->getTypeName() != typeid(ESM::Armor).name())
|
||||||
return false;
|
return false;
|
||||||
|
@ -72,17 +86,6 @@ namespace MWMechanics
|
||||||
if (angle.valueDegrees() > gmst.find("fCombatBlockRightAngle")->getFloat())
|
if (angle.valueDegrees() > gmst.find("fCombatBlockRightAngle")->getFloat())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
MWMechanics::CreatureStats& blockerStats = blocker.getClass().getCreatureStats(blocker);
|
|
||||||
|
|
||||||
// Don't block when in spellcasting state (shield is equipped, but not visible)
|
|
||||||
if (blockerStats.getDrawState() == DrawState_Spell)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Don't block when in hand-to-hand combat (shield is equipped, but not visible)
|
|
||||||
if (blockerStats.getDrawState() == DrawState_Weapon &&
|
|
||||||
inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight) == inv.end())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
MWMechanics::CreatureStats& attackerStats = attacker.getClass().getCreatureStats(attacker);
|
MWMechanics::CreatureStats& attackerStats = attacker.getClass().getCreatureStats(attacker);
|
||||||
|
|
||||||
float blockTerm = blocker.getClass().getSkill(blocker, ESM::Skill::Block) + 0.2 * blockerStats.getAttribute(ESM::Attribute::Agility).getModified()
|
float blockTerm = blocker.getClass().getSkill(blocker, ESM::Skill::Block) + 0.2 * blockerStats.getAttribute(ESM::Attribute::Agility).getModified()
|
||||||
|
@ -144,11 +147,7 @@ namespace MWMechanics
|
||||||
float resistance = std::min(100.f, stats.getMagicEffects().get(ESM::MagicEffect::ResistNormalWeapons).mMagnitude
|
float resistance = std::min(100.f, stats.getMagicEffects().get(ESM::MagicEffect::ResistNormalWeapons).mMagnitude
|
||||||
- stats.getMagicEffects().get(ESM::MagicEffect::WeaknessToNormalWeapons).mMagnitude);
|
- stats.getMagicEffects().get(ESM::MagicEffect::WeaknessToNormalWeapons).mMagnitude);
|
||||||
|
|
||||||
float multiplier = 0;
|
float multiplier = 1.f - resistance / 100.f;
|
||||||
if (resistance >= 0)
|
|
||||||
multiplier = 1 - resistance / 100.f;
|
|
||||||
else
|
|
||||||
multiplier = -(resistance-100) / 100.f;
|
|
||||||
|
|
||||||
if (!(weapon.get<ESM::Weapon>()->mBase->mData.mFlags & ESM::Weapon::Silver
|
if (!(weapon.get<ESM::Weapon>()->mBase->mData.mFlags & ESM::Weapon::Silver
|
||||||
|| weapon.get<ESM::Weapon>()->mBase->mData.mFlags & ESM::Weapon::Magical))
|
|| weapon.get<ESM::Weapon>()->mBase->mData.mFlags & ESM::Weapon::Magical))
|
||||||
|
@ -210,16 +209,10 @@ namespace MWMechanics
|
||||||
damage *= fDamageStrengthBase +
|
damage *= fDamageStrengthBase +
|
||||||
(attackerStats.getAttribute(ESM::Attribute::Strength).getModified() * fDamageStrengthMult * 0.1);
|
(attackerStats.getAttribute(ESM::Attribute::Strength).getModified() * fDamageStrengthMult * 0.1);
|
||||||
|
|
||||||
|
|
||||||
if(attacker.getRefData().getHandle() == "player")
|
if(attacker.getRefData().getHandle() == "player")
|
||||||
attacker.getClass().skillUsageSucceeded(attacker, weapskill, 0);
|
attacker.getClass().skillUsageSucceeded(attacker, weapskill, 0);
|
||||||
|
|
||||||
bool detected = MWBase::Environment::get().getMechanicsManager()->awarenessCheck(attacker, victim);
|
|
||||||
if(!detected)
|
|
||||||
{
|
|
||||||
damage *= gmst.find("fCombatCriticalStrikeMult")->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())
|
if (victim.getClass().getCreatureStats(victim).getKnockedDown())
|
||||||
damage *= gmst.find("fCombatKODamageMult")->getFloat();
|
damage *= gmst.find("fCombatKODamageMult")->getFloat();
|
||||||
|
|
||||||
|
@ -256,4 +249,50 @@ namespace MWMechanics
|
||||||
return hitchance;
|
return hitchance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void applyElementalShields(const MWWorld::Ptr &attacker, const MWWorld::Ptr &victim)
|
||||||
|
{
|
||||||
|
for (int i=0; i<3; ++i)
|
||||||
|
{
|
||||||
|
float magnitude = victim.getClass().getCreatureStats(victim).getMagicEffects().get(ESM::MagicEffect::FireShield+i).mMagnitude;
|
||||||
|
|
||||||
|
if (!magnitude)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
CreatureStats& attackerStats = attacker.getClass().getCreatureStats(attacker);
|
||||||
|
float saveTerm = attacker.getClass().getSkill(attacker, ESM::Skill::Destruction)
|
||||||
|
+ 0.2f * attackerStats.getAttribute(ESM::Attribute::Willpower).getModified()
|
||||||
|
+ 0.1f * attackerStats.getAttribute(ESM::Attribute::Luck).getModified();
|
||||||
|
|
||||||
|
int fatigueMax = attackerStats.getFatigue().getModified();
|
||||||
|
int fatigueCurrent = attackerStats.getFatigue().getCurrent();
|
||||||
|
|
||||||
|
float normalisedFatigue = fatigueMax==0 ? 1 : std::max (0.0f, static_cast<float> (fatigueCurrent)/fatigueMax);
|
||||||
|
|
||||||
|
saveTerm *= 1.25f * normalisedFatigue;
|
||||||
|
|
||||||
|
float roll = std::rand()/ (static_cast<double> (RAND_MAX) + 1) * 100; // [0, 99]
|
||||||
|
float x = std::max(0.f, saveTerm - roll);
|
||||||
|
|
||||||
|
int element = ESM::MagicEffect::FireDamage;
|
||||||
|
if (i == 1)
|
||||||
|
element = ESM::MagicEffect::ShockDamage;
|
||||||
|
if (i == 2)
|
||||||
|
element = ESM::MagicEffect::FrostDamage;
|
||||||
|
|
||||||
|
float elementResistance = MWMechanics::getEffectResistanceAttribute(element, &attackerStats.getMagicEffects());
|
||||||
|
|
||||||
|
x = std::min(100.f, x + elementResistance);
|
||||||
|
|
||||||
|
static const float fElementalShieldMult = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fElementalShieldMult")->getFloat();
|
||||||
|
x = fElementalShieldMult * magnitude * (1.f - 0.01f * x);
|
||||||
|
|
||||||
|
// Note swapped victim and attacker, since the attacker takes the damage here.
|
||||||
|
x = scaleDamage(x, victim, attacker);
|
||||||
|
|
||||||
|
MWMechanics::DynamicStat<float> health = attackerStats.getHealth();
|
||||||
|
health.setCurrent(health.getCurrent() - x);
|
||||||
|
attackerStats.setHealth(health);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,9 @@ void projectileHit (const MWWorld::Ptr& attacker, const MWWorld::Ptr& victim, MW
|
||||||
/// Get the chance (in percent) for \a attacker to successfully hit \a victim with a given weapon skill value
|
/// Get the chance (in percent) for \a attacker to successfully hit \a victim with a given weapon skill value
|
||||||
float getHitChance (const MWWorld::Ptr& attacker, const MWWorld::Ptr& victim, int skillValue);
|
float getHitChance (const MWWorld::Ptr& attacker, const MWWorld::Ptr& victim, int skillValue);
|
||||||
|
|
||||||
|
/// Applies damage to attacker based on the victim's elemental shields.
|
||||||
|
void applyElementalShields(const MWWorld::Ptr& attacker, const MWWorld::Ptr& victim);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
|
|
||||||
#include "../mwbase/environment.hpp"
|
#include "../mwbase/environment.hpp"
|
||||||
#include "../mwbase/world.hpp"
|
#include "../mwbase/world.hpp"
|
||||||
|
#include "../mwbase/mechanicsmanager.hpp"
|
||||||
|
|
||||||
namespace MWMechanics
|
namespace MWMechanics
|
||||||
{
|
{
|
||||||
|
@ -191,6 +192,12 @@ namespace MWMechanics
|
||||||
mDied = true;
|
mDied = true;
|
||||||
|
|
||||||
mDead = true;
|
mDead = true;
|
||||||
|
|
||||||
|
if (mDied)
|
||||||
|
// Must increase death count immediately. There are scripts that use getDeadCount as reaction to onDeath
|
||||||
|
// and rely on the increased value.
|
||||||
|
// Would be more appropriate to use a killActor(actor) function, but we don't have access to the Ptr in CreatureStats.
|
||||||
|
MWBase::Environment::get().getMechanicsManager()->killDeadActors();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -208,7 +208,8 @@ namespace MWMechanics
|
||||||
float getEvasion() const;
|
float getEvasion() const;
|
||||||
|
|
||||||
void setKnockedDown(bool value);
|
void setKnockedDown(bool value);
|
||||||
///Returns true for the entire duration of the actor being knocked down
|
/// Returns true for the entire duration of the actor being knocked down or knocked out,
|
||||||
|
/// including transition animations (falling down & standing up)
|
||||||
bool getKnockedDown() const;
|
bool getKnockedDown() const;
|
||||||
void setKnockedDownOneFrame(bool value);
|
void setKnockedDownOneFrame(bool value);
|
||||||
///Returns true only for the first frame of the actor being knocked out; used for "onKnockedOut" command
|
///Returns true only for the first frame of the actor being knocked out; used for "onKnockedOut" command
|
||||||
|
|
38
apps/openmw/mwmechanics/difficultyscaling.cpp
Normal file
38
apps/openmw/mwmechanics/difficultyscaling.cpp
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
#include "difficultyscaling.hpp"
|
||||||
|
|
||||||
|
#include "../mwbase/world.hpp"
|
||||||
|
#include "../mwbase/environment.hpp"
|
||||||
|
#include "../mwworld/esmstore.hpp"
|
||||||
|
|
||||||
|
#include <components/settings/settings.hpp>
|
||||||
|
|
||||||
|
float scaleDamage(float damage, const MWWorld::Ptr& attacker, const MWWorld::Ptr& victim)
|
||||||
|
{
|
||||||
|
const MWWorld::Ptr& player = MWBase::Environment::get().getWorld()->getPlayerPtr();
|
||||||
|
|
||||||
|
// [-100, 100]
|
||||||
|
int difficultySetting = Settings::Manager::getInt("difficulty", "Game");
|
||||||
|
|
||||||
|
static const float fDifficultyMult = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fDifficultyMult")->getFloat();
|
||||||
|
|
||||||
|
float difficultyTerm = 0.01f * difficultySetting;
|
||||||
|
|
||||||
|
float x = 0;
|
||||||
|
if (victim == player)
|
||||||
|
{
|
||||||
|
if (difficultyTerm > 0)
|
||||||
|
x = fDifficultyMult * difficultyTerm;
|
||||||
|
else
|
||||||
|
x = difficultyTerm / fDifficultyMult;
|
||||||
|
}
|
||||||
|
else if (attacker == player)
|
||||||
|
{
|
||||||
|
if (difficultyTerm > 0)
|
||||||
|
x = -difficultyTerm / fDifficultyMult;
|
||||||
|
else
|
||||||
|
x = fDifficultyMult * (-difficultyTerm);
|
||||||
|
}
|
||||||
|
|
||||||
|
damage *= 1 + x;
|
||||||
|
return damage;
|
||||||
|
}
|
12
apps/openmw/mwmechanics/difficultyscaling.hpp
Normal file
12
apps/openmw/mwmechanics/difficultyscaling.hpp
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
#ifndef OPENMW_MWMECHANICS_DIFFICULTYSCALING_H
|
||||||
|
#define OPENMW_MWMECHANICS_DIFFICULTYSCALING_H
|
||||||
|
|
||||||
|
namespace MWWorld
|
||||||
|
{
|
||||||
|
class Ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Scales damage dealt to an actor based on difficulty setting
|
||||||
|
float scaleDamage(float damage, const MWWorld::Ptr& attacker, const MWWorld::Ptr& victim);
|
||||||
|
|
||||||
|
#endif
|
|
@ -14,9 +14,11 @@ namespace MWMechanics
|
||||||
{
|
{
|
||||||
|
|
||||||
/// Call when \a actor has got in contact with \a carrier (e.g. hit by him, or loots him)
|
/// Call when \a actor has got in contact with \a carrier (e.g. hit by him, or loots him)
|
||||||
|
/// @param actor The actor that will potentially catch diseases. Currently only the player can catch diseases.
|
||||||
|
/// @param carrier The disease carrier.
|
||||||
inline void diseaseContact (MWWorld::Ptr actor, MWWorld::Ptr carrier)
|
inline void diseaseContact (MWWorld::Ptr actor, MWWorld::Ptr carrier)
|
||||||
{
|
{
|
||||||
if (!carrier.getClass().isActor())
|
if (!carrier.getClass().isActor() || actor != MWBase::Environment::get().getWorld()->getPlayerPtr())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
float fDiseaseXferChance =
|
float fDiseaseXferChance =
|
||||||
|
@ -27,25 +29,47 @@ namespace MWMechanics
|
||||||
for (Spells::TIterator it = spells.begin(); it != spells.end(); ++it)
|
for (Spells::TIterator it = spells.begin(); it != spells.end(); ++it)
|
||||||
{
|
{
|
||||||
const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>().find(it->first);
|
const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>().find(it->first);
|
||||||
if (spell->mData.mType == ESM::Spell::ST_Disease
|
|
||||||
|| spell->mData.mType == ESM::Spell::ST_Blight)
|
|
||||||
{
|
|
||||||
float roll = std::rand()/ (static_cast<double> (RAND_MAX) + 1) * 100; // [0, 99]
|
|
||||||
if (roll < fDiseaseXferChance)
|
|
||||||
{
|
|
||||||
// Contracted disease!
|
|
||||||
actor.getClass().getCreatureStats(actor).getSpells().add(it->first);
|
|
||||||
|
|
||||||
if (actor.getRefData().getHandle() == "player")
|
if (actor.getClass().getCreatureStats(actor).getSpells().hasSpell(spell->mId))
|
||||||
{
|
continue;
|
||||||
std::string msg = "sMagicContractDisease";
|
|
||||||
msg = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find(msg)->getString();
|
bool hasCorprusEffect = false;
|
||||||
if (msg.find("%s") != std::string::npos)
|
for (std::vector<ESM::ENAMstruct>::const_iterator effectIt = spell->mEffects.mList.begin(); effectIt != spell->mEffects.mList.end(); ++effectIt)
|
||||||
msg.replace(msg.find("%s"), 2, spell->mName);
|
{
|
||||||
MWBase::Environment::get().getWindowManager()->messageBox(msg);
|
if (effectIt->mEffectID == ESM::MagicEffect::Corprus)
|
||||||
}
|
{
|
||||||
|
hasCorprusEffect = true;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float resist = 0.f;
|
||||||
|
if (hasCorprusEffect)
|
||||||
|
resist = 1.f - 0.01 * (actor.getClass().getCreatureStats(actor).getMagicEffects().get(ESM::MagicEffect::ResistCorprusDisease).mMagnitude
|
||||||
|
- actor.getClass().getCreatureStats(actor).getMagicEffects().get(ESM::MagicEffect::WeaknessToCorprusDisease).mMagnitude);
|
||||||
|
else if (spell->mData.mType == ESM::Spell::ST_Disease)
|
||||||
|
resist = 1.f - 0.01 * (actor.getClass().getCreatureStats(actor).getMagicEffects().get(ESM::MagicEffect::ResistCommonDisease).mMagnitude
|
||||||
|
- actor.getClass().getCreatureStats(actor).getMagicEffects().get(ESM::MagicEffect::WeaknessToCommonDisease).mMagnitude);
|
||||||
|
else if (spell->mData.mType == ESM::Spell::ST_Blight)
|
||||||
|
resist = 1.f - 0.01 * (actor.getClass().getCreatureStats(actor).getMagicEffects().get(ESM::MagicEffect::ResistBlightDisease).mMagnitude
|
||||||
|
- actor.getClass().getCreatureStats(actor).getMagicEffects().get(ESM::MagicEffect::WeaknessToBlightDisease).mMagnitude);
|
||||||
|
else
|
||||||
|
continue;
|
||||||
|
|
||||||
|
int x = fDiseaseXferChance * 100 * resist;
|
||||||
|
float roll = std::rand()/ (static_cast<double> (RAND_MAX) + 1) * 10000; // [0, 9999]
|
||||||
|
|
||||||
|
if (roll < x)
|
||||||
|
{
|
||||||
|
// Contracted disease!
|
||||||
|
actor.getClass().getCreatureStats(actor).getSpells().add(it->first);
|
||||||
|
|
||||||
|
std::string msg = "sMagicContractDisease";
|
||||||
|
msg = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find(msg)->getString();
|
||||||
|
if (msg.find("%s") != std::string::npos)
|
||||||
|
msg.replace(msg.find("%s"), 2, spell->mName);
|
||||||
|
MWBase::Environment::get().getWindowManager()->messageBox(msg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#include <OgreSceneNode.h>
|
#include <OgreSceneNode.h>
|
||||||
|
|
||||||
#include "spellcasting.hpp"
|
#include "spellcasting.hpp"
|
||||||
|
#include "autocalcspell.hpp"
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
@ -33,10 +34,19 @@ namespace
|
||||||
if (!faction.empty() && ptr.getClass().isNpc())
|
if (!faction.empty() && ptr.getClass().isNpc())
|
||||||
{
|
{
|
||||||
const std::map<std::string, int>& factions = ptr.getClass().getNpcStats(ptr).getFactionRanks();
|
const std::map<std::string, int>& factions = ptr.getClass().getNpcStats(ptr).getFactionRanks();
|
||||||
if (factions.find(Misc::StringUtils::lowerCase(faction)) == factions.end())
|
std::map<std::string, int>::const_iterator found = factions.find(Misc::StringUtils::lowerCase(faction));
|
||||||
|
if (found == factions.end()
|
||||||
|
|| found->second < item.getCellRef().getFactionRank())
|
||||||
isFactionOwned = true;
|
isFactionOwned = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const std::string& globalVariable = item.getCellRef().getGlobalVariable();
|
||||||
|
if (!globalVariable.empty() && MWBase::Environment::get().getWorld()->getGlobalInt(Misc::StringUtils::lowerCase(globalVariable)) == 1)
|
||||||
|
{
|
||||||
|
isOwned = false;
|
||||||
|
isFactionOwned = false;
|
||||||
|
}
|
||||||
|
|
||||||
if (!item.getCellRef().getOwner().empty())
|
if (!item.getCellRef().getOwner().empty())
|
||||||
victim = MWBase::Environment::get().getWorld()->searchPtr(item.getCellRef().getOwner(), true);
|
victim = MWBase::Environment::get().getWorld()->searchPtr(item.getCellRef().getOwner(), true);
|
||||||
|
|
||||||
|
@ -155,19 +165,6 @@ namespace MWMechanics
|
||||||
npcStats.getSkill (index).setBase (
|
npcStats.getSkill (index).setBase (
|
||||||
npcStats.getSkill (index).getBase() + bonus);
|
npcStats.getSkill (index).getBase() + bonus);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i==1)
|
|
||||||
{
|
|
||||||
// Major skill - add starting spells for this skill if existing
|
|
||||||
const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore();
|
|
||||||
MWWorld::Store<ESM::Spell>::iterator it = store.get<ESM::Spell>().begin();
|
|
||||||
for (; it != store.get<ESM::Spell>().end(); ++it)
|
|
||||||
{
|
|
||||||
if (it->mData.mFlags & ESM::Spell::F_PCStart
|
|
||||||
&& spellSchoolToSkill(getSpellSchool(&*it, ptr)) == index)
|
|
||||||
creatureStats.getSpells().add(it->mId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -190,6 +187,87 @@ namespace MWMechanics
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// F_PCStart spells
|
||||||
|
static const float fPCbaseMagickaMult = esmStore.get<ESM::GameSetting>().find("fPCbaseMagickaMult")->getFloat();
|
||||||
|
|
||||||
|
float baseMagicka = fPCbaseMagickaMult * creatureStats.getAttribute(ESM::Attribute::Intelligence).getBase();
|
||||||
|
bool reachedLimit = false;
|
||||||
|
const ESM::Spell* weakestSpell = NULL;
|
||||||
|
int minCost = INT_MAX;
|
||||||
|
|
||||||
|
std::vector<std::string> selectedSpells;
|
||||||
|
|
||||||
|
const ESM::Race* race = NULL;
|
||||||
|
if (mRaceSelected)
|
||||||
|
race = esmStore.get<ESM::Race>().find(player->mRace);
|
||||||
|
|
||||||
|
int skills[ESM::Skill::Length];
|
||||||
|
for (int i=0; i<ESM::Skill::Length; ++i)
|
||||||
|
skills[i] = npcStats.getSkill(i).getBase();
|
||||||
|
|
||||||
|
int attributes[ESM::Attribute::Length];
|
||||||
|
for (int i=0; i<ESM::Attribute::Length; ++i)
|
||||||
|
attributes[i] = npcStats.getAttribute(i).getBase();
|
||||||
|
|
||||||
|
const MWWorld::Store<ESM::Spell> &spells =
|
||||||
|
esmStore.get<ESM::Spell>();
|
||||||
|
for (MWWorld::Store<ESM::Spell>::iterator iter = spells.begin(); iter != spells.end(); ++iter)
|
||||||
|
{
|
||||||
|
const ESM::Spell* spell = &*iter;
|
||||||
|
|
||||||
|
if (spell->mData.mType != ESM::Spell::ST_Spell)
|
||||||
|
continue;
|
||||||
|
if (!(spell->mData.mFlags & ESM::Spell::F_PCStart))
|
||||||
|
continue;
|
||||||
|
if (reachedLimit && spell->mData.mCost <= minCost)
|
||||||
|
continue;
|
||||||
|
if (race && std::find(race->mPowers.mList.begin(), race->mPowers.mList.end(), spell->mId) != race->mPowers.mList.end())
|
||||||
|
continue;
|
||||||
|
if (baseMagicka < spell->mData.mCost)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
static const float fAutoPCSpellChance = esmStore.get<ESM::GameSetting>().find("fAutoPCSpellChance")->getFloat();
|
||||||
|
if (calcAutoCastChance(spell, skills, attributes, -1) < fAutoPCSpellChance)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!attrSkillCheck(spell, skills, attributes))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
selectedSpells.push_back(spell->mId);
|
||||||
|
|
||||||
|
if (reachedLimit)
|
||||||
|
{
|
||||||
|
std::vector<std::string>::iterator it = std::find(selectedSpells.begin(), selectedSpells.end(), weakestSpell->mId);
|
||||||
|
if (it != selectedSpells.end())
|
||||||
|
selectedSpells.erase(it);
|
||||||
|
|
||||||
|
minCost = INT_MAX;
|
||||||
|
for (std::vector<std::string>::iterator weakIt = selectedSpells.begin(); weakIt != selectedSpells.end(); ++weakIt)
|
||||||
|
{
|
||||||
|
const ESM::Spell* testSpell = esmStore.get<ESM::Spell>().find(*weakIt);
|
||||||
|
if (testSpell->mData.mCost < minCost)
|
||||||
|
{
|
||||||
|
minCost = testSpell->mData.mCost;
|
||||||
|
weakestSpell = testSpell;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (spell->mData.mCost < minCost)
|
||||||
|
{
|
||||||
|
weakestSpell = spell;
|
||||||
|
minCost = weakestSpell->mData.mCost;
|
||||||
|
}
|
||||||
|
static const unsigned int iAutoPCSpellMax = esmStore.get<ESM::GameSetting>().find("iAutoPCSpellMax")->getInt();
|
||||||
|
if (selectedSpells.size() == iAutoPCSpellMax)
|
||||||
|
reachedLimit = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (std::vector<std::string>::iterator it = selectedSpells.begin(); it != selectedSpells.end(); ++it)
|
||||||
|
creatureStats.getSpells().add(*it);
|
||||||
|
|
||||||
// forced update and current value adjustments
|
// forced update and current value adjustments
|
||||||
mActors.updateActor (ptr, 0);
|
mActors.updateActor (ptr, 0);
|
||||||
|
|
||||||
|
@ -584,6 +662,10 @@ namespace MWMechanics
|
||||||
return mActors.countDeaths (id);
|
return mActors.countDeaths (id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MechanicsManager::killDeadActors()
|
||||||
|
{
|
||||||
|
mActors.killDeadActors();
|
||||||
|
}
|
||||||
|
|
||||||
void MechanicsManager::getPersuasionDispositionChange (const MWWorld::Ptr& npc, PersuasionType type,
|
void MechanicsManager::getPersuasionDispositionChange (const MWWorld::Ptr& npc, PersuasionType type,
|
||||||
float currentTemporaryDispositionDelta, bool& success, float& tempChange, float& permChange)
|
float currentTemporaryDispositionDelta, bool& success, float& tempChange, float& permChange)
|
||||||
|
|
|
@ -160,6 +160,10 @@ namespace MWMechanics
|
||||||
/// @param bias Can be used to add an additional aggression bias towards the target,
|
/// @param bias Can be used to add an additional aggression bias towards the target,
|
||||||
/// making it more likely for the function to return true.
|
/// making it more likely for the function to return true.
|
||||||
virtual bool isAggressive (const MWWorld::Ptr& ptr, const MWWorld::Ptr& target, int bias=0, bool ignoreDistance=false);
|
virtual bool isAggressive (const MWWorld::Ptr& ptr, const MWWorld::Ptr& target, int bias=0, bool ignoreDistance=false);
|
||||||
|
|
||||||
|
/// Usually done once a frame, but can be invoked manually in time-critical situations.
|
||||||
|
/// This will increase the death count for any actors that were killed.
|
||||||
|
virtual void killDeadActors();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -57,10 +57,13 @@ void Repair::repair(const MWWorld::Ptr &itemToRepair)
|
||||||
charge = std::min(charge + y, itemToRepair.getClass().getItemMaxHealth(itemToRepair));
|
charge = std::min(charge + y, itemToRepair.getClass().getItemMaxHealth(itemToRepair));
|
||||||
itemToRepair.getCellRef().setCharge(charge);
|
itemToRepair.getCellRef().setCharge(charge);
|
||||||
|
|
||||||
|
// attempt to re-stack item, in case it was fully repaired
|
||||||
|
MWWorld::ContainerStoreIterator stacked = player.getClass().getContainerStore(player).restack(itemToRepair);
|
||||||
|
|
||||||
// set the OnPCRepair variable on the item's script
|
// set the OnPCRepair variable on the item's script
|
||||||
std::string script = itemToRepair.getClass().getScript(itemToRepair);
|
std::string script = stacked->getClass().getScript(itemToRepair);
|
||||||
if(script != "")
|
if(script != "")
|
||||||
itemToRepair.getRefData().getLocals().setVarByInt(script, "onpcrepair", 1);
|
stacked->getRefData().getLocals().setVarByInt(script, "onpcrepair", 1);
|
||||||
|
|
||||||
// increase skill
|
// increase skill
|
||||||
player.getClass().skillUsageSucceeded(player, ESM::Skill::Armorer, 0);
|
player.getClass().skillUsageSucceeded(player, ESM::Skill::Armorer, 0);
|
||||||
|
|
|
@ -92,7 +92,7 @@ namespace MWMechanics
|
||||||
x *= 0.1 * magicEffect->mData.mBaseCost;
|
x *= 0.1 * magicEffect->mData.mBaseCost;
|
||||||
x *= 0.5 * (it->mMagnMin + it->mMagnMax);
|
x *= 0.5 * (it->mMagnMin + it->mMagnMax);
|
||||||
x *= it->mArea * 0.05 * magicEffect->mData.mBaseCost;
|
x *= it->mArea * 0.05 * magicEffect->mData.mBaseCost;
|
||||||
if (magicEffect->mData.mFlags & ESM::MagicEffect::CastTarget)
|
if (it->mRange == ESM::RT_Target)
|
||||||
x *= 1.5;
|
x *= 1.5;
|
||||||
static const float fEffectCostMult = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find(
|
static const float fEffectCostMult = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find(
|
||||||
"fEffectCostMult")->getFloat();
|
"fEffectCostMult")->getFloat();
|
||||||
|
@ -148,6 +148,27 @@ namespace MWMechanics
|
||||||
return school;
|
return school;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float getEffectResistanceAttribute (short effectId, const MagicEffects* actorEffects)
|
||||||
|
{
|
||||||
|
short resistanceEffect = ESM::MagicEffect::getResistanceEffect(effectId);
|
||||||
|
short weaknessEffect = ESM::MagicEffect::getWeaknessEffect(effectId);
|
||||||
|
|
||||||
|
float resistance = 0;
|
||||||
|
if (resistanceEffect != -1)
|
||||||
|
resistance += actorEffects->get(resistanceEffect).mMagnitude;
|
||||||
|
if (weaknessEffect != -1)
|
||||||
|
resistance -= actorEffects->get(weaknessEffect).mMagnitude;
|
||||||
|
|
||||||
|
if (effectId == ESM::MagicEffect::FireDamage)
|
||||||
|
resistance += actorEffects->get(ESM::MagicEffect::FireShield).mMagnitude;
|
||||||
|
if (effectId == ESM::MagicEffect::ShockDamage)
|
||||||
|
resistance += actorEffects->get(ESM::MagicEffect::LightningShield).mMagnitude;
|
||||||
|
if (effectId == ESM::MagicEffect::FrostDamage)
|
||||||
|
resistance += actorEffects->get(ESM::MagicEffect::FrostShield).mMagnitude;
|
||||||
|
|
||||||
|
return resistance;
|
||||||
|
}
|
||||||
|
|
||||||
float getEffectResistance (short effectId, const MWWorld::Ptr& actor, const MWWorld::Ptr& caster,
|
float getEffectResistance (short effectId, const MWWorld::Ptr& actor, const MWWorld::Ptr& caster,
|
||||||
const ESM::Spell* spell, const MagicEffects* effects)
|
const ESM::Spell* spell, const MagicEffects* effects)
|
||||||
{
|
{
|
||||||
|
@ -163,16 +184,7 @@ namespace MWMechanics
|
||||||
float resisted = 0;
|
float resisted = 0;
|
||||||
if (magicEffect->mData.mFlags & ESM::MagicEffect::Harmful)
|
if (magicEffect->mData.mFlags & ESM::MagicEffect::Harmful)
|
||||||
{
|
{
|
||||||
|
float resistance = getEffectResistanceAttribute(effectId, magicEffects);
|
||||||
short resistanceEffect = ESM::MagicEffect::getResistanceEffect(effectId);
|
|
||||||
short weaknessEffect = ESM::MagicEffect::getWeaknessEffect(effectId);
|
|
||||||
|
|
||||||
float resistance = 0;
|
|
||||||
if (resistanceEffect != -1)
|
|
||||||
resistance += magicEffects->get(resistanceEffect).mMagnitude;
|
|
||||||
if (weaknessEffect != -1)
|
|
||||||
resistance -= magicEffects->get(weaknessEffect).mMagnitude;
|
|
||||||
|
|
||||||
|
|
||||||
float willpower = stats.getAttribute(ESM::Attribute::Willpower).getModified();
|
float willpower = stats.getAttribute(ESM::Attribute::Willpower).getModified();
|
||||||
float luck = stats.getAttribute(ESM::Attribute::Luck).getModified();
|
float luck = stats.getAttribute(ESM::Attribute::Luck).getModified();
|
||||||
|
@ -484,7 +496,11 @@ namespace MWMechanics
|
||||||
if (effectId == ESM::MagicEffect::Lock)
|
if (effectId == ESM::MagicEffect::Lock)
|
||||||
{
|
{
|
||||||
if (target.getCellRef().getLockLevel() < magnitude) //If the door is not already locked to a higher value, lock it to spell magnitude
|
if (target.getCellRef().getLockLevel() < magnitude) //If the door is not already locked to a higher value, lock it to spell magnitude
|
||||||
|
{
|
||||||
|
if (caster.getRefData().getHandle() == "player")
|
||||||
|
MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicLockSuccess}");
|
||||||
target.getCellRef().setLockLevel(magnitude);
|
target.getCellRef().setLockLevel(magnitude);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (effectId == ESM::MagicEffect::Open)
|
else if (effectId == ESM::MagicEffect::Open)
|
||||||
{
|
{
|
||||||
|
@ -492,12 +508,14 @@ namespace MWMechanics
|
||||||
{
|
{
|
||||||
if (target.getCellRef().getLockLevel() > 0)
|
if (target.getCellRef().getLockLevel() > 0)
|
||||||
{
|
{
|
||||||
//Door not already unlocked
|
|
||||||
MWBase::Environment::get().getSoundManager()->playSound3D(target, "Open Lock", 1.f, 1.f);
|
MWBase::Environment::get().getSoundManager()->playSound3D(target, "Open Lock", 1.f, 1.f);
|
||||||
if (!caster.isEmpty() && caster.getClass().isActor())
|
if (!caster.isEmpty() && caster.getClass().isActor())
|
||||||
MWBase::Environment::get().getMechanicsManager()->objectOpened(caster, target);
|
MWBase::Environment::get().getMechanicsManager()->objectOpened(caster, target);
|
||||||
|
|
||||||
|
if (caster.getRefData().getHandle() == "player")
|
||||||
|
MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicOpenSuccess}");
|
||||||
}
|
}
|
||||||
target.getCellRef().setLockLevel(-abs(target.getCellRef().getLockLevel())); //unlocks the door
|
target.getCellRef().setLockLevel(-abs(target.getCellRef().getLockLevel()));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
MWBase::Environment::get().getSoundManager()->playSound3D(target, "Open Lock Fail", 1.f, 1.f);
|
MWBase::Environment::get().getSoundManager()->playSound3D(target, "Open Lock Fail", 1.f, 1.f);
|
||||||
|
|
|
@ -35,6 +35,11 @@ namespace MWMechanics
|
||||||
int getSpellSchool(const std::string& spellId, const MWWorld::Ptr& actor);
|
int getSpellSchool(const std::string& spellId, const MWWorld::Ptr& actor);
|
||||||
int getSpellSchool(const ESM::Spell* spell, const MWWorld::Ptr& actor);
|
int getSpellSchool(const ESM::Spell* spell, const MWWorld::Ptr& actor);
|
||||||
|
|
||||||
|
/// Get the resistance attribute against an effect for a given actor. This will add together
|
||||||
|
/// ResistX and Weakness to X effects relevant against the given effect.
|
||||||
|
float getEffectResistanceAttribute (short effectId, const MagicEffects* actorEffects);
|
||||||
|
|
||||||
|
/// Get the effective resistance against an effect casted by the given actor in the given spell (optional).
|
||||||
/// @return >=100 for fully resisted. can also return negative value for damage amplification.
|
/// @return >=100 for fully resisted. can also return negative value for damage amplification.
|
||||||
/// @param effects Override the actor's current magicEffects. Useful if there are effects currently
|
/// @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.
|
/// being applied (but not applied yet) that should also be considered.
|
||||||
|
|
|
@ -149,6 +149,8 @@ namespace MWRender
|
||||||
mViewModeToggleQueued = true;
|
mViewModeToggleQueued = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
mViewModeToggleQueued = false;
|
||||||
|
|
||||||
mFirstPersonView = !mFirstPersonView;
|
mFirstPersonView = !mFirstPersonView;
|
||||||
processViewChange();
|
processViewChange();
|
||||||
|
|
|
@ -340,7 +340,9 @@ Ogre::TexturePtr LocalMap::createFogOfWarTexture(const std::string &texName)
|
||||||
sFogOfWarResolution, sFogOfWarResolution,
|
sFogOfWarResolution, sFogOfWarResolution,
|
||||||
0,
|
0,
|
||||||
PF_A8R8G8B8,
|
PF_A8R8G8B8,
|
||||||
TU_DYNAMIC_WRITE_ONLY);
|
TU_DYNAMIC_WRITE_ONLY,
|
||||||
|
this // ManualResourceLoader required if the texture contents are lost (due to lost devices nonsense that can occur with D3D)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return tex;
|
return tex;
|
||||||
|
@ -457,6 +459,30 @@ bool LocalMap::isPositionExplored (float nX, float nY, int x, int y, bool interi
|
||||||
return alpha < 200;
|
return alpha < 200;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LocalMap::loadResource(Ogre::Resource* resource)
|
||||||
|
{
|
||||||
|
std::string resourceName = resource->getName();
|
||||||
|
size_t pos = resourceName.find("_fog");
|
||||||
|
if (pos != std::string::npos)
|
||||||
|
resourceName = resourceName.substr(0, pos);
|
||||||
|
if (mBuffers.find(resourceName) == mBuffers.end())
|
||||||
|
{
|
||||||
|
// create a buffer to use for dynamic operations
|
||||||
|
std::vector<uint32> buffer;
|
||||||
|
|
||||||
|
// initialize to (0, 0, 0, 1)
|
||||||
|
buffer.resize(sFogOfWarResolution*sFogOfWarResolution, 0xFF000000);
|
||||||
|
mBuffers[resourceName] = buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<uint32>& buffer = mBuffers[resourceName];
|
||||||
|
|
||||||
|
Ogre::Texture* tex = dynamic_cast<Ogre::Texture*>(resource);
|
||||||
|
tex->createInternalResources();
|
||||||
|
memcpy(tex->getBuffer()->lock(HardwareBuffer::HBL_DISCARD), &buffer[0], sFogOfWarResolution*sFogOfWarResolution*4);
|
||||||
|
tex->getBuffer()->unlock();
|
||||||
|
}
|
||||||
|
|
||||||
void LocalMap::updatePlayer (const Ogre::Vector3& position, const Ogre::Quaternion& orientation)
|
void LocalMap::updatePlayer (const Ogre::Vector3& position, const Ogre::Quaternion& orientation)
|
||||||
{
|
{
|
||||||
if (sFogOfWarSkip != 0)
|
if (sFogOfWarSkip != 0)
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
|
|
||||||
#include <OgreAxisAlignedBox.h>
|
#include <OgreAxisAlignedBox.h>
|
||||||
#include <OgreColourValue.h>
|
#include <OgreColourValue.h>
|
||||||
|
#include <OgreResource.h>
|
||||||
|
|
||||||
namespace MWWorld
|
namespace MWWorld
|
||||||
{
|
{
|
||||||
|
@ -23,12 +24,14 @@ namespace MWRender
|
||||||
///
|
///
|
||||||
/// \brief Local map rendering
|
/// \brief Local map rendering
|
||||||
///
|
///
|
||||||
class LocalMap
|
class LocalMap : public Ogre::ManualResourceLoader
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
LocalMap(OEngine::Render::OgreRenderer*, MWRender::RenderingManager* rendering);
|
LocalMap(OEngine::Render::OgreRenderer*, MWRender::RenderingManager* rendering);
|
||||||
~LocalMap();
|
~LocalMap();
|
||||||
|
|
||||||
|
virtual void loadResource(Ogre::Resource* resource);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clear all savegame-specific data (i.e. fog of war textures)
|
* Clear all savegame-specific data (i.e. fog of war textures)
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -1088,7 +1088,7 @@ public:
|
||||||
|
|
||||||
void close() { }
|
void close() { }
|
||||||
|
|
||||||
bool update(Ogre::MaterialPtr &mat, Ogre::Rectangle2D *rect, int screen_width, int screen_height)
|
bool update()
|
||||||
{ return false; }
|
{ return false; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -147,6 +147,14 @@ namespace MWScript
|
||||||
}
|
}
|
||||||
|
|
||||||
ptr.getClass().lock (ptr, lockLevel);
|
ptr.getClass().lock (ptr, lockLevel);
|
||||||
|
|
||||||
|
// Instantly reset door to closed state
|
||||||
|
// This is done when using Lock in scripts, but not when using Lock spells.
|
||||||
|
if (ptr.getTypeName() == typeid(ESM::Door).name())
|
||||||
|
{
|
||||||
|
MWBase::Environment::get().getWorld()->activateDoor(ptr, 0);
|
||||||
|
MWBase::Environment::get().getWorld()->localRotateObject(ptr, 0, 0, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -86,16 +86,24 @@ namespace MWScript
|
||||||
float ay = Ogre::Radian(ptr.getRefData().getPosition().rot[1]).valueDegrees();
|
float ay = Ogre::Radian(ptr.getRefData().getPosition().rot[1]).valueDegrees();
|
||||||
float az = Ogre::Radian(ptr.getRefData().getPosition().rot[2]).valueDegrees();
|
float az = Ogre::Radian(ptr.getRefData().getPosition().rot[2]).valueDegrees();
|
||||||
|
|
||||||
|
MWWorld::LocalRotation localRot = ptr.getRefData().getLocalRotation();
|
||||||
|
|
||||||
if (axis == "x")
|
if (axis == "x")
|
||||||
{
|
{
|
||||||
|
localRot.rot[0] = 0;
|
||||||
|
ptr.getRefData().setLocalRotation(localRot);
|
||||||
MWBase::Environment::get().getWorld()->rotateObject(ptr,angle,ay,az);
|
MWBase::Environment::get().getWorld()->rotateObject(ptr,angle,ay,az);
|
||||||
}
|
}
|
||||||
else if (axis == "y")
|
else if (axis == "y")
|
||||||
{
|
{
|
||||||
|
localRot.rot[1] = 0;
|
||||||
|
ptr.getRefData().setLocalRotation(localRot);
|
||||||
MWBase::Environment::get().getWorld()->rotateObject(ptr,ax,angle,az);
|
MWBase::Environment::get().getWorld()->rotateObject(ptr,ax,angle,az);
|
||||||
}
|
}
|
||||||
else if (axis == "z")
|
else if (axis == "z")
|
||||||
{
|
{
|
||||||
|
localRot.rot[2] = 0;
|
||||||
|
ptr.getRefData().setLocalRotation(localRot);
|
||||||
MWBase::Environment::get().getWorld()->rotateObject(ptr,ax,ay,angle);
|
MWBase::Environment::get().getWorld()->rotateObject(ptr,ax,ay,angle);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
@ -88,6 +88,16 @@ namespace MWWorld
|
||||||
return mCellRef.mOwner;
|
return mCellRef.mOwner;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string CellRef::getGlobalVariable() const
|
||||||
|
{
|
||||||
|
return mCellRef.mGlobalVariable;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CellRef::getFactionRank() const
|
||||||
|
{
|
||||||
|
return mCellRef.mFactionRank;
|
||||||
|
}
|
||||||
|
|
||||||
void CellRef::setOwner(const std::string &owner)
|
void CellRef::setOwner(const std::string &owner)
|
||||||
{
|
{
|
||||||
if (owner != mCellRef.mOwner)
|
if (owner != mCellRef.mOwner)
|
||||||
|
|
|
@ -61,6 +61,11 @@ namespace MWWorld
|
||||||
std::string getOwner() const;
|
std::string getOwner() const;
|
||||||
void setOwner(const std::string& owner);
|
void setOwner(const std::string& owner);
|
||||||
|
|
||||||
|
// Name of a global variable. If the global variable is set to '1', using the object is temporarily allowed
|
||||||
|
// even if it has an Owner field.
|
||||||
|
// Used by bed rent scripts to allow the player to use the bed for the duration of the rent.
|
||||||
|
std::string getGlobalVariable() const;
|
||||||
|
|
||||||
// ID of creature trapped in this soul gem
|
// ID of creature trapped in this soul gem
|
||||||
std::string getSoul() const;
|
std::string getSoul() const;
|
||||||
void setSoul(const std::string& soul);
|
void setSoul(const std::string& soul);
|
||||||
|
@ -70,6 +75,9 @@ namespace MWWorld
|
||||||
std::string getFaction() const;
|
std::string getFaction() const;
|
||||||
void setFaction (const std::string& faction);
|
void setFaction (const std::string& faction);
|
||||||
|
|
||||||
|
// PC faction rank required to use the item. Sometimes is -1, which means "any rank".
|
||||||
|
int getFactionRank() const;
|
||||||
|
|
||||||
// Lock level for doors and containers
|
// Lock level for doors and containers
|
||||||
// Positive for a locked door. 0 for a door that was never locked.
|
// Positive for a locked door. 0 for a door that was never locked.
|
||||||
// For an unlocked door, it is set to -(previous locklevel)
|
// For an unlocked door, it is set to -(previous locklevel)
|
||||||
|
|
|
@ -141,6 +141,34 @@ void MWWorld::ContainerStore::unstack(const Ptr &ptr, const Ptr& container)
|
||||||
remove(ptr, ptr.getRefData().getCount()-1, container);
|
remove(ptr, ptr.getRefData().getCount()-1, container);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MWWorld::ContainerStoreIterator MWWorld::ContainerStore::restack(const MWWorld::Ptr& item)
|
||||||
|
{
|
||||||
|
MWWorld::ContainerStoreIterator retval = end();
|
||||||
|
for (MWWorld::ContainerStoreIterator iter (begin()); iter != end(); ++iter)
|
||||||
|
{
|
||||||
|
if (item == *iter)
|
||||||
|
{
|
||||||
|
retval = iter;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (retval == end())
|
||||||
|
throw std::runtime_error("item is not from this container");
|
||||||
|
|
||||||
|
for (MWWorld::ContainerStoreIterator iter (begin()); iter != end(); ++iter)
|
||||||
|
{
|
||||||
|
if (stacks(*iter, item))
|
||||||
|
{
|
||||||
|
iter->getRefData().setCount(iter->getRefData().getCount() + item.getRefData().getCount());
|
||||||
|
item.getRefData().setCount(0);
|
||||||
|
retval = iter;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
bool MWWorld::ContainerStore::stacks(const Ptr& ptr1, const Ptr& ptr2)
|
bool MWWorld::ContainerStore::stacks(const Ptr& ptr1, const Ptr& ptr2)
|
||||||
{
|
{
|
||||||
const MWWorld::Class& cls1 = ptr1.getClass();
|
const MWWorld::Class& cls1 = ptr1.getClass();
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue