Merge branch 'master' of git://github.com/zinnschlag/openmw into graphics

actorid
scrawl 12 years ago
commit 3ec703e6af

2
.gitignore vendored

@ -15,3 +15,5 @@ makefile
data data
*.kdev4 *.kdev4
CMakeLists.txt.user CMakeLists.txt.user
*.swp
*.swo

@ -1,123 +0,0 @@
Bitstream Vera Fonts Copyright
The fonts have a generous copyright, allowing derivative works (as
long as "Bitstream" or "Vera" are not in the names), and full
redistribution (so long as they are not *sold* by themselves). They
can be be bundled, redistributed and sold with any software.
The fonts are distributed under the following copyright:
Copyright
=========
Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream
Vera is a trademark of Bitstream, Inc.
Permission is hereby granted, free of charge, to any person obtaining
a copy of the fonts accompanying this license ("Fonts") and associated
documentation files (the "Font Software"), to reproduce and distribute
the Font Software, including without limitation the rights to use,
copy, merge, publish, distribute, and/or sell copies of the Font
Software, and to permit persons to whom the Font Software is furnished
to do so, subject to the following conditions:
The above copyright and trademark notices and this permission notice
shall be included in all copies of one or more of the Font Software
typefaces.
The Font Software may be modified, altered, or added to, and in
particular the designs of glyphs or characters in the Fonts may be
modified and additional glyphs or characters may be added to the
Fonts, only if the fonts are renamed to names not containing either
the words "Bitstream" or the word "Vera".
This License becomes null and void to the extent applicable to Fonts
or Font Software that has been modified and is distributed under the
"Bitstream Vera" names.
The Font Software may be sold as part of a larger software package but
no copy of one or more of the Font Software typefaces may be sold by
itself.
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
BITSTREAM OR THE GNOME FOUNDATION 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.
Except as contained in this notice, the names of Gnome, the Gnome
Foundation, and Bitstream Inc., shall not be used in advertising or
otherwise to promote the sale, use or other dealings in this Font
Software without prior written authorization from the Gnome Foundation
or Bitstream Inc., respectively. For further information, contact:
fonts at gnome dot org.
Copyright FAQ
=============
1. I don't understand the resale restriction... What gives?
Bitstream is giving away these fonts, but wishes to ensure its
competitors can't just drop the fonts as is into a font sale system
and sell them as is. It seems fair that if Bitstream can't make money
from the Bitstream Vera fonts, their competitors should not be able to
do so either. You can sell the fonts as part of any software package,
however.
2. I want to package these fonts separately for distribution and
sale as part of a larger software package or system. Can I do so?
Yes. A RPM or Debian package is a "larger software package" to begin
with, and you aren't selling them independently by themselves.
See 1. above.
3. Are derivative works allowed?
Yes!
4. Can I change or add to the font(s)?
Yes, but you must change the name(s) of the font(s).
5. Under what terms are derivative works allowed?
You must change the name(s) of the fonts. This is to ensure the
quality of the fonts, both to protect Bitstream and Gnome. We want to
ensure that if an application has opened a font specifically of these
names, it gets what it expects (though of course, using fontconfig,
substitutions could still could have occurred during font
opening). You must include the Bitstream copyright. Additional
copyrights can be added, as per copyright law. Happy Font Hacking!
6. If I have improvements for Bitstream Vera, is it possible they might get
adopted in future versions?
Yes. The contract between the Gnome Foundation and Bitstream has
provisions for working with Bitstream to ensure quality additions to
the Bitstream Vera font family. Please contact us if you have such
additions. Note, that in general, we will want such additions for the
entire family, not just a single font, and that you'll have to keep
both Gnome and Jim Lyles, Vera's designer, happy! To make sense to add
glyphs to the font, they must be stylistically in keeping with Vera's
design. Vera cannot become a "ransom note" font. Jim Lyles will be
providing a document describing the design elements used in Vera, as a
guide and aid for people interested in contributing to Vera.
7. I want to sell a software package that uses these fonts: Can I do so?
Sure. Bundle the fonts with your software and sell your software
with the fonts. That is the intent of the copyright.
8. If applications have built the names "Bitstream Vera" into them,
can I override this somehow to use fonts of my choosing?
This depends on exact details of the software. Most open source
systems and software (e.g., Gnome, KDE, etc.) are now converting to
use fontconfig (see www.fontconfig.org) to handle font configuration,
selection and substitution; it has provisions for overriding font
names and subsituting alternatives. An example is provided by the
supplied local.conf file, which chooses the family Bitstream Vera for
"sans", "serif" and "monospace". Other software (e.g., the XFree86
core server) has other mechanisms for font substitution.

@ -67,35 +67,6 @@ endif()
# We probably support older versions than this. # We probably support older versions than this.
cmake_minimum_required(VERSION 2.6) cmake_minimum_required(VERSION 2.6)
#
# Pre-built binaries being used?
#
IF(EXISTS "${CMAKE_SOURCE_DIR}/prebuilt/vc100-mt-gd/ogre_1_7_1")
set(PREBUILT_DIR "${CMAKE_SOURCE_DIR}/prebuilt/vc100-mt-gd")
message (STATUS "OpenMW pre-built binaries found at ${PREBUILT_DIR}.")
SET(ENV{OGRE_HOME} "${PREBUILT_DIR}/ogre_1_7_1")
SET(ENV{BOOST_ROOT} "${PREBUILT_DIR}/boost_1_42_0")
set(Boost_USE_STATIC_LIBS ON)
set(Boost_USE_MULTITHREADED ON)
set(ENV{BOOST_INCLUDEDIR} "${BOOST_ROOT}/include")
set(ENV{BOOST_LIBRARYDIR} "${BOOST_ROOT}/lib")
set(ENV{FREETYPE_DIR} "${PREBUILT_DIR}/freetype-2.3.5-1")
set(USE_MPG123 OFF)
set(USE_AUDIERE ON)
set(AUDIERE_INCLUDE_DIR "${PREBUILT_DIR}/audiere-1.9.4/include")
set(AUDIERE_LIBRARY "${PREBUILT_DIR}/audiere-1.9.4/lib/audiere.lib")
set(ENV{OPENALDIR} "${PREBUILT_DIR}/OpenAL 1.1 SDK")
set(BULLET_ROOT "${PREBUILT_DIR}/bullet")
ELSE()
message (STATUS "OpenMW pre-built binaries not found. Using standard locations.")
ENDIF()
# source directory: libs # source directory: libs
set(LIBDIR ${CMAKE_SOURCE_DIR}/libs) set(LIBDIR ${CMAKE_SOURCE_DIR}/libs)

@ -0,0 +1,99 @@
Fonts are (c) Bitstream (see below). DejaVu changes are in public domain.
Glyphs imported from Arev fonts are (c) Tavmjong Bah (see below)
Bitstream Vera Fonts Copyright
------------------------------
Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream Vera is
a trademark of Bitstream, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy
of the fonts accompanying this license ("Fonts") and associated
documentation files (the "Font Software"), to reproduce and distribute the
Font Software, including without limitation the rights to use, copy, merge,
publish, distribute, and/or sell copies of the Font Software, and to permit
persons to whom the Font Software is furnished to do so, subject to the
following conditions:
The above copyright and trademark notices and this permission notice shall
be included in all copies of one or more of the Font Software typefaces.
The Font Software may be modified, altered, or added to, and in particular
the designs of glyphs or characters in the Fonts may be modified and
additional glyphs or characters may be added to the Fonts, only if the fonts
are renamed to names not containing either the words "Bitstream" or the word
"Vera".
This License becomes null and void to the extent applicable to Fonts or Font
Software that has been modified and is distributed under the "Bitstream
Vera" names.
The Font Software may be sold as part of a larger software package but no
copy of one or more of the Font Software typefaces may be sold by itself.
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 BITSTREAM OR THE GNOME
FOUNDATION 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.
Except as contained in this notice, the names of Gnome, the Gnome
Foundation, and Bitstream Inc., shall not be used in advertising or
otherwise to promote the sale, use or other dealings in this Font Software
without prior written authorization from the Gnome Foundation or Bitstream
Inc., respectively. For further information, contact: fonts at gnome dot
org.
Arev Fonts Copyright
------------------------------
Copyright (c) 2006 by Tavmjong Bah. All Rights Reserved.
Permission is hereby granted, free of charge, to any person obtaining
a copy of the fonts accompanying this license ("Fonts") and
associated documentation files (the "Font Software"), to reproduce
and distribute the modifications to the Bitstream Vera Font Software,
including without limitation the rights to use, copy, merge, publish,
distribute, and/or sell copies of the Font Software, and to permit
persons to whom the Font Software is furnished to do so, subject to
the following conditions:
The above copyright and trademark notices and this permission notice
shall be included in all copies of one or more of the Font Software
typefaces.
The Font Software may be modified, altered, or added to, and in
particular the designs of glyphs or characters in the Fonts may be
modified and additional glyphs or characters may be added to the
Fonts, only if the fonts are renamed to names not containing either
the words "Tavmjong Bah" or the word "Arev".
This License becomes null and void to the extent applicable to Fonts
or Font Software that has been modified and is distributed under the
"Tavmjong Bah Arev" names.
The Font Software may be sold as part of a larger software package but
no copy of one or more of the Font Software typefaces may be sold by
itself.
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
TAVMJONG BAH 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.
Except as contained in this notice, the name of Tavmjong Bah shall not
be used in advertising or otherwise to promote the sale, use or other
dealings in this Font Software without prior written authorization
from Tavmjong Bah. For further information, contact: tavmjong @ free
. fr.
$Id: LICENSE 2133 2007-11-28 02:46:28Z lechimp $

@ -1,8 +1,8 @@
#include "columnbase.hpp" #include "columnbase.hpp"
CSMWorld::ColumnBase::ColumnBase (const std::string& title, int flags) CSMWorld::ColumnBase::ColumnBase (const std::string& title, Display displayType, int flags)
: mTitle (title), mFlags (flags) : mTitle (title), mDisplayType (displayType), mFlags (flags)
{} {}
CSMWorld::ColumnBase::~ColumnBase() {} CSMWorld::ColumnBase::~ColumnBase() {}

@ -14,7 +14,8 @@ namespace CSMWorld
{ {
enum Roles enum Roles
{ {
Role_Flags = Qt::UserRole Role_Flags = Qt::UserRole,
Role_Display = Qt::UserRole+1
}; };
enum Flags enum Flags
@ -23,10 +24,18 @@ namespace CSMWorld
Flag_Dialogue = 2 // column should be displayed in dialogue view Flag_Dialogue = 2 // column should be displayed in dialogue view
}; };
enum Display
{
Display_String,
Display_Integer,
Display_Float
};
std::string mTitle; std::string mTitle;
int mFlags; int mFlags;
Display mDisplayType;
ColumnBase (const std::string& title, int flag); ColumnBase (const std::string& title, Display displayType, int flag);
virtual ~ColumnBase(); virtual ~ColumnBase();
@ -34,6 +43,7 @@ namespace CSMWorld
virtual bool isUserEditable() const; virtual bool isUserEditable() const;
///< Can this column be edited directly by the user? ///< Can this column be edited directly by the user?
}; };
template<typename ESXRecordT> template<typename ESXRecordT>
@ -42,8 +52,8 @@ namespace CSMWorld
std::string mTitle; std::string mTitle;
int mFlags; int mFlags;
Column (const std::string& title, int flags = Flag_Table | Flag_Dialogue) Column (const std::string& title, Display displayType, int flags = Flag_Table | Flag_Dialogue)
: ColumnBase (title, flags) {} : ColumnBase (title, displayType, flags) {}
virtual QVariant get (const Record<ESXRecordT>& record) const = 0; virtual QVariant get (const Record<ESXRecordT>& record) const = 0;

