Merge branch 'master' into preview
|
@ -73,6 +73,8 @@ option(OGRE_STATIC "Link static build of Ogre and Ogre Plugins into the binarie
|
|||
option(BOOST_STATIC "Link static build of Boost into the binaries" FALSE)
|
||||
option(SDL2_STATIC "Link static build of SDL into the binaries" FALSE)
|
||||
|
||||
option(OPENMW_UNITY_BUILD "Use fewer compilation units to speed up compile time" FALSE)
|
||||
|
||||
# Apps and tools
|
||||
option(BUILD_BSATOOL "build BSA extractor" OFF)
|
||||
option(BUILD_ESMTOOL "build ESM inspector" ON)
|
||||
|
@ -463,7 +465,6 @@ if(WIN32)
|
|||
INSTALL(FILES
|
||||
"${OpenMW_SOURCE_DIR}/readme.txt"
|
||||
"${OpenMW_SOURCE_DIR}/GPL3.txt"
|
||||
"${OpenMW_SOURCE_DIR}/OFL.txt"
|
||||
"${OpenMW_SOURCE_DIR}/DejaVu Font License.txt"
|
||||
"${OpenMW_BINARY_DIR}/settings-default.cfg"
|
||||
"${OpenMW_BINARY_DIR}/transparency-overrides.cfg"
|
||||
|
|
93
OFL.txt
|
@ -1,93 +0,0 @@
|
|||
Copyright (c) 2010, 2011 Georg Duffner (http://www.georgduffner.at)
|
||||
|
||||
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||
This license is copied below, and is also available with a FAQ at:
|
||||
http://scripts.sil.org/OFL
|
||||
|
||||
|
||||
-----------------------------------------------------------
|
||||
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||
-----------------------------------------------------------
|
||||
|
||||
PREAMBLE
|
||||
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||
development of collaborative font projects, to support the font creation
|
||||
efforts of academic and linguistic communities, and to provide a free and
|
||||
open framework in which fonts may be shared and improved in partnership
|
||||
with others.
|
||||
|
||||
The OFL allows the licensed fonts to be used, studied, modified and
|
||||
redistributed freely as long as they are not sold by themselves. The
|
||||
fonts, including any derivative works, can be bundled, embedded,
|
||||
redistributed and/or sold with any software provided that any reserved
|
||||
names are not used by derivative works. The fonts and derivatives,
|
||||
however, cannot be released under any other type of license. The
|
||||
requirement for fonts to remain under this license does not apply
|
||||
to any document created using the fonts or their derivatives.
|
||||
|
||||
DEFINITIONS
|
||||
"Font Software" refers to the set of files released by the Copyright
|
||||
Holder(s) under this license and clearly marked as such. This may
|
||||
include source files, build scripts and documentation.
|
||||
|
||||
"Reserved Font Name" refers to any names specified as such after the
|
||||
copyright statement(s).
|
||||
|
||||
"Original Version" refers to the collection of Font Software components as
|
||||
distributed by the Copyright Holder(s).
|
||||
|
||||
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||
or substituting -- in part or in whole -- any of the components of the
|
||||
Original Version, by changing formats or by porting the Font Software to a
|
||||
new environment.
|
||||
|
||||
"Author" refers to any designer, engineer, programmer, technical
|
||||
writer or other person who contributed to the Font Software.
|
||||
|
||||
PERMISSION & CONDITIONS
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||
redistribute, and sell modified and unmodified copies of the Font
|
||||
Software, subject to the following conditions:
|
||||
|
||||
1) Neither the Font Software nor any of its individual components,
|
||||
in Original or Modified Versions, may be sold by itself.
|
||||
|
||||
2) Original or Modified Versions of the Font Software may be bundled,
|
||||
redistributed and/or sold with any software, provided that each copy
|
||||
contains the above copyright notice and this license. These can be
|
||||
included either as stand-alone text files, human-readable headers or
|
||||
in the appropriate machine-readable metadata fields within text or
|
||||
binary files as long as those fields can be easily viewed by the user.
|
||||
|
||||
3) No Modified Version of the Font Software may use the Reserved Font
|
||||
Name(s) unless explicit written permission is granted by the corresponding
|
||||
Copyright Holder. This restriction only applies to the primary font name as
|
||||
presented to the users.
|
||||
|
||||
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||
Software shall not be used to promote, endorse or advertise any
|
||||
Modified Version, except to acknowledge the contribution(s) of the
|
||||
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||
permission.
|
||||
|
||||
5) The Font Software, modified or unmodified, in part or in whole,
|
||||
must be distributed entirely under this license, and must not be
|
||||
distributed under any other license. The requirement for fonts to
|
||||
remain under this license does not apply to any document created
|
||||
using the Font Software.
|
||||
|
||||
TERMINATION
|
||||
This license becomes null and void if any of the above conditions are
|
||||
not met.
|
||||
|
||||
DISCLAIMER
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||
OTHER DEALINGS IN THE FONT SOFTWARE.
|
|
@ -60,7 +60,7 @@ opencs_hdrs_noqt (view/doc
|
|||
opencs_units (view/world
|
||||
table tablesubview scriptsubview util regionmapsubview tablebottombox creator genericcreator
|
||||
cellcreator referenceablecreator referencecreator scenesubview scenetoolbar scenetool
|
||||
scenetoolmode infocreator scriptedit previewsubview
|
||||
scenetoolmode infocreator scriptedit dialoguesubview previewsubview
|
||||
)
|
||||
|
||||
opencs_units (view/render
|
||||
|
@ -73,8 +73,7 @@ opencs_units_noqt (view/render
|
|||
)
|
||||
|
||||
opencs_units_noqt (view/world
|
||||
dialoguesubview subviews
|
||||
enumdelegate vartypedelegate recordstatusdelegate idtypedelegate datadisplaydelegate
|
||||
subviews enumdelegate vartypedelegate recordstatusdelegate idtypedelegate datadisplaydelegate
|
||||
scripthighlighter idvalidator dialoguecreator
|
||||
)
|
||||
|
||||
|
|
|
@ -17,4 +17,9 @@ bool CSMWorld::ColumnBase::isUserEditable() const
|
|||
std::string CSMWorld::ColumnBase::getTitle() const
|
||||
{
|
||||
return Columns::getName (static_cast<Columns::ColumnId> (mColumnId));
|
||||
}
|
||||
|
||||
int CSMWorld::ColumnBase::getId() const
|
||||
{
|
||||
return mColumnId;
|
||||
}
|
|
@ -28,6 +28,7 @@ namespace CSMWorld
|
|||
{
|
||||
Display_None, //Do not use
|
||||
Display_String,
|
||||
Display_LongString,
|
||||
|
||||
//CONCRETE TYPES STARTS HERE
|
||||
Display_Skill,
|
||||
|
@ -105,6 +106,8 @@ namespace CSMWorld
|
|||
///< Can this column be edited directly by the user?
|
||||
|
||||
virtual std::string getTitle() const;
|
||||
|
||||
virtual int getId() const;
|
||||
};
|
||||
|
||||
template<typename ESXRecordT>
|
||||
|
|
|
@ -201,7 +201,7 @@ namespace CSMWorld
|
|||
struct DescriptionColumn : public Column<ESXRecordT>
|
||||
{
|
||||
DescriptionColumn()
|
||||
: Column<ESXRecordT> (Columns::ColumnId_Description, ColumnBase::Display_String)
|
||||
: Column<ESXRecordT> (Columns::ColumnId_Description, ColumnBase::Display_LongString)
|
||||
{}
|
||||
|
||||
virtual QVariant get (const Record<ESXRecordT>& record) const
|
||||
|
@ -833,7 +833,7 @@ namespace CSMWorld
|
|||
|
||||
virtual bool isUserEditable() const
|
||||
{
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1113,7 +1113,7 @@ namespace CSMWorld
|
|||
|
||||
virtual bool isUserEditable() const
|
||||
{
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1379,7 +1379,7 @@ namespace CSMWorld
|
|||
template<typename ESXRecordT>
|
||||
struct QuestDescriptionColumn : public Column<ESXRecordT>
|
||||
{
|
||||
QuestDescriptionColumn() : Column<ESXRecordT> (Columns::ColumnId_QuestDescription, ColumnBase::Display_String) {}
|
||||
QuestDescriptionColumn() : Column<ESXRecordT> (Columns::ColumnId_QuestDescription, ColumnBase::Display_LongString) {}
|
||||
|
||||
virtual QVariant get (const Record<ESXRecordT>& record) const
|
||||
{
|
||||
|
@ -1559,7 +1559,7 @@ namespace CSMWorld
|
|||
template<typename ESXRecordT>
|
||||
struct ResponseColumn : public Column<ESXRecordT>
|
||||
{
|
||||
ResponseColumn() : Column<ESXRecordT> (Columns::ColumnId_Response, ColumnBase::Display_String) {}
|
||||
ResponseColumn() : Column<ESXRecordT> (Columns::ColumnId_Response, ColumnBase::Display_LongString) {}
|
||||
|
||||
virtual QVariant get (const Record<ESXRecordT>& record) const
|
||||
{
|
||||
|
|
|
@ -235,4 +235,9 @@ std::pair<CSMWorld::UniversalId, std::string> CSMWorld::IdTable::view (int row)
|
|||
id = "sys::default";
|
||||
|
||||
return std::make_pair (UniversalId (UniversalId::Type_Scene, id), hint);
|
||||
}
|
||||
|
||||
int CSMWorld::IdTable::getColumnId(int column) const
|
||||
{
|
||||
return mIdCollection->getColumn(column).getId();
|
||||
}
|
|
@ -106,6 +106,8 @@ namespace CSMWorld
|
|||
std::pair<UniversalId, std::string> view (int row) const;
|
||||
///< Return the UniversalId and the hint for viewing \a row. If viewing is not
|
||||
/// supported by this table, return (UniversalId::Type_None, "").
|
||||
|
||||
int getColumnId(int column) const;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -443,4 +443,9 @@ CSMWorld::ColumnBase::Display CSMWorld::TableMimeData::convertEnums (CSMWorld::U
|
|||
default:
|
||||
return CSMWorld::ColumnBase::Display_None;
|
||||
}
|
||||
}
|
||||
|
||||
const CSMDoc::Document* CSMWorld::TableMimeData::getDocumentPtr() const
|
||||
{
|
||||
return &mDocument;
|
||||
}
|
|
@ -48,6 +48,8 @@ namespace CSMWorld
|
|||
|
||||
UniversalId returnMatching(UniversalId::Type type) const;
|
||||
|
||||
const CSMDoc::Document* getDocumentPtr() const;
|
||||
|
||||
UniversalId returnMatching(CSMWorld::ColumnBase::Display type) const;
|
||||
|
||||
static CSMWorld::UniversalId::Type convertEnums(CSMWorld::ColumnBase::Display type);
|
||||
|
|
|
@ -18,4 +18,10 @@ void CSVDoc::SubView::updateEditorSetting (const QString &settingName, const QSt
|
|||
|
||||
void CSVDoc::SubView::setStatusBar (bool show) {}
|
||||
|
||||
void CSVDoc::SubView::useHint (const std::string& hint) {}
|
||||
void CSVDoc::SubView::useHint (const std::string& hint) {}
|
||||
|
||||
void CSVDoc::SubView::setUniversalId (const CSMWorld::UniversalId& id)
|
||||
{
|
||||
mUniversalId = id;
|
||||
setWindowTitle (mUniversalId.toString().c_str());
|
||||
}
|
|
@ -27,6 +27,8 @@ namespace CSVDoc
|
|||
// not implemented
|
||||
SubView (const SubView&);
|
||||
SubView& operator= (SubView&);
|
||||
protected:
|
||||
void setUniversalId(const CSMWorld::UniversalId& id);
|
||||
|
||||
public:
|
||||
|
||||
|
|
|
@ -316,8 +316,16 @@ void CSVDoc::View::addSubView (const CSMWorld::UniversalId& id, const std::strin
|
|||
|
||||
/// \todo add an user setting to reuse sub views (on a per document basis or on a per top level view basis)
|
||||
|
||||
SubView *view = mSubViewFactory.makeSubView (id, *mDocument);
|
||||
|
||||
const std::vector<CSMWorld::UniversalId::Type> referenceables(CSMWorld::UniversalId::listReferenceableTypes());
|
||||
SubView *view = NULL;
|
||||
if(std::find(referenceables.begin(), referenceables.end(), id.getType()) != referenceables.end())
|
||||
{
|
||||
view = mSubViewFactory.makeSubView (CSMWorld::UniversalId(CSMWorld::UniversalId::Type_Referenceable, id.getId()), *mDocument);
|
||||
} else
|
||||
{
|
||||
view = mSubViewFactory.makeSubView (id, *mDocument);
|
||||
}
|
||||
assert(view);
|
||||
if (!hint.empty())
|
||||
view->useHint (hint);
|
||||
|
||||
|
|
|
@ -1,98 +1,663 @@
|
|||
|
||||
#include "dialoguesubview.hpp"
|
||||
|
||||
#include <utility>
|
||||
#include <memory>
|
||||
|
||||
#include <QGridLayout>
|
||||
#include <QLabel>
|
||||
#include <QSize>
|
||||
#include <QAbstractItemModel>
|
||||
#include <QDoubleSpinBox>
|
||||
#include <QSpinBox>
|
||||
#include <QLineEdit>
|
||||
#include <QEvent>
|
||||
#include <QDataWidgetMapper>
|
||||
#include <QCheckBox>
|
||||
#include <QLineEdit>
|
||||
#include <QPlainTextEdit>
|
||||
#include <QComboBox>
|
||||
#include <QScrollArea>
|
||||
#include <QPushButton>
|
||||
#include <QToolButton>
|
||||
|
||||
#include "../../model/world/columnbase.hpp"
|
||||
#include "../../model/world/idtable.hpp"
|
||||
#include "../../model/world/columns.hpp"
|
||||
#include "../../model/world/record.hpp"
|
||||
#include "../../model/world/tablemimedata.hpp"
|
||||
#include "../../model/doc/document.hpp"
|
||||
#include "../../model/world/commands.hpp"
|
||||
|
||||
CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document,
|
||||
bool createAndDelete)
|
||||
: SubView (id)
|
||||
#include "recordstatusdelegate.hpp"
|
||||
#include "util.hpp"
|
||||
#include "tablebottombox.hpp"
|
||||
/*
|
||||
==============================NotEditableSubDelegate==========================================
|
||||
*/
|
||||
CSVWorld::NotEditableSubDelegate::NotEditableSubDelegate(const CSMWorld::IdTable* table, QObject * parent) :
|
||||
QAbstractItemDelegate(parent),
|
||||
mTable(table)
|
||||
{}
|
||||
|
||||
void CSVWorld::NotEditableSubDelegate::setEditorData (QLabel* editor, const QModelIndex& index) const
|
||||
{
|
||||
QWidget *widget = new QWidget (this);
|
||||
|
||||
setWidget (widget);
|
||||
|
||||
QGridLayout *layout = new QGridLayout;
|
||||
|
||||
widget->setLayout (layout);
|
||||
|
||||
QAbstractItemModel *model = document.getData().getTableModel (id);
|
||||
|
||||
int columns = model->columnCount();
|
||||
|
||||
mWidgetMapper = new QDataWidgetMapper (this);
|
||||
mWidgetMapper->setModel (model);
|
||||
|
||||
for (int i=0; i<columns; ++i)
|
||||
QVariant v = index.data(Qt::EditRole);
|
||||
if (!v.isValid())
|
||||
{
|
||||
int flags = model->headerData (i, Qt::Horizontal, CSMWorld::ColumnBase::Role_Flags).toInt();
|
||||
|
||||
if (flags & CSMWorld::ColumnBase::Flag_Dialogue)
|
||||
v = index.data(Qt::DisplayRole);
|
||||
if (!v.isValid())
|
||||
{
|
||||
layout->addWidget (new QLabel (model->headerData (i, Qt::Horizontal).toString()), i, 0);
|
||||
|
||||
CSMWorld::ColumnBase::Display display = static_cast<CSMWorld::ColumnBase::Display>
|
||||
(model->headerData (i, Qt::Horizontal, CSMWorld::ColumnBase::Role_Display).toInt());
|
||||
|
||||
QWidget *widget = 0;
|
||||
|
||||
if (model->flags (model->index (0, i)) & Qt::ItemIsEditable)
|
||||
{
|
||||
switch (display)
|
||||
{
|
||||
case CSMWorld::ColumnBase::Display_String:
|
||||
|
||||
layout->addWidget (widget = new QLineEdit, i, 1);
|
||||
break;
|
||||
|
||||
case CSMWorld::ColumnBase::Display_Integer:
|
||||
|
||||
/// \todo configure widget properly (range)
|
||||
layout->addWidget (widget = new QSpinBox, i, 1);
|
||||
break;
|
||||
|
||||
case CSMWorld::ColumnBase::Display_Float:
|
||||
|
||||
/// \todo configure widget properly (range, format?)
|
||||
layout->addWidget (widget = new QDoubleSpinBox, i, 1);
|
||||
break;
|
||||
|
||||
default: break; // silence warnings for other times for now
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (display)
|
||||
{
|
||||
case CSMWorld::ColumnBase::Display_String:
|
||||
case CSMWorld::ColumnBase::Display_Integer:
|
||||
case CSMWorld::ColumnBase::Display_Float:
|
||||
|
||||
layout->addWidget (widget = new QLabel, i, 1);
|
||||
break;
|
||||
|
||||
default: break; // silence warnings for other times for now
|
||||
}
|
||||
}
|
||||
|
||||
if (widget)
|
||||
mWidgetMapper->addMapping (widget, i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
mWidgetMapper->setCurrentModelIndex (
|
||||
dynamic_cast<CSMWorld::IdTable&> (*model).getModelIndex (id.getId(), 0));
|
||||
if (QVariant::String == v.type())
|
||||
{
|
||||
editor->setText(v.toString());
|
||||
} else //else we are facing enums
|
||||
{
|
||||
int data = v.toInt();
|
||||
std::vector<std::string> enumNames (CSMWorld::Columns::getEnums (static_cast<CSMWorld::Columns::ColumnId> (mTable->getColumnId (index.column()))));
|
||||
editor->setText(QString::fromUtf8(enumNames.at(data).c_str()));
|
||||
}
|
||||
}
|
||||
|
||||
void CSVWorld::NotEditableSubDelegate::setModelData (QWidget* editor, QAbstractItemModel* model, const QModelIndex& index, CSMWorld::ColumnBase::Display display) const
|
||||
{
|
||||
//not editable widgets will not save model data
|
||||
}
|
||||
|
||||
void CSVWorld::NotEditableSubDelegate::paint (QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const
|
||||
{
|
||||
//does nothing
|
||||
}
|
||||
|
||||
QSize CSVWorld::NotEditableSubDelegate::sizeHint (const QStyleOptionViewItem& option, const QModelIndex& index) const
|
||||
{
|
||||
return QSize();
|
||||
}
|
||||
|
||||
QWidget* CSVWorld::NotEditableSubDelegate::createEditor (QWidget *parent,
|
||||
const QStyleOptionViewItem& option,
|
||||
const QModelIndex& index,
|
||||
CSMWorld::ColumnBase::Display display) const
|
||||
{
|
||||
return new QLabel(parent);
|
||||
}
|
||||
|
||||
/*
|
||||
==============================DialogueDelegateDispatcherProxy==========================================
|
||||
*/
|
||||
CSVWorld::DialogueDelegateDispatcherProxy::refWrapper::refWrapper(const QModelIndex& index) :
|
||||
mIndex(index)
|
||||
{}
|
||||
|
||||
CSVWorld::DialogueDelegateDispatcherProxy::DialogueDelegateDispatcherProxy(QWidget* editor, CSMWorld::ColumnBase::Display display) :
|
||||
mEditor(editor),
|
||||
mDisplay(display),
|
||||
mIndexWrapper(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
void CSVWorld::DialogueDelegateDispatcherProxy::editorDataCommited()
|
||||
{
|
||||
if (mIndexWrapper.get())
|
||||
{
|
||||
emit editorDataCommited(mEditor, mIndexWrapper->mIndex, mDisplay);
|
||||
}
|
||||
}
|
||||
|
||||
void CSVWorld::DialogueDelegateDispatcherProxy::setIndex(const QModelIndex& index)
|
||||
{
|
||||
mIndexWrapper.reset(new refWrapper(index));
|
||||
}
|
||||
|
||||
QWidget* CSVWorld::DialogueDelegateDispatcherProxy::getEditor() const
|
||||
{
|
||||
return mEditor;
|
||||
}
|
||||
|
||||
void CSVWorld::DialogueDelegateDispatcherProxy::tableMimeDataDropped(const std::vector<CSMWorld::UniversalId>& data, const CSMDoc::Document* document)
|
||||
{
|
||||
QLineEdit* lineEdit = qobject_cast<QLineEdit*>(mEditor);
|
||||
{
|
||||
if (!lineEdit or !mIndexWrapper.get())
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
for (unsigned i = 0; i < data.size(); ++i)
|
||||
{
|
||||
if (mDisplay == CSMWorld::TableMimeData::convertEnums(data[i].getType()))
|
||||
{
|
||||
emit tableMimeDataDropped(mEditor, mIndexWrapper->mIndex, data[i], document);
|
||||
emit editorDataCommited(mEditor, mIndexWrapper->mIndex, mDisplay);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
==============================DialogueDelegateDispatcher==========================================
|
||||
*/
|
||||
|
||||
CSVWorld::DialogueDelegateDispatcher::DialogueDelegateDispatcher(QObject* parent, CSMWorld::IdTable* table, QUndoStack& undoStack) :
|
||||
mParent(parent),
|
||||
mTable(table),
|
||||
mUndoStack(undoStack),
|
||||
mNotEditableDelegate(table, parent)
|
||||
{
|
||||
}
|
||||
|
||||
CSVWorld::CommandDelegate* CSVWorld::DialogueDelegateDispatcher::makeDelegate(CSMWorld::ColumnBase::Display display)
|
||||
{
|
||||
CommandDelegate *delegate = NULL;
|
||||
std::map<int, CommandDelegate*>::const_iterator delegateIt(mDelegates.find(display));
|
||||
if (delegateIt == mDelegates.end())
|
||||
{
|
||||
delegate = CommandDelegateFactoryCollection::get().makeDelegate (
|
||||
display, mUndoStack, mParent);
|
||||
mDelegates.insert(std::make_pair<int, CommandDelegate*>(display, delegate));
|
||||
} else
|
||||
{
|
||||
delegate = delegateIt->second;
|
||||
}
|
||||
return delegate;
|
||||
}
|
||||
|
||||
void CSVWorld::DialogueDelegateDispatcher::editorDataCommited(QWidget* editor, const QModelIndex& index, CSMWorld::ColumnBase::Display display)
|
||||
{
|
||||
setModelData(editor, mTable, index, display);
|
||||
}
|
||||
|
||||
void CSVWorld::DialogueDelegateDispatcher::setEditorData (QWidget* editor, const QModelIndex& index) const
|
||||
{
|
||||
CSMWorld::ColumnBase::Display display = static_cast<CSMWorld::ColumnBase::Display>
|
||||
(mTable->headerData (index.column(), Qt::Horizontal, CSMWorld::ColumnBase::Role_Display).toInt());
|
||||
|
||||
QLabel* label = qobject_cast<QLabel*>(editor);
|
||||
if(label)
|
||||
{
|
||||
mNotEditableDelegate.setEditorData(label, index);
|
||||
return;
|
||||
}
|
||||
|
||||
std::map<int, CommandDelegate*>::const_iterator delegateIt(mDelegates.find(display));
|
||||
if (delegateIt != mDelegates.end())
|
||||
{
|
||||
delegateIt->second->setEditorData(editor, index, true);
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < mProxys.size(); ++i)
|
||||
{
|
||||
if (mProxys[i]->getEditor() == editor)
|
||||
{
|
||||
mProxys[i]->setIndex(index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CSVWorld::DialogueDelegateDispatcher::setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index, CSMWorld::ColumnBase::Display display) const
|
||||
{
|
||||
std::map<int, CommandDelegate*>::const_iterator delegateIt(mDelegates.find(display));
|
||||
if (delegateIt != mDelegates.end())
|
||||
{
|
||||
delegateIt->second->setModelData(editor, model, index);
|
||||
}
|
||||
}
|
||||
|
||||
void CSVWorld::DialogueDelegateDispatcher::paint (QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const
|
||||
{
|
||||
//Does nothing
|
||||
}
|
||||
|
||||
QSize CSVWorld::DialogueDelegateDispatcher::sizeHint (const QStyleOptionViewItem& option, const QModelIndex& index) const
|
||||
{
|
||||
return QSize(); //silencing warning, otherwise does nothing
|
||||
}
|
||||
|
||||
QWidget* CSVWorld::DialogueDelegateDispatcher::makeEditor(CSMWorld::ColumnBase::Display display, const QModelIndex& index)
|
||||
{
|
||||
QVariant variant = index.data();
|
||||
if (!variant.isValid())
|
||||
{
|
||||
variant = index.data(Qt::DisplayRole);
|
||||
if (!variant.isValid())
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
QWidget* editor = NULL;
|
||||
if (! (mTable->flags (index) & Qt::ItemIsEditable))
|
||||
{
|
||||
return mNotEditableDelegate.createEditor(qobject_cast<QWidget*>(mParent), QStyleOptionViewItem(), index, display);
|
||||
}
|
||||
|
||||
std::map<int, CommandDelegate*>::iterator delegateIt(mDelegates.find(display));
|
||||
if (delegateIt != mDelegates.end())
|
||||
{
|
||||
editor = delegateIt->second->createEditor(qobject_cast<QWidget*>(mParent), QStyleOptionViewItem(), index, display);
|
||||
DialogueDelegateDispatcherProxy* proxy = new DialogueDelegateDispatcherProxy(editor, display);
|
||||
|
||||
bool skip = false;
|
||||
if (qobject_cast<DropLineEdit*>(editor))
|
||||
{
|
||||
connect(editor, SIGNAL(editingFinished()), proxy, SLOT(editorDataCommited()));
|
||||
connect(editor, SIGNAL(tableMimeDataDropped(const std::vector<CSMWorld::UniversalId>&, const CSMDoc::Document*)),
|
||||
proxy, SLOT(tableMimeDataDropped(const std::vector<CSMWorld::UniversalId>&, const CSMDoc::Document*)));
|
||||
connect(proxy, SIGNAL(tableMimeDataDropped(QWidget*, const QModelIndex&, const CSMWorld::UniversalId&, const CSMDoc::Document*)),
|
||||
this, SIGNAL(tableMimeDataDropped(QWidget*, const QModelIndex&, const CSMWorld::UniversalId&, const CSMDoc::Document*)));
|
||||
skip = true;
|
||||
}
|
||||
if(!skip && qobject_cast<QCheckBox*>(editor))
|
||||
{
|
||||
connect(editor, SIGNAL(stateChanged(int)), proxy, SLOT(editorDataCommited()));
|
||||
skip = true;
|
||||
}
|
||||
if(!skip && qobject_cast<QPlainTextEdit*>(editor))
|
||||
{
|
||||
connect(editor, SIGNAL(textChanged()), proxy, SLOT(editorDataCommited()));
|
||||
skip = true;
|
||||
}
|
||||
if(!skip && qobject_cast<QComboBox*>(editor))
|
||||
{
|
||||
connect(editor, SIGNAL(currentIndexChanged (int)), proxy, SLOT(editorDataCommited()));
|
||||
skip = true;
|
||||
}
|
||||
if(!skip && qobject_cast<QAbstractSpinBox*>(editor))
|
||||
{
|
||||
connect(editor, SIGNAL(editingFinished()), proxy, SLOT(editorDataCommited()));
|
||||
skip = true;
|
||||
}
|
||||
|
||||
connect(proxy, SIGNAL(editorDataCommited(QWidget*, const QModelIndex&, CSMWorld::ColumnBase::Display)), this, SLOT(editorDataCommited(QWidget*, const QModelIndex&, CSMWorld::ColumnBase::Display)));
|
||||
mProxys.push_back(proxy); //deleted in the destructor
|
||||
}
|
||||
return editor;
|
||||
}
|
||||
|
||||
CSVWorld::DialogueDelegateDispatcher::~DialogueDelegateDispatcher()
|
||||
{
|
||||
for (unsigned i = 0; i < mProxys.size(); ++i)
|
||||
{
|
||||
delete mProxys[i]; //unique_ptr could be handy
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
=============================================================EditWidget=====================================================
|
||||
*/
|
||||
|
||||
CSVWorld::EditWidget::EditWidget(QWidget *parent, int row, CSMWorld::IdTable* table, QUndoStack& undoStack, bool createAndDelete) :
|
||||
mDispatcher(this, table, undoStack),
|
||||
QScrollArea(parent),
|
||||
mWidgetMapper(NULL),
|
||||
mMainWidget(NULL),
|
||||
mUndoStack(undoStack),
|
||||
mTable(table)
|
||||
{
|
||||
remake (row);
|
||||
connect(&mDispatcher, SIGNAL(tableMimeDataDropped(QWidget*, const QModelIndex&, const CSMWorld::UniversalId&, const CSMDoc::Document*)), this, SIGNAL(tableMimeDataDropped(QWidget*, const QModelIndex&, const CSMWorld::UniversalId&, const CSMDoc::Document*)));
|
||||
}
|
||||
|
||||
void CSVWorld::EditWidget::remake(int row)
|
||||
{
|
||||
if (mMainWidget)
|
||||
{
|
||||
delete mMainWidget;
|
||||
}
|
||||
mMainWidget = new QWidget (this);
|
||||
|
||||
//not sure if widget mapper can handle deleting the widgets that were mapped
|
||||
if (mWidgetMapper)
|
||||
{
|
||||
delete mWidgetMapper;
|
||||
}
|
||||
mWidgetMapper = new QDataWidgetMapper (this);
|
||||
mWidgetMapper->setModel(mTable);
|
||||
mWidgetMapper->setItemDelegate(&mDispatcher);
|
||||
|
||||
QFrame* line = new QFrame(mMainWidget);
|
||||
line->setObjectName(QString::fromUtf8("line"));
|
||||
line->setGeometry(QRect(320, 150, 118, 3));
|
||||
line->setFrameShape(QFrame::HLine);
|
||||
line->setFrameShadow(QFrame::Sunken);
|
||||
|
||||
QVBoxLayout *mainLayout = new QVBoxLayout(mMainWidget);
|
||||
QGridLayout *unlockedLayout = new QGridLayout();
|
||||
QGridLayout *lockedLayout = new QGridLayout();
|
||||
mainLayout->addLayout(lockedLayout, 0);
|
||||
mainLayout->addWidget(line, 1);
|
||||
mainLayout->addLayout(unlockedLayout, 2);
|
||||
mainLayout->addStretch(1);
|
||||
|
||||
int unlocked = 0;
|
||||
int locked = 0;
|
||||
const int columns = mTable->columnCount();
|
||||
for (int i=0; i<columns; ++i)
|
||||
{
|
||||
int flags = mTable->headerData (i, Qt::Horizontal, CSMWorld::ColumnBase::Role_Flags).toInt();
|
||||
|
||||
if (flags & CSMWorld::ColumnBase::Flag_Dialogue)
|
||||
{
|
||||
CSMWorld::ColumnBase::Display display = static_cast<CSMWorld::ColumnBase::Display>
|
||||
(mTable->headerData (i, Qt::Horizontal, CSMWorld::ColumnBase::Role_Display).toInt());
|
||||
|
||||
mDispatcher.makeDelegate(display);
|
||||
QWidget *editor = mDispatcher.makeEditor(display, (mTable->index (row, i)));
|
||||
|
||||
if (editor)
|
||||
{
|
||||
mWidgetMapper->addMapping (editor, i);
|
||||
QLabel* label = new QLabel(mTable->headerData (i, Qt::Horizontal).toString(), mMainWidget);
|
||||
label->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
|
||||
editor->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed);
|
||||
if (! (mTable->flags (mTable->index (row, i)) & Qt::ItemIsEditable))
|
||||
{
|
||||
lockedLayout->addWidget (label, locked, 0);
|
||||
lockedLayout->addWidget (editor, locked, 1);
|
||||
++locked;
|
||||
} else
|
||||
{
|
||||
unlockedLayout->addWidget (label, unlocked, 0);
|
||||
unlockedLayout->addWidget (editor, unlocked, 1);
|
||||
++unlocked;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mWidgetMapper->setCurrentModelIndex(mTable->index(row, 0));
|
||||
|
||||
this->setMinimumWidth(325); //TODO find better way to set the width or make it customizable
|
||||
this->setWidget(mMainWidget);
|
||||
this->setWidgetResizable(true);
|
||||
}
|
||||
|
||||
/*
|
||||
==============================DialogueSubView==========================================
|
||||
*/
|
||||
|
||||
CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document,
|
||||
const CreatorFactoryBase& creatorFactory, bool sorting) :
|
||||
|
||||
SubView (id),
|
||||
mEditWidget(0),
|
||||
mMainLayout(NULL),
|
||||
mUndoStack(document.getUndoStack()),
|
||||
mTable(dynamic_cast<CSMWorld::IdTable*>(document.getData().getTableModel(id))),
|
||||
mRow (-1),
|
||||
mLocked(false),
|
||||
mDocument(document)
|
||||
|
||||
{
|
||||
connect(mTable, SIGNAL(dataChanged (const QModelIndex&, const QModelIndex&)), this, SLOT(dataChanged(const QModelIndex&)));
|
||||
mRow = mTable->getModelIndex (id.getId(), 0).row();
|
||||
QWidget *mainWidget = new QWidget(this);
|
||||
|
||||
QHBoxLayout *buttonsLayout = new QHBoxLayout;
|
||||
QToolButton* prevButton = new QToolButton(mainWidget);
|
||||
prevButton->setIcon(QIcon(":/go-previous.png"));
|
||||
QToolButton* nextButton = new QToolButton(mainWidget);
|
||||
nextButton->setIcon(QIcon(":/go-next.png"));
|
||||
buttonsLayout->addWidget(prevButton, 0);
|
||||
buttonsLayout->addWidget(nextButton, 1);
|
||||
buttonsLayout->addStretch(2);
|
||||
|
||||
QToolButton* cloneButton = new QToolButton(mainWidget);
|
||||
cloneButton->setIcon(QIcon(":/edit-clone.png"));
|
||||
QToolButton* addButton = new QToolButton(mainWidget);
|
||||
addButton->setIcon(QIcon(":/add.png"));
|
||||
QToolButton* deleteButton = new QToolButton(mainWidget);
|
||||
deleteButton->setIcon(QIcon(":/edit-delete.png"));
|
||||
QToolButton* revertButton = new QToolButton(mainWidget);
|
||||
revertButton->setIcon(QIcon(":/edit-undo.png"));
|
||||
|
||||
if (mTable->hasPreview())
|
||||
{
|
||||
QToolButton* previewButton = new QToolButton(mainWidget);
|
||||
previewButton->setIcon(QIcon(":/edit-preview.png"));
|
||||
buttonsLayout->addWidget(previewButton);
|
||||
connect(previewButton, SIGNAL(clicked()), this, SLOT(showPreview()));
|
||||
}
|
||||
|
||||
if (mTable->getViewing()!=CSMWorld::IdTable::Viewing_None)
|
||||
{
|
||||
QToolButton* viewButton = new QToolButton(mainWidget);
|
||||
viewButton->setIcon(QIcon(":/cell.png"));
|
||||
buttonsLayout->addWidget(viewButton);
|
||||
connect(viewButton, SIGNAL(clicked()), this, SLOT(viewRecord()));
|
||||
}
|
||||
|
||||
buttonsLayout->addWidget(cloneButton);
|
||||
buttonsLayout->addWidget(addButton);
|
||||
buttonsLayout->addWidget(deleteButton);
|
||||
buttonsLayout->addWidget(revertButton);
|
||||
|
||||
connect(nextButton, SIGNAL(clicked()), this, SLOT(nextId()));
|
||||
connect(prevButton, SIGNAL(clicked()), this, SLOT(prevId()));
|
||||
connect(cloneButton, SIGNAL(clicked()), this, SLOT(cloneRequest()));
|
||||
connect(revertButton, SIGNAL(clicked()), this, SLOT(revertRecord()));
|
||||
connect(deleteButton, SIGNAL(clicked()), this, SLOT(deleteRecord()));
|
||||
|
||||
mMainLayout = new QVBoxLayout(mainWidget);
|
||||
|
||||
mEditWidget = new EditWidget(mainWidget, mRow, mTable, mUndoStack, false);
|
||||
connect(mEditWidget, SIGNAL(tableMimeDataDropped(QWidget*, const QModelIndex&, const CSMWorld::UniversalId&, const CSMDoc::Document*)),
|
||||
this, SLOT(tableMimeDataDropped(QWidget*, const QModelIndex&, const CSMWorld::UniversalId&, const CSMDoc::Document*)));
|
||||
|
||||
mMainLayout->addWidget(mEditWidget);
|
||||
mEditWidget->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
|
||||
|
||||
mMainLayout->addWidget (mBottom =
|
||||
new TableBottomBox (creatorFactory, document.getData(), document.getUndoStack(), id, this));
|
||||
|
||||
mBottom->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Fixed);
|
||||
connect(mBottom, SIGNAL(requestFocus(const std::string&)), this, SLOT(requestFocus(const std::string&)));
|
||||
connect(addButton, SIGNAL(clicked()), mBottom, SLOT(createRequest()));
|
||||
|
||||
if(!mBottom->canCreateAndDelete())
|
||||
{
|
||||
cloneButton->setDisabled(true);
|
||||
addButton->setDisabled(true);
|
||||
deleteButton->setDisabled(true);
|
||||
}
|
||||
|
||||
dataChanged(mTable->index(mRow, 0));
|
||||
mMainLayout->addLayout(buttonsLayout);
|
||||
setWidget(mainWidget);
|
||||
}
|
||||
|
||||
void CSVWorld::DialogueSubView::prevId()
|
||||
{
|
||||
int newRow = mRow - 1;
|
||||
if (newRow < 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
while (newRow >= 0)
|
||||
{
|
||||
QModelIndex newIndex(mTable->index(newRow, 0));
|
||||
|
||||
if (!newIndex.isValid())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
CSMWorld::RecordBase::State state = static_cast<CSMWorld::RecordBase::State>(mTable->data (mTable->index (newRow, 1)).toInt());
|
||||
if (!(state == CSMWorld::RecordBase::State_Deleted || state == CSMWorld::RecordBase::State_Erased))
|
||||
{
|
||||
mEditWidget->remake(newRow);
|
||||
setUniversalId(CSMWorld::UniversalId (static_cast<CSMWorld::UniversalId::Type> (mTable->data (mTable->index (newRow, 2)).toInt()),
|
||||
mTable->data (mTable->index (newRow, 0)).toString().toStdString()));
|
||||
mRow = newRow;
|
||||
mEditWidget->setDisabled(mLocked);
|
||||
return;
|
||||
}
|
||||
--newRow;
|
||||
}
|
||||
}
|
||||
|
||||
void CSVWorld::DialogueSubView::nextId()
|
||||
{
|
||||
int newRow = mRow + 1;
|
||||
|
||||
if (newRow >= mTable->rowCount())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
while (newRow < mTable->rowCount())
|
||||
{
|
||||
QModelIndex newIndex(mTable->index(newRow, 0));
|
||||
|
||||
if (!newIndex.isValid())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
CSMWorld::RecordBase::State state = static_cast<CSMWorld::RecordBase::State>(mTable->data (mTable->index (newRow, 1)).toInt());
|
||||
if (!(state == CSMWorld::RecordBase::State_Deleted || state == CSMWorld::RecordBase::State_Erased))
|
||||
{
|
||||
mEditWidget->remake(newRow);
|
||||
setUniversalId(CSMWorld::UniversalId (static_cast<CSMWorld::UniversalId::Type> (mTable->data (mTable->index (newRow, 2)).toInt()),
|
||||
mTable->data (mTable->index (newRow, 0)).toString().toStdString()));
|
||||
mRow = newRow;
|
||||
mEditWidget->setDisabled(mLocked);
|
||||
return;
|
||||
}
|
||||
++newRow;
|
||||
}
|
||||
}
|
||||
|
||||
void CSVWorld::DialogueSubView::setEditLock (bool locked)
|
||||
{
|
||||
mLocked = locked;
|
||||
CSMWorld::RecordBase::State state = static_cast<CSMWorld::RecordBase::State>(mTable->data (mTable->index (mRow, 1)).toInt());
|
||||
if (state == CSMWorld::RecordBase::State_Deleted || state == CSMWorld::RecordBase::State_Erased)
|
||||
{
|
||||
mEditWidget->setDisabled(true);
|
||||
} else
|
||||
{
|
||||
mEditWidget->setDisabled(mLocked);
|
||||
}
|
||||
}
|
||||
|
||||
void CSVWorld::DialogueSubView::dataChanged(const QModelIndex & index)
|
||||
{
|
||||
if (index.row() == mRow)
|
||||
{
|
||||
CSMWorld::RecordBase::State state = static_cast<CSMWorld::RecordBase::State>(mTable->data (mTable->index (mRow, 1)).toInt());
|
||||
if (state == CSMWorld::RecordBase::State_Deleted || state == CSMWorld::RecordBase::State_Erased)
|
||||
{
|
||||
mEditWidget->setDisabled(true);
|
||||
} else
|
||||
{
|
||||
mEditWidget->setDisabled(mLocked);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CSVWorld::DialogueSubView::tableMimeDataDropped(QWidget* editor,
|
||||
const QModelIndex& index,
|
||||
const CSMWorld::UniversalId& id,
|
||||
const CSMDoc::Document* document)
|
||||
{
|
||||
if (document == &mDocument)
|
||||
{
|
||||
qobject_cast<DropLineEdit*>(editor)->setText(id.getId().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void CSVWorld::DialogueSubView::revertRecord()
|
||||
{
|
||||
int rows = mTable->rowCount();
|
||||
if (!mLocked && mTable->columnCount() > 0 && mRow < mTable->rowCount() )
|
||||
{
|
||||
CSMWorld::RecordBase::State state =
|
||||
static_cast<CSMWorld::RecordBase::State> (mTable->data (mTable->index (mRow, 1)).toInt());
|
||||
|
||||
if (state!=CSMWorld::RecordBase::State_BaseOnly)
|
||||
{
|
||||
mUndoStack.push(new CSMWorld::RevertCommand(*mTable, mTable->data(mTable->index (mRow, 0)).toString().toStdString()));
|
||||
}
|
||||
if (rows != mTable->rowCount())
|
||||
{
|
||||
if (mTable->rowCount() == 0)
|
||||
{
|
||||
mEditWidget->setDisabled(true); //closing the editor is other option
|
||||
return;
|
||||
}
|
||||
if (mRow >= mTable->rowCount())
|
||||
{
|
||||
prevId();
|
||||
} else {
|
||||
dataChanged(mTable->index(mRow, 0));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CSVWorld::DialogueSubView::deleteRecord()
|
||||
{
|
||||
int rows = mTable->rowCount();
|
||||
|
||||
//easier than disabling the button
|
||||
CSMWorld::RecordBase::State state = static_cast<CSMWorld::RecordBase::State>(mTable->data (mTable->index (mRow, 1)).toInt());
|
||||
bool deledetedOrErased = (state == CSMWorld::RecordBase::State_Deleted || state == CSMWorld::RecordBase::State_Erased);
|
||||
|
||||
if (!mLocked &&
|
||||
mTable->columnCount() > 0 &&
|
||||
!deledetedOrErased &&
|
||||
mRow < rows &&
|
||||
mBottom->canCreateAndDelete())
|
||||
{
|
||||
mUndoStack.push(new CSMWorld::DeleteCommand(*mTable, mTable->data(mTable->index (mRow, 0)).toString().toStdString()));
|
||||
if (rows != mTable->rowCount())
|
||||
{
|
||||
if (mTable->rowCount() == 0)
|
||||
{
|
||||
mEditWidget->setDisabled(true); //closing the editor is other option
|
||||
return;
|
||||
}
|
||||
if (mRow >= mTable->rowCount())
|
||||
{
|
||||
prevId();
|
||||
} else {
|
||||
dataChanged(mTable->index(mRow, 0));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CSVWorld::DialogueSubView::requestFocus (const std::string& id)
|
||||
{
|
||||
mRow = mTable->getModelIndex (id, 0).row();
|
||||
mEditWidget->remake(mRow);
|
||||
}
|
||||
|
||||
void CSVWorld::DialogueSubView::cloneRequest ()
|
||||
{
|
||||
mBottom->cloneRequest(mTable->data(mTable->index (mRow, 0)).toString().toStdString(),
|
||||
static_cast<CSMWorld::UniversalId::Type>(mTable->data(mTable->index(mRow, 2)).toInt()));
|
||||
}
|
||||
|
||||
void CSVWorld::DialogueSubView::showPreview ()
|
||||
{
|
||||
if (mTable->hasPreview() && mRow < mTable->rowCount())
|
||||
{
|
||||
emit focusId(CSMWorld::UniversalId(CSMWorld::UniversalId::Type_Preview, mTable->data(mTable->index (mRow, 0)).toString().toStdString()), "");
|
||||
}
|
||||
}
|
||||
|
||||
void CSVWorld::DialogueSubView::viewRecord()
|
||||
{
|
||||
if (mRow < mTable->rowCount())
|
||||
{
|
||||
std::pair<CSMWorld::UniversalId, std::string> params = mTable->view (mRow);
|
||||
|
||||
if (params.first.getType()!=CSMWorld::UniversalId::Type_None)
|
||||
emit focusId (params.first, params.second);
|
||||
}
|
||||
}
|
|
@ -1,9 +1,25 @@
|
|||
#ifndef CSV_WORLD_DIALOGUESUBVIEW_H
|
||||
#define CSV_WORLD_DIALOGUESUBVIEW_H
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
|
||||
#include <QAbstractItemDelegate>
|
||||
#include <QScrollArea>
|
||||
|
||||
#include "../doc/subview.hpp"
|
||||
#include "../../model/world/columnbase.hpp"
|
||||
|
||||
class QDataWidgetMapper;
|
||||
class QSize;
|
||||
class QEvent;
|
||||
class QLabel;
|
||||
class QVBoxLayout;
|
||||
|
||||
namespace CSMWorld
|
||||
{
|
||||
class IdTable;
|
||||
}
|
||||
|
||||
namespace CSMDoc
|
||||
{
|
||||
|
@ -12,15 +28,181 @@ namespace CSMDoc
|
|||
|
||||
namespace CSVWorld
|
||||
{
|
||||
class DialogueSubView : public CSVDoc::SubView
|
||||
class CommandDelegate;
|
||||
class CreatorFactoryBase;
|
||||
class TableBottomBox;
|
||||
|
||||
class NotEditableSubDelegate : public QAbstractItemDelegate
|
||||
{
|
||||
const CSMWorld::IdTable* mTable;
|
||||
public:
|
||||
NotEditableSubDelegate(const CSMWorld::IdTable* table, QObject * parent = 0);
|
||||
|
||||
virtual void setEditorData (QLabel* editor, const QModelIndex& index) const;
|
||||
|
||||
virtual void setModelData (QWidget* editor, QAbstractItemModel* model, const QModelIndex& index, CSMWorld::ColumnBase::Display display) const;
|
||||
|
||||
virtual void paint (QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const;
|
||||
///< does nothing
|
||||
|
||||
virtual QSize sizeHint (const QStyleOptionViewItem& option, const QModelIndex& index) const;
|
||||
///< does nothing
|
||||
|
||||
virtual QWidget *createEditor (QWidget *parent,
|
||||
const QStyleOptionViewItem& option,
|
||||
const QModelIndex& index,
|
||||
CSMWorld::ColumnBase::Display display = CSMWorld::ColumnBase::Display_None) const;
|
||||
};
|
||||
|
||||
//this can't be nested into the DialogueDelegateDispatcher, because it needs to emit signals
|
||||
class DialogueDelegateDispatcherProxy : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
class refWrapper
|
||||
{
|
||||
public:
|
||||
refWrapper(const QModelIndex& index);
|
||||
|
||||
const QModelIndex& mIndex;
|
||||
};
|
||||
|
||||
QWidget* mEditor;
|
||||
|
||||
CSMWorld::ColumnBase::Display mDisplay;
|
||||
|
||||
std::auto_ptr<refWrapper> mIndexWrapper;
|
||||
|
||||
public:
|
||||
DialogueDelegateDispatcherProxy(QWidget* editor, CSMWorld::ColumnBase::Display display);
|
||||
QWidget* getEditor() const;
|
||||
|
||||
public slots:
|
||||
void editorDataCommited();
|
||||
void setIndex(const QModelIndex& index);
|
||||
void tableMimeDataDropped(const std::vector<CSMWorld::UniversalId>& data, const CSMDoc::Document* document);
|
||||
|
||||
signals:
|
||||
void editorDataCommited(QWidget* editor, const QModelIndex& index, CSMWorld::ColumnBase::Display display);
|
||||
|
||||
void tableMimeDataDropped(QWidget* editor, const QModelIndex& index,
|
||||
const CSMWorld::UniversalId& id,
|
||||
const CSMDoc::Document* document);
|
||||
|
||||
};
|
||||
|
||||
class DialogueDelegateDispatcher : public QAbstractItemDelegate
|
||||
{
|
||||
Q_OBJECT
|
||||
std::map<int, CommandDelegate*> mDelegates;
|
||||
|
||||
QObject* mParent;
|
||||
|
||||
CSMWorld::IdTable* mTable;
|
||||
|
||||
QUndoStack& mUndoStack;
|
||||
|
||||
NotEditableSubDelegate mNotEditableDelegate;
|
||||
|
||||
std::vector<DialogueDelegateDispatcherProxy*> mProxys; //once we move to the C++11 we should use unique_ptr
|
||||
|
||||
public:
|
||||
DialogueDelegateDispatcher(QObject* parent, CSMWorld::IdTable* table, QUndoStack& undoStack);
|
||||
|
||||
~DialogueDelegateDispatcher();
|
||||
|
||||
CSVWorld::CommandDelegate* makeDelegate(CSMWorld::ColumnBase::Display display);
|
||||
|
||||
QWidget* makeEditor(CSMWorld::ColumnBase::Display display, const QModelIndex& index);
|
||||
///< will return null if delegate is not present, parent of the widget is same as for dispatcher itself
|
||||
|
||||
virtual void setEditorData (QWidget* editor, const QModelIndex& index) const;
|
||||
|
||||
virtual void setModelData (QWidget* editor, QAbstractItemModel* model, const QModelIndex& index, CSMWorld::ColumnBase::Display display) const;
|
||||
|
||||
virtual void paint (QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const;
|
||||
///< does nothing
|
||||
|
||||
virtual QSize sizeHint (const QStyleOptionViewItem& option, const QModelIndex& index) const;
|
||||
///< does nothing
|
||||
|
||||
private slots:
|
||||
void editorDataCommited(QWidget* editor, const QModelIndex& index, CSMWorld::ColumnBase::Display display);
|
||||
|
||||
signals:
|
||||
void tableMimeDataDropped(QWidget* editor, const QModelIndex& index,
|
||||
const CSMWorld::UniversalId& id,
|
||||
const CSMDoc::Document* document);
|
||||
|
||||
|
||||
};
|
||||
|
||||
class EditWidget : public QScrollArea
|
||||
{
|
||||
Q_OBJECT
|
||||
QDataWidgetMapper *mWidgetMapper;
|
||||
DialogueDelegateDispatcher mDispatcher;
|
||||
QWidget* mMainWidget;
|
||||
CSMWorld::IdTable* mTable;
|
||||
QUndoStack& mUndoStack;
|
||||
|
||||
public:
|
||||
|
||||
DialogueSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document, bool createAndDelete);
|
||||
EditWidget (QWidget *parent, int row, CSMWorld::IdTable* table, QUndoStack& undoStack, bool createAndDelete = false);
|
||||
|
||||
void remake(int row);
|
||||
|
||||
signals:
|
||||
void tableMimeDataDropped(QWidget* editor, const QModelIndex& index,
|
||||
const CSMWorld::UniversalId& id,
|
||||
const CSMDoc::Document* document);
|
||||
};
|
||||
|
||||
class DialogueSubView : public CSVDoc::SubView
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
EditWidget* mEditWidget;
|
||||
QVBoxLayout* mMainLayout;
|
||||
CSMWorld::IdTable* mTable;
|
||||
QUndoStack& mUndoStack;
|
||||
int mRow;
|
||||
bool mLocked;
|
||||
const CSMDoc::Document& mDocument;
|
||||
TableBottomBox* mBottom;
|
||||
|
||||
public:
|
||||
|
||||
DialogueSubView (const CSMWorld::UniversalId& id,
|
||||
CSMDoc::Document& document,
|
||||
const CreatorFactoryBase& creatorFactory,
|
||||
bool sorting = false);
|
||||
|
||||
virtual void setEditLock (bool locked);
|
||||
|
||||
private slots:
|
||||
|
||||
void nextId();
|
||||
|
||||
void prevId();
|
||||
|
||||
void showPreview();
|
||||
|
||||
void viewRecord();
|
||||
|
||||
void revertRecord();
|
||||
|
||||
void deleteRecord();
|
||||
|
||||
void cloneRequest();
|
||||
|
||||
void dataChanged(const QModelIndex & index);
|
||||
///\brief we need to care for deleting currently edited record
|
||||
|
||||
void tableMimeDataDropped(QWidget* editor, const QModelIndex& index,
|
||||
const CSMWorld::UniversalId& id,
|
||||
const CSMDoc::Document* document);
|
||||
|
||||
void requestFocus (const std::string& id);
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -41,10 +41,18 @@ CSVWorld::EnumDelegate::EnumDelegate (const std::vector<std::pair<int, QString>
|
|||
|
||||
}
|
||||
|
||||
QWidget *CSVWorld::EnumDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem& option,
|
||||
const QModelIndex& index) const
|
||||
QWidget *CSVWorld::EnumDelegate::createEditor(QWidget *parent,
|
||||
const QStyleOptionViewItem& option,
|
||||
const QModelIndex& index) const
|
||||
{
|
||||
if (!index.data().isValid())
|
||||
return createEditor(parent, option, index, CSMWorld::ColumnBase::Display_None);
|
||||
//overloading virtual functions is HARD
|
||||
}
|
||||
|
||||
QWidget *CSVWorld::EnumDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem& option,
|
||||
const QModelIndex& index, CSMWorld::ColumnBase::Display display) const
|
||||
{
|
||||
if (!index.data(Qt::EditRole).isValid() && !index.data(Qt::DisplayRole).isValid())
|
||||
return 0;
|
||||
|
||||
QComboBox *comboBox = new QComboBox (parent);
|
||||
|
@ -56,11 +64,22 @@ QWidget *CSVWorld::EnumDelegate::createEditor(QWidget *parent, const QStyleOptio
|
|||
return comboBox;
|
||||
}
|
||||
|
||||
void CSVWorld::EnumDelegate::setEditorData (QWidget *editor, const QModelIndex& index) const
|
||||
void CSVWorld::EnumDelegate::setEditorData (QWidget *editor, const QModelIndex& index, bool tryDisplay) const
|
||||
{
|
||||
if (QComboBox *comboBox = dynamic_cast<QComboBox *> (editor))
|
||||
{
|
||||
int value = index.data (Qt::EditRole).toInt();
|
||||
QVariant data = index.data (Qt::EditRole);
|
||||
|
||||
if (tryDisplay && !data.isValid())
|
||||
{
|
||||
data = index.data (Qt::DisplayRole);
|
||||
if (!data.isValid())
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
int value = data.toInt();
|
||||
|
||||
std::size_t size = mValues.size();
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include <vector>
|
||||
|
||||
#include <QString>
|
||||
#include <QStyledItemDelegate>
|
||||
|
||||
#include <components/esm/defs.hpp>
|
||||
|
||||
|
@ -31,10 +32,16 @@ namespace CSVWorld
|
|||
EnumDelegate (const std::vector<std::pair<int, QString> >& values,
|
||||
QUndoStack& undoStack, QObject *parent);
|
||||
|
||||
virtual QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem& option,
|
||||
const QModelIndex& index) const;
|
||||
virtual QWidget *createEditor(QWidget *parent,
|
||||
const QStyleOptionViewItem& option,
|
||||
const QModelIndex& index) const;
|
||||
|
||||
virtual void setEditorData (QWidget *editor, const QModelIndex& index) const;
|
||||
virtual QWidget *createEditor(QWidget *parent,
|
||||
const QStyleOptionViewItem& option,
|
||||
const QModelIndex& index,
|
||||
CSMWorld::ColumnBase::Display display = CSMWorld::ColumnBase::Display_None) const;
|
||||
|
||||
virtual void setEditorData (QWidget *editor, const QModelIndex& index, bool tryDisplay = false) const;
|
||||
|
||||
virtual void paint (QPainter *painter, const QStyleOptionViewItem& option,
|
||||
const QModelIndex& index) const;
|
||||
|
|
|
@ -80,5 +80,61 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager)
|
|||
|
||||
manager.add (CSMWorld::UniversalId::Type_Scene, new CSVDoc::SubViewFactory<SceneSubView>);
|
||||
|
||||
//edit subviews
|
||||
manager.add (CSMWorld::UniversalId::Type_Region,
|
||||
new CSVDoc::SubViewFactoryWithCreator<DialogueSubView, CreatorFactory<GenericCreator> > (false));
|
||||
|
||||
manager.add (CSMWorld::UniversalId::Type_Spell,
|
||||
new CSVDoc::SubViewFactoryWithCreator<DialogueSubView, CreatorFactory<GenericCreator> > (false));
|
||||
|
||||
manager.add (CSMWorld::UniversalId::Type_Referenceable,
|
||||
new CSVDoc::SubViewFactoryWithCreator<DialogueSubView, CreatorFactory<ReferenceableCreator> > (false));
|
||||
|
||||
manager.add (CSMWorld::UniversalId::Type_Birthsign,
|
||||
new CSVDoc::SubViewFactoryWithCreator<DialogueSubView, CreatorFactory<GenericCreator> > (false));
|
||||
|
||||
manager.add (CSMWorld::UniversalId::Type_Global,
|
||||
new CSVDoc::SubViewFactoryWithCreator<DialogueSubView, CreatorFactory<GenericCreator> > (false));
|
||||
|
||||
manager.add (CSMWorld::UniversalId::Type_Gmst,
|
||||
new CSVDoc::SubViewFactoryWithCreator<DialogueSubView, CreatorFactory<GenericCreator> > (false));
|
||||
|
||||
manager.add (CSMWorld::UniversalId::Type_Race,
|
||||
new CSVDoc::SubViewFactoryWithCreator<DialogueSubView, CreatorFactory<GenericCreator> > (false));
|
||||
|
||||
manager.add (CSMWorld::UniversalId::Type_Class,
|
||||
new CSVDoc::SubViewFactoryWithCreator<DialogueSubView, CreatorFactory<GenericCreator> > (false));
|
||||
|
||||
manager.add (CSMWorld::UniversalId::Type_Reference,
|
||||
new CSVDoc::SubViewFactoryWithCreator<DialogueSubView, CreatorFactory<ReferenceCreator> > (false));
|
||||
|
||||
manager.add (CSMWorld::UniversalId::Type_Cell,
|
||||
new CSVDoc::SubViewFactoryWithCreator<DialogueSubView, CreatorFactory<CellCreator> > (false));
|
||||
|
||||
manager.add (CSMWorld::UniversalId::Type_Filter,
|
||||
new CSVDoc::SubViewFactoryWithCreator<DialogueSubView, CreatorFactory<GenericCreator> > (false));
|
||||
|
||||
manager.add (CSMWorld::UniversalId::Type_Sound,
|
||||
new CSVDoc::SubViewFactoryWithCreator<DialogueSubView, CreatorFactory<GenericCreator> > (false));
|
||||
|
||||
manager.add (CSMWorld::UniversalId::Type_Faction,
|
||||
new CSVDoc::SubViewFactoryWithCreator<DialogueSubView, CreatorFactory<GenericCreator> > (false));
|
||||
|
||||
manager.add (CSMWorld::UniversalId::Type_Skill,
|
||||
new CSVDoc::SubViewFactoryWithCreator<DialogueSubView, CreatorFactory<GenericCreator> > (false));
|
||||
|
||||
manager.add (CSMWorld::UniversalId::Type_JournalInfo,
|
||||
new CSVDoc::SubViewFactoryWithCreator<DialogueSubView, CreatorFactory<InfoCreator> > (false));
|
||||
|
||||
manager.add (CSMWorld::UniversalId::Type_TopicInfo,
|
||||
new CSVDoc::SubViewFactoryWithCreator<DialogueSubView, CreatorFactory<InfoCreator> >(false));
|
||||
|
||||
manager.add (CSMWorld::UniversalId::Type_Topic,
|
||||
new CSVDoc::SubViewFactoryWithCreator<DialogueSubView, TopicCreatorFactory> (false));
|
||||
|
||||
manager.add (CSMWorld::UniversalId::Type_Journal,
|
||||
new CSVDoc::SubViewFactoryWithCreator<DialogueSubView, JournalCreatorFactory> (false));
|
||||
|
||||
//preview
|
||||
manager.add (CSMWorld::UniversalId::Type_Preview, new CSVDoc::SubViewFactory<PreviewSubView>);
|
||||
}
|
|
@ -442,6 +442,7 @@ void CSVWorld::Table::previewRecord()
|
|||
emit editRequest (CSMWorld::UniversalId (CSMWorld::UniversalId::Type_Preview, id) , "");
|
||||
}
|
||||
}
|
||||
|
||||
void CSVWorld::Table::updateEditorSetting (const QString &settingName, const QString &settingValue)
|
||||
{
|
||||
int columns = mModel->columnCount();
|
||||
|
@ -533,27 +534,14 @@ void CSVWorld::Table::mouseMoveEvent (QMouseEvent* event)
|
|||
|
||||
drag->setMimeData (mime);
|
||||
drag->setPixmap (QString::fromStdString (mime->getIcon()));
|
||||
|
||||
Qt::DropActions action = Qt::IgnoreAction;
|
||||
switch (QApplication::keyboardModifiers())
|
||||
{
|
||||
case Qt::ControlModifier:
|
||||
action = Qt::CopyAction;
|
||||
break;
|
||||
|
||||
case Qt::ShiftModifier:
|
||||
action = Qt::MoveAction;
|
||||
break;
|
||||
}
|
||||
|
||||
drag->exec(action);
|
||||
drag->exec(Qt::CopyAction);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void CSVWorld::Table::dragEnterEvent(QDragEnterEvent *event)
|
||||
{
|
||||
event->acceptProposedAction();
|
||||
event->acceptProposedAction();
|
||||
}
|
||||
|
||||
void CSVWorld::Table::dropEvent(QDropEvent *event)
|
||||
|
@ -585,7 +573,7 @@ void CSVWorld::Table::dropEvent(QDropEvent *event)
|
|||
|
||||
void CSVWorld::Table::dragMoveEvent(QDragMoveEvent *event)
|
||||
{
|
||||
event->accept();
|
||||
event->accept();
|
||||
}
|
||||
|
||||
std::vector<std::string> CSVWorld::Table::getColumnsWithDisplay(CSMWorld::ColumnBase::Display display) const
|
||||
|
|
|
@ -4,8 +4,18 @@
|
|||
#include <stdexcept>
|
||||
|
||||
#include <QUndoStack>
|
||||
#include <QMetaProperty>
|
||||
#include <QStyledItemDelegate>
|
||||
#include <QLineEdit>
|
||||
#include <QSpinBox>
|
||||
#include <QDoubleSpinBox>
|
||||
#include <QComboBox>
|
||||
#include <QCheckBox>
|
||||
#include <QPlainTextEdit>
|
||||
#include <QEvent>
|
||||
|
||||
#include "../../model/world/commands.hpp"
|
||||
#include "../../model/world/tablemimedata.hpp"
|
||||
|
||||
CSVWorld::NastyTableModelHack::NastyTableModelHack (QAbstractItemModel& model)
|
||||
: mModel (model)
|
||||
|
@ -117,10 +127,56 @@ void CSVWorld::CommandDelegate::setModelData (QWidget *editor, QAbstractItemMode
|
|||
}
|
||||
|
||||
QWidget *CSVWorld::CommandDelegate::createEditor (QWidget *parent, const QStyleOptionViewItem& option,
|
||||
const QModelIndex& index) const
|
||||
const QModelIndex& index, CSMWorld::ColumnBase::Display display) const
|
||||
{
|
||||
if (!index.data().isValid())
|
||||
return 0;
|
||||
QVariant variant = index.data();
|
||||
if (!variant.isValid())
|
||||
{
|
||||
variant = index.data(Qt::DisplayRole);
|
||||
if (!variant.isValid())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (display != CSMWorld::ColumnBase::Display_None)
|
||||
{
|
||||
if (variant.type() == QVariant::Color)
|
||||
{
|
||||
return new QLineEdit(parent);
|
||||
}
|
||||
if (display == CSMWorld::ColumnBase::Display_Integer)
|
||||
{
|
||||
return new QSpinBox(parent);
|
||||
}
|
||||
if (display == CSMWorld::ColumnBase::Display_Var)
|
||||
{
|
||||
return new QLineEdit(parent);
|
||||
}
|
||||
if (display == CSMWorld::ColumnBase::Display_Float)
|
||||
{
|
||||
return new QDoubleSpinBox(parent);
|
||||
}
|
||||
if (display == CSMWorld::ColumnBase::Display_LongString)
|
||||
{
|
||||
return new QTextEdit(parent);
|
||||
}
|
||||
if (display == CSMWorld::ColumnBase::Display_String ||
|
||||
display == CSMWorld::ColumnBase::Display_Skill ||
|
||||
display == CSMWorld::ColumnBase::Display_Script ||
|
||||
display == CSMWorld::ColumnBase::Display_Race ||
|
||||
display == CSMWorld::ColumnBase::Display_Class ||
|
||||
display == CSMWorld::ColumnBase::Display_Faction ||
|
||||
display == CSMWorld::ColumnBase::Display_Miscellaneous ||
|
||||
display == CSMWorld::ColumnBase::Display_Sound)
|
||||
{
|
||||
return new DropLineEdit(parent);
|
||||
}
|
||||
if (display == CSMWorld::ColumnBase::Display_Boolean)
|
||||
{
|
||||
return new QCheckBox(parent);
|
||||
}
|
||||
}
|
||||
|
||||
return QStyledItemDelegate::createEditor (parent, option, index);
|
||||
}
|
||||
|
@ -140,4 +196,67 @@ bool CSVWorld::CommandDelegate::updateEditorSetting (const QString &settingName,
|
|||
const QString &settingValue)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void CSVWorld::CommandDelegate::setEditorData (QWidget *editor, const QModelIndex& index, bool tryDisplay) const
|
||||
{
|
||||
QVariant v = index.data(Qt::EditRole);
|
||||
if (tryDisplay)
|
||||
{
|
||||
if (!v.isValid())
|
||||
{
|
||||
v = index.data(Qt::DisplayRole);
|
||||
if (!v.isValid())
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
QPlainTextEdit* plainTextEdit = qobject_cast<QPlainTextEdit*>(editor);
|
||||
if(plainTextEdit) //for some reason it is easier to brake the loop here
|
||||
{
|
||||
if(plainTextEdit->toPlainText() == v.toString())
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QByteArray n = editor->metaObject()->userProperty().name();
|
||||
|
||||
if (n == "dateTime") {
|
||||
if (editor->inherits("QTimeEdit"))
|
||||
n = "time";
|
||||
else if (editor->inherits("QDateEdit"))
|
||||
n = "date";
|
||||
}
|
||||
|
||||
if (!n.isEmpty()) {
|
||||
if (!v.isValid())
|
||||
v = QVariant(editor->property(n).userType(), (const void *)0);
|
||||
editor->setProperty(n, v);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
CSVWorld::DropLineEdit::DropLineEdit(QWidget* parent) :
|
||||
QLineEdit(parent)
|
||||
{
|
||||
setAcceptDrops(true);
|
||||
}
|
||||
|
||||
void CSVWorld::DropLineEdit::dragEnterEvent(QDragEnterEvent *event)
|
||||
{
|
||||
event->acceptProposedAction();
|
||||
}
|
||||
|
||||
void CSVWorld::DropLineEdit::dragMoveEvent(QDragMoveEvent *event)
|
||||
{
|
||||
event->accept();
|
||||
}
|
||||
|
||||
void CSVWorld::DropLineEdit::dropEvent(QDropEvent *event)
|
||||
{
|
||||
const CSMWorld::TableMimeData* data(dynamic_cast<const CSMWorld::TableMimeData*>(event->mimeData()));
|
||||
emit tableMimeDataDropped(data->getData(), data->getDocumentPtr());
|
||||
//WIP
|
||||
}
|
|
@ -5,11 +5,19 @@
|
|||
|
||||
#include <QAbstractTableModel>
|
||||
#include <QStyledItemDelegate>
|
||||
#include <QLineEdit>
|
||||
|
||||
#include "../../model/world/columnbase.hpp"
|
||||
#include "../../model/doc/document.hpp"
|
||||
|
||||
class QUndoStack;
|
||||
|
||||
namespace CSMWorld
|
||||
{
|
||||
class TableMimeData;
|
||||
class UniversalId;
|
||||
}
|
||||
|
||||
namespace CSVWorld
|
||||
{
|
||||
///< \brief Getting the data out of an editor widget
|
||||
|
@ -79,6 +87,24 @@ namespace CSVWorld
|
|||
|
||||
};
|
||||
|
||||
class DropLineEdit : public QLineEdit
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
DropLineEdit(QWidget *parent);
|
||||
|
||||
private:
|
||||
void dragEnterEvent(QDragEnterEvent *event);
|
||||
|
||||
void dragMoveEvent(QDragMoveEvent *event);
|
||||
|
||||
void dropEvent(QDropEvent *event);
|
||||
|
||||
signals:
|
||||
void tableMimeDataDropped(const std::vector<CSMWorld::UniversalId>& data, const CSMDoc::Document* document);
|
||||
};
|
||||
|
||||
///< \brief Use commands instead of manipulating the model directly
|
||||
class CommandDelegate : public QStyledItemDelegate
|
||||
{
|
||||
|
@ -101,8 +127,10 @@ namespace CSVWorld
|
|||
virtual void setModelData (QWidget *editor, QAbstractItemModel *model,
|
||||
const QModelIndex& index) const;
|
||||
|
||||
virtual QWidget *createEditor (QWidget *parent, const QStyleOptionViewItem& option,
|
||||
const QModelIndex& index) const;
|
||||
virtual QWidget *createEditor (QWidget *parent,
|
||||
const QStyleOptionViewItem& option,
|
||||
const QModelIndex& index,
|
||||
CSMWorld::ColumnBase::Display display = CSMWorld::ColumnBase::Display_None) const;
|
||||
|
||||
void setEditLock (bool locked);
|
||||
|
||||
|
@ -111,6 +139,9 @@ namespace CSVWorld
|
|||
virtual bool updateEditorSetting (const QString &settingName, const QString &settingValue);
|
||||
///< \return Does column require update?
|
||||
|
||||
virtual void setEditorData (QWidget *editor, const QModelIndex& index, bool tryDisplay = false) const;
|
||||
|
||||
|
||||
private slots:
|
||||
|
||||
virtual void slotUpdateEditorSetting (const QString &settingName, const QString &settingValue) {}
|
||||
|
|
|
@ -15,7 +15,7 @@ add_openmw_dir (mwrender
|
|||
renderingmanager debugging sky camera animation npcanimation creatureanimation activatoranimation
|
||||
actors objects renderinginterface localmap occlusionquery water shadows
|
||||
characterpreview globalmap videoplayer ripplesimulation refraction
|
||||
terrainstorage renderconst effectmanager
|
||||
terrainstorage renderconst effectmanager weaponanimation
|
||||
)
|
||||
|
||||
add_openmw_dir (mwinput
|
||||
|
@ -44,7 +44,7 @@ add_openmw_dir (mwscript
|
|||
locals scriptmanagerimp compilercontext interpretercontext cellextensions miscextensions
|
||||
guiextensions soundextensions skyextensions statsextensions containerextensions
|
||||
aiextensions controlextensions extensions globalscripts ref dialogueextensions
|
||||
animationextensions transformationextensions consoleextensions userextensions locals
|
||||
animationextensions transformationextensions consoleextensions userextensions
|
||||
)
|
||||
|
||||
add_openmw_dir (mwsound
|
||||
|
|
|
@ -359,7 +359,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
|
|||
// Create the world
|
||||
mEnvironment.setWorld( new MWWorld::World (*mOgre, mFileCollections, mContentFiles,
|
||||
mResDir, mCfgMgr.getCachePath(), mEncoder, mFallbackMap,
|
||||
mActivationDistanceOverride));
|
||||
mActivationDistanceOverride, mCellName));
|
||||
MWBase::Environment::get().getWorld()->setupPlayer();
|
||||
input->setPlayer(&mEnvironment.getWorld()->getPlayer());
|
||||
|
||||
|
@ -395,31 +395,6 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
|
|||
mechanics->buildPlayer();
|
||||
window->updatePlayer();
|
||||
|
||||
// load cell
|
||||
ESM::Position pos;
|
||||
MWBase::World *world = MWBase::Environment::get().getWorld();
|
||||
|
||||
if (!mCellName.empty())
|
||||
{
|
||||
if (world->findExteriorPosition(mCellName, pos)) {
|
||||
world->changeToExteriorCell (pos);
|
||||
}
|
||||
else {
|
||||
world->findInteriorPosition(mCellName, pos);
|
||||
world->changeToInteriorCell (mCellName, pos);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pos.pos[0] = pos.pos[1] = pos.pos[2] = 0;
|
||||
pos.rot[0] = pos.rot[1] = pos.rot[2] = 0;
|
||||
world->changeToExteriorCell (pos);
|
||||
}
|
||||
|
||||
Ogre::FrameEvent event;
|
||||
event.timeSinceLastEvent = 0;
|
||||
event.timeSinceLastFrame = 0;
|
||||
frameRenderingQueued(event);
|
||||
mOgre->getRoot()->addFrameListener (this);
|
||||
|
||||
// scripts
|
||||
|
@ -457,15 +432,15 @@ void OMW::Engine::go()
|
|||
// Play some good 'ol tunes
|
||||
MWBase::Environment::get().getSoundManager()->playPlaylist(std::string("Explore"));
|
||||
|
||||
if (!mStartupScript.empty())
|
||||
MWBase::Environment::get().getWindowManager()->executeInConsole (mStartupScript);
|
||||
|
||||
// start in main menu
|
||||
if (!mSkipMenu)
|
||||
MWBase::Environment::get().getWindowManager()->pushGuiMode (MWGui::GM_MainMenu);
|
||||
else
|
||||
MWBase::Environment::get().getStateManager()->newGame (true);
|
||||
|
||||
if (!mStartupScript.empty())
|
||||
MWBase::Environment::get().getWindowManager()->executeInConsole (mStartupScript);
|
||||
|
||||
// Start the main rendering loop
|
||||
while (!mEnvironment.get().getStateManager()->hasQuitRequest())
|
||||
Ogre::Root::getSingleton().renderOneFrame();
|
||||
|
|
|
@ -20,6 +20,9 @@ namespace MWBase
|
|||
|
||||
InputManager() {}
|
||||
|
||||
/// Clear all savegame-specific data
|
||||
virtual void clear() = 0;
|
||||
|
||||
virtual ~InputManager() {}
|
||||
|
||||
virtual void update(float dt, bool loading) = 0;
|
||||
|
|
|
@ -101,7 +101,8 @@ namespace MWBase
|
|||
|
||||
virtual ~World() {}
|
||||
|
||||
virtual void startNewGame() = 0;
|
||||
virtual void startNewGame (bool bypass) = 0;
|
||||
///< \param bypass Bypass regular game start.
|
||||
|
||||
virtual void clear() = 0;
|
||||
|
||||
|
|
|
@ -28,16 +28,16 @@
|
|||
|
||||
namespace
|
||||
{
|
||||
struct CustomData : public MWWorld::CustomData
|
||||
struct ContainerCustomData : public MWWorld::CustomData
|
||||
{
|
||||
MWWorld::ContainerStore mContainerStore;
|
||||
|
||||
virtual MWWorld::CustomData *clone() const;
|
||||
};
|
||||
|
||||
MWWorld::CustomData *CustomData::clone() const
|
||||
MWWorld::CustomData *ContainerCustomData::clone() const
|
||||
{
|
||||
return new CustomData (*this);
|
||||
return new ContainerCustomData (*this);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -47,7 +47,7 @@ namespace MWClass
|
|||
{
|
||||
if (!ptr.getRefData().getCustomData())
|
||||
{
|
||||
std::auto_ptr<CustomData> data (new CustomData);
|
||||
std::auto_ptr<ContainerCustomData> data (new ContainerCustomData);
|
||||
|
||||
MWWorld::LiveCellRef<ESM::Container> *ref =
|
||||
ptr.get<ESM::Container>();
|
||||
|
@ -174,7 +174,7 @@ namespace MWClass
|
|||
{
|
||||
ensureCustomData (ptr);
|
||||
|
||||
return dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData()).mContainerStore;
|
||||
return dynamic_cast<ContainerCustomData&> (*ptr.getRefData().getCustomData()).mContainerStore;
|
||||
}
|
||||
|
||||
std::string Container::getScript (const MWWorld::Ptr& ptr) const
|
||||
|
@ -267,7 +267,7 @@ namespace MWClass
|
|||
|
||||
ensureCustomData (ptr);
|
||||
|
||||
dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData()).mContainerStore.
|
||||
dynamic_cast<ContainerCustomData&> (*ptr.getRefData().getCustomData()).mContainerStore.
|
||||
readState (state2.mInventory);
|
||||
}
|
||||
|
||||
|
@ -278,7 +278,7 @@ namespace MWClass
|
|||
|
||||
ensureCustomData (ptr);
|
||||
|
||||
dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData()).mContainerStore.
|
||||
dynamic_cast<ContainerCustomData&> (*ptr.getRefData().getCustomData()).mContainerStore.
|
||||
writeState (state2.mInventory);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,7 +37,7 @@
|
|||
|
||||
namespace
|
||||
{
|
||||
struct CustomData : public MWWorld::CustomData
|
||||
struct CreatureCustomData : public MWWorld::CustomData
|
||||
{
|
||||
MWMechanics::CreatureStats mCreatureStats;
|
||||
MWWorld::ContainerStore* mContainerStore; // may be InventoryStore for some creatures
|
||||
|
@ -45,13 +45,13 @@ namespace
|
|||
|
||||
virtual MWWorld::CustomData *clone() const;
|
||||
|
||||
CustomData() : mContainerStore(0) {}
|
||||
virtual ~CustomData() { delete mContainerStore; }
|
||||
CreatureCustomData() : mContainerStore(0) {}
|
||||
virtual ~CreatureCustomData() { delete mContainerStore; }
|
||||
};
|
||||
|
||||
MWWorld::CustomData *CustomData::clone() const
|
||||
MWWorld::CustomData *CreatureCustomData::clone() const
|
||||
{
|
||||
CustomData* cloned = new CustomData (*this);
|
||||
CreatureCustomData* cloned = new CreatureCustomData (*this);
|
||||
cloned->mContainerStore = mContainerStore->clone();
|
||||
return cloned;
|
||||
}
|
||||
|
@ -63,7 +63,7 @@ namespace MWClass
|
|||
{
|
||||
if (!ptr.getRefData().getCustomData())
|
||||
{
|
||||
std::auto_ptr<CustomData> data (new CustomData);
|
||||
std::auto_ptr<CreatureCustomData> data (new CreatureCustomData);
|
||||
|
||||
static bool inited = false;
|
||||
if(!inited)
|
||||
|
@ -192,7 +192,7 @@ namespace MWClass
|
|||
{
|
||||
ensureCustomData (ptr);
|
||||
|
||||
return dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData()).mCreatureStats;
|
||||
return dynamic_cast<CreatureCustomData&> (*ptr.getRefData().getCustomData()).mCreatureStats;
|
||||
}
|
||||
|
||||
|
||||
|
@ -456,7 +456,7 @@ namespace MWClass
|
|||
{
|
||||
ensureCustomData (ptr);
|
||||
|
||||
return *dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData()).mContainerStore;
|
||||
return *dynamic_cast<CreatureCustomData&> (*ptr.getRefData().getCustomData()).mContainerStore;
|
||||
}
|
||||
|
||||
MWWorld::InventoryStore& Creature::getInventoryStore(const MWWorld::Ptr &ptr) const
|
||||
|
@ -525,7 +525,7 @@ namespace MWClass
|
|||
float moveSpeed;
|
||||
if(normalizedEncumbrance >= 1.0f)
|
||||
moveSpeed = 0.0f;
|
||||
else if(isFlying(ptr) || (mageffects.get(ESM::MagicEffect::Levitate).mMagnitude > 0 &&
|
||||
else if(canFly(ptr) || (mageffects.get(ESM::MagicEffect::Levitate).mMagnitude > 0 &&
|
||||
world->isLevitationEnabled()))
|
||||
{
|
||||
float flySpeed = 0.01f*(stats.getAttribute(ESM::Attribute::Speed).getModified() +
|
||||
|
@ -559,7 +559,7 @@ namespace MWClass
|
|||
{
|
||||
ensureCustomData (ptr);
|
||||
|
||||
return dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData()).mMovement;
|
||||
return dynamic_cast<CreatureCustomData&> (*ptr.getRefData().getCustomData()).mMovement;
|
||||
}
|
||||
|
||||
Ogre::Vector3 Creature::getMovementVector (const MWWorld::Ptr& ptr) const
|
||||
|
@ -678,7 +678,15 @@ namespace MWClass
|
|||
return MWWorld::Ptr(&cell.get<ESM::Creature>().insert(*ref), &cell);
|
||||
}
|
||||
|
||||
bool Creature::isFlying(const MWWorld::Ptr &ptr) const
|
||||
bool Creature::isBipedal(const MWWorld::Ptr &ptr) const
|
||||
{
|
||||
MWWorld::LiveCellRef<ESM::Creature> *ref =
|
||||
ptr.get<ESM::Creature>();
|
||||
|
||||
return ref->mBase->mFlags & ESM::Creature::Bipedal;
|
||||
}
|
||||
|
||||
bool Creature::canFly(const MWWorld::Ptr &ptr) const
|
||||
{
|
||||
MWWorld::LiveCellRef<ESM::Creature> *ref =
|
||||
ptr.get<ESM::Creature>();
|
||||
|
@ -686,6 +694,22 @@ namespace MWClass
|
|||
return ref->mBase->mFlags & ESM::Creature::Flies;
|
||||
}
|
||||
|
||||
bool Creature::canSwim(const MWWorld::Ptr &ptr) const
|
||||
{
|
||||
MWWorld::LiveCellRef<ESM::Creature> *ref =
|
||||
ptr.get<ESM::Creature>();
|
||||
|
||||
return ref->mBase->mFlags & ESM::Creature::Swims;
|
||||
}
|
||||
|
||||
bool Creature::canWalk(const MWWorld::Ptr &ptr) const
|
||||
{
|
||||
MWWorld::LiveCellRef<ESM::Creature> *ref =
|
||||
ptr.get<ESM::Creature>();
|
||||
|
||||
return ref->mBase->mFlags & ESM::Creature::Walks;
|
||||
}
|
||||
|
||||
int Creature::getSndGenTypeFromName(const MWWorld::Ptr &ptr, const std::string &name)
|
||||
{
|
||||
if(name == "left")
|
||||
|
@ -762,7 +786,7 @@ namespace MWClass
|
|||
|
||||
ensureCustomData (ptr);
|
||||
|
||||
CustomData& customData = dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData());
|
||||
CreatureCustomData& customData = dynamic_cast<CreatureCustomData&> (*ptr.getRefData().getCustomData());
|
||||
|
||||
customData.mContainerStore->readState (state2.mInventory);
|
||||
customData.mCreatureStats.readState (state2.mCreatureStats);
|
||||
|
@ -776,7 +800,7 @@ namespace MWClass
|
|||
|
||||
ensureCustomData (ptr);
|
||||
|
||||
CustomData& customData = dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData());
|
||||
CreatureCustomData& customData = dynamic_cast<CreatureCustomData&> (*ptr.getRefData().getCustomData());
|
||||
|
||||
customData.mContainerStore->writeState (state2.mInventory);
|
||||
customData.mCreatureStats.writeState (state2.mCreatureStats);
|
||||
|
|
|
@ -124,7 +124,10 @@ namespace MWClass
|
|||
return true;
|
||||
}
|
||||
|
||||
virtual bool isFlying (const MWWorld::Ptr &ptr) const;
|
||||
virtual bool isBipedal (const MWWorld::Ptr &ptr) const;
|
||||
virtual bool canFly (const MWWorld::Ptr &ptr) const;
|
||||
virtual bool canSwim (const MWWorld::Ptr &ptr) const;
|
||||
virtual bool canWalk (const MWWorld::Ptr &ptr) const;
|
||||
|
||||
virtual int getSkill(const MWWorld::Ptr &ptr, int skill) const;
|
||||
|
||||
|
|
|
@ -9,15 +9,15 @@
|
|||
|
||||
namespace
|
||||
{
|
||||
struct CustomData : public MWWorld::CustomData
|
||||
struct CreatureLevListCustomData : public MWWorld::CustomData
|
||||
{
|
||||
// TODO: save the creature we spawned here
|
||||
virtual MWWorld::CustomData *clone() const;
|
||||
};
|
||||
|
||||
MWWorld::CustomData *CustomData::clone() const
|
||||
MWWorld::CustomData *CreatureLevListCustomData::clone() const
|
||||
{
|
||||
return new CustomData (*this);
|
||||
return new CreatureLevListCustomData (*this);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -44,7 +44,7 @@ namespace MWClass
|
|||
{
|
||||
if (!ptr.getRefData().getCustomData())
|
||||
{
|
||||
std::auto_ptr<CustomData> data (new CustomData);
|
||||
std::auto_ptr<CreatureLevListCustomData> data (new CreatureLevListCustomData);
|
||||
|
||||
MWWorld::LiveCellRef<ESM::CreatureLevList> *ref =
|
||||
ptr.get<ESM::CreatureLevList>();
|
||||
|
|
|
@ -26,12 +26,12 @@
|
|||
|
||||
namespace
|
||||
{
|
||||
struct CustomData : public MWWorld::CustomData
|
||||
struct LightCustomData : public MWWorld::CustomData
|
||||
{
|
||||
float mTime;
|
||||
///< Time remaining
|
||||
|
||||
CustomData(MWWorld::Ptr ptr)
|
||||
LightCustomData(MWWorld::Ptr ptr)
|
||||
{
|
||||
MWWorld::LiveCellRef<ESM::Light> *ref = ptr.get<ESM::Light>();
|
||||
mTime = ref->mBase->mData.mTime;
|
||||
|
@ -40,7 +40,7 @@ namespace
|
|||
|
||||
virtual MWWorld::CustomData *clone() const
|
||||
{
|
||||
return new CustomData (*this);
|
||||
return new LightCustomData (*this);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -210,7 +210,7 @@ namespace MWClass
|
|||
{
|
||||
ensureCustomData(ptr);
|
||||
|
||||
float &timeRemaining = dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData()).mTime;
|
||||
float &timeRemaining = dynamic_cast<LightCustomData&> (*ptr.getRefData().getCustomData()).mTime;
|
||||
timeRemaining = duration;
|
||||
}
|
||||
|
||||
|
@ -218,7 +218,7 @@ namespace MWClass
|
|||
{
|
||||
ensureCustomData(ptr);
|
||||
|
||||
return dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData()).mTime;
|
||||
return dynamic_cast<LightCustomData&> (*ptr.getRefData().getCustomData()).mTime;
|
||||
}
|
||||
|
||||
MWWorld::Ptr
|
||||
|
@ -233,7 +233,7 @@ namespace MWClass
|
|||
void Light::ensureCustomData (const MWWorld::Ptr& ptr) const
|
||||
{
|
||||
if (!ptr.getRefData().getCustomData())
|
||||
ptr.getRefData().setCustomData(new CustomData(ptr));
|
||||
ptr.getRefData().setCustomData(new LightCustomData(ptr));
|
||||
}
|
||||
|
||||
bool Light::canSell (const MWWorld::Ptr& item, int npcServices) const
|
||||
|
@ -278,7 +278,7 @@ namespace MWClass
|
|||
|
||||
ensureCustomData (ptr);
|
||||
|
||||
dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData()).mTime = state2.mTime;
|
||||
dynamic_cast<LightCustomData&> (*ptr.getRefData().getCustomData()).mTime = state2.mTime;
|
||||
}
|
||||
|
||||
void Light::writeAdditionalState (const MWWorld::Ptr& ptr, ESM::ObjectState& state)
|
||||
|
@ -288,6 +288,6 @@ namespace MWClass
|
|||
|
||||
ensureCustomData (ptr);
|
||||
|
||||
state2.mTime = dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData()).mTime;
|
||||
state2.mTime = dynamic_cast<LightCustomData&> (*ptr.getRefData().getCustomData()).mTime;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,7 +39,7 @@
|
|||
|
||||
namespace
|
||||
{
|
||||
struct CustomData : public MWWorld::CustomData
|
||||
struct NpcCustomData : public MWWorld::CustomData
|
||||
{
|
||||
MWMechanics::NpcStats mNpcStats;
|
||||
MWMechanics::Movement mMovement;
|
||||
|
@ -48,9 +48,9 @@ namespace
|
|||
virtual MWWorld::CustomData *clone() const;
|
||||
};
|
||||
|
||||
MWWorld::CustomData *CustomData::clone() const
|
||||
MWWorld::CustomData *NpcCustomData::clone() const
|
||||
{
|
||||
return new CustomData (*this);
|
||||
return new NpcCustomData (*this);
|
||||
}
|
||||
|
||||
void autoCalculateAttributes (const ESM::NPC* npc, MWMechanics::CreatureStats& creatureStats)
|
||||
|
@ -262,7 +262,7 @@ namespace MWClass
|
|||
}
|
||||
if (!ptr.getRefData().getCustomData())
|
||||
{
|
||||
std::auto_ptr<CustomData> data(new CustomData);
|
||||
std::auto_ptr<NpcCustomData> data(new NpcCustomData);
|
||||
|
||||
MWWorld::LiveCellRef<ESM::NPC> *ref = ptr.get<ESM::NPC>();
|
||||
|
||||
|
@ -436,14 +436,14 @@ namespace MWClass
|
|||
{
|
||||
ensureCustomData (ptr);
|
||||
|
||||
return dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData()).mNpcStats;
|
||||
return dynamic_cast<NpcCustomData&> (*ptr.getRefData().getCustomData()).mNpcStats;
|
||||
}
|
||||
|
||||
MWMechanics::NpcStats& Npc::getNpcStats (const MWWorld::Ptr& ptr) const
|
||||
{
|
||||
ensureCustomData (ptr);
|
||||
|
||||
return dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData()).mNpcStats;
|
||||
return dynamic_cast<NpcCustomData&> (*ptr.getRefData().getCustomData()).mNpcStats;
|
||||
}
|
||||
|
||||
|
||||
|
@ -673,12 +673,7 @@ namespace MWClass
|
|||
else
|
||||
getCreatureStats(ptr).setHitRecovery(true); // Is this supposed to always occur?
|
||||
|
||||
if(object.isEmpty())
|
||||
{
|
||||
if(ishealth)
|
||||
damage /= std::min(1.0f + getArmorRating(ptr)/std::max(1.0f, damage), 4.0f);
|
||||
}
|
||||
else if(ishealth)
|
||||
if(ishealth)
|
||||
{
|
||||
// Hit percentages:
|
||||
// cuirass = 30%
|
||||
|
@ -824,7 +819,7 @@ namespace MWClass
|
|||
{
|
||||
ensureCustomData (ptr);
|
||||
|
||||
return dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData()).mInventoryStore;
|
||||
return dynamic_cast<NpcCustomData&> (*ptr.getRefData().getCustomData()).mInventoryStore;
|
||||
}
|
||||
|
||||
MWWorld::InventoryStore& Npc::getInventoryStore (const MWWorld::Ptr& ptr)
|
||||
|
@ -832,7 +827,7 @@ namespace MWClass
|
|||
{
|
||||
ensureCustomData (ptr);
|
||||
|
||||
return dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData()).mInventoryStore;
|
||||
return dynamic_cast<NpcCustomData&> (*ptr.getRefData().getCustomData()).mInventoryStore;
|
||||
}
|
||||
|
||||
std::string Npc::getScript (const MWWorld::Ptr& ptr) const
|
||||
|
@ -846,7 +841,7 @@ namespace MWClass
|
|||
float Npc::getSpeed(const MWWorld::Ptr& ptr) const
|
||||
{
|
||||
const MWBase::World *world = MWBase::Environment::get().getWorld();
|
||||
const CustomData *npcdata = static_cast<const CustomData*>(ptr.getRefData().getCustomData());
|
||||
const NpcCustomData *npcdata = static_cast<const NpcCustomData*>(ptr.getRefData().getCustomData());
|
||||
const MWMechanics::MagicEffects &mageffects = npcdata->mNpcStats.getMagicEffects();
|
||||
|
||||
const float normalizedEncumbrance = Npc::getEncumbrance(ptr) / Npc::getCapacity(ptr);
|
||||
|
@ -901,7 +896,7 @@ namespace MWClass
|
|||
|
||||
float Npc::getJump(const MWWorld::Ptr &ptr) const
|
||||
{
|
||||
const CustomData *npcdata = static_cast<const CustomData*>(ptr.getRefData().getCustomData());
|
||||
const NpcCustomData *npcdata = static_cast<const NpcCustomData*>(ptr.getRefData().getCustomData());
|
||||
const MWMechanics::MagicEffects &mageffects = npcdata->mNpcStats.getMagicEffects();
|
||||
const float encumbranceTerm = fJumpEncumbranceBase->getFloat() +
|
||||
fJumpEncumbranceMultiplier->getFloat() *
|
||||
|
@ -940,7 +935,7 @@ namespace MWClass
|
|||
if (fallHeight >= fallDistanceMin)
|
||||
{
|
||||
const float acrobaticsSkill = MWWorld::Class::get(ptr).getNpcStats (ptr).getSkill(ESM::Skill::Acrobatics).getModified();
|
||||
const CustomData *npcdata = static_cast<const CustomData*>(ptr.getRefData().getCustomData());
|
||||
const NpcCustomData *npcdata = static_cast<const NpcCustomData*>(ptr.getRefData().getCustomData());
|
||||
const float jumpSpellBonus = npcdata->mNpcStats.getMagicEffects().get(ESM::MagicEffect::Jump).mMagnitude;
|
||||
const float fallAcroBase = gmst.find("fFallAcroBase")->getFloat();
|
||||
const float fallAcroMult = gmst.find("fFallAcroMult")->getFloat();
|
||||
|
@ -965,7 +960,7 @@ namespace MWClass
|
|||
{
|
||||
ensureCustomData (ptr);
|
||||
|
||||
return dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData()).mMovement;
|
||||
return dynamic_cast<NpcCustomData&> (*ptr.getRefData().getCustomData()).mMovement;
|
||||
}
|
||||
|
||||
Ogre::Vector3 Npc::getMovementVector (const MWWorld::Ptr& ptr) const
|
||||
|
@ -1271,7 +1266,7 @@ namespace MWClass
|
|||
|
||||
ensureCustomData (ptr);
|
||||
|
||||
CustomData& customData = dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData());
|
||||
NpcCustomData& customData = dynamic_cast<NpcCustomData&> (*ptr.getRefData().getCustomData());
|
||||
|
||||
customData.mInventoryStore.readState (state2.mInventory);
|
||||
customData.mNpcStats.readState (state2.mNpcStats);
|
||||
|
@ -1285,7 +1280,7 @@ namespace MWClass
|
|||
|
||||
ensureCustomData (ptr);
|
||||
|
||||
CustomData& customData = dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData());
|
||||
NpcCustomData& customData = dynamic_cast<NpcCustomData&> (*ptr.getRefData().getCustomData());
|
||||
|
||||
customData.mInventoryStore.writeState (state2.mInventory);
|
||||
customData.mNpcStats.writeState (state2.mNpcStats);
|
||||
|
|
|
@ -26,16 +26,6 @@ namespace
|
|||
return path;
|
||||
}
|
||||
|
||||
std::string getCountString(const int count)
|
||||
{
|
||||
if (count == 1)
|
||||
return "";
|
||||
if (count > 9999)
|
||||
return boost::lexical_cast<std::string>(int(count/1000.f)) + "k";
|
||||
else
|
||||
return boost::lexical_cast<std::string>(count);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace MWGui
|
||||
|
@ -226,7 +216,7 @@ namespace MWGui
|
|||
text->setNeedMouseFocus(false);
|
||||
text->setTextShadow(true);
|
||||
text->setTextShadowColour(MyGUI::Colour(0,0,0));
|
||||
text->setCaption(getCountString(ingredient->getUserData<MWWorld::Ptr>()->getRefData().getCount()));
|
||||
text->setCaption(ItemView::getCountString(ingredient->getUserData<MWWorld::Ptr>()->getRefData().getCount()));
|
||||
}
|
||||
|
||||
mItemView->update();
|
||||
|
|
|
@ -23,19 +23,6 @@
|
|||
#include "sortfilteritemmodel.hpp"
|
||||
#include "pickpocketitemmodel.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
std::string getCountString(const int count)
|
||||
{
|
||||
if (count == 1)
|
||||
return "";
|
||||
if (count > 9999)
|
||||
return boost::lexical_cast<std::string>(int(count/1000.f)) + "k";
|
||||
else
|
||||
return boost::lexical_cast<std::string>(count);
|
||||
}
|
||||
}
|
||||
|
||||
namespace MWGui
|
||||
{
|
||||
|
||||
|
@ -79,7 +66,7 @@ namespace MWGui
|
|||
text->setNeedMouseFocus(false);
|
||||
text->setTextShadow(true);
|
||||
text->setTextShadowColour(MyGUI::Colour(0,0,0));
|
||||
text->setCaption(getCountString(count));
|
||||
text->setCaption(ItemView::getCountString(count));
|
||||
|
||||
sourceView->update();
|
||||
|
||||
|
|
|
@ -23,18 +23,7 @@
|
|||
#include "travelwindow.hpp"
|
||||
#include "bookpage.hpp"
|
||||
|
||||
|
||||
namespace
|
||||
{
|
||||
MWGui::BookTypesetter::Utf8Span to_utf8_span (char const * text)
|
||||
{
|
||||
typedef MWGui::BookTypesetter::Utf8Point point;
|
||||
|
||||
point begin = reinterpret_cast <point> (text);
|
||||
|
||||
return MWGui::BookTypesetter::Utf8Span (begin, begin + strlen (text));
|
||||
}
|
||||
}
|
||||
#include "journalbooks.hpp" // to_utf8_span
|
||||
|
||||
namespace MWGui
|
||||
{
|
||||
|
|
|
@ -604,15 +604,22 @@ namespace MWGui
|
|||
mEffectBox->setPosition((viewSize.width - mEffectBoxBaseRight) - mEffectBox->getWidth() + effectsDx, mEffectBox->getTop());
|
||||
}
|
||||
|
||||
void HUD::updateEnemyHealthBar()
|
||||
{
|
||||
MWMechanics::CreatureStats& stats = MWWorld::Class::get(mEnemy).getCreatureStats(mEnemy);
|
||||
mEnemyHealth->setProgressRange(100);
|
||||
// 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 :)
|
||||
mEnemyHealth->setProgressPosition(int(stats.getHealth().getCurrent()) / stats.getHealth().getModified() * 100);
|
||||
}
|
||||
|
||||
void HUD::update()
|
||||
{
|
||||
mSpellIcons->updateWidgets(mEffectBox, true);
|
||||
|
||||
if (!mEnemy.isEmpty() && mEnemyHealth->getVisible())
|
||||
{
|
||||
MWMechanics::CreatureStats& stats = MWWorld::Class::get(mEnemy).getCreatureStats(mEnemy);
|
||||
mEnemyHealth->setProgressRange(100);
|
||||
mEnemyHealth->setProgressPosition(stats.getHealth().getCurrent() / stats.getHealth().getModified() * 100);
|
||||
updateEnemyHealthBar();
|
||||
}
|
||||
|
||||
if (mIsDrowning)
|
||||
|
@ -629,9 +636,7 @@ namespace MWGui
|
|||
if (!mEnemyHealth->getVisible())
|
||||
mWeaponSpellBox->setPosition(mWeaponSpellBox->getPosition() - MyGUI::IntPoint(0,20));
|
||||
mEnemyHealth->setVisible(true);
|
||||
MWMechanics::CreatureStats& stats = MWWorld::Class::get(mEnemy).getCreatureStats(mEnemy);
|
||||
mEnemyHealth->setProgressRange(100);
|
||||
mEnemyHealth->setProgressPosition(stats.getHealth().getCurrent() / stats.getHealth().getModified() * 100);
|
||||
updateEnemyHealthBar();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
#ifndef OPENMW_GAME_MWGUI_HUD_H
|
||||
#define OPENMW_GAME_MWGUI_HUD_H
|
||||
|
||||
#include "mapwindow.hpp"
|
||||
|
||||
#include "../mwmechanics/stat.hpp"
|
||||
|
@ -112,6 +115,10 @@ namespace MWGui
|
|||
void onMagicClicked(MyGUI::Widget* _sender);
|
||||
void onMapClicked(MyGUI::Widget* _sender);
|
||||
|
||||
void updateEnemyHealthBar();
|
||||
|
||||
void updatePositions();
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -162,6 +162,7 @@ namespace MWGui
|
|||
}
|
||||
|
||||
const ItemStack& item = mTradeModel->getItem(index);
|
||||
std::string sound = MWWorld::Class::get(item.mBase).getDownSoundId(item.mBase);
|
||||
|
||||
MWWorld::Ptr object = item.mBase;
|
||||
int count = item.mCount;
|
||||
|
@ -170,6 +171,7 @@ namespace MWGui
|
|||
if (item.mBase.getCellRef().mRefID.size() > 6
|
||||
&& item.mBase.getCellRef().mRefID.substr(0,6) == "bound_")
|
||||
{
|
||||
MWBase::Environment::get().getSoundManager()->playSound (sound, 1.0, 1.0);
|
||||
MWBase::Environment::get().getWindowManager()->messageBox("#{sBarterDialog12}");
|
||||
return;
|
||||
}
|
||||
|
@ -213,6 +215,7 @@ namespace MWGui
|
|||
int services = MWBase::Environment::get().getWindowManager()->getTradeWindow()->getMerchantServices();
|
||||
if (!MWWorld::Class::get(object).canSell(object, services))
|
||||
{
|
||||
MWBase::Environment::get().getSoundManager()->playSound (sound, 1.0, 1.0);
|
||||
MWBase::Environment::get().getWindowManager()->
|
||||
messageBox("#{sBarterDialog4}");
|
||||
return;
|
||||
|
@ -514,6 +517,9 @@ namespace MWGui
|
|||
|
||||
void InventoryWindow::pickUpObject (MWWorld::Ptr object)
|
||||
{
|
||||
// If the inventory is not yet enabled, don't pick anything up
|
||||
if (!MWBase::Environment::get().getWindowManager()->isAllowed(GW_Inventory))
|
||||
return;
|
||||
// make sure the object is of a type that can be picked up
|
||||
std::string type = object.getTypeName();
|
||||
if ( (type != typeid(ESM::Apparatus).name())
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
#ifndef OPENMW_GAME_MWGUI_ITEMSELECTION_H
|
||||
#define OPENMW_GAME_MWGUI_ITEMSELECTION_H
|
||||
|
||||
#include "container.hpp"
|
||||
|
||||
namespace MWGui
|
||||
|
@ -32,3 +35,5 @@ namespace MWGui
|
|||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -13,23 +13,19 @@
|
|||
|
||||
#include "itemmodel.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
std::string getCountString(const int count)
|
||||
{
|
||||
if (count == 1)
|
||||
return "";
|
||||
if (count > 9999)
|
||||
return boost::lexical_cast<std::string>(int(count/1000.f)) + "k";
|
||||
else
|
||||
return boost::lexical_cast<std::string>(count);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
namespace MWGui
|
||||
{
|
||||
|
||||
std::string ItemView::getCountString(int count)
|
||||
{
|
||||
if (count == 1)
|
||||
return "";
|
||||
if (count > 9999)
|
||||
return boost::lexical_cast<std::string>(int(count/1000.f)) + "k";
|
||||
else
|
||||
return boost::lexical_cast<std::string>(count);
|
||||
}
|
||||
|
||||
ItemView::ItemView()
|
||||
: mModel(NULL)
|
||||
, mScrollView(NULL)
|
||||
|
|
|
@ -30,6 +30,8 @@ namespace MWGui
|
|||
|
||||
void update();
|
||||
|
||||
static std::string getCountString(int count);
|
||||
|
||||
private:
|
||||
virtual void initialiseOverride();
|
||||
|
||||
|
|
|
@ -2,15 +2,6 @@
|
|||
|
||||
namespace
|
||||
{
|
||||
MWGui::BookTypesetter::Utf8Span to_utf8_span (char const * text)
|
||||
{
|
||||
typedef MWGui::BookTypesetter::Utf8Point point;
|
||||
|
||||
point begin = reinterpret_cast <point> (text);
|
||||
|
||||
return MWGui::BookTypesetter::Utf8Span (begin, begin + strlen (text));
|
||||
}
|
||||
|
||||
const MyGUI::Colour linkHot (0.40f, 0.40f, 0.80f);
|
||||
const MyGUI::Colour linkNormal (0.20f, 0.20f, 0.60f);
|
||||
const MyGUI::Colour linkActive (0.50f, 0.50f, 1.00f);
|
||||
|
@ -178,6 +169,15 @@ namespace
|
|||
namespace MWGui
|
||||
{
|
||||
|
||||
MWGui::BookTypesetter::Utf8Span to_utf8_span (char const * text)
|
||||
{
|
||||
typedef MWGui::BookTypesetter::Utf8Point point;
|
||||
|
||||
point begin = reinterpret_cast <point> (text);
|
||||
|
||||
return MWGui::BookTypesetter::Utf8Span (begin, begin + strlen (text));
|
||||
}
|
||||
|
||||
typedef TypesetBook::Ptr book;
|
||||
|
||||
JournalBooks::JournalBooks (JournalViewModel::Ptr model) :
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
|
||||
namespace MWGui
|
||||
{
|
||||
MWGui::BookTypesetter::Utf8Span to_utf8_span (char const * text);
|
||||
|
||||
struct JournalBooks
|
||||
{
|
||||
typedef TypesetBook::Ptr Book;
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
#include "mainmenu.hpp"
|
||||
|
||||
#include <components/version/version.hpp>
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/windowmanager.hpp"
|
||||
#include "../mwbase/soundmanager.hpp"
|
||||
|
@ -20,6 +22,22 @@ namespace MWGui
|
|||
, mButtonBox(0), mWidth (w), mHeight (h)
|
||||
, mSaveGameDialog(NULL)
|
||||
{
|
||||
getWidget(mVersionText, "VersionText");
|
||||
std::stringstream sstream;
|
||||
sstream << "OpenMW version: " << OPENMW_VERSION;
|
||||
|
||||
// adding info about git hash if availible
|
||||
std::string rev = OPENMW_VERSION_COMMITHASH;
|
||||
std::string tag = OPENMW_VERSION_TAGHASH;
|
||||
if (!rev.empty() && !tag.empty())
|
||||
{
|
||||
rev = rev.substr(0,10);
|
||||
sstream << "\nrevision: " << rev;
|
||||
}
|
||||
|
||||
std::string output = sstream.str();
|
||||
mVersionText->setCaption(output);
|
||||
|
||||
updateMenu();
|
||||
}
|
||||
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
#ifndef OPENMW_GAME_MWGUI_MAINMENU_H
|
||||
#define OPENMW_GAME_MWGUI_MAINMENU_H
|
||||
|
||||
#include <openengine/gui/layout.hpp>
|
||||
|
||||
#include "imagebutton.hpp"
|
||||
|
@ -24,6 +27,7 @@ namespace MWGui
|
|||
private:
|
||||
|
||||
MyGUI::Widget* mButtonBox;
|
||||
MyGUI::TextBox* mVersionText;
|
||||
|
||||
std::map<std::string, MWGui::ImageButton*> mButtons;
|
||||
|
||||
|
@ -35,3 +39,5 @@ namespace MWGui
|
|||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -19,28 +19,8 @@
|
|||
#include "windowmanagerimp.hpp"
|
||||
#include "itemselection.hpp"
|
||||
|
||||
#include "spellwindow.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
bool sortItems(const MWWorld::Ptr& left, const MWWorld::Ptr& right)
|
||||
{
|
||||
int cmp = left.getClass().getName(left).compare(
|
||||
right.getClass().getName(right));
|
||||
return cmp < 0;
|
||||
}
|
||||
|
||||
bool sortSpells(const std::string& left, const std::string& right)
|
||||
{
|
||||
const MWWorld::Store<ESM::Spell> &spells =
|
||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>();
|
||||
|
||||
const ESM::Spell* a = spells.find(left);
|
||||
const ESM::Spell* b = spells.find(right);
|
||||
|
||||
int cmp = a->mName.compare(b->mName);
|
||||
return cmp < 0;
|
||||
}
|
||||
}
|
||||
|
||||
namespace MWGui
|
||||
{
|
||||
|
|
|
@ -41,9 +41,13 @@ namespace MWGui
|
|||
getWidget(mPreviewImage, "PreviewImage");
|
||||
|
||||
getWidget(mHeadRotate, "HeadRotate");
|
||||
mHeadRotate->setScrollRange(50);
|
||||
mHeadRotate->setScrollPosition(25);
|
||||
mHeadRotate->setScrollViewPage(10);
|
||||
|
||||
// Mouse wheel step is hardcoded to 50 in MyGUI 3.2 ("FIXME").
|
||||
// Give other steps the same value to accomodate.
|
||||
mHeadRotate->setScrollRange(1000);
|
||||
mHeadRotate->setScrollPosition(500);
|
||||
mHeadRotate->setScrollViewPage(50);
|
||||
mHeadRotate->setScrollPage(50);
|
||||
mHeadRotate->eventScrollChangePosition += MyGUI::newDelegate(this, &RaceDialog::onHeadRotate);
|
||||
|
||||
// Set up next/previous buttons
|
||||
|
@ -171,9 +175,9 @@ namespace MWGui
|
|||
eventBack();
|
||||
}
|
||||
|
||||
void RaceDialog::onHeadRotate(MyGUI::ScrollBar*, size_t _position)
|
||||
void RaceDialog::onHeadRotate(MyGUI::ScrollBar* scroll, size_t _position)
|
||||
{
|
||||
float angle = (float(_position) / 49.f - 0.5) * 3.14 * 2;
|
||||
float angle = (float(_position) / (scroll->getScrollRange()-1) - 0.5) * 3.14 * 2;
|
||||
float diff = angle - mCurrentAngle;
|
||||
mPreview->update (diff);
|
||||
mPreviewDirty = true;
|
||||
|
|
|
@ -18,8 +18,16 @@
|
|||
#include "inventorywindow.hpp"
|
||||
#include "confirmationdialog.hpp"
|
||||
|
||||
namespace
|
||||
namespace MWGui
|
||||
{
|
||||
|
||||
bool sortItems(const MWWorld::Ptr& left, const MWWorld::Ptr& right)
|
||||
{
|
||||
int cmp = left.getClass().getName(left).compare(
|
||||
right.getClass().getName(right));
|
||||
return cmp < 0;
|
||||
}
|
||||
|
||||
bool sortSpells(const std::string& left, const std::string& right)
|
||||
{
|
||||
const MWWorld::Store<ESM::Spell> &spells =
|
||||
|
@ -32,16 +40,6 @@ namespace
|
|||
return cmp < 0;
|
||||
}
|
||||
|
||||
bool sortItems(const MWWorld::Ptr& left, const MWWorld::Ptr& right)
|
||||
{
|
||||
int cmp = MWWorld::Class::get(left).getName(left).compare(
|
||||
MWWorld::Class::get(right).getName(right));
|
||||
return cmp < 0;
|
||||
}
|
||||
}
|
||||
|
||||
namespace MWGui
|
||||
{
|
||||
SpellWindow::SpellWindow(DragAndDrop* drag)
|
||||
: WindowPinnableBase("openmw_spell_window.layout")
|
||||
, NoDrop(drag, mMainWidget)
|
||||
|
|
|
@ -2,11 +2,16 @@
|
|||
#define MWGUI_SPELLWINDOW_H
|
||||
|
||||
#include "windowpinnablebase.hpp"
|
||||
#include "../mwworld/ptr.hpp"
|
||||
|
||||
namespace MWGui
|
||||
{
|
||||
class SpellIcons;
|
||||
|
||||
bool sortItems(const MWWorld::Ptr& left, const MWWorld::Ptr& right);
|
||||
|
||||
bool sortSpells(const std::string& left, const std::string& right);
|
||||
|
||||
class SpellWindow : public WindowPinnableBase, public NoDrop
|
||||
{
|
||||
public:
|
||||
|
|
|
@ -143,6 +143,13 @@ namespace MWInput
|
|||
mControlSwitch["vanitymode"] = true;
|
||||
}
|
||||
|
||||
void InputManager::clear()
|
||||
{
|
||||
// Enable all controls
|
||||
for (std::map<std::string, bool>::iterator it = mControlSwitch.begin(); it != mControlSwitch.end(); ++it)
|
||||
it->second = true;
|
||||
}
|
||||
|
||||
InputManager::~InputManager()
|
||||
{
|
||||
mInputBinder->save (mUserFile);
|
||||
|
|
|
@ -65,6 +65,9 @@ namespace MWInput
|
|||
|
||||
virtual ~InputManager();
|
||||
|
||||
/// Clear all savegame-specific data
|
||||
virtual void clear();
|
||||
|
||||
virtual void update(float dt, bool loading);
|
||||
|
||||
void setPlayer (MWWorld::Player* player) { mPlayer = player; }
|
||||
|
|
|
@ -10,16 +10,6 @@
|
|||
#include "steering.hpp"
|
||||
#include "movement.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
float sgn(float a)
|
||||
{
|
||||
if(a > 0)
|
||||
return 1.0;
|
||||
return -1.0;
|
||||
}
|
||||
}
|
||||
|
||||
MWMechanics::AiActivate::AiActivate(const std::string &objectId)
|
||||
: mObjectId(objectId)
|
||||
{
|
||||
|
@ -38,7 +28,7 @@ bool MWMechanics::AiActivate::execute (const MWWorld::Ptr& actor,float duration)
|
|||
MWWorld::Ptr player = world->getPlayerPtr();
|
||||
if(cell->mData.mX != player.getCell()->getCell()->mData.mX)
|
||||
{
|
||||
int sideX = sgn(cell->mData.mX - player.getCell()->getCell()->mData.mX);
|
||||
int sideX = PathFinder::sgn(cell->mData.mX - player.getCell()->getCell()->mData.mX);
|
||||
//check if actor is near the border of an inactive cell. If so, stop walking.
|
||||
if(sideX * (pos.pos[0] - cell->mData.mX*ESM::Land::REAL_SIZE) >
|
||||
sideX * (ESM::Land::REAL_SIZE/2.0f - 200.0f))
|
||||
|
@ -49,7 +39,7 @@ bool MWMechanics::AiActivate::execute (const MWWorld::Ptr& actor,float duration)
|
|||
}
|
||||
if(cell->mData.mY != player.getCell()->getCell()->mData.mY)
|
||||
{
|
||||
int sideY = sgn(cell->mData.mY - player.getCell()->getCell()->mData.mY);
|
||||
int sideY = PathFinder::sgn(cell->mData.mY - player.getCell()->getCell()->mData.mY);
|
||||
//check if actor is near the border of an inactive cell. If so, stop walking.
|
||||
if(sideY * (pos.pos[1] - cell->mData.mY*ESM::Land::REAL_SIZE) >
|
||||
sideY * (ESM::Land::REAL_SIZE/2.0f - 200.0f))
|
||||
|
|
|
@ -11,16 +11,6 @@
|
|||
#include "steering.hpp"
|
||||
#include "movement.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
float sgn(float a)
|
||||
{
|
||||
if(a > 0)
|
||||
return 1.0;
|
||||
return -1.0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
TODO: Test vanilla behavior on passing x0, y0, and z0 with duration of anything including 0.
|
||||
TODO: Different behavior for AIEscort a d x y z and AIEscortCell a c d x y z.
|
||||
|
@ -91,7 +81,7 @@ namespace MWMechanics
|
|||
|
||||
if(actor.getCell()->getCell()->mData.mX != player.getCell()->getCell()->mData.mX)
|
||||
{
|
||||
int sideX = sgn(actor.getCell()->getCell()->mData.mX - player.getCell()->getCell()->mData.mX);
|
||||
int sideX = PathFinder::sgn(actor.getCell()->getCell()->mData.mX - player.getCell()->getCell()->mData.mX);
|
||||
// Check if actor is near the border of an inactive cell. If so, pause walking.
|
||||
if(sideX * (pos.pos[0] - actor.getCell()->getCell()->mData.mX * ESM::Land::REAL_SIZE) > sideX * (ESM::Land::REAL_SIZE /
|
||||
2.0 - 200))
|
||||
|
@ -102,7 +92,7 @@ namespace MWMechanics
|
|||
}
|
||||
if(actor.getCell()->getCell()->mData.mY != player.getCell()->getCell()->mData.mY)
|
||||
{
|
||||
int sideY = sgn(actor.getCell()->getCell()->mData.mY - player.getCell()->getCell()->mData.mY);
|
||||
int sideY = PathFinder::sgn(actor.getCell()->getCell()->mData.mY - player.getCell()->getCell()->mData.mY);
|
||||
// Check if actor is near the border of an inactive cell. If so, pause walking.
|
||||
if(sideY*(pos.pos[1] - actor.getCell()->getCell()->mData.mY * ESM::Land::REAL_SIZE) > sideY * (ESM::Land::REAL_SIZE /
|
||||
2.0 - 200))
|
||||
|
|
|
@ -9,16 +9,6 @@
|
|||
#include "steering.hpp"
|
||||
#include "movement.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
float sgn(float a)
|
||||
{
|
||||
if(a > 0)
|
||||
return 1.0;
|
||||
return -1.0;
|
||||
}
|
||||
}
|
||||
|
||||
namespace MWMechanics
|
||||
{
|
||||
AiTravel::AiTravel(float x, float y, float z)
|
||||
|
@ -43,7 +33,7 @@ namespace MWMechanics
|
|||
MWWorld::Ptr player = world->getPlayerPtr();
|
||||
if(cell->mData.mX != player.getCell()->getCell()->mData.mX)
|
||||
{
|
||||
int sideX = sgn(cell->mData.mX - player.getCell()->getCell()->mData.mX);
|
||||
int sideX = PathFinder::sgn(cell->mData.mX - player.getCell()->getCell()->mData.mX);
|
||||
//check if actor is near the border of an inactive cell. If so, stop walking.
|
||||
if(sideX * (pos.pos[0] - cell->mData.mX*ESM::Land::REAL_SIZE) >
|
||||
sideX * (ESM::Land::REAL_SIZE/2.0f - 200.0f))
|
||||
|
@ -54,7 +44,7 @@ namespace MWMechanics
|
|||
}
|
||||
if(cell->mData.mY != player.getCell()->getCell()->mData.mY)
|
||||
{
|
||||
int sideY = sgn(cell->mData.mY - player.getCell()->getCell()->mData.mY);
|
||||
int sideY = PathFinder::sgn(cell->mData.mY - player.getCell()->getCell()->mData.mY);
|
||||
//check if actor is near the border of an inactive cell. If so, stop walking.
|
||||
if(sideY * (pos.pos[1] - cell->mData.mY*ESM::Land::REAL_SIZE) >
|
||||
sideY * (ESM::Land::REAL_SIZE/2.0f - 200.0f))
|
||||
|
|
|
@ -15,18 +15,13 @@
|
|||
#include "steering.hpp"
|
||||
#include "movement.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
float sgn(float a)
|
||||
{
|
||||
if(a > 0)
|
||||
return 1.0;
|
||||
return -1.0;
|
||||
}
|
||||
}
|
||||
|
||||
namespace MWMechanics
|
||||
{
|
||||
// NOTE: determined empirically but probably need further tweaking
|
||||
static const int COUNT_BEFORE_STUCK = 20;
|
||||
static const int COUNT_BEFORE_RESET = 200;
|
||||
static const int COUNT_EVADE = 7;
|
||||
|
||||
AiWander::AiWander(int distance, int duration, int timeOfDay, const std::vector<int>& idle, bool repeat):
|
||||
mDistance(distance), mDuration(duration), mTimeOfDay(timeOfDay), mIdle(idle), mRepeat(repeat)
|
||||
, mCellX(std::numeric_limits<int>::max())
|
||||
|
@ -36,6 +31,11 @@ namespace MWMechanics
|
|||
, mX(0)
|
||||
, mY(0)
|
||||
, mZ(0)
|
||||
, mPrevX(0)
|
||||
, mPrevY(0)
|
||||
, mWalkState(State_Norm)
|
||||
, mStuckCount(0)
|
||||
, mEvadeCount(0)
|
||||
, mSaidGreeting(false)
|
||||
{
|
||||
for(unsigned short counter = 0; counter < mIdle.size(); counter++)
|
||||
|
@ -298,9 +298,91 @@ namespace MWMechanics
|
|||
}
|
||||
else
|
||||
{
|
||||
zTurn(actor, Ogre::Degree(mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1])));
|
||||
/* 1 n
|
||||
* State_Norm <---> State_CheckStuck --> State_Evade
|
||||
* ^ ^ | ^ | ^ | |
|
||||
* | | | | | | | |
|
||||
* | +---+ +---+ +---+ | m
|
||||
* | any < n < m |
|
||||
* +--------------------------------------------+
|
||||
*/
|
||||
bool samePosition = (abs(pos.pos[0] - mPrevX) < 1) && (abs(pos.pos[1] - mPrevY) < 1);
|
||||
switch(mWalkState)
|
||||
{
|
||||
case State_Norm:
|
||||
{
|
||||
if(!samePosition)
|
||||
break;
|
||||
else
|
||||
mWalkState = State_CheckStuck;
|
||||
}
|
||||
/* FALL THROUGH */
|
||||
case State_CheckStuck:
|
||||
{
|
||||
if(!samePosition)
|
||||
{
|
||||
mWalkState = State_Norm;
|
||||
// to do this properly need yet another variable, simply don't clear for now
|
||||
//mStuckCount = 0;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
// consider stuck only if position unchanges consecutively
|
||||
if((mStuckCount++ % COUNT_BEFORE_STUCK) == 0)
|
||||
mWalkState = State_Evade;
|
||||
// NOTE: mStuckCount is purposely not cleared here
|
||||
else
|
||||
break; // still in the same state, but counter got incremented
|
||||
}
|
||||
}
|
||||
/* FALL THROUGH */
|
||||
case State_Evade:
|
||||
{
|
||||
if(mEvadeCount++ < COUNT_EVADE)
|
||||
break;
|
||||
else
|
||||
{
|
||||
mWalkState = State_Norm; // tried to evade, assume all is ok and start again
|
||||
// NOTE: mStuckCount is purposely not cleared here
|
||||
mEvadeCount = 0;
|
||||
}
|
||||
}
|
||||
/* NO DEFAULT CASE */
|
||||
}
|
||||
|
||||
actor.getClass().getMovementSettings(actor).mPosition[1] = 1;
|
||||
if(mWalkState == State_Evade)
|
||||
{
|
||||
//std::cout << "Stuck \""<<actor.getClass().getName(actor)<<"\"" << std::endl;
|
||||
|
||||
// diagonal should have same animation as walk forward
|
||||
actor.getClass().getMovementSettings(actor).mPosition[0] = 1;
|
||||
actor.getClass().getMovementSettings(actor).mPosition[1] = 0.01f;
|
||||
// change the angle a bit, too
|
||||
zTurn(actor, Ogre::Degree(mPathFinder.getZAngleToNext(pos.pos[0] + 1, pos.pos[1])));
|
||||
}
|
||||
else
|
||||
{
|
||||
actor.getClass().getMovementSettings(actor).mPosition[1] = 1;
|
||||
zTurn(actor, Ogre::Degree(mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1])));
|
||||
}
|
||||
|
||||
if(mStuckCount >= COUNT_BEFORE_RESET) // something has gone wrong, reset
|
||||
{
|
||||
//std::cout << "Reset \""<<actor.getClass().getName(actor)<<"\"" << std::endl;
|
||||
mWalkState = State_Norm;
|
||||
mStuckCount = 0;
|
||||
|
||||
stopWalking(actor);
|
||||
mMoveNow = false;
|
||||
mWalking = false;
|
||||
mChooseAction = true;
|
||||
}
|
||||
|
||||
// update position
|
||||
ESM::Position updatedPos = actor.getRefData().getPosition();
|
||||
mPrevX = updatedPos.pos[0];
|
||||
mPrevY = updatedPos.pos[1];
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -43,6 +43,21 @@ namespace MWMechanics
|
|||
float mXCell;
|
||||
float mYCell;
|
||||
|
||||
// for checking if we're stuck (but don't check Z axis)
|
||||
float mPrevX;
|
||||
float mPrevY;
|
||||
|
||||
enum WalkState
|
||||
{
|
||||
State_Norm,
|
||||
State_CheckStuck,
|
||||
State_Evade
|
||||
};
|
||||
WalkState mWalkState;
|
||||
|
||||
int mStuckCount;
|
||||
int mEvadeCount;
|
||||
|
||||
bool mStoredAvailableNodes;
|
||||
bool mChooseAction;
|
||||
bool mIdleNow;
|
||||
|
|
|
@ -37,13 +37,6 @@ namespace
|
|||
return sqrt(x * x + y * y + z * z);
|
||||
}
|
||||
|
||||
static float sgn(Ogre::Radian a)
|
||||
{
|
||||
if(a.valueRadians() > 0)
|
||||
return 1.0;
|
||||
return -1.0;
|
||||
}
|
||||
|
||||
int getClosestPoint(const ESM::Pathgrid* grid, float x, float y, float z)
|
||||
{
|
||||
if(!grid || grid->mPoints.empty())
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
#include <components/esm/loadpgrd.hpp>
|
||||
#include <list>
|
||||
|
||||
#include <OgreMath.h>
|
||||
|
||||
namespace MWWorld
|
||||
{
|
||||
class CellStore;
|
||||
|
@ -16,6 +18,20 @@ namespace MWMechanics
|
|||
public:
|
||||
PathFinder();
|
||||
|
||||
static float sgn(Ogre::Radian a)
|
||||
{
|
||||
if(a.valueRadians() > 0)
|
||||
return 1.0;
|
||||
return -1.0;
|
||||
}
|
||||
|
||||
static float sgn(float a)
|
||||
{
|
||||
if(a > 0)
|
||||
return 1.0;
|
||||
return -1.0;
|
||||
}
|
||||
|
||||
void clearPath();
|
||||
|
||||
void buildPathgridGraph(const ESM::Pathgrid* pathGrid);
|
||||
|
|
|
@ -55,6 +55,8 @@ CreatureWeaponAnimation::CreatureWeaponAnimation(const MWWorld::Ptr &ptr)
|
|||
|
||||
updateParts();
|
||||
}
|
||||
|
||||
mWeaponAnimationTime = Ogre::SharedPtr<WeaponAnimationTime>(new WeaponAnimationTime(this));
|
||||
}
|
||||
|
||||
void CreatureWeaponAnimation::showWeapons(bool showWeapon)
|
||||
|
@ -110,6 +112,20 @@ void CreatureWeaponAnimation::updatePart(NifOgre::ObjectScenePtr& scene, int slo
|
|||
setRenderProperties(scene, RV_Actors, RQG_Main, RQG_Alpha, 0,
|
||||
!item.getClass().getEnchantment(item).empty(), &glowColor);
|
||||
|
||||
// Crossbows start out with a bolt attached
|
||||
if (slot == MWWorld::InventoryStore::Slot_CarriedRight &&
|
||||
item.getTypeName() == typeid(ESM::Weapon).name() &&
|
||||
item.get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::MarksmanCrossbow)
|
||||
{
|
||||
MWWorld::ContainerStoreIterator ammo = inv.getSlot(MWWorld::InventoryStore::Slot_Ammunition);
|
||||
if (ammo != inv.end() && ammo->get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::Bolt)
|
||||
attachArrow();
|
||||
else
|
||||
mAmmunition.setNull();
|
||||
}
|
||||
else
|
||||
mAmmunition.setNull();
|
||||
|
||||
if(scene->mSkelBase)
|
||||
{
|
||||
Ogre::SkeletonInstance *skel = scene->mSkelBase->getSkeleton();
|
||||
|
@ -133,15 +149,42 @@ void CreatureWeaponAnimation::updatePart(NifOgre::ObjectScenePtr& scene, int slo
|
|||
updateSkeletonInstance(mSkelBase->getSkeleton(), skel);
|
||||
}
|
||||
|
||||
// TODO:
|
||||
// type == ESM::PRT_Weapon should get an animation source based on the current offset
|
||||
// of the weapon attack animation (from its beginning, or start marker?)
|
||||
std::vector<Ogre::Controller<Ogre::Real> >::iterator ctrl(scene->mControllers.begin());
|
||||
for(;ctrl != scene->mControllers.end();ctrl++)
|
||||
{
|
||||
if(ctrl->getSource().isNull())
|
||||
ctrl->setSource(Ogre::SharedPtr<NullAnimationTime>(new NullAnimationTime()));
|
||||
{
|
||||
if (slot == MWWorld::InventoryStore::Slot_CarriedRight)
|
||||
ctrl->setSource(mWeaponAnimationTime);
|
||||
else
|
||||
ctrl->setSource(Ogre::SharedPtr<NullAnimationTime>(new NullAnimationTime()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CreatureWeaponAnimation::configureAddedObject(NifOgre::ObjectScenePtr object, MWWorld::Ptr ptr, int slot)
|
||||
{
|
||||
Ogre::Vector3 glowColor = getEnchantmentColor(ptr);
|
||||
|
||||
setRenderProperties(object, RV_Actors, RQG_Main, RQG_Alpha, 0,
|
||||
!ptr.getClass().getEnchantment(ptr).empty(), &glowColor);
|
||||
}
|
||||
|
||||
void CreatureWeaponAnimation::attachArrow()
|
||||
{
|
||||
WeaponAnimation::attachArrow(mPtr);
|
||||
}
|
||||
|
||||
void CreatureWeaponAnimation::releaseArrow()
|
||||
{
|
||||
WeaponAnimation::releaseArrow(mPtr);
|
||||
}
|
||||
|
||||
Ogre::Vector3 CreatureWeaponAnimation::runAnimation(float duration)
|
||||
{
|
||||
Ogre::Vector3 ret = Animation::runAnimation(duration);
|
||||
pitchSkeleton(mPtr.getRefData().getPosition().rot[0], mSkelBase->getSkeleton());
|
||||
return ret;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#define GAME_RENDER_CREATUREANIMATION_H
|
||||
|
||||
#include "animation.hpp"
|
||||
#include "weaponanimation.hpp"
|
||||
#include "../mwworld/inventorystore.hpp"
|
||||
|
||||
namespace MWWorld
|
||||
|
@ -21,7 +22,7 @@ namespace MWRender
|
|||
// For creatures with weapons and shields
|
||||
// Animation is already virtual anyway, so might as well make a separate class.
|
||||
// Most creatures don't need weapons/shields, so this will save some memory.
|
||||
class CreatureWeaponAnimation : public Animation, public MWWorld::InventoryStoreListener
|
||||
class CreatureWeaponAnimation : public Animation, public WeaponAnimation, public MWWorld::InventoryStoreListener
|
||||
{
|
||||
public:
|
||||
CreatureWeaponAnimation(const MWWorld::Ptr& ptr);
|
||||
|
@ -36,11 +37,29 @@ namespace MWRender
|
|||
|
||||
void updatePart(NifOgre::ObjectScenePtr& scene, int slot);
|
||||
|
||||
virtual void attachArrow();
|
||||
virtual void releaseArrow();
|
||||
|
||||
virtual Ogre::Vector3 runAnimation(float duration);
|
||||
|
||||
/// A relative factor (0-1) that decides if and how much the skeleton should be pitched
|
||||
/// to indicate the facing orientation of the character.
|
||||
virtual void setPitchFactor(float factor) { mPitchFactor = factor; }
|
||||
|
||||
virtual void setWeaponGroup(const std::string& group) { mWeaponAnimationTime->setGroup(group); }
|
||||
|
||||
// WeaponAnimation
|
||||
virtual NifOgre::ObjectScenePtr getWeapon() { return mWeapon; }
|
||||
virtual void showWeapon(bool show) { showWeapons(show); }
|
||||
virtual void configureAddedObject(NifOgre::ObjectScenePtr object, MWWorld::Ptr ptr, int slot);
|
||||
|
||||
private:
|
||||
NifOgre::ObjectScenePtr mWeapon;
|
||||
NifOgre::ObjectScenePtr mShield;
|
||||
bool mShowWeapons;
|
||||
bool mShowCarriedLeft;
|
||||
|
||||
Ogre::SharedPtr<WeaponAnimationTime> mWeaponAnimationTime;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -76,27 +76,6 @@ float HeadAnimationTime::getValue() const
|
|||
return 1;
|
||||
}
|
||||
|
||||
float WeaponAnimationTime::getValue() const
|
||||
{
|
||||
if (mWeaponGroup.empty())
|
||||
return 0;
|
||||
float current = mAnimation->getCurrentTime(mWeaponGroup);
|
||||
if (current == -1)
|
||||
return 0;
|
||||
return current - mStartTime;
|
||||
}
|
||||
|
||||
void WeaponAnimationTime::setGroup(const std::string &group)
|
||||
{
|
||||
mWeaponGroup = group;
|
||||
mStartTime = mAnimation->getStartTime(mWeaponGroup);
|
||||
}
|
||||
|
||||
void WeaponAnimationTime::updateStartTime()
|
||||
{
|
||||
setGroup(mWeaponGroup);
|
||||
}
|
||||
|
||||
static NpcAnimation::PartBoneMap createPartListMap()
|
||||
{
|
||||
NpcAnimation::PartBoneMap result;
|
||||
|
@ -147,8 +126,7 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, int v
|
|||
mShowCarriedLeft(true),
|
||||
mFirstPersonOffset(0.f, 0.f, 0.f),
|
||||
mAlpha(1.f),
|
||||
mNpcType(Type_Normal),
|
||||
mPitchFactor(0)
|
||||
mNpcType(Type_Normal)
|
||||
{
|
||||
mNpc = mPtr.get<ESM::NPC>()->mBase;
|
||||
|
||||
|
@ -538,14 +516,10 @@ Ogre::Vector3 NpcAnimation::runAnimation(float timepassed)
|
|||
// updateSkeletonInstance, below, touches the hands.
|
||||
node->translate(mFirstPersonOffset, Ogre::Node::TS_WORLD);
|
||||
}
|
||||
else if (mPitchFactor > 0)
|
||||
else
|
||||
{
|
||||
// In third person mode we may still need pitch for ranged weapon targeting
|
||||
float pitch = mPtr.getRefData().getPosition().rot[0] * mPitchFactor;
|
||||
Ogre::Node *node = baseinst->getBone("Bip01 Spine2");
|
||||
node->pitch(Ogre::Radian(-pitch/2), Ogre::Node::TS_WORLD);
|
||||
node = baseinst->getBone("Bip01 Spine1");
|
||||
node->pitch(Ogre::Radian(-pitch/2), Ogre::Node::TS_WORLD);
|
||||
pitchSkeleton(mPtr.getRefData().getPosition().rot[0], baseinst);
|
||||
}
|
||||
mFirstPersonOffset = 0.f; // reset the X, Y, Z offset for the next frame.
|
||||
|
||||
|
@ -695,13 +669,14 @@ void NpcAnimation::showWeapons(bool showWeapon)
|
|||
{
|
||||
MWWorld::InventoryStore &inv = MWWorld::Class::get(mPtr).getInventoryStore(mPtr);
|
||||
MWWorld::ContainerStoreIterator weapon = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
|
||||
if(weapon != inv.end()) // special case for weapons
|
||||
if(weapon != inv.end())
|
||||
{
|
||||
Ogre::Vector3 glowColor = getEnchantmentColor(*weapon);
|
||||
std::string mesh = MWWorld::Class::get(*weapon).getModel(*weapon);
|
||||
addOrReplaceIndividualPart(ESM::PRT_Weapon, MWWorld::InventoryStore::Slot_CarriedRight, 1,
|
||||
mesh, !weapon->getClass().getEnchantment(*weapon).empty(), &glowColor);
|
||||
|
||||
// Crossbows start out with a bolt attached
|
||||
if (weapon->getTypeName() == typeid(ESM::Weapon).name() &&
|
||||
weapon->get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::MarksmanCrossbow)
|
||||
{
|
||||
|
@ -743,113 +718,24 @@ void NpcAnimation::showCarriedLeft(bool show)
|
|||
removeIndividualPart(ESM::PRT_Shield);
|
||||
}
|
||||
|
||||
void NpcAnimation::configureAddedObject(NifOgre::ObjectScenePtr object, MWWorld::Ptr ptr, int slot)
|
||||
{
|
||||
Ogre::Vector3 glowColor = getEnchantmentColor(ptr);
|
||||
setRenderProperties(object, (mViewMode == VM_FirstPerson) ? RV_FirstPerson : mVisibilityFlags, RQG_Main, RQG_Alpha, 0,
|
||||
!ptr.getClass().getEnchantment(ptr).empty(), &glowColor);
|
||||
|
||||
std::for_each(object->mEntities.begin(), object->mEntities.end(), SetObjectGroup(slot));
|
||||
std::for_each(object->mParticles.begin(), object->mParticles.end(), SetObjectGroup(slot));
|
||||
}
|
||||
|
||||
void NpcAnimation::attachArrow()
|
||||
{
|
||||
MWWorld::InventoryStore& inv = mPtr.getClass().getInventoryStore(mPtr);
|
||||
MWWorld::ContainerStoreIterator weaponSlot = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
|
||||
if (weaponSlot != inv.end() && weaponSlot->get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::MarksmanThrown)
|
||||
showWeapons(true);
|
||||
else
|
||||
{
|
||||
NifOgre::ObjectScenePtr weapon = mObjectParts[ESM::PRT_Weapon];
|
||||
|
||||
MWWorld::ContainerStoreIterator ammo = inv.getSlot(MWWorld::InventoryStore::Slot_Ammunition);
|
||||
if (ammo == inv.end())
|
||||
return;
|
||||
std::string model = ammo->getClass().getModel(*ammo);
|
||||
|
||||
mAmmunition = NifOgre::Loader::createObjects(weapon->mSkelBase, "ArrowBone", mInsert, model);
|
||||
Ogre::Vector3 glowColor = getEnchantmentColor(*ammo);
|
||||
setRenderProperties(mAmmunition, (mViewMode == VM_FirstPerson) ? RV_FirstPerson : mVisibilityFlags, RQG_Main, RQG_Alpha, 0,
|
||||
!ammo->getClass().getEnchantment(*ammo).empty(), &glowColor);
|
||||
|
||||
std::for_each(mAmmunition->mEntities.begin(), mAmmunition->mEntities.end(), SetObjectGroup(MWWorld::InventoryStore::Slot_Ammunition));
|
||||
std::for_each(mAmmunition->mParticles.begin(), mAmmunition->mParticles.end(), SetObjectGroup(MWWorld::InventoryStore::Slot_Ammunition));
|
||||
}
|
||||
WeaponAnimation::attachArrow(mPtr);
|
||||
}
|
||||
|
||||
void NpcAnimation::releaseArrow()
|
||||
{
|
||||
MWWorld::InventoryStore& inv = mPtr.getClass().getInventoryStore(mPtr);
|
||||
MWWorld::ContainerStoreIterator weapon = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
|
||||
if (weapon == inv.end())
|
||||
return;
|
||||
|
||||
// The orientation of the launched projectile. Always the same as the actor orientation, even if the ArrowBone's orientation dictates otherwise.
|
||||
Ogre::Quaternion orient = Ogre::Quaternion(Ogre::Radian(mPtr.getRefData().getPosition().rot[2]), Ogre::Vector3::NEGATIVE_UNIT_Z) *
|
||||
Ogre::Quaternion(Ogre::Radian(mPtr.getRefData().getPosition().rot[0]), Ogre::Vector3::NEGATIVE_UNIT_X);
|
||||
|
||||
const MWWorld::Store<ESM::GameSetting> &gmst =
|
||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
|
||||
|
||||
// Reduce fatigue
|
||||
// somewhat of a guess, but using the weapon weight makes sense
|
||||
const float fFatigueAttackBase = gmst.find("fFatigueAttackBase")->getFloat();
|
||||
const float fFatigueAttackMult = gmst.find("fFatigueAttackMult")->getFloat();
|
||||
const float fWeaponFatigueMult = gmst.find("fWeaponFatigueMult")->getFloat();
|
||||
MWMechanics::CreatureStats& attackerStats = mPtr.getClass().getCreatureStats(mPtr);
|
||||
MWMechanics::DynamicStat<float> fatigue = attackerStats.getFatigue();
|
||||
const float normalizedEncumbrance = mPtr.getClass().getEncumbrance(mPtr) / mPtr.getClass().getCapacity(mPtr);
|
||||
float fatigueLoss = fFatigueAttackBase + normalizedEncumbrance * fFatigueAttackMult;
|
||||
if (!weapon->isEmpty())
|
||||
fatigueLoss += weapon->getClass().getWeight(*weapon) * attackerStats.getAttackStrength() * fWeaponFatigueMult;
|
||||
fatigue.setCurrent(fatigue.getCurrent() - fatigueLoss);
|
||||
attackerStats.setFatigue(fatigue);
|
||||
|
||||
if (weapon->get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::MarksmanThrown)
|
||||
{
|
||||
// Thrown weapons get detached now
|
||||
NifOgre::ObjectScenePtr objects = mObjectParts[ESM::PRT_Weapon];
|
||||
|
||||
Ogre::Vector3 launchPos(0,0,0);
|
||||
if (objects->mSkelBase)
|
||||
{
|
||||
launchPos = objects->mSkelBase->getParentNode()->_getDerivedPosition();
|
||||
}
|
||||
else if (objects->mEntities.size())
|
||||
{
|
||||
objects->mEntities[0]->getParentNode()->needUpdate(true);
|
||||
launchPos = objects->mEntities[0]->getParentNode()->_getDerivedPosition();
|
||||
}
|
||||
|
||||
float fThrownWeaponMinSpeed = gmst.find("fThrownWeaponMinSpeed")->getFloat();
|
||||
float fThrownWeaponMaxSpeed = gmst.find("fThrownWeaponMaxSpeed")->getFloat();
|
||||
float speed = fThrownWeaponMinSpeed + (fThrownWeaponMaxSpeed - fThrownWeaponMinSpeed) *
|
||||
mPtr.getClass().getCreatureStats(mPtr).getAttackStrength();
|
||||
|
||||
MWBase::Environment::get().getWorld()->launchProjectile(mPtr, *weapon, launchPos, orient, *weapon, speed);
|
||||
|
||||
showWeapons(false);
|
||||
|
||||
inv.remove(*weapon, 1, mPtr);
|
||||
}
|
||||
else
|
||||
{
|
||||
// With bows and crossbows only the used arrow/bolt gets detached
|
||||
MWWorld::ContainerStoreIterator ammo = inv.getSlot(MWWorld::InventoryStore::Slot_Ammunition);
|
||||
if (ammo == inv.end())
|
||||
return;
|
||||
|
||||
Ogre::Vector3 launchPos(0,0,0);
|
||||
if (mAmmunition->mSkelBase)
|
||||
{
|
||||
launchPos = mAmmunition->mSkelBase->getParentNode()->_getDerivedPosition();
|
||||
}
|
||||
else if (mAmmunition->mEntities.size())
|
||||
{
|
||||
mAmmunition->mEntities[0]->getParentNode()->needUpdate(true);
|
||||
launchPos = mAmmunition->mEntities[0]->getParentNode()->_getDerivedPosition();
|
||||
}
|
||||
|
||||
float fProjectileMinSpeed = gmst.find("fProjectileMinSpeed")->getFloat();
|
||||
float fProjectileMaxSpeed = gmst.find("fProjectileMaxSpeed")->getFloat();
|
||||
float speed = fProjectileMinSpeed + (fProjectileMaxSpeed - fProjectileMinSpeed) * mPtr.getClass().getCreatureStats(mPtr).getAttackStrength();
|
||||
|
||||
MWBase::Environment::get().getWorld()->launchProjectile(mPtr, *ammo, launchPos, orient, *weapon, speed);
|
||||
|
||||
inv.remove(*ammo, 1, mPtr);
|
||||
mAmmunition.setNull();
|
||||
}
|
||||
WeaponAnimation::releaseArrow(mPtr);
|
||||
}
|
||||
|
||||
void NpcAnimation::permanentEffectAdded(const ESM::MagicEffect *magicEffect, bool isNew, bool playSound)
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
|
||||
#include "../mwworld/inventorystore.hpp"
|
||||
|
||||
#include "weaponanimation.hpp"
|
||||
|
||||
namespace ESM
|
||||
{
|
||||
struct NPC;
|
||||
|
@ -25,24 +27,7 @@ public:
|
|||
{ }
|
||||
};
|
||||
|
||||
class WeaponAnimationTime : public Ogre::ControllerValue<Ogre::Real>
|
||||
{
|
||||
private:
|
||||
Animation* mAnimation;
|
||||
std::string mWeaponGroup;
|
||||
float mStartTime;
|
||||
public:
|
||||
WeaponAnimationTime(Animation* animation) : mAnimation(animation), mStartTime(0) {}
|
||||
void setGroup(const std::string& group);
|
||||
void updateStartTime();
|
||||
|
||||
virtual Ogre::Real getValue() const;
|
||||
virtual void setValue(Ogre::Real value)
|
||||
{ }
|
||||
};
|
||||
|
||||
|
||||
class NpcAnimation : public Animation, public MWWorld::InventoryStoreListener
|
||||
class NpcAnimation : public Animation, public WeaponAnimation, public MWWorld::InventoryStoreListener
|
||||
{
|
||||
public:
|
||||
virtual void equipmentChanged() { updateParts(); }
|
||||
|
@ -91,7 +76,6 @@ private:
|
|||
Ogre::SharedPtr<WeaponAnimationTime> mWeaponAnimationTime;
|
||||
|
||||
float mAlpha;
|
||||
float mPitchFactor;
|
||||
|
||||
void updateNpcBase();
|
||||
|
||||
|
@ -138,7 +122,10 @@ public:
|
|||
virtual void attachArrow();
|
||||
virtual void releaseArrow();
|
||||
|
||||
NifOgre::ObjectScenePtr mAmmunition;
|
||||
// WeaponAnimation
|
||||
virtual NifOgre::ObjectScenePtr getWeapon() { return mObjectParts[ESM::PRT_Weapon]; }
|
||||
virtual void showWeapon(bool show) { showWeapons(show); }
|
||||
virtual void configureAddedObject(NifOgre::ObjectScenePtr object, MWWorld::Ptr ptr, int slot);
|
||||
|
||||
void setViewMode(ViewMode viewMode);
|
||||
|
||||
|
|
|
@ -1073,7 +1073,7 @@ float RenderingManager::getCameraDistance() const
|
|||
|
||||
void RenderingManager::spawnEffect(const std::string &model, const std::string &texture, const Vector3 &worldPosition, float scale)
|
||||
{
|
||||
mEffectManager->addEffect(model, "", worldPosition, scale);
|
||||
mEffectManager->addEffect(model, texture, worldPosition, scale);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
|
159
apps/openmw/mwrender/weaponanimation.cpp
Normal file
|
@ -0,0 +1,159 @@
|
|||
#include "weaponanimation.hpp"
|
||||
|
||||
#include <OgreEntity.h>
|
||||
#include <OgreBone.h>
|
||||
#include <OgreSceneNode.h>
|
||||
#include <OgreSkeletonInstance.h>
|
||||
|
||||
#include "../mwbase/world.hpp"
|
||||
#include "../mwbase/environment.hpp"
|
||||
|
||||
#include "../mwworld/inventorystore.hpp"
|
||||
#include "../mwworld/class.hpp"
|
||||
#include "../mwworld/esmstore.hpp"
|
||||
|
||||
#include "../mwmechanics/creaturestats.hpp"
|
||||
|
||||
#include "animation.hpp"
|
||||
|
||||
namespace MWRender
|
||||
{
|
||||
|
||||
float WeaponAnimationTime::getValue() const
|
||||
{
|
||||
if (mWeaponGroup.empty())
|
||||
return 0;
|
||||
float current = mAnimation->getCurrentTime(mWeaponGroup);
|
||||
if (current == -1)
|
||||
return 0;
|
||||
return current - mStartTime;
|
||||
}
|
||||
|
||||
void WeaponAnimationTime::setGroup(const std::string &group)
|
||||
{
|
||||
mWeaponGroup = group;
|
||||
mStartTime = mAnimation->getStartTime(mWeaponGroup);
|
||||
}
|
||||
|
||||
void WeaponAnimationTime::updateStartTime()
|
||||
{
|
||||
setGroup(mWeaponGroup);
|
||||
}
|
||||
|
||||
void WeaponAnimation::attachArrow(MWWorld::Ptr actor)
|
||||
{
|
||||
MWWorld::InventoryStore& inv = actor.getClass().getInventoryStore(actor);
|
||||
MWWorld::ContainerStoreIterator weaponSlot = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
|
||||
if (weaponSlot != inv.end() && weaponSlot->get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::MarksmanThrown)
|
||||
showWeapon(true);
|
||||
else
|
||||
{
|
||||
NifOgre::ObjectScenePtr weapon = getWeapon();
|
||||
|
||||
MWWorld::ContainerStoreIterator ammo = inv.getSlot(MWWorld::InventoryStore::Slot_Ammunition);
|
||||
if (ammo == inv.end())
|
||||
return;
|
||||
std::string model = ammo->getClass().getModel(*ammo);
|
||||
|
||||
mAmmunition = NifOgre::Loader::createObjects(weapon->mSkelBase, "ArrowBone", weapon->mSkelBase->getParentSceneNode(), model);
|
||||
configureAddedObject(mAmmunition, *ammo, MWWorld::InventoryStore::Slot_Ammunition);
|
||||
}
|
||||
}
|
||||
|
||||
void WeaponAnimation::releaseArrow(MWWorld::Ptr actor)
|
||||
{
|
||||
MWWorld::InventoryStore& inv = actor.getClass().getInventoryStore(actor);
|
||||
MWWorld::ContainerStoreIterator weapon = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
|
||||
if (weapon == inv.end())
|
||||
return;
|
||||
|
||||
// The orientation of the launched projectile. Always the same as the actor orientation, even if the ArrowBone's orientation dictates otherwise.
|
||||
Ogre::Quaternion orient = Ogre::Quaternion(Ogre::Radian(actor.getRefData().getPosition().rot[2]), Ogre::Vector3::NEGATIVE_UNIT_Z) *
|
||||
Ogre::Quaternion(Ogre::Radian(actor.getRefData().getPosition().rot[0]), Ogre::Vector3::NEGATIVE_UNIT_X);
|
||||
|
||||
const MWWorld::Store<ESM::GameSetting> &gmst =
|
||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
|
||||
|
||||
// Reduce fatigue
|
||||
// somewhat of a guess, but using the weapon weight makes sense
|
||||
const float fFatigueAttackBase = gmst.find("fFatigueAttackBase")->getFloat();
|
||||
const float fFatigueAttackMult = gmst.find("fFatigueAttackMult")->getFloat();
|
||||
const float fWeaponFatigueMult = gmst.find("fWeaponFatigueMult")->getFloat();
|
||||
MWMechanics::CreatureStats& attackerStats = actor.getClass().getCreatureStats(actor);
|
||||
MWMechanics::DynamicStat<float> fatigue = attackerStats.getFatigue();
|
||||
const float normalizedEncumbrance = actor.getClass().getEncumbrance(actor) / actor.getClass().getCapacity(actor);
|
||||
float fatigueLoss = fFatigueAttackBase + normalizedEncumbrance * fFatigueAttackMult;
|
||||
if (!weapon->isEmpty())
|
||||
fatigueLoss += weapon->getClass().getWeight(*weapon) * attackerStats.getAttackStrength() * fWeaponFatigueMult;
|
||||
fatigue.setCurrent(fatigue.getCurrent() - fatigueLoss);
|
||||
attackerStats.setFatigue(fatigue);
|
||||
|
||||
if (weapon->get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::MarksmanThrown)
|
||||
{
|
||||
// Thrown weapons get detached now
|
||||
NifOgre::ObjectScenePtr objects = getWeapon();
|
||||
|
||||
Ogre::Vector3 launchPos(0,0,0);
|
||||
if (objects->mSkelBase)
|
||||
{
|
||||
launchPos = objects->mSkelBase->getParentNode()->_getDerivedPosition();
|
||||
}
|
||||
else if (objects->mEntities.size())
|
||||
{
|
||||
objects->mEntities[0]->getParentNode()->needUpdate(true);
|
||||
launchPos = objects->mEntities[0]->getParentNode()->_getDerivedPosition();
|
||||
}
|
||||
|
||||
float fThrownWeaponMinSpeed = gmst.find("fThrownWeaponMinSpeed")->getFloat();
|
||||
float fThrownWeaponMaxSpeed = gmst.find("fThrownWeaponMaxSpeed")->getFloat();
|
||||
float speed = fThrownWeaponMinSpeed + (fThrownWeaponMaxSpeed - fThrownWeaponMinSpeed) *
|
||||
actor.getClass().getCreatureStats(actor).getAttackStrength();
|
||||
|
||||
MWBase::Environment::get().getWorld()->launchProjectile(actor, *weapon, launchPos, orient, *weapon, speed);
|
||||
|
||||
showWeapon(false);
|
||||
|
||||
inv.remove(*weapon, 1, actor);
|
||||
}
|
||||
else
|
||||
{
|
||||
// With bows and crossbows only the used arrow/bolt gets detached
|
||||
MWWorld::ContainerStoreIterator ammo = inv.getSlot(MWWorld::InventoryStore::Slot_Ammunition);
|
||||
if (ammo == inv.end())
|
||||
return;
|
||||
|
||||
Ogre::Vector3 launchPos(0,0,0);
|
||||
if (mAmmunition->mSkelBase)
|
||||
{
|
||||
launchPos = mAmmunition->mSkelBase->getParentNode()->_getDerivedPosition();
|
||||
}
|
||||
else if (mAmmunition->mEntities.size())
|
||||
{
|
||||
mAmmunition->mEntities[0]->getParentNode()->needUpdate(true);
|
||||
launchPos = mAmmunition->mEntities[0]->getParentNode()->_getDerivedPosition();
|
||||
}
|
||||
|
||||
float fProjectileMinSpeed = gmst.find("fProjectileMinSpeed")->getFloat();
|
||||
float fProjectileMaxSpeed = gmst.find("fProjectileMaxSpeed")->getFloat();
|
||||
float speed = fProjectileMinSpeed + (fProjectileMaxSpeed - fProjectileMinSpeed) * actor.getClass().getCreatureStats(actor).getAttackStrength();
|
||||
|
||||
MWBase::Environment::get().getWorld()->launchProjectile(actor, *ammo, launchPos, orient, *weapon, speed);
|
||||
|
||||
inv.remove(*ammo, 1, actor);
|
||||
mAmmunition.setNull();
|
||||
}
|
||||
}
|
||||
|
||||
void WeaponAnimation::pitchSkeleton(float xrot, Ogre::SkeletonInstance* skel)
|
||||
{
|
||||
if (mPitchFactor == 0)
|
||||
return;
|
||||
|
||||
float pitch = xrot * mPitchFactor;
|
||||
Ogre::Node *node = skel->getBone("Bip01 Spine2");
|
||||
node->pitch(Ogre::Radian(-pitch/2), Ogre::Node::TS_WORLD);
|
||||
node = skel->getBone("Bip01 Spine1");
|
||||
node->pitch(Ogre::Radian(-pitch/2), Ogre::Node::TS_WORLD);
|
||||
}
|
||||
|
||||
}
|
56
apps/openmw/mwrender/weaponanimation.hpp
Normal file
|
@ -0,0 +1,56 @@
|
|||
#ifndef OPENMW_MWRENDER_WEAPONANIMATION_H
|
||||
#define OPENMW_MWRENDER_WEAPONANIMATION_H
|
||||
|
||||
#include <OgreController.h>
|
||||
|
||||
#include <components/nifogre/ogrenifloader.hpp>
|
||||
|
||||
#include "../mwworld/ptr.hpp"
|
||||
|
||||
namespace MWRender
|
||||
{
|
||||
|
||||
class Animation;
|
||||
|
||||
class WeaponAnimationTime : public Ogre::ControllerValue<Ogre::Real>
|
||||
{
|
||||
private:
|
||||
Animation* mAnimation;
|
||||
std::string mWeaponGroup;
|
||||
float mStartTime;
|
||||
public:
|
||||
WeaponAnimationTime(Animation* animation) : mAnimation(animation), mStartTime(0) {}
|
||||
void setGroup(const std::string& group);
|
||||
void updateStartTime();
|
||||
|
||||
virtual Ogre::Real getValue() const;
|
||||
virtual void setValue(Ogre::Real value)
|
||||
{ }
|
||||
};
|
||||
|
||||
/// Handles attach & release of projectiles for ranged weapons
|
||||
class WeaponAnimation
|
||||
{
|
||||
public:
|
||||
WeaponAnimation() : mPitchFactor(0) {}
|
||||
|
||||
virtual void attachArrow(MWWorld::Ptr actor);
|
||||
virtual void releaseArrow(MWWorld::Ptr actor);
|
||||
|
||||
protected:
|
||||
NifOgre::ObjectScenePtr mAmmunition;
|
||||
|
||||
virtual NifOgre::ObjectScenePtr getWeapon() = 0;
|
||||
virtual void showWeapon(bool show) = 0;
|
||||
virtual void configureAddedObject(NifOgre::ObjectScenePtr object, MWWorld::Ptr ptr, int slot) = 0;
|
||||
|
||||
/// A relative factor (0-1) that decides if and how much the skeleton should be pitched
|
||||
/// to indicate the facing orientation of the character, for ranged weapon aiming.
|
||||
float mPitchFactor;
|
||||
|
||||
void pitchSkeleton(float xrot, Ogre::SkeletonInstance* skel);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -121,7 +121,7 @@ namespace MWScript
|
|||
|
||||
std::string itemName;
|
||||
for (MWWorld::ContainerStoreIterator iter(store.begin()); iter != store.end(); ++iter)
|
||||
if (Misc::StringUtils::ciEqual(iter->getCellRef().mRefID, item))
|
||||
if (::Misc::StringUtils::ciEqual(iter->getCellRef().mRefID, item))
|
||||
itemName = iter->getClass().getName(*iter);
|
||||
|
||||
int numRemoved = store.remove(item, count, ptr);
|
||||
|
@ -165,7 +165,7 @@ namespace MWScript
|
|||
MWWorld::ContainerStoreIterator it = invStore.begin();
|
||||
for (; it != invStore.end(); ++it)
|
||||
{
|
||||
if (Misc::StringUtils::ciEqual(it->getCellRef().mRefID, item))
|
||||
if (::Misc::StringUtils::ciEqual(it->getCellRef().mRefID, item))
|
||||
break;
|
||||
}
|
||||
if (it == invStore.end())
|
||||
|
@ -268,7 +268,7 @@ namespace MWScript
|
|||
for (int slot = 0; slot < MWWorld::InventoryStore::Slots; ++slot)
|
||||
{
|
||||
MWWorld::ContainerStoreIterator it = invStore.getSlot (slot);
|
||||
if (it != invStore.end() && Misc::StringUtils::ciEqual(it->getCellRef().mRefID, item))
|
||||
if (it != invStore.end() && ::Misc::StringUtils::ciEqual(it->getCellRef().mRefID, item))
|
||||
{
|
||||
runtime.push(1);
|
||||
return;
|
||||
|
@ -295,7 +295,7 @@ namespace MWScript
|
|||
it != invStore.end(); ++it)
|
||||
{
|
||||
|
||||
if (Misc::StringUtils::ciEqual(it->getCellRef().mSoul, name))
|
||||
if (::Misc::StringUtils::ciEqual(it->getCellRef().mSoul, name))
|
||||
{
|
||||
runtime.push(1);
|
||||
return;
|
||||
|
|
|
@ -24,7 +24,7 @@ namespace MWScript
|
|||
void GlobalScripts::addScript (const std::string& name)
|
||||
{
|
||||
std::map<std::string, std::pair<bool, Locals> >::iterator iter =
|
||||
mScripts.find (Misc::StringUtils::lowerCase (name));
|
||||
mScripts.find (::Misc::StringUtils::lowerCase (name));
|
||||
|
||||
if (iter==mScripts.end())
|
||||
{
|
||||
|
@ -44,7 +44,7 @@ namespace MWScript
|
|||
void GlobalScripts::removeScript (const std::string& name)
|
||||
{
|
||||
std::map<std::string, std::pair<bool, Locals> >::iterator iter =
|
||||
mScripts.find (Misc::StringUtils::lowerCase (name));
|
||||
mScripts.find (::Misc::StringUtils::lowerCase (name));
|
||||
|
||||
if (iter!=mScripts.end())
|
||||
iter->second.first = false;
|
||||
|
@ -53,7 +53,7 @@ namespace MWScript
|
|||
bool GlobalScripts::isRunning (const std::string& name) const
|
||||
{
|
||||
std::map<std::string, std::pair<bool, Locals> >::const_iterator iter =
|
||||
mScripts.find (Misc::StringUtils::lowerCase (name));
|
||||
mScripts.find (::Misc::StringUtils::lowerCase (name));
|
||||
|
||||
if (iter==mScripts.end())
|
||||
return false;
|
||||
|
@ -151,7 +151,7 @@ namespace MWScript
|
|||
|
||||
Locals& GlobalScripts::getLocals (const std::string& name)
|
||||
{
|
||||
std::string name2 = Misc::StringUtils::lowerCase (name);
|
||||
std::string name2 = ::Misc::StringUtils::lowerCase (name);
|
||||
std::map<std::string, std::pair<bool, Locals> >::iterator iter =
|
||||
mScripts.find (name2);
|
||||
|
||||
|
|
|
@ -113,7 +113,7 @@ namespace MWScript
|
|||
virtual void execute (Interpreter::Runtime& runtime)
|
||||
{
|
||||
std::string cell = (runtime.getStringLiteral (runtime[0].mInteger));
|
||||
Misc::StringUtils::toLower(cell);
|
||||
::Misc::StringUtils::toLower(cell);
|
||||
runtime.pop();
|
||||
|
||||
// "Will match complete or partial cells, so ShowMap, "Vivec" will show cells Vivec and Vivec, Fred's House as well."
|
||||
|
@ -126,7 +126,7 @@ namespace MWScript
|
|||
for (; it != cells.extEnd(); ++it)
|
||||
{
|
||||
std::string name = it->mName;
|
||||
Misc::StringUtils::toLower(name);
|
||||
::Misc::StringUtils::toLower(name);
|
||||
if (name.find(cell) != std::string::npos)
|
||||
MWBase::Environment::get().getWindowManager()->addVisitedLocation (
|
||||
it->mName,
|
||||
|
|
|
@ -540,7 +540,7 @@ namespace MWScript
|
|||
factionID = runtime.getStringLiteral (runtime[0].mInteger);
|
||||
runtime.pop();
|
||||
}
|
||||
Misc::StringUtils::toLower(factionID);
|
||||
::Misc::StringUtils::toLower(factionID);
|
||||
if(factionID != "")
|
||||
{
|
||||
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
|
||||
|
@ -569,7 +569,7 @@ namespace MWScript
|
|||
factionID = runtime.getStringLiteral (runtime[0].mInteger);
|
||||
runtime.pop();
|
||||
}
|
||||
Misc::StringUtils::toLower(factionID);
|
||||
::Misc::StringUtils::toLower(factionID);
|
||||
if(factionID != "")
|
||||
{
|
||||
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
|
||||
|
@ -602,7 +602,7 @@ namespace MWScript
|
|||
factionID = runtime.getStringLiteral (runtime[0].mInteger);
|
||||
runtime.pop();
|
||||
}
|
||||
Misc::StringUtils::toLower(factionID);
|
||||
::Misc::StringUtils::toLower(factionID);
|
||||
if(factionID != "")
|
||||
{
|
||||
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
|
||||
|
@ -640,7 +640,7 @@ namespace MWScript
|
|||
factionID = MWWorld::Class::get(ptr).getNpcStats(ptr).getFactionRanks().begin()->first;
|
||||
}
|
||||
}
|
||||
Misc::StringUtils::toLower(factionID);
|
||||
::Misc::StringUtils::toLower(factionID);
|
||||
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
|
||||
if(factionID!="")
|
||||
{
|
||||
|
@ -742,7 +742,7 @@ namespace MWScript
|
|||
if (factionId.empty())
|
||||
throw std::runtime_error ("failed to determine faction");
|
||||
|
||||
Misc::StringUtils::toLower (factionId);
|
||||
::Misc::StringUtils::toLower (factionId);
|
||||
|
||||
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
|
||||
runtime.push (
|
||||
|
@ -778,7 +778,7 @@ namespace MWScript
|
|||
if (factionId.empty())
|
||||
throw std::runtime_error ("failed to determine faction");
|
||||
|
||||
Misc::StringUtils::toLower (factionId);
|
||||
::Misc::StringUtils::toLower (factionId);
|
||||
|
||||
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
|
||||
MWWorld::Class::get (player).getNpcStats (player).setFactionReputation (factionId, value);
|
||||
|
@ -813,7 +813,7 @@ namespace MWScript
|
|||
if (factionId.empty())
|
||||
throw std::runtime_error ("failed to determine faction");
|
||||
|
||||
Misc::StringUtils::toLower (factionId);
|
||||
::Misc::StringUtils::toLower (factionId);
|
||||
|
||||
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
|
||||
MWWorld::Class::get (player).getNpcStats (player).setFactionReputation (factionId,
|
||||
|
@ -858,11 +858,11 @@ namespace MWScript
|
|||
MWWorld::Ptr ptr = R()(runtime);
|
||||
|
||||
std::string race = runtime.getStringLiteral(runtime[0].mInteger);
|
||||
Misc::StringUtils::toLower(race);
|
||||
::Misc::StringUtils::toLower(race);
|
||||
runtime.pop();
|
||||
|
||||
std::string npcRace = ptr.get<ESM::NPC>()->mBase->mRace;
|
||||
Misc::StringUtils::toLower(npcRace);
|
||||
::Misc::StringUtils::toLower(npcRace);
|
||||
|
||||
runtime.push (npcRace == race);
|
||||
}
|
||||
|
@ -906,7 +906,7 @@ namespace MWScript
|
|||
factionID = MWWorld::Class::get(ptr).getNpcStats(ptr).getFactionRanks().begin()->first;
|
||||
}
|
||||
}
|
||||
Misc::StringUtils::toLower(factionID);
|
||||
::Misc::StringUtils::toLower(factionID);
|
||||
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
|
||||
if(factionID!="")
|
||||
{
|
||||
|
|
|
@ -99,7 +99,7 @@ namespace MWScript
|
|||
MWBase::Environment::get().getWorld()->rotateObject(ptr,ax,ay,angle);
|
||||
}
|
||||
else
|
||||
throw std::runtime_error ("invalid ration axis: " + axis);
|
||||
throw std::runtime_error ("invalid rotation axis: " + axis);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -128,7 +128,7 @@ namespace MWScript
|
|||
runtime.push(Ogre::Radian(ptr.getCellRef().mPos.rot[2]).valueDegrees());
|
||||
}
|
||||
else
|
||||
throw std::runtime_error ("invalid ration axis: " + axis);
|
||||
throw std::runtime_error ("invalid rotation axis: " + axis);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -157,7 +157,7 @@ namespace MWScript
|
|||
runtime.push(Ogre::Radian(ptr.getRefData().getPosition().rot[2]).valueDegrees());
|
||||
}
|
||||
else
|
||||
throw std::runtime_error ("invalid ration axis: " + axis);
|
||||
throw std::runtime_error ("invalid rotation axis: " + axis);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -186,7 +186,7 @@ namespace MWScript
|
|||
runtime.push(ptr.getRefData().getPosition().pos[2]);
|
||||
}
|
||||
else
|
||||
throw std::runtime_error ("invalid rotation axis: " + axis);
|
||||
throw std::runtime_error ("invalid axis: " + axis);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -11,9 +11,10 @@
|
|||
namespace MWSound
|
||||
{
|
||||
|
||||
static void fail(const std::string &msg)
|
||||
{ throw std::runtime_error("FFmpeg exception: "+msg); }
|
||||
|
||||
void FFmpeg_Decoder::fail(const std::string &msg)
|
||||
{
|
||||
throw std::runtime_error("FFmpeg exception: "+msg);
|
||||
}
|
||||
|
||||
int FFmpeg_Decoder::readPacket(void *user_data, uint8_t *buf, int buf_size)
|
||||
{
|
||||
|
|
|
@ -61,6 +61,8 @@ namespace MWSound
|
|||
virtual void rewind();
|
||||
virtual size_t getSampleOffset();
|
||||
|
||||
void fail(const std::string &msg);
|
||||
|
||||
FFmpeg_Decoder& operator=(const FFmpeg_Decoder &rhs);
|
||||
FFmpeg_Decoder(const FFmpeg_Decoder &rhs);
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "../mwbase/mechanicsmanager.hpp"
|
||||
#include "../mwbase/scriptmanager.hpp"
|
||||
#include "../mwbase/soundmanager.hpp"
|
||||
#include "../mwbase/inputmanager.hpp"
|
||||
|
||||
#include "../mwworld/player.hpp"
|
||||
#include "../mwworld/class.hpp"
|
||||
|
@ -39,6 +40,7 @@ void MWState::StateManager::cleanup (bool force)
|
|||
MWBase::Environment::get().getScriptManager()->getGlobalScripts().clear();
|
||||
MWBase::Environment::get().getWorld()->clear();
|
||||
MWBase::Environment::get().getWindowManager()->clear();
|
||||
MWBase::Environment::get().getInputManager()->clear();
|
||||
|
||||
mState = State_NoGame;
|
||||
mCharacterManager.clearCurrentCharacter();
|
||||
|
@ -123,11 +125,10 @@ void MWState::StateManager::newGame (bool bypass)
|
|||
{
|
||||
cleanup();
|
||||
|
||||
MWBase::Environment::get().getWorld()->startNewGame (bypass);
|
||||
|
||||
if (!bypass)
|
||||
{
|
||||
MWBase::Environment::get().getWorld()->startNewGame();
|
||||
MWBase::Environment::get().getWindowManager()->setNewGame (true);
|
||||
}
|
||||
else
|
||||
MWBase::Environment::get().getWorld()->setGlobalInt ("chargenstate", -1);
|
||||
|
||||
|
|
|
@ -363,7 +363,22 @@ namespace MWWorld
|
|||
return newPtr;
|
||||
}
|
||||
|
||||
bool Class::isFlying(const Ptr &ptr) const
|
||||
bool Class::isBipedal(const Ptr &ptr) const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Class::canFly(const Ptr &ptr) const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Class::canSwim(const Ptr &ptr) const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Class::canWalk(const Ptr &ptr) const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -307,7 +307,10 @@ namespace MWWorld
|
|||
return false;
|
||||
}
|
||||
|
||||
virtual bool isFlying(const MWWorld::Ptr& ptr) const;
|
||||
virtual bool isBipedal(const MWWorld::Ptr& ptr) const;
|
||||
virtual bool canFly(const MWWorld::Ptr& ptr) const;
|
||||
virtual bool canSwim(const MWWorld::Ptr& ptr) const;
|
||||
virtual bool canWalk(const MWWorld::Ptr& ptr) const;
|
||||
|
||||
virtual int getSkill(const MWWorld::Ptr& ptr, int skill) const;
|
||||
|
||||
|
|
|
@ -130,31 +130,52 @@ namespace MWWorld
|
|||
position.z += halfExtents.z;
|
||||
|
||||
waterlevel -= halfExtents.z * 0.5;
|
||||
/*
|
||||
* A 3/4 submerged example
|
||||
*
|
||||
* +---+
|
||||
* | |
|
||||
* | | <- (original waterlevel)
|
||||
* | |
|
||||
* | | <- position <- waterlevel
|
||||
* | |
|
||||
* | |
|
||||
* | |
|
||||
* +---+ <- (original position)
|
||||
*/
|
||||
|
||||
OEngine::Physic::ActorTracer tracer;
|
||||
bool wasOnGround = false;
|
||||
bool isOnGround = false;
|
||||
Ogre::Vector3 inertia(0.0f);
|
||||
Ogre::Vector3 velocity;
|
||||
if(position.z < waterlevel || isFlying)
|
||||
|
||||
bool canWalk = ptr.getClass().canWalk(ptr);
|
||||
bool isBipedal = ptr.getClass().isBipedal(ptr);
|
||||
bool isNpc = ptr.getClass().isNpc();
|
||||
|
||||
if(position.z < waterlevel || isFlying) // under water by 3/4 or can fly
|
||||
{
|
||||
// TODO: Shouldn't water have higher drag in calculating velocity?
|
||||
velocity = (Ogre::Quaternion(Ogre::Radian(refpos.rot[2]), Ogre::Vector3::NEGATIVE_UNIT_Z)*
|
||||
Ogre::Quaternion(Ogre::Radian(refpos.rot[0]), Ogre::Vector3::NEGATIVE_UNIT_X)) * movement;
|
||||
}
|
||||
else
|
||||
{
|
||||
velocity = Ogre::Quaternion(Ogre::Radian(refpos.rot[2]), Ogre::Vector3::NEGATIVE_UNIT_Z) * movement;
|
||||
// not in water nor can fly, so need to deal with gravity
|
||||
if(!physicActor->getOnGround())
|
||||
{
|
||||
// If falling, add part of the incoming velocity with the current inertia
|
||||
velocity = velocity*time + physicActor->getInertialForce();
|
||||
velocity = velocity * time + physicActor->getInertialForce();
|
||||
}
|
||||
inertia = velocity;
|
||||
inertia = velocity; // REM velocity is for z axis only in this code block
|
||||
|
||||
if(!(movement.z > 0.0f))
|
||||
{
|
||||
wasOnGround = physicActor->getOnGround();
|
||||
tracer.doTrace(colobj, position, position-Ogre::Vector3(0,0,2), engine);
|
||||
// TODO: Find out if there is a significance with the value 2 used here
|
||||
tracer.doTrace(colobj, position, position - Ogre::Vector3(0,0,2), engine);
|
||||
if(tracer.mFraction < 1.0f && getSlope(tracer.mPlaneNormal) <= sMaxSlope)
|
||||
isOnGround = true;
|
||||
}
|
||||
|
@ -163,24 +184,38 @@ namespace MWWorld
|
|||
if(isOnGround)
|
||||
{
|
||||
// if we're on the ground, don't try to fall
|
||||
velocity.z = std::max(0.0f, velocity.z);
|
||||
velocity.z = std::max(0.0f, velocity.z); // NOTE: two different velocity assignments above
|
||||
}
|
||||
|
||||
Ogre::Vector3 newPosition = position;
|
||||
/*
|
||||
* A loop to find newPosition using tracer, if successful different from the starting position.
|
||||
* nextpos is the local variable used to find potential newPosition, using velocity and remainingTime
|
||||
* The initial velocity was set earlier (see above).
|
||||
*/
|
||||
float remainingTime = time;
|
||||
for(int iterations = 0;iterations < sMaxIterations && remainingTime > 0.01f;++iterations)
|
||||
for(int iterations = 0; iterations < sMaxIterations && remainingTime > 0.01f; ++iterations)
|
||||
{
|
||||
Ogre::Vector3 nextpos = newPosition + velocity*remainingTime;
|
||||
Ogre::Vector3 nextpos = newPosition + velocity * remainingTime;
|
||||
|
||||
if(newPosition.z < waterlevel && !isFlying &&
|
||||
nextpos.z > waterlevel && newPosition.z <= waterlevel)
|
||||
// If not able to fly, walk or bipedal don't allow to move out of water
|
||||
// TODO: this if condition may not work for large creatures or situations
|
||||
// where the creature gets above the waterline for some reason
|
||||
if(newPosition.z < waterlevel && // started 3/4 under water
|
||||
!isFlying && // can't fly
|
||||
!canWalk && // can't walk
|
||||
!isBipedal && // not bipedal (assume bipedals can walk)
|
||||
!isNpc && // FIXME: shouldn't really need this
|
||||
nextpos.z > waterlevel && // but about to go above water
|
||||
newPosition.z <= waterlevel)
|
||||
{
|
||||
const Ogre::Vector3 down(0,0,-1);
|
||||
Ogre::Real movelen = velocity.normalise();
|
||||
Ogre::Vector3 reflectdir = velocity.reflect(down);
|
||||
reflectdir.normalise();
|
||||
velocity = slide(reflectdir, down)*movelen;
|
||||
continue;
|
||||
// NOTE: remainingTime is unchanged before the loop continues
|
||||
continue; // velocity updated, calculate nextpos again
|
||||
}
|
||||
|
||||
// trace to where character would go if there were no obstructions
|
||||
|
@ -189,13 +224,14 @@ namespace MWWorld
|
|||
// check for obstructions
|
||||
if(tracer.mFraction >= 1.0f)
|
||||
{
|
||||
newPosition = tracer.mEndPos;
|
||||
remainingTime *= (1.0f-tracer.mFraction);
|
||||
newPosition = tracer.mEndPos; // ok to move, so set newPosition
|
||||
remainingTime *= (1.0f-tracer.mFraction); // FIXME: remainingTime is no longer used so don't set it?
|
||||
break;
|
||||
}
|
||||
|
||||
// We hit something. Try to step up onto it.
|
||||
if(stepMove(colobj, newPosition, velocity, remainingTime, engine))
|
||||
// NOTE: May need to stop slaughterfish step out of the water.
|
||||
if((canWalk || isBipedal || isNpc) && stepMove(colobj, newPosition, velocity, remainingTime, engine))
|
||||
isOnGround = !(newPosition.z < waterlevel || isFlying); // Only on the ground if there's gravity
|
||||
else
|
||||
{
|
||||
|
@ -214,7 +250,7 @@ namespace MWWorld
|
|||
|
||||
if(isOnGround || wasOnGround)
|
||||
{
|
||||
tracer.doTrace(colobj, newPosition, newPosition-Ogre::Vector3(0,0,sStepSize+2.0f), engine);
|
||||
tracer.doTrace(colobj, newPosition, newPosition - Ogre::Vector3(0,0,sStepSize+2.0f), engine);
|
||||
if(tracer.mFraction < 1.0f && getSlope(tracer.mPlaneNormal) <= sMaxSlope)
|
||||
{
|
||||
newPosition.z = tracer.mEndPos.z + 1.0f;
|
||||
|
@ -236,7 +272,7 @@ namespace MWWorld
|
|||
}
|
||||
physicActor->setOnGround(isOnGround);
|
||||
|
||||
newPosition.z -= halfExtents.z;
|
||||
newPosition.z -= halfExtents.z; // remove what was added at the beggining
|
||||
return newPosition;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -121,13 +121,15 @@ namespace MWWorld
|
|||
const Files::Collections& fileCollections,
|
||||
const std::vector<std::string>& contentFiles,
|
||||
const boost::filesystem::path& resDir, const boost::filesystem::path& cacheDir,
|
||||
ToUTF8::Utf8Encoder* encoder, const std::map<std::string,std::string>& fallbackMap, int mActivationDistanceOverride)
|
||||
ToUTF8::Utf8Encoder* encoder, const std::map<std::string,std::string>& fallbackMap,
|
||||
int activationDistanceOverride, const std::string& startCell)
|
||||
: mPlayer (0), mLocalScripts (mStore),
|
||||
mSky (true), mCells (mStore, mEsm),
|
||||
mActivationDistanceOverride (mActivationDistanceOverride),
|
||||
mActivationDistanceOverride (activationDistanceOverride),
|
||||
mFallback(fallbackMap), mPlayIntro(0), mTeleportEnabled(true), mLevitationEnabled(true),
|
||||
mFacedDistance(FLT_MAX), mGodMode(false), mContentFiles (contentFiles),
|
||||
mGoToJail(false)
|
||||
mGoToJail(false),
|
||||
mStartCell (startCell)
|
||||
{
|
||||
mPhysics = new PhysicsSystem(renderer);
|
||||
mPhysEngine = mPhysics->getEngine();
|
||||
|
@ -168,7 +170,7 @@ namespace MWWorld
|
|||
mWorldScene = new Scene(*mRendering, mPhysics);
|
||||
}
|
||||
|
||||
void World::startNewGame()
|
||||
void World::startNewGame (bool bypass)
|
||||
{
|
||||
mGoToJail = false;
|
||||
mLevitationEnabled = true;
|
||||
|
@ -181,23 +183,44 @@ namespace MWWorld
|
|||
|
||||
MWBase::Environment::get().getWindowManager()->updatePlayer();
|
||||
|
||||
// FIXME: this will add cell 0,0 as visible on the global map
|
||||
ESM::Position pos;
|
||||
const int cellSize = 8192;
|
||||
pos.pos[0] = cellSize/2;
|
||||
pos.pos[1] = cellSize/2;
|
||||
pos.pos[2] = 0;
|
||||
pos.rot[0] = 0;
|
||||
pos.rot[1] = 0;
|
||||
pos.rot[2] = 0;
|
||||
mWorldScene->changeToExteriorCell(pos);
|
||||
if (bypass && !mStartCell.empty())
|
||||
{
|
||||
ESM::Position pos;
|
||||
|
||||
// FIXME: should be set to 1, but the sound manager won't pause newly started sounds
|
||||
mPlayIntro = 2;
|
||||
if (findExteriorPosition (mStartCell, pos))
|
||||
{
|
||||
changeToExteriorCell (pos);
|
||||
}
|
||||
else
|
||||
{
|
||||
findInteriorPosition (mStartCell, pos);
|
||||
changeToInteriorCell (mStartCell, pos);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/// \todo if !bypass, do not add player location to global map for the duration of one
|
||||
/// frame
|
||||
ESM::Position pos;
|
||||
const int cellSize = 8192;
|
||||
pos.pos[0] = cellSize/2;
|
||||
pos.pos[1] = cellSize/2;
|
||||
pos.pos[2] = 0;
|
||||
pos.rot[0] = 0;
|
||||
pos.rot[1] = 0;
|
||||
pos.rot[2] = 0;
|
||||
mWorldScene->changeToExteriorCell(pos);
|
||||
}
|
||||
|
||||
// set new game mark
|
||||
mGlobalVariables["chargenstate"].setInteger (1);
|
||||
mGlobalVariables["pcrace"].setInteger (3);
|
||||
if (!bypass)
|
||||
{
|
||||
// FIXME: should be set to 1, but the sound manager won't pause newly started sounds
|
||||
mPlayIntro = 2;
|
||||
|
||||
// set new game mark
|
||||
mGlobalVariables["chargenstate"].setInteger (1);
|
||||
mGlobalVariables["pcrace"].setInteger (3);
|
||||
}
|
||||
|
||||
// we don't want old weather to persist on a new game
|
||||
delete mWeatherManager;
|
||||
|
@ -1626,7 +1649,7 @@ namespace MWWorld
|
|||
if (ptr.getClass().getCreatureStats(ptr).isDead())
|
||||
return false;
|
||||
|
||||
if (ptr.getClass().isFlying(ptr))
|
||||
if (ptr.getClass().canFly(ptr))
|
||||
return true;
|
||||
|
||||
const MWMechanics::CreatureStats &stats = ptr.getClass().getCreatureStats(ptr);
|
||||
|
|
|
@ -120,6 +120,9 @@ namespace MWWorld
|
|||
|
||||
std::map<MWWorld::Ptr, MagicBoltState> mMagicBolts;
|
||||
std::map<MWWorld::Ptr, ProjectileState> mProjectiles;
|
||||
|
||||
std::string mStartCell;
|
||||
|
||||
void updateWeather(float duration);
|
||||
int getDaysPerMonth (int month) const;
|
||||
|
||||
|
@ -179,11 +182,13 @@ namespace MWWorld
|
|||
const Files::Collections& fileCollections,
|
||||
const std::vector<std::string>& contentFiles,
|
||||
const boost::filesystem::path& resDir, const boost::filesystem::path& cacheDir,
|
||||
ToUTF8::Utf8Encoder* encoder, const std::map<std::string,std::string>& fallbackMap, int mActivationDistanceOverride);
|
||||
ToUTF8::Utf8Encoder* encoder, const std::map<std::string,std::string>& fallbackMap,
|
||||
int activationDistanceOverride, const std::string& startCell);
|
||||
|
||||
virtual ~World();
|
||||
|
||||
virtual void startNewGame();
|
||||
virtual void startNewGame (bool bypass);
|
||||
///< \param bypass Bypass regular game start.
|
||||
|
||||
virtual void clear();
|
||||
|
||||
|
|
|
@ -1,26 +1,75 @@
|
|||
function(enable_unity_build UB_SUFFIX SOURCE_VARIABLE_NAME)
|
||||
set(files ${SOURCE_VARIABLE_NAME})
|
||||
# Generate a unique filename for the unity build translation unit
|
||||
set(unit_build_file ${CMAKE_CURRENT_BINARY_DIR}/ub_${UB_SUFFIX}.cpp)
|
||||
# Exclude all translation units from compilation
|
||||
set_source_files_properties(${files} PROPERTIES HEADER_FILE_ONLY true)
|
||||
# Open the ub file
|
||||
FILE(WRITE ${unit_build_file} "// Unity Build generated by CMake\n")
|
||||
# Add include statement for each translation unit
|
||||
foreach(source_file ${files} )
|
||||
FILE( APPEND ${unit_build_file} "#include <${source_file}>\n")
|
||||
endforeach(source_file)
|
||||
# Complement list of translation units with the name of ub
|
||||
set(${SOURCE_VARIABLE_NAME} ${${SOURCE_VARIABLE_NAME}} ${unit_build_file} PARENT_SCOPE)
|
||||
endfunction(enable_unity_build)
|
||||
|
||||
|
||||
|
||||
macro (add_openmw_dir dir)
|
||||
set (files)
|
||||
foreach (u ${ARGN})
|
||||
file (GLOB ALL "${dir}/${u}.[ch]pp")
|
||||
foreach (f ${ALL})
|
||||
list (APPEND files "${f}")
|
||||
list (APPEND OPENMW_FILES "${f}")
|
||||
endforeach (f)
|
||||
endforeach (u)
|
||||
source_group ("apps\\openmw\\${dir}" FILES ${files})
|
||||
set (files)
|
||||
set (cppfiles)
|
||||
foreach (u ${ARGN})
|
||||
|
||||
# Add cpp and hpp to OPENMW_FILES
|
||||
file (GLOB ALL "${dir}/${u}.[ch]pp")
|
||||
foreach (f ${ALL})
|
||||
list (APPEND files "${f}")
|
||||
list (APPEND OPENMW_FILES "${f}")
|
||||
endforeach (f)
|
||||
|
||||
# Add cpp to unity build
|
||||
file (GLOB ALL "${dir}/${u}.cpp")
|
||||
foreach (f ${ALL})
|
||||
list (APPEND cppfiles "${f}")
|
||||
endforeach (f)
|
||||
|
||||
endforeach (u)
|
||||
|
||||
if (OPENMW_UNITY_BUILD)
|
||||
enable_unity_build(${dir} "${cppfiles}")
|
||||
list (APPEND OPENMW_FILES ${CMAKE_CURRENT_BINARY_DIR}/ub_${dir}.cpp)
|
||||
endif()
|
||||
|
||||
source_group ("apps\\openmw\\${dir}" FILES ${files})
|
||||
endmacro (add_openmw_dir)
|
||||
|
||||
macro (add_component_dir dir)
|
||||
set (files)
|
||||
foreach (u ${ARGN})
|
||||
file (GLOB ALL "${dir}/${u}.[ch]pp")
|
||||
foreach (f ${ALL})
|
||||
list (APPEND files "${f}")
|
||||
list (APPEND COMPONENT_FILES "${f}")
|
||||
endforeach (f)
|
||||
endforeach (u)
|
||||
source_group ("components\\${dir}" FILES ${files})
|
||||
set (files)
|
||||
set (cppfiles)
|
||||
|
||||
foreach (u ${ARGN})
|
||||
file (GLOB ALL "${dir}/${u}.[ch]pp")
|
||||
|
||||
foreach (f ${ALL})
|
||||
list (APPEND files "${f}")
|
||||
list (APPEND COMPONENT_FILES "${f}")
|
||||
endforeach (f)
|
||||
|
||||
# Add cpp to unity build
|
||||
file (GLOB ALL "${dir}/${u}.cpp")
|
||||
foreach (f ${ALL})
|
||||
list (APPEND cppfiles "${f}")
|
||||
endforeach (f)
|
||||
|
||||
endforeach (u)
|
||||
|
||||
if (OPENMW_UNITY_BUILD)
|
||||
enable_unity_build(${dir} "${cppfiles}")
|
||||
list (APPEND COMPONENT_FILES ${CMAKE_CURRENT_BINARY_DIR}/ub_${dir}.cpp)
|
||||
endif()
|
||||
|
||||
source_group ("components\\${dir}" FILES ${files})
|
||||
endmacro (add_component_dir)
|
||||
|
||||
macro (add_component_qt_dir dir)
|
||||
|
|
|
@ -111,7 +111,7 @@ void BSAFile::readHeader()
|
|||
fail("Directory information larger than entire archive");
|
||||
|
||||
// Read the offset info into a temporary buffer
|
||||
vector<uint32_t> offsets(3*filenum);
|
||||
std::vector<uint32_t> offsets(3*filenum);
|
||||
input.read(reinterpret_cast<char*>(&offsets[0]), 12*filenum);
|
||||
|
||||
// Read the string table
|
||||
|
|
|
@ -18,7 +18,7 @@ bool Compiler::DeclarationParser::parseName (const std::string& name, const Toke
|
|||
{
|
||||
if (mState==State_Name)
|
||||
{
|
||||
std::string name2 = Misc::StringUtils::lowerCase (name);
|
||||
std::string name2 = ::Misc::StringUtils::lowerCase (name);
|
||||
|
||||
char type = mLocals.getType (name2);
|
||||
|
||||
|
@ -80,4 +80,4 @@ bool Compiler::DeclarationParser::parseSpecial (int code, const TokenLoc& loc, S
|
|||
void Compiler::DeclarationParser::reset()
|
||||
{
|
||||
mState = State_Begin;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -50,7 +50,7 @@ namespace Interpreter
|
|||
return literalBlock+offset;
|
||||
}
|
||||
|
||||
void Runtime::configure (const Interpreter::Type_Code *code, int codeSize, Context& context)
|
||||
void Runtime::configure (const Type_Code *code, int codeSize, Context& context)
|
||||
{
|
||||
clear();
|
||||
|
||||
|
|
|
@ -282,9 +282,6 @@ bool QuadTreeNode::update(const Ogre::Vector3 &cameraPos)
|
|||
size_t wantedLod = 0;
|
||||
float cellWorldSize = mTerrain->getStorage()->getCellWorldSize();
|
||||
|
||||
if (!mTerrain->getDistantLandEnabled() && dist > cellWorldSize)
|
||||
return true;
|
||||
|
||||
if (dist > cellWorldSize*64)
|
||||
wantedLod = 6;
|
||||
else if (dist > cellWorldSize*32)
|
||||
|
@ -357,6 +354,7 @@ bool QuadTreeNode::update(const Ogre::Vector3 &cameraPos)
|
|||
|
||||
if (!childrenLoaded)
|
||||
{
|
||||
mChunk->setVisible(true);
|
||||
// Make sure child scene nodes are detached until all children are loaded
|
||||
mSceneNode->removeAllChildren();
|
||||
}
|
||||
|
@ -391,6 +389,8 @@ void QuadTreeNode::load(const LoadResponseData &data)
|
|||
mChunk = new Chunk(mTerrain->getBufferCache().getUVBuffer(), mBounds, data);
|
||||
mChunk->setVisibilityFlags(mTerrain->getVisiblityFlags());
|
||||
mChunk->setCastShadows(true);
|
||||
if (!mTerrain->getDistantLandEnabled())
|
||||
mChunk->setRenderingDistance(8192);
|
||||
mSceneNode->attachObject(mChunk);
|
||||
|
||||
mMaterialGenerator->enableShadows(mTerrain->getShadowsEnabled());
|
||||
|
@ -437,7 +437,7 @@ void QuadTreeNode::unload(bool recursive)
|
|||
if (recursive && hasChildren())
|
||||
{
|
||||
for (int i=0; i<4; ++i)
|
||||
mChildren[i]->unload();
|
||||
mChildren[i]->unload(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -82,12 +82,14 @@ Sandy Carter (bwrsandman) - Arch Linux
|
|||
|
||||
|
||||
Public Relations and Translations:
|
||||
Alex McKibben (WeirdSexy) - Podcaster
|
||||
Artem Kotsynyak (greye) - Russian News Writer
|
||||
Jim Clauwaert (Zedd) - Public Outreach
|
||||
Julien Voisin (jvoisin/ap0) - French News Writer
|
||||
Lukasz Gromanowski (lgro) - English News Writer
|
||||
Mickey Lyle (raevol) - Release Manager
|
||||
Pithorn - Chinese News Writer
|
||||
sir_herrbatka - English/Polish News Writer
|
||||
Alex McKibben (WeirdSexy) - Podcaster
|
||||
sir_herrbatka - Polish News Writer
|
||||
|
||||
|
||||
Website:
|
||||
|
|
|
@ -2,5 +2,11 @@
|
|||
|
||||
<MyGUI type="Layout">
|
||||
<!-- The entire screen -->
|
||||
<Widget type="Widget" layer="Windows" position="0 0 300 300" name="_Main" />
|
||||
<Widget type="Widget" layer="Windows" position="0 0 300 300" name="_Main" >
|
||||
<Widget type="TextBox" skin="SandText" position="0 250 300 50" align="Bottom" name="VersionText">
|
||||
<Property key="TextAlign" value="Center"/>
|
||||
<Property key="TextShadow" value="true"/>
|
||||
<Property key="TextShadowColour" value="0 0 0"/>
|
||||
</Widget>
|
||||
</Widget>
|
||||
</MyGUI>
|
||||
|
|
BIN
files/opencs/add.png
Normal file
After Width: | Height: | Size: 520 B |
BIN
files/opencs/edit-clone.png
Normal file
After Width: | Height: | Size: 472 B |
BIN
files/opencs/edit-delete.png
Normal file
After Width: | Height: | Size: 680 B |
BIN
files/opencs/edit-preview.png
Normal file
After Width: | Height: | Size: 525 B |
BIN
files/opencs/edit-undo.png
Normal file
After Width: | Height: | Size: 650 B |
BIN
files/opencs/go-next.png
Normal file
After Width: | Height: | Size: 676 B |
BIN
files/opencs/go-previous.png
Normal file
After Width: | Height: | Size: 655 B |
|
@ -57,6 +57,13 @@
|
|||
<file>static.png</file>
|
||||
<file>weapon.png</file>
|
||||
<file>multitype.png</file>
|
||||
<file>go-next.png</file>
|
||||
<file>go-previous.png</file>
|
||||
<file>edit-delete.png</file>
|
||||
<file>edit-undo.png</file>
|
||||
<file>edit-preview.png</file>
|
||||
<file>edit-clone.png</file>
|
||||
<file>add.png</file>
|
||||
<file alias="startup/create-addon">raster/startup/big/create-addon.png</file>
|
||||
<file alias="startup/create-game">raster/startup/big/new-game.png</file>
|
||||
<file alias="startup/edit-content">raster/startup/big/edit-content.png</file>
|
||||
|
|
|
@ -8,7 +8,6 @@ License: GPL (see GPL3.txt for more information)
|
|||
Website: http://www.openmw.org
|
||||
|
||||
Font Licenses:
|
||||
EBGaramond-Regular.ttf: OFL (see OFL.txt for more information)
|
||||
DejaVuLGCSansMono.ttf: custom (see DejaVu Font License.txt for more information)
|
||||
|
||||
|
||||
|
|