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(BOOST_STATIC "Link static build of Boost into the binaries" FALSE)
|
||||||
option(SDL2_STATIC "Link static build of SDL 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
|
# Apps and tools
|
||||||
option(BUILD_BSATOOL "build BSA extractor" OFF)
|
option(BUILD_BSATOOL "build BSA extractor" OFF)
|
||||||
option(BUILD_ESMTOOL "build ESM inspector" ON)
|
option(BUILD_ESMTOOL "build ESM inspector" ON)
|
||||||
|
@ -463,7 +465,6 @@ if(WIN32)
|
||||||
INSTALL(FILES
|
INSTALL(FILES
|
||||||
"${OpenMW_SOURCE_DIR}/readme.txt"
|
"${OpenMW_SOURCE_DIR}/readme.txt"
|
||||||
"${OpenMW_SOURCE_DIR}/GPL3.txt"
|
"${OpenMW_SOURCE_DIR}/GPL3.txt"
|
||||||
"${OpenMW_SOURCE_DIR}/OFL.txt"
|
|
||||||
"${OpenMW_SOURCE_DIR}/DejaVu Font License.txt"
|
"${OpenMW_SOURCE_DIR}/DejaVu Font License.txt"
|
||||||
"${OpenMW_BINARY_DIR}/settings-default.cfg"
|
"${OpenMW_BINARY_DIR}/settings-default.cfg"
|
||||||
"${OpenMW_BINARY_DIR}/transparency-overrides.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
|
opencs_units (view/world
|
||||||
table tablesubview scriptsubview util regionmapsubview tablebottombox creator genericcreator
|
table tablesubview scriptsubview util regionmapsubview tablebottombox creator genericcreator
|
||||||
cellcreator referenceablecreator referencecreator scenesubview scenetoolbar scenetool
|
cellcreator referenceablecreator referencecreator scenesubview scenetoolbar scenetool
|
||||||
scenetoolmode infocreator scriptedit previewsubview
|
scenetoolmode infocreator scriptedit dialoguesubview previewsubview
|
||||||
)
|
)
|
||||||
|
|
||||||
opencs_units (view/render
|
opencs_units (view/render
|
||||||
|
@ -73,8 +73,7 @@ opencs_units_noqt (view/render
|
||||||
)
|
)
|
||||||
|
|
||||||
opencs_units_noqt (view/world
|
opencs_units_noqt (view/world
|
||||||
dialoguesubview subviews
|
subviews enumdelegate vartypedelegate recordstatusdelegate idtypedelegate datadisplaydelegate
|
||||||
enumdelegate vartypedelegate recordstatusdelegate idtypedelegate datadisplaydelegate
|
|
||||||
scripthighlighter idvalidator dialoguecreator
|
scripthighlighter idvalidator dialoguecreator
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -18,3 +18,8 @@ std::string CSMWorld::ColumnBase::getTitle() const
|
||||||
{
|
{
|
||||||
return Columns::getName (static_cast<Columns::ColumnId> (mColumnId));
|
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_None, //Do not use
|
||||||
Display_String,
|
Display_String,
|
||||||
|
Display_LongString,
|
||||||
|
|
||||||
//CONCRETE TYPES STARTS HERE
|
//CONCRETE TYPES STARTS HERE
|
||||||
Display_Skill,
|
Display_Skill,
|
||||||
|
@ -105,6 +106,8 @@ namespace CSMWorld
|
||||||
///< Can this column be edited directly by the user?
|
///< Can this column be edited directly by the user?
|
||||||
|
|
||||||
virtual std::string getTitle() const;
|
virtual std::string getTitle() const;
|
||||||
|
|
||||||
|
virtual int getId() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename ESXRecordT>
|
template<typename ESXRecordT>
|
||||||
|
|
|
@ -201,7 +201,7 @@ namespace CSMWorld
|
||||||
struct DescriptionColumn : public Column<ESXRecordT>
|
struct DescriptionColumn : public Column<ESXRecordT>
|
||||||
{
|
{
|
||||||
DescriptionColumn()
|
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
|
virtual QVariant get (const Record<ESXRecordT>& record) const
|
||||||
|
@ -833,7 +833,7 @@ namespace CSMWorld
|
||||||
|
|
||||||
virtual bool isUserEditable() const
|
virtual bool isUserEditable() const
|
||||||
{
|
{
|
||||||
return false;
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1113,7 +1113,7 @@ namespace CSMWorld
|
||||||
|
|
||||||
virtual bool isUserEditable() const
|
virtual bool isUserEditable() const
|
||||||
{
|
{
|
||||||
return false;
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1379,7 +1379,7 @@ namespace CSMWorld
|
||||||
template<typename ESXRecordT>
|
template<typename ESXRecordT>
|
||||||
struct QuestDescriptionColumn : public Column<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
|
virtual QVariant get (const Record<ESXRecordT>& record) const
|
||||||
{
|
{
|
||||||
|
@ -1559,7 +1559,7 @@ namespace CSMWorld
|
||||||
template<typename ESXRecordT>
|
template<typename ESXRecordT>
|
||||||
struct ResponseColumn : public Column<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
|
virtual QVariant get (const Record<ESXRecordT>& record) const
|
||||||
{
|
{
|
||||||
|
|
|
@ -236,3 +236,8 @@ std::pair<CSMWorld::UniversalId, std::string> CSMWorld::IdTable::view (int row)
|
||||||
|
|
||||||
return std::make_pair (UniversalId (UniversalId::Type_Scene, id), hint);
|
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;
|
std::pair<UniversalId, std::string> view (int row) const;
|
||||||
///< Return the UniversalId and the hint for viewing \a row. If viewing is not
|
///< Return the UniversalId and the hint for viewing \a row. If viewing is not
|
||||||
/// supported by this table, return (UniversalId::Type_None, "").
|
/// supported by this table, return (UniversalId::Type_None, "").
|
||||||
|
|
||||||
|
int getColumnId(int column) const;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -444,3 +444,8 @@ CSMWorld::ColumnBase::Display CSMWorld::TableMimeData::convertEnums (CSMWorld::U
|
||||||
return CSMWorld::ColumnBase::Display_None;
|
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;
|
UniversalId returnMatching(UniversalId::Type type) const;
|
||||||
|
|
||||||
|
const CSMDoc::Document* getDocumentPtr() const;
|
||||||
|
|
||||||
UniversalId returnMatching(CSMWorld::ColumnBase::Display type) const;
|
UniversalId returnMatching(CSMWorld::ColumnBase::Display type) const;
|
||||||
|
|
||||||
static CSMWorld::UniversalId::Type convertEnums(CSMWorld::ColumnBase::Display type);
|
static CSMWorld::UniversalId::Type convertEnums(CSMWorld::ColumnBase::Display type);
|
||||||
|
|
|
@ -19,3 +19,9 @@ void CSVDoc::SubView::updateEditorSetting (const QString &settingName, const QSt
|
||||||
void CSVDoc::SubView::setStatusBar (bool show) {}
|
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
|
// not implemented
|
||||||
SubView (const SubView&);
|
SubView (const SubView&);
|
||||||
SubView& operator= (SubView&);
|
SubView& operator= (SubView&);
|
||||||
|
protected:
|
||||||
|
void setUniversalId(const CSMWorld::UniversalId& id);
|
||||||
|
|
||||||
public:
|
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)
|
/// \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())
|
if (!hint.empty())
|
||||||
view->useHint (hint);
|
view->useHint (hint);
|
||||||
|
|
||||||
|
|
|
@ -1,98 +1,663 @@
|
||||||
|
|
||||||
#include "dialoguesubview.hpp"
|
#include "dialoguesubview.hpp"
|
||||||
|
|
||||||
|
#include <utility>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
#include <QGridLayout>
|
#include <QGridLayout>
|
||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
|
#include <QSize>
|
||||||
#include <QAbstractItemModel>
|
#include <QAbstractItemModel>
|
||||||
#include <QDoubleSpinBox>
|
#include <QDoubleSpinBox>
|
||||||
#include <QSpinBox>
|
#include <QSpinBox>
|
||||||
#include <QLineEdit>
|
#include <QLineEdit>
|
||||||
|
#include <QEvent>
|
||||||
#include <QDataWidgetMapper>
|
#include <QDataWidgetMapper>
|
||||||
|
#include <QCheckBox>
|
||||||
|
#include <QLineEdit>
|
||||||
|
#include <QPlainTextEdit>
|
||||||
|
#include <QComboBox>
|
||||||
|
#include <QScrollArea>
|
||||||
|
#include <QPushButton>
|
||||||
|
#include <QToolButton>
|
||||||
|
|
||||||
#include "../../model/world/columnbase.hpp"
|
#include "../../model/world/columnbase.hpp"
|
||||||
#include "../../model/world/idtable.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,
|
#include "recordstatusdelegate.hpp"
|
||||||
bool createAndDelete)
|
#include "util.hpp"
|
||||||
: SubView (id)
|
#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);
|
QVariant v = index.data(Qt::EditRole);
|
||||||
|
if (!v.isValid())
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
int flags = model->headerData (i, Qt::Horizontal, CSMWorld::ColumnBase::Role_Flags).toInt();
|
v = index.data(Qt::DisplayRole);
|
||||||
|
if (!v.isValid())
|
||||||
if (flags & CSMWorld::ColumnBase::Flag_Dialogue)
|
|
||||||
{
|
{
|
||||||
layout->addWidget (new QLabel (model->headerData (i, Qt::Horizontal).toString()), i, 0);
|
return;
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mWidgetMapper->setCurrentModelIndex (
|
if (QVariant::String == v.type())
|
||||||
dynamic_cast<CSMWorld::IdTable&> (*model).getModelIndex (id.getId(), 0));
|
{
|
||||||
|
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)
|
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
|
#ifndef CSV_WORLD_DIALOGUESUBVIEW_H
|
||||||
#define CSV_WORLD_DIALOGUESUBVIEW_H
|
#define CSV_WORLD_DIALOGUESUBVIEW_H
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include <QAbstractItemDelegate>
|
||||||
|
#include <QScrollArea>
|
||||||
|
|
||||||
#include "../doc/subview.hpp"
|
#include "../doc/subview.hpp"
|
||||||
|
#include "../../model/world/columnbase.hpp"
|
||||||
|
|
||||||
class QDataWidgetMapper;
|
class QDataWidgetMapper;
|
||||||
|
class QSize;
|
||||||
|
class QEvent;
|
||||||
|
class QLabel;
|
||||||
|
class QVBoxLayout;
|
||||||
|
|
||||||
|
namespace CSMWorld
|
||||||
|
{
|
||||||
|
class IdTable;
|
||||||
|
}
|
||||||
|
|
||||||
namespace CSMDoc
|
namespace CSMDoc
|
||||||
{
|
{
|
||||||
|
@ -12,15 +28,181 @@ namespace CSMDoc
|
||||||
|
|
||||||
namespace CSVWorld
|
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;
|
QDataWidgetMapper *mWidgetMapper;
|
||||||
|
DialogueDelegateDispatcher mDispatcher;
|
||||||
|
QWidget* mMainWidget;
|
||||||
|
CSMWorld::IdTable* mTable;
|
||||||
|
QUndoStack& mUndoStack;
|
||||||
|
|
||||||
public:
|
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);
|
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,
|
QWidget *CSVWorld::EnumDelegate::createEditor(QWidget *parent,
|
||||||
const QModelIndex& index) const
|
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;
|
return 0;
|
||||||
|
|
||||||
QComboBox *comboBox = new QComboBox (parent);
|
QComboBox *comboBox = new QComboBox (parent);
|
||||||
|
@ -56,11 +64,22 @@ QWidget *CSVWorld::EnumDelegate::createEditor(QWidget *parent, const QStyleOptio
|
||||||
return comboBox;
|
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))
|
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();
|
std::size_t size = mValues.size();
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
#include <QStyledItemDelegate>
|
||||||
|
|
||||||
#include <components/esm/defs.hpp>
|
#include <components/esm/defs.hpp>
|
||||||
|
|
||||||
|
@ -31,10 +32,16 @@ namespace CSVWorld
|
||||||
EnumDelegate (const std::vector<std::pair<int, QString> >& values,
|
EnumDelegate (const std::vector<std::pair<int, QString> >& values,
|
||||||
QUndoStack& undoStack, QObject *parent);
|
QUndoStack& undoStack, QObject *parent);
|
||||||
|
|
||||||
virtual QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem& option,
|
virtual QWidget *createEditor(QWidget *parent,
|
||||||
const QModelIndex& index) const;
|
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,
|
virtual void paint (QPainter *painter, const QStyleOptionViewItem& option,
|
||||||
const QModelIndex& index) const;
|
const QModelIndex& index) const;
|
||||||
|
|
|
@ -80,5 +80,61 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager)
|
||||||
|
|
||||||
manager.add (CSMWorld::UniversalId::Type_Scene, new CSVDoc::SubViewFactory<SceneSubView>);
|
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>);
|
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) , "");
|
emit editRequest (CSMWorld::UniversalId (CSMWorld::UniversalId::Type_Preview, id) , "");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSVWorld::Table::updateEditorSetting (const QString &settingName, const QString &settingValue)
|
void CSVWorld::Table::updateEditorSetting (const QString &settingName, const QString &settingValue)
|
||||||
{
|
{
|
||||||
int columns = mModel->columnCount();
|
int columns = mModel->columnCount();
|
||||||
|
@ -533,27 +534,14 @@ void CSVWorld::Table::mouseMoveEvent (QMouseEvent* event)
|
||||||
|
|
||||||
drag->setMimeData (mime);
|
drag->setMimeData (mime);
|
||||||
drag->setPixmap (QString::fromStdString (mime->getIcon()));
|
drag->setPixmap (QString::fromStdString (mime->getIcon()));
|
||||||
|
drag->exec(Qt::CopyAction);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSVWorld::Table::dragEnterEvent(QDragEnterEvent *event)
|
void CSVWorld::Table::dragEnterEvent(QDragEnterEvent *event)
|
||||||
{
|
{
|
||||||
event->acceptProposedAction();
|
event->acceptProposedAction();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSVWorld::Table::dropEvent(QDropEvent *event)
|
void CSVWorld::Table::dropEvent(QDropEvent *event)
|
||||||
|
@ -585,7 +573,7 @@ void CSVWorld::Table::dropEvent(QDropEvent *event)
|
||||||
|
|
||||||
void CSVWorld::Table::dragMoveEvent(QDragMoveEvent *event)
|
void CSVWorld::Table::dragMoveEvent(QDragMoveEvent *event)
|
||||||
{
|
{
|
||||||
event->accept();
|
event->accept();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> CSVWorld::Table::getColumnsWithDisplay(CSMWorld::ColumnBase::Display display) const
|
std::vector<std::string> CSVWorld::Table::getColumnsWithDisplay(CSMWorld::ColumnBase::Display display) const
|
||||||
|
|
|
@ -4,8 +4,18 @@
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
#include <QUndoStack>
|
#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/commands.hpp"
|
||||||
|
#include "../../model/world/tablemimedata.hpp"
|
||||||
|
|
||||||
CSVWorld::NastyTableModelHack::NastyTableModelHack (QAbstractItemModel& model)
|
CSVWorld::NastyTableModelHack::NastyTableModelHack (QAbstractItemModel& model)
|
||||||
: mModel (model)
|
: mModel (model)
|
||||||
|
@ -117,10 +127,56 @@ void CSVWorld::CommandDelegate::setModelData (QWidget *editor, QAbstractItemMode
|
||||||
}
|
}
|
||||||
|
|
||||||
QWidget *CSVWorld::CommandDelegate::createEditor (QWidget *parent, const QStyleOptionViewItem& option,
|
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())
|
QVariant variant = index.data();
|
||||||
return 0;
|
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);
|
return QStyledItemDelegate::createEditor (parent, option, index);
|
||||||
}
|
}
|
||||||
|
@ -141,3 +197,66 @@ bool CSVWorld::CommandDelegate::updateEditorSetting (const QString &settingName,
|
||||||
{
|
{
|
||||||
return false;
|
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 <QAbstractTableModel>
|
||||||
#include <QStyledItemDelegate>
|
#include <QStyledItemDelegate>
|
||||||
|
#include <QLineEdit>
|
||||||
|
|
||||||
#include "../../model/world/columnbase.hpp"
|
#include "../../model/world/columnbase.hpp"
|
||||||
|
#include "../../model/doc/document.hpp"
|
||||||
|
|
||||||
class QUndoStack;
|
class QUndoStack;
|
||||||
|
|
||||||
|
namespace CSMWorld
|
||||||
|
{
|
||||||
|
class TableMimeData;
|
||||||
|
class UniversalId;
|
||||||
|
}
|
||||||
|
|
||||||
namespace CSVWorld
|
namespace CSVWorld
|
||||||
{
|
{
|
||||||
///< \brief Getting the data out of an editor widget
|
///< \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
|
///< \brief Use commands instead of manipulating the model directly
|
||||||
class CommandDelegate : public QStyledItemDelegate
|
class CommandDelegate : public QStyledItemDelegate
|
||||||
{
|
{
|
||||||
|
@ -101,8 +127,10 @@ namespace CSVWorld
|
||||||
virtual void setModelData (QWidget *editor, QAbstractItemModel *model,
|
virtual void setModelData (QWidget *editor, QAbstractItemModel *model,
|
||||||
const QModelIndex& index) const;
|
const QModelIndex& index) const;
|
||||||
|
|
||||||
virtual QWidget *createEditor (QWidget *parent, const QStyleOptionViewItem& option,
|
virtual QWidget *createEditor (QWidget *parent,
|
||||||
const QModelIndex& index) const;
|
const QStyleOptionViewItem& option,
|
||||||
|
const QModelIndex& index,
|
||||||
|
CSMWorld::ColumnBase::Display display = CSMWorld::ColumnBase::Display_None) const;
|
||||||
|
|
||||||
void setEditLock (bool locked);
|
void setEditLock (bool locked);
|
||||||
|
|
||||||
|
@ -111,6 +139,9 @@ namespace CSVWorld
|
||||||
virtual bool updateEditorSetting (const QString &settingName, const QString &settingValue);
|
virtual bool updateEditorSetting (const QString &settingName, const QString &settingValue);
|
||||||
///< \return Does column require update?
|
///< \return Does column require update?
|
||||||
|
|
||||||
|
virtual void setEditorData (QWidget *editor, const QModelIndex& index, bool tryDisplay = false) const;
|
||||||
|
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
|
|
||||||
virtual void slotUpdateEditorSetting (const QString &settingName, const QString &settingValue) {}
|
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
|
renderingmanager debugging sky camera animation npcanimation creatureanimation activatoranimation
|
||||||
actors objects renderinginterface localmap occlusionquery water shadows
|
actors objects renderinginterface localmap occlusionquery water shadows
|
||||||
characterpreview globalmap videoplayer ripplesimulation refraction
|
characterpreview globalmap videoplayer ripplesimulation refraction
|
||||||
terrainstorage renderconst effectmanager
|
terrainstorage renderconst effectmanager weaponanimation
|
||||||
)
|
)
|
||||||
|
|
||||||
add_openmw_dir (mwinput
|
add_openmw_dir (mwinput
|
||||||
|
@ -44,7 +44,7 @@ add_openmw_dir (mwscript
|
||||||
locals scriptmanagerimp compilercontext interpretercontext cellextensions miscextensions
|
locals scriptmanagerimp compilercontext interpretercontext cellextensions miscextensions
|
||||||
guiextensions soundextensions skyextensions statsextensions containerextensions
|
guiextensions soundextensions skyextensions statsextensions containerextensions
|
||||||
aiextensions controlextensions extensions globalscripts ref dialogueextensions
|
aiextensions controlextensions extensions globalscripts ref dialogueextensions
|
||||||
animationextensions transformationextensions consoleextensions userextensions locals
|
animationextensions transformationextensions consoleextensions userextensions
|
||||||
)
|
)
|
||||||
|
|
||||||
add_openmw_dir (mwsound
|
add_openmw_dir (mwsound
|
||||||
|
|
|
@ -359,7 +359,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
|
||||||
// Create the world
|
// Create the world
|
||||||
mEnvironment.setWorld( new MWWorld::World (*mOgre, mFileCollections, mContentFiles,
|
mEnvironment.setWorld( new MWWorld::World (*mOgre, mFileCollections, mContentFiles,
|
||||||
mResDir, mCfgMgr.getCachePath(), mEncoder, mFallbackMap,
|
mResDir, mCfgMgr.getCachePath(), mEncoder, mFallbackMap,
|
||||||
mActivationDistanceOverride));
|
mActivationDistanceOverride, mCellName));
|
||||||
MWBase::Environment::get().getWorld()->setupPlayer();
|
MWBase::Environment::get().getWorld()->setupPlayer();
|
||||||
input->setPlayer(&mEnvironment.getWorld()->getPlayer());
|
input->setPlayer(&mEnvironment.getWorld()->getPlayer());
|
||||||
|
|
||||||
|
@ -395,31 +395,6 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
|
||||||
mechanics->buildPlayer();
|
mechanics->buildPlayer();
|
||||||
window->updatePlayer();
|
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);
|
mOgre->getRoot()->addFrameListener (this);
|
||||||
|
|
||||||
// scripts
|
// scripts
|
||||||
|
@ -457,15 +432,15 @@ void OMW::Engine::go()
|
||||||
// Play some good 'ol tunes
|
// Play some good 'ol tunes
|
||||||
MWBase::Environment::get().getSoundManager()->playPlaylist(std::string("Explore"));
|
MWBase::Environment::get().getSoundManager()->playPlaylist(std::string("Explore"));
|
||||||
|
|
||||||
if (!mStartupScript.empty())
|
|
||||||
MWBase::Environment::get().getWindowManager()->executeInConsole (mStartupScript);
|
|
||||||
|
|
||||||
// start in main menu
|
// start in main menu
|
||||||
if (!mSkipMenu)
|
if (!mSkipMenu)
|
||||||
MWBase::Environment::get().getWindowManager()->pushGuiMode (MWGui::GM_MainMenu);
|
MWBase::Environment::get().getWindowManager()->pushGuiMode (MWGui::GM_MainMenu);
|
||||||
else
|
else
|
||||||
MWBase::Environment::get().getStateManager()->newGame (true);
|
MWBase::Environment::get().getStateManager()->newGame (true);
|
||||||
|
|
||||||
|
if (!mStartupScript.empty())
|
||||||
|
MWBase::Environment::get().getWindowManager()->executeInConsole (mStartupScript);
|
||||||
|
|
||||||
// Start the main rendering loop
|
// Start the main rendering loop
|
||||||
while (!mEnvironment.get().getStateManager()->hasQuitRequest())
|
while (!mEnvironment.get().getStateManager()->hasQuitRequest())
|
||||||
Ogre::Root::getSingleton().renderOneFrame();
|
Ogre::Root::getSingleton().renderOneFrame();
|
||||||
|
|
|
@ -20,6 +20,9 @@ namespace MWBase
|
||||||
|
|
||||||
InputManager() {}
|
InputManager() {}
|
||||||
|
|
||||||
|
/// Clear all savegame-specific data
|
||||||
|
virtual void clear() = 0;
|
||||||
|
|
||||||
virtual ~InputManager() {}
|
virtual ~InputManager() {}
|
||||||
|
|
||||||
virtual void update(float dt, bool loading) = 0;
|
virtual void update(float dt, bool loading) = 0;
|
||||||
|
|
|
@ -101,7 +101,8 @@ namespace MWBase
|
||||||
|
|
||||||
virtual ~World() {}
|
virtual ~World() {}
|
||||||
|
|
||||||
virtual void startNewGame() = 0;
|
virtual void startNewGame (bool bypass) = 0;
|
||||||
|
///< \param bypass Bypass regular game start.
|
||||||
|
|
||||||
virtual void clear() = 0;
|
virtual void clear() = 0;
|
||||||
|
|
||||||
|
|
|
@ -28,16 +28,16 @@
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
struct CustomData : public MWWorld::CustomData
|
struct ContainerCustomData : public MWWorld::CustomData
|
||||||
{
|
{
|
||||||
MWWorld::ContainerStore mContainerStore;
|
MWWorld::ContainerStore mContainerStore;
|
||||||
|
|
||||||
virtual MWWorld::CustomData *clone() const;
|
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())
|
if (!ptr.getRefData().getCustomData())
|
||||||
{
|
{
|
||||||
std::auto_ptr<CustomData> data (new CustomData);
|
std::auto_ptr<ContainerCustomData> data (new ContainerCustomData);
|
||||||
|
|
||||||
MWWorld::LiveCellRef<ESM::Container> *ref =
|
MWWorld::LiveCellRef<ESM::Container> *ref =
|
||||||
ptr.get<ESM::Container>();
|
ptr.get<ESM::Container>();
|
||||||
|
@ -174,7 +174,7 @@ namespace MWClass
|
||||||
{
|
{
|
||||||
ensureCustomData (ptr);
|
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
|
std::string Container::getScript (const MWWorld::Ptr& ptr) const
|
||||||
|
@ -267,7 +267,7 @@ namespace MWClass
|
||||||
|
|
||||||
ensureCustomData (ptr);
|
ensureCustomData (ptr);
|
||||||
|
|
||||||
dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData()).mContainerStore.
|
dynamic_cast<ContainerCustomData&> (*ptr.getRefData().getCustomData()).mContainerStore.
|
||||||
readState (state2.mInventory);
|
readState (state2.mInventory);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -278,7 +278,7 @@ namespace MWClass
|
||||||
|
|
||||||
ensureCustomData (ptr);
|
ensureCustomData (ptr);
|
||||||
|
|
||||||
dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData()).mContainerStore.
|
dynamic_cast<ContainerCustomData&> (*ptr.getRefData().getCustomData()).mContainerStore.
|
||||||
writeState (state2.mInventory);
|
writeState (state2.mInventory);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,7 +37,7 @@
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
struct CustomData : public MWWorld::CustomData
|
struct CreatureCustomData : public MWWorld::CustomData
|
||||||
{
|
{
|
||||||
MWMechanics::CreatureStats mCreatureStats;
|
MWMechanics::CreatureStats mCreatureStats;
|
||||||
MWWorld::ContainerStore* mContainerStore; // may be InventoryStore for some creatures
|
MWWorld::ContainerStore* mContainerStore; // may be InventoryStore for some creatures
|
||||||
|
@ -45,13 +45,13 @@ namespace
|
||||||
|
|
||||||
virtual MWWorld::CustomData *clone() const;
|
virtual MWWorld::CustomData *clone() const;
|
||||||
|
|
||||||
CustomData() : mContainerStore(0) {}
|
CreatureCustomData() : mContainerStore(0) {}
|
||||||
virtual ~CustomData() { delete mContainerStore; }
|
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();
|
cloned->mContainerStore = mContainerStore->clone();
|
||||||
return cloned;
|
return cloned;
|
||||||
}
|
}
|
||||||
|
@ -63,7 +63,7 @@ namespace MWClass
|
||||||
{
|
{
|
||||||
if (!ptr.getRefData().getCustomData())
|
if (!ptr.getRefData().getCustomData())
|
||||||
{
|
{
|
||||||
std::auto_ptr<CustomData> data (new CustomData);
|
std::auto_ptr<CreatureCustomData> data (new CreatureCustomData);
|
||||||
|
|
||||||
static bool inited = false;
|
static bool inited = false;
|
||||||
if(!inited)
|
if(!inited)
|
||||||
|
@ -192,7 +192,7 @@ namespace MWClass
|
||||||
{
|
{
|
||||||
ensureCustomData (ptr);
|
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);
|
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
|
MWWorld::InventoryStore& Creature::getInventoryStore(const MWWorld::Ptr &ptr) const
|
||||||
|
@ -525,7 +525,7 @@ namespace MWClass
|
||||||
float moveSpeed;
|
float moveSpeed;
|
||||||
if(normalizedEncumbrance >= 1.0f)
|
if(normalizedEncumbrance >= 1.0f)
|
||||||
moveSpeed = 0.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()))
|
world->isLevitationEnabled()))
|
||||||
{
|
{
|
||||||
float flySpeed = 0.01f*(stats.getAttribute(ESM::Attribute::Speed).getModified() +
|
float flySpeed = 0.01f*(stats.getAttribute(ESM::Attribute::Speed).getModified() +
|
||||||
|
@ -559,7 +559,7 @@ namespace MWClass
|
||||||
{
|
{
|
||||||
ensureCustomData (ptr);
|
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
|
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);
|
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 =
|
MWWorld::LiveCellRef<ESM::Creature> *ref =
|
||||||
ptr.get<ESM::Creature>();
|
ptr.get<ESM::Creature>();
|
||||||
|
@ -686,6 +694,22 @@ namespace MWClass
|
||||||
return ref->mBase->mFlags & ESM::Creature::Flies;
|
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)
|
int Creature::getSndGenTypeFromName(const MWWorld::Ptr &ptr, const std::string &name)
|
||||||
{
|
{
|
||||||
if(name == "left")
|
if(name == "left")
|
||||||
|
@ -762,7 +786,7 @@ namespace MWClass
|
||||||
|
|
||||||
ensureCustomData (ptr);
|
ensureCustomData (ptr);
|
||||||
|
|
||||||
CustomData& customData = dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData());
|
CreatureCustomData& customData = dynamic_cast<CreatureCustomData&> (*ptr.getRefData().getCustomData());
|
||||||
|
|
||||||
customData.mContainerStore->readState (state2.mInventory);
|
customData.mContainerStore->readState (state2.mInventory);
|
||||||
customData.mCreatureStats.readState (state2.mCreatureStats);
|
customData.mCreatureStats.readState (state2.mCreatureStats);
|
||||||
|
@ -776,7 +800,7 @@ namespace MWClass
|
||||||
|
|
||||||
ensureCustomData (ptr);
|
ensureCustomData (ptr);
|
||||||
|
|
||||||
CustomData& customData = dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData());
|
CreatureCustomData& customData = dynamic_cast<CreatureCustomData&> (*ptr.getRefData().getCustomData());
|
||||||
|
|
||||||
customData.mContainerStore->writeState (state2.mInventory);
|
customData.mContainerStore->writeState (state2.mInventory);
|
||||||
customData.mCreatureStats.writeState (state2.mCreatureStats);
|
customData.mCreatureStats.writeState (state2.mCreatureStats);
|
||||||
|
|
|
@ -124,7 +124,10 @@ namespace MWClass
|
||||||
return true;
|
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;
|
virtual int getSkill(const MWWorld::Ptr &ptr, int skill) const;
|
||||||
|
|
||||||
|
|
|
@ -9,15 +9,15 @@
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
struct CustomData : public MWWorld::CustomData
|
struct CreatureLevListCustomData : public MWWorld::CustomData
|
||||||
{
|
{
|
||||||
// TODO: save the creature we spawned here
|
// TODO: save the creature we spawned here
|
||||||
virtual MWWorld::CustomData *clone() const;
|
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())
|
if (!ptr.getRefData().getCustomData())
|
||||||
{
|
{
|
||||||
std::auto_ptr<CustomData> data (new CustomData);
|
std::auto_ptr<CreatureLevListCustomData> data (new CreatureLevListCustomData);
|
||||||
|
|
||||||
MWWorld::LiveCellRef<ESM::CreatureLevList> *ref =
|
MWWorld::LiveCellRef<ESM::CreatureLevList> *ref =
|
||||||
ptr.get<ESM::CreatureLevList>();
|
ptr.get<ESM::CreatureLevList>();
|
||||||
|
|
|
@ -26,12 +26,12 @@
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
struct CustomData : public MWWorld::CustomData
|
struct LightCustomData : public MWWorld::CustomData
|
||||||
{
|
{
|
||||||
float mTime;
|
float mTime;
|
||||||
///< Time remaining
|
///< Time remaining
|
||||||
|
|
||||||
CustomData(MWWorld::Ptr ptr)
|
LightCustomData(MWWorld::Ptr ptr)
|
||||||
{
|
{
|
||||||
MWWorld::LiveCellRef<ESM::Light> *ref = ptr.get<ESM::Light>();
|
MWWorld::LiveCellRef<ESM::Light> *ref = ptr.get<ESM::Light>();
|
||||||
mTime = ref->mBase->mData.mTime;
|
mTime = ref->mBase->mData.mTime;
|
||||||
|
@ -40,7 +40,7 @@ namespace
|
||||||
|
|
||||||
virtual MWWorld::CustomData *clone() const
|
virtual MWWorld::CustomData *clone() const
|
||||||
{
|
{
|
||||||
return new CustomData (*this);
|
return new LightCustomData (*this);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -210,7 +210,7 @@ namespace MWClass
|
||||||
{
|
{
|
||||||
ensureCustomData(ptr);
|
ensureCustomData(ptr);
|
||||||
|
|
||||||
float &timeRemaining = dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData()).mTime;
|
float &timeRemaining = dynamic_cast<LightCustomData&> (*ptr.getRefData().getCustomData()).mTime;
|
||||||
timeRemaining = duration;
|
timeRemaining = duration;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -218,7 +218,7 @@ namespace MWClass
|
||||||
{
|
{
|
||||||
ensureCustomData(ptr);
|
ensureCustomData(ptr);
|
||||||
|
|
||||||
return dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData()).mTime;
|
return dynamic_cast<LightCustomData&> (*ptr.getRefData().getCustomData()).mTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
MWWorld::Ptr
|
MWWorld::Ptr
|
||||||
|
@ -233,7 +233,7 @@ namespace MWClass
|
||||||
void Light::ensureCustomData (const MWWorld::Ptr& ptr) const
|
void Light::ensureCustomData (const MWWorld::Ptr& ptr) const
|
||||||
{
|
{
|
||||||
if (!ptr.getRefData().getCustomData())
|
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
|
bool Light::canSell (const MWWorld::Ptr& item, int npcServices) const
|
||||||
|
@ -278,7 +278,7 @@ namespace MWClass
|
||||||
|
|
||||||
ensureCustomData (ptr);
|
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)
|
void Light::writeAdditionalState (const MWWorld::Ptr& ptr, ESM::ObjectState& state)
|
||||||
|
@ -288,6 +288,6 @@ namespace MWClass
|
||||||
|
|
||||||
ensureCustomData (ptr);
|
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
|
namespace
|
||||||
{
|
{
|
||||||
struct CustomData : public MWWorld::CustomData
|
struct NpcCustomData : public MWWorld::CustomData
|
||||||
{
|
{
|
||||||
MWMechanics::NpcStats mNpcStats;
|
MWMechanics::NpcStats mNpcStats;
|
||||||
MWMechanics::Movement mMovement;
|
MWMechanics::Movement mMovement;
|
||||||
|
@ -48,9 +48,9 @@ namespace
|
||||||
virtual MWWorld::CustomData *clone() const;
|
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)
|
void autoCalculateAttributes (const ESM::NPC* npc, MWMechanics::CreatureStats& creatureStats)
|
||||||
|
@ -262,7 +262,7 @@ namespace MWClass
|
||||||
}
|
}
|
||||||
if (!ptr.getRefData().getCustomData())
|
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>();
|
MWWorld::LiveCellRef<ESM::NPC> *ref = ptr.get<ESM::NPC>();
|
||||||
|
|
||||||
|
@ -436,14 +436,14 @@ namespace MWClass
|
||||||
{
|
{
|
||||||
ensureCustomData (ptr);
|
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
|
MWMechanics::NpcStats& Npc::getNpcStats (const MWWorld::Ptr& ptr) const
|
||||||
{
|
{
|
||||||
ensureCustomData (ptr);
|
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
|
else
|
||||||
getCreatureStats(ptr).setHitRecovery(true); // Is this supposed to always occur?
|
getCreatureStats(ptr).setHitRecovery(true); // Is this supposed to always occur?
|
||||||
|
|
||||||
if(object.isEmpty())
|
if(ishealth)
|
||||||
{
|
|
||||||
if(ishealth)
|
|
||||||
damage /= std::min(1.0f + getArmorRating(ptr)/std::max(1.0f, damage), 4.0f);
|
|
||||||
}
|
|
||||||
else if(ishealth)
|
|
||||||
{
|
{
|
||||||
// Hit percentages:
|
// Hit percentages:
|
||||||
// cuirass = 30%
|
// cuirass = 30%
|
||||||
|
@ -824,7 +819,7 @@ namespace MWClass
|
||||||
{
|
{
|
||||||
ensureCustomData (ptr);
|
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)
|
MWWorld::InventoryStore& Npc::getInventoryStore (const MWWorld::Ptr& ptr)
|
||||||
|
@ -832,7 +827,7 @@ namespace MWClass
|
||||||
{
|
{
|
||||||
ensureCustomData (ptr);
|
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
|
std::string Npc::getScript (const MWWorld::Ptr& ptr) const
|
||||||
|
@ -846,7 +841,7 @@ namespace MWClass
|
||||||
float Npc::getSpeed(const MWWorld::Ptr& ptr) const
|
float Npc::getSpeed(const MWWorld::Ptr& ptr) const
|
||||||
{
|
{
|
||||||
const MWBase::World *world = MWBase::Environment::get().getWorld();
|
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 MWMechanics::MagicEffects &mageffects = npcdata->mNpcStats.getMagicEffects();
|
||||||
|
|
||||||
const float normalizedEncumbrance = Npc::getEncumbrance(ptr) / Npc::getCapacity(ptr);
|
const float normalizedEncumbrance = Npc::getEncumbrance(ptr) / Npc::getCapacity(ptr);
|
||||||
|
@ -901,7 +896,7 @@ namespace MWClass
|
||||||
|
|
||||||
float Npc::getJump(const MWWorld::Ptr &ptr) const
|
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 MWMechanics::MagicEffects &mageffects = npcdata->mNpcStats.getMagicEffects();
|
||||||
const float encumbranceTerm = fJumpEncumbranceBase->getFloat() +
|
const float encumbranceTerm = fJumpEncumbranceBase->getFloat() +
|
||||||
fJumpEncumbranceMultiplier->getFloat() *
|
fJumpEncumbranceMultiplier->getFloat() *
|
||||||
|
@ -940,7 +935,7 @@ namespace MWClass
|
||||||
if (fallHeight >= fallDistanceMin)
|
if (fallHeight >= fallDistanceMin)
|
||||||
{
|
{
|
||||||
const float acrobaticsSkill = MWWorld::Class::get(ptr).getNpcStats (ptr).getSkill(ESM::Skill::Acrobatics).getModified();
|
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 jumpSpellBonus = npcdata->mNpcStats.getMagicEffects().get(ESM::MagicEffect::Jump).mMagnitude;
|
||||||
const float fallAcroBase = gmst.find("fFallAcroBase")->getFloat();
|
const float fallAcroBase = gmst.find("fFallAcroBase")->getFloat();
|
||||||
const float fallAcroMult = gmst.find("fFallAcroMult")->getFloat();
|
const float fallAcroMult = gmst.find("fFallAcroMult")->getFloat();
|
||||||
|
@ -965,7 +960,7 @@ namespace MWClass
|
||||||
{
|
{
|
||||||
ensureCustomData (ptr);
|
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
|
Ogre::Vector3 Npc::getMovementVector (const MWWorld::Ptr& ptr) const
|
||||||
|
@ -1271,7 +1266,7 @@ namespace MWClass
|
||||||
|
|
||||||
ensureCustomData (ptr);
|
ensureCustomData (ptr);
|
||||||
|
|
||||||
CustomData& customData = dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData());
|
NpcCustomData& customData = dynamic_cast<NpcCustomData&> (*ptr.getRefData().getCustomData());
|
||||||
|
|
||||||
customData.mInventoryStore.readState (state2.mInventory);
|
customData.mInventoryStore.readState (state2.mInventory);
|
||||||
customData.mNpcStats.readState (state2.mNpcStats);
|
customData.mNpcStats.readState (state2.mNpcStats);
|
||||||
|
@ -1285,7 +1280,7 @@ namespace MWClass
|
||||||
|
|
||||||
ensureCustomData (ptr);
|
ensureCustomData (ptr);
|
||||||
|
|
||||||
CustomData& customData = dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData());
|
NpcCustomData& customData = dynamic_cast<NpcCustomData&> (*ptr.getRefData().getCustomData());
|
||||||
|
|
||||||
customData.mInventoryStore.writeState (state2.mInventory);
|
customData.mInventoryStore.writeState (state2.mInventory);
|
||||||
customData.mNpcStats.writeState (state2.mNpcStats);
|
customData.mNpcStats.writeState (state2.mNpcStats);
|
||||||
|
|
|
@ -26,16 +26,6 @@ namespace
|
||||||
return path;
|
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
|
namespace MWGui
|
||||||
|
@ -226,7 +216,7 @@ namespace MWGui
|
||||||
text->setNeedMouseFocus(false);
|
text->setNeedMouseFocus(false);
|
||||||
text->setTextShadow(true);
|
text->setTextShadow(true);
|
||||||
text->setTextShadowColour(MyGUI::Colour(0,0,0));
|
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();
|
mItemView->update();
|
||||||
|
|
|
@ -23,19 +23,6 @@
|
||||||
#include "sortfilteritemmodel.hpp"
|
#include "sortfilteritemmodel.hpp"
|
||||||
#include "pickpocketitemmodel.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
|
namespace MWGui
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -79,7 +66,7 @@ namespace MWGui
|
||||||
text->setNeedMouseFocus(false);
|
text->setNeedMouseFocus(false);
|
||||||
text->setTextShadow(true);
|
text->setTextShadow(true);
|
||||||
text->setTextShadowColour(MyGUI::Colour(0,0,0));
|
text->setTextShadowColour(MyGUI::Colour(0,0,0));
|
||||||
text->setCaption(getCountString(count));
|
text->setCaption(ItemView::getCountString(count));
|
||||||
|
|
||||||
sourceView->update();
|
sourceView->update();
|
||||||
|
|
||||||
|
|
|
@ -23,18 +23,7 @@
|
||||||
#include "travelwindow.hpp"
|
#include "travelwindow.hpp"
|
||||||
#include "bookpage.hpp"
|
#include "bookpage.hpp"
|
||||||
|
|
||||||
|
#include "journalbooks.hpp" // to_utf8_span
|
||||||
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));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace MWGui
|
namespace MWGui
|
||||||
{
|
{
|
||||||
|
|
|
@ -604,15 +604,22 @@ namespace MWGui
|
||||||
mEffectBox->setPosition((viewSize.width - mEffectBoxBaseRight) - mEffectBox->getWidth() + effectsDx, mEffectBox->getTop());
|
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()
|
void HUD::update()
|
||||||
{
|
{
|
||||||
mSpellIcons->updateWidgets(mEffectBox, true);
|
mSpellIcons->updateWidgets(mEffectBox, true);
|
||||||
|
|
||||||
if (!mEnemy.isEmpty() && mEnemyHealth->getVisible())
|
if (!mEnemy.isEmpty() && mEnemyHealth->getVisible())
|
||||||
{
|
{
|
||||||
MWMechanics::CreatureStats& stats = MWWorld::Class::get(mEnemy).getCreatureStats(mEnemy);
|
updateEnemyHealthBar();
|
||||||
mEnemyHealth->setProgressRange(100);
|
|
||||||
mEnemyHealth->setProgressPosition(stats.getHealth().getCurrent() / stats.getHealth().getModified() * 100);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mIsDrowning)
|
if (mIsDrowning)
|
||||||
|
@ -629,9 +636,7 @@ namespace MWGui
|
||||||
if (!mEnemyHealth->getVisible())
|
if (!mEnemyHealth->getVisible())
|
||||||
mWeaponSpellBox->setPosition(mWeaponSpellBox->getPosition() - MyGUI::IntPoint(0,20));
|
mWeaponSpellBox->setPosition(mWeaponSpellBox->getPosition() - MyGUI::IntPoint(0,20));
|
||||||
mEnemyHealth->setVisible(true);
|
mEnemyHealth->setVisible(true);
|
||||||
MWMechanics::CreatureStats& stats = MWWorld::Class::get(mEnemy).getCreatureStats(mEnemy);
|
updateEnemyHealthBar();
|
||||||
mEnemyHealth->setProgressRange(100);
|
|
||||||
mEnemyHealth->setProgressPosition(stats.getHealth().getCurrent() / stats.getHealth().getModified() * 100);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
#ifndef OPENMW_GAME_MWGUI_HUD_H
|
||||||
|
#define OPENMW_GAME_MWGUI_HUD_H
|
||||||
|
|
||||||
#include "mapwindow.hpp"
|
#include "mapwindow.hpp"
|
||||||
|
|
||||||
#include "../mwmechanics/stat.hpp"
|
#include "../mwmechanics/stat.hpp"
|
||||||
|
@ -112,6 +115,10 @@ namespace MWGui
|
||||||
void onMagicClicked(MyGUI::Widget* _sender);
|
void onMagicClicked(MyGUI::Widget* _sender);
|
||||||
void onMapClicked(MyGUI::Widget* _sender);
|
void onMapClicked(MyGUI::Widget* _sender);
|
||||||
|
|
||||||
|
void updateEnemyHealthBar();
|
||||||
|
|
||||||
void updatePositions();
|
void updatePositions();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -162,6 +162,7 @@ namespace MWGui
|
||||||
}
|
}
|
||||||
|
|
||||||
const ItemStack& item = mTradeModel->getItem(index);
|
const ItemStack& item = mTradeModel->getItem(index);
|
||||||
|
std::string sound = MWWorld::Class::get(item.mBase).getDownSoundId(item.mBase);
|
||||||
|
|
||||||
MWWorld::Ptr object = item.mBase;
|
MWWorld::Ptr object = item.mBase;
|
||||||
int count = item.mCount;
|
int count = item.mCount;
|
||||||
|
@ -170,6 +171,7 @@ namespace MWGui
|
||||||
if (item.mBase.getCellRef().mRefID.size() > 6
|
if (item.mBase.getCellRef().mRefID.size() > 6
|
||||||
&& item.mBase.getCellRef().mRefID.substr(0,6) == "bound_")
|
&& item.mBase.getCellRef().mRefID.substr(0,6) == "bound_")
|
||||||
{
|
{
|
||||||
|
MWBase::Environment::get().getSoundManager()->playSound (sound, 1.0, 1.0);
|
||||||
MWBase::Environment::get().getWindowManager()->messageBox("#{sBarterDialog12}");
|
MWBase::Environment::get().getWindowManager()->messageBox("#{sBarterDialog12}");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -213,6 +215,7 @@ namespace MWGui
|
||||||
int services = MWBase::Environment::get().getWindowManager()->getTradeWindow()->getMerchantServices();
|
int services = MWBase::Environment::get().getWindowManager()->getTradeWindow()->getMerchantServices();
|
||||||
if (!MWWorld::Class::get(object).canSell(object, services))
|
if (!MWWorld::Class::get(object).canSell(object, services))
|
||||||
{
|
{
|
||||||
|
MWBase::Environment::get().getSoundManager()->playSound (sound, 1.0, 1.0);
|
||||||
MWBase::Environment::get().getWindowManager()->
|
MWBase::Environment::get().getWindowManager()->
|
||||||
messageBox("#{sBarterDialog4}");
|
messageBox("#{sBarterDialog4}");
|
||||||
return;
|
return;
|
||||||
|
@ -514,6 +517,9 @@ namespace MWGui
|
||||||
|
|
||||||
void InventoryWindow::pickUpObject (MWWorld::Ptr object)
|
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
|
// make sure the object is of a type that can be picked up
|
||||||
std::string type = object.getTypeName();
|
std::string type = object.getTypeName();
|
||||||
if ( (type != typeid(ESM::Apparatus).name())
|
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"
|
#include "container.hpp"
|
||||||
|
|
||||||
namespace MWGui
|
namespace MWGui
|
||||||
|
@ -32,3 +35,5 @@ namespace MWGui
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -13,23 +13,19 @@
|
||||||
|
|
||||||
#include "itemmodel.hpp"
|
#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
|
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()
|
ItemView::ItemView()
|
||||||
: mModel(NULL)
|
: mModel(NULL)
|
||||||
, mScrollView(NULL)
|
, mScrollView(NULL)
|
||||||
|
|
|
@ -30,6 +30,8 @@ namespace MWGui
|
||||||
|
|
||||||
void update();
|
void update();
|
||||||
|
|
||||||
|
static std::string getCountString(int count);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
virtual void initialiseOverride();
|
virtual void initialiseOverride();
|
||||||
|
|
||||||
|
|
|
@ -2,15 +2,6 @@
|
||||||
|
|
||||||
namespace
|
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 linkHot (0.40f, 0.40f, 0.80f);
|
||||||
const MyGUI::Colour linkNormal (0.20f, 0.20f, 0.60f);
|
const MyGUI::Colour linkNormal (0.20f, 0.20f, 0.60f);
|
||||||
const MyGUI::Colour linkActive (0.50f, 0.50f, 1.00f);
|
const MyGUI::Colour linkActive (0.50f, 0.50f, 1.00f);
|
||||||
|
@ -178,6 +169,15 @@ namespace
|
||||||
namespace MWGui
|
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;
|
typedef TypesetBook::Ptr book;
|
||||||
|
|
||||||
JournalBooks::JournalBooks (JournalViewModel::Ptr model) :
|
JournalBooks::JournalBooks (JournalViewModel::Ptr model) :
|
||||||
|
|
|
@ -6,6 +6,8 @@
|
||||||
|
|
||||||
namespace MWGui
|
namespace MWGui
|
||||||
{
|
{
|
||||||
|
MWGui::BookTypesetter::Utf8Span to_utf8_span (char const * text);
|
||||||
|
|
||||||
struct JournalBooks
|
struct JournalBooks
|
||||||
{
|
{
|
||||||
typedef TypesetBook::Ptr Book;
|
typedef TypesetBook::Ptr Book;
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
#include "mainmenu.hpp"
|
#include "mainmenu.hpp"
|
||||||
|
|
||||||
|
#include <components/version/version.hpp>
|
||||||
|
|
||||||
#include "../mwbase/environment.hpp"
|
#include "../mwbase/environment.hpp"
|
||||||
#include "../mwbase/windowmanager.hpp"
|
#include "../mwbase/windowmanager.hpp"
|
||||||
#include "../mwbase/soundmanager.hpp"
|
#include "../mwbase/soundmanager.hpp"
|
||||||
|
@ -20,6 +22,22 @@ namespace MWGui
|
||||||
, mButtonBox(0), mWidth (w), mHeight (h)
|
, mButtonBox(0), mWidth (w), mHeight (h)
|
||||||
, mSaveGameDialog(NULL)
|
, 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();
|
updateMenu();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
#ifndef OPENMW_GAME_MWGUI_MAINMENU_H
|
||||||
|
#define OPENMW_GAME_MWGUI_MAINMENU_H
|
||||||
|
|
||||||
#include <openengine/gui/layout.hpp>
|
#include <openengine/gui/layout.hpp>
|
||||||
|
|
||||||
#include "imagebutton.hpp"
|
#include "imagebutton.hpp"
|
||||||
|
@ -24,6 +27,7 @@ namespace MWGui
|
||||||
private:
|
private:
|
||||||
|
|
||||||
MyGUI::Widget* mButtonBox;
|
MyGUI::Widget* mButtonBox;
|
||||||
|
MyGUI::TextBox* mVersionText;
|
||||||
|
|
||||||
std::map<std::string, MWGui::ImageButton*> mButtons;
|
std::map<std::string, MWGui::ImageButton*> mButtons;
|
||||||
|
|
||||||
|
@ -35,3 +39,5 @@ namespace MWGui
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -19,28 +19,8 @@
|
||||||
#include "windowmanagerimp.hpp"
|
#include "windowmanagerimp.hpp"
|
||||||
#include "itemselection.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
|
namespace MWGui
|
||||||
{
|
{
|
||||||
|
|
|
@ -41,9 +41,13 @@ namespace MWGui
|
||||||
getWidget(mPreviewImage, "PreviewImage");
|
getWidget(mPreviewImage, "PreviewImage");
|
||||||
|
|
||||||
getWidget(mHeadRotate, "HeadRotate");
|
getWidget(mHeadRotate, "HeadRotate");
|
||||||
mHeadRotate->setScrollRange(50);
|
|
||||||
mHeadRotate->setScrollPosition(25);
|
// Mouse wheel step is hardcoded to 50 in MyGUI 3.2 ("FIXME").
|
||||||
mHeadRotate->setScrollViewPage(10);
|
// 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);
|
mHeadRotate->eventScrollChangePosition += MyGUI::newDelegate(this, &RaceDialog::onHeadRotate);
|
||||||
|
|
||||||
// Set up next/previous buttons
|
// Set up next/previous buttons
|
||||||
|
@ -171,9 +175,9 @@ namespace MWGui
|
||||||
eventBack();
|
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;
|
float diff = angle - mCurrentAngle;
|
||||||
mPreview->update (diff);
|
mPreview->update (diff);
|
||||||
mPreviewDirty = true;
|
mPreviewDirty = true;
|
||||||
|
|
|
@ -18,8 +18,16 @@
|
||||||
#include "inventorywindow.hpp"
|
#include "inventorywindow.hpp"
|
||||||
#include "confirmationdialog.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)
|
bool sortSpells(const std::string& left, const std::string& right)
|
||||||
{
|
{
|
||||||
const MWWorld::Store<ESM::Spell> &spells =
|
const MWWorld::Store<ESM::Spell> &spells =
|
||||||
|
@ -32,16 +40,6 @@ namespace
|
||||||
return cmp < 0;
|
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)
|
SpellWindow::SpellWindow(DragAndDrop* drag)
|
||||||
: WindowPinnableBase("openmw_spell_window.layout")
|
: WindowPinnableBase("openmw_spell_window.layout")
|
||||||
, NoDrop(drag, mMainWidget)
|
, NoDrop(drag, mMainWidget)
|
||||||
|
|
|
@ -2,11 +2,16 @@
|
||||||
#define MWGUI_SPELLWINDOW_H
|
#define MWGUI_SPELLWINDOW_H
|
||||||
|
|
||||||
#include "windowpinnablebase.hpp"
|
#include "windowpinnablebase.hpp"
|
||||||
|
#include "../mwworld/ptr.hpp"
|
||||||
|
|
||||||
namespace MWGui
|
namespace MWGui
|
||||||
{
|
{
|
||||||
class SpellIcons;
|
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
|
class SpellWindow : public WindowPinnableBase, public NoDrop
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -143,6 +143,13 @@ namespace MWInput
|
||||||
mControlSwitch["vanitymode"] = true;
|
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()
|
InputManager::~InputManager()
|
||||||
{
|
{
|
||||||
mInputBinder->save (mUserFile);
|
mInputBinder->save (mUserFile);
|
||||||
|
|
|
@ -65,6 +65,9 @@ namespace MWInput
|
||||||
|
|
||||||
virtual ~InputManager();
|
virtual ~InputManager();
|
||||||
|
|
||||||
|
/// Clear all savegame-specific data
|
||||||
|
virtual void clear();
|
||||||
|
|
||||||
virtual void update(float dt, bool loading);
|
virtual void update(float dt, bool loading);
|
||||||
|
|
||||||
void setPlayer (MWWorld::Player* player) { mPlayer = player; }
|
void setPlayer (MWWorld::Player* player) { mPlayer = player; }
|
||||||
|
|
|
@ -10,16 +10,6 @@
|
||||||
#include "steering.hpp"
|
#include "steering.hpp"
|
||||||
#include "movement.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)
|
MWMechanics::AiActivate::AiActivate(const std::string &objectId)
|
||||||
: mObjectId(objectId)
|
: mObjectId(objectId)
|
||||||
{
|
{
|
||||||
|
@ -38,7 +28,7 @@ bool MWMechanics::AiActivate::execute (const MWWorld::Ptr& actor,float duration)
|
||||||
MWWorld::Ptr player = world->getPlayerPtr();
|
MWWorld::Ptr player = world->getPlayerPtr();
|
||||||
if(cell->mData.mX != player.getCell()->getCell()->mData.mX)
|
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.
|
//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) >
|
if(sideX * (pos.pos[0] - cell->mData.mX*ESM::Land::REAL_SIZE) >
|
||||||
sideX * (ESM::Land::REAL_SIZE/2.0f - 200.0f))
|
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)
|
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.
|
//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) >
|
if(sideY * (pos.pos[1] - cell->mData.mY*ESM::Land::REAL_SIZE) >
|
||||||
sideY * (ESM::Land::REAL_SIZE/2.0f - 200.0f))
|
sideY * (ESM::Land::REAL_SIZE/2.0f - 200.0f))
|
||||||
|
|
|
@ -11,16 +11,6 @@
|
||||||
#include "steering.hpp"
|
#include "steering.hpp"
|
||||||
#include "movement.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: 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.
|
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)
|
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.
|
// 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 /
|
if(sideX * (pos.pos[0] - actor.getCell()->getCell()->mData.mX * ESM::Land::REAL_SIZE) > sideX * (ESM::Land::REAL_SIZE /
|
||||||
2.0 - 200))
|
2.0 - 200))
|
||||||
|
@ -102,7 +92,7 @@ namespace MWMechanics
|
||||||
}
|
}
|
||||||
if(actor.getCell()->getCell()->mData.mY != player.getCell()->getCell()->mData.mY)
|
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.
|
// 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 /
|
if(sideY*(pos.pos[1] - actor.getCell()->getCell()->mData.mY * ESM::Land::REAL_SIZE) > sideY * (ESM::Land::REAL_SIZE /
|
||||||
2.0 - 200))
|
2.0 - 200))
|
||||||
|
|
|
@ -9,16 +9,6 @@
|
||||||
#include "steering.hpp"
|
#include "steering.hpp"
|
||||||
#include "movement.hpp"
|
#include "movement.hpp"
|
||||||
|
|
||||||
namespace
|
|
||||||
{
|
|
||||||
float sgn(float a)
|
|
||||||
{
|
|
||||||
if(a > 0)
|
|
||||||
return 1.0;
|
|
||||||
return -1.0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace MWMechanics
|
namespace MWMechanics
|
||||||
{
|
{
|
||||||
AiTravel::AiTravel(float x, float y, float z)
|
AiTravel::AiTravel(float x, float y, float z)
|
||||||
|
@ -43,7 +33,7 @@ namespace MWMechanics
|
||||||
MWWorld::Ptr player = world->getPlayerPtr();
|
MWWorld::Ptr player = world->getPlayerPtr();
|
||||||
if(cell->mData.mX != player.getCell()->getCell()->mData.mX)
|
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.
|
//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) >
|
if(sideX * (pos.pos[0] - cell->mData.mX*ESM::Land::REAL_SIZE) >
|
||||||
sideX * (ESM::Land::REAL_SIZE/2.0f - 200.0f))
|
sideX * (ESM::Land::REAL_SIZE/2.0f - 200.0f))
|
||||||
|
@ -54,7 +44,7 @@ namespace MWMechanics
|
||||||
}
|
}
|
||||||
if(cell->mData.mY != player.getCell()->getCell()->mData.mY)
|
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.
|
//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) >
|
if(sideY * (pos.pos[1] - cell->mData.mY*ESM::Land::REAL_SIZE) >
|
||||||
sideY * (ESM::Land::REAL_SIZE/2.0f - 200.0f))
|
sideY * (ESM::Land::REAL_SIZE/2.0f - 200.0f))
|
||||||
|
|
|
@ -15,18 +15,13 @@
|
||||||
#include "steering.hpp"
|
#include "steering.hpp"
|
||||||
#include "movement.hpp"
|
#include "movement.hpp"
|
||||||
|
|
||||||
namespace
|
|
||||||
{
|
|
||||||
float sgn(float a)
|
|
||||||
{
|
|
||||||
if(a > 0)
|
|
||||||
return 1.0;
|
|
||||||
return -1.0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace MWMechanics
|
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):
|
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)
|
mDistance(distance), mDuration(duration), mTimeOfDay(timeOfDay), mIdle(idle), mRepeat(repeat)
|
||||||
, mCellX(std::numeric_limits<int>::max())
|
, mCellX(std::numeric_limits<int>::max())
|
||||||
|
@ -36,6 +31,11 @@ namespace MWMechanics
|
||||||
, mX(0)
|
, mX(0)
|
||||||
, mY(0)
|
, mY(0)
|
||||||
, mZ(0)
|
, mZ(0)
|
||||||
|
, mPrevX(0)
|
||||||
|
, mPrevY(0)
|
||||||
|
, mWalkState(State_Norm)
|
||||||
|
, mStuckCount(0)
|
||||||
|
, mEvadeCount(0)
|
||||||
, mSaidGreeting(false)
|
, mSaidGreeting(false)
|
||||||
{
|
{
|
||||||
for(unsigned short counter = 0; counter < mIdle.size(); counter++)
|
for(unsigned short counter = 0; counter < mIdle.size(); counter++)
|
||||||
|
@ -298,9 +298,91 @@ namespace MWMechanics
|
||||||
}
|
}
|
||||||
else
|
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 mXCell;
|
||||||
float mYCell;
|
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 mStoredAvailableNodes;
|
||||||
bool mChooseAction;
|
bool mChooseAction;
|
||||||
bool mIdleNow;
|
bool mIdleNow;
|
||||||
|
|
|
@ -37,13 +37,6 @@ namespace
|
||||||
return sqrt(x * x + y * y + z * z);
|
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)
|
int getClosestPoint(const ESM::Pathgrid* grid, float x, float y, float z)
|
||||||
{
|
{
|
||||||
if(!grid || grid->mPoints.empty())
|
if(!grid || grid->mPoints.empty())
|
||||||
|
|
|
@ -4,6 +4,8 @@
|
||||||
#include <components/esm/loadpgrd.hpp>
|
#include <components/esm/loadpgrd.hpp>
|
||||||
#include <list>
|
#include <list>
|
||||||
|
|
||||||
|
#include <OgreMath.h>
|
||||||
|
|
||||||
namespace MWWorld
|
namespace MWWorld
|
||||||
{
|
{
|
||||||
class CellStore;
|
class CellStore;
|
||||||
|
@ -16,6 +18,20 @@ namespace MWMechanics
|
||||||
public:
|
public:
|
||||||
PathFinder();
|
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 clearPath();
|
||||||
|
|
||||||
void buildPathgridGraph(const ESM::Pathgrid* pathGrid);
|
void buildPathgridGraph(const ESM::Pathgrid* pathGrid);
|
||||||
|
|
|
@ -55,6 +55,8 @@ CreatureWeaponAnimation::CreatureWeaponAnimation(const MWWorld::Ptr &ptr)
|
||||||
|
|
||||||
updateParts();
|
updateParts();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mWeaponAnimationTime = Ogre::SharedPtr<WeaponAnimationTime>(new WeaponAnimationTime(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
void CreatureWeaponAnimation::showWeapons(bool showWeapon)
|
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,
|
setRenderProperties(scene, RV_Actors, RQG_Main, RQG_Alpha, 0,
|
||||||
!item.getClass().getEnchantment(item).empty(), &glowColor);
|
!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)
|
if(scene->mSkelBase)
|
||||||
{
|
{
|
||||||
Ogre::SkeletonInstance *skel = scene->mSkelBase->getSkeleton();
|
Ogre::SkeletonInstance *skel = scene->mSkelBase->getSkeleton();
|
||||||
|
@ -133,15 +149,42 @@ void CreatureWeaponAnimation::updatePart(NifOgre::ObjectScenePtr& scene, int slo
|
||||||
updateSkeletonInstance(mSkelBase->getSkeleton(), skel);
|
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());
|
std::vector<Ogre::Controller<Ogre::Real> >::iterator ctrl(scene->mControllers.begin());
|
||||||
for(;ctrl != scene->mControllers.end();ctrl++)
|
for(;ctrl != scene->mControllers.end();ctrl++)
|
||||||
{
|
{
|
||||||
if(ctrl->getSource().isNull())
|
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
|
#define GAME_RENDER_CREATUREANIMATION_H
|
||||||
|
|
||||||
#include "animation.hpp"
|
#include "animation.hpp"
|
||||||
|
#include "weaponanimation.hpp"
|
||||||
#include "../mwworld/inventorystore.hpp"
|
#include "../mwworld/inventorystore.hpp"
|
||||||
|
|
||||||
namespace MWWorld
|
namespace MWWorld
|
||||||
|
@ -21,7 +22,7 @@ namespace MWRender
|
||||||
// For creatures with weapons and shields
|
// For creatures with weapons and shields
|
||||||
// Animation is already virtual anyway, so might as well make a separate class.
|
// 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.
|
// 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:
|
public:
|
||||||
CreatureWeaponAnimation(const MWWorld::Ptr& ptr);
|
CreatureWeaponAnimation(const MWWorld::Ptr& ptr);
|
||||||
|
@ -36,11 +37,29 @@ namespace MWRender
|
||||||
|
|
||||||
void updatePart(NifOgre::ObjectScenePtr& scene, int slot);
|
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:
|
private:
|
||||||
NifOgre::ObjectScenePtr mWeapon;
|
NifOgre::ObjectScenePtr mWeapon;
|
||||||
NifOgre::ObjectScenePtr mShield;
|
NifOgre::ObjectScenePtr mShield;
|
||||||
bool mShowWeapons;
|
bool mShowWeapons;
|
||||||
bool mShowCarriedLeft;
|
bool mShowCarriedLeft;
|
||||||
|
|
||||||
|
Ogre::SharedPtr<WeaponAnimationTime> mWeaponAnimationTime;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -76,27 +76,6 @@ float HeadAnimationTime::getValue() const
|
||||||
return 1;
|
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()
|
static NpcAnimation::PartBoneMap createPartListMap()
|
||||||
{
|
{
|
||||||
NpcAnimation::PartBoneMap result;
|
NpcAnimation::PartBoneMap result;
|
||||||
|
@ -147,8 +126,7 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, int v
|
||||||
mShowCarriedLeft(true),
|
mShowCarriedLeft(true),
|
||||||
mFirstPersonOffset(0.f, 0.f, 0.f),
|
mFirstPersonOffset(0.f, 0.f, 0.f),
|
||||||
mAlpha(1.f),
|
mAlpha(1.f),
|
||||||
mNpcType(Type_Normal),
|
mNpcType(Type_Normal)
|
||||||
mPitchFactor(0)
|
|
||||||
{
|
{
|
||||||
mNpc = mPtr.get<ESM::NPC>()->mBase;
|
mNpc = mPtr.get<ESM::NPC>()->mBase;
|
||||||
|
|
||||||
|
@ -538,14 +516,10 @@ Ogre::Vector3 NpcAnimation::runAnimation(float timepassed)
|
||||||
// updateSkeletonInstance, below, touches the hands.
|
// updateSkeletonInstance, below, touches the hands.
|
||||||
node->translate(mFirstPersonOffset, Ogre::Node::TS_WORLD);
|
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
|
// In third person mode we may still need pitch for ranged weapon targeting
|
||||||
float pitch = mPtr.getRefData().getPosition().rot[0] * mPitchFactor;
|
pitchSkeleton(mPtr.getRefData().getPosition().rot[0], baseinst);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
mFirstPersonOffset = 0.f; // reset the X, Y, Z offset for the next frame.
|
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::InventoryStore &inv = MWWorld::Class::get(mPtr).getInventoryStore(mPtr);
|
||||||
MWWorld::ContainerStoreIterator weapon = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
|
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);
|
Ogre::Vector3 glowColor = getEnchantmentColor(*weapon);
|
||||||
std::string mesh = MWWorld::Class::get(*weapon).getModel(*weapon);
|
std::string mesh = MWWorld::Class::get(*weapon).getModel(*weapon);
|
||||||
addOrReplaceIndividualPart(ESM::PRT_Weapon, MWWorld::InventoryStore::Slot_CarriedRight, 1,
|
addOrReplaceIndividualPart(ESM::PRT_Weapon, MWWorld::InventoryStore::Slot_CarriedRight, 1,
|
||||||
mesh, !weapon->getClass().getEnchantment(*weapon).empty(), &glowColor);
|
mesh, !weapon->getClass().getEnchantment(*weapon).empty(), &glowColor);
|
||||||
|
|
||||||
|
// Crossbows start out with a bolt attached
|
||||||
if (weapon->getTypeName() == typeid(ESM::Weapon).name() &&
|
if (weapon->getTypeName() == typeid(ESM::Weapon).name() &&
|
||||||
weapon->get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::MarksmanCrossbow)
|
weapon->get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::MarksmanCrossbow)
|
||||||
{
|
{
|
||||||
|
@ -743,113 +718,24 @@ void NpcAnimation::showCarriedLeft(bool show)
|
||||||
removeIndividualPart(ESM::PRT_Shield);
|
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()
|
void NpcAnimation::attachArrow()
|
||||||
{
|
{
|
||||||
MWWorld::InventoryStore& inv = mPtr.getClass().getInventoryStore(mPtr);
|
WeaponAnimation::attachArrow(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));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void NpcAnimation::releaseArrow()
|
void NpcAnimation::releaseArrow()
|
||||||
{
|
{
|
||||||
MWWorld::InventoryStore& inv = mPtr.getClass().getInventoryStore(mPtr);
|
WeaponAnimation::releaseArrow(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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void NpcAnimation::permanentEffectAdded(const ESM::MagicEffect *magicEffect, bool isNew, bool playSound)
|
void NpcAnimation::permanentEffectAdded(const ESM::MagicEffect *magicEffect, bool isNew, bool playSound)
|
||||||
|
|
|
@ -5,6 +5,8 @@
|
||||||
|
|
||||||
#include "../mwworld/inventorystore.hpp"
|
#include "../mwworld/inventorystore.hpp"
|
||||||
|
|
||||||
|
#include "weaponanimation.hpp"
|
||||||
|
|
||||||
namespace ESM
|
namespace ESM
|
||||||
{
|
{
|
||||||
struct NPC;
|
struct NPC;
|
||||||
|
@ -25,24 +27,7 @@ public:
|
||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
|
|
||||||
class WeaponAnimationTime : public Ogre::ControllerValue<Ogre::Real>
|
class NpcAnimation : public Animation, public WeaponAnimation, public MWWorld::InventoryStoreListener
|
||||||
{
|
|
||||||
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
|
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual void equipmentChanged() { updateParts(); }
|
virtual void equipmentChanged() { updateParts(); }
|
||||||
|
@ -91,7 +76,6 @@ private:
|
||||||
Ogre::SharedPtr<WeaponAnimationTime> mWeaponAnimationTime;
|
Ogre::SharedPtr<WeaponAnimationTime> mWeaponAnimationTime;
|
||||||
|
|
||||||
float mAlpha;
|
float mAlpha;
|
||||||
float mPitchFactor;
|
|
||||||
|
|
||||||
void updateNpcBase();
|
void updateNpcBase();
|
||||||
|
|
||||||
|
@ -138,7 +122,10 @@ public:
|
||||||
virtual void attachArrow();
|
virtual void attachArrow();
|
||||||
virtual void releaseArrow();
|
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);
|
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)
|
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
|
} // 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;
|
std::string itemName;
|
||||||
for (MWWorld::ContainerStoreIterator iter(store.begin()); iter != store.end(); ++iter)
|
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);
|
itemName = iter->getClass().getName(*iter);
|
||||||
|
|
||||||
int numRemoved = store.remove(item, count, ptr);
|
int numRemoved = store.remove(item, count, ptr);
|
||||||
|
@ -165,7 +165,7 @@ namespace MWScript
|
||||||
MWWorld::ContainerStoreIterator it = invStore.begin();
|
MWWorld::ContainerStoreIterator it = invStore.begin();
|
||||||
for (; it != invStore.end(); ++it)
|
for (; it != invStore.end(); ++it)
|
||||||
{
|
{
|
||||||
if (Misc::StringUtils::ciEqual(it->getCellRef().mRefID, item))
|
if (::Misc::StringUtils::ciEqual(it->getCellRef().mRefID, item))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (it == invStore.end())
|
if (it == invStore.end())
|
||||||
|
@ -268,7 +268,7 @@ namespace MWScript
|
||||||
for (int slot = 0; slot < MWWorld::InventoryStore::Slots; ++slot)
|
for (int slot = 0; slot < MWWorld::InventoryStore::Slots; ++slot)
|
||||||
{
|
{
|
||||||
MWWorld::ContainerStoreIterator it = invStore.getSlot (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);
|
runtime.push(1);
|
||||||
return;
|
return;
|
||||||
|
@ -295,7 +295,7 @@ namespace MWScript
|
||||||
it != invStore.end(); ++it)
|
it != invStore.end(); ++it)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (Misc::StringUtils::ciEqual(it->getCellRef().mSoul, name))
|
if (::Misc::StringUtils::ciEqual(it->getCellRef().mSoul, name))
|
||||||
{
|
{
|
||||||
runtime.push(1);
|
runtime.push(1);
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -24,7 +24,7 @@ namespace MWScript
|
||||||
void GlobalScripts::addScript (const std::string& name)
|
void GlobalScripts::addScript (const std::string& name)
|
||||||
{
|
{
|
||||||
std::map<std::string, std::pair<bool, Locals> >::iterator iter =
|
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())
|
if (iter==mScripts.end())
|
||||||
{
|
{
|
||||||
|
@ -44,7 +44,7 @@ namespace MWScript
|
||||||
void GlobalScripts::removeScript (const std::string& name)
|
void GlobalScripts::removeScript (const std::string& name)
|
||||||
{
|
{
|
||||||
std::map<std::string, std::pair<bool, Locals> >::iterator iter =
|
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())
|
if (iter!=mScripts.end())
|
||||||
iter->second.first = false;
|
iter->second.first = false;
|
||||||
|
@ -53,7 +53,7 @@ namespace MWScript
|
||||||
bool GlobalScripts::isRunning (const std::string& name) const
|
bool GlobalScripts::isRunning (const std::string& name) const
|
||||||
{
|
{
|
||||||
std::map<std::string, std::pair<bool, Locals> >::const_iterator iter =
|
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())
|
if (iter==mScripts.end())
|
||||||
return false;
|
return false;
|
||||||
|
@ -151,7 +151,7 @@ namespace MWScript
|
||||||
|
|
||||||
Locals& GlobalScripts::getLocals (const std::string& name)
|
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 =
|
std::map<std::string, std::pair<bool, Locals> >::iterator iter =
|
||||||
mScripts.find (name2);
|
mScripts.find (name2);
|
||||||
|
|
||||||
|
|
|
@ -113,7 +113,7 @@ namespace MWScript
|
||||||
virtual void execute (Interpreter::Runtime& runtime)
|
virtual void execute (Interpreter::Runtime& runtime)
|
||||||
{
|
{
|
||||||
std::string cell = (runtime.getStringLiteral (runtime[0].mInteger));
|
std::string cell = (runtime.getStringLiteral (runtime[0].mInteger));
|
||||||
Misc::StringUtils::toLower(cell);
|
::Misc::StringUtils::toLower(cell);
|
||||||
runtime.pop();
|
runtime.pop();
|
||||||
|
|
||||||
// "Will match complete or partial cells, so ShowMap, "Vivec" will show cells Vivec and Vivec, Fred's House as well."
|
// "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)
|
for (; it != cells.extEnd(); ++it)
|
||||||
{
|
{
|
||||||
std::string name = it->mName;
|
std::string name = it->mName;
|
||||||
Misc::StringUtils::toLower(name);
|
::Misc::StringUtils::toLower(name);
|
||||||
if (name.find(cell) != std::string::npos)
|
if (name.find(cell) != std::string::npos)
|
||||||
MWBase::Environment::get().getWindowManager()->addVisitedLocation (
|
MWBase::Environment::get().getWindowManager()->addVisitedLocation (
|
||||||
it->mName,
|
it->mName,
|
||||||
|
|
|
@ -540,7 +540,7 @@ namespace MWScript
|
||||||
factionID = runtime.getStringLiteral (runtime[0].mInteger);
|
factionID = runtime.getStringLiteral (runtime[0].mInteger);
|
||||||
runtime.pop();
|
runtime.pop();
|
||||||
}
|
}
|
||||||
Misc::StringUtils::toLower(factionID);
|
::Misc::StringUtils::toLower(factionID);
|
||||||
if(factionID != "")
|
if(factionID != "")
|
||||||
{
|
{
|
||||||
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
|
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
|
||||||
|
@ -569,7 +569,7 @@ namespace MWScript
|
||||||
factionID = runtime.getStringLiteral (runtime[0].mInteger);
|
factionID = runtime.getStringLiteral (runtime[0].mInteger);
|
||||||
runtime.pop();
|
runtime.pop();
|
||||||
}
|
}
|
||||||
Misc::StringUtils::toLower(factionID);
|
::Misc::StringUtils::toLower(factionID);
|
||||||
if(factionID != "")
|
if(factionID != "")
|
||||||
{
|
{
|
||||||
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
|
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
|
||||||
|
@ -602,7 +602,7 @@ namespace MWScript
|
||||||
factionID = runtime.getStringLiteral (runtime[0].mInteger);
|
factionID = runtime.getStringLiteral (runtime[0].mInteger);
|
||||||
runtime.pop();
|
runtime.pop();
|
||||||
}
|
}
|
||||||
Misc::StringUtils::toLower(factionID);
|
::Misc::StringUtils::toLower(factionID);
|
||||||
if(factionID != "")
|
if(factionID != "")
|
||||||
{
|
{
|
||||||
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
|
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
|
||||||
|
@ -640,7 +640,7 @@ namespace MWScript
|
||||||
factionID = MWWorld::Class::get(ptr).getNpcStats(ptr).getFactionRanks().begin()->first;
|
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();
|
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
|
||||||
if(factionID!="")
|
if(factionID!="")
|
||||||
{
|
{
|
||||||
|
@ -742,7 +742,7 @@ namespace MWScript
|
||||||
if (factionId.empty())
|
if (factionId.empty())
|
||||||
throw std::runtime_error ("failed to determine faction");
|
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::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
|
||||||
runtime.push (
|
runtime.push (
|
||||||
|
@ -778,7 +778,7 @@ namespace MWScript
|
||||||
if (factionId.empty())
|
if (factionId.empty())
|
||||||
throw std::runtime_error ("failed to determine faction");
|
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::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
|
||||||
MWWorld::Class::get (player).getNpcStats (player).setFactionReputation (factionId, value);
|
MWWorld::Class::get (player).getNpcStats (player).setFactionReputation (factionId, value);
|
||||||
|
@ -813,7 +813,7 @@ namespace MWScript
|
||||||
if (factionId.empty())
|
if (factionId.empty())
|
||||||
throw std::runtime_error ("failed to determine faction");
|
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::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
|
||||||
MWWorld::Class::get (player).getNpcStats (player).setFactionReputation (factionId,
|
MWWorld::Class::get (player).getNpcStats (player).setFactionReputation (factionId,
|
||||||
|
@ -858,11 +858,11 @@ namespace MWScript
|
||||||
MWWorld::Ptr ptr = R()(runtime);
|
MWWorld::Ptr ptr = R()(runtime);
|
||||||
|
|
||||||
std::string race = runtime.getStringLiteral(runtime[0].mInteger);
|
std::string race = runtime.getStringLiteral(runtime[0].mInteger);
|
||||||
Misc::StringUtils::toLower(race);
|
::Misc::StringUtils::toLower(race);
|
||||||
runtime.pop();
|
runtime.pop();
|
||||||
|
|
||||||
std::string npcRace = ptr.get<ESM::NPC>()->mBase->mRace;
|
std::string npcRace = ptr.get<ESM::NPC>()->mBase->mRace;
|
||||||
Misc::StringUtils::toLower(npcRace);
|
::Misc::StringUtils::toLower(npcRace);
|
||||||
|
|
||||||
runtime.push (npcRace == race);
|
runtime.push (npcRace == race);
|
||||||
}
|
}
|
||||||
|
@ -906,7 +906,7 @@ namespace MWScript
|
||||||
factionID = MWWorld::Class::get(ptr).getNpcStats(ptr).getFactionRanks().begin()->first;
|
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();
|
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
|
||||||
if(factionID!="")
|
if(factionID!="")
|
||||||
{
|
{
|
||||||
|
|
|
@ -99,7 +99,7 @@ namespace MWScript
|
||||||
MWBase::Environment::get().getWorld()->rotateObject(ptr,ax,ay,angle);
|
MWBase::Environment::get().getWorld()->rotateObject(ptr,ax,ay,angle);
|
||||||
}
|
}
|
||||||
else
|
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());
|
runtime.push(Ogre::Radian(ptr.getCellRef().mPos.rot[2]).valueDegrees());
|
||||||
}
|
}
|
||||||
else
|
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());
|
runtime.push(Ogre::Radian(ptr.getRefData().getPosition().rot[2]).valueDegrees());
|
||||||
}
|
}
|
||||||
else
|
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]);
|
runtime.push(ptr.getRefData().getPosition().pos[2]);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
throw std::runtime_error ("invalid rotation axis: " + axis);
|
throw std::runtime_error ("invalid axis: " + axis);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -11,9 +11,10 @@
|
||||||
namespace MWSound
|
namespace MWSound
|
||||||
{
|
{
|
||||||
|
|
||||||
static void fail(const std::string &msg)
|
void FFmpeg_Decoder::fail(const std::string &msg)
|
||||||
{ throw std::runtime_error("FFmpeg exception: "+msg); }
|
{
|
||||||
|
throw std::runtime_error("FFmpeg exception: "+msg);
|
||||||
|
}
|
||||||
|
|
||||||
int FFmpeg_Decoder::readPacket(void *user_data, uint8_t *buf, int buf_size)
|
int FFmpeg_Decoder::readPacket(void *user_data, uint8_t *buf, int buf_size)
|
||||||
{
|
{
|
||||||
|
|
|
@ -61,6 +61,8 @@ namespace MWSound
|
||||||
virtual void rewind();
|
virtual void rewind();
|
||||||
virtual size_t getSampleOffset();
|
virtual size_t getSampleOffset();
|
||||||
|
|
||||||
|
void fail(const std::string &msg);
|
||||||
|
|
||||||
FFmpeg_Decoder& operator=(const FFmpeg_Decoder &rhs);
|
FFmpeg_Decoder& operator=(const FFmpeg_Decoder &rhs);
|
||||||
FFmpeg_Decoder(const FFmpeg_Decoder &rhs);
|
FFmpeg_Decoder(const FFmpeg_Decoder &rhs);
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#include "../mwbase/mechanicsmanager.hpp"
|
#include "../mwbase/mechanicsmanager.hpp"
|
||||||
#include "../mwbase/scriptmanager.hpp"
|
#include "../mwbase/scriptmanager.hpp"
|
||||||
#include "../mwbase/soundmanager.hpp"
|
#include "../mwbase/soundmanager.hpp"
|
||||||
|
#include "../mwbase/inputmanager.hpp"
|
||||||
|
|
||||||
#include "../mwworld/player.hpp"
|
#include "../mwworld/player.hpp"
|
||||||
#include "../mwworld/class.hpp"
|
#include "../mwworld/class.hpp"
|
||||||
|
@ -39,6 +40,7 @@ void MWState::StateManager::cleanup (bool force)
|
||||||
MWBase::Environment::get().getScriptManager()->getGlobalScripts().clear();
|
MWBase::Environment::get().getScriptManager()->getGlobalScripts().clear();
|
||||||
MWBase::Environment::get().getWorld()->clear();
|
MWBase::Environment::get().getWorld()->clear();
|
||||||
MWBase::Environment::get().getWindowManager()->clear();
|
MWBase::Environment::get().getWindowManager()->clear();
|
||||||
|
MWBase::Environment::get().getInputManager()->clear();
|
||||||
|
|
||||||
mState = State_NoGame;
|
mState = State_NoGame;
|
||||||
mCharacterManager.clearCurrentCharacter();
|
mCharacterManager.clearCurrentCharacter();
|
||||||
|
@ -123,11 +125,10 @@ void MWState::StateManager::newGame (bool bypass)
|
||||||
{
|
{
|
||||||
cleanup();
|
cleanup();
|
||||||
|
|
||||||
|
MWBase::Environment::get().getWorld()->startNewGame (bypass);
|
||||||
|
|
||||||
if (!bypass)
|
if (!bypass)
|
||||||
{
|
|
||||||
MWBase::Environment::get().getWorld()->startNewGame();
|
|
||||||
MWBase::Environment::get().getWindowManager()->setNewGame (true);
|
MWBase::Environment::get().getWindowManager()->setNewGame (true);
|
||||||
}
|
|
||||||
else
|
else
|
||||||
MWBase::Environment::get().getWorld()->setGlobalInt ("chargenstate", -1);
|
MWBase::Environment::get().getWorld()->setGlobalInt ("chargenstate", -1);
|
||||||
|
|
||||||
|
|
|
@ -363,7 +363,22 @@ namespace MWWorld
|
||||||
return newPtr;
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -307,7 +307,10 @@ namespace MWWorld
|
||||||
return false;
|
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;
|
virtual int getSkill(const MWWorld::Ptr& ptr, int skill) const;
|
||||||
|
|
||||||
|
|
|
@ -130,31 +130,52 @@ namespace MWWorld
|
||||||
position.z += halfExtents.z;
|
position.z += halfExtents.z;
|
||||||
|
|
||||||
waterlevel -= halfExtents.z * 0.5;
|
waterlevel -= halfExtents.z * 0.5;
|
||||||
|
/*
|
||||||
|
* A 3/4 submerged example
|
||||||
|
*
|
||||||
|
* +---+
|
||||||
|
* | |
|
||||||
|
* | | <- (original waterlevel)
|
||||||
|
* | |
|
||||||
|
* | | <- position <- waterlevel
|
||||||
|
* | |
|
||||||
|
* | |
|
||||||
|
* | |
|
||||||
|
* +---+ <- (original position)
|
||||||
|
*/
|
||||||
|
|
||||||
OEngine::Physic::ActorTracer tracer;
|
OEngine::Physic::ActorTracer tracer;
|
||||||
bool wasOnGround = false;
|
bool wasOnGround = false;
|
||||||
bool isOnGround = false;
|
bool isOnGround = false;
|
||||||
Ogre::Vector3 inertia(0.0f);
|
Ogre::Vector3 inertia(0.0f);
|
||||||
Ogre::Vector3 velocity;
|
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)*
|
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;
|
Ogre::Quaternion(Ogre::Radian(refpos.rot[0]), Ogre::Vector3::NEGATIVE_UNIT_X)) * movement;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
velocity = Ogre::Quaternion(Ogre::Radian(refpos.rot[2]), Ogre::Vector3::NEGATIVE_UNIT_Z) * movement;
|
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(!physicActor->getOnGround())
|
||||||
{
|
{
|
||||||
// If falling, add part of the incoming velocity with the current inertia
|
// 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))
|
if(!(movement.z > 0.0f))
|
||||||
{
|
{
|
||||||
wasOnGround = physicActor->getOnGround();
|
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)
|
if(tracer.mFraction < 1.0f && getSlope(tracer.mPlaneNormal) <= sMaxSlope)
|
||||||
isOnGround = true;
|
isOnGround = true;
|
||||||
}
|
}
|
||||||
|
@ -163,24 +184,38 @@ namespace MWWorld
|
||||||
if(isOnGround)
|
if(isOnGround)
|
||||||
{
|
{
|
||||||
// if we're on the ground, don't try to fall
|
// 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;
|
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;
|
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 &&
|
// If not able to fly, walk or bipedal don't allow to move out of water
|
||||||
nextpos.z > waterlevel && newPosition.z <= waterlevel)
|
// 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);
|
const Ogre::Vector3 down(0,0,-1);
|
||||||
Ogre::Real movelen = velocity.normalise();
|
Ogre::Real movelen = velocity.normalise();
|
||||||
Ogre::Vector3 reflectdir = velocity.reflect(down);
|
Ogre::Vector3 reflectdir = velocity.reflect(down);
|
||||||
reflectdir.normalise();
|
reflectdir.normalise();
|
||||||
velocity = slide(reflectdir, down)*movelen;
|
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
|
// trace to where character would go if there were no obstructions
|
||||||
|
@ -189,13 +224,14 @@ namespace MWWorld
|
||||||
// check for obstructions
|
// check for obstructions
|
||||||
if(tracer.mFraction >= 1.0f)
|
if(tracer.mFraction >= 1.0f)
|
||||||
{
|
{
|
||||||
newPosition = tracer.mEndPos;
|
newPosition = tracer.mEndPos; // ok to move, so set newPosition
|
||||||
remainingTime *= (1.0f-tracer.mFraction);
|
remainingTime *= (1.0f-tracer.mFraction); // FIXME: remainingTime is no longer used so don't set it?
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We hit something. Try to step up onto it.
|
// 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
|
isOnGround = !(newPosition.z < waterlevel || isFlying); // Only on the ground if there's gravity
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -214,7 +250,7 @@ namespace MWWorld
|
||||||
|
|
||||||
if(isOnGround || wasOnGround)
|
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)
|
if(tracer.mFraction < 1.0f && getSlope(tracer.mPlaneNormal) <= sMaxSlope)
|
||||||
{
|
{
|
||||||
newPosition.z = tracer.mEndPos.z + 1.0f;
|
newPosition.z = tracer.mEndPos.z + 1.0f;
|
||||||
|
@ -236,7 +272,7 @@ namespace MWWorld
|
||||||
}
|
}
|
||||||
physicActor->setOnGround(isOnGround);
|
physicActor->setOnGround(isOnGround);
|
||||||
|
|
||||||
newPosition.z -= halfExtents.z;
|
newPosition.z -= halfExtents.z; // remove what was added at the beggining
|
||||||
return newPosition;
|
return newPosition;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -121,13 +121,15 @@ namespace MWWorld
|
||||||
const Files::Collections& fileCollections,
|
const Files::Collections& fileCollections,
|
||||||
const std::vector<std::string>& contentFiles,
|
const std::vector<std::string>& contentFiles,
|
||||||
const boost::filesystem::path& resDir, const boost::filesystem::path& cacheDir,
|
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),
|
: mPlayer (0), mLocalScripts (mStore),
|
||||||
mSky (true), mCells (mStore, mEsm),
|
mSky (true), mCells (mStore, mEsm),
|
||||||
mActivationDistanceOverride (mActivationDistanceOverride),
|
mActivationDistanceOverride (activationDistanceOverride),
|
||||||
mFallback(fallbackMap), mPlayIntro(0), mTeleportEnabled(true), mLevitationEnabled(true),
|
mFallback(fallbackMap), mPlayIntro(0), mTeleportEnabled(true), mLevitationEnabled(true),
|
||||||
mFacedDistance(FLT_MAX), mGodMode(false), mContentFiles (contentFiles),
|
mFacedDistance(FLT_MAX), mGodMode(false), mContentFiles (contentFiles),
|
||||||
mGoToJail(false)
|
mGoToJail(false),
|
||||||
|
mStartCell (startCell)
|
||||||
{
|
{
|
||||||
mPhysics = new PhysicsSystem(renderer);
|
mPhysics = new PhysicsSystem(renderer);
|
||||||
mPhysEngine = mPhysics->getEngine();
|
mPhysEngine = mPhysics->getEngine();
|
||||||
|
@ -168,7 +170,7 @@ namespace MWWorld
|
||||||
mWorldScene = new Scene(*mRendering, mPhysics);
|
mWorldScene = new Scene(*mRendering, mPhysics);
|
||||||
}
|
}
|
||||||
|
|
||||||
void World::startNewGame()
|
void World::startNewGame (bool bypass)
|
||||||
{
|
{
|
||||||
mGoToJail = false;
|
mGoToJail = false;
|
||||||
mLevitationEnabled = true;
|
mLevitationEnabled = true;
|
||||||
|
@ -181,23 +183,44 @@ namespace MWWorld
|
||||||
|
|
||||||
MWBase::Environment::get().getWindowManager()->updatePlayer();
|
MWBase::Environment::get().getWindowManager()->updatePlayer();
|
||||||
|
|
||||||
// FIXME: this will add cell 0,0 as visible on the global map
|
if (bypass && !mStartCell.empty())
|
||||||
ESM::Position pos;
|
{
|
||||||
const int cellSize = 8192;
|
ESM::Position pos;
|
||||||
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);
|
|
||||||
|
|
||||||
// FIXME: should be set to 1, but the sound manager won't pause newly started sounds
|
if (findExteriorPosition (mStartCell, pos))
|
||||||
mPlayIntro = 2;
|
{
|
||||||
|
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
|
if (!bypass)
|
||||||
mGlobalVariables["chargenstate"].setInteger (1);
|
{
|
||||||
mGlobalVariables["pcrace"].setInteger (3);
|
// 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
|
// we don't want old weather to persist on a new game
|
||||||
delete mWeatherManager;
|
delete mWeatherManager;
|
||||||
|
@ -1626,7 +1649,7 @@ namespace MWWorld
|
||||||
if (ptr.getClass().getCreatureStats(ptr).isDead())
|
if (ptr.getClass().getCreatureStats(ptr).isDead())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (ptr.getClass().isFlying(ptr))
|
if (ptr.getClass().canFly(ptr))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
const MWMechanics::CreatureStats &stats = ptr.getClass().getCreatureStats(ptr);
|
const MWMechanics::CreatureStats &stats = ptr.getClass().getCreatureStats(ptr);
|
||||||
|
|
|
@ -120,6 +120,9 @@ namespace MWWorld
|
||||||
|
|
||||||
std::map<MWWorld::Ptr, MagicBoltState> mMagicBolts;
|
std::map<MWWorld::Ptr, MagicBoltState> mMagicBolts;
|
||||||
std::map<MWWorld::Ptr, ProjectileState> mProjectiles;
|
std::map<MWWorld::Ptr, ProjectileState> mProjectiles;
|
||||||
|
|
||||||
|
std::string mStartCell;
|
||||||
|
|
||||||
void updateWeather(float duration);
|
void updateWeather(float duration);
|
||||||
int getDaysPerMonth (int month) const;
|
int getDaysPerMonth (int month) const;
|
||||||
|
|
||||||
|
@ -179,11 +182,13 @@ namespace MWWorld
|
||||||
const Files::Collections& fileCollections,
|
const Files::Collections& fileCollections,
|
||||||
const std::vector<std::string>& contentFiles,
|
const std::vector<std::string>& contentFiles,
|
||||||
const boost::filesystem::path& resDir, const boost::filesystem::path& cacheDir,
|
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 ~World();
|
||||||
|
|
||||||
virtual void startNewGame();
|
virtual void startNewGame (bool bypass);
|
||||||
|
///< \param bypass Bypass regular game start.
|
||||||
|
|
||||||
virtual void clear();
|
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)
|
macro (add_openmw_dir dir)
|
||||||
set (files)
|
set (files)
|
||||||
foreach (u ${ARGN})
|
set (cppfiles)
|
||||||
file (GLOB ALL "${dir}/${u}.[ch]pp")
|
foreach (u ${ARGN})
|
||||||
foreach (f ${ALL})
|
|
||||||
list (APPEND files "${f}")
|
# Add cpp and hpp to OPENMW_FILES
|
||||||
list (APPEND OPENMW_FILES "${f}")
|
file (GLOB ALL "${dir}/${u}.[ch]pp")
|
||||||
endforeach (f)
|
foreach (f ${ALL})
|
||||||
endforeach (u)
|
list (APPEND files "${f}")
|
||||||
source_group ("apps\\openmw\\${dir}" FILES ${files})
|
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)
|
endmacro (add_openmw_dir)
|
||||||
|
|
||||||
macro (add_component_dir dir)
|
macro (add_component_dir dir)
|
||||||
set (files)
|
set (files)
|
||||||
foreach (u ${ARGN})
|
set (cppfiles)
|
||||||
file (GLOB ALL "${dir}/${u}.[ch]pp")
|
|
||||||
foreach (f ${ALL})
|
foreach (u ${ARGN})
|
||||||
list (APPEND files "${f}")
|
file (GLOB ALL "${dir}/${u}.[ch]pp")
|
||||||
list (APPEND COMPONENT_FILES "${f}")
|
|
||||||
endforeach (f)
|
foreach (f ${ALL})
|
||||||
endforeach (u)
|
list (APPEND files "${f}")
|
||||||
source_group ("components\\${dir}" FILES ${files})
|
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)
|
endmacro (add_component_dir)
|
||||||
|
|
||||||
macro (add_component_qt_dir dir)
|
macro (add_component_qt_dir dir)
|
||||||
|
|
|
@ -111,7 +111,7 @@ void BSAFile::readHeader()
|
||||||
fail("Directory information larger than entire archive");
|
fail("Directory information larger than entire archive");
|
||||||
|
|
||||||
// Read the offset info into a temporary buffer
|
// 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);
|
input.read(reinterpret_cast<char*>(&offsets[0]), 12*filenum);
|
||||||
|
|
||||||
// Read the string table
|
// Read the string table
|
||||||
|
|
|
@ -18,7 +18,7 @@ bool Compiler::DeclarationParser::parseName (const std::string& name, const Toke
|
||||||
{
|
{
|
||||||
if (mState==State_Name)
|
if (mState==State_Name)
|
||||||
{
|
{
|
||||||
std::string name2 = Misc::StringUtils::lowerCase (name);
|
std::string name2 = ::Misc::StringUtils::lowerCase (name);
|
||||||
|
|
||||||
char type = mLocals.getType (name2);
|
char type = mLocals.getType (name2);
|
||||||
|
|
||||||
|
|
|
@ -50,7 +50,7 @@ namespace Interpreter
|
||||||
return literalBlock+offset;
|
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();
|
clear();
|
||||||
|
|
||||||
|
|
|
@ -282,9 +282,6 @@ bool QuadTreeNode::update(const Ogre::Vector3 &cameraPos)
|
||||||
size_t wantedLod = 0;
|
size_t wantedLod = 0;
|
||||||
float cellWorldSize = mTerrain->getStorage()->getCellWorldSize();
|
float cellWorldSize = mTerrain->getStorage()->getCellWorldSize();
|
||||||
|
|
||||||
if (!mTerrain->getDistantLandEnabled() && dist > cellWorldSize)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
if (dist > cellWorldSize*64)
|
if (dist > cellWorldSize*64)
|
||||||
wantedLod = 6;
|
wantedLod = 6;
|
||||||
else if (dist > cellWorldSize*32)
|
else if (dist > cellWorldSize*32)
|
||||||
|
@ -357,6 +354,7 @@ bool QuadTreeNode::update(const Ogre::Vector3 &cameraPos)
|
||||||
|
|
||||||
if (!childrenLoaded)
|
if (!childrenLoaded)
|
||||||
{
|
{
|
||||||
|
mChunk->setVisible(true);
|
||||||
// Make sure child scene nodes are detached until all children are loaded
|
// Make sure child scene nodes are detached until all children are loaded
|
||||||
mSceneNode->removeAllChildren();
|
mSceneNode->removeAllChildren();
|
||||||
}
|
}
|
||||||
|
@ -391,6 +389,8 @@ void QuadTreeNode::load(const LoadResponseData &data)
|
||||||
mChunk = new Chunk(mTerrain->getBufferCache().getUVBuffer(), mBounds, data);
|
mChunk = new Chunk(mTerrain->getBufferCache().getUVBuffer(), mBounds, data);
|
||||||
mChunk->setVisibilityFlags(mTerrain->getVisiblityFlags());
|
mChunk->setVisibilityFlags(mTerrain->getVisiblityFlags());
|
||||||
mChunk->setCastShadows(true);
|
mChunk->setCastShadows(true);
|
||||||
|
if (!mTerrain->getDistantLandEnabled())
|
||||||
|
mChunk->setRenderingDistance(8192);
|
||||||
mSceneNode->attachObject(mChunk);
|
mSceneNode->attachObject(mChunk);
|
||||||
|
|
||||||
mMaterialGenerator->enableShadows(mTerrain->getShadowsEnabled());
|
mMaterialGenerator->enableShadows(mTerrain->getShadowsEnabled());
|
||||||
|
@ -437,7 +437,7 @@ void QuadTreeNode::unload(bool recursive)
|
||||||
if (recursive && hasChildren())
|
if (recursive && hasChildren())
|
||||||
{
|
{
|
||||||
for (int i=0; i<4; ++i)
|
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:
|
Public Relations and Translations:
|
||||||
|
Alex McKibben (WeirdSexy) - Podcaster
|
||||||
Artem Kotsynyak (greye) - Russian News Writer
|
Artem Kotsynyak (greye) - Russian News Writer
|
||||||
|
Jim Clauwaert (Zedd) - Public Outreach
|
||||||
Julien Voisin (jvoisin/ap0) - French News Writer
|
Julien Voisin (jvoisin/ap0) - French News Writer
|
||||||
|
Lukasz Gromanowski (lgro) - English News Writer
|
||||||
Mickey Lyle (raevol) - Release Manager
|
Mickey Lyle (raevol) - Release Manager
|
||||||
Pithorn - Chinese News Writer
|
Pithorn - Chinese News Writer
|
||||||
sir_herrbatka - English/Polish News Writer
|
sir_herrbatka - Polish News Writer
|
||||||
Alex McKibben (WeirdSexy) - Podcaster
|
|
||||||
|
|
||||||
|
|
||||||
Website:
|
Website:
|
||||||
|
|
|
@ -2,5 +2,11 @@
|
||||||
|
|
||||||
<MyGUI type="Layout">
|
<MyGUI type="Layout">
|
||||||
<!-- The entire screen -->
|
<!-- 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>
|
</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>static.png</file>
|
||||||
<file>weapon.png</file>
|
<file>weapon.png</file>
|
||||||
<file>multitype.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-addon">raster/startup/big/create-addon.png</file>
|
||||||
<file alias="startup/create-game">raster/startup/big/new-game.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>
|
<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
|
Website: http://www.openmw.org
|
||||||
|
|
||||||
Font Licenses:
|
Font Licenses:
|
||||||
EBGaramond-Regular.ttf: OFL (see OFL.txt for more information)
|
|
||||||
DejaVuLGCSansMono.ttf: custom (see DejaVu Font License.txt for more information)
|
DejaVuLGCSansMono.ttf: custom (see DejaVu Font License.txt for more information)
|
||||||
|
|
||||||
|
|
||||||
|
|