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
*.kdev4
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.
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
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"
CSMWorld::ColumnBase::ColumnBase (const std::string& title, int flags)
: mTitle (title), mFlags (flags)
CSMWorld::ColumnBase::ColumnBase (const std::string& title, Display displayType, int flags)
: mTitle (title), mDisplayType (displayType), mFlags (flags)
{}
CSMWorld::ColumnBase::~ColumnBase() {}

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

@ -8,7 +8,7 @@ namespace CSMWorld
template<typename 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
{
@ -31,7 +31,7 @@ namespace CSMWorld
template<typename 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
{
@ -47,7 +47,7 @@ namespace CSMWorld
template<typename ESXRecordT>
struct RecordStateColumn : public Column<ESXRecordT>
{
RecordStateColumn() : Column<ESXRecordT> ("*") {}
RecordStateColumn() : Column<ESXRecordT> ("*", ColumnBase::Display_Integer) {}
virtual QVariant get (const Record<ESXRecordT>& record) const
{
@ -78,7 +78,8 @@ namespace CSMWorld
{
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
{

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

@ -4,8 +4,13 @@
#include <QGridLayout>
#include <QLabel>
#include <QAbstractTableModel>
#include <QDoubleSpinBox>
#include <QSpinBox>
#include <QLineEdit>
#include <QDataWidgetMapper>
#include "../../model/world/columnbase.hpp"
#include "../../model/world/idtable.hpp"
CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document,
bool createAndDelete)
@ -23,6 +28,9 @@ CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, CSM
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();
@ -30,8 +38,54 @@ CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, CSM
if (flags & CSMWorld::ColumnBase::Flag_Dialogue)
{
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)

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

@ -21,5 +21,6 @@ void CSVWorld::TableSubView::setEditLock (bool locked)
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
/// \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.
/// \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
/// \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?
virtual void stopSay(MWWorld::Ptr reference=MWWorld::Ptr()) = 0;
virtual void stopSay(const MWWorld::Ptr &reference=MWWorld::Ptr()) = 0;
///< Stop an actor speaking
virtual SoundPtr playTrack(const MWSound::DecoderPtr& decoder, PlayType type) = 0;
@ -105,14 +105,14 @@ namespace MWBase
PlayMode mode=Play_Normal) = 0;
///< 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;
///< 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,
virtual void stopSound3D(MWWorld::Ptr reference) = 0;
virtual void stopSound3D(const MWWorld::Ptr &reference) = 0;
///< Stop the given object from playing all sounds.
virtual void stopSound(const MWWorld::CellStore *cell) = 0;
@ -121,7 +121,7 @@ namespace MWBase
virtual void stopSound(const std::string& soundId) = 0;
///< 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?
virtual void pauseSounds(int types=Play_TypeMask) = 0;

@ -45,6 +45,7 @@ namespace MWWorld
class Ptr;
class TimeStamp;
class ESMStore;
class RefData;
}
namespace MWBase
@ -138,6 +139,9 @@ namespace MWBase
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;
///< Return a pointer to a liveCellRef with the given name.
/// \param activeOnly do non search inactive cells.

@ -100,14 +100,15 @@ namespace MWClass
}
else
{
/// \todo do something with mNpdt12 maybe:p
for (int i=0; i<8; ++i)
data->mCreatureStats.getAttribute (i).set (10);
for (int i=0; i<3; ++i)
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);

@ -20,6 +20,7 @@
#include "../mwbase/environment.hpp"
#include "../mwbase/world.hpp"
#include "../mwbase/journal.hpp"
#include "../mwbase/scriptmanager.hpp"
#include "../mwbase/windowmanager.hpp"
#include "../mwbase/mechanicsmanager.hpp"
@ -122,15 +123,9 @@ namespace MWDialogue
MWMechanics::CreatureStats& creatureStats = MWWorld::Class::get (actor).getCreatureStats (actor);
mTalkedTo = creatureStats.hasTalkedToPlayer();
creatureStats.talkedToPlayer();
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
updateTopics();
@ -144,8 +139,16 @@ namespace MWDialogue
{
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())
{
// TODO play sound
@ -246,12 +249,12 @@ namespace MWDialogue
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);
MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow();
if (dialogue.mType==ESM::Dialogue::Persuasion)
{
std::string modifiedTopic = "s" + topic;
@ -268,12 +271,20 @@ namespace MWDialogue
MWScript::InterpreterContext interpreterContext(&mActor.getRefData().getLocals(),mActor);
win->addText (Interpreter::fixDefinesDialog(info->mResponse, interpreterContext));
MWBase::Environment::get().getJournal()->addTopic (topic, info->mId);
executeScript (info->mResultScript);
mLastTopic = topic;
mLastDialogue = *info;
}
else
{
// no response found, print a fallback text
win->addTitle (topic);
win->addText ("");
}
}
void DialogueManager::updateTopics()
@ -292,7 +303,7 @@ namespace MWDialogue
{
if (iter->mType == ESM::Dialogue::Topic)
{
if (filter.search (*iter))
if (filter.responseAvailable (*iter))
{
std::string lower = Misc::StringUtils::lowerCase(iter->mId);
mActorKnownTopics.push_back (lower);
@ -381,6 +392,10 @@ namespace MWDialogue
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);
// Apply disposition change to NPC's base disposition
@ -405,7 +420,7 @@ namespace MWDialogue
{
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();
mChoice = -1;
@ -415,6 +430,7 @@ namespace MWDialogue
MWScript::InterpreterContext interpreterContext(&mActor.getRefData().getLocals(),mActor);
MWBase::Environment::get().getWindowManager()->getDialogueWindow()->addText (Interpreter::fixDefinesDialog(text, interpreterContext));
MWBase::Environment::get().getJournal()->addTopic (mLastTopic, info->mId);
executeScript (info->mResultScript);
mLastTopic = mLastTopic;
mLastDialogue = *info;

@ -19,12 +19,19 @@
bool MWDialogue::Filter::testActor (const ESM::DialInfo& info) const
{
bool isCreature = (mActor.getTypeName() != typeid (ESM::NPC).name());
// actor id
if (!info.mActor.empty())
{
if ( Misc::StringUtils::lowerCase (info.mActor)!=MWWorld::Class::get (mActor).getId (mActor))
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
if (!info.mRace.empty())
@ -114,6 +121,18 @@ bool MWDialogue::Filter::testSelectStructs (const ESM::DialInfo& info) const
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
{
if (select.isNpcOnly() && mActor.getTypeName()!=typeid (ESM::NPC).name())
@ -155,7 +174,7 @@ bool MWDialogue::Filter::testSelectStructNumeric (const SelectWrapper& select) c
int i = 0;
for (; i<static_cast<int> (script->mVarNames.size()); ++i)
if (script->mVarNames[i]==name)
if (Misc::StringUtils::lowerCase(script->mVarNames[i]) == name)
break;
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)
{}
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();
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;
}
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;
int mChoice;
bool mTalkedToPlayer;
bool testActor (const ESM::DialInfo& info) const;
///< Is this the right actor for this \a info?
bool testPlayer (const ESM::DialInfo& info) const;
///< Do the player and the cell the player is currently in match \a info?
bool testSelectStructs (const ESM::DialInfo& info) const;
///< 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 testSelectStructNumeric (const SelectWrapper& select) const;
int getSelectStructInteger (const SelectWrapper& select) const;
bool getSelectStructBoolean (const SelectWrapper& select) const;
int getFactionRank (const MWWorld::Ptr& actor, const std::string& factionId) const;
bool hasFactionRankSkillRequirements (const MWWorld::Ptr& actor, const std::string& factionId,
int rank) const;
bool hasFactionRankReputationRequirements (const MWWorld::Ptr& actor, const std::string& factionId,
int rank) const;
public:
Filter (const MWWorld::Ptr& actor, int choice, bool talkedToPlayer);
bool operator() (const ESM::DialInfo& info) const;
///< \return does the dialogue match?
const ESM::DialInfo *search (const ESM::Dialogue& dialogue) const;
Filter (const MWWorld::Ptr& actor, int choice, bool talkedToPlayer);
const ESM::DialInfo *search (const ESM::Dialogue& dialogue, const bool fallbackToInfoRefusal) 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)
{
int day = MWBase::Environment::get().getWorld()->getGlobalVariable ("dayspassed").mLong;
int month = MWBase::Environment::get().getWorld()->getGlobalVariable ("day").mLong;
int dayOfMonth = MWBase::Environment::get().getWorld()->getGlobalVariable ("month").mLong;
int month = 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);
}

@ -31,6 +31,12 @@ namespace MWDialogue
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);
mJournal.push_back (entry);

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

@ -34,13 +34,15 @@ namespace MWDialogue
///
/// \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.
TEntryIter end();
TEntryIter end() const;
///< 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()
{
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,
MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(mPtr)

@ -6,41 +6,42 @@
#include "renderconst.hpp"
using namespace Ogre;
using namespace MWRender;
using namespace NifOgre;
namespace MWRender
{
Actors::~Actors(){
std::map<MWWorld::Ptr, Animation*>::iterator it = mAllActors.begin();
for (; it != mAllActors.end(); ++it) {
PtrAnimationMap::iterator it = mAllActors.begin();
for(;it != mAllActors.end();++it)
{
delete it->second;
it->second = NULL;
}
}
void Actors::setMwRoot(Ogre::SceneNode* root){
mMwRoot = root;
}
void Actors::insertNPC(const MWWorld::Ptr& ptr, MWWorld::InventoryStore& inv){
void Actors::setMwRoot(Ogre::SceneNode* root)
{ mMwRoot = root; }
void Actors::insertNPC(const MWWorld::Ptr &ptr, MWWorld::InventoryStore &inv)
{
insertBegin(ptr, true, true);
NpcAnimation* anim = new MWRender::NpcAnimation(ptr, ptr.getRefData ().getBaseNode (), inv, RV_Actors);
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;
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
cellnode = mMwRoot->createChildSceneNode();
mCellSceneNodes[ptr.getCell()] = cellnode;
}
else
{
cellnode = mCellSceneNodes[ptr.getCell()];
}
Ogre::SceneNode* insert = cellnode->createChildSceneNode();
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;
// 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
Quaternion yr(Radian(-f[1]), Vector3::UNIT_Y);
Ogre::Quaternion yr(Ogre::Radian(-f[1]), Ogre::Vector3::UNIT_Y);
// 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
insert->setOrientation(xr*yr*zr);
@ -71,30 +72,30 @@ void Actors::insertCreature (const MWWorld::Ptr& ptr){
insertBegin(ptr, true, true);
CreatureAnimation* anim = new MWRender::CreatureAnimation(ptr);
//mAllActors.insert(std::pair<MWWorld::Ptr, Animation*>(ptr,anim));
delete mAllActors[ptr];
mAllActors[ptr] = anim;
//mAllActors.push_back(&anim);*/
}
bool Actors::deleteObject (const MWWorld::Ptr& ptr)
{
delete mAllActors[ptr];
mAllActors.erase(ptr);
if (Ogre::SceneNode *base = ptr.getRefData().getBaseNode())
{
delete mAllActors[ptr];
mAllActors.erase(ptr);
if(Ogre::SceneNode *base=ptr.getRefData().getBaseNode())
{
Ogre::SceneNode *parent = base->getParentSceneNode();
for (std::map<MWWorld::Ptr::CellStore *, Ogre::SceneNode *>::const_iterator iter (
mCellSceneNodes.begin()); iter!=mCellSceneNodes.end(); ++iter)
if (iter->second==parent)
CellSceneNodeMap::const_iterator iter(mCellSceneNodes.begin());
for(;iter != mCellSceneNodes.end();++iter)
{
if(iter->second == parent)
{
base->removeAndDestroyAllChildren();
mRend.getScene()->destroySceneNode (base);
ptr.getRefData().setBaseNode (0);
return true;
}
}
return false;
}
@ -102,57 +103,70 @@ bool Actors::deleteObject (const MWWorld::Ptr& ptr)
return true;
}
void Actors::removeCell(MWWorld::Ptr::CellStore* store){
if(mCellSceneNodes.find(store) != mCellSceneNodes.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(); )
void Actors::removeCell(MWWorld::Ptr::CellStore* store)
{
for(PtrAnimationMap::iterator iter = mAllActors.begin();iter != mAllActors.end();)
{
if(iter->first.getCell() == store){
if(iter->first.getCell() == store)
{
delete iter->second;
mAllActors.erase(iter++);
}
else
++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){
if(mAllActors.find(ptr) != mAllActors.end())
mAllActors[ptr]->playGroup(groupName, mode, number);
void Actors::playAnimationGroup (const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int 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){
if(mAllActors.find(ptr) != mAllActors.end())
mAllActors[ptr]->skipAnim();
void Actors::skipAnimation (const MWWorld::Ptr& ptr)
{
PtrAnimationMap::const_iterator iter = mAllActors.find(ptr);
if(iter != mAllActors.end())
iter->second->skipAnim();
}
void Actors::update (float duration){
for(std::map<MWWorld::Ptr, Animation*>::iterator iter = mAllActors.begin(); iter != mAllActors.end(); iter++)
void Actors::update (float duration)
{
for(PtrAnimationMap::const_iterator iter = mAllActors.begin();iter != mAllActors.end();iter++)
iter->second->runAnimation(duration);
}
void
Actors::updateObjectCell(const MWWorld::Ptr &ptr)
void Actors::updateObjectCell(const MWWorld::Ptr &ptr)
{
Ogre::SceneNode *node;
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();
mCellSceneNodes[newCell] = node;
} else {
node = mCellSceneNodes[newCell];
}
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
/// on key is outdated), maybe redundant
Animation *anim = mAllActors[ptr];
mAllActors.erase(ptr);
Animation *anim = iter->second;
mAllActors.erase(iter);
mAllActors[ptr] = anim;
}
}
}

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

@ -181,10 +181,14 @@ namespace MWScript
runtime.pop();
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;
idleList.push_back(idleValue);
runtime.pop();
--arg0;
}
// discard additional arguments (reset), because we have no idea what they mean.

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

@ -160,7 +160,7 @@ namespace MWSound
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();
while(snditer != mActiveSounds.end())
@ -229,7 +229,7 @@ namespace MWSound
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())
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");
}
void SoundManager::stopSay(MWWorld::Ptr ptr)
void SoundManager::stopSay(const MWWorld::Ptr &ptr)
{
SoundMap::iterator snditer = mActiveSounds.begin();
while(snditer != mActiveSounds.end())
@ -328,7 +328,7 @@ namespace MWSound
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)
{
MWBase::SoundPtr sound;
@ -356,7 +356,7 @@ namespace MWSound
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();
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();
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);
}

@ -14,8 +14,6 @@
#include "../mwbase/soundmanager.hpp"
#include "../mwworld/ptr.hpp"
namespace MWSound
{
class Sound_Output;
@ -57,7 +55,7 @@ namespace MWSound
std::string lookup(const std::string &soundId,
float &volume, float &min, float &max);
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 updateRegionSound(float duration);
@ -93,7 +91,7 @@ namespace MWSound
///< Start playing music from the selected folder
/// \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.
/// \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
/// \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?
virtual void stopSay(MWWorld::Ptr reference=MWWorld::Ptr());
virtual void stopSay(const MWWorld::Ptr &reference=MWWorld::Ptr());
///< Stop an actor speaking
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);
///< 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);
///< 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,
virtual void stopSound3D(MWWorld::Ptr reference);
virtual void stopSound3D(const MWWorld::Ptr &reference);
///< Stop the given object from playing all sounds.
virtual void stopSound(const MWWorld::CellStore *cell);
@ -129,7 +127,7 @@ namespace MWSound
virtual void stopSound(const std::string& soundId);
///< 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?
virtual void pauseSounds(int types=Play_TypeMask);

@ -15,6 +15,8 @@
#include "manualref.hpp"
#include "refdata.hpp"
#include "class.hpp"
#include "localscripts.hpp"
#include "player.hpp"
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 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);
@ -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)
add (ref.getPtr());
addImp (ref.getPtr());
}
flagAsModified();

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

@ -3,6 +3,10 @@
#include "esmstore.hpp"
#include "cellstore.hpp"
#include "class.hpp"
#include "containerstore.hpp"
namespace
{
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) {}
@ -78,13 +108,16 @@ void MWWorld::LocalScripts::addCell (Ptr::CellStore *cell)
listCellScripts (*this, cell->mBooks, cell);
listCellScripts (*this, cell->mClothes, cell);
listCellScripts (*this, cell->mContainers, cell);
listCellScriptsCont (*this, cell->mContainers, cell);
listCellScripts (*this, cell->mCreatures, cell);
listCellScriptsCont (*this, cell->mCreatures, cell);
listCellScripts (*this, cell->mDoors, cell);
listCellScripts (*this, cell->mIngreds, cell);
listCellScripts (*this, cell->mLights, cell);
listCellScripts (*this, cell->mLockpicks, cell);
listCellScripts (*this, cell->mMiscItems, cell);
listCellScripts (*this, cell->mNpcs, cell);
listCellScriptsCont (*this, cell->mNpcs, cell);
listCellScripts (*this, cell->mProbes, cell);
listCellScripts (*this, cell->mRepairs, cell);
listCellScripts (*this, cell->mWeapons, cell);
@ -101,7 +134,7 @@ void MWWorld::LocalScripts::clearCell (Ptr::CellStore *cell)
while (iter!=mScripts.end())
{
if (iter->second.getCell()==cell)
if (iter->second.mCell==cell)
{
if (iter==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)
{
for (std::list<std::pair<std::string, Ptr> >::iterator iter = mScripts.begin();

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

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

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

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

@ -105,6 +105,9 @@ namespace MWWorld
float getNpcActivationDistance ();
float getObjectActivationDistance ();
void removeContainerScripts(const Ptr& reference);
void addContainerScripts(const Ptr& reference, Ptr::CellStore* cell);
public:
World (OEngine::Render::OgreRenderer& renderer,
@ -172,6 +175,9 @@ namespace MWWorld
virtual std::vector<std::string> getGlobals () 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);
///< Return a pointer to a liveCellRef with the given name.

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

@ -118,5 +118,5 @@ for the open-source EB Garamond fontface.
Thanks to Dongle,
for his Daedric fontface, see Daedric Font License.txt for his license terms.
Thanks to Bitstream Inc.
for their Bitstream Vera fontface, see Bitstream Vera License.txt for their license terms.
Thanks to DejaVu team,
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_persuasion_dialog.layout
smallbars.png
VeraMono.ttf
DejaVuLGCSansMono.ttf
markers.png
)

Binary file not shown.

Binary file not shown.

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

Loading…
Cancel
Save