@ -8,7 +8,7 @@ namespace CSMWorld
template<typename ESXRecordT> template<typename ESXRecordT>
struct FloatValueColumn : public Column<ESXRecordT> struct FloatValueColumn : public Column<ESXRecordT>
{ {
FloatValueColumn() : Column<ESXRecordT> ("Value") {} FloatValueColumn() : Column<ESXRecordT> ("Value", ColumnBase::Display_Float) {}
virtual QVariant get (const Record<ESXRecordT>& record) const virtual QVariant get (const Record<ESXRecordT>& record) const
{ {
@ -31,7 +31,7 @@ namespace CSMWorld
template<typename ESXRecordT> template<typename ESXRecordT>
struct StringIdColumn : public Column<ESXRecordT> struct StringIdColumn : public Column<ESXRecordT>
{ {
StringIdColumn() : Column<ESXRecordT> ("ID") {} StringIdColumn() : Column<ESXRecordT> ("ID", ColumnBase::Display_String) {}
virtual QVariant get (const Record<ESXRecordT>& record) const virtual QVariant get (const Record<ESXRecordT>& record) const
{ {
@ -47,7 +47,7 @@ namespace CSMWorld
template<typename ESXRecordT> template<typename ESXRecordT>
struct RecordStateColumn : public Column<ESXRecordT> struct RecordStateColumn : public Column<ESXRecordT>
{ {
RecordStateColumn() : Column<ESXRecordT> ("*") {} RecordStateColumn() : Column<ESXRecordT> ("*", ColumnBase::Display_Integer) {}
virtual QVariant get (const Record<ESXRecordT>& record) const virtual QVariant get (const Record<ESXRecordT>& record) const
{ {
@ -78,7 +78,8 @@ namespace CSMWorld
{ {
int mType; int mType;
FixedRecordTypeColumn (int type) : Column<ESXRecordT> ("Type", 0), mType (type) {} FixedRecordTypeColumn (int type)
: Column<ESXRecordT> ("Type", ColumnBase::Display_Integer, 0), mType (type) {}
virtual QVariant get (const Record<ESXRecordT>& record) const virtual QVariant get (const Record<ESXRecordT>& record) const
{ {

@ -51,6 +51,9 @@ QVariant CSMWorld::IdTable::headerData (int section, Qt::Orientation orientation
if (role==ColumnBase::Role_Flags) if (role==ColumnBase::Role_Flags)
return mIdCollection->getColumn (section).mFlags; return mIdCollection->getColumn (section).mFlags;
if (role==ColumnBase::Role_Display)
return mIdCollection->getColumn (section).mDisplayType;
return QVariant(); return QVariant();
} }

@ -4,8 +4,13 @@
#include <QGridLayout> #include <QGridLayout>
#include <QLabel> #include <QLabel>
#include <QAbstractTableModel> #include <QAbstractTableModel>
#include <QDoubleSpinBox>
#include <QSpinBox>
#include <QLineEdit>
#include <QDataWidgetMapper>
#include "../../model/world/columnbase.hpp" #include "../../model/world/columnbase.hpp"
#include "../../model/world/idtable.hpp"
CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document, CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document,
bool createAndDelete) bool createAndDelete)
@ -23,6 +28,9 @@ CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, CSM
int columns = model->columnCount(); int columns = model->columnCount();
mWidgetMapper = new QDataWidgetMapper (this);
mWidgetMapper->setModel (model);
for (int i=0; i<columns; ++i) for (int i=0; i<columns; ++i)
{ {
int flags = model->headerData (i, Qt::Horizontal, CSMWorld::ColumnBase::Role_Flags).toInt(); int flags = model->headerData (i, Qt::Horizontal, CSMWorld::ColumnBase::Role_Flags).toInt();
@ -30,8 +38,54 @@ CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, CSM
if (flags & CSMWorld::ColumnBase::Flag_Dialogue) if (flags & CSMWorld::ColumnBase::Flag_Dialogue)
{ {
layout->addWidget (new QLabel (model->headerData (i, Qt::Horizontal).toString()), i, 0); layout->addWidget (new QLabel (model->headerData (i, Qt::Horizontal).toString()), i, 0);
CSMWorld::ColumnBase::Display display = static_cast<CSMWorld::ColumnBase::Display>
(model->headerData (i, Qt::Horizontal, CSMWorld::ColumnBase::Role_Display).toInt());
QWidget *widget = 0;
if (model->flags (model->index (0, i)) & Qt::ItemIsEditable)
{
switch (display)
{
case CSMWorld::ColumnBase::Display_String:
layout->addWidget (widget = new QLineEdit, i, 1);
break;
case CSMWorld::ColumnBase::Display_Integer:
/// \todo configure widget properly (range)
layout->addWidget (widget = new QSpinBox, i, 1);
break;
case CSMWorld::ColumnBase::Display_Float:
/// \todo configure widget properly (range, format?)
layout->addWidget (widget = new QDoubleSpinBox, i, 1);
break;
}
}
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;
}
}
if (widget)
mWidgetMapper->addMapping (widget, i);
} }
} }
mWidgetMapper->setCurrentModelIndex (
dynamic_cast<CSMWorld::IdTable&> (*model).getModelIndex (id.getId(), 0));
} }
void CSVWorld::DialogueSubView::setEditLock (bool locked) void CSVWorld::DialogueSubView::setEditLock (bool locked)

@ -3,6 +3,8 @@
#include "../doc/subview.hpp" #include "../doc/subview.hpp"
class QDataWidgetMapper;
namespace CSMDoc namespace CSMDoc
{ {
class Document; class Document;
@ -12,6 +14,7 @@ namespace CSVWorld
{ {
class DialogueSubView : public CSVDoc::SubView class DialogueSubView : public CSVDoc::SubView
{ {
QDataWidgetMapper *mWidgetMapper;
public: public:

@ -21,5 +21,6 @@ void CSVWorld::TableSubView::setEditLock (bool locked)
void CSVWorld::TableSubView::rowActivated (const QModelIndex& index) void CSVWorld::TableSubView::rowActivated (const QModelIndex& index)
{ {
focusId (mTable->getUniversalId (index.row())); /// \todo re-enable, after dialogue sub views have been fixed up
// focusId (mTable->getUniversalId (index.row()));
} }

@ -84,7 +84,7 @@ namespace MWBase
///< Start playing music from the selected folder ///< Start playing music from the selected folder
/// \param name of the folder that contains the playlist /// \param name of the folder that contains the playlist
virtual void say(MWWorld::Ptr reference, const std::string& filename) = 0; virtual void say(const MWWorld::Ptr &reference, const std::string& filename) = 0;
///< Make an actor say some text. ///< Make an actor say some text.
/// \param filename name of a sound file in "Sound/" in the data directory. /// \param filename name of a sound file in "Sound/" in the data directory.
@ -92,10 +92,10 @@ namespace MWBase
///< Say some text, without an actor ref ///< Say some text, without an actor ref
/// \param filename name of a sound file in "Sound/" in the data directory. /// \param filename name of a sound file in "Sound/" in the data directory.
virtual bool sayDone(MWWorld::Ptr reference=MWWorld::Ptr()) const = 0; virtual bool sayDone(const MWWorld::Ptr &reference=MWWorld::Ptr()) const = 0;
///< Is actor not speaking? ///< Is actor not speaking?
virtual void stopSay(MWWorld::Ptr reference=MWWorld::Ptr()) = 0; virtual void stopSay(const MWWorld::Ptr &reference=MWWorld::Ptr()) = 0;
///< Stop an actor speaking ///< Stop an actor speaking
virtual SoundPtr playTrack(const MWSound::DecoderPtr& decoder, PlayType type) = 0; virtual SoundPtr playTrack(const MWSound::DecoderPtr& decoder, PlayType type) = 0;
@ -105,14 +105,14 @@ namespace MWBase
PlayMode mode=Play_Normal) = 0; PlayMode mode=Play_Normal) = 0;
///< Play a sound, independently of 3D-position ///< Play a sound, independently of 3D-position
virtual SoundPtr playSound3D(MWWorld::Ptr reference, const std::string& soundId, virtual SoundPtr playSound3D(const MWWorld::Ptr &reference, const std::string& soundId,
float volume, float pitch, PlayMode mode=Play_Normal) = 0; float volume, float pitch, PlayMode mode=Play_Normal) = 0;
///< Play a sound from an object ///< Play a sound from an object
virtual void stopSound3D(MWWorld::Ptr reference, const std::string& soundId) = 0; virtual void stopSound3D(const MWWorld::Ptr &reference, const std::string& soundId) = 0;
///< Stop the given object from playing the given sound, ///< Stop the given object from playing the given sound,
virtual void stopSound3D(MWWorld::Ptr reference) = 0; virtual void stopSound3D(const MWWorld::Ptr &reference) = 0;
///< Stop the given object from playing all sounds. ///< Stop the given object from playing all sounds.
virtual void stopSound(const MWWorld::CellStore *cell) = 0; virtual void stopSound(const MWWorld::CellStore *cell) = 0;
@ -121,7 +121,7 @@ namespace MWBase
virtual void stopSound(const std::string& soundId) = 0; virtual void stopSound(const std::string& soundId) = 0;
///< Stop a non-3d looping sound ///< Stop a non-3d looping sound
virtual bool getSoundPlaying(MWWorld::Ptr reference, const std::string& soundId) const = 0; virtual bool getSoundPlaying(const MWWorld::Ptr &reference, const std::string& soundId) const = 0;
///< Is the given sound currently playing on the given object? ///< Is the given sound currently playing on the given object?
virtual void pauseSounds(int types=Play_TypeMask) = 0; virtual void pauseSounds(int types=Play_TypeMask) = 0;

@ -45,6 +45,7 @@ namespace MWWorld
class Ptr; class Ptr;
class TimeStamp; class TimeStamp;
class ESMStore; class ESMStore;
class RefData;
} }
namespace MWBase namespace MWBase
@ -138,6 +139,9 @@ namespace MWBase
virtual std::string getCurrentCellName() const = 0; virtual std::string getCurrentCellName() const = 0;
virtual void removeRefScript (MWWorld::RefData *ref) = 0;
//< Remove the script attached to ref from mLocalScripts
virtual MWWorld::Ptr getPtr (const std::string& name, bool activeOnly) = 0; virtual MWWorld::Ptr getPtr (const std::string& name, bool activeOnly) = 0;
///< Return a pointer to a liveCellRef with the given name. ///< Return a pointer to a liveCellRef with the given name.
/// \param activeOnly do non search inactive cells. /// \param activeOnly do non search inactive cells.

@ -100,14 +100,15 @@ namespace MWClass
} }
else else
{ {
/// \todo do something with mNpdt12 maybe:p
for (int i=0; i<8; ++i) for (int i=0; i<8; ++i)
data->mCreatureStats.getAttribute (i).set (10); data->mCreatureStats.getAttribute (i).set (10);
for (int i=0; i<3; ++i) for (int i=0; i<3; ++i)
data->mCreatureStats.setDynamic (i, 10); data->mCreatureStats.setDynamic (i, 10);
data->mCreatureStats.setLevel (1); data->mCreatureStats.setLevel(ref->mBase->mNpdt12.mLevel);
data->mNpcStats.setBaseDisposition(ref->mBase->mNpdt12.mDisposition);
data->mNpcStats.setReputation(ref->mBase->mNpdt12.mReputation);
} }
data->mCreatureStats.setAiSetting (0, ref->mBase->mAiData.mHello); data->mCreatureStats.setAiSetting (0, ref->mBase->mAiData.mHello);

@ -20,6 +20,7 @@
#include "../mwbase/environment.hpp" #include "../mwbase/environment.hpp"
#include "../mwbase/world.hpp" #include "../mwbase/world.hpp"
#include "../mwbase/journal.hpp"
#include "../mwbase/scriptmanager.hpp" #include "../mwbase/scriptmanager.hpp"
#include "../mwbase/windowmanager.hpp" #include "../mwbase/windowmanager.hpp"
#include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/mechanicsmanager.hpp"
@ -122,15 +123,9 @@ namespace MWDialogue
MWMechanics::CreatureStats& creatureStats = MWWorld::Class::get (actor).getCreatureStats (actor); MWMechanics::CreatureStats& creatureStats = MWWorld::Class::get (actor).getCreatureStats (actor);
mTalkedTo = creatureStats.hasTalkedToPlayer(); mTalkedTo = creatureStats.hasTalkedToPlayer();
creatureStats.talkedToPlayer();
mActorKnownTopics.clear(); mActorKnownTopics.clear();
//initialise the GUI
MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Dialogue);
MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow();
win->startDialogue(actor, MWWorld::Class::get (actor).getName (actor));
//setup the list of topics known by the actor. Topics who are also on the knownTopics list will be added to the GUI //setup the list of topics known by the actor. Topics who are also on the knownTopics list will be added to the GUI
updateTopics(); updateTopics();
@ -144,8 +139,16 @@ namespace MWDialogue
{ {
if(it->mType == ESM::Dialogue::Greeting) if(it->mType == ESM::Dialogue::Greeting)
{ {
if (const ESM::DialInfo *info = filter.search (*it)) // Search a response (we do not accept a fallback to "Info refusal" here)
if (const ESM::DialInfo *info = filter.search (*it, false))
{ {
//initialise the GUI
MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Dialogue);
MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow();
win->startDialogue(actor, MWWorld::Class::get (actor).getName (actor));
creatureStats.talkedToPlayer();
if (!info->mSound.empty()) if (!info->mSound.empty())
{ {
// TODO play sound // TODO play sound
@ -246,12 +249,12 @@ namespace MWDialogue
const ESM::Dialogue& dialogue = *dialogues.find (topic); const ESM::Dialogue& dialogue = *dialogues.find (topic);
if (const ESM::DialInfo *info = filter.search (dialogue)) MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow();
if (const ESM::DialInfo *info = filter.search (dialogue, true))
{ {
parseText (info->mResponse); parseText (info->mResponse);
MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow();
if (dialogue.mType==ESM::Dialogue::Persuasion) if (dialogue.mType==ESM::Dialogue::Persuasion)
{ {
std::string modifiedTopic = "s" + topic; std::string modifiedTopic = "s" + topic;
@ -268,12 +271,20 @@ namespace MWDialogue
MWScript::InterpreterContext interpreterContext(&mActor.getRefData().getLocals(),mActor); MWScript::InterpreterContext interpreterContext(&mActor.getRefData().getLocals(),mActor);
win->addText (Interpreter::fixDefinesDialog(info->mResponse, interpreterContext)); win->addText (Interpreter::fixDefinesDialog(info->mResponse, interpreterContext));
MWBase::Environment::get().getJournal()->addTopic (topic, info->mId);
executeScript (info->mResultScript); executeScript (info->mResultScript);
mLastTopic = topic; mLastTopic = topic;
mLastDialogue = *info; mLastDialogue = *info;
} }
else
{
// no response found, print a fallback text
win->addTitle (topic);
win->addText ("");
}
} }
void DialogueManager::updateTopics() void DialogueManager::updateTopics()
@ -292,7 +303,7 @@ namespace MWDialogue
{ {
if (iter->mType == ESM::Dialogue::Topic) if (iter->mType == ESM::Dialogue::Topic)
{ {
if (filter.search (*iter)) if (filter.responseAvailable (*iter))
{ {
std::string lower = Misc::StringUtils::lowerCase(iter->mId); std::string lower = Misc::StringUtils::lowerCase(iter->mId);
mActorKnownTopics.push_back (lower); mActorKnownTopics.push_back (lower);
@ -381,6 +392,10 @@ namespace MWDialogue
void DialogueManager::goodbyeSelected() void DialogueManager::goodbyeSelected()
{ {
// Do not close the dialogue window if the player has to answer a question
if (mIsInChoice)
return;
MWBase::Environment::get().getWindowManager()->removeGuiMode(MWGui::GM_Dialogue); MWBase::Environment::get().getWindowManager()->removeGuiMode(MWGui::GM_Dialogue);
// Apply disposition change to NPC's base disposition // Apply disposition change to NPC's base disposition
@ -405,7 +420,7 @@ namespace MWDialogue
{ {
Filter filter (mActor, mChoice, mTalkedTo); Filter filter (mActor, mChoice, mTalkedTo);
if (const ESM::DialInfo *info = filter.search (mDialogueMap[mLastTopic])) if (const ESM::DialInfo *info = filter.search (mDialogueMap[mLastTopic], true))
{ {
mChoiceMap.clear(); mChoiceMap.clear();
mChoice = -1; mChoice = -1;
@ -415,6 +430,7 @@ namespace MWDialogue
MWScript::InterpreterContext interpreterContext(&mActor.getRefData().getLocals(),mActor); MWScript::InterpreterContext interpreterContext(&mActor.getRefData().getLocals(),mActor);
MWBase::Environment::get().getWindowManager()->getDialogueWindow()->addText (Interpreter::fixDefinesDialog(text, interpreterContext)); MWBase::Environment::get().getWindowManager()->getDialogueWindow()->addText (Interpreter::fixDefinesDialog(text, interpreterContext));
MWBase::Environment::get().getJournal()->addTopic (mLastTopic, info->mId);
executeScript (info->mResultScript); executeScript (info->mResultScript);
mLastTopic = mLastTopic; mLastTopic = mLastTopic;
mLastDialogue = *info; mLastDialogue = *info;

@ -19,12 +19,19 @@
bool MWDialogue::Filter::testActor (const ESM::DialInfo& info) const bool MWDialogue::Filter::testActor (const ESM::DialInfo& info) const
{ {
bool isCreature = (mActor.getTypeName() != typeid (ESM::NPC).name());
// actor id // actor id
if (!info.mActor.empty()) if (!info.mActor.empty())
{
if ( Misc::StringUtils::lowerCase (info.mActor)!=MWWorld::Class::get (mActor).getId (mActor)) if ( Misc::StringUtils::lowerCase (info.mActor)!=MWWorld::Class::get (mActor).getId (mActor))
return false; return false;
}
bool isCreature = (mActor.getTypeName() != typeid (ESM::NPC).name()); else if (isCreature)
{
// Creatures must not have topics aside of those specific to their id
return false;
}
// NPC race // NPC race
if (!info.mRace.empty()) if (!info.mRace.empty())
@ -114,6 +121,18 @@ bool MWDialogue::Filter::testSelectStructs (const ESM::DialInfo& info) const
return true; return true;
} }
bool MWDialogue::Filter::testDisposition (const ESM::DialInfo& info) const
{
bool isCreature = (mActor.getTypeName() != typeid (ESM::NPC).name());
if (isCreature)
return true;
int actorDisposition = MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(mActor);
return actorDisposition >= info.mData.mDisposition;
}
bool MWDialogue::Filter::testSelectStruct (const SelectWrapper& select) const bool MWDialogue::Filter::testSelectStruct (const SelectWrapper& select) const
{ {
if (select.isNpcOnly() && mActor.getTypeName()!=typeid (ESM::NPC).name()) if (select.isNpcOnly() && mActor.getTypeName()!=typeid (ESM::NPC).name())
@ -155,7 +174,7 @@ bool MWDialogue::Filter::testSelectStructNumeric (const SelectWrapper& select) c
int i = 0; int i = 0;
for (; i<static_cast<int> (script->mVarNames.size()); ++i) for (; i<static_cast<int> (script->mVarNames.size()); ++i)
if (script->mVarNames[i]==name) if (Misc::StringUtils::lowerCase(script->mVarNames[i]) == name)
break; break;
if (i>=static_cast<int> (script->mVarNames.size())) if (i>=static_cast<int> (script->mVarNames.size()))
@ -540,18 +559,50 @@ MWDialogue::Filter::Filter (const MWWorld::Ptr& actor, int choice, bool talkedTo
: mActor (actor), mChoice (choice), mTalkedToPlayer (talkedToPlayer) : mActor (actor), mChoice (choice), mTalkedToPlayer (talkedToPlayer)
{} {}
bool MWDialogue::Filter::operator() (const ESM::DialInfo& info) const const ESM::DialInfo *MWDialogue::Filter::search (const ESM::Dialogue& dialogue, const bool fallbackToInfoRefusal) const
{ {
return testActor (info) && testPlayer (info) && testSelectStructs (info); bool infoRefusal = false;
}
const ESM::DialInfo *MWDialogue::Filter::search (const ESM::Dialogue& dialogue) const // Iterate over topic responses to find a matching one
{
for (std::vector<ESM::DialInfo>::const_iterator iter = dialogue.mInfo.begin(); for (std::vector<ESM::DialInfo>::const_iterator iter = dialogue.mInfo.begin();
iter!=dialogue.mInfo.end(); ++iter) iter!=dialogue.mInfo.end(); ++iter)
if ((*this) (*iter)) {
return &*iter; if (testActor (*iter) && testPlayer (*iter) && testSelectStructs (*iter))
{
if (testDisposition (*iter))
return &*iter;
else
infoRefusal = true;
}
}
if (infoRefusal && fallbackToInfoRefusal)
{
// No response is valid because of low NPC disposition,
// search a response in the topic "Info Refusal"
const MWWorld::Store<ESM::Dialogue> &dialogues =
MWBase::Environment::get().getWorld()->getStore().get<ESM::Dialogue>();
const ESM::Dialogue& infoRefusalDialogue = *dialogues.find ("Info Refusal");
for (std::vector<ESM::DialInfo>::const_iterator iter = infoRefusalDialogue.mInfo.begin();
iter!=infoRefusalDialogue.mInfo.end(); ++iter)
if (testActor (*iter) && testPlayer (*iter) && testSelectStructs (*iter) && testDisposition(*iter))
return &*iter;
}
return 0; return 0;
} }
bool MWDialogue::Filter::responseAvailable (const ESM::Dialogue& dialogue) const
{
for (std::vector<ESM::DialInfo>::const_iterator iter = dialogue.mInfo.begin();
iter!=dialogue.mInfo.end(); ++iter)
{
if (testActor (*iter) && testPlayer (*iter) && testSelectStructs (*iter))
return true;
}
return false;
}

@ -18,40 +18,45 @@ namespace MWDialogue
MWWorld::Ptr mActor; MWWorld::Ptr mActor;
int mChoice; int mChoice;
bool mTalkedToPlayer; bool mTalkedToPlayer;
bool testActor (const ESM::DialInfo& info) const; bool testActor (const ESM::DialInfo& info) const;
///< Is this the right actor for this \a info? ///< Is this the right actor for this \a info?
bool testPlayer (const ESM::DialInfo& info) const; bool testPlayer (const ESM::DialInfo& info) const;
///< Do the player and the cell the player is currently in match \a info? ///< Do the player and the cell the player is currently in match \a info?
bool testSelectStructs (const ESM::DialInfo& info) const; bool testSelectStructs (const ESM::DialInfo& info) const;
///< Are all select structs matching? ///< Are all select structs matching?
bool testDisposition (const ESM::DialInfo& info) const;
///< Is the actor disposition toward the player high enough?
bool testSelectStruct (const SelectWrapper& select) const; bool testSelectStruct (const SelectWrapper& select) const;
bool testSelectStructNumeric (const SelectWrapper& select) const; bool testSelectStructNumeric (const SelectWrapper& select) const;
int getSelectStructInteger (const SelectWrapper& select) const; int getSelectStructInteger (const SelectWrapper& select) const;
bool getSelectStructBoolean (const SelectWrapper& select) const; bool getSelectStructBoolean (const SelectWrapper& select) const;
int getFactionRank (const MWWorld::Ptr& actor, const std::string& factionId) const; int getFactionRank (const MWWorld::Ptr& actor, const std::string& factionId) const;
bool hasFactionRankSkillRequirements (const MWWorld::Ptr& actor, const std::string& factionId, bool hasFactionRankSkillRequirements (const MWWorld::Ptr& actor, const std::string& factionId,
int rank) const; int rank) const;
bool hasFactionRankReputationRequirements (const MWWorld::Ptr& actor, const std::string& factionId, bool hasFactionRankReputationRequirements (const MWWorld::Ptr& actor, const std::string& factionId,
int rank) const; int rank) const;
public: public:
Filter (const MWWorld::Ptr& actor, int choice, bool talkedToPlayer);
bool operator() (const ESM::DialInfo& info) const; Filter (const MWWorld::Ptr& actor, int choice, bool talkedToPlayer);
///< \return does the dialogue match?
const ESM::DialInfo *search (const ESM::Dialogue& dialogue, const bool fallbackToInfoRefusal) const;
const ESM::DialInfo *search (const ESM::Dialogue& dialogue) const; ///< Get a matching response for the requested dialogue.
/// Redirect to "Info Refusal" topic if a response fulfills all conditions but disposition.
bool responseAvailable (const ESM::Dialogue& dialogue) const;
///< Does a matching response exist? (disposition is ignored for this check)
}; };
} }

@ -61,8 +61,8 @@ namespace MWDialogue
StampedJournalEntry StampedJournalEntry::makeFromQuest (const std::string& topic, int index) StampedJournalEntry StampedJournalEntry::makeFromQuest (const std::string& topic, int index)
{ {
int day = MWBase::Environment::get().getWorld()->getGlobalVariable ("dayspassed").mLong; int day = MWBase::Environment::get().getWorld()->getGlobalVariable ("dayspassed").mLong;
int month = MWBase::Environment::get().getWorld()->getGlobalVariable ("day").mLong; int month = MWBase::Environment::get().getWorld()->getGlobalVariable ("month").mLong;
int dayOfMonth = MWBase::Environment::get().getWorld()->getGlobalVariable ("month").mLong; int dayOfMonth = MWBase::Environment::get().getWorld()->getGlobalVariable ("day").mLong;
return StampedJournalEntry (topic, idFromIndex (topic, index), day, month, dayOfMonth); return StampedJournalEntry (topic, idFromIndex (topic, index), day, month, dayOfMonth);
} }

@ -31,6 +31,12 @@ namespace MWDialogue
void Journal::addEntry (const std::string& id, int index) void Journal::addEntry (const std::string& id, int index)
{ {
// bail out of we already have heard this...
std::string infoId = JournalEntry::idFromIndex (id, index);
for (TEntryIter i = mJournal.begin (); i != mJournal.end (); ++i)
if (i->mTopic == id && i->mInfoId == infoId)
return;
StampedJournalEntry entry = StampedJournalEntry::makeFromQuest (id, index); StampedJournalEntry entry = StampedJournalEntry::makeFromQuest (id, index);
mJournal.push_back (entry); mJournal.push_back (entry);

@ -27,17 +27,17 @@ namespace MWDialogue
mEntries.push_back (entry.mInfoId); mEntries.push_back (entry.mInfoId);
} }
Topic::TEntryIter Topic::begin() Topic::TEntryIter Topic::begin() const
{ {
return mEntries.begin(); return mEntries.begin();
} }
Topic::TEntryIter Topic::end() Topic::TEntryIter Topic::end() const
{ {
return mEntries.end(); return mEntries.end();
} }
JournalEntry Topic::getEntry (const std::string& infoId) JournalEntry Topic::getEntry (const std::string& infoId) const
{ {
return JournalEntry (mTopic, infoId); return JournalEntry (mTopic, infoId);
} }

@ -34,13 +34,15 @@ namespace MWDialogue
/// ///
/// \note Redundant entries are ignored. /// \note Redundant entries are ignored.
TEntryIter begin(); std::string const & getName () const { return mTopic; }
TEntryIter begin() const;
///< Iterator pointing to the begin of the journal for this topic. ///< Iterator pointing to the begin of the journal for this topic.
TEntryIter end(); TEntryIter end() const;
///< Iterator pointing past the end of the journal for this topic. ///< Iterator pointing past the end of the journal for this topic.
JournalEntry getEntry (const std::string& infoId); JournalEntry getEntry (const std::string& infoId) const;
}; };
} }

@ -490,7 +490,7 @@ void DialogueWindow::onReferenceUnavailable()
void DialogueWindow::onFrame() void DialogueWindow::onFrame()
{ {
if(mEnabled && mPtr.getTypeName() == typeid(ESM::NPC).name()) if(mMainWidget->getVisible() && mEnabled && mPtr.getTypeName() == typeid(ESM::NPC).name())
{ {
int disp = std::max(0, std::min(100, int disp = std::max(0, std::min(100,
MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(mPtr) MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(mPtr)

@ -6,41 +6,42 @@
#include "renderconst.hpp" #include "renderconst.hpp"
using namespace Ogre; namespace MWRender
using namespace MWRender; {
using namespace NifOgre;
Actors::~Actors(){ Actors::~Actors(){
std::map<MWWorld::Ptr, Animation*>::iterator it = mAllActors.begin(); PtrAnimationMap::iterator it = mAllActors.begin();
for (; it != mAllActors.end(); ++it) { for(;it != mAllActors.end();++it)
{
delete it->second; delete it->second;
it->second = NULL; it->second = NULL;
} }
} }
void Actors::setMwRoot(Ogre::SceneNode* root){ void Actors::setMwRoot(Ogre::SceneNode* root)
mMwRoot = root; { mMwRoot = root; }
}
void Actors::insertNPC(const MWWorld::Ptr& ptr, MWWorld::InventoryStore& inv){
void Actors::insertNPC(const MWWorld::Ptr &ptr, MWWorld::InventoryStore &inv)
{
insertBegin(ptr, true, true); insertBegin(ptr, true, true);
NpcAnimation* anim = new MWRender::NpcAnimation(ptr, ptr.getRefData ().getBaseNode (), inv, RV_Actors); NpcAnimation* anim = new MWRender::NpcAnimation(ptr, ptr.getRefData ().getBaseNode (), inv, RV_Actors);
mAllActors[ptr] = anim; mAllActors[ptr] = anim;
} }
void Actors::insertBegin (const MWWorld::Ptr& ptr, bool enabled, bool static_){
void Actors::insertBegin (const MWWorld::Ptr& ptr, bool enabled, bool static_)
{
Ogre::SceneNode* cellnode; Ogre::SceneNode* cellnode;
if(mCellSceneNodes.find(ptr.getCell()) == mCellSceneNodes.end()) CellSceneNodeMap::const_iterator celliter = mCellSceneNodes.find(ptr.getCell());
if(celliter != mCellSceneNodes.end())
cellnode = celliter->second;
else
{ {
//Create the scenenode and put it in the map //Create the scenenode and put it in the map
cellnode = mMwRoot->createChildSceneNode(); cellnode = mMwRoot->createChildSceneNode();
mCellSceneNodes[ptr.getCell()] = cellnode; mCellSceneNodes[ptr.getCell()] = cellnode;
} }
else
{
cellnode = mCellSceneNodes[ptr.getCell()];
}
Ogre::SceneNode* insert = cellnode->createChildSceneNode(); Ogre::SceneNode* insert = cellnode->createChildSceneNode();
const float *f = ptr.getRefData().getPosition().pos; const float *f = ptr.getRefData().getPosition().pos;
@ -51,13 +52,13 @@ void Actors::insertBegin (const MWWorld::Ptr& ptr, bool enabled, bool static_){
f = ptr.getCellRef().mPos.rot; f = ptr.getCellRef().mPos.rot;
// Rotate around X axis // Rotate around X axis
Quaternion xr(Radian(-f[0]), Vector3::UNIT_X); Ogre::Quaternion xr(Ogre::Radian(-f[0]), Ogre::Vector3::UNIT_X);
// Rotate around Y axis // Rotate around Y axis
Quaternion yr(Radian(-f[1]), Vector3::UNIT_Y); Ogre::Quaternion yr(Ogre::Radian(-f[1]), Ogre::Vector3::UNIT_Y);
// Rotate around Z axis // Rotate around Z axis
Quaternion zr(Radian(-f[2]), Vector3::UNIT_Z); Ogre::Quaternion zr(Ogre::Radian(-f[2]), Ogre::Vector3::UNIT_Z);
// Rotates first around z, then y, then x // Rotates first around z, then y, then x
insert->setOrientation(xr*yr*zr); insert->setOrientation(xr*yr*zr);
@ -71,30 +72,30 @@ void Actors::insertCreature (const MWWorld::Ptr& ptr){
insertBegin(ptr, true, true); insertBegin(ptr, true, true);
CreatureAnimation* anim = new MWRender::CreatureAnimation(ptr); CreatureAnimation* anim = new MWRender::CreatureAnimation(ptr);
//mAllActors.insert(std::pair<MWWorld::Ptr, Animation*>(ptr,anim));
delete mAllActors[ptr]; delete mAllActors[ptr];
mAllActors[ptr] = anim; mAllActors[ptr] = anim;
//mAllActors.push_back(&anim);*/
} }
bool Actors::deleteObject (const MWWorld::Ptr& ptr) bool Actors::deleteObject (const MWWorld::Ptr& ptr)
{ {
delete mAllActors[ptr]; delete mAllActors[ptr];
mAllActors.erase(ptr); mAllActors.erase(ptr);
if (Ogre::SceneNode *base = ptr.getRefData().getBaseNode())
{
if(Ogre::SceneNode *base=ptr.getRefData().getBaseNode())
{
Ogre::SceneNode *parent = base->getParentSceneNode(); Ogre::SceneNode *parent = base->getParentSceneNode();
CellSceneNodeMap::const_iterator iter(mCellSceneNodes.begin());
for (std::map<MWWorld::Ptr::CellStore *, Ogre::SceneNode *>::const_iterator iter ( for(;iter != mCellSceneNodes.end();++iter)
mCellSceneNodes.begin()); iter!=mCellSceneNodes.end(); ++iter) {
if (iter->second==parent) if(iter->second == parent)
{ {
base->removeAndDestroyAllChildren(); base->removeAndDestroyAllChildren();
mRend.getScene()->destroySceneNode (base); mRend.getScene()->destroySceneNode (base);
ptr.getRefData().setBaseNode (0); ptr.getRefData().setBaseNode (0);
return true; return true;
} }
}
return false; return false;
} }
@ -102,57 +103,70 @@ bool Actors::deleteObject (const MWWorld::Ptr& ptr)
return true; return true;
} }
void Actors::removeCell(MWWorld::Ptr::CellStore* store){ void Actors::removeCell(MWWorld::Ptr::CellStore* store)
if(mCellSceneNodes.find(store) != mCellSceneNodes.end()) {
{ for(PtrAnimationMap::iterator iter = mAllActors.begin();iter != mAllActors.end();)
Ogre::SceneNode* base = mCellSceneNodes[store];
base->removeAndDestroyAllChildren();
mCellSceneNodes.erase(store);
mRend.getScene()->destroySceneNode(base);
base = 0;
}
for(std::map<MWWorld::Ptr, Animation*>::iterator iter = mAllActors.begin(); iter != mAllActors.end(); )
{ {
if(iter->first.getCell() == store){ if(iter->first.getCell() == store)
{
delete iter->second; delete iter->second;
mAllActors.erase(iter++); mAllActors.erase(iter++);
} }
else else
++iter; ++iter;
} }
CellSceneNodeMap::iterator celliter = mCellSceneNodes.find(store);
if(celliter != mCellSceneNodes.end())
{
Ogre::SceneNode *base = celliter->second;
base->removeAndDestroyAllChildren();
mRend.getScene()->destroySceneNode(base);
mCellSceneNodes.erase(celliter);
}
} }
void Actors::playAnimationGroup (const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number){ void Actors::playAnimationGroup (const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number)
if(mAllActors.find(ptr) != mAllActors.end()) {
mAllActors[ptr]->playGroup(groupName, mode, number); PtrAnimationMap::const_iterator iter = mAllActors.find(ptr);
if(iter != mAllActors.end())
iter->second->playGroup(groupName, mode, number);
} }
void Actors::skipAnimation (const MWWorld::Ptr& ptr){ void Actors::skipAnimation (const MWWorld::Ptr& ptr)
if(mAllActors.find(ptr) != mAllActors.end()) {
mAllActors[ptr]->skipAnim(); PtrAnimationMap::const_iterator iter = mAllActors.find(ptr);
if(iter != mAllActors.end())
iter->second->skipAnim();
} }
void Actors::update (float duration){ void Actors::update (float duration)
for(std::map<MWWorld::Ptr, Animation*>::iterator iter = mAllActors.begin(); iter != mAllActors.end(); iter++) {
for(PtrAnimationMap::const_iterator iter = mAllActors.begin();iter != mAllActors.end();iter++)
iter->second->runAnimation(duration); iter->second->runAnimation(duration);
} }
void void Actors::updateObjectCell(const MWWorld::Ptr &ptr)
Actors::updateObjectCell(const MWWorld::Ptr &ptr)
{ {
Ogre::SceneNode *node; Ogre::SceneNode *node;
MWWorld::CellStore *newCell = ptr.getCell(); MWWorld::CellStore *newCell = ptr.getCell();
if(mCellSceneNodes.find(newCell) == mCellSceneNodes.end()) { CellSceneNodeMap::const_iterator celliter = mCellSceneNodes.find(newCell);
if(celliter != mCellSceneNodes.end())
node = celliter->second;
else
{
node = mMwRoot->createChildSceneNode(); node = mMwRoot->createChildSceneNode();
mCellSceneNodes[newCell] = node; mCellSceneNodes[newCell] = node;
} else {
node = mCellSceneNodes[newCell];
} }
node->addChild(ptr.getRefData().getBaseNode()); node->addChild(ptr.getRefData().getBaseNode());
if (mAllActors.find(ptr) != mAllActors.end()) {
PtrAnimationMap::iterator iter = mAllActors.find(ptr);
if(iter != mAllActors.end())
{
/// \note Update key (Ptr's are compared only with refdata so mCell /// \note Update key (Ptr's are compared only with refdata so mCell
/// on key is outdated), maybe redundant /// on key is outdated), maybe redundant
Animation *anim = mAllActors[ptr]; Animation *anim = iter->second;
mAllActors.erase(ptr); mAllActors.erase(iter);
mAllActors[ptr] = anim; mAllActors[ptr] = anim;
} }
} }
}

@ -10,18 +10,22 @@ namespace MWWorld
class CellStore; class CellStore;
} }
namespace MWRender{ namespace MWRender
class Actors{ {
class Actors
{
typedef std::map<MWWorld::CellStore*,Ogre::SceneNode*> CellSceneNodeMap;
typedef std::map<MWWorld::Ptr,Animation*> PtrAnimationMap;
OEngine::Render::OgreRenderer &mRend; OEngine::Render::OgreRenderer &mRend;
std::map<MWWorld::CellStore *, Ogre::SceneNode *> mCellSceneNodes;
Ogre::SceneNode* mMwRoot; Ogre::SceneNode* mMwRoot;
std::map<MWWorld::Ptr, Animation*> mAllActors; CellSceneNodeMap mCellSceneNodes;
PtrAnimationMap mAllActors;
public:
public:
Actors(OEngine::Render::OgreRenderer& _rend): mRend(_rend) {} Actors(OEngine::Render::OgreRenderer& _rend): mRend(_rend) {}
~Actors(); ~Actors();
void setMwRoot(Ogre::SceneNode* root); void setMwRoot(Ogre::SceneNode* root);
void insertBegin (const MWWorld::Ptr& ptr, bool enabled, bool static_); void insertBegin (const MWWorld::Ptr& ptr, bool enabled, bool static_);
void insertCreature (const MWWorld::Ptr& ptr); void insertCreature (const MWWorld::Ptr& ptr);

@ -181,10 +181,14 @@ namespace MWScript
runtime.pop(); runtime.pop();
std::vector<int> idleList; std::vector<int> idleList;
for (unsigned int i=0; i<arg0; ++i) { idleList.push_back (0); // why MW, why?
for (int i=2; i<10 && arg0; ++i)
{
Interpreter::Type_Integer idleValue = runtime[0].mFloat; Interpreter::Type_Integer idleValue = runtime[0].mFloat;
idleList.push_back(idleValue); idleList.push_back(idleValue);
runtime.pop(); runtime.pop();
--arg0;
} }
// discard additional arguments (reset), because we have no idea what they mean. // discard additional arguments (reset), because we have no idea what they mean.

@ -13,7 +13,7 @@ namespace Interpreter
namespace MWScript namespace MWScript
{ {
/// \brief Temporaty script functionality limited to the console /// \brief Temporary script functionality limited to the console
namespace User namespace User
{ {
void registerExtensions (Compiler::Extensions& extensions); void registerExtensions (Compiler::Extensions& extensions);

@ -160,7 +160,7 @@ namespace MWSound
return volume; return volume;
} }
bool SoundManager::isPlaying(MWWorld::Ptr ptr, const std::string &id) const bool SoundManager::isPlaying(const MWWorld::Ptr &ptr, const std::string &id) const
{ {
SoundMap::const_iterator snditer = mActiveSounds.begin(); SoundMap::const_iterator snditer = mActiveSounds.begin();
while(snditer != mActiveSounds.end()) while(snditer != mActiveSounds.end())
@ -229,7 +229,7 @@ namespace MWSound
startRandomTitle(); startRandomTitle();
} }
void SoundManager::say(MWWorld::Ptr ptr, const std::string& filename) void SoundManager::say(const MWWorld::Ptr &ptr, const std::string& filename)
{ {
if(!mOutput->isInitialized()) if(!mOutput->isInitialized())
return; return;
@ -269,12 +269,12 @@ namespace MWSound
} }
} }
bool SoundManager::sayDone(MWWorld::Ptr ptr) const bool SoundManager::sayDone(const MWWorld::Ptr &ptr) const
{ {
return !isPlaying(ptr, "_say_sound"); return !isPlaying(ptr, "_say_sound");
} }
void SoundManager::stopSay(MWWorld::Ptr ptr) void SoundManager::stopSay(const MWWorld::Ptr &ptr)
{ {
SoundMap::iterator snditer = mActiveSounds.begin(); SoundMap::iterator snditer = mActiveSounds.begin();
while(snditer != mActiveSounds.end()) while(snditer != mActiveSounds.end())
@ -328,7 +328,7 @@ namespace MWSound
return sound; return sound;
} }
MWBase::SoundPtr SoundManager::playSound3D(MWWorld::Ptr ptr, const std::string& soundId, MWBase::SoundPtr SoundManager::playSound3D(const MWWorld::Ptr &ptr, const std::string& soundId,
float volume, float pitch, PlayMode mode) float volume, float pitch, PlayMode mode)
{ {
MWBase::SoundPtr sound; MWBase::SoundPtr sound;
@ -356,7 +356,7 @@ namespace MWSound
return sound; return sound;
} }
void SoundManager::stopSound3D(MWWorld::Ptr ptr, const std::string& soundId) void SoundManager::stopSound3D(const MWWorld::Ptr &ptr, const std::string& soundId)
{ {
SoundMap::iterator snditer = mActiveSounds.begin(); SoundMap::iterator snditer = mActiveSounds.begin();
while(snditer != mActiveSounds.end()) while(snditer != mActiveSounds.end())
@ -371,7 +371,7 @@ namespace MWSound
} }
} }
void SoundManager::stopSound3D(MWWorld::Ptr ptr) void SoundManager::stopSound3D(const MWWorld::Ptr &ptr)
{ {
SoundMap::iterator snditer = mActiveSounds.begin(); SoundMap::iterator snditer = mActiveSounds.begin();
while(snditer != mActiveSounds.end()) while(snditer != mActiveSounds.end())
@ -418,7 +418,7 @@ namespace MWSound
} }
} }
bool SoundManager::getSoundPlaying(MWWorld::Ptr ptr, const std::string& soundId) const bool SoundManager::getSoundPlaying(const MWWorld::Ptr &ptr, const std::string& soundId) const
{ {
return isPlaying(ptr, soundId); return isPlaying(ptr, soundId);
} }

@ -14,8 +14,6 @@
#include "../mwbase/soundmanager.hpp" #include "../mwbase/soundmanager.hpp"
#include "../mwworld/ptr.hpp"
namespace MWSound namespace MWSound
{ {
class Sound_Output; class Sound_Output;
@ -57,7 +55,7 @@ namespace MWSound
std::string lookup(const std::string &soundId, std::string lookup(const std::string &soundId,
float &volume, float &min, float &max); float &volume, float &min, float &max);
void streamMusicFull(const std::string& filename); void streamMusicFull(const std::string& filename);
bool isPlaying(MWWorld::Ptr ptr, const std::string &id) const; bool isPlaying(const MWWorld::Ptr &ptr, const std::string &id) const;
void updateSounds(float duration); void updateSounds(float duration);
void updateRegionSound(float duration); void updateRegionSound(float duration);
@ -93,7 +91,7 @@ namespace MWSound
///< Start playing music from the selected folder ///< Start playing music from the selected folder
/// \param name of the folder that contains the playlist /// \param name of the folder that contains the playlist
virtual void say(MWWorld::Ptr reference, const std::string& filename); virtual void say(const MWWorld::Ptr &reference, const std::string& filename);
///< Make an actor say some text. ///< Make an actor say some text.
/// \param filename name of a sound file in "Sound/" in the data directory. /// \param filename name of a sound file in "Sound/" in the data directory.
@ -101,10 +99,10 @@ namespace MWSound
///< Say some text, without an actor ref ///< Say some text, without an actor ref
/// \param filename name of a sound file in "Sound/" in the data directory. /// \param filename name of a sound file in "Sound/" in the data directory.
virtual bool sayDone(MWWorld::Ptr reference=MWWorld::Ptr()) const; virtual bool sayDone(const MWWorld::Ptr &reference=MWWorld::Ptr()) const;
///< Is actor not speaking? ///< Is actor not speaking?
virtual void stopSay(MWWorld::Ptr reference=MWWorld::Ptr()); virtual void stopSay(const MWWorld::Ptr &reference=MWWorld::Ptr());
///< Stop an actor speaking ///< Stop an actor speaking
virtual MWBase::SoundPtr playTrack(const DecoderPtr& decoder, PlayType type); virtual MWBase::SoundPtr playTrack(const DecoderPtr& decoder, PlayType type);
@ -113,14 +111,14 @@ namespace MWSound
virtual MWBase::SoundPtr playSound(const std::string& soundId, float volume, float pitch, PlayMode mode=Play_Normal); virtual MWBase::SoundPtr playSound(const std::string& soundId, float volume, float pitch, PlayMode mode=Play_Normal);
///< Play a sound, independently of 3D-position ///< Play a sound, independently of 3D-position
virtual MWBase::SoundPtr playSound3D(MWWorld::Ptr reference, const std::string& soundId, virtual MWBase::SoundPtr playSound3D(const MWWorld::Ptr &reference, const std::string& soundId,
float volume, float pitch, PlayMode mode=Play_Normal); float volume, float pitch, PlayMode mode=Play_Normal);
///< Play a sound from an object ///< Play a sound from an object
virtual void stopSound3D(MWWorld::Ptr reference, const std::string& soundId); virtual void stopSound3D(const MWWorld::Ptr &reference, const std::string& soundId);
///< Stop the given object from playing the given sound, ///< Stop the given object from playing the given sound,
virtual void stopSound3D(MWWorld::Ptr reference); virtual void stopSound3D(const MWWorld::Ptr &reference);
///< Stop the given object from playing all sounds. ///< Stop the given object from playing all sounds.
virtual void stopSound(const MWWorld::CellStore *cell); virtual void stopSound(const MWWorld::CellStore *cell);
@ -129,7 +127,7 @@ namespace MWSound
virtual void stopSound(const std::string& soundId); virtual void stopSound(const std::string& soundId);
///< Stop a non-3d looping sound ///< Stop a non-3d looping sound
virtual bool getSoundPlaying(MWWorld::Ptr reference, const std::string& soundId) const; virtual bool getSoundPlaying(const MWWorld::Ptr &reference, const std::string& soundId) const;
///< Is the given sound currently playing on the given object? ///< Is the given sound currently playing on the given object?
virtual void pauseSounds(int types=Play_TypeMask); virtual void pauseSounds(int types=Play_TypeMask);

@ -15,6 +15,8 @@
#include "manualref.hpp" #include "manualref.hpp"
#include "refdata.hpp" #include "refdata.hpp"
#include "class.hpp" #include "class.hpp"
#include "localscripts.hpp"
#include "player.hpp"
namespace namespace
{ {
@ -71,6 +73,31 @@ bool MWWorld::ContainerStore::stacks(const Ptr& ptr1, const Ptr& ptr2)
} }
MWWorld::ContainerStoreIterator MWWorld::ContainerStore::add (const Ptr& ptr) MWWorld::ContainerStoreIterator MWWorld::ContainerStore::add (const Ptr& ptr)
{
MWWorld::ContainerStoreIterator it = addImp(ptr);
MWWorld::Ptr item = *it;
std::string script = MWWorld::Class::get(item).getScript(item);
if(script != "")
{
CellStore *cell;
Ptr player = MWBase::Environment::get().getWorld ()->getPlayer().getPlayer();
// Items in players inventory have cell set to 0, so their scripts will never be removed
if(&(MWWorld::Class::get (player).getContainerStore (player)) == this)
cell = 0;
else
cell = player.getCell();
item.mCell = cell;
item.mContainerStore = 0;
MWBase::Environment::get().getWorld()->getLocalScripts().add(script, item);
}
return it;
}
MWWorld::ContainerStoreIterator MWWorld::ContainerStore::addImp (const Ptr& ptr)
{ {
int type = getType(ptr); int type = getType(ptr);
@ -162,7 +189,7 @@ void MWWorld::ContainerStore::fill (const ESM::InventoryList& items, const MWWor
} }
ref.getPtr().getRefData().setCount (std::abs(iter->mCount)); /// \todo implement item restocking (indicated by negative count) ref.getPtr().getRefData().setCount (std::abs(iter->mCount)); /// \todo implement item restocking (indicated by negative count)
add (ref.getPtr()); addImp (ref.getPtr());
} }
flagAsModified(); flagAsModified();

@ -52,6 +52,7 @@ namespace MWWorld
int mStateId; int mStateId;
mutable float mCachedWeight; mutable float mCachedWeight;
mutable bool mWeightUpToDate; mutable bool mWeightUpToDate;
ContainerStoreIterator addImp (const Ptr& ptr);
public: public:

@ -3,6 +3,10 @@
#include "esmstore.hpp" #include "esmstore.hpp"
#include "cellstore.hpp" #include "cellstore.hpp"
#include "class.hpp"
#include "containerstore.hpp"
namespace namespace
{ {
template<typename T> template<typename T>
@ -19,6 +23,32 @@ namespace
} }
} }
} }
// Adds scripts for items in containers (containers/npcs/creatures)
template<typename T>
void listCellScriptsCont (MWWorld::LocalScripts& localScripts,
MWWorld::CellRefList<T>& cellRefList, MWWorld::Ptr::CellStore *cell)
{
for (typename MWWorld::CellRefList<T>::List::iterator iter (
cellRefList.mList.begin());
iter!=cellRefList.mList.end(); ++iter)
{
MWWorld::Ptr containerPtr (&*iter, cell);
MWWorld::ContainerStore& container = MWWorld::Class::get(containerPtr).getContainerStore(containerPtr);
for(MWWorld::ContainerStoreIterator it3 = container.begin(); it3 != container.end(); ++it3)
{
std::string script = MWWorld::Class::get(*it3).getScript(*it3);
if(script != "")
{
MWWorld::Ptr item = *it3;
item.mCell = cell;
localScripts.add (script, item);
}
}
}
}
} }
MWWorld::LocalScripts::LocalScripts (const MWWorld::ESMStore& store) : mStore (store) {} MWWorld::LocalScripts::LocalScripts (const MWWorld::ESMStore& store) : mStore (store) {}
@ -78,13 +108,16 @@ void MWWorld::LocalScripts::addCell (Ptr::CellStore *cell)
listCellScripts (*this, cell->mBooks, cell); listCellScripts (*this, cell->mBooks, cell);
listCellScripts (*this, cell->mClothes, cell); listCellScripts (*this, cell->mClothes, cell);
listCellScripts (*this, cell->mContainers, cell); listCellScripts (*this, cell->mContainers, cell);
listCellScriptsCont (*this, cell->mContainers, cell);
listCellScripts (*this, cell->mCreatures, cell); listCellScripts (*this, cell->mCreatures, cell);
listCellScriptsCont (*this, cell->mCreatures, cell);
listCellScripts (*this, cell->mDoors, cell); listCellScripts (*this, cell->mDoors, cell);
listCellScripts (*this, cell->mIngreds, cell); listCellScripts (*this, cell->mIngreds, cell);
listCellScripts (*this, cell->mLights, cell); listCellScripts (*this, cell->mLights, cell);
listCellScripts (*this, cell->mLockpicks, cell); listCellScripts (*this, cell->mLockpicks, cell);
listCellScripts (*this, cell->mMiscItems, cell); listCellScripts (*this, cell->mMiscItems, cell);
listCellScripts (*this, cell->mNpcs, cell); listCellScripts (*this, cell->mNpcs, cell);
listCellScriptsCont (*this, cell->mNpcs, cell);
listCellScripts (*this, cell->mProbes, cell); listCellScripts (*this, cell->mProbes, cell);
listCellScripts (*this, cell->mRepairs, cell); listCellScripts (*this, cell->mRepairs, cell);
listCellScripts (*this, cell->mWeapons, cell); listCellScripts (*this, cell->mWeapons, cell);
@ -101,7 +134,7 @@ void MWWorld::LocalScripts::clearCell (Ptr::CellStore *cell)
while (iter!=mScripts.end()) while (iter!=mScripts.end())
{ {
if (iter->second.getCell()==cell) if (iter->second.mCell==cell)
{ {
if (iter==mIter) if (iter==mIter)
++mIter; ++mIter;
@ -113,6 +146,20 @@ void MWWorld::LocalScripts::clearCell (Ptr::CellStore *cell)
} }
} }
void MWWorld::LocalScripts::remove (RefData *ref)
{
for (std::list<std::pair<std::string, Ptr> >::iterator iter = mScripts.begin();
iter!=mScripts.end(); ++iter)
if (&(iter->second.getRefData()) == ref)
{
if (iter==mIter)
++mIter;
mScripts.erase (iter);
break;
}
}
void MWWorld::LocalScripts::remove (const Ptr& ptr) void MWWorld::LocalScripts::remove (const Ptr& ptr)
{ {
for (std::list<std::pair<std::string, Ptr> >::iterator iter = mScripts.begin(); for (std::list<std::pair<std::string, Ptr> >::iterator iter = mScripts.begin();

@ -10,6 +10,7 @@ namespace MWWorld
{ {
struct ESMStore; struct ESMStore;
class CellStore; class CellStore;
class RefData;
/// \brief List of active local scripts /// \brief List of active local scripts
class LocalScripts class LocalScripts
@ -47,6 +48,8 @@ namespace MWWorld
void clearCell (CellStore *cell); void clearCell (CellStore *cell);
///< Remove all scripts belonging to \a cell. ///< Remove all scripts belonging to \a cell.
void remove (RefData *ref);
void remove (const Ptr& ptr); void remove (const Ptr& ptr);
///< Remove script for given reference (ignored if reference does not have a scirpt listed). ///< Remove script for given reference (ignored if reference does not have a scirpt listed).

@ -74,7 +74,7 @@ namespace MWWorld
bool isInCell() const bool isInCell() const
{ {
return (mCell != 0); return (mContainerStore == 0);
} }
void setContainerStore (ContainerStore *store); void setContainerStore (ContainerStore *store);

@ -6,6 +6,9 @@
#include "customdata.hpp" #include "customdata.hpp"
#include "cellstore.hpp" #include "cellstore.hpp"
#include "../mwbase/environment.hpp"
#include "../mwbase/world.hpp"
namespace MWWorld namespace MWWorld
{ {
void RefData::copy (const RefData& refData) void RefData::copy (const RefData& refData)
@ -107,6 +110,9 @@ namespace MWWorld
void RefData::setCount (int count) void RefData::setCount (int count)
{ {
if(count == 0)
MWBase::Environment::get().getWorld()->removeRefScript(this);
mCount = count; mCount = count;
} }

@ -341,6 +341,11 @@ namespace MWWorld
return name; return name;
} }
void World::removeRefScript (MWWorld::RefData *ref)
{
mLocalScripts.remove (ref);
}
Ptr World::getPtr (const std::string& name, bool activeOnly) Ptr World::getPtr (const std::string& name, bool activeOnly)
{ {
// the player is always in an active cell. // the player is always in an active cell.
@ -396,23 +401,62 @@ namespace MWWorld
return MWWorld::Ptr(); return MWWorld::Ptr();
} }
void World::addContainerScripts(const Ptr& reference, Ptr::CellStore * cell)
{
if( reference.getTypeName()==typeid (ESM::Container).name() ||
reference.getTypeName()==typeid (ESM::NPC).name() ||
reference.getTypeName()==typeid (ESM::Creature).name())
{
MWWorld::ContainerStore& container = MWWorld::Class::get(reference).getContainerStore(reference);
for(MWWorld::ContainerStoreIterator it = container.begin(); it != container.end(); ++it)
{
std::string script = MWWorld::Class::get(*it).getScript(*it);
if(script != "")
{
MWWorld::Ptr item = *it;
item.mCell = cell;
mLocalScripts.add (script, item);
}
}
}
}
void World::enable (const Ptr& reference) void World::enable (const Ptr& reference)
{ {
if (!reference.getRefData().isEnabled()) if (!reference.getRefData().isEnabled())
{ {
reference.getRefData().enable(); reference.getRefData().enable();
if(mWorldScene->getActiveCells().find (reference.getCell()) != mWorldScene->getActiveCells().end() && reference.getRefData().getCount()) if(mWorldScene->getActiveCells().find (reference.getCell()) != mWorldScene->getActiveCells().end() && reference.getRefData().getCount())
mWorldScene->addObjectToScene (reference); mWorldScene->addObjectToScene (reference);
} }
} }
void World::removeContainerScripts(const Ptr& reference)
{
if( reference.getTypeName()==typeid (ESM::Container).name() ||
reference.getTypeName()==typeid (ESM::NPC).name() ||
reference.getTypeName()==typeid (ESM::Creature).name())
{
MWWorld::ContainerStore& container = MWWorld::Class::get(reference).getContainerStore(reference);
for(MWWorld::ContainerStoreIterator it = container.begin(); it != container.end(); ++it)
{
std::string script = MWWorld::Class::get(*it).getScript(*it);
if(script != "")
{
MWWorld::Ptr item = *it;
mLocalScripts.remove (item);
}
}
}
}
void World::disable (const Ptr& reference) void World::disable (const Ptr& reference)
{ {
if (reference.getRefData().isEnabled()) if (reference.getRefData().isEnabled())
{ {
reference.getRefData().disable(); reference.getRefData().disable();
if(mWorldScene->getActiveCells().find (reference.getCell())!=mWorldScene->getActiveCells().end() && reference.getRefData().getCount()) if(mWorldScene->getActiveCells().find (reference.getCell())!=mWorldScene->getActiveCells().end() && reference.getRefData().getCount())
mWorldScene->removeObjectFromScene (reference); mWorldScene->removeObjectFromScene (reference);
} }
@ -635,6 +679,7 @@ namespace MWWorld
{ {
mWorldScene->removeObjectFromScene (ptr); mWorldScene->removeObjectFromScene (ptr);
mLocalScripts.remove (ptr); mLocalScripts.remove (ptr);
removeContainerScripts (ptr);
} }
} }
} }
@ -648,6 +693,8 @@ namespace MWWorld
CellStore *currCell = ptr.getCell(); CellStore *currCell = ptr.getCell();
bool isPlayer = ptr == mPlayer->getPlayer(); bool isPlayer = ptr == mPlayer->getPlayer();
bool haveToMove = mWorldScene->isCellActive(*currCell) || isPlayer; bool haveToMove = mWorldScene->isCellActive(*currCell) || isPlayer;
removeContainerScripts(ptr);
if (*currCell != newCell) if (*currCell != newCell)
{ {
@ -675,6 +722,8 @@ namespace MWWorld
MWWorld::Ptr copy = MWWorld::Ptr copy =
MWWorld::Class::get(ptr).copyToCell(ptr, newCell); MWWorld::Class::get(ptr).copyToCell(ptr, newCell);
addContainerScripts(copy, &newCell);
mRendering->moveObjectToCell(copy, vec, currCell); mRendering->moveObjectToCell(copy, vec, currCell);
if (MWWorld::Class::get(ptr).isActor()) if (MWWorld::Class::get(ptr).isActor())
@ -1283,6 +1332,7 @@ namespace MWWorld
if (!script.empty()) { if (!script.empty()) {
mLocalScripts.add(script, dropped); mLocalScripts.add(script, dropped);
} }
addContainerScripts(dropped, &cell);
} }
} }

@ -105,6 +105,9 @@ namespace MWWorld
float getNpcActivationDistance (); float getNpcActivationDistance ();
float getObjectActivationDistance (); float getObjectActivationDistance ();
void removeContainerScripts(const Ptr& reference);
void addContainerScripts(const Ptr& reference, Ptr::CellStore* cell);
public: public:
World (OEngine::Render::OgreRenderer& renderer, World (OEngine::Render::OgreRenderer& renderer,
@ -172,6 +175,9 @@ namespace MWWorld
virtual std::vector<std::string> getGlobals () const; virtual std::vector<std::string> getGlobals () const;
virtual std::string getCurrentCellName () const; virtual std::string getCurrentCellName () const;
virtual void removeRefScript (MWWorld::RefData *ref);
//< Remove the script attached to ref from mLocalScripts
virtual Ptr getPtr (const std::string& name, bool activeOnly); virtual Ptr getPtr (const std::string& name, bool activeOnly);
///< Return a pointer to a liveCellRef with the given name. ///< Return a pointer to a liveCellRef with the given name.

@ -31,150 +31,30 @@
#include "../files/constrainedfiledatastream.hpp" #include "../files/constrainedfiledatastream.hpp"
namespace
{
using namespace Ogre; using namespace Ogre;
using namespace Bsa;
struct PathPatternMatcher
{
PathPatternMatcher (char const * pattern) : pattern (pattern)
{
}
bool operator () (char const * input)
{
char const * p = pattern;
char const * i = input;
while (*p && *i) static bool fsstrict = false;
{
if (*p == '*')
{
++p;
while (*i && *i != *p && *i != '/' && *i != '\\')
++i;
}
else
if (*p == '?')
{
if (*i == '/' || *i == '\\')
break;
++i, ++p;
}
if (*p == '/' || *p == '\\')
{
if (*i != '/' && *i != '\\')
break;
++i, ++p;
}
else
{
if (*i != *p)
break;
++i, ++p;
}
}
return *p == 0 && *i == 0;
}
private:
char const * pattern;
};
struct FileNameGatherer static char strict_normalize_char(char ch)
{ {
StringVectorPtr ptr; return ch == '\\' ? '/' : ch;
}
FileNameGatherer (StringVectorPtr ptr) : ptr (ptr)
{
}
void operator () (std::string const & filename) const
{
ptr->push_back (filename);
}
};
struct FileInfoGatherer static char nonstrict_normalize_char(char ch)
{ {
Archive const * archive; return ch == '\\' ? '/' : std::tolower(ch);
FileInfoListPtr ptr; }
FileInfoGatherer (Archive const * archive, FileInfoListPtr ptr) :
archive (archive), ptr (ptr)
{
}
void operator () (std::string filename) const
{
FileInfo fi;
std::size_t pt = filename.rfind ('/');
if (pt == std::string::npos)
pt = 0;
fi.archive = const_cast <Archive *> (archive);
fi.path = filename.substr (0, pt);
fi.filename = filename.substr (pt);
fi.compressedSize = fi.uncompressedSize = 0;
ptr->push_back(fi);
}
};
template <typename file_iterator, typename filename_extractor, typename match_handler> template<typename T1, typename T2>
void matchFiles (bool recursive, std::string const & pattern, file_iterator begin, file_iterator end, filename_extractor filenameExtractor, match_handler matchHandler) static std::string normalize_path(T1 begin, T2 end)
{ {
if (recursive && pattern == "*") std::string normalized;
{ normalized.reserve(std::distance(begin, end));
for (file_iterator i = begin; i != end; ++i) char (*normalize_char)(char) = fsstrict ? &strict_normalize_char : &nonstrict_normalize_char;
matchHandler (filenameExtractor (*i)); std::transform(begin, end, std::back_inserter(normalized), normalize_char);
} return normalized;
else
{
PathPatternMatcher matcher (pattern.c_str ());
if (recursive)
{
for (file_iterator i = begin; i != end; ++i)
{
char const * filename = filenameExtractor (*i);
char const * matchable_part = filename;
for (char const * j = matchable_part; *j; ++j)
{
if (*j == '/' || *j == '\\')
matchable_part = j + 1;
}
if (matcher (matchable_part))
matchHandler (filename);
}
}
else
{
for (file_iterator i = begin; i != end; ++i)
{
char const * filename = filenameExtractor (*i);
if (matcher (filename))
matchHandler (filename);
}
}
}
} }
static bool fsstrict = false;
/// An OGRE Archive wrapping a BSAFile archive /// An OGRE Archive wrapping a BSAFile archive
class DirArchive: public Ogre::Archive class DirArchive: public Ogre::Archive
{ {
@ -182,37 +62,12 @@ class DirArchive: public Ogre::Archive
index mIndex; index mIndex;
static char strict_normalize_char(char ch)
{
return ch == '\\' ? '/' : ch;
}
static char nonstrict_normalize_char(char ch)
{
return ch == '\\' ? '/' : std::tolower (ch);
}
static std::string normalize_path (std::string::const_iterator begin, std::string::const_iterator end)
{
std::string normalized;
normalized.reserve (end-begin);
char (*normalize_char) (char) = fsstrict ? &strict_normalize_char : &nonstrict_normalize_char;
std::transform (begin, end, std::back_inserter (normalized), normalize_char);
return normalized;
}
index::const_iterator lookup_filename (std::string const & filename) const index::const_iterator lookup_filename (std::string const & filename) const
{ {
std::string normalized = normalize_path (filename.begin (), filename.end ()); std::string normalized = normalize_path (filename.begin (), filename.end ());
return mIndex.find (normalized); return mIndex.find (normalized);
} }
static char const * extractFilename (index::value_type const & entry)
{
return entry.first.c_str ();
}
public: public:
DirArchive(const String& name) DirArchive(const String& name)
@ -273,15 +128,20 @@ public:
StringVectorPtr find(const String& pattern, bool recursive = true, StringVectorPtr find(const String& pattern, bool recursive = true,
bool dirs = false) bool dirs = false)
{ {
std::string normalizedPattern = normalize_path (pattern.begin (), pattern.end ()); std::string normalizedPattern = normalize_path(pattern.begin(), pattern.end());
StringVectorPtr ptr = StringVectorPtr(new StringVector()); StringVectorPtr ptr = StringVectorPtr(new StringVector());
matchFiles (recursive, normalizedPattern, mIndex.begin (), mIndex.end (), extractFilename, FileNameGatherer (ptr)); for(index::const_iterator iter = mIndex.begin();iter != mIndex.end();iter++)
{
if(Ogre::StringUtil::match(iter->first, normalizedPattern) ||
(recursive && Ogre::StringUtil::match(iter->first, "*/"+normalizedPattern)))
ptr->push_back(iter->first);
}
return ptr; return ptr;
} }
bool exists(const String& filename) bool exists(const String& filename)
{ {
return lookup_filename (filename) != mIndex.end (); return lookup_filename(filename) != mIndex.end ();
} }
time_t getModifiedTime(const String&) { return 0; } time_t getModifiedTime(const String&) { return 0; }
@ -289,21 +149,44 @@ public:
FileInfoListPtr findFileInfo(const String& pattern, bool recursive = true, FileInfoListPtr findFileInfo(const String& pattern, bool recursive = true,
bool dirs = false) const bool dirs = false) const
{ {
std::string normalizedPattern = normalize_path(pattern.begin(), pattern.end());
FileInfoListPtr ptr = FileInfoListPtr(new FileInfoList()); FileInfoListPtr ptr = FileInfoListPtr(new FileInfoList());
FileInfoGatherer gatherer (this, ptr);
std::string normalizedPattern = normalize_path (pattern.begin (), pattern.end ()); index::const_iterator i = mIndex.find(normalizedPattern);
if(i != mIndex.end())
{
std::string::size_type pt = i->first.rfind('/');
if(pt == std::string::npos)
pt = 0;
index::const_iterator i = mIndex.find (normalizedPattern); FileInfo fi;
fi.archive = const_cast<DirArchive*>(this);
fi.path = i->first.substr(0, pt);
fi.filename = i->first.substr((i->first[pt]=='/') ? pt+1 : pt);
fi.compressedSize = fi.uncompressedSize = 0;
if (i != mIndex.end ()) ptr->push_back(fi);
{
gatherer (i->first);
} }
else else
{ {
for(index::const_iterator iter = mIndex.begin();iter != mIndex.end();iter++)
{
if(Ogre::StringUtil::match(iter->first, normalizedPattern) ||
(recursive && Ogre::StringUtil::match(iter->first, "*/"+normalizedPattern)))
{
std::string::size_type pt = iter->first.rfind('/');
if(pt == std::string::npos)
pt = 0;
FileInfo fi;
fi.archive = const_cast<DirArchive*>(this);
fi.path = iter->first.substr(0, pt);
fi.filename = iter->first.substr((iter->first[pt]=='/') ? pt+1 : pt);
fi.compressedSize = fi.uncompressedSize = 0;
matchFiles (recursive, normalizedPattern, mIndex.begin (), mIndex.end (), extractFilename, gatherer); ptr->push_back(fi);
}
}
} }
return ptr; return ptr;
@ -312,9 +195,9 @@ public:
class BSAArchive : public Archive class BSAArchive : public Archive
{ {
BSAFile arc; Bsa::BSAFile arc;
static char const * extractFilename (BSAFile::FileStruct const & entry) static const char *extractFilename(const Bsa::BSAFile::FileStruct &entry)
{ {
return entry.name; return entry.name;
} }
@ -330,13 +213,13 @@ public:
void load() {} void load() {}
void unload() {} void unload() {}
DataStreamPtr open(const String& filename, bool recursive = true) const DataStreamPtr open(const String& filename, bool readonly = true) const
{ {
// Get a non-const reference to arc. This is a hack and it's all // Get a non-const reference to arc. This is a hack and it's all
// OGRE's fault. You should NOT expect an open() command not to // OGRE's fault. You should NOT expect an open() command not to
// have any side effects on the archive, and hence this function // have any side effects on the archive, and hence this function
// should not have been declared const in the first place. // should not have been declared const in the first place.
BSAFile *narc = const_cast<BSAFile*>(&arc); Bsa::BSAFile *narc = const_cast<Bsa::BSAFile*>(&arc);
// Open the file // Open the file
return narc->getFile(filename.c_str()); return narc->getFile(filename.c_str());
@ -360,32 +243,51 @@ public:
return findFileInfo ("*", recursive, dirs); return findFileInfo ("*", recursive, dirs);
} }
// After load() is called, find("*") is called once. It doesn't seem StringVectorPtr find(const String& pattern, bool recursive = true,
// to matter that we return an empty list, exists() gets called on bool dirs = false)
// the correct files anyway. {
StringVectorPtr find(const String& pattern, bool recursive = true, std::string normalizedPattern = normalize_path(pattern.begin(), pattern.end());
bool dirs = false) const Bsa::BSAFile::FileList &filelist = arc.getList();
{
StringVectorPtr ptr = StringVectorPtr(new StringVector()); StringVectorPtr ptr = StringVectorPtr(new StringVector());
matchFiles (recursive, pattern, arc.getList ().begin (), arc.getList ().end (), extractFilename, FileNameGatherer (ptr)); for(Bsa::BSAFile::FileList::const_iterator iter = filelist.begin();iter != filelist.end();iter++)
{
std::string ent = normalize_path(iter->name, iter->name+std::strlen(iter->name));
if(Ogre::StringUtil::match(ent, normalizedPattern) ||
(recursive && Ogre::StringUtil::match(ent, "*/"+normalizedPattern)))
ptr->push_back(iter->name);
}
return ptr; return ptr;
} }
FileInfoListPtr findFileInfo(const String& pattern, bool recursive = true,
bool dirs = false) const
{
std::string normalizedPattern = normalize_path(pattern.begin(), pattern.end());
FileInfoListPtr ptr = FileInfoListPtr(new FileInfoList());
const Bsa::BSAFile::FileList &filelist = arc.getList();
/* Gets called once for each of the ogre formats, *.program, for(Bsa::BSAFile::FileList::const_iterator iter = filelist.begin();iter != filelist.end();iter++)
*.material etc. We ignore all these. {
std::string ent = normalize_path(iter->name, iter->name+std::strlen(iter->name));
if(Ogre::StringUtil::match(ent, normalizedPattern) ||
(recursive && Ogre::StringUtil::match(ent, "*/"+normalizedPattern)))
{
std::string::size_type pt = ent.rfind('/');
if(pt == std::string::npos)
pt = 0;
However, it's also called by MyGUI to find individual textures, FileInfo fi;
and we can't ignore these since many of the GUI textures are fi.archive = const_cast<BSAArchive*>(this);
located in BSAs. So instead we channel it through exists() and fi.path = std::string(iter->name, pt);
set up a single-element result list if the file is found. fi.filename = std::string(iter->name + ((ent[pt]=='/') ? pt+1 : pt));
*/ fi.compressedSize = fi.uncompressedSize = iter->fileSize;
FileInfoListPtr findFileInfo(const String& pattern, bool recursive = true,
bool dirs = false) const ptr->push_back(fi);
{ }
FileInfoListPtr ptr = FileInfoListPtr(new FileInfoList()); }
matchFiles (recursive, pattern, arc.getList ().begin (), arc.getList ().end (), extractFilename, FileInfoGatherer (this, ptr));
return ptr; return ptr;
} }
}; };
// An archive factory for BSA archives // An archive factory for BSA archives
@ -450,7 +352,6 @@ static void insertDirFactory()
} }
} }
}
namespace Bsa namespace Bsa
{ {

@ -118,5 +118,5 @@ for the open-source EB Garamond fontface.
Thanks to Dongle, Thanks to Dongle,
for his Daedric fontface, see Daedric Font License.txt for his license terms. for his Daedric fontface, see Daedric Font License.txt for his license terms.
Thanks to Bitstream Inc. Thanks to DejaVu team,
for their Bitstream Vera fontface, see Bitstream Vera License.txt for their license terms. for their DejaVuLGCSansMono fontface, see DejaVu Font License.txt for their license terms.

@ -80,7 +80,7 @@ set(MYGUI_FILES
openmw_travel_window.layout openmw_travel_window.layout
openmw_persuasion_dialog.layout openmw_persuasion_dialog.layout
smallbars.png smallbars.png
VeraMono.ttf DejaVuLGCSansMono.ttf
markers.png markers.png
) )

Binary file not shown.

Binary file not shown.

@ -11,6 +11,7 @@
<Code range="33 126"/> <Code range="33 126"/>
<Code range="192 382"/> <!-- Central and Eastern European languages glyphs --> <Code range="192 382"/> <!-- Central and Eastern European languages glyphs -->
<Code range="1025 1105"/> <Code range="1025 1105"/>
<Code range="2026"/> <!-- Ellipsis -->
<Code range="8470"/> <Code range="8470"/>
<Code range="8211"/> <!-- Minus --> <Code range="8211"/> <!-- Minus -->
<Code range="8216 8217"/> <!-- Single quotes --> <Code range="8216 8217"/> <!-- Single quotes -->
@ -35,7 +36,7 @@
</Resource> </Resource>
<Resource type="ResourceTrueTypeFont" name="MonoFont"> <Resource type="ResourceTrueTypeFont" name="MonoFont">
<Property key="Source" value="VeraMono.ttf"/> <Property key="Source" value="DejaVuLGCSansMono.ttf"/>
<Property key="Size" value="18"/> <Property key="Size" value="18"/>
<Property key="Resolution" value="50"/> <Property key="Resolution" value="50"/>
<Property key="Antialias" value="false"/> <Property key="Antialias" value="false"/>

Loading…
Cancel
Save