mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-02-22 08:39:41 +00:00
Merge branch 'master' of https://github.com/OpenMW/openmw
This commit is contained in:
commit
4d2bdda22f
90 changed files with 2910 additions and 7407 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -37,6 +37,7 @@ resources
|
||||||
/omwlauncher
|
/omwlauncher
|
||||||
/openmw
|
/openmw
|
||||||
/opencs
|
/opencs
|
||||||
|
/niftest
|
||||||
|
|
||||||
## generated objects
|
## generated objects
|
||||||
apps/openmw/config.hpp
|
apps/openmw/config.hpp
|
||||||
|
|
139
.mailmap
Normal file
139
.mailmap
Normal file
|
@ -0,0 +1,139 @@
|
||||||
|
Adam Hogan <comrade@comrade-desktop.(none)>
|
||||||
|
Aleksandar Jovanov <ajovanov93@yahoo.com>
|
||||||
|
Alexander Olofsson <ace@haxalot.com>
|
||||||
|
Alex McKibben <mckibbenta@gmail.com>
|
||||||
|
Alex "rainChu" Haddad <alx1213@gmail.com>
|
||||||
|
Ardekantur <greystone@ardekantur.com>
|
||||||
|
Armin Preiml <b.nutzer@gmail.com>
|
||||||
|
Artem Kotsynyak <greye@carceri>
|
||||||
|
Arthur Moore <arthur@Behemoth>
|
||||||
|
Arthur Moore <Arthur.Moore.git@cd-net.net>
|
||||||
|
athile <athile@athile.net>
|
||||||
|
athile <athile.g@gmail.com>
|
||||||
|
Stefan Galowicz <bogglez@the.mind>
|
||||||
|
Bret Curtis <psi29a@gmail.com>
|
||||||
|
Britt Mathis <britt.mathis@gmail.com>
|
||||||
|
Sandy Carter <bwrsandman@gmail.com>
|
||||||
|
Sandy Carter <mr.sandy.carter@gmail.com>
|
||||||
|
Carl Maxwell <carl.maxwell@gmail.com>
|
||||||
|
cc9cii <cc9c@iinet.net.au>
|
||||||
|
Cory F. Cohen <cfcohen@verizon.net>
|
||||||
|
Chris Robinson <chris.kcat@gmail.com>
|
||||||
|
Cris Mihalache <mirceam94@hotmail.com>
|
||||||
|
darkf <lw9k123@gmail.com>
|
||||||
|
Diggory Hardy <diggory.hardy@gmail.com>
|
||||||
|
Thomas Luppi <ThomasLuppi@gmail.com>
|
||||||
|
Thomas Luppi <tluppi@thomas-GE60.(none)>
|
||||||
|
Dmitriy 'Endorph' Shkurskiy <end0rph@hotmail.com>
|
||||||
|
Dmitry Marakasov <amdmi3@amdmi3.ru>
|
||||||
|
Douglas Diniz <dgdiniz@gmail.com>
|
||||||
|
Douglas Mencken <dougmencken@gmail.com>
|
||||||
|
Edmondo Tommasina <edmondo.tommasina@gmail.com>
|
||||||
|
Eduard Cot <eduard@eduard-iMac.(none)>
|
||||||
|
Eli2 <fabian@fabian-desktop.(none)>
|
||||||
|
Emanuel Guével <guevel.emanuel@gmail.com>
|
||||||
|
Leon Saunders <LeonDavidSaunders@gmail.com>
|
||||||
|
Fil Krynicki <filipkrynicki@gmail.com>
|
||||||
|
John Blomberg <johnblo@kth.se>
|
||||||
|
Gašper Sedej <gsedej@gmail.com>
|
||||||
|
Michał Bień <michal1.bien@gmail.com>
|
||||||
|
Joel Graff <monograff76@gmail.com>
|
||||||
|
Paul McElroy <pcm1123@gmail.com>
|
||||||
|
Artem Kotsynyak <greye@carceri>
|
||||||
|
Artem Kotsynyak <greye@null.net>
|
||||||
|
gugus <gus_512@hotmail.com>
|
||||||
|
guidoj <guido@thuisbasis.net>
|
||||||
|
gus <gus_512@hotmail.com>
|
||||||
|
Hallfaer Tuilinn <gijsbertth@gmail.com>
|
||||||
|
Julian Ospald <julian.ospald@googlemail.com>
|
||||||
|
Jacob Essex <jacob@jacobessex.com>
|
||||||
|
Jan Borsodi <jborsodi@gmail.com>
|
||||||
|
Jan-Peter Nilsson <peppe@pappkartong.se>
|
||||||
|
Jason Hooks <Hooks@.(none)>
|
||||||
|
Jason Hooks <jason@Jason-ThinkPad-R61.(none)>
|
||||||
|
Jason Hooks <jhooks1@mix.wvu.edu>
|
||||||
|
Jeffrey Haines <jeffhaines@me.com>
|
||||||
|
Jeffrey Haines <jib-y@users.noreply.github.com>
|
||||||
|
Jordan Ayers <jordan.ayers@gmail.com>
|
||||||
|
Jordan Milne <jordan.milne@saynotolinux.com>
|
||||||
|
Josua Grawitter <josh@greyage.org>
|
||||||
|
Julien Voisin <pouicpouicpouic@gmail.com>
|
||||||
|
Karl-Felix Glatzer <karl.glatzer@gmx.de>
|
||||||
|
Chris Robinson <chris.kcat@gmail.com>
|
||||||
|
Kevin Poitra <pupkev@yahoo.com>
|
||||||
|
Roman Proskuryakov <humbug@deeptown.org>
|
||||||
|
Lars Söderberg <lazze_1983@hotmail.com>
|
||||||
|
lazydev <lazydev@homecomp>
|
||||||
|
lazydev <lazydev@nomail>
|
||||||
|
Lukasz Gromanowski <lgromanowski@gmail.com>
|
||||||
|
Marc Bouvier <marcrbouvier@gmail.com>
|
||||||
|
Marcin Hulist <Gohan1989@gmail.com>
|
||||||
|
Marc Zinnschlag <marc@zpages.de>
|
||||||
|
Marek Kochanowicz <herr@mikrus.pl>
|
||||||
|
Marek Kochanowicz <marek@localhost.localdomain>
|
||||||
|
Marek Kochanowicz <sirherrbatka@gmail.com>
|
||||||
|
Mark Siewert <mark.siewert@t-online.de>
|
||||||
|
Mark Siewert <ms@cerebra.localdomain>
|
||||||
|
megaton <9megaton6@gmail.com>
|
||||||
|
Michael Mc Donnell <michael@mcdonnell.dk>
|
||||||
|
Michael Papageorgiou <werdanith@yahoo.gr>
|
||||||
|
Michal Sciubidlo <michal.sciubidlo@gmail.com>
|
||||||
|
Michał Ściubidło <michal.sciubidlo@gmail.com>
|
||||||
|
Nathan Jeffords <blunted2night@gmail.com>
|
||||||
|
Nicolay Korslund <korslund@gmail.com>
|
||||||
|
Nicolay Korslund <nicolayk@met.no>
|
||||||
|
Nikolay Kasyanov <corrmage@gmail.com>
|
||||||
|
pchan3 <chantlerpeter@gmail.com>
|
||||||
|
Pieter van der Kloet <pvdkloet@gmail.com>
|
||||||
|
Mateusz Kołaczek <mateusz.kolaczek@gmail.com>
|
||||||
|
Bret Curtis <psi29a@gmail.com>
|
||||||
|
Pieter van der Kloet <pvdkloet@gmail.com>
|
||||||
|
Rohit Nirmal <rohitnirmal9@gmail.com>
|
||||||
|
Roman Melnik <kromgart@gmail.com>
|
||||||
|
Radu-Marius Popovici <rpopovici@github.com>
|
||||||
|
Sandy Carter <bwrsandman@gmail.com>
|
||||||
|
Scott Howard <showard314@gmail.com>
|
||||||
|
Jannik Heller <scrawl@baseoftrash.de>
|
||||||
|
Jannik Heller <scrawl@scrawl-laptop.(none)>
|
||||||
|
Sebastian Wick <sebastian@sebastianwick.net>
|
||||||
|
Sebastian Wick <wick.sebastian@gmail.com>
|
||||||
|
Sergey Shambir <sergey.shambir.auto@gmail.com>
|
||||||
|
sergoz <parapvr@yandex.ru>
|
||||||
|
Chris Boyce <slothlife@users.noreply.github.com>
|
||||||
|
Star-Demon <starsickle@yahoo.com>
|
||||||
|
Sylvain Thesnieres <garvek@gmail.com>
|
||||||
|
Thomas Luppi <digrules@gmail.com>
|
||||||
|
Thomas Luppi <tluppi@thomas-GE60.(none)>
|
||||||
|
Thoronador <thoronador@users.sourceforge.net>
|
||||||
|
TomKoenderink <tom_koenderink-github@omniadicta.net>
|
||||||
|
Tom Mason <wheybags@wheybags.com>
|
||||||
|
Torben Carrington <torbenlcarrington@Gmail.com>
|
||||||
|
Vincent Heuken <vincent@vincentheuken.com>
|
||||||
|
Manuel Edelmann <edelmann.manuel@gmail.com>
|
||||||
|
Manuel Edelmann <vorenon@hotmail.com>
|
||||||
|
Alexander Nadeau <wareya@gmail.com>
|
||||||
|
Michael Hogan <mr.michaelhogan@gmail.com>
|
||||||
|
Jacob Essex <github@JacobEssex.com>
|
||||||
|
Yuri Krupenin <yuri.krupenin@gmail.com>
|
||||||
|
Bret Curtis <noone@your.box>
|
||||||
|
|
||||||
|
sirherrbatka <herr@localhost.localdomain>
|
||||||
|
sirherrbatka <sirherrbatka@myopera.com>
|
||||||
|
sergei <sergei@ubuntu.(none)>
|
||||||
|
riothamus <digimars@gmail.com>
|
||||||
|
nobrakal <nobrakal@gmail.com>
|
||||||
|
nkorslund <nkorslund@ea6a568a-9f4f-0410-981a-c910a81bb256>
|
||||||
|
mrcheko <cheko@sevas.ua>
|
||||||
|
Miroslav Puda <pakanek@gmail.com>
|
||||||
|
MiroslavR <miroslavr256@gmail.com>
|
||||||
|
mckibbenta <mckibbenta@gmail.com>
|
||||||
|
jeaye <jeaye@arrownext.com>
|
||||||
|
eroen <eroen@falcon.eroen.eu>
|
||||||
|
eroen <eroen@occam.eroen.eu>
|
||||||
|
dreamer-dead <dreamer.dead@gmail.com>
|
||||||
|
crysthala <crystalsoulslayer@gmail.com>
|
||||||
|
Berulacks <beru@eml.cc>
|
||||||
|
Axujen <axujen@gmail.com>
|
||||||
|
root <root@debian>
|
||||||
|
unknown <Hooks@.(none)>
|
||||||
|
|
|
@ -77,6 +77,7 @@ option(BUILD_MWINIIMPORTER "build MWiniImporter" ON)
|
||||||
option(BUILD_OPENCS "build OpenMW Construction Set" ON)
|
option(BUILD_OPENCS "build OpenMW Construction Set" ON)
|
||||||
option(BUILD_WITH_CODE_COVERAGE "Enable code coverage with gconv" OFF)
|
option(BUILD_WITH_CODE_COVERAGE "Enable code coverage with gconv" OFF)
|
||||||
option(BUILD_UNITTESTS "Enable Unittests with Google C++ Unittest ang GMock frameworks" OFF)
|
option(BUILD_UNITTESTS "Enable Unittests with Google C++ Unittest ang GMock frameworks" OFF)
|
||||||
|
option(BUILD_NIFTEST "build nif file tester" OFF)
|
||||||
|
|
||||||
# OS X deployment
|
# OS X deployment
|
||||||
option(OPENMW_OSX_DEPLOYMENT OFF)
|
option(OPENMW_OSX_DEPLOYMENT OFF)
|
||||||
|
@ -396,6 +397,9 @@ IF(NOT WIN32 AND NOT APPLE)
|
||||||
IF(BUILD_OPENCS)
|
IF(BUILD_OPENCS)
|
||||||
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/opencs" DESTINATION "${BINDIR}" )
|
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/opencs" DESTINATION "${BINDIR}" )
|
||||||
ENDIF(BUILD_OPENCS)
|
ENDIF(BUILD_OPENCS)
|
||||||
|
IF(BUILD_NIFTEST)
|
||||||
|
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/niftest" DESTINATION "${BINDIR}" )
|
||||||
|
ENDIF(BUILD_NIFTEST)
|
||||||
|
|
||||||
# Install licenses
|
# Install licenses
|
||||||
INSTALL(FILES "docs/license/DejaVu Font License.txt" DESTINATION "${LICDIR}" )
|
INSTALL(FILES "docs/license/DejaVu Font License.txt" DESTINATION "${LICDIR}" )
|
||||||
|
@ -512,6 +516,11 @@ add_subdirectory (extern/sdl4ogre)
|
||||||
# Components
|
# Components
|
||||||
add_subdirectory (components)
|
add_subdirectory (components)
|
||||||
|
|
||||||
|
#Testing
|
||||||
|
if (BUILD_NIFTEST)
|
||||||
|
add_subdirectory(components/nif/tests/)
|
||||||
|
endif(BUILD_NIFTEST)
|
||||||
|
|
||||||
# Apps and tools
|
# Apps and tools
|
||||||
add_subdirectory( apps/openmw )
|
add_subdirectory( apps/openmw )
|
||||||
|
|
||||||
|
|
|
@ -950,9 +950,9 @@ void Record<ESM::MagicEffect>::print()
|
||||||
std::cout << " School: " << schoolLabel(mData.mData.mSchool)
|
std::cout << " School: " << schoolLabel(mData.mData.mSchool)
|
||||||
<< " (" << mData.mData.mSchool << ")" << std::endl;
|
<< " (" << mData.mData.mSchool << ")" << std::endl;
|
||||||
std::cout << " Base Cost: " << mData.mData.mBaseCost << std::endl;
|
std::cout << " Base Cost: " << mData.mData.mBaseCost << std::endl;
|
||||||
|
std::cout << " Unknown 1: " << mData.mData.mUnknown1 << std::endl;
|
||||||
std::cout << " Speed: " << mData.mData.mSpeed << std::endl;
|
std::cout << " Speed: " << mData.mData.mSpeed << std::endl;
|
||||||
std::cout << " Size: " << mData.mData.mSize << std::endl;
|
std::cout << " Unknown 2: " << mData.mData.mUnknown2 << std::endl;
|
||||||
std::cout << " Size Cap: " << mData.mData.mSizeCap << std::endl;
|
|
||||||
std::cout << " RGB Color: " << "("
|
std::cout << " RGB Color: " << "("
|
||||||
<< mData.mData.mRed << ","
|
<< mData.mData.mRed << ","
|
||||||
<< mData.mData.mGreen << ","
|
<< mData.mData.mGreen << ","
|
||||||
|
|
|
@ -16,6 +16,8 @@
|
||||||
|
|
||||||
#include <components/files/multidircollection.hpp>
|
#include <components/files/multidircollection.hpp>
|
||||||
|
|
||||||
|
#include <components/nifcache/nifcache.hpp>
|
||||||
|
|
||||||
#include "model/settings/usersettings.hpp"
|
#include "model/settings/usersettings.hpp"
|
||||||
#include "model/doc/documentmanager.hpp"
|
#include "model/doc/documentmanager.hpp"
|
||||||
|
|
||||||
|
@ -37,6 +39,7 @@ namespace CS
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
|
Nif::Cache mNifCache;
|
||||||
Files::ConfigurationManager mCfgMgr;
|
Files::ConfigurationManager mCfgMgr;
|
||||||
CSMSettings::UserSettings mUserSettings;
|
CSMSettings::UserSettings mUserSettings;
|
||||||
CSMDoc::DocumentManager mDocumentManager;
|
CSMDoc::DocumentManager mDocumentManager;
|
||||||
|
|
|
@ -37,6 +37,10 @@ static const char pipe_err[] = "!!! Failed to create pipe\n";
|
||||||
static const char fork_err[] = "!!! Failed to fork debug process\n";
|
static const char fork_err[] = "!!! Failed to fork debug process\n";
|
||||||
static const char exec_err[] = "!!! Failed to exec debug process\n";
|
static const char exec_err[] = "!!! Failed to exec debug process\n";
|
||||||
|
|
||||||
|
#ifndef PATH_MAX /* Not all platforms (GNU Hurd) have this. */
|
||||||
|
# define PATH_MAX 256
|
||||||
|
#endif
|
||||||
|
|
||||||
static char argv0[PATH_MAX];
|
static char argv0[PATH_MAX];
|
||||||
|
|
||||||
static char altstack[SIGSTKSZ];
|
static char altstack[SIGSTKSZ];
|
||||||
|
@ -66,7 +70,7 @@ static const struct {
|
||||||
int code;
|
int code;
|
||||||
const char *name;
|
const char *name;
|
||||||
} sigill_codes[] = {
|
} sigill_codes[] = {
|
||||||
#ifndef __FreeBSD__
|
#if !defined(__FreeBSD__) && !defined(__FreeBSD_kernel__)
|
||||||
{ ILL_ILLOPC, "Illegal opcode" },
|
{ ILL_ILLOPC, "Illegal opcode" },
|
||||||
{ ILL_ILLOPN, "Illegal operand" },
|
{ ILL_ILLOPN, "Illegal operand" },
|
||||||
{ ILL_ILLADR, "Illegal addressing mode" },
|
{ ILL_ILLADR, "Illegal addressing mode" },
|
||||||
|
|
|
@ -15,7 +15,6 @@
|
||||||
#include <components/bsa/resources.hpp>
|
#include <components/bsa/resources.hpp>
|
||||||
#include <components/files/configurationmanager.hpp>
|
#include <components/files/configurationmanager.hpp>
|
||||||
#include <components/translation/translation.hpp>
|
#include <components/translation/translation.hpp>
|
||||||
#include <components/nif/niffile.hpp>
|
|
||||||
#include <components/nifoverrides/nifoverrides.hpp>
|
#include <components/nifoverrides/nifoverrides.hpp>
|
||||||
|
|
||||||
#include <components/nifbullet/bulletnifloader.hpp>
|
#include <components/nifbullet/bulletnifloader.hpp>
|
||||||
|
@ -315,8 +314,6 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
|
||||||
mEnvironment.setStateManager (
|
mEnvironment.setStateManager (
|
||||||
new MWState::StateManager (mCfgMgr.getUserDataPath() / "saves", mContentFiles.at (0)));
|
new MWState::StateManager (mCfgMgr.getUserDataPath() / "saves", mContentFiles.at (0)));
|
||||||
|
|
||||||
Nif::NIFFile::CacheLock cachelock;
|
|
||||||
|
|
||||||
std::string renderSystem = settings.getString("render system", "Video");
|
std::string renderSystem = settings.getString("render system", "Video");
|
||||||
if (renderSystem == "")
|
if (renderSystem == "")
|
||||||
{
|
{
|
||||||
|
|
|
@ -7,6 +7,8 @@
|
||||||
#include <components/files/collections.hpp>
|
#include <components/files/collections.hpp>
|
||||||
#include <components/translation/translation.hpp>
|
#include <components/translation/translation.hpp>
|
||||||
#include <components/settings/settings.hpp>
|
#include <components/settings/settings.hpp>
|
||||||
|
#include <components/nifcache/nifcache.hpp>
|
||||||
|
|
||||||
|
|
||||||
#include "mwbase/environment.hpp"
|
#include "mwbase/environment.hpp"
|
||||||
|
|
||||||
|
@ -94,6 +96,8 @@ namespace OMW
|
||||||
std::vector<std::string> mScriptBlacklist;
|
std::vector<std::string> mScriptBlacklist;
|
||||||
bool mScriptBlacklistUse;
|
bool mScriptBlacklistUse;
|
||||||
|
|
||||||
|
Nif::Cache mNifCache;
|
||||||
|
|
||||||
// not implemented
|
// not implemented
|
||||||
Engine (const Engine&);
|
Engine (const Engine&);
|
||||||
Engine& operator= (const Engine&);
|
Engine& operator= (const Engine&);
|
||||||
|
|
|
@ -863,9 +863,9 @@ namespace MWClass
|
||||||
return boost::shared_ptr<MWWorld::Action>(new MWWorld::ActionOpen(ptr, true));
|
return boost::shared_ptr<MWWorld::Action>(new MWWorld::ActionOpen(ptr, true));
|
||||||
if(ptr.getClass().getCreatureStats(ptr).getAiSequence().isInCombat())
|
if(ptr.getClass().getCreatureStats(ptr).getAiSequence().isInCombat())
|
||||||
return boost::shared_ptr<MWWorld::Action>(new MWWorld::FailedAction("#{sActorInCombat}"));
|
return boost::shared_ptr<MWWorld::Action>(new MWWorld::FailedAction("#{sActorInCombat}"));
|
||||||
if(getCreatureStats(actor).getStance(MWMechanics::CreatureStats::Stance_Sneak))
|
if(getCreatureStats(actor).getStance(MWMechanics::CreatureStats::Stance_Sneak)
|
||||||
|
|| ptr.getClass().getCreatureStats(ptr).getKnockedDown())
|
||||||
return boost::shared_ptr<MWWorld::Action>(new MWWorld::ActionOpen(ptr)); // stealing
|
return boost::shared_ptr<MWWorld::Action>(new MWWorld::ActionOpen(ptr)); // stealing
|
||||||
|
|
||||||
// Can't talk to werewolfs
|
// Can't talk to werewolfs
|
||||||
if(ptr.getClass().isNpc() && ptr.getClass().getNpcStats(ptr).isWerewolf())
|
if(ptr.getClass().isNpc() && ptr.getClass().getNpcStats(ptr).isWerewolf())
|
||||||
return boost::shared_ptr<MWWorld::Action> (new MWWorld::FailedAction(""));
|
return boost::shared_ptr<MWWorld::Action> (new MWWorld::FailedAction(""));
|
||||||
|
|
|
@ -244,7 +244,8 @@ namespace MWGui
|
||||||
{
|
{
|
||||||
// we are stealing stuff
|
// we are stealing stuff
|
||||||
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
|
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
|
||||||
mModel = new PickpocketItemModel(player, new InventoryItemModel(container));
|
mModel = new PickpocketItemModel(player, new InventoryItemModel(container),
|
||||||
|
!mPtr.getClass().getCreatureStats(mPtr).getKnockedDown());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
mModel = new InventoryItemModel(container);
|
mModel = new InventoryItemModel(container);
|
||||||
|
@ -368,7 +369,9 @@ namespace MWGui
|
||||||
bool ContainerWindow::onTakeItem(const ItemStack &item, int count)
|
bool ContainerWindow::onTakeItem(const ItemStack &item, int count)
|
||||||
{
|
{
|
||||||
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
|
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
|
||||||
if (dynamic_cast<PickpocketItemModel*>(mModel))
|
// TODO: move to ItemModels
|
||||||
|
if (dynamic_cast<PickpocketItemModel*>(mModel)
|
||||||
|
&& !mPtr.getClass().getCreatureStats(mPtr).getKnockedDown())
|
||||||
{
|
{
|
||||||
MWMechanics::Pickpocket pickpocket(player, mPtr);
|
MWMechanics::Pickpocket pickpocket(player, mPtr);
|
||||||
if (pickpocket.pick(item.mBase, count))
|
if (pickpocket.pick(item.mBase, count))
|
||||||
|
|
|
@ -24,7 +24,7 @@ namespace MWGui
|
||||||
|
|
||||||
EnchantingDialog::EnchantingDialog()
|
EnchantingDialog::EnchantingDialog()
|
||||||
: WindowBase("openmw_enchanting_dialog.layout")
|
: WindowBase("openmw_enchanting_dialog.layout")
|
||||||
, EffectEditorBase()
|
, EffectEditorBase(EffectEditorBase::Enchanting)
|
||||||
, mItemSelectionDialog(NULL)
|
, mItemSelectionDialog(NULL)
|
||||||
{
|
{
|
||||||
getWidget(mName, "NameEdit");
|
getWidget(mName, "NameEdit");
|
||||||
|
@ -87,6 +87,7 @@ namespace MWGui
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
mName->setCaption(item.getClass().getName(item));
|
||||||
mItemBox->setItem(item);
|
mItemBox->setItem(item);
|
||||||
mItemBox->setUserString ("ToolTipType", "ItemPtr");
|
mItemBox->setUserString ("ToolTipType", "ItemPtr");
|
||||||
mItemBox->setUserData(item);
|
mItemBox->setUserData(item);
|
||||||
|
@ -208,6 +209,7 @@ namespace MWGui
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
setItem(MWWorld::Ptr());
|
setItem(MWWorld::Ptr());
|
||||||
|
updateLabels();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -216,6 +218,7 @@ namespace MWGui
|
||||||
mItemSelectionDialog->setVisible(false);
|
mItemSelectionDialog->setVisible(false);
|
||||||
|
|
||||||
setItem(item);
|
setItem(item);
|
||||||
|
MWBase::Environment::get().getSoundManager()->playSound(item.getClass().getDownSoundId(item), 1, 1);
|
||||||
mEnchanting.nextCastStyle();
|
mEnchanting.nextCastStyle();
|
||||||
updateLabels();
|
updateLabels();
|
||||||
}
|
}
|
||||||
|
@ -237,6 +240,7 @@ namespace MWGui
|
||||||
}
|
}
|
||||||
|
|
||||||
setSoulGem(item);
|
setSoulGem(item);
|
||||||
|
MWBase::Environment::get().getSoundManager()->playSound(item.getClass().getDownSoundId(item), 1, 1);
|
||||||
updateLabels();
|
updateLabels();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -471,6 +471,7 @@ namespace MWGui
|
||||||
mWeaponSpellBox->setVisible(true);
|
mWeaponSpellBox->setVisible(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mWeapBox->clearUserStrings();
|
||||||
mWeapBox->setUserString("ToolTipType", "ItemPtr");
|
mWeapBox->setUserString("ToolTipType", "ItemPtr");
|
||||||
mWeapBox->setUserData(item);
|
mWeapBox->setUserData(item);
|
||||||
|
|
||||||
|
@ -515,12 +516,14 @@ namespace MWGui
|
||||||
MWWorld::Ptr player = world->getPlayerPtr();
|
MWWorld::Ptr player = world->getPlayerPtr();
|
||||||
|
|
||||||
mWeapImage->setItem(MWWorld::Ptr());
|
mWeapImage->setItem(MWWorld::Ptr());
|
||||||
if (player.getClass().getNpcStats(player).isWerewolf())
|
std::string icon = (player.getClass().getNpcStats(player).isWerewolf()) ? "icons\\k\\tx_werewolf_hand.dds" : "icons\\k\\stealth_handtohand.dds";
|
||||||
mWeapImage->setIcon("icons\\k\\tx_werewolf_hand.dds");
|
mWeapImage->setIcon(icon);
|
||||||
else
|
|
||||||
mWeapImage->setIcon("icons\\k\\stealth_handtohand.dds");
|
|
||||||
|
|
||||||
mWeapBox->clearUserStrings();
|
mWeapBox->clearUserStrings();
|
||||||
|
mWeapBox->setUserString("ToolTipType", "Layout");
|
||||||
|
mWeapBox->setUserString("ToolTipLayout", "HandToHandToolTip");
|
||||||
|
mWeapBox->setUserString("Caption_HandToHandText", itemName);
|
||||||
|
mWeapBox->setUserString("ImageTexture_HandToHandImage", icon);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HUD::setCrosshairVisible(bool visible)
|
void HUD::setCrosshairVisible(bool visible)
|
||||||
|
|
|
@ -493,6 +493,7 @@ namespace MWGui
|
||||||
|
|
||||||
float capacity = player.getClass().getCapacity(player);
|
float capacity = player.getClass().getCapacity(player);
|
||||||
float encumbrance = player.getClass().getEncumbrance(player);
|
float encumbrance = player.getClass().getEncumbrance(player);
|
||||||
|
mTradeModel->adjustEncumbrance(encumbrance);
|
||||||
mEncumbranceBar->setValue(encumbrance, capacity);
|
mEncumbranceBar->setValue(encumbrance, capacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,18 +6,21 @@
|
||||||
namespace MWGui
|
namespace MWGui
|
||||||
{
|
{
|
||||||
|
|
||||||
PickpocketItemModel::PickpocketItemModel(const MWWorld::Ptr& thief, ItemModel *sourceModel)
|
PickpocketItemModel::PickpocketItemModel(const MWWorld::Ptr& thief, ItemModel *sourceModel, bool hideItems)
|
||||||
{
|
{
|
||||||
mSourceModel = sourceModel;
|
mSourceModel = sourceModel;
|
||||||
int chance = thief.getClass().getSkill(thief, ESM::Skill::Sneak);
|
int chance = thief.getClass().getSkill(thief, ESM::Skill::Sneak);
|
||||||
|
|
||||||
mSourceModel->update();
|
mSourceModel->update();
|
||||||
|
if (hideItems)
|
||||||
|
{
|
||||||
for (size_t i = 0; i<mSourceModel->getItemCount(); ++i)
|
for (size_t i = 0; i<mSourceModel->getItemCount(); ++i)
|
||||||
{
|
{
|
||||||
if (std::rand() / static_cast<float>(RAND_MAX) * 100 > chance)
|
if (std::rand() / static_cast<float>(RAND_MAX) * 100 > chance)
|
||||||
mHiddenItems.push_back(mSourceModel->getItem(i));
|
mHiddenItems.push_back(mSourceModel->getItem(i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ItemStack PickpocketItemModel::getItem (ModelIndex index)
|
ItemStack PickpocketItemModel::getItem (ModelIndex index)
|
||||||
{
|
{
|
||||||
|
|
|
@ -10,7 +10,7 @@ namespace MWGui
|
||||||
class PickpocketItemModel : public ProxyItemModel
|
class PickpocketItemModel : public ProxyItemModel
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
PickpocketItemModel (const MWWorld::Ptr& thief, ItemModel* sourceModel);
|
PickpocketItemModel (const MWWorld::Ptr& thief, ItemModel* sourceModel, bool hideItems=true);
|
||||||
virtual ItemStack getItem (ModelIndex index);
|
virtual ItemStack getItem (ModelIndex index);
|
||||||
virtual size_t getItemCount();
|
virtual size_t getItemCount();
|
||||||
virtual void update();
|
virtual void update();
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
|
|
||||||
#include "../mwworld/inventorystore.hpp"
|
#include "../mwworld/inventorystore.hpp"
|
||||||
#include "../mwworld/class.hpp"
|
#include "../mwworld/class.hpp"
|
||||||
|
#include "../mwworld/player.hpp"
|
||||||
|
|
||||||
#include "../mwbase/environment.hpp"
|
#include "../mwbase/environment.hpp"
|
||||||
#include "../mwbase/world.hpp"
|
#include "../mwbase/world.hpp"
|
||||||
|
@ -293,12 +294,18 @@ namespace MWGui
|
||||||
return;
|
return;
|
||||||
store.setSelectedEnchantItem(store.end());
|
store.setSelectedEnchantItem(store.end());
|
||||||
MWBase::Environment::get().getWindowManager()->setSelectedSpell(spellId, int(MWMechanics::getSpellSuccessChance(spellId, player)));
|
MWBase::Environment::get().getWindowManager()->setSelectedSpell(spellId, int(MWMechanics::getSpellSuccessChance(spellId, player)));
|
||||||
|
MWBase::Environment::get().getWorld()->getPlayer().setDrawState(MWMechanics::DrawState_Spell);
|
||||||
}
|
}
|
||||||
else if (type == Type_Item)
|
else if (type == Type_Item)
|
||||||
{
|
{
|
||||||
MWWorld::Ptr item = *button->getUserData<MWWorld::Ptr>();
|
MWWorld::Ptr item = *button->getUserData<MWWorld::Ptr>();
|
||||||
|
|
||||||
MWBase::Environment::get().getWindowManager()->getInventoryWindow()->useItem(item);
|
MWBase::Environment::get().getWindowManager()->getInventoryWindow()->useItem(item);
|
||||||
|
MWWorld::ContainerStoreIterator rightHand = store.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
|
||||||
|
// change draw state only if the item is in player's right hand
|
||||||
|
if (rightHand != store.end() && item == *rightHand)
|
||||||
|
{
|
||||||
|
MWBase::Environment::get().getWorld()->getPlayer().setDrawState(MWMechanics::DrawState_Weapon);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (type == Type_MagicItem)
|
else if (type == Type_MagicItem)
|
||||||
{
|
{
|
||||||
|
@ -322,6 +329,7 @@ namespace MWGui
|
||||||
}
|
}
|
||||||
|
|
||||||
store.setSelectedEnchantItem(it);
|
store.setSelectedEnchantItem(it);
|
||||||
|
MWBase::Environment::get().getWorld()->getPlayer().setDrawState(MWMechanics::DrawState_Spell);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -37,10 +37,11 @@ namespace MWGui
|
||||||
mOkButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SaveGameDialog::onOkButtonClicked);
|
mOkButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SaveGameDialog::onOkButtonClicked);
|
||||||
mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SaveGameDialog::onCancelButtonClicked);
|
mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SaveGameDialog::onCancelButtonClicked);
|
||||||
mDeleteButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SaveGameDialog::onDeleteButtonClicked);
|
mDeleteButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SaveGameDialog::onDeleteButtonClicked);
|
||||||
mCharacterSelection->eventComboChangePosition += MyGUI::newDelegate(this, &SaveGameDialog::onCharacterSelected);
|
mCharacterSelection->eventComboAccept += MyGUI::newDelegate(this, &SaveGameDialog::onCharacterSelected);
|
||||||
mSaveList->eventListChangePosition += MyGUI::newDelegate(this, &SaveGameDialog::onSlotSelected);
|
mSaveList->eventListChangePosition += MyGUI::newDelegate(this, &SaveGameDialog::onSlotSelected);
|
||||||
mSaveList->eventListMouseItemActivate += MyGUI::newDelegate(this, &SaveGameDialog::onSlotMouseClick);
|
mSaveList->eventListMouseItemActivate += MyGUI::newDelegate(this, &SaveGameDialog::onSlotMouseClick);
|
||||||
mSaveList->eventListSelectAccept += MyGUI::newDelegate(this, &SaveGameDialog::onSlotActivated);
|
mSaveList->eventListSelectAccept += MyGUI::newDelegate(this, &SaveGameDialog::onSlotActivated);
|
||||||
|
mSaveList->eventKeyButtonPressed += MyGUI::newDelegate(this, &SaveGameDialog::onKeyButtonPressed);
|
||||||
mSaveNameEdit->eventEditSelectAccept += MyGUI::newDelegate(this, &SaveGameDialog::onEditSelectAccept);
|
mSaveNameEdit->eventEditSelectAccept += MyGUI::newDelegate(this, &SaveGameDialog::onEditSelectAccept);
|
||||||
mSaveNameEdit->eventEditTextChange += MyGUI::newDelegate(this, &SaveGameDialog::onSaveNameChanged);
|
mSaveNameEdit->eventEditTextChange += MyGUI::newDelegate(this, &SaveGameDialog::onSaveNameChanged);
|
||||||
}
|
}
|
||||||
|
@ -247,6 +248,12 @@ namespace MWGui
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SaveGameDialog::onKeyButtonPressed(MyGUI::Widget* _sender, MyGUI::KeyCode key, MyGUI::Char character)
|
||||||
|
{
|
||||||
|
if (key == MyGUI::KeyCode::Delete && mCurrentSlot)
|
||||||
|
confirmDeleteSave();
|
||||||
|
}
|
||||||
|
|
||||||
void SaveGameDialog::onOkButtonClicked(MyGUI::Widget *sender)
|
void SaveGameDialog::onOkButtonClicked(MyGUI::Widget *sender)
|
||||||
{
|
{
|
||||||
accept();
|
accept();
|
||||||
|
|
|
@ -26,6 +26,7 @@ namespace MWGui
|
||||||
private:
|
private:
|
||||||
void confirmDeleteSave();
|
void confirmDeleteSave();
|
||||||
|
|
||||||
|
void onKeyButtonPressed(MyGUI::Widget* _sender, MyGUI::KeyCode key, MyGUI::Char character);
|
||||||
void onCancelButtonClicked (MyGUI::Widget* sender);
|
void onCancelButtonClicked (MyGUI::Widget* sender);
|
||||||
void onOkButtonClicked (MyGUI::Widget* sender);
|
void onOkButtonClicked (MyGUI::Widget* sender);
|
||||||
void onDeleteButtonClicked (MyGUI::Widget* sender);
|
void onDeleteButtonClicked (MyGUI::Widget* sender);
|
||||||
|
|
|
@ -287,7 +287,7 @@ namespace MWGui
|
||||||
|
|
||||||
SpellCreationDialog::SpellCreationDialog()
|
SpellCreationDialog::SpellCreationDialog()
|
||||||
: WindowBase("openmw_spellcreation_dialog.layout")
|
: WindowBase("openmw_spellcreation_dialog.layout")
|
||||||
, EffectEditorBase()
|
, EffectEditorBase(EffectEditorBase::Spellmaking)
|
||||||
{
|
{
|
||||||
getWidget(mNameEdit, "NameEdit");
|
getWidget(mNameEdit, "NameEdit");
|
||||||
getWidget(mMagickaCost, "MagickaCost");
|
getWidget(mMagickaCost, "MagickaCost");
|
||||||
|
@ -444,10 +444,11 @@ namespace MWGui
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
EffectEditorBase::EffectEditorBase()
|
EffectEditorBase::EffectEditorBase(Type type)
|
||||||
: mAddEffectDialog()
|
: mAddEffectDialog()
|
||||||
, mSelectAttributeDialog(NULL)
|
, mSelectAttributeDialog(NULL)
|
||||||
, mSelectSkillDialog(NULL)
|
, mSelectSkillDialog(NULL)
|
||||||
|
, mType(type)
|
||||||
{
|
{
|
||||||
mAddEffectDialog.eventEffectAdded += MyGUI::newDelegate(this, &EffectEditorBase::onEffectAdded);
|
mAddEffectDialog.eventEffectAdded += MyGUI::newDelegate(this, &EffectEditorBase::onEffectAdded);
|
||||||
mAddEffectDialog.eventEffectModified += MyGUI::newDelegate(this, &EffectEditorBase::onEffectModified);
|
mAddEffectDialog.eventEffectModified += MyGUI::newDelegate(this, &EffectEditorBase::onEffectModified);
|
||||||
|
@ -482,6 +483,13 @@ namespace MWGui
|
||||||
const std::vector<ESM::ENAMstruct>& list = spell->mEffects.mList;
|
const std::vector<ESM::ENAMstruct>& list = spell->mEffects.mList;
|
||||||
for (std::vector<ESM::ENAMstruct>::const_iterator it2 = list.begin(); it2 != list.end(); ++it2)
|
for (std::vector<ESM::ENAMstruct>::const_iterator it2 = list.begin(); it2 != list.end(); ++it2)
|
||||||
{
|
{
|
||||||
|
const ESM::MagicEffect * effect = MWBase::Environment::get().getWorld()->getStore().get<ESM::MagicEffect>().find(it2->mEffectID);
|
||||||
|
|
||||||
|
// skip effects that do not allow spellmaking/enchanting
|
||||||
|
int requiredFlags = (mType == Spellmaking) ? ESM::MagicEffect::AllowSpellmaking : ESM::MagicEffect::AllowEnchanting;
|
||||||
|
if (!(effect->mData.mFlags & requiredFlags))
|
||||||
|
continue;
|
||||||
|
|
||||||
if (std::find(knownEffects.begin(), knownEffects.end(), it2->mEffectID) == knownEffects.end())
|
if (std::find(knownEffects.begin(), knownEffects.end(), it2->mEffectID) == knownEffects.end())
|
||||||
knownEffects.push_back(it2->mEffectID);
|
knownEffects.push_back(it2->mEffectID);
|
||||||
}
|
}
|
||||||
|
|
|
@ -85,7 +85,13 @@ namespace MWGui
|
||||||
class EffectEditorBase
|
class EffectEditorBase
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
EffectEditorBase();
|
enum Type
|
||||||
|
{
|
||||||
|
Spellmaking,
|
||||||
|
Enchanting
|
||||||
|
};
|
||||||
|
|
||||||
|
EffectEditorBase(Type type);
|
||||||
virtual ~EffectEditorBase();
|
virtual ~EffectEditorBase();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -121,6 +127,9 @@ namespace MWGui
|
||||||
void setWidgets (Widgets::MWList* availableEffectsList, MyGUI::ScrollView* usedEffectsView);
|
void setWidgets (Widgets::MWList* availableEffectsList, MyGUI::ScrollView* usedEffectsView);
|
||||||
|
|
||||||
virtual void notifyEffectsChanged () {}
|
virtual void notifyEffectsChanged () {}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Type mType;
|
||||||
};
|
};
|
||||||
|
|
||||||
class SpellCreationDialog : public WindowBase, public ReferenceInterface, public EffectEditorBase
|
class SpellCreationDialog : public WindowBase, public ReferenceInterface, public EffectEditorBase
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#include "../mwbase/windowmanager.hpp"
|
#include "../mwbase/windowmanager.hpp"
|
||||||
|
|
||||||
#include "../mwworld/class.hpp"
|
#include "../mwworld/class.hpp"
|
||||||
|
#include "../mwmechanics/spellcasting.hpp"
|
||||||
|
|
||||||
#include "mapwindow.hpp"
|
#include "mapwindow.hpp"
|
||||||
#include "inventorywindow.hpp"
|
#include "inventorywindow.hpp"
|
||||||
|
@ -19,6 +20,7 @@
|
||||||
|
|
||||||
namespace MWGui
|
namespace MWGui
|
||||||
{
|
{
|
||||||
|
std::string ToolTips::sSchoolNames[] = {"#{sSchoolAlteration}", "#{sSchoolConjuration}", "#{sSchoolDestruction}", "#{sSchoolIllusion}", "#{sSchoolMysticism}", "#{sSchoolRestoration}"};
|
||||||
|
|
||||||
ToolTips::ToolTips() :
|
ToolTips::ToolTips() :
|
||||||
Layout("openmw_tooltips.layout")
|
Layout("openmw_tooltips.layout")
|
||||||
|
@ -220,6 +222,12 @@ namespace MWGui
|
||||||
params.mNoTarget = false;
|
params.mNoTarget = false;
|
||||||
effects.push_back(params);
|
effects.push_back(params);
|
||||||
}
|
}
|
||||||
|
if (MWMechanics::spellIncreasesSkill(spell)) // display school of spells that contribute to skill progress
|
||||||
|
{
|
||||||
|
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
|
||||||
|
int school = MWMechanics::getSpellSchool(spell, player);
|
||||||
|
info.text = "#{sSchool}: " + sSchoolNames[school];
|
||||||
|
}
|
||||||
info.effects = effects;
|
info.effects = effects;
|
||||||
tooltipSize = createToolTip(info);
|
tooltipSize = createToolTip(info);
|
||||||
}
|
}
|
||||||
|
@ -739,19 +747,11 @@ namespace MWGui
|
||||||
icon.insert(slashPos+1, "b_");
|
icon.insert(slashPos+1, "b_");
|
||||||
icon = Misc::ResourceHelpers::correctIconPath(icon);
|
icon = Misc::ResourceHelpers::correctIconPath(icon);
|
||||||
|
|
||||||
std::vector<std::string> schools;
|
|
||||||
schools.push_back ("#{sSchoolAlteration}");
|
|
||||||
schools.push_back ("#{sSchoolConjuration}");
|
|
||||||
schools.push_back ("#{sSchoolDestruction}");
|
|
||||||
schools.push_back ("#{sSchoolIllusion}");
|
|
||||||
schools.push_back ("#{sSchoolMysticism}");
|
|
||||||
schools.push_back ("#{sSchoolRestoration}");
|
|
||||||
|
|
||||||
widget->setUserString("ToolTipType", "Layout");
|
widget->setUserString("ToolTipType", "Layout");
|
||||||
widget->setUserString("ToolTipLayout", "MagicEffectToolTip");
|
widget->setUserString("ToolTipLayout", "MagicEffectToolTip");
|
||||||
widget->setUserString("Caption_MagicEffectName", "#{" + name + "}");
|
widget->setUserString("Caption_MagicEffectName", "#{" + name + "}");
|
||||||
widget->setUserString("Caption_MagicEffectDescription", effect->mDescription);
|
widget->setUserString("Caption_MagicEffectDescription", effect->mDescription);
|
||||||
widget->setUserString("Caption_MagicEffectSchool", "#{sSchool}: " + schools[effect->mData.mSchool]);
|
widget->setUserString("Caption_MagicEffectSchool", "#{sSchool}: " + sSchoolNames[effect->mData.mSchool]);
|
||||||
widget->setUserString("ImageTexture_MagicEffectImage", icon);
|
widget->setUserString("ImageTexture_MagicEffectImage", icon);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -96,6 +96,8 @@ namespace MWGui
|
||||||
/// Adjust position for a tooltip so that it doesn't leave the screen and does not obscure the mouse cursor
|
/// Adjust position for a tooltip so that it doesn't leave the screen and does not obscure the mouse cursor
|
||||||
void position(MyGUI::IntPoint& position, MyGUI::IntSize size, MyGUI::IntSize viewportSize);
|
void position(MyGUI::IntPoint& position, MyGUI::IntSize size, MyGUI::IntSize viewportSize);
|
||||||
|
|
||||||
|
static std::string sSchoolNames[6];
|
||||||
|
|
||||||
int mHorizontalScrollIndex;
|
int mHorizontalScrollIndex;
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -93,6 +93,21 @@ namespace MWGui
|
||||||
unborrowImpl(item, count, mBorrowedFromUs);
|
unborrowImpl(item, count, mBorrowedFromUs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TradeItemModel::adjustEncumbrance(float &encumbrance)
|
||||||
|
{
|
||||||
|
for (std::vector<ItemStack>::iterator it = mBorrowedToUs.begin(); it != mBorrowedToUs.end(); ++it)
|
||||||
|
{
|
||||||
|
MWWorld::Ptr item = it->mBase;
|
||||||
|
encumbrance += item.getClass().getWeight(item) * it->mCount;
|
||||||
|
}
|
||||||
|
for (std::vector<ItemStack>::iterator it = mBorrowedFromUs.begin(); it != mBorrowedFromUs.end(); ++it)
|
||||||
|
{
|
||||||
|
MWWorld::Ptr item = it->mBase;
|
||||||
|
encumbrance -= item.getClass().getWeight(item) * it->mCount;
|
||||||
|
}
|
||||||
|
encumbrance = std::max(0.f, encumbrance);
|
||||||
|
}
|
||||||
|
|
||||||
void TradeItemModel::abort()
|
void TradeItemModel::abort()
|
||||||
{
|
{
|
||||||
mBorrowedFromUs.clear();
|
mBorrowedFromUs.clear();
|
||||||
|
|
|
@ -34,6 +34,10 @@ namespace MWGui
|
||||||
/// Aborts trade
|
/// Aborts trade
|
||||||
void abort();
|
void abort();
|
||||||
|
|
||||||
|
/// Adjusts the given encumbrance by adding weight for items that have been lent to us,
|
||||||
|
/// and removing weight for items we've lent to someone else.
|
||||||
|
void adjustEncumbrance (float& encumbrance);
|
||||||
|
|
||||||
std::vector<ItemStack> getItemsBorrowedToUs();
|
std::vector<ItemStack> getItemsBorrowedToUs();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -206,6 +206,15 @@ namespace MWGui
|
||||||
mVideoWidget = mVideoBackground->createWidgetReal<VideoWidget>("ImageBox", 0,0,1,1, MyGUI::Align::Default);
|
mVideoWidget = mVideoBackground->createWidgetReal<VideoWidget>("ImageBox", 0,0,1,1, MyGUI::Align::Default);
|
||||||
mVideoWidget->setNeedMouseFocus(true);
|
mVideoWidget->setNeedMouseFocus(true);
|
||||||
mVideoWidget->setNeedKeyFocus(true);
|
mVideoWidget->setNeedKeyFocus(true);
|
||||||
|
|
||||||
|
#if MYGUI_VERSION >= MYGUI_DEFINE_VERSION(3,2,1)
|
||||||
|
// Removes default MyGUI system clipboard implementation, which supports windows only
|
||||||
|
MyGUI::ClipboardManager::getInstance().eventClipboardChanged.clear();
|
||||||
|
MyGUI::ClipboardManager::getInstance().eventClipboardRequested.clear();
|
||||||
|
|
||||||
|
MyGUI::ClipboardManager::getInstance().eventClipboardChanged += MyGUI::newDelegate(this, &WindowManager::onClipboardChanged);
|
||||||
|
MyGUI::ClipboardManager::getInstance().eventClipboardRequested += MyGUI::newDelegate(this, &WindowManager::onClipboardRequested);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void WindowManager::initUI()
|
void WindowManager::initUI()
|
||||||
|
@ -1699,4 +1708,27 @@ namespace MWGui
|
||||||
{
|
{
|
||||||
mScreenFader->setFactor(factor);
|
mScreenFader->setFactor(factor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WindowManager::onClipboardChanged(const std::string &_type, const std::string &_data)
|
||||||
|
{
|
||||||
|
if (_type == "Text")
|
||||||
|
SDL_SetClipboardText(MyGUI::TextIterator::getOnlyText(MyGUI::UString(_data)).asUTF8().c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
void WindowManager::onClipboardRequested(const std::string &_type, std::string &_data)
|
||||||
|
{
|
||||||
|
if (_type != "Text")
|
||||||
|
return;
|
||||||
|
char* text=0;
|
||||||
|
text = SDL_GetClipboardText();
|
||||||
|
if (text)
|
||||||
|
{
|
||||||
|
// MyGUI's clipboard might still have color information, to retain that information, only set the new text
|
||||||
|
// if it actually changed (clipboard inserted by an external application)
|
||||||
|
if (MyGUI::TextIterator::getOnlyText(_data) != text)
|
||||||
|
_data = text;
|
||||||
|
}
|
||||||
|
SDL_free(text);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -448,6 +448,9 @@ namespace MWGui
|
||||||
void onVideoKeyPressed(MyGUI::Widget *_sender, MyGUI::KeyCode _key, MyGUI::Char _char);
|
void onVideoKeyPressed(MyGUI::Widget *_sender, MyGUI::KeyCode _key, MyGUI::Char _char);
|
||||||
|
|
||||||
void sizeVideo(int screenWidth, int screenHeight);
|
void sizeVideo(int screenWidth, int screenHeight);
|
||||||
|
|
||||||
|
void onClipboardChanged(const std::string& _type, const std::string& _data);
|
||||||
|
void onClipboardRequested(const std::string& _type, std::string& _data);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -498,6 +498,7 @@ namespace MWInput
|
||||||
|
|
||||||
void InputManager::keyPressed( const SDL_KeyboardEvent &arg )
|
void InputManager::keyPressed( const SDL_KeyboardEvent &arg )
|
||||||
{
|
{
|
||||||
|
#if MYGUI_VERSION <= MYGUI_DEFINE_VERSION(3,2,0)
|
||||||
// Cut, copy & paste
|
// Cut, copy & paste
|
||||||
MyGUI::Widget* focus = MyGUI::InputManager::getInstance().getKeyFocusWidget();
|
MyGUI::Widget* focus = MyGUI::InputManager::getInstance().getKeyFocusWidget();
|
||||||
if (focus)
|
if (focus)
|
||||||
|
@ -537,20 +538,26 @@ namespace MWInput
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
OIS::KeyCode kc = mInputManager->sdl2OISKeyCode(arg.keysym.sym);
|
OIS::KeyCode kc = mInputManager->sdl2OISKeyCode(arg.keysym.sym);
|
||||||
|
|
||||||
|
bool consumed = false;
|
||||||
if (kc != OIS::KC_UNASSIGNED)
|
if (kc != OIS::KC_UNASSIGNED)
|
||||||
{
|
{
|
||||||
|
consumed = SDL_IsTextInputActive() &&
|
||||||
|
( !(SDLK_SCANCODE_MASK & arg.keysym.sym) && std::isprint(arg.keysym.sym)); // Little trick to check if key is printable
|
||||||
bool guiFocus = MyGUI::InputManager::getInstance().injectKeyPress(MyGUI::KeyCode::Enum(kc), 0);
|
bool guiFocus = MyGUI::InputManager::getInstance().injectKeyPress(MyGUI::KeyCode::Enum(kc), 0);
|
||||||
setPlayerControlsEnabled(!guiFocus);
|
setPlayerControlsEnabled(!guiFocus);
|
||||||
}
|
}
|
||||||
if (!mControlsDisabled)
|
if (!mControlsDisabled && !consumed)
|
||||||
mInputBinder->keyPressed (arg);
|
mInputBinder->keyPressed (arg);
|
||||||
|
|
||||||
// Clear MyGUI's clipboard, so it doesn't interfere with our own clipboard implementation.
|
// Clear MyGUI's clipboard, so it doesn't interfere with our own clipboard implementation.
|
||||||
// We do not use MyGUI's clipboard manager because it doesn't support system clipboard integration with SDL.
|
// We do not use MyGUI's clipboard manager because it doesn't support system clipboard integration with SDL.
|
||||||
|
#if MYGUI_VERSION <= MYGUI_DEFINE_VERSION(3,2,0)
|
||||||
MyGUI::ClipboardManager::getInstance().clearClipboardData("Text");
|
MyGUI::ClipboardManager::getInstance().clearClipboardData("Text");
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void InputManager::textInput(const SDL_TextInputEvent &arg)
|
void InputManager::textInput(const SDL_TextInputEvent &arg)
|
||||||
|
@ -804,8 +811,7 @@ namespace MWInput
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if(MWBase::Environment::get().getWindowManager()->getMode() != MWGui::GM_Journal
|
if(MWBase::Environment::get().getWindowManager()->getMode() != MWGui::GM_Journal
|
||||||
&& MWBase::Environment::get().getWindowManager ()->getJournalAllowed()
|
&& MWBase::Environment::get().getWindowManager ()->getJournalAllowed())
|
||||||
&& MWBase::Environment::get().getWindowManager()->getMode() != MWGui::GM_Console)
|
|
||||||
{
|
{
|
||||||
MWBase::Environment::get().getSoundManager()->playSound ("book open", 1.0, 1.0);
|
MWBase::Environment::get().getSoundManager()->playSound ("book open", 1.0, 1.0);
|
||||||
MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Journal);
|
MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Journal);
|
||||||
|
|
|
@ -1402,6 +1402,7 @@ namespace MWMechanics
|
||||||
if (stats.isDead())
|
if (stats.isDead())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
// An actor counts as following if AiFollow is the current AiPackage, or there are only Combat packages before the AiFollow package
|
||||||
for (std::list<MWMechanics::AiPackage*>::const_iterator it = stats.getAiSequence().begin(); it != stats.getAiSequence().end(); ++it)
|
for (std::list<MWMechanics::AiPackage*>::const_iterator it = stats.getAiSequence().begin(); it != stats.getAiSequence().end(); ++it)
|
||||||
{
|
{
|
||||||
if ((*it)->getTypeId() == MWMechanics::AiPackage::TypeIdFollow)
|
if ((*it)->getTypeId() == MWMechanics::AiPackage::TypeIdFollow)
|
||||||
|
@ -1412,6 +1413,8 @@ namespace MWMechanics
|
||||||
if (followTarget == actor)
|
if (followTarget == actor)
|
||||||
list.push_back(iter->first);
|
list.push_back(iter->first);
|
||||||
}
|
}
|
||||||
|
else if ((*it)->getTypeId() != MWMechanics::AiPackage::TypeIdCombat)
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return list;
|
return list;
|
||||||
|
|
|
@ -32,6 +32,15 @@ MWMechanics::AiFollow::AiFollow(const std::string &actorId, bool commanded)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MWMechanics::AiFollow::AiFollow(const ESM::AiSequence::AiFollow *follow)
|
||||||
|
: mAlwaysFollow(follow->mAlwaysFollow), mRemainingDuration(follow->mRemainingDuration)
|
||||||
|
, mX(follow->mData.mX), mY(follow->mData.mY), mZ(follow->mData.mZ)
|
||||||
|
, mActorRefId(follow->mTargetId), mActorId(-1), mCellId(follow->mCellId)
|
||||||
|
, mCommanded(follow->mCommanded)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
bool MWMechanics::AiFollow::execute (const MWWorld::Ptr& actor,float duration)
|
bool MWMechanics::AiFollow::execute (const MWWorld::Ptr& actor,float duration)
|
||||||
{
|
{
|
||||||
MWWorld::Ptr target = getTarget();
|
MWWorld::Ptr target = getTarget();
|
||||||
|
@ -131,15 +140,6 @@ void MWMechanics::AiFollow::writeState(ESM::AiSequence::AiSequence &sequence) co
|
||||||
sequence.mPackages.push_back(package);
|
sequence.mPackages.push_back(package);
|
||||||
}
|
}
|
||||||
|
|
||||||
MWMechanics::AiFollow::AiFollow(const ESM::AiSequence::AiFollow *follow)
|
|
||||||
: mAlwaysFollow(follow->mAlwaysFollow), mRemainingDuration(follow->mRemainingDuration)
|
|
||||||
, mX(follow->mData.mX), mY(follow->mData.mY), mZ(follow->mData.mZ)
|
|
||||||
, mActorRefId(follow->mTargetId), mCellId(follow->mCellId)
|
|
||||||
, mCommanded(follow->mCommanded)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
MWWorld::Ptr MWMechanics::AiFollow::getTarget()
|
MWWorld::Ptr MWMechanics::AiFollow::getTarget()
|
||||||
{
|
{
|
||||||
if (mActorId == -2)
|
if (mActorId == -2)
|
||||||
|
|
|
@ -32,12 +32,18 @@ AiPursue *MWMechanics::AiPursue::clone() const
|
||||||
}
|
}
|
||||||
bool AiPursue::execute (const MWWorld::Ptr& actor, float duration)
|
bool AiPursue::execute (const MWWorld::Ptr& actor, float duration)
|
||||||
{
|
{
|
||||||
|
if(actor.getClass().getCreatureStats(actor).isDead())
|
||||||
|
return true;
|
||||||
|
|
||||||
ESM::Position pos = actor.getRefData().getPosition(); //position of the actor
|
ESM::Position pos = actor.getRefData().getPosition(); //position of the actor
|
||||||
const MWWorld::Ptr target = MWBase::Environment::get().getWorld()->searchPtrViaActorId(mTargetActorId); //The target to follow
|
const MWWorld::Ptr target = MWBase::Environment::get().getWorld()->searchPtrViaActorId(mTargetActorId); //The target to follow
|
||||||
|
|
||||||
if(target == MWWorld::Ptr())
|
if(target == MWWorld::Ptr())
|
||||||
return true; //Target doesn't exist
|
return true; //Target doesn't exist
|
||||||
|
|
||||||
|
if(target.getClass().getCreatureStats(target).isDead())
|
||||||
|
return true;
|
||||||
|
|
||||||
actor.getClass().getCreatureStats(actor).setDrawState(DrawState_Nothing);
|
actor.getClass().getCreatureStats(actor).setDrawState(DrawState_Nothing);
|
||||||
|
|
||||||
//Set the target desition from the actor
|
//Set the target desition from the actor
|
||||||
|
|
|
@ -196,7 +196,8 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat
|
||||||
bool block = mPtr.getClass().getCreatureStats(mPtr).getBlock();
|
bool block = mPtr.getClass().getCreatureStats(mPtr).getBlock();
|
||||||
if(mHitState == CharState_None)
|
if(mHitState == CharState_None)
|
||||||
{
|
{
|
||||||
if (mPtr.getClass().getCreatureStats(mPtr).getFatigue().getCurrent() < 0)
|
if (mPtr.getClass().getCreatureStats(mPtr).getFatigue().getCurrent() < 0
|
||||||
|
|| mPtr.getClass().getCreatureStats(mPtr).getFatigue().getBase() == 0)
|
||||||
{
|
{
|
||||||
mHitState = CharState_KnockOut;
|
mHitState = CharState_KnockOut;
|
||||||
mCurrentHit = "knockout";
|
mCurrentHit = "knockout";
|
||||||
|
@ -1663,6 +1664,9 @@ void CharacterController::updateVisibility()
|
||||||
}
|
}
|
||||||
|
|
||||||
mAnimation->setAlpha(alpha);
|
mAnimation->setAlpha(alpha);
|
||||||
|
|
||||||
|
float light = mPtr.getClass().getCreatureStats(mPtr).getMagicEffects().get(ESM::MagicEffect::Light).getMagnitude();
|
||||||
|
mAnimation->setLightEffect(light);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CharacterController::determineAttackType()
|
void CharacterController::determineAttackType()
|
||||||
|
@ -1671,9 +1675,9 @@ void CharacterController::determineAttackType()
|
||||||
|
|
||||||
if(mPtr.getClass().hasInventoryStore(mPtr))
|
if(mPtr.getClass().hasInventoryStore(mPtr))
|
||||||
{
|
{
|
||||||
if (move[1]) // forward-backward
|
if (move[1] && !move[0]) // forward-backward
|
||||||
mAttackType = "thrust";
|
mAttackType = "thrust";
|
||||||
else if (move[0]) //sideway
|
else if (move[0] && !move[1]) //sideway
|
||||||
mAttackType = "slash";
|
mAttackType = "slash";
|
||||||
else
|
else
|
||||||
mAttackType = "chop";
|
mAttackType = "chop";
|
||||||
|
|
|
@ -19,9 +19,6 @@ namespace ESM
|
||||||
namespace MWMechanics
|
namespace MWMechanics
|
||||||
{
|
{
|
||||||
/// \brief Additional stats for NPCs
|
/// \brief Additional stats for NPCs
|
||||||
///
|
|
||||||
/// \note For technical reasons the spell list and the currently selected spell is also handled by
|
|
||||||
/// CreatureStats, even though they are actually NPC stats.
|
|
||||||
|
|
||||||
class NpcStats : public CreatureStats
|
class NpcStats : public CreatureStats
|
||||||
{
|
{
|
||||||
|
|
|
@ -151,6 +151,20 @@ namespace MWMechanics
|
||||||
return school;
|
return school;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool spellIncreasesSkill(const ESM::Spell *spell)
|
||||||
|
{
|
||||||
|
if (spell->mData.mType == ESM::Spell::ST_Spell && !(spell->mData.mFlags & ESM::Spell::F_Always))
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool spellIncreasesSkill(const std::string &spellId)
|
||||||
|
{
|
||||||
|
const ESM::Spell* spell =
|
||||||
|
MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>().find(spellId);
|
||||||
|
return spellIncreasesSkill(spell);
|
||||||
|
}
|
||||||
|
|
||||||
float getEffectResistanceAttribute (short effectId, const MagicEffects* actorEffects)
|
float getEffectResistanceAttribute (short effectId, const MagicEffects* actorEffects)
|
||||||
{
|
{
|
||||||
short resistanceEffect = ESM::MagicEffect::getResistanceEffect(effectId);
|
short resistanceEffect = ESM::MagicEffect::getResistanceEffect(effectId);
|
||||||
|
@ -775,7 +789,7 @@ namespace MWMechanics
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mCaster.getRefData().getHandle() == "player" && spell->mData.mType == ESM::Spell::ST_Spell)
|
if (mCaster.getRefData().getHandle() == "player" && spellIncreasesSkill(spell))
|
||||||
mCaster.getClass().skillUsageSucceeded(mCaster,
|
mCaster.getClass().skillUsageSucceeded(mCaster,
|
||||||
spellSchoolToSkill(school), 0);
|
spellSchoolToSkill(school), 0);
|
||||||
|
|
||||||
|
@ -874,5 +888,4 @@ namespace MWMechanics
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,6 +36,10 @@ namespace MWMechanics
|
||||||
int getSpellSchool(const std::string& spellId, const MWWorld::Ptr& actor);
|
int getSpellSchool(const std::string& spellId, const MWWorld::Ptr& actor);
|
||||||
int getSpellSchool(const ESM::Spell* spell, const MWWorld::Ptr& actor);
|
int getSpellSchool(const ESM::Spell* spell, const MWWorld::Ptr& actor);
|
||||||
|
|
||||||
|
/// Get whether or not the given spell contributes to skill progress.
|
||||||
|
bool spellIncreasesSkill(const ESM::Spell* spell);
|
||||||
|
bool spellIncreasesSkill(const std::string& spellId);
|
||||||
|
|
||||||
/// Get the resistance attribute against an effect for a given actor. This will add together
|
/// Get the resistance attribute against an effect for a given actor. This will add together
|
||||||
/// ResistX and Weakness to X effects relevant against the given effect.
|
/// ResistX and Weakness to X effects relevant against the given effect.
|
||||||
float getEffectResistanceAttribute (short effectId, const MagicEffects* actorEffects);
|
float getEffectResistanceAttribute (short effectId, const MagicEffects* actorEffects);
|
||||||
|
|
|
@ -63,12 +63,26 @@ namespace MWMechanics
|
||||||
TContainer::iterator iter = mSpells.find (lower);
|
TContainer::iterator iter = mSpells.find (lower);
|
||||||
std::map<std::string, CorprusStats>::iterator corprusIt = mCorprusSpells.find(lower);
|
std::map<std::string, CorprusStats>::iterator corprusIt = mCorprusSpells.find(lower);
|
||||||
|
|
||||||
|
// if it's corprus, remove negative and keep positive effects
|
||||||
|
if (corprusIt != mCorprusSpells.end())
|
||||||
|
{
|
||||||
|
worsenCorprus(lower);
|
||||||
|
if (mPermanentSpellEffects.find(lower) != mPermanentSpellEffects.end())
|
||||||
|
{
|
||||||
|
MagicEffects & effects = mPermanentSpellEffects[lower];
|
||||||
|
for (MagicEffects::Collection::const_iterator effectIt = effects.begin(); effectIt != effects.end(); ++effectIt)
|
||||||
|
{
|
||||||
|
const ESM::MagicEffect * magicEffect = MWBase::Environment::get().getWorld()->getStore().get<ESM::MagicEffect>().find(effectIt->first.mId);
|
||||||
|
if (magicEffect->mData.mFlags & ESM::MagicEffect::Harmful)
|
||||||
|
effects.remove(effectIt->first);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mCorprusSpells.erase(corprusIt);
|
||||||
|
}
|
||||||
|
|
||||||
if (iter!=mSpells.end())
|
if (iter!=mSpells.end())
|
||||||
mSpells.erase (iter);
|
mSpells.erase (iter);
|
||||||
|
|
||||||
if (corprusIt != mCorprusSpells.end())
|
|
||||||
mCorprusSpells.erase(corprusIt);
|
|
||||||
|
|
||||||
if (spellId==mSelectedSpell)
|
if (spellId==mSelectedSpell)
|
||||||
mSelectedSpell.clear();
|
mSelectedSpell.clear();
|
||||||
}
|
}
|
||||||
|
@ -94,20 +108,17 @@ namespace MWMechanics
|
||||||
if (iter->second.find(i) != iter->second.end())
|
if (iter->second.find(i) != iter->second.end())
|
||||||
random = iter->second.at(i);
|
random = iter->second.at(i);
|
||||||
|
|
||||||
int magnMult = 1;
|
effects.add (*it, it->mMagnMin + (it->mMagnMax - it->mMagnMin) * random);
|
||||||
if (mCorprusSpells.find(spell->mId) != mCorprusSpells.end())
|
|
||||||
{
|
|
||||||
const ESM::MagicEffect* effect = MWBase::Environment::get().getWorld()->getStore().get<ESM::MagicEffect>().find(spell->mEffects.mList.front().mEffectID);
|
|
||||||
if ((it->mEffectID != ESM::MagicEffect::Corprus) && (effect->mData.mFlags & ESM::MagicEffect::UncappedDamage)) // APPLIED_ONCE
|
|
||||||
magnMult += mCorprusSpells.at(spell->mId).mWorsenings;
|
|
||||||
}
|
|
||||||
|
|
||||||
effects.add (*it, (it->mMagnMin + (it->mMagnMax - it->mMagnMin) * random) * magnMult);
|
|
||||||
++i;
|
++i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (std::map<std::string, MagicEffects>::const_iterator it = mPermanentSpellEffects.begin(); it != mPermanentSpellEffects.end(); ++it)
|
||||||
|
{
|
||||||
|
effects += it->second;
|
||||||
|
}
|
||||||
|
|
||||||
return effects;
|
return effects;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -241,6 +252,25 @@ namespace MWMechanics
|
||||||
{
|
{
|
||||||
mCorprusSpells[corpSpellId].mNextWorsening = MWBase::Environment::get().getWorld()->getTimeStamp() + CorprusStats::sWorseningPeriod;
|
mCorprusSpells[corpSpellId].mNextWorsening = MWBase::Environment::get().getWorld()->getTimeStamp() + CorprusStats::sWorseningPeriod;
|
||||||
mCorprusSpells[corpSpellId].mWorsenings++;
|
mCorprusSpells[corpSpellId].mWorsenings++;
|
||||||
|
|
||||||
|
// update worsened effects
|
||||||
|
mPermanentSpellEffects[corpSpellId] = MagicEffects();
|
||||||
|
const ESM::Spell * spell = MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>().find(corpSpellId);
|
||||||
|
int i=0;
|
||||||
|
for (std::vector<ESM::ENAMstruct>::const_iterator effectIt = spell->mEffects.mList.begin(); effectIt != spell->mEffects.mList.end(); ++effectIt, ++i)
|
||||||
|
{
|
||||||
|
const ESM::MagicEffect * magicEffect = MWBase::Environment::get().getWorld()->getStore().get<ESM::MagicEffect>().find(effectIt->mEffectID);
|
||||||
|
if ((effectIt->mEffectID != ESM::MagicEffect::Corprus) && (magicEffect->mData.mFlags & ESM::MagicEffect::UncappedDamage)) // APPLIED_ONCE
|
||||||
|
{
|
||||||
|
float random = 1.f;
|
||||||
|
if (mSpells[corpSpellId].find(i) != mSpells[corpSpellId].end())
|
||||||
|
random = mSpells[corpSpellId].at(i);
|
||||||
|
|
||||||
|
float magnitude = effectIt->mMagnMin + (effectIt->mMagnMax - effectIt->mMagnMin) * random;
|
||||||
|
magnitude *= std::max(1, mCorprusSpells[corpSpellId].mWorsenings);
|
||||||
|
mPermanentSpellEffects[corpSpellId].add(MWMechanics::EffectKey(*effectIt), MWMechanics::EffectParam(magnitude));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Spells::hasCorprusEffect(const ESM::Spell *spell)
|
bool Spells::hasCorprusEffect(const ESM::Spell *spell)
|
||||||
|
@ -297,6 +327,20 @@ namespace MWMechanics
|
||||||
for (std::map<std::string, ESM::TimeStamp>::const_iterator it = state.mUsedPowers.begin(); it != state.mUsedPowers.end(); ++it)
|
for (std::map<std::string, ESM::TimeStamp>::const_iterator it = state.mUsedPowers.begin(); it != state.mUsedPowers.end(); ++it)
|
||||||
mUsedPowers[it->first] = MWWorld::TimeStamp(it->second);
|
mUsedPowers[it->first] = MWWorld::TimeStamp(it->second);
|
||||||
|
|
||||||
|
for (std::map<std::string, std::vector<ESM::SpellState::PermanentSpellEffectInfo> >::const_iterator it =
|
||||||
|
state.mPermanentSpellEffects.begin(); it != state.mPermanentSpellEffects.end(); ++it)
|
||||||
|
{
|
||||||
|
const ESM::Spell * spell = MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>().search(it->first);
|
||||||
|
if (!spell)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
mPermanentSpellEffects[it->first] = MagicEffects();
|
||||||
|
for (std::vector<ESM::SpellState::PermanentSpellEffectInfo>::const_iterator effectIt = it->second.begin(); effectIt != it->second.end(); ++effectIt)
|
||||||
|
{
|
||||||
|
mPermanentSpellEffects[it->first].add(EffectKey(effectIt->mId, effectIt->mArg), effectIt->mMagnitude);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
mCorprusSpells.clear();
|
mCorprusSpells.clear();
|
||||||
for (std::map<std::string, ESM::SpellState::CorprusStats>::const_iterator it = state.mCorprusSpells.begin(); it != state.mCorprusSpells.end(); ++it)
|
for (std::map<std::string, ESM::SpellState::CorprusStats>::const_iterator it = state.mCorprusSpells.begin(); it != state.mCorprusSpells.end(); ++it)
|
||||||
{
|
{
|
||||||
|
@ -316,6 +360,21 @@ namespace MWMechanics
|
||||||
for (std::map<std::string, MWWorld::TimeStamp>::const_iterator it = mUsedPowers.begin(); it != mUsedPowers.end(); ++it)
|
for (std::map<std::string, MWWorld::TimeStamp>::const_iterator it = mUsedPowers.begin(); it != mUsedPowers.end(); ++it)
|
||||||
state.mUsedPowers[it->first] = it->second.toEsm();
|
state.mUsedPowers[it->first] = it->second.toEsm();
|
||||||
|
|
||||||
|
for (std::map<std::string, MagicEffects>::const_iterator it = mPermanentSpellEffects.begin(); it != mPermanentSpellEffects.end(); ++it)
|
||||||
|
{
|
||||||
|
std::vector<ESM::SpellState::PermanentSpellEffectInfo> effectList;
|
||||||
|
for (MagicEffects::Collection::const_iterator effectIt = it->second.begin(); effectIt != it->second.end(); ++effectIt)
|
||||||
|
{
|
||||||
|
ESM::SpellState::PermanentSpellEffectInfo info;
|
||||||
|
info.mId = effectIt->first.mId;
|
||||||
|
info.mArg = effectIt->first.mArg;
|
||||||
|
info.mMagnitude = effectIt->second.getModifier();
|
||||||
|
|
||||||
|
effectList.push_back(info);
|
||||||
|
}
|
||||||
|
state.mPermanentSpellEffects[it->first] = effectList;
|
||||||
|
}
|
||||||
|
|
||||||
for (std::map<std::string, CorprusStats>::const_iterator it = mCorprusSpells.begin(); it != mCorprusSpells.end(); ++it)
|
for (std::map<std::string, CorprusStats>::const_iterator it = mCorprusSpells.begin(); it != mCorprusSpells.end(); ++it)
|
||||||
{
|
{
|
||||||
state.mCorprusSpells[it->first].mWorsenings = mCorprusSpells.at(it->first).mWorsenings;
|
state.mCorprusSpells[it->first].mWorsenings = mCorprusSpells.at(it->first).mWorsenings;
|
||||||
|
|
|
@ -46,6 +46,9 @@ namespace MWMechanics
|
||||||
|
|
||||||
TContainer mSpells;
|
TContainer mSpells;
|
||||||
|
|
||||||
|
// spell-tied effects that will be applied even after removing the spell (currently used to keep positive effects when corprus is removed)
|
||||||
|
std::map<std::string, MagicEffects> mPermanentSpellEffects;
|
||||||
|
|
||||||
// Note: this is the spell that's about to be cast, *not* the spell selected in the GUI (which may be different)
|
// Note: this is the spell that's about to be cast, *not* the spell selected in the GUI (which may be different)
|
||||||
std::string mSelectedSpell;
|
std::string mSelectedSpell;
|
||||||
|
|
||||||
|
|
|
@ -71,6 +71,7 @@ Animation::Animation(const MWWorld::Ptr &ptr, Ogre::SceneNode *node)
|
||||||
, mNonAccumCtrl(NULL)
|
, mNonAccumCtrl(NULL)
|
||||||
, mAccumulate(0.0f)
|
, mAccumulate(0.0f)
|
||||||
, mNullAnimationTimePtr(OGRE_NEW NullAnimationTime)
|
, mNullAnimationTimePtr(OGRE_NEW NullAnimationTime)
|
||||||
|
, mGlowLight(NULL)
|
||||||
{
|
{
|
||||||
for(size_t i = 0;i < sNumGroups;i++)
|
for(size_t i = 0;i < sNumGroups;i++)
|
||||||
mAnimationTimePtr[i].bind(OGRE_NEW AnimationTime(this));
|
mAnimationTimePtr[i].bind(OGRE_NEW AnimationTime(this));
|
||||||
|
@ -78,6 +79,8 @@ Animation::Animation(const MWWorld::Ptr &ptr, Ogre::SceneNode *node)
|
||||||
|
|
||||||
Animation::~Animation()
|
Animation::~Animation()
|
||||||
{
|
{
|
||||||
|
setLightEffect(0);
|
||||||
|
|
||||||
mEffects.clear();
|
mEffects.clear();
|
||||||
|
|
||||||
mAnimSources.clear();
|
mAnimSources.clear();
|
||||||
|
@ -110,6 +113,11 @@ void Animation::setObjectRoot(const std::string &model, bool baseonly)
|
||||||
|
|
||||||
mObjectRoot = (!baseonly ? NifOgre::Loader::createObjects(mInsert, mdlname) :
|
mObjectRoot = (!baseonly ? NifOgre::Loader::createObjects(mInsert, mdlname) :
|
||||||
NifOgre::Loader::createObjectBase(mInsert, mdlname));
|
NifOgre::Loader::createObjectBase(mInsert, mdlname));
|
||||||
|
|
||||||
|
// Fast forward auto-play particles, which will have been set up as Emitting by the loader.
|
||||||
|
for (unsigned int i=0; i<mObjectRoot->mParticles.size(); ++i)
|
||||||
|
mObjectRoot->mParticles[i]->fastForward(1, 0.1);
|
||||||
|
|
||||||
if(mObjectRoot->mSkelBase)
|
if(mObjectRoot->mSkelBase)
|
||||||
{
|
{
|
||||||
mSkelBase = mObjectRoot->mSkelBase;
|
mSkelBase = mObjectRoot->mSkelBase;
|
||||||
|
@ -1194,8 +1202,9 @@ bool Animation::allowSwitchViewMode() const
|
||||||
{
|
{
|
||||||
for (AnimStateMap::const_iterator stateiter = mStates.begin(); stateiter != mStates.end(); ++stateiter)
|
for (AnimStateMap::const_iterator stateiter = mStates.begin(); stateiter != mStates.end(); ++stateiter)
|
||||||
{
|
{
|
||||||
if(stateiter->second.mPriority > MWMechanics::Priority_Movement
|
if((stateiter->second.mPriority > MWMechanics::Priority_Movement
|
||||||
&& stateiter->second.mPriority < MWMechanics::Priority_Torch)
|
&& stateiter->second.mPriority < MWMechanics::Priority_Torch)
|
||||||
|
|| stateiter->second.mPriority == MWMechanics::Priority_Death)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -1391,6 +1400,37 @@ Ogre::Vector3 Animation::getEnchantmentColor(MWWorld::Ptr item)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Animation::setLightEffect(float effect)
|
||||||
|
{
|
||||||
|
if (effect == 0)
|
||||||
|
{
|
||||||
|
if (mGlowLight)
|
||||||
|
{
|
||||||
|
mInsert->getCreator()->destroySceneNode(mGlowLight->getParentSceneNode());
|
||||||
|
mInsert->getCreator()->destroyLight(mGlowLight);
|
||||||
|
mGlowLight = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!mGlowLight)
|
||||||
|
{
|
||||||
|
mGlowLight = mInsert->getCreator()->createLight();
|
||||||
|
|
||||||
|
Ogre::AxisAlignedBox bounds = Ogre::AxisAlignedBox::BOX_NULL;
|
||||||
|
for(size_t i = 0;i < mObjectRoot->mEntities.size();i++)
|
||||||
|
{
|
||||||
|
Ogre::Entity *ent = mObjectRoot->mEntities[i];
|
||||||
|
bounds.merge(ent->getBoundingBox());
|
||||||
|
}
|
||||||
|
mInsert->createChildSceneNode(bounds.getCenter())->attachObject(mGlowLight);
|
||||||
|
}
|
||||||
|
mGlowLight->setType(Ogre::Light::LT_POINT);
|
||||||
|
effect += 3;
|
||||||
|
mGlowLight->setAttenuation(1.0f / (0.03 * (0.5/effect)), 0, 0.5/effect, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
ObjectAnimation::ObjectAnimation(const MWWorld::Ptr& ptr, const std::string &model)
|
ObjectAnimation::ObjectAnimation(const MWWorld::Ptr& ptr, const std::string &model)
|
||||||
: Animation(ptr, ptr.getRefData().getBaseNode())
|
: Animation(ptr, ptr.getRefData().getBaseNode())
|
||||||
|
|
|
@ -126,6 +126,8 @@ protected:
|
||||||
|
|
||||||
MWWorld::Ptr mPtr;
|
MWWorld::Ptr mPtr;
|
||||||
|
|
||||||
|
Ogre::Light* mGlowLight;
|
||||||
|
|
||||||
Ogre::SceneNode *mInsert;
|
Ogre::SceneNode *mInsert;
|
||||||
Ogre::Entity *mSkelBase;
|
Ogre::Entity *mSkelBase;
|
||||||
NifOgre::ObjectScenePtr mObjectRoot;
|
NifOgre::ObjectScenePtr mObjectRoot;
|
||||||
|
@ -301,6 +303,11 @@ public:
|
||||||
/// This is typically called as part of runAnimation, but may be called manually if needed.
|
/// This is typically called as part of runAnimation, but may be called manually if needed.
|
||||||
void updateEffects(float duration);
|
void updateEffects(float duration);
|
||||||
|
|
||||||
|
// TODO: move outside of this class
|
||||||
|
/// Makes this object glow, by placing a Light in its center.
|
||||||
|
/// @param effect Controls the radius and intensity of the light.
|
||||||
|
void setLightEffect(float effect);
|
||||||
|
|
||||||
virtual void showWeapons(bool showWeapon);
|
virtual void showWeapons(bool showWeapon);
|
||||||
virtual void showCarriedLeft(bool show) {}
|
virtual void showCarriedLeft(bool show) {}
|
||||||
virtual void attachArrow() {}
|
virtual void attachArrow() {}
|
||||||
|
|
|
@ -552,6 +552,10 @@ NifOgre::ObjectScenePtr NpcAnimation::insertBoundedPart(const std::string &model
|
||||||
std::for_each(objects->mEntities.begin(), objects->mEntities.end(), SetObjectGroup(group));
|
std::for_each(objects->mEntities.begin(), objects->mEntities.end(), SetObjectGroup(group));
|
||||||
std::for_each(objects->mParticles.begin(), objects->mParticles.end(), SetObjectGroup(group));
|
std::for_each(objects->mParticles.begin(), objects->mParticles.end(), SetObjectGroup(group));
|
||||||
|
|
||||||
|
// Fast forward auto-play particles, which will have been set up as Emitting by the loader.
|
||||||
|
for (unsigned int i=0; i<objects->mParticles.size(); ++i)
|
||||||
|
objects->mParticles[i]->fastForward(1, 0.1);
|
||||||
|
|
||||||
if(objects->mSkelBase)
|
if(objects->mSkelBase)
|
||||||
{
|
{
|
||||||
Ogre::AnimationStateSet *aset = objects->mSkelBase->getAllAnimationStates();
|
Ogre::AnimationStateSet *aset = objects->mSkelBase->getAllAnimationStates();
|
||||||
|
|
|
@ -111,7 +111,7 @@ namespace MWScript
|
||||||
const std::string& name, char type) const
|
const std::string& name, char type) const
|
||||||
{
|
{
|
||||||
int index = MWBase::Environment::get().getScriptManager()->getLocals (scriptId).
|
int index = MWBase::Environment::get().getScriptManager()->getLocals (scriptId).
|
||||||
search (type, name);
|
searchIndex (type, name);
|
||||||
|
|
||||||
if (index!=-1)
|
if (index!=-1)
|
||||||
return index;
|
return index;
|
||||||
|
|
|
@ -528,11 +528,12 @@ namespace MWScript
|
||||||
|
|
||||||
virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0)
|
virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0)
|
||||||
{
|
{
|
||||||
|
MWWorld::Ptr actor = R()(runtime, false);
|
||||||
|
|
||||||
std::string factionID = "";
|
std::string factionID = "";
|
||||||
|
|
||||||
if(arg0==0)
|
if(arg0==0)
|
||||||
{
|
{
|
||||||
MWWorld::Ptr actor = R()(runtime);
|
|
||||||
factionID = getDialogueActorFaction(actor);
|
factionID = getDialogueActorFaction(actor);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -562,11 +563,12 @@ namespace MWScript
|
||||||
|
|
||||||
virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0)
|
virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0)
|
||||||
{
|
{
|
||||||
|
MWWorld::Ptr actor = R()(runtime, false);
|
||||||
|
|
||||||
std::string factionID = "";
|
std::string factionID = "";
|
||||||
|
|
||||||
if(arg0==0)
|
if(arg0==0)
|
||||||
{
|
{
|
||||||
MWWorld::Ptr actor = R()(runtime);
|
|
||||||
factionID = getDialogueActorFaction(actor);
|
factionID = getDialogueActorFaction(actor);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -602,11 +604,12 @@ namespace MWScript
|
||||||
|
|
||||||
virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0)
|
virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0)
|
||||||
{
|
{
|
||||||
|
MWWorld::Ptr actor = R()(runtime, false);
|
||||||
|
|
||||||
std::string factionID = "";
|
std::string factionID = "";
|
||||||
|
|
||||||
if(arg0==0)
|
if(arg0==0)
|
||||||
{
|
{
|
||||||
MWWorld::Ptr actor = R()(runtime);
|
|
||||||
factionID = getDialogueActorFaction(actor);
|
factionID = getDialogueActorFaction(actor);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -637,6 +640,8 @@ namespace MWScript
|
||||||
|
|
||||||
virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0)
|
virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0)
|
||||||
{
|
{
|
||||||
|
MWWorld::Ptr ptr = R()(runtime, false);
|
||||||
|
|
||||||
std::string factionID = "";
|
std::string factionID = "";
|
||||||
if(arg0 >0)
|
if(arg0 >0)
|
||||||
{
|
{
|
||||||
|
@ -645,8 +650,6 @@ namespace MWScript
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
MWWorld::Ptr ptr = R()(runtime);
|
|
||||||
|
|
||||||
if(ptr.getClass().getNpcStats(ptr).getFactionRanks().empty())
|
if(ptr.getClass().getNpcStats(ptr).getFactionRanks().empty())
|
||||||
{
|
{
|
||||||
factionID = "";
|
factionID = "";
|
||||||
|
@ -750,6 +753,8 @@ namespace MWScript
|
||||||
|
|
||||||
virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0)
|
virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0)
|
||||||
{
|
{
|
||||||
|
MWWorld::Ptr ptr = R()(runtime, false);
|
||||||
|
|
||||||
std::string factionId;
|
std::string factionId;
|
||||||
|
|
||||||
if (arg0==1)
|
if (arg0==1)
|
||||||
|
@ -759,8 +764,6 @@ namespace MWScript
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
MWWorld::Ptr ptr = R()(runtime);
|
|
||||||
|
|
||||||
if (!ptr.getClass().getNpcStats (ptr).getFactionRanks().empty())
|
if (!ptr.getClass().getNpcStats (ptr).getFactionRanks().empty())
|
||||||
factionId = ptr.getClass().getNpcStats (ptr).getFactionRanks().begin()->first;
|
factionId = ptr.getClass().getNpcStats (ptr).getFactionRanks().begin()->first;
|
||||||
}
|
}
|
||||||
|
@ -783,6 +786,8 @@ namespace MWScript
|
||||||
|
|
||||||
virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0)
|
virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0)
|
||||||
{
|
{
|
||||||
|
MWWorld::Ptr ptr = R()(runtime, false);
|
||||||
|
|
||||||
Interpreter::Type_Integer value = runtime[0].mInteger;
|
Interpreter::Type_Integer value = runtime[0].mInteger;
|
||||||
runtime.pop();
|
runtime.pop();
|
||||||
|
|
||||||
|
@ -795,8 +800,6 @@ namespace MWScript
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
MWWorld::Ptr ptr = R()(runtime);
|
|
||||||
|
|
||||||
if (!ptr.getClass().getNpcStats (ptr).getFactionRanks().empty())
|
if (!ptr.getClass().getNpcStats (ptr).getFactionRanks().empty())
|
||||||
factionId = ptr.getClass().getNpcStats (ptr).getFactionRanks().begin()->first;
|
factionId = ptr.getClass().getNpcStats (ptr).getFactionRanks().begin()->first;
|
||||||
}
|
}
|
||||||
|
@ -818,6 +821,8 @@ namespace MWScript
|
||||||
|
|
||||||
virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0)
|
virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0)
|
||||||
{
|
{
|
||||||
|
MWWorld::Ptr ptr = R()(runtime, false);
|
||||||
|
|
||||||
Interpreter::Type_Integer value = runtime[0].mInteger;
|
Interpreter::Type_Integer value = runtime[0].mInteger;
|
||||||
runtime.pop();
|
runtime.pop();
|
||||||
|
|
||||||
|
@ -830,8 +835,6 @@ namespace MWScript
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
MWWorld::Ptr ptr = R()(runtime);
|
|
||||||
|
|
||||||
if (!ptr.getClass().getNpcStats (ptr).getFactionRanks().empty())
|
if (!ptr.getClass().getNpcStats (ptr).getFactionRanks().empty())
|
||||||
factionId = ptr.getClass().getNpcStats (ptr).getFactionRanks().begin()->first;
|
factionId = ptr.getClass().getNpcStats (ptr).getFactionRanks().begin()->first;
|
||||||
}
|
}
|
||||||
|
@ -913,6 +916,8 @@ namespace MWScript
|
||||||
|
|
||||||
virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0)
|
virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0)
|
||||||
{
|
{
|
||||||
|
MWWorld::Ptr ptr = R()(runtime, false);
|
||||||
|
|
||||||
std::string factionID = "";
|
std::string factionID = "";
|
||||||
if(arg0 >0 )
|
if(arg0 >0 )
|
||||||
{
|
{
|
||||||
|
@ -921,8 +926,6 @@ namespace MWScript
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
MWWorld::Ptr ptr = R()(runtime);
|
|
||||||
|
|
||||||
if(ptr.getClass().getNpcStats(ptr).getFactionRanks().empty())
|
if(ptr.getClass().getNpcStats(ptr).getFactionRanks().empty())
|
||||||
{
|
{
|
||||||
factionID = "";
|
factionID = "";
|
||||||
|
@ -952,6 +955,8 @@ namespace MWScript
|
||||||
|
|
||||||
virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0)
|
virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0)
|
||||||
{
|
{
|
||||||
|
MWWorld::Ptr ptr = R()(runtime, false);
|
||||||
|
|
||||||
std::string factionID = "";
|
std::string factionID = "";
|
||||||
if(arg0 >0 )
|
if(arg0 >0 )
|
||||||
{
|
{
|
||||||
|
@ -960,7 +965,6 @@ namespace MWScript
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
MWWorld::Ptr ptr = R()(runtime);
|
|
||||||
if(ptr.getClass().getNpcStats(ptr).getFactionRanks().empty())
|
if(ptr.getClass().getNpcStats(ptr).getFactionRanks().empty())
|
||||||
{
|
{
|
||||||
factionID = "";
|
factionID = "";
|
||||||
|
@ -985,6 +989,8 @@ namespace MWScript
|
||||||
|
|
||||||
virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0)
|
virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0)
|
||||||
{
|
{
|
||||||
|
MWWorld::Ptr ptr = R()(runtime, false);
|
||||||
|
|
||||||
std::string factionID = "";
|
std::string factionID = "";
|
||||||
if(arg0 >0 )
|
if(arg0 >0 )
|
||||||
{
|
{
|
||||||
|
@ -993,7 +999,6 @@ namespace MWScript
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
MWWorld::Ptr ptr = R()(runtime);
|
|
||||||
if(ptr.getClass().getNpcStats(ptr).getFactionRanks().empty())
|
if(ptr.getClass().getNpcStats(ptr).getFactionRanks().empty())
|
||||||
{
|
{
|
||||||
factionID = "";
|
factionID = "";
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
#include "actionteleport.hpp"
|
#include "actionteleport.hpp"
|
||||||
|
|
||||||
#include "../mwbase/environment.hpp"
|
#include "../mwbase/environment.hpp"
|
||||||
|
@ -16,15 +15,19 @@ namespace MWWorld
|
||||||
|
|
||||||
void ActionTeleport::executeImp (const Ptr& actor)
|
void ActionTeleport::executeImp (const Ptr& actor)
|
||||||
{
|
{
|
||||||
MWBase::World* world = MWBase::Environment::get().getWorld();
|
|
||||||
|
|
||||||
//find any NPC that is following the actor and teleport him too
|
//find any NPC that is following the actor and teleport him too
|
||||||
std::list<MWWorld::Ptr> followers = MWBase::Environment::get().getMechanicsManager()->getActorsFollowing(actor);
|
std::list<MWWorld::Ptr> followers = MWBase::Environment::get().getMechanicsManager()->getActorsFollowing(actor);
|
||||||
for(std::list<MWWorld::Ptr>::iterator it = followers.begin();it != followers.end();++it)
|
for(std::list<MWWorld::Ptr>::iterator it = followers.begin();it != followers.end();++it)
|
||||||
{
|
{
|
||||||
executeImp(*it);
|
teleport(*it);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
teleport(actor);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ActionTeleport::teleport(const Ptr &actor)
|
||||||
|
{
|
||||||
|
MWBase::World* world = MWBase::Environment::get().getWorld();
|
||||||
if(actor == world->getPlayerPtr())
|
if(actor == world->getPlayerPtr())
|
||||||
{
|
{
|
||||||
world->getPlayer().setTeleported(true);
|
world->getPlayer().setTeleported(true);
|
||||||
|
|
|
@ -14,12 +14,16 @@ namespace MWWorld
|
||||||
std::string mCellName;
|
std::string mCellName;
|
||||||
ESM::Position mPosition;
|
ESM::Position mPosition;
|
||||||
|
|
||||||
|
/// Teleports this actor and also teleports anyone following that actor.
|
||||||
virtual void executeImp (const Ptr& actor);
|
virtual void executeImp (const Ptr& actor);
|
||||||
|
|
||||||
|
/// Teleports only the given actor (internal use).
|
||||||
|
void teleport(const Ptr &actor);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
ActionTeleport (const std::string& cellName, const ESM::Position& position);
|
ActionTeleport (const std::string& cellName, const ESM::Position& position);
|
||||||
///< If cellName is empty, an exterior cell is asumed.
|
///< If cellName is empty, an exterior cell is assumed.
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,8 @@
|
||||||
#include "../mwmechanics/spellcasting.hpp"
|
#include "../mwmechanics/spellcasting.hpp"
|
||||||
|
|
||||||
#include "../mwrender/effectmanager.hpp"
|
#include "../mwrender/effectmanager.hpp"
|
||||||
|
#include "../mwrender/animation.hpp"
|
||||||
|
#include "../mwrender/renderconst.hpp"
|
||||||
|
|
||||||
#include "../mwsound/sound.hpp"
|
#include "../mwsound/sound.hpp"
|
||||||
|
|
||||||
|
@ -41,6 +43,9 @@ namespace MWWorld
|
||||||
if(state.mObject->mControllers[i].getSource().isNull())
|
if(state.mObject->mControllers[i].getSource().isNull())
|
||||||
state.mObject->mControllers[i].setSource(Ogre::SharedPtr<MWRender::EffectAnimationTime> (new MWRender::EffectAnimationTime()));
|
state.mObject->mControllers[i].setSource(Ogre::SharedPtr<MWRender::EffectAnimationTime> (new MWRender::EffectAnimationTime()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MWRender::Animation::setRenderProperties(state.mObject, MWRender::RV_Misc,
|
||||||
|
MWRender::RQG_Main, MWRender::RQG_Alpha, 0.f, false, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProjectileManager::update(NifOgre::ObjectScenePtr object, float duration)
|
void ProjectileManager::update(NifOgre::ObjectScenePtr object, float duration)
|
||||||
|
|
|
@ -259,8 +259,6 @@ namespace MWWorld
|
||||||
|
|
||||||
void Scene::changeCell (int X, int Y, const ESM::Position& position, bool adjustPlayerPos)
|
void Scene::changeCell (int X, int Y, const ESM::Position& position, bool adjustPlayerPos)
|
||||||
{
|
{
|
||||||
Nif::NIFFile::CacheLock cachelock;
|
|
||||||
|
|
||||||
Loading::Listener* loadingListener = MWBase::Environment::get().getWindowManager()->getLoadingScreen();
|
Loading::Listener* loadingListener = MWBase::Environment::get().getWindowManager()->getLoadingScreen();
|
||||||
Loading::ScopedLoad load(loadingListener);
|
Loading::ScopedLoad load(loadingListener);
|
||||||
|
|
||||||
|
@ -271,24 +269,6 @@ namespace MWWorld
|
||||||
|
|
||||||
CellStoreCollection::iterator active = mActiveCells.begin();
|
CellStoreCollection::iterator active = mActiveCells.begin();
|
||||||
|
|
||||||
// get the number of cells to unload
|
|
||||||
int numUnload = 0;
|
|
||||||
while (active!=mActiveCells.end())
|
|
||||||
{
|
|
||||||
if ((*active)->getCell()->isExterior())
|
|
||||||
{
|
|
||||||
if (std::abs (X-(*active)->getCell()->getGridX())<=1 &&
|
|
||||||
std::abs (Y-(*active)->getCell()->getGridY())<=1)
|
|
||||||
{
|
|
||||||
// keep cells within the new 3x3 grid
|
|
||||||
++active;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
++active;
|
|
||||||
++numUnload;
|
|
||||||
}
|
|
||||||
|
|
||||||
active = mActiveCells.begin();
|
active = mActiveCells.begin();
|
||||||
while (active!=mActiveCells.end())
|
while (active!=mActiveCells.end())
|
||||||
{
|
{
|
||||||
|
@ -408,7 +388,6 @@ namespace MWWorld
|
||||||
if(!loadcell)
|
if(!loadcell)
|
||||||
loadcell = *mCurrentCell != *cell;
|
loadcell = *mCurrentCell != *cell;
|
||||||
|
|
||||||
Nif::NIFFile::CacheLock lock;
|
|
||||||
MWBase::Environment::get().getWindowManager()->fadeScreenOut(0.5);
|
MWBase::Environment::get().getWindowManager()->fadeScreenOut(0.5);
|
||||||
|
|
||||||
Loading::Listener* loadingListener = MWBase::Environment::get().getWindowManager()->getLoadingScreen();
|
Loading::Listener* loadingListener = MWBase::Environment::get().getWindowManager()->getLoadingScreen();
|
||||||
|
@ -438,14 +417,6 @@ namespace MWWorld
|
||||||
// remove active
|
// remove active
|
||||||
CellStoreCollection::iterator active = mActiveCells.begin();
|
CellStoreCollection::iterator active = mActiveCells.begin();
|
||||||
|
|
||||||
// count number of cells to unload
|
|
||||||
int numUnload = 0;
|
|
||||||
while (active!=mActiveCells.end())
|
|
||||||
{
|
|
||||||
++active;
|
|
||||||
++numUnload;
|
|
||||||
}
|
|
||||||
|
|
||||||
// unload
|
// unload
|
||||||
int current = 0;
|
int current = 0;
|
||||||
active = mActiveCells.begin();
|
active = mActiveCells.begin();
|
||||||
|
|
|
@ -19,7 +19,11 @@ add_component_dir (bsa
|
||||||
)
|
)
|
||||||
|
|
||||||
add_component_dir (nif
|
add_component_dir (nif
|
||||||
controlled effect niftypes record controller extra node record_ptr data niffile property
|
controlled effect niftypes record controller extra node record_ptr data niffile property nifkey data node
|
||||||
|
)
|
||||||
|
|
||||||
|
add_component_dir (nifcache
|
||||||
|
nifcache
|
||||||
)
|
)
|
||||||
|
|
||||||
add_component_dir (nifogre
|
add_component_dir (nifogre
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
|
|
||||||
#include "lineparser.hpp"
|
#include "lineparser.hpp"
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
#include <components/misc/stringops.hpp>
|
#include <components/misc/stringops.hpp>
|
||||||
|
|
||||||
#include "scanner.hpp"
|
#include "scanner.hpp"
|
||||||
|
@ -120,7 +122,7 @@ namespace Compiler
|
||||||
|
|
||||||
if (mState==SetMemberVarState)
|
if (mState==SetMemberVarState)
|
||||||
{
|
{
|
||||||
mMemberName = name;
|
mMemberName = Misc::StringUtils::lowerCase (name);
|
||||||
std::pair<char, bool> type = getContext().getMemberType (mMemberName, mName);
|
std::pair<char, bool> type = getContext().getMemberType (mMemberName, mName);
|
||||||
|
|
||||||
if (type.first!=' ')
|
if (type.first!=' ')
|
||||||
|
@ -297,7 +299,12 @@ namespace Compiler
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
ErrorDowngrade errorDowngrade (getErrorHandler());
|
// workaround for broken positioncell instructions.
|
||||||
|
/// \todo add option to disable this
|
||||||
|
std::auto_ptr<ErrorDowngrade> errorDowngrade (0);
|
||||||
|
if (Misc::StringUtils::lowerCase (loc.mLiteral)=="positioncell")
|
||||||
|
errorDowngrade.reset (new ErrorDowngrade (getErrorHandler()));
|
||||||
|
|
||||||
std::vector<Interpreter::Type_Code> code;
|
std::vector<Interpreter::Type_Code> code;
|
||||||
optionals = mExprParser.parseArguments (argumentType, scanner, code);
|
optionals = mExprParser.parseArguments (argumentType, scanner, code);
|
||||||
mCode.insert (mCode.begin(), code.begin(), code.end());
|
mCode.insert (mCode.begin(), code.begin(), code.end());
|
||||||
|
|
|
@ -15,8 +15,6 @@ namespace Compiler
|
||||||
std::vector<std::string> mLongs;
|
std::vector<std::string> mLongs;
|
||||||
std::vector<std::string> mFloats;
|
std::vector<std::string> mFloats;
|
||||||
|
|
||||||
int searchIndex (char type, const std::string& name) const;
|
|
||||||
|
|
||||||
std::vector<std::string>& get (char type);
|
std::vector<std::string>& get (char type);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -27,9 +25,11 @@ namespace Compiler
|
||||||
int getIndex (const std::string& name) const;
|
int getIndex (const std::string& name) const;
|
||||||
///< return index for local variable \a name (-1: does not exist).
|
///< return index for local variable \a name (-1: does not exist).
|
||||||
|
|
||||||
|
bool search (char type, const std::string& name) const;
|
||||||
|
|
||||||
/// Return index for local variable \a name of type \a type (-1: variable does not
|
/// Return index for local variable \a name of type \a type (-1: variable does not
|
||||||
/// exit).
|
/// exit).
|
||||||
bool search (char type, const std::string& name) const;
|
int searchIndex (char type, const std::string& name) const;
|
||||||
|
|
||||||
const std::vector<std::string>& get (char type) const;
|
const std::vector<std::string>& get (char type) const;
|
||||||
|
|
||||||
|
|
|
@ -42,8 +42,13 @@ void MagicEffect::load(ESMReader &esm)
|
||||||
esm.getHNT(mIndex, "INDX");
|
esm.getHNT(mIndex, "INDX");
|
||||||
|
|
||||||
esm.getHNT(mData, "MEDT", 36);
|
esm.getHNT(mData, "MEDT", 36);
|
||||||
|
if (esm.getFormat() == 0)
|
||||||
|
{
|
||||||
|
// don't allow mods to change fixed flags in the legacy format
|
||||||
|
mData.mFlags &= (AllowSpellmaking | AllowEnchanting | NegativeLight);
|
||||||
if (mIndex>=0 && mIndex<NumberOfHardcodedFlags)
|
if (mIndex>=0 && mIndex<NumberOfHardcodedFlags)
|
||||||
mData.mFlags |= HardcodedFlags[mIndex];
|
mData.mFlags |= HardcodedFlags[mIndex];
|
||||||
|
}
|
||||||
|
|
||||||
mIcon = esm.getHNOString("ITEX");
|
mIcon = esm.getHNOString("ITEX");
|
||||||
mParticle = esm.getHNOString("PTEX");
|
mParticle = esm.getHNOString("PTEX");
|
||||||
|
|
|
@ -16,6 +16,7 @@ struct MagicEffect
|
||||||
|
|
||||||
enum Flags
|
enum Flags
|
||||||
{
|
{
|
||||||
|
// Originally fixed flags (HardcodedFlags array consists of just these)
|
||||||
TargetSkill = 0x1, // Affects a specific skill, which is specified elsewhere in the effect structure.
|
TargetSkill = 0x1, // Affects a specific skill, which is specified elsewhere in the effect structure.
|
||||||
TargetAttribute = 0x2, // Affects a specific attribute, which is specified elsewhere in the effect structure.
|
TargetAttribute = 0x2, // Affects a specific attribute, which is specified elsewhere in the effect structure.
|
||||||
NoDuration = 0x4, // Has no duration. Only runs effect once on cast.
|
NoDuration = 0x4, // Has no duration. Only runs effect once on cast.
|
||||||
|
@ -28,8 +29,14 @@ struct MagicEffect
|
||||||
UncappedDamage = 0x1000, // Negates multiple cap behaviours. Allows an effect to reduce an attribute below zero; removes the normal minimum effect duration of 1 second.
|
UncappedDamage = 0x1000, // Negates multiple cap behaviours. Allows an effect to reduce an attribute below zero; removes the normal minimum effect duration of 1 second.
|
||||||
NonRecastable = 0x4000, // Does not land if parent spell is already affecting target. Shows "you cannot re-cast" message for self target.
|
NonRecastable = 0x4000, // Does not land if parent spell is already affecting target. Shows "you cannot re-cast" message for self target.
|
||||||
Unreflectable = 0x10000, // Cannot be reflected, the effect always lands normally.
|
Unreflectable = 0x10000, // Cannot be reflected, the effect always lands normally.
|
||||||
CasterLinked = 0x20000 // Must quench if caster is dead, or not an NPC/creature. Not allowed in containter/door trap spells.
|
CasterLinked = 0x20000, // Must quench if caster is dead, or not an NPC/creature. Not allowed in containter/door trap spells.
|
||||||
|
|
||||||
|
// Originally modifiable flags
|
||||||
|
AllowSpellmaking = 0x200, // Can be used for spellmaking
|
||||||
|
AllowEnchanting = 0x400, // Can be used for enchanting
|
||||||
|
NegativeLight = 0x800 // Negative light source
|
||||||
};
|
};
|
||||||
|
|
||||||
enum MagnitudeDisplayType
|
enum MagnitudeDisplayType
|
||||||
{
|
{
|
||||||
MDT_None,
|
MDT_None,
|
||||||
|
@ -47,8 +54,10 @@ struct MagicEffect
|
||||||
int mFlags;
|
int mFlags;
|
||||||
// Glow color for enchanted items with this effect
|
// Glow color for enchanted items with this effect
|
||||||
int mRed, mGreen, mBlue;
|
int mRed, mGreen, mBlue;
|
||||||
// Properties of the fired magic 'ball'
|
|
||||||
float mSpeed, mSize, mSizeCap;
|
float mUnknown1;
|
||||||
|
float mSpeed; // Speed of fired projectile
|
||||||
|
float mUnknown2;
|
||||||
}; // 36 bytes
|
}; // 36 bytes
|
||||||
|
|
||||||
static const std::map<short,std::string> sNames;
|
static const std::map<short,std::string> sNames;
|
||||||
|
|
|
@ -27,6 +27,23 @@ namespace ESM
|
||||||
mSpells[id] = random;
|
mSpells[id] = random;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
while (esm.isNextSub("PERM"))
|
||||||
|
{
|
||||||
|
std::string spellId = esm.getHString();
|
||||||
|
|
||||||
|
std::vector<PermanentSpellEffectInfo> permEffectList;
|
||||||
|
while (esm.isNextSub("EFID"))
|
||||||
|
{
|
||||||
|
PermanentSpellEffectInfo info;
|
||||||
|
esm.getHT(info.mId);
|
||||||
|
esm.getHNT(info.mArg, "ARG_");
|
||||||
|
esm.getHNT(info.mMagnitude, "MAGN");
|
||||||
|
|
||||||
|
permEffectList.push_back(info);
|
||||||
|
}
|
||||||
|
mPermanentSpellEffects[spellId] = permEffectList;
|
||||||
|
}
|
||||||
|
|
||||||
while (esm.isNextSub("CORP"))
|
while (esm.isNextSub("CORP"))
|
||||||
{
|
{
|
||||||
std::string id = esm.getHString();
|
std::string id = esm.getHString();
|
||||||
|
@ -64,6 +81,19 @@ namespace ESM
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (std::map<std::string, std::vector<PermanentSpellEffectInfo> >::const_iterator it = mPermanentSpellEffects.begin(); it != mPermanentSpellEffects.end(); ++it)
|
||||||
|
{
|
||||||
|
esm.writeHNString("PERM", it->first);
|
||||||
|
|
||||||
|
const std::vector<PermanentSpellEffectInfo> & effects = it->second;
|
||||||
|
for (std::vector<PermanentSpellEffectInfo>::const_iterator effectIt = effects.begin(); effectIt != effects.end(); ++effectIt)
|
||||||
|
{
|
||||||
|
esm.writeHNT("EFID", effectIt->mId);
|
||||||
|
esm.writeHNT("ARG_", effectIt->mArg);
|
||||||
|
esm.writeHNT("MAGN", effectIt->mMagnitude);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (std::map<std::string, CorprusStats>::const_iterator it = mCorprusSpells.begin(); it != mCorprusSpells.end(); ++it)
|
for (std::map<std::string, CorprusStats>::const_iterator it = mCorprusSpells.begin(); it != mCorprusSpells.end(); ++it)
|
||||||
{
|
{
|
||||||
esm.writeHNString("CORP", it->first);
|
esm.writeHNString("CORP", it->first);
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#define OPENMW_ESM_SPELLSTATE_H
|
#define OPENMW_ESM_SPELLSTATE_H
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <vector>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "defs.hpp"
|
#include "defs.hpp"
|
||||||
|
@ -19,9 +20,18 @@ namespace ESM
|
||||||
TimeStamp mNextWorsening;
|
TimeStamp mNextWorsening;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct PermanentSpellEffectInfo
|
||||||
|
{
|
||||||
|
int mId;
|
||||||
|
int mArg;
|
||||||
|
float mMagnitude;
|
||||||
|
};
|
||||||
|
|
||||||
typedef std::map<std::string, std::map<const int, float> > TContainer;
|
typedef std::map<std::string, std::map<const int, float> > TContainer;
|
||||||
TContainer mSpells;
|
TContainer mSpells;
|
||||||
|
|
||||||
|
std::map<std::string, std::vector<PermanentSpellEffectInfo> > mPermanentSpellEffects;
|
||||||
|
|
||||||
std::map<std::string, CorprusStats> mCorprusSpells;
|
std::map<std::string, CorprusStats> mCorprusSpells;
|
||||||
|
|
||||||
std::map<std::string, TimeStamp> mUsedPowers;
|
std::map<std::string, TimeStamp> mUsedPowers;
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <boost/filesystem.hpp>
|
#include <boost/filesystem.hpp>
|
||||||
|
|
||||||
#if defined(__linux__) || defined(__FreeBSD__)
|
#if defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
|
||||||
#ifndef ANDROID
|
#ifndef ANDROID
|
||||||
#include <components/files/linuxpath.hpp>
|
#include <components/files/linuxpath.hpp>
|
||||||
namespace Files { typedef LinuxPath TargetPathType; }
|
namespace Files { typedef LinuxPath TargetPathType; }
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#include "linuxpath.hpp"
|
#include "linuxpath.hpp"
|
||||||
|
|
||||||
#if defined(__linux__) || defined(__FreeBSD__)
|
#if defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
|
||||||
|
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
@ -157,4 +157,4 @@ boost::filesystem::path LinuxPath::getInstallPath() const
|
||||||
|
|
||||||
} /* namespace Files */
|
} /* namespace Files */
|
||||||
|
|
||||||
#endif /* defined(__linux__) || defined(__FreeBSD__) */
|
#endif /* defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) */
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#ifndef COMPONENTS_FILES_LINUXPATH_H
|
#ifndef COMPONENTS_FILES_LINUXPATH_H
|
||||||
#define COMPONENTS_FILES_LINUXPATH_H
|
#define COMPONENTS_FILES_LINUXPATH_H
|
||||||
|
|
||||||
#if defined(__linux__) || defined(__FreeBSD__)
|
#if defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
|
||||||
|
|
||||||
#include <boost/filesystem.hpp>
|
#include <boost/filesystem.hpp>
|
||||||
|
|
||||||
|
@ -56,6 +56,6 @@ struct LinuxPath
|
||||||
|
|
||||||
} /* namespace Files */
|
} /* namespace Files */
|
||||||
|
|
||||||
#endif /* defined(__linux__) || defined(__FreeBSD__) */
|
#endif /* defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) */
|
||||||
|
|
||||||
#endif /* COMPONENTS_FILES_LINUXPATH_H */
|
#endif /* COMPONENTS_FILES_LINUXPATH_H */
|
||||||
|
|
29
components/nif/data.cpp
Normal file
29
components/nif/data.cpp
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
#include "data.hpp"
|
||||||
|
#include "node.hpp"
|
||||||
|
|
||||||
|
namespace Nif
|
||||||
|
{
|
||||||
|
void NiSkinInstance::post(NIFFile *nif)
|
||||||
|
{
|
||||||
|
data.post(nif);
|
||||||
|
root.post(nif);
|
||||||
|
bones.post(nif);
|
||||||
|
|
||||||
|
if(data.empty() || root.empty())
|
||||||
|
nif->fail("NiSkinInstance missing root or data");
|
||||||
|
|
||||||
|
size_t bnum = bones.length();
|
||||||
|
if(bnum != data->bones.size())
|
||||||
|
nif->fail("Mismatch in NiSkinData bone count");
|
||||||
|
|
||||||
|
root->makeRootBone(&data->trafo);
|
||||||
|
|
||||||
|
for(size_t i=0; i<bnum; i++)
|
||||||
|
{
|
||||||
|
if(bones[i].empty())
|
||||||
|
nif->fail("Oops: Missing bone! Don't know how to handle this.");
|
||||||
|
bones[i]->makeBone(i, data->bones[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // Namespace
|
|
@ -25,9 +25,8 @@
|
||||||
#define OPENMW_COMPONENTS_NIF_DATA_HPP
|
#define OPENMW_COMPONENTS_NIF_DATA_HPP
|
||||||
|
|
||||||
#include "controlled.hpp"
|
#include "controlled.hpp"
|
||||||
|
#include "nifstream.hpp"
|
||||||
#include <OgreQuaternion.h>
|
#include "nifkey.hpp"
|
||||||
#include <OgreVector3.h>
|
|
||||||
|
|
||||||
namespace Nif
|
namespace Nif
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,177 +1,15 @@
|
||||||
/*
|
|
||||||
OpenMW - The completely unofficial reimplementation of Morrowind
|
|
||||||
Copyright (C) 2008-2010 Nicolay Korslund
|
|
||||||
Email: < korslund@gmail.com >
|
|
||||||
WWW: http://openmw.sourceforge.net/
|
|
||||||
|
|
||||||
This file (nif_file.cpp) is part of the OpenMW package.
|
|
||||||
|
|
||||||
OpenMW is distributed as free software: you can redistribute it
|
|
||||||
and/or modify it under the terms of the GNU General Public License
|
|
||||||
version 3, as published by the Free Software Foundation.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful, but
|
|
||||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
version 3 along with this program. If not, see
|
|
||||||
http://www.gnu.org/licenses/ .
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "niffile.hpp"
|
#include "niffile.hpp"
|
||||||
#include "record.hpp"
|
|
||||||
#include "components/misc/stringops.hpp"
|
|
||||||
|
|
||||||
#include "extra.hpp"
|
|
||||||
#include "controlled.hpp"
|
|
||||||
#include "node.hpp"
|
|
||||||
#include "property.hpp"
|
|
||||||
#include "data.hpp"
|
|
||||||
#include "effect.hpp"
|
#include "effect.hpp"
|
||||||
#include "controller.hpp"
|
|
||||||
|
|
||||||
#include <iostream>
|
#include <map>
|
||||||
|
|
||||||
//TODO: when threading is needed, enable these
|
#include <OgreResourceGroupManager.h>
|
||||||
//#include <boost/mutex.hpp>
|
|
||||||
#include <boost/thread/locks.hpp>
|
|
||||||
|
|
||||||
namespace Nif
|
namespace Nif
|
||||||
{
|
{
|
||||||
|
|
||||||
class NIFFile::LoadedCache
|
|
||||||
{
|
|
||||||
//TODO: enable this to make cache thread safe...
|
|
||||||
//typedef boost::mutex mutex;
|
|
||||||
|
|
||||||
struct mutex
|
|
||||||
{
|
|
||||||
void lock () {};
|
|
||||||
void unlock () {}
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef boost::lock_guard <mutex> lock_guard;
|
|
||||||
typedef std::map < std::string, boost::weak_ptr <NIFFile> > loaded_map;
|
|
||||||
typedef std::vector < boost::shared_ptr <NIFFile> > locked_files;
|
|
||||||
|
|
||||||
static int sLockLevel;
|
|
||||||
static mutex sProtector;
|
|
||||||
static loaded_map sLoadedMap;
|
|
||||||
static locked_files sLockedFiles;
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
static ptr create (const std::string &name)
|
|
||||||
{
|
|
||||||
lock_guard _ (sProtector);
|
|
||||||
|
|
||||||
ptr result;
|
|
||||||
|
|
||||||
// lookup the resource
|
|
||||||
loaded_map::iterator i = sLoadedMap.find (name);
|
|
||||||
|
|
||||||
if (i == sLoadedMap.end ()) // it doesn't existing currently,
|
|
||||||
{ // or hasn't in the very near past
|
|
||||||
|
|
||||||
// create it now, for smoother threading if needed, the
|
|
||||||
// loading should be performed outside of the sLoaderMap
|
|
||||||
// lock and an alternate mechanism should be used to
|
|
||||||
// synchronize threads competing to load the same resource
|
|
||||||
result = boost::make_shared <NIFFile> (name, psudo_private_modifier());
|
|
||||||
|
|
||||||
// if we are locking the cache add an extra reference
|
|
||||||
// to keep the file in memory
|
|
||||||
if (sLockLevel > 0)
|
|
||||||
sLockedFiles.push_back (result);
|
|
||||||
|
|
||||||
// stash a reference to the resource so that future
|
|
||||||
// calls can benefit
|
|
||||||
sLoadedMap [name] = boost::weak_ptr <NIFFile> (result);
|
|
||||||
}
|
|
||||||
else // it may (probably) still exists
|
|
||||||
{
|
|
||||||
// attempt to get the reference
|
|
||||||
result = i->second.lock ();
|
|
||||||
|
|
||||||
if (!result) // resource is in the process of being destroyed
|
|
||||||
{
|
|
||||||
// create a new instance, to replace the one that has
|
|
||||||
// begun the irreversible process of being destroyed
|
|
||||||
result = boost::make_shared <NIFFile> (name, psudo_private_modifier());
|
|
||||||
|
|
||||||
// respect the cache lock...
|
|
||||||
if (sLockLevel > 0)
|
|
||||||
sLockedFiles.push_back (result);
|
|
||||||
|
|
||||||
// we potentially overwrite an expired pointer here
|
|
||||||
// but the other thread performing the delete on
|
|
||||||
// the previous copy of this resource will detect it
|
|
||||||
// and make sure not to erase the new reference
|
|
||||||
sLoadedMap [name] = boost::weak_ptr <NIFFile> (result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// we made it!
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void release (NIFFile * file)
|
|
||||||
{
|
|
||||||
lock_guard _ (sProtector);
|
|
||||||
|
|
||||||
loaded_map::iterator i = sLoadedMap.find (file->filename);
|
|
||||||
|
|
||||||
// its got to be in here, it just might not be us...
|
|
||||||
assert (i != sLoadedMap.end ());
|
|
||||||
|
|
||||||
// if weak_ptr is still expired, this resource hasn't been recreated
|
|
||||||
// between the initiation of the final release due to destruction
|
|
||||||
// of the last shared pointer and this thread acquiring the lock on
|
|
||||||
// the loader map
|
|
||||||
if (i->second.expired ())
|
|
||||||
sLoadedMap.erase (i);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void lockCache ()
|
|
||||||
{
|
|
||||||
lock_guard _ (sProtector);
|
|
||||||
|
|
||||||
sLockLevel++;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void unlockCache ()
|
|
||||||
{
|
|
||||||
locked_files resetList;
|
|
||||||
|
|
||||||
{
|
|
||||||
lock_guard _ (sProtector);
|
|
||||||
|
|
||||||
if (--sLockLevel)
|
|
||||||
sLockedFiles.swap(resetList);
|
|
||||||
}
|
|
||||||
|
|
||||||
// this not necessary, but makes it clear that the
|
|
||||||
// deletion of the locked cache entries is being done
|
|
||||||
// outside the protection of sProtector
|
|
||||||
resetList.clear ();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
int NIFFile::LoadedCache::sLockLevel = 0;
|
|
||||||
NIFFile::LoadedCache::mutex NIFFile::LoadedCache::sProtector;
|
|
||||||
NIFFile::LoadedCache::loaded_map NIFFile::LoadedCache::sLoadedMap;
|
|
||||||
NIFFile::LoadedCache::locked_files NIFFile::LoadedCache::sLockedFiles;
|
|
||||||
|
|
||||||
// these three calls are forwarded to the cache implementation...
|
|
||||||
void NIFFile::lockCache () { LoadedCache::lockCache (); }
|
|
||||||
void NIFFile::unlockCache () { LoadedCache::unlockCache (); }
|
|
||||||
NIFFile::ptr NIFFile::create (const std::string &name) { return LoadedCache::create (name); }
|
|
||||||
|
|
||||||
/// Open a NIF stream. The name is used for error messages.
|
/// Open a NIF stream. The name is used for error messages.
|
||||||
NIFFile::NIFFile(const std::string &name, psudo_private_modifier)
|
NIFFile::NIFFile(const std::string &name)
|
||||||
: ver(0)
|
: ver(0)
|
||||||
, filename(name)
|
, filename(name)
|
||||||
{
|
{
|
||||||
|
@ -180,10 +18,10 @@ NIFFile::NIFFile(const std::string &name, psudo_private_modifier)
|
||||||
|
|
||||||
NIFFile::~NIFFile()
|
NIFFile::~NIFFile()
|
||||||
{
|
{
|
||||||
LoadedCache::release (this);
|
for (std::vector<Record*>::iterator it = records.begin() ; it != records.end(); it++)
|
||||||
|
{
|
||||||
for(std::size_t i=0; i<records.size(); i++)
|
delete *it;
|
||||||
delete records[i];
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename NodeType> static Record* construct() { return new NodeType; }
|
template <typename NodeType> static Record* construct() { return new NodeType; }
|
||||||
|
@ -192,100 +30,84 @@ struct RecordFactoryEntry {
|
||||||
|
|
||||||
typedef Record* (*create_t) ();
|
typedef Record* (*create_t) ();
|
||||||
|
|
||||||
char const * mName;
|
|
||||||
create_t mCreate;
|
create_t mCreate;
|
||||||
RecordType mType;
|
RecordType mType;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* These are all the record types we know how to read.
|
///Helper function for adding records to the factory map
|
||||||
|
static std::pair<std::string,RecordFactoryEntry> makeEntry(std::string recName, Record* (*create_t) (), RecordType type)
|
||||||
This can be heavily optimized later if needed. For example, a
|
|
||||||
hash table or a FSM-based parser could be used to look up
|
|
||||||
node names.
|
|
||||||
*/
|
|
||||||
|
|
||||||
static const RecordFactoryEntry recordFactories [] = {
|
|
||||||
|
|
||||||
{ "NiNode", &construct <NiNode >, RC_NiNode },
|
|
||||||
{ "AvoidNode", &construct <NiNode >, RC_AvoidNode },
|
|
||||||
{ "NiBSParticleNode", &construct <NiNode >, RC_NiBSParticleNode },
|
|
||||||
{ "NiBSAnimationNode", &construct <NiNode >, RC_NiBSAnimationNode },
|
|
||||||
{ "NiBillboardNode", &construct <NiNode >, RC_NiBillboardNode },
|
|
||||||
{ "NiTriShape", &construct <NiTriShape >, RC_NiTriShape },
|
|
||||||
{ "NiRotatingParticles", &construct <NiRotatingParticles >, RC_NiRotatingParticles },
|
|
||||||
{ "NiAutoNormalParticles", &construct <NiAutoNormalParticles >, RC_NiAutoNormalParticles },
|
|
||||||
{ "NiCamera", &construct <NiCamera >, RC_NiCamera },
|
|
||||||
{ "RootCollisionNode", &construct <NiNode >, RC_RootCollisionNode },
|
|
||||||
{ "NiTexturingProperty", &construct <NiTexturingProperty >, RC_NiTexturingProperty },
|
|
||||||
{ "NiMaterialProperty", &construct <NiMaterialProperty >, RC_NiMaterialProperty },
|
|
||||||
{ "NiZBufferProperty", &construct <NiZBufferProperty >, RC_NiZBufferProperty },
|
|
||||||
{ "NiAlphaProperty", &construct <NiAlphaProperty >, RC_NiAlphaProperty },
|
|
||||||
{ "NiVertexColorProperty", &construct <NiVertexColorProperty >, RC_NiVertexColorProperty },
|
|
||||||
{ "NiShadeProperty", &construct <NiShadeProperty >, RC_NiShadeProperty },
|
|
||||||
{ "NiDitherProperty", &construct <NiDitherProperty >, RC_NiDitherProperty },
|
|
||||||
{ "NiWireframeProperty", &construct <NiWireframeProperty >, RC_NiWireframeProperty },
|
|
||||||
{ "NiSpecularProperty", &construct <NiSpecularProperty >, RC_NiSpecularProperty },
|
|
||||||
{ "NiStencilProperty", &construct <NiStencilProperty >, RC_NiStencilProperty },
|
|
||||||
{ "NiVisController", &construct <NiVisController >, RC_NiVisController },
|
|
||||||
{ "NiGeomMorpherController", &construct <NiGeomMorpherController >, RC_NiGeomMorpherController },
|
|
||||||
{ "NiKeyframeController", &construct <NiKeyframeController >, RC_NiKeyframeController },
|
|
||||||
{ "NiAlphaController", &construct <NiAlphaController >, RC_NiAlphaController },
|
|
||||||
{ "NiUVController", &construct <NiUVController >, RC_NiUVController },
|
|
||||||
{ "NiPathController", &construct <NiPathController >, RC_NiPathController },
|
|
||||||
{ "NiMaterialColorController", &construct <NiMaterialColorController >, RC_NiMaterialColorController },
|
|
||||||
{ "NiBSPArrayController", &construct <NiBSPArrayController >, RC_NiBSPArrayController },
|
|
||||||
{ "NiParticleSystemController", &construct <NiParticleSystemController >, RC_NiParticleSystemController },
|
|
||||||
{ "NiFlipController", &construct <NiFlipController >, RC_NiFlipController },
|
|
||||||
{ "NiAmbientLight", &construct <NiLight >, RC_NiLight },
|
|
||||||
{ "NiDirectionalLight", &construct <NiLight >, RC_NiLight },
|
|
||||||
{ "NiTextureEffect", &construct <NiTextureEffect >, RC_NiTextureEffect },
|
|
||||||
{ "NiVertWeightsExtraData", &construct <NiVertWeightsExtraData >, RC_NiVertWeightsExtraData },
|
|
||||||
{ "NiTextKeyExtraData", &construct <NiTextKeyExtraData >, RC_NiTextKeyExtraData },
|
|
||||||
{ "NiStringExtraData", &construct <NiStringExtraData >, RC_NiStringExtraData },
|
|
||||||
{ "NiGravity", &construct <NiGravity >, RC_NiGravity },
|
|
||||||
{ "NiPlanarCollider", &construct <NiPlanarCollider >, RC_NiPlanarCollider },
|
|
||||||
{ "NiParticleGrowFade", &construct <NiParticleGrowFade >, RC_NiParticleGrowFade },
|
|
||||||
{ "NiParticleColorModifier", &construct <NiParticleColorModifier >, RC_NiParticleColorModifier },
|
|
||||||
{ "NiParticleRotation", &construct <NiParticleRotation >, RC_NiParticleRotation },
|
|
||||||
{ "NiFloatData", &construct <NiFloatData >, RC_NiFloatData },
|
|
||||||
{ "NiTriShapeData", &construct <NiTriShapeData >, RC_NiTriShapeData },
|
|
||||||
{ "NiVisData", &construct <NiVisData >, RC_NiVisData },
|
|
||||||
{ "NiColorData", &construct <NiColorData >, RC_NiColorData },
|
|
||||||
{ "NiPixelData", &construct <NiPixelData >, RC_NiPixelData },
|
|
||||||
{ "NiMorphData", &construct <NiMorphData >, RC_NiMorphData },
|
|
||||||
{ "NiKeyframeData", &construct <NiKeyframeData >, RC_NiKeyframeData },
|
|
||||||
{ "NiSkinData", &construct <NiSkinData >, RC_NiSkinData },
|
|
||||||
{ "NiUVData", &construct <NiUVData >, RC_NiUVData },
|
|
||||||
{ "NiPosData", &construct <NiPosData >, RC_NiPosData },
|
|
||||||
{ "NiRotatingParticlesData", &construct <NiRotatingParticlesData >, RC_NiRotatingParticlesData },
|
|
||||||
{ "NiAutoNormalParticlesData", &construct <NiAutoNormalParticlesData >, RC_NiAutoNormalParticlesData },
|
|
||||||
{ "NiSequenceStreamHelper", &construct <NiSequenceStreamHelper >, RC_NiSequenceStreamHelper },
|
|
||||||
{ "NiSourceTexture", &construct <NiSourceTexture >, RC_NiSourceTexture },
|
|
||||||
{ "NiSkinInstance", &construct <NiSkinInstance >, RC_NiSkinInstance },
|
|
||||||
};
|
|
||||||
|
|
||||||
static RecordFactoryEntry const * recordFactories_begin = &recordFactories [0];
|
|
||||||
static RecordFactoryEntry const * recordFactories_end = &recordFactories [sizeof (recordFactories) / sizeof (recordFactories[0])];
|
|
||||||
|
|
||||||
RecordFactoryEntry const * lookupRecordFactory (char const * name)
|
|
||||||
{
|
{
|
||||||
RecordFactoryEntry const * i;
|
RecordFactoryEntry anEntry = {create_t,type};
|
||||||
|
return std::make_pair<std::string,RecordFactoryEntry>(recName, anEntry);
|
||||||
for (i = recordFactories_begin; i != recordFactories_end; ++i)
|
|
||||||
if (strcmp (name, i->mName) == 0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (i == recordFactories_end)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
return i;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This file implements functions from the NIFFile class. It is also
|
///These are all the record types we know how to read.
|
||||||
where we stash all the functions we couldn't add as inline
|
static std::map<std::string,RecordFactoryEntry> makeFactory()
|
||||||
definitions in the record types.
|
{
|
||||||
*/
|
std::map<std::string,RecordFactoryEntry> newFactory;
|
||||||
|
newFactory.insert(makeEntry("NiNode", &construct <NiNode> , RC_NiNode ));
|
||||||
|
newFactory.insert(makeEntry("AvoidNode", &construct <NiNode> , RC_AvoidNode ));
|
||||||
|
newFactory.insert(makeEntry("NiBSParticleNode", &construct <NiNode> , RC_NiBSParticleNode ));
|
||||||
|
newFactory.insert(makeEntry("NiBSAnimationNode", &construct <NiNode> , RC_NiBSAnimationNode ));
|
||||||
|
newFactory.insert(makeEntry("NiBillboardNode", &construct <NiNode> , RC_NiBillboardNode ));
|
||||||
|
newFactory.insert(makeEntry("NiTriShape", &construct <NiTriShape> , RC_NiTriShape ));
|
||||||
|
newFactory.insert(makeEntry("NiRotatingParticles", &construct <NiRotatingParticles> , RC_NiRotatingParticles ));
|
||||||
|
newFactory.insert(makeEntry("NiAutoNormalParticles", &construct <NiAutoNormalParticles> , RC_NiAutoNormalParticles ));
|
||||||
|
newFactory.insert(makeEntry("NiCamera", &construct <NiCamera> , RC_NiCamera ));
|
||||||
|
newFactory.insert(makeEntry("RootCollisionNode", &construct <NiNode> , RC_RootCollisionNode ));
|
||||||
|
newFactory.insert(makeEntry("NiTexturingProperty", &construct <NiTexturingProperty> , RC_NiTexturingProperty ));
|
||||||
|
newFactory.insert(makeEntry("NiMaterialProperty", &construct <NiMaterialProperty> , RC_NiMaterialProperty ));
|
||||||
|
newFactory.insert(makeEntry("NiZBufferProperty", &construct <NiZBufferProperty> , RC_NiZBufferProperty ));
|
||||||
|
newFactory.insert(makeEntry("NiAlphaProperty", &construct <NiAlphaProperty> , RC_NiAlphaProperty ));
|
||||||
|
newFactory.insert(makeEntry("NiVertexColorProperty", &construct <NiVertexColorProperty> , RC_NiVertexColorProperty ));
|
||||||
|
newFactory.insert(makeEntry("NiShadeProperty", &construct <NiShadeProperty> , RC_NiShadeProperty ));
|
||||||
|
newFactory.insert(makeEntry("NiDitherProperty", &construct <NiDitherProperty> , RC_NiDitherProperty ));
|
||||||
|
newFactory.insert(makeEntry("NiWireframeProperty", &construct <NiWireframeProperty> , RC_NiWireframeProperty ));
|
||||||
|
newFactory.insert(makeEntry("NiSpecularProperty", &construct <NiSpecularProperty> , RC_NiSpecularProperty ));
|
||||||
|
newFactory.insert(makeEntry("NiStencilProperty", &construct <NiStencilProperty> , RC_NiStencilProperty ));
|
||||||
|
newFactory.insert(makeEntry("NiVisController", &construct <NiVisController> , RC_NiVisController ));
|
||||||
|
newFactory.insert(makeEntry("NiGeomMorpherController", &construct <NiGeomMorpherController> , RC_NiGeomMorpherController ));
|
||||||
|
newFactory.insert(makeEntry("NiKeyframeController", &construct <NiKeyframeController> , RC_NiKeyframeController ));
|
||||||
|
newFactory.insert(makeEntry("NiAlphaController", &construct <NiAlphaController> , RC_NiAlphaController ));
|
||||||
|
newFactory.insert(makeEntry("NiUVController", &construct <NiUVController> , RC_NiUVController ));
|
||||||
|
newFactory.insert(makeEntry("NiPathController", &construct <NiPathController> , RC_NiPathController ));
|
||||||
|
newFactory.insert(makeEntry("NiMaterialColorController", &construct <NiMaterialColorController> , RC_NiMaterialColorController ));
|
||||||
|
newFactory.insert(makeEntry("NiBSPArrayController", &construct <NiBSPArrayController> , RC_NiBSPArrayController ));
|
||||||
|
newFactory.insert(makeEntry("NiParticleSystemController", &construct <NiParticleSystemController> , RC_NiParticleSystemController ));
|
||||||
|
newFactory.insert(makeEntry("NiFlipController", &construct <NiFlipController> , RC_NiFlipController ));
|
||||||
|
newFactory.insert(makeEntry("NiAmbientLight", &construct <NiLight> , RC_NiLight ));
|
||||||
|
newFactory.insert(makeEntry("NiDirectionalLight", &construct <NiLight> , RC_NiLight ));
|
||||||
|
newFactory.insert(makeEntry("NiTextureEffect", &construct <NiTextureEffect> , RC_NiTextureEffect ));
|
||||||
|
newFactory.insert(makeEntry("NiVertWeightsExtraData", &construct <NiVertWeightsExtraData> , RC_NiVertWeightsExtraData ));
|
||||||
|
newFactory.insert(makeEntry("NiTextKeyExtraData", &construct <NiTextKeyExtraData> , RC_NiTextKeyExtraData ));
|
||||||
|
newFactory.insert(makeEntry("NiStringExtraData", &construct <NiStringExtraData> , RC_NiStringExtraData ));
|
||||||
|
newFactory.insert(makeEntry("NiGravity", &construct <NiGravity> , RC_NiGravity ));
|
||||||
|
newFactory.insert(makeEntry("NiPlanarCollider", &construct <NiPlanarCollider> , RC_NiPlanarCollider ));
|
||||||
|
newFactory.insert(makeEntry("NiParticleGrowFade", &construct <NiParticleGrowFade> , RC_NiParticleGrowFade ));
|
||||||
|
newFactory.insert(makeEntry("NiParticleColorModifier", &construct <NiParticleColorModifier> , RC_NiParticleColorModifier ));
|
||||||
|
newFactory.insert(makeEntry("NiParticleRotation", &construct <NiParticleRotation> , RC_NiParticleRotation ));
|
||||||
|
newFactory.insert(makeEntry("NiFloatData", &construct <NiFloatData> , RC_NiFloatData ));
|
||||||
|
newFactory.insert(makeEntry("NiTriShapeData", &construct <NiTriShapeData> , RC_NiTriShapeData ));
|
||||||
|
newFactory.insert(makeEntry("NiVisData", &construct <NiVisData> , RC_NiVisData ));
|
||||||
|
newFactory.insert(makeEntry("NiColorData", &construct <NiColorData> , RC_NiColorData ));
|
||||||
|
newFactory.insert(makeEntry("NiPixelData", &construct <NiPixelData> , RC_NiPixelData ));
|
||||||
|
newFactory.insert(makeEntry("NiMorphData", &construct <NiMorphData> , RC_NiMorphData ));
|
||||||
|
newFactory.insert(makeEntry("NiKeyframeData", &construct <NiKeyframeData> , RC_NiKeyframeData ));
|
||||||
|
newFactory.insert(makeEntry("NiSkinData", &construct <NiSkinData> , RC_NiSkinData ));
|
||||||
|
newFactory.insert(makeEntry("NiUVData", &construct <NiUVData> , RC_NiUVData ));
|
||||||
|
newFactory.insert(makeEntry("NiPosData", &construct <NiPosData> , RC_NiPosData ));
|
||||||
|
newFactory.insert(makeEntry("NiRotatingParticlesData", &construct <NiRotatingParticlesData> , RC_NiRotatingParticlesData ));
|
||||||
|
newFactory.insert(makeEntry("NiAutoNormalParticlesData", &construct <NiAutoNormalParticlesData> , RC_NiAutoNormalParticlesData ));
|
||||||
|
newFactory.insert(makeEntry("NiSequenceStreamHelper", &construct <NiSequenceStreamHelper> , RC_NiSequenceStreamHelper ));
|
||||||
|
newFactory.insert(makeEntry("NiSourceTexture", &construct <NiSourceTexture> , RC_NiSourceTexture ));
|
||||||
|
newFactory.insert(makeEntry("NiSkinInstance", &construct <NiSkinInstance> , RC_NiSkinInstance ));
|
||||||
|
return newFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///Make the factory map used for parsing the file
|
||||||
|
static const std::map<std::string,RecordFactoryEntry> factories = makeFactory();
|
||||||
|
|
||||||
void NIFFile::parse()
|
void NIFFile::parse()
|
||||||
{
|
{
|
||||||
|
@ -322,12 +144,13 @@ void NIFFile::parse()
|
||||||
if(rec.empty())
|
if(rec.empty())
|
||||||
fail("Record number " + Ogre::StringConverter::toString(i) + " out of " + Ogre::StringConverter::toString(recNum) + " is blank.");
|
fail("Record number " + Ogre::StringConverter::toString(i) + " out of " + Ogre::StringConverter::toString(recNum) + " is blank.");
|
||||||
|
|
||||||
RecordFactoryEntry const * entry = lookupRecordFactory (rec.c_str ());
|
|
||||||
|
|
||||||
if (entry != NULL)
|
std::map<std::string,RecordFactoryEntry>::const_iterator entry = factories.find(rec);
|
||||||
|
|
||||||
|
if (entry != factories.end())
|
||||||
{
|
{
|
||||||
r = entry->mCreate ();
|
r = entry->second.mCreate ();
|
||||||
r->recType = entry->mType;
|
r->recType = entry->second.mType;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
fail("Unknown record type " + rec);
|
fail("Unknown record type " + rec);
|
||||||
|
@ -338,24 +161,24 @@ void NIFFile::parse()
|
||||||
r->recIndex = i;
|
r->recIndex = i;
|
||||||
records[i] = r;
|
records[i] = r;
|
||||||
r->read(&nif);
|
r->read(&nif);
|
||||||
|
|
||||||
// Discard tranformations for the root node, otherwise some meshes
|
|
||||||
// occasionally get wrong orientation. Only for NiNode-s for now, but
|
|
||||||
// can be expanded if needed.
|
|
||||||
// This should be rewritten when the method is cleaned up.
|
|
||||||
if (0 == i && rec == "NiNode")
|
|
||||||
{
|
|
||||||
static_cast<Nif::Node*>(r)->trafo = Nif::Transformation::getIdentity();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t rootNum = nif.getUInt();
|
size_t rootNum = nif.getUInt();
|
||||||
roots.resize(rootNum);
|
roots.resize(rootNum);
|
||||||
|
|
||||||
|
//Determine which records are roots
|
||||||
for(size_t i = 0;i < rootNum;i++)
|
for(size_t i = 0;i < rootNum;i++)
|
||||||
{
|
{
|
||||||
intptr_t idx = nif.getInt();
|
int idx = nif.getInt();
|
||||||
roots[i] = ((idx >= 0) ? records.at(idx) : NULL);
|
if (idx >= 0)
|
||||||
|
{
|
||||||
|
roots[i] = records.at(idx);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
roots[i] = NULL;
|
||||||
|
warn("Null Root found");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Once parsing is done, do post-processing.
|
// Once parsing is done, do post-processing.
|
||||||
|
@ -363,81 +186,4 @@ void NIFFile::parse()
|
||||||
records[i]->post(this);
|
records[i]->post(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \todo move to the write cpp file
|
|
||||||
|
|
||||||
void NiSkinInstance::post(NIFFile *nif)
|
|
||||||
{
|
|
||||||
data.post(nif);
|
|
||||||
root.post(nif);
|
|
||||||
bones.post(nif);
|
|
||||||
|
|
||||||
if(data.empty() || root.empty())
|
|
||||||
nif->fail("NiSkinInstance missing root or data");
|
|
||||||
|
|
||||||
size_t bnum = bones.length();
|
|
||||||
if(bnum != data->bones.size())
|
|
||||||
nif->fail("Mismatch in NiSkinData bone count");
|
|
||||||
|
|
||||||
root->makeRootBone(&data->trafo);
|
|
||||||
|
|
||||||
for(size_t i=0; i<bnum; i++)
|
|
||||||
{
|
|
||||||
if(bones[i].empty())
|
|
||||||
nif->fail("Oops: Missing bone! Don't know how to handle this.");
|
|
||||||
bones[i]->makeBone(i, data->bones[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Node::getProperties(const Nif::NiTexturingProperty *&texprop,
|
|
||||||
const Nif::NiMaterialProperty *&matprop,
|
|
||||||
const Nif::NiAlphaProperty *&alphaprop,
|
|
||||||
const Nif::NiVertexColorProperty *&vertprop,
|
|
||||||
const Nif::NiZBufferProperty *&zprop,
|
|
||||||
const Nif::NiSpecularProperty *&specprop,
|
|
||||||
const Nif::NiWireframeProperty *&wireprop) const
|
|
||||||
{
|
|
||||||
if(parent)
|
|
||||||
parent->getProperties(texprop, matprop, alphaprop, vertprop, zprop, specprop, wireprop);
|
|
||||||
|
|
||||||
for(size_t i = 0;i < props.length();i++)
|
|
||||||
{
|
|
||||||
// Entries may be empty
|
|
||||||
if(props[i].empty())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
const Nif::Property *pr = props[i].getPtr();
|
|
||||||
if(pr->recType == Nif::RC_NiTexturingProperty)
|
|
||||||
texprop = static_cast<const Nif::NiTexturingProperty*>(pr);
|
|
||||||
else if(pr->recType == Nif::RC_NiMaterialProperty)
|
|
||||||
matprop = static_cast<const Nif::NiMaterialProperty*>(pr);
|
|
||||||
else if(pr->recType == Nif::RC_NiAlphaProperty)
|
|
||||||
alphaprop = static_cast<const Nif::NiAlphaProperty*>(pr);
|
|
||||||
else if(pr->recType == Nif::RC_NiVertexColorProperty)
|
|
||||||
vertprop = static_cast<const Nif::NiVertexColorProperty*>(pr);
|
|
||||||
else if(pr->recType == Nif::RC_NiZBufferProperty)
|
|
||||||
zprop = static_cast<const Nif::NiZBufferProperty*>(pr);
|
|
||||||
else if(pr->recType == Nif::RC_NiSpecularProperty)
|
|
||||||
specprop = static_cast<const Nif::NiSpecularProperty*>(pr);
|
|
||||||
else if(pr->recType == Nif::RC_NiWireframeProperty)
|
|
||||||
wireprop = static_cast<const Nif::NiWireframeProperty*>(pr);
|
|
||||||
else
|
|
||||||
std::cerr<< "Unhandled property type: "<<pr->recName <<std::endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ogre::Matrix4 Node::getLocalTransform() const
|
|
||||||
{
|
|
||||||
Ogre::Matrix4 mat4 = Ogre::Matrix4(Ogre::Matrix4::IDENTITY);
|
|
||||||
mat4.makeTransform(trafo.pos, Ogre::Vector3(trafo.scale), Ogre::Quaternion(trafo.rotation));
|
|
||||||
return mat4;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ogre::Matrix4 Node::getWorldTransform() const
|
|
||||||
{
|
|
||||||
if(parent != NULL)
|
|
||||||
return parent->getWorldTransform() * getLocalTransform();
|
|
||||||
return getLocalTransform();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,53 +1,13 @@
|
||||||
/*
|
///Main header for reading .nif files
|
||||||
OpenMW - The completely unofficial reimplementation of Morrowind
|
|
||||||
Copyright (C) 2008-2010 Nicolay Korslund
|
|
||||||
Email: < korslund@gmail.com >
|
|
||||||
WWW: http://openmw.sourceforge.net/
|
|
||||||
|
|
||||||
This file (nif_file.h) is part of the OpenMW package.
|
|
||||||
|
|
||||||
OpenMW is distributed as free software: you can redistribute it
|
|
||||||
and/or modify it under the terms of the GNU General Public License
|
|
||||||
version 3, as published by the Free Software Foundation.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful, but
|
|
||||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
version 3 along with this program. If not, see
|
|
||||||
http://www.gnu.org/licenses/ .
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef OPENMW_COMPONENTS_NIF_NIFFILE_HPP
|
#ifndef OPENMW_COMPONENTS_NIF_NIFFILE_HPP
|
||||||
#define OPENMW_COMPONENTS_NIF_NIFFILE_HPP
|
#define OPENMW_COMPONENTS_NIF_NIFFILE_HPP
|
||||||
|
|
||||||
#include <OgreResourceGroupManager.h>
|
|
||||||
#include <OgreDataStream.h>
|
|
||||||
#include <OgreVector2.h>
|
|
||||||
#include <OgreVector3.h>
|
|
||||||
#include <OgreVector4.h>
|
|
||||||
#include <OgreMatrix3.h>
|
|
||||||
#include <OgreQuaternion.h>
|
|
||||||
#include <OgreStringConverter.h>
|
|
||||||
|
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <cassert>
|
#include <iostream>
|
||||||
#include <typeinfo>
|
|
||||||
|
|
||||||
#include <boost/weak_ptr.hpp>
|
|
||||||
#include <boost/shared_ptr.hpp>
|
|
||||||
#include <boost/make_shared.hpp>
|
|
||||||
#include <boost/detail/endian.hpp>
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
#include "record.hpp"
|
#include "record.hpp"
|
||||||
#include "niftypes.hpp"
|
|
||||||
#include "nifstream.hpp"
|
|
||||||
|
|
||||||
namespace Nif
|
namespace Nif
|
||||||
{
|
{
|
||||||
|
@ -61,62 +21,46 @@ class NIFFile
|
||||||
/// Nif file version
|
/// Nif file version
|
||||||
int ver;
|
int ver;
|
||||||
|
|
||||||
/// File name, used for error messages
|
/// File name, used for error messages and opening the file
|
||||||
std::string filename;
|
std::string filename;
|
||||||
|
|
||||||
/// Record list
|
/// Record list
|
||||||
std::vector<Record*> records;
|
std::vector<Record*> records;
|
||||||
|
|
||||||
/// Root list
|
/// Root list. This is a select portion of the pointers from records
|
||||||
std::vector<Record*> roots;
|
std::vector<Record*> roots;
|
||||||
|
|
||||||
/// Parse the file
|
/// Parse the file
|
||||||
void parse();
|
void parse();
|
||||||
|
|
||||||
class LoadedCache;
|
///Private Copy Constructor
|
||||||
friend class LoadedCache;
|
|
||||||
|
|
||||||
// attempt to protect NIFFile from misuse...
|
|
||||||
struct psudo_private_modifier {}; // this dirty little trick should optimize out
|
|
||||||
NIFFile (NIFFile const &);
|
NIFFile (NIFFile const &);
|
||||||
|
///\overload
|
||||||
void operator = (NIFFile const &);
|
void operator = (NIFFile const &);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/// Used for error handling
|
/// Used if file parsing fails
|
||||||
void fail(const std::string &msg)
|
void fail(const std::string &msg)
|
||||||
{
|
{
|
||||||
std::string err = "NIFFile Error: " + msg;
|
std::string err = "NIFFile Error: " + msg;
|
||||||
err += "\nFile: " + filename;
|
err += "\nFile: " + filename;
|
||||||
throw std::runtime_error(err);
|
throw std::runtime_error(err);
|
||||||
}
|
}
|
||||||
|
/// Used when something goes wrong, but not catastrophically so
|
||||||
void warn(const std::string &msg)
|
void warn(const std::string &msg)
|
||||||
{
|
{
|
||||||
std::cerr << "NIFFile Warning: " << msg <<std::endl
|
std::cerr << "NIFFile Warning: " << msg <<std::endl
|
||||||
<< "File: " << filename <<std::endl;
|
<< "File: " << filename <<std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef boost::shared_ptr <NIFFile> ptr;
|
/// Open a NIF stream. The name is used for error messages and opening the file.
|
||||||
|
NIFFile(const std::string &name);
|
||||||
/// Open a NIF stream. The name is used for error messages.
|
|
||||||
NIFFile(const std::string &name, psudo_private_modifier);
|
|
||||||
~NIFFile();
|
~NIFFile();
|
||||||
|
|
||||||
static ptr create (const std::string &name);
|
|
||||||
static void lockCache ();
|
|
||||||
static void unlockCache ();
|
|
||||||
|
|
||||||
struct CacheLock
|
|
||||||
{
|
|
||||||
CacheLock () { lockCache (); }
|
|
||||||
~CacheLock () { unlockCache (); }
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Get a given record
|
/// Get a given record
|
||||||
Record *getRecord(size_t index) const
|
Record *getRecord(size_t index) const
|
||||||
{
|
{
|
||||||
Record *res = records.at(index);
|
Record *res = records.at(index);
|
||||||
assert(res != NULL);
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
/// Number of records
|
/// Number of records
|
||||||
|
@ -126,7 +70,6 @@ public:
|
||||||
Record *getRoot(size_t index=0) const
|
Record *getRoot(size_t index=0) const
|
||||||
{
|
{
|
||||||
Record *res = roots.at(index);
|
Record *res = roots.at(index);
|
||||||
assert(res != NULL);
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
/// Number of roots
|
/// Number of roots
|
||||||
|
@ -134,131 +77,6 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
struct KeyT {
|
|
||||||
float mTime;
|
|
||||||
T mValue;
|
|
||||||
T mForwardValue; // Only for Quadratic interpolation, and never for QuaternionKeyList
|
|
||||||
T mBackwardValue; // Only for Quadratic interpolation, and never for QuaternionKeyList
|
|
||||||
float mTension; // Only for TBC interpolation
|
|
||||||
float mBias; // Only for TBC interpolation
|
|
||||||
float mContinuity; // Only for TBC interpolation
|
|
||||||
};
|
|
||||||
typedef KeyT<float> FloatKey;
|
|
||||||
typedef KeyT<Ogre::Vector3> Vector3Key;
|
|
||||||
typedef KeyT<Ogre::Vector4> Vector4Key;
|
|
||||||
typedef KeyT<Ogre::Quaternion> QuaternionKey;
|
|
||||||
|
|
||||||
template<typename T, T (NIFStream::*getValue)()>
|
|
||||||
struct KeyListT {
|
|
||||||
typedef std::vector< KeyT<T> > VecType;
|
|
||||||
|
|
||||||
static const unsigned int sLinearInterpolation = 1;
|
|
||||||
static const unsigned int sQuadraticInterpolation = 2;
|
|
||||||
static const unsigned int sTBCInterpolation = 3;
|
|
||||||
static const unsigned int sXYZInterpolation = 4;
|
|
||||||
|
|
||||||
unsigned int mInterpolationType;
|
|
||||||
VecType mKeys;
|
|
||||||
|
|
||||||
KeyListT() : mInterpolationType(sLinearInterpolation) {}
|
|
||||||
|
|
||||||
//Read in a KeyGroup (see http://niftools.sourceforge.net/doc/nif/NiKeyframeData.html)
|
|
||||||
void read(NIFStream *nif, bool force=false)
|
|
||||||
{
|
|
||||||
assert(nif);
|
|
||||||
|
|
||||||
mInterpolationType = 0;
|
|
||||||
|
|
||||||
size_t count = nif->getUInt();
|
|
||||||
if(count == 0 && !force)
|
|
||||||
return;
|
|
||||||
|
|
||||||
//If we aren't forcing things, make sure that read clears any previous keys
|
|
||||||
if(!force)
|
|
||||||
mKeys.clear();
|
|
||||||
|
|
||||||
mInterpolationType = nif->getUInt();
|
|
||||||
|
|
||||||
KeyT<T> key;
|
|
||||||
NIFStream &nifReference = *nif;
|
|
||||||
|
|
||||||
if(mInterpolationType == sLinearInterpolation)
|
|
||||||
{
|
|
||||||
for(size_t i = 0;i < count;i++)
|
|
||||||
{
|
|
||||||
readTimeAndValue(nifReference, key);
|
|
||||||
mKeys.push_back(key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if(mInterpolationType == sQuadraticInterpolation)
|
|
||||||
{
|
|
||||||
for(size_t i = 0;i < count;i++)
|
|
||||||
{
|
|
||||||
readQuadratic(nifReference, key);
|
|
||||||
mKeys.push_back(key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if(mInterpolationType == sTBCInterpolation)
|
|
||||||
{
|
|
||||||
for(size_t i = 0;i < count;i++)
|
|
||||||
{
|
|
||||||
readTBC(nifReference, key);
|
|
||||||
mKeys.push_back(key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//XYZ keys aren't actually read here.
|
|
||||||
//data.hpp sees that the last type read was sXYZInterpolation and:
|
|
||||||
// Eats a floating point number, then
|
|
||||||
// Re-runs the read function 3 more times, with force enabled so that the previous values aren't cleared.
|
|
||||||
// When it does that it's reading in a bunch of sLinearInterpolation keys, not sXYZInterpolation.
|
|
||||||
else if(mInterpolationType == sXYZInterpolation)
|
|
||||||
{
|
|
||||||
//Don't try to read XYZ keys into the wrong part
|
|
||||||
if ( count != 1 )
|
|
||||||
nif->file->fail("XYZ_ROTATION_KEY count should always be '1' . Retrieved Value: "+Ogre::StringConverter::toString(count));
|
|
||||||
}
|
|
||||||
else if (0 == mInterpolationType)
|
|
||||||
{
|
|
||||||
if (count != 0)
|
|
||||||
nif->file->fail("Interpolation type 0 doesn't work with keys");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
nif->file->fail("Unhandled interpolation type: "+Ogre::StringConverter::toString(mInterpolationType));
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
static void readTimeAndValue(NIFStream &nif, KeyT<T> &key)
|
|
||||||
{
|
|
||||||
key.mTime = nif.getFloat();
|
|
||||||
key.mValue = (nif.*getValue)();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void readQuadratic(NIFStream &nif, KeyT<Ogre::Quaternion> &key)
|
|
||||||
{
|
|
||||||
readTimeAndValue(nif, key);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename U>
|
|
||||||
static void readQuadratic(NIFStream &nif, KeyT<U> &key)
|
|
||||||
{
|
|
||||||
readTimeAndValue(nif, key);
|
|
||||||
key.mForwardValue = (nif.*getValue)();
|
|
||||||
key.mBackwardValue = (nif.*getValue)();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void readTBC(NIFStream &nif, KeyT<T> &key)
|
|
||||||
{
|
|
||||||
readTimeAndValue(nif, key);
|
|
||||||
key.mTension = nif.getFloat();
|
|
||||||
key.mBias = nif.getFloat();
|
|
||||||
key.mContinuity = nif.getFloat();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
typedef KeyListT<float,&NIFStream::getFloat> FloatKeyList;
|
|
||||||
typedef KeyListT<Ogre::Vector3,&NIFStream::getVector3> Vector3KeyList;
|
|
||||||
typedef KeyListT<Ogre::Vector4,&NIFStream::getVector4> Vector4KeyList;
|
|
||||||
typedef KeyListT<Ogre::Quaternion,&NIFStream::getQuaternion> QuaternionKeyList;
|
|
||||||
|
|
||||||
} // Namespace
|
} // Namespace
|
||||||
#endif
|
#endif
|
||||||
|
|
140
components/nif/nifkey.hpp
Normal file
140
components/nif/nifkey.hpp
Normal file
|
@ -0,0 +1,140 @@
|
||||||
|
///File to handle keys used by nif file records
|
||||||
|
|
||||||
|
#ifndef OPENMW_COMPONENTS_NIF_NIFKEY_HPP
|
||||||
|
#define OPENMW_COMPONENTS_NIF_NIFKEY_HPP
|
||||||
|
|
||||||
|
#include <OgreStringConverter.h>
|
||||||
|
|
||||||
|
#include "nifstream.hpp"
|
||||||
|
|
||||||
|
namespace Nif
|
||||||
|
{
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct KeyT {
|
||||||
|
float mTime;
|
||||||
|
T mValue;
|
||||||
|
T mForwardValue; // Only for Quadratic interpolation, and never for QuaternionKeyList
|
||||||
|
T mBackwardValue; // Only for Quadratic interpolation, and never for QuaternionKeyList
|
||||||
|
float mTension; // Only for TBC interpolation
|
||||||
|
float mBias; // Only for TBC interpolation
|
||||||
|
float mContinuity; // Only for TBC interpolation
|
||||||
|
};
|
||||||
|
typedef KeyT<float> FloatKey;
|
||||||
|
typedef KeyT<Ogre::Vector3> Vector3Key;
|
||||||
|
typedef KeyT<Ogre::Vector4> Vector4Key;
|
||||||
|
typedef KeyT<Ogre::Quaternion> QuaternionKey;
|
||||||
|
|
||||||
|
template<typename T, T (NIFStream::*getValue)()>
|
||||||
|
struct KeyListT {
|
||||||
|
typedef std::vector< KeyT<T> > VecType;
|
||||||
|
|
||||||
|
static const unsigned int sLinearInterpolation = 1;
|
||||||
|
static const unsigned int sQuadraticInterpolation = 2;
|
||||||
|
static const unsigned int sTBCInterpolation = 3;
|
||||||
|
static const unsigned int sXYZInterpolation = 4;
|
||||||
|
|
||||||
|
unsigned int mInterpolationType;
|
||||||
|
VecType mKeys;
|
||||||
|
|
||||||
|
KeyListT() : mInterpolationType(sLinearInterpolation) {}
|
||||||
|
|
||||||
|
//Read in a KeyGroup (see http://niftools.sourceforge.net/doc/nif/NiKeyframeData.html)
|
||||||
|
void read(NIFStream *nif, bool force=false)
|
||||||
|
{
|
||||||
|
assert(nif);
|
||||||
|
|
||||||
|
mInterpolationType = 0;
|
||||||
|
|
||||||
|
size_t count = nif->getUInt();
|
||||||
|
if(count == 0 && !force)
|
||||||
|
return;
|
||||||
|
|
||||||
|
//If we aren't forcing things, make sure that read clears any previous keys
|
||||||
|
if(!force)
|
||||||
|
mKeys.clear();
|
||||||
|
|
||||||
|
mInterpolationType = nif->getUInt();
|
||||||
|
|
||||||
|
KeyT<T> key;
|
||||||
|
NIFStream &nifReference = *nif;
|
||||||
|
|
||||||
|
if(mInterpolationType == sLinearInterpolation)
|
||||||
|
{
|
||||||
|
for(size_t i = 0;i < count;i++)
|
||||||
|
{
|
||||||
|
readTimeAndValue(nifReference, key);
|
||||||
|
mKeys.push_back(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(mInterpolationType == sQuadraticInterpolation)
|
||||||
|
{
|
||||||
|
for(size_t i = 0;i < count;i++)
|
||||||
|
{
|
||||||
|
readQuadratic(nifReference, key);
|
||||||
|
mKeys.push_back(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(mInterpolationType == sTBCInterpolation)
|
||||||
|
{
|
||||||
|
for(size_t i = 0;i < count;i++)
|
||||||
|
{
|
||||||
|
readTBC(nifReference, key);
|
||||||
|
mKeys.push_back(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//XYZ keys aren't actually read here.
|
||||||
|
//data.hpp sees that the last type read was sXYZInterpolation and:
|
||||||
|
// Eats a floating point number, then
|
||||||
|
// Re-runs the read function 3 more times, with force enabled so that the previous values aren't cleared.
|
||||||
|
// When it does that it's reading in a bunch of sLinearInterpolation keys, not sXYZInterpolation.
|
||||||
|
else if(mInterpolationType == sXYZInterpolation)
|
||||||
|
{
|
||||||
|
//Don't try to read XYZ keys into the wrong part
|
||||||
|
if ( count != 1 )
|
||||||
|
nif->file->fail("XYZ_ROTATION_KEY count should always be '1' . Retrieved Value: "+Ogre::StringConverter::toString(count));
|
||||||
|
}
|
||||||
|
else if (0 == mInterpolationType)
|
||||||
|
{
|
||||||
|
if (count != 0)
|
||||||
|
nif->file->fail("Interpolation type 0 doesn't work with keys");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
nif->file->fail("Unhandled interpolation type: "+Ogre::StringConverter::toString(mInterpolationType));
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
static void readTimeAndValue(NIFStream &nif, KeyT<T> &key)
|
||||||
|
{
|
||||||
|
key.mTime = nif.getFloat();
|
||||||
|
key.mValue = (nif.*getValue)();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void readQuadratic(NIFStream &nif, KeyT<Ogre::Quaternion> &key)
|
||||||
|
{
|
||||||
|
readTimeAndValue(nif, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename U>
|
||||||
|
static void readQuadratic(NIFStream &nif, KeyT<U> &key)
|
||||||
|
{
|
||||||
|
readTimeAndValue(nif, key);
|
||||||
|
key.mForwardValue = (nif.*getValue)();
|
||||||
|
key.mBackwardValue = (nif.*getValue)();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void readTBC(NIFStream &nif, KeyT<T> &key)
|
||||||
|
{
|
||||||
|
readTimeAndValue(nif, key);
|
||||||
|
key.mTension = nif.getFloat();
|
||||||
|
key.mBias = nif.getFloat();
|
||||||
|
key.mContinuity = nif.getFloat();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
typedef KeyListT<float,&NIFStream::getFloat> FloatKeyList;
|
||||||
|
typedef KeyListT<Ogre::Vector3,&NIFStream::getVector3> Vector3KeyList;
|
||||||
|
typedef KeyListT<Ogre::Vector4,&NIFStream::getVector4> Vector4KeyList;
|
||||||
|
typedef KeyListT<Ogre::Quaternion,&NIFStream::getQuaternion> QuaternionKeyList;
|
||||||
|
|
||||||
|
} // Namespace
|
||||||
|
#endif //#ifndef OPENMW_COMPONENTS_NIF_NIFKEY_HPP
|
|
@ -1,6 +1,20 @@
|
||||||
|
///Functions used to read raw binary data from .nif files
|
||||||
|
|
||||||
#ifndef OPENMW_COMPONENTS_NIF_NIFSTREAM_HPP
|
#ifndef OPENMW_COMPONENTS_NIF_NIFSTREAM_HPP
|
||||||
#define OPENMW_COMPONENTS_NIF_NIFSTREAM_HPP
|
#define OPENMW_COMPONENTS_NIF_NIFSTREAM_HPP
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
#include <OgreDataStream.h>
|
||||||
|
#include <OgreVector2.h>
|
||||||
|
#include <OgreVector3.h>
|
||||||
|
#include <OgreVector4.h>
|
||||||
|
#include <OgreMatrix3.h>
|
||||||
|
#include <OgreQuaternion.h>
|
||||||
|
|
||||||
|
#include "niftypes.hpp"
|
||||||
|
|
||||||
namespace Nif
|
namespace Nif
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
57
components/nif/node.cpp
Normal file
57
components/nif/node.cpp
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
#include "node.hpp"
|
||||||
|
|
||||||
|
namespace Nif
|
||||||
|
{
|
||||||
|
|
||||||
|
void Node::getProperties(const Nif::NiTexturingProperty *&texprop,
|
||||||
|
const Nif::NiMaterialProperty *&matprop,
|
||||||
|
const Nif::NiAlphaProperty *&alphaprop,
|
||||||
|
const Nif::NiVertexColorProperty *&vertprop,
|
||||||
|
const Nif::NiZBufferProperty *&zprop,
|
||||||
|
const Nif::NiSpecularProperty *&specprop,
|
||||||
|
const Nif::NiWireframeProperty *&wireprop) const
|
||||||
|
{
|
||||||
|
if(parent)
|
||||||
|
parent->getProperties(texprop, matprop, alphaprop, vertprop, zprop, specprop, wireprop);
|
||||||
|
|
||||||
|
for(size_t i = 0;i < props.length();i++)
|
||||||
|
{
|
||||||
|
// Entries may be empty
|
||||||
|
if(props[i].empty())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const Nif::Property *pr = props[i].getPtr();
|
||||||
|
if(pr->recType == Nif::RC_NiTexturingProperty)
|
||||||
|
texprop = static_cast<const Nif::NiTexturingProperty*>(pr);
|
||||||
|
else if(pr->recType == Nif::RC_NiMaterialProperty)
|
||||||
|
matprop = static_cast<const Nif::NiMaterialProperty*>(pr);
|
||||||
|
else if(pr->recType == Nif::RC_NiAlphaProperty)
|
||||||
|
alphaprop = static_cast<const Nif::NiAlphaProperty*>(pr);
|
||||||
|
else if(pr->recType == Nif::RC_NiVertexColorProperty)
|
||||||
|
vertprop = static_cast<const Nif::NiVertexColorProperty*>(pr);
|
||||||
|
else if(pr->recType == Nif::RC_NiZBufferProperty)
|
||||||
|
zprop = static_cast<const Nif::NiZBufferProperty*>(pr);
|
||||||
|
else if(pr->recType == Nif::RC_NiSpecularProperty)
|
||||||
|
specprop = static_cast<const Nif::NiSpecularProperty*>(pr);
|
||||||
|
else if(pr->recType == Nif::RC_NiWireframeProperty)
|
||||||
|
wireprop = static_cast<const Nif::NiWireframeProperty*>(pr);
|
||||||
|
else
|
||||||
|
std::cerr<< "Unhandled property type: "<<pr->recName <<std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ogre::Matrix4 Node::getLocalTransform() const
|
||||||
|
{
|
||||||
|
Ogre::Matrix4 mat4 = Ogre::Matrix4(Ogre::Matrix4::IDENTITY);
|
||||||
|
mat4.makeTransform(trafo.pos, Ogre::Vector3(trafo.scale), Ogre::Quaternion(trafo.rotation));
|
||||||
|
return mat4;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ogre::Matrix4 Node::getWorldTransform() const
|
||||||
|
{
|
||||||
|
if(parent != NULL)
|
||||||
|
return parent->getWorldTransform() * getLocalTransform();
|
||||||
|
return getLocalTransform();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,26 +1,3 @@
|
||||||
/*
|
|
||||||
OpenMW - The completely unofficial reimplementation of Morrowind
|
|
||||||
Copyright (C) 2008-2010 Nicolay Korslund
|
|
||||||
Email: < korslund@gmail.com >
|
|
||||||
WWW: http://openmw.sourceforge.net/
|
|
||||||
|
|
||||||
This file (node.h) is part of the OpenMW package.
|
|
||||||
|
|
||||||
OpenMW is distributed as free software: you can redistribute it
|
|
||||||
and/or modify it under the terms of the GNU General Public License
|
|
||||||
version 3, as published by the Free Software Foundation.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful, but
|
|
||||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
version 3 along with this program. If not, see
|
|
||||||
http://www.gnu.org/licenses/ .
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef OPENMW_COMPONENTS_NIF_NODE_HPP
|
#ifndef OPENMW_COMPONENTS_NIF_NODE_HPP
|
||||||
#define OPENMW_COMPONENTS_NIF_NODE_HPP
|
#define OPENMW_COMPONENTS_NIF_NODE_HPP
|
||||||
|
|
||||||
|
@ -29,6 +6,7 @@
|
||||||
#include "controlled.hpp"
|
#include "controlled.hpp"
|
||||||
#include "data.hpp"
|
#include "data.hpp"
|
||||||
#include "property.hpp"
|
#include "property.hpp"
|
||||||
|
#include "niftypes.hpp"
|
||||||
|
|
||||||
namespace Nif
|
namespace Nif
|
||||||
{
|
{
|
||||||
|
@ -149,6 +127,14 @@ struct NiNode : Node
|
||||||
Node::read(nif);
|
Node::read(nif);
|
||||||
children.read(nif);
|
children.read(nif);
|
||||||
effects.read(nif);
|
effects.read(nif);
|
||||||
|
|
||||||
|
// Discard tranformations for the root node, otherwise some meshes
|
||||||
|
// occasionally get wrong orientation. Only for NiNode-s for now, but
|
||||||
|
// can be expanded if needed.
|
||||||
|
if (0 == recIndex)
|
||||||
|
{
|
||||||
|
static_cast<Nif::Node*>(this)->trafo = Nif::Transformation::getIdentity();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void post(NIFFile *nif)
|
void post(NIFFile *nif)
|
||||||
|
|
|
@ -1,30 +1,8 @@
|
||||||
/*
|
|
||||||
OpenMW - The completely unofficial reimplementation of Morrowind
|
|
||||||
Copyright (C) 2008-2010 Nicolay Korslund
|
|
||||||
Email: < korslund@gmail.com >
|
|
||||||
WWW: http://openmw.sourceforge.net/
|
|
||||||
|
|
||||||
This file (record_ptr.h) is part of the OpenMW package.
|
|
||||||
|
|
||||||
OpenMW is distributed as free software: you can redistribute it
|
|
||||||
and/or modify it under the terms of the GNU General Public License
|
|
||||||
version 3, as published by the Free Software Foundation.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful, but
|
|
||||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
version 3 along with this program. If not, see
|
|
||||||
http://www.gnu.org/licenses/ .
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef OPENMW_COMPONENTS_NIF_RECORDPTR_HPP
|
#ifndef OPENMW_COMPONENTS_NIF_RECORDPTR_HPP
|
||||||
#define OPENMW_COMPONENTS_NIF_RECORDPTR_HPP
|
#define OPENMW_COMPONENTS_NIF_RECORDPTR_HPP
|
||||||
|
|
||||||
#include "niffile.hpp"
|
#include "niffile.hpp"
|
||||||
|
#include "nifstream.hpp"
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace Nif
|
namespace Nif
|
||||||
|
|
6
components/nif/tests/.gitignore
vendored
6
components/nif/tests/.gitignore
vendored
|
@ -1,5 +1 @@
|
||||||
niftool
|
*.log
|
||||||
*_test
|
|
||||||
*.nif
|
|
||||||
*.kf
|
|
||||||
output.txt
|
|
||||||
|
|
19
components/nif/tests/CMakeLists.txt
Normal file
19
components/nif/tests/CMakeLists.txt
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
set(NIFTEST
|
||||||
|
niftest.cpp
|
||||||
|
)
|
||||||
|
source_group(components\\nif\\tests FILES ${NIFTEST})
|
||||||
|
|
||||||
|
# Main executable
|
||||||
|
add_executable(niftest
|
||||||
|
${NIFTEST}
|
||||||
|
)
|
||||||
|
|
||||||
|
target_link_libraries(niftest
|
||||||
|
${Boost_LIBRARIES}
|
||||||
|
components
|
||||||
|
)
|
||||||
|
|
||||||
|
if (BUILD_WITH_CODE_COVERAGE)
|
||||||
|
add_definitions (--coverage)
|
||||||
|
target_link_libraries(niftest gcov)
|
||||||
|
endif()
|
|
@ -1,12 +0,0 @@
|
||||||
GCC=g++
|
|
||||||
|
|
||||||
all: niftool nif_bsa_test
|
|
||||||
|
|
||||||
niftool: niftool.cpp ../nif_file.hpp ../nif_file.cpp ../record.hpp
|
|
||||||
$(GCC) $< ../nif_file.cpp ../../tools/stringops.cpp -o $@
|
|
||||||
|
|
||||||
nif_bsa_test: nif_bsa_test.cpp ../nif_file.cpp ../../bsa/bsa_file.cpp ../../tools/stringops.cpp
|
|
||||||
$(GCC) $^ -o $@
|
|
||||||
|
|
||||||
clean:
|
|
||||||
rm niftool *_test
|
|
|
@ -1,30 +0,0 @@
|
||||||
/*
|
|
||||||
Runs NIFFile through all the NIFs in Morrowind.bsa.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "../nif_file.hpp"
|
|
||||||
#include "../../bsa/bsa_file.hpp"
|
|
||||||
#include "../../tools/stringops.hpp"
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
using namespace Mangle::Stream;
|
|
||||||
using namespace std;
|
|
||||||
using namespace Nif;
|
|
||||||
|
|
||||||
int main(int argc, char **args)
|
|
||||||
{
|
|
||||||
BSAFile bsa;
|
|
||||||
cout << "Reading Morrowind.bsa\n";
|
|
||||||
bsa.open("../../data/Morrowind.bsa");
|
|
||||||
|
|
||||||
const BSAFile::FileList &files = bsa.getList();
|
|
||||||
|
|
||||||
for(int i=0; i<files.size(); i++)
|
|
||||||
{
|
|
||||||
const char *n = files[i].name;
|
|
||||||
if(!ends(n, ".nif")) continue;
|
|
||||||
|
|
||||||
cout << "Decoding " << n << endl;
|
|
||||||
NIFFile nif(bsa.getFile(n), n);
|
|
||||||
}
|
|
||||||
}
|
|
96
components/nif/tests/niftest.cpp
Normal file
96
components/nif/tests/niftest.cpp
Normal file
|
@ -0,0 +1,96 @@
|
||||||
|
///Program to test .nif files both on the FileSystem and in BSA archives.
|
||||||
|
|
||||||
|
#include "../niffile.hpp"
|
||||||
|
#include "../../bsa/bsa_file.hpp"
|
||||||
|
#include "../../bsa/bsa_archive.hpp"
|
||||||
|
#include <OgreRoot.h>
|
||||||
|
#include <OgreResourceGroupManager.h>
|
||||||
|
#include <iostream>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <exception>
|
||||||
|
|
||||||
|
///See if the file has the named extension
|
||||||
|
bool hasExtension(std::string filename, std::string extensionToFind)
|
||||||
|
{
|
||||||
|
std::string extension = filename.substr(filename.find_last_of(".")+1);
|
||||||
|
|
||||||
|
//Convert strings to lower case for comparison
|
||||||
|
std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower);
|
||||||
|
std::transform(extensionToFind.begin(), extensionToFind.end(), extensionToFind.begin(), ::tolower);
|
||||||
|
|
||||||
|
if(extension == extensionToFind)
|
||||||
|
return true;
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
///See if the file has the "nif" extension.
|
||||||
|
bool isNIF(std::string filename)
|
||||||
|
{
|
||||||
|
return hasExtension(filename,"nif");
|
||||||
|
}
|
||||||
|
///See if the file has the "bsa" extension.
|
||||||
|
bool isBSA(std::string filename)
|
||||||
|
{
|
||||||
|
return hasExtension(filename,"bsa");
|
||||||
|
}
|
||||||
|
|
||||||
|
///Check all the nif files in the given BSA archive
|
||||||
|
void readBSA(std::string filename)
|
||||||
|
{
|
||||||
|
Bsa::BSAFile bsa;
|
||||||
|
bsa.open(filename.c_str());
|
||||||
|
|
||||||
|
const Bsa::BSAFile::FileList &files = bsa.getList();
|
||||||
|
Bsa::addBSA(filename,"Bsa Files");
|
||||||
|
|
||||||
|
for(unsigned int i=0; i<files.size(); i++)
|
||||||
|
{
|
||||||
|
std::string name = files[i].name;
|
||||||
|
if(isNIF(name))
|
||||||
|
{
|
||||||
|
//std::cout << "Decoding " << name << std::endl;
|
||||||
|
Nif::NIFFile temp_nif(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
|
||||||
|
//Need this for Ogre's getSingleton
|
||||||
|
new Ogre::Root("", "", "niftest.log");
|
||||||
|
Ogre::ResourceGroupManager::getSingleton ().createResourceGroup ("Bsa Files");
|
||||||
|
//Needed to read files from file system
|
||||||
|
Ogre::ResourceGroupManager::getSingleton().addResourceLocation("/", "FileSystem");
|
||||||
|
// Initialize the resource groups:
|
||||||
|
Ogre::ResourceGroupManager::getSingleton().initialiseAllResourceGroups();
|
||||||
|
|
||||||
|
std::cout << "Reading Files" << std::endl;
|
||||||
|
for(int i = 1; i<argc;i++)
|
||||||
|
{
|
||||||
|
std::string name = argv[i];
|
||||||
|
|
||||||
|
try{
|
||||||
|
if(isNIF(name))
|
||||||
|
{
|
||||||
|
//std::cout << "Decoding " << name << std::endl;
|
||||||
|
Nif::NIFFile temp_nif(name);
|
||||||
|
}
|
||||||
|
else if(isBSA(name))
|
||||||
|
{
|
||||||
|
std::cout << "Reading " << name << std::endl;
|
||||||
|
readBSA(name);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::cerr << "ERROR: \"" << name << "\" is not a nif or bsa file!" << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (std::exception& e)
|
||||||
|
{
|
||||||
|
std::cerr << "ERROR, an exception has occured" << e.what() << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
File diff suppressed because it is too large
Load diff
|
@ -1,18 +1,15 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
make || exit
|
#Script to test all nif files (both loose, and in BSA archives) in data files directory
|
||||||
|
|
||||||
mkdir -p output
|
DATAFILESDIR="$1"
|
||||||
|
|
||||||
PROGS=*_test
|
find "$DATAFILESDIR" -iname *bsa > nifs.txt
|
||||||
|
find "$DATAFILESDIR" -iname *nif >> nifs.txt
|
||||||
|
|
||||||
for a in $PROGS; do
|
sed -e 's/.*/\"&\"/' nifs.txt > quoted_nifs.txt
|
||||||
if [ -f "output/$a.out" ]; then
|
|
||||||
echo "Running $a:"
|
xargs --arg-file=quoted_nifs.txt ../../../niftest
|
||||||
./$a | diff output/$a.out -
|
|
||||||
else
|
rm nifs.txt
|
||||||
echo "Creating $a.out"
|
rm quoted_nifs.txt
|
||||||
./$a > "output/$a.out"
|
|
||||||
git add "output/$a.out"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
|
@ -28,6 +28,8 @@ http://www.gnu.org/licenses/ .
|
||||||
|
|
||||||
#include <components/misc/stringops.hpp>
|
#include <components/misc/stringops.hpp>
|
||||||
|
|
||||||
|
#include <components/nifcache/nifcache.hpp>
|
||||||
|
|
||||||
#include "../nif/niffile.hpp"
|
#include "../nif/niffile.hpp"
|
||||||
#include "../nif/node.hpp"
|
#include "../nif/node.hpp"
|
||||||
#include "../nif/data.hpp"
|
#include "../nif/data.hpp"
|
||||||
|
@ -74,7 +76,7 @@ void ManualBulletShapeLoader::loadResource(Ogre::Resource *resource)
|
||||||
// of the early stages of development. Right now we WANT to catch
|
// of the early stages of development. Right now we WANT to catch
|
||||||
// every error as early and intrusively as possible, as it's most
|
// every error as early and intrusively as possible, as it's most
|
||||||
// likely a sign of incomplete code rather than faulty input.
|
// likely a sign of incomplete code rather than faulty input.
|
||||||
Nif::NIFFile::ptr pnif (Nif::NIFFile::create (mResourceName.substr(0, mResourceName.length()-7)));
|
Nif::NIFFilePtr pnif (Nif::Cache::getInstance().load(mResourceName.substr(0, mResourceName.length()-7)));
|
||||||
Nif::NIFFile & nif = *pnif.get ();
|
Nif::NIFFile & nif = *pnif.get ();
|
||||||
if (nif.numRoots() < 1)
|
if (nif.numRoots() < 1)
|
||||||
{
|
{
|
||||||
|
@ -388,7 +390,7 @@ bool findBoundingBox (const Nif::Node* node, Ogre::Vector3& halfExtents, Ogre::V
|
||||||
|
|
||||||
bool getBoundingBox(const std::string& nifFile, Ogre::Vector3& halfExtents, Ogre::Vector3& translation, Ogre::Quaternion& orientation)
|
bool getBoundingBox(const std::string& nifFile, Ogre::Vector3& halfExtents, Ogre::Vector3& translation, Ogre::Quaternion& orientation)
|
||||||
{
|
{
|
||||||
Nif::NIFFile::ptr pnif (Nif::NIFFile::create (nifFile));
|
Nif::NIFFilePtr pnif (Nif::Cache::getInstance().load(nifFile));
|
||||||
Nif::NIFFile & nif = *pnif.get ();
|
Nif::NIFFile & nif = *pnif.get ();
|
||||||
|
|
||||||
if (nif.numRoots() < 1)
|
if (nif.numRoots() < 1)
|
||||||
|
|
40
components/nifcache/nifcache.cpp
Normal file
40
components/nifcache/nifcache.cpp
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
#include "nifcache.hpp"
|
||||||
|
|
||||||
|
namespace Nif
|
||||||
|
{
|
||||||
|
|
||||||
|
Cache* Cache::sThis = 0;
|
||||||
|
|
||||||
|
Cache& Cache::getInstance()
|
||||||
|
{
|
||||||
|
assert (sThis);
|
||||||
|
return *sThis;
|
||||||
|
}
|
||||||
|
|
||||||
|
Cache* Cache::getInstancePtr()
|
||||||
|
{
|
||||||
|
return sThis;
|
||||||
|
}
|
||||||
|
|
||||||
|
Cache::Cache()
|
||||||
|
{
|
||||||
|
assert (!sThis);
|
||||||
|
sThis = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
NIFFilePtr Cache::load(const std::string &filename)
|
||||||
|
{
|
||||||
|
// TODO: normalize file path to make sure we're not loading the same file twice
|
||||||
|
|
||||||
|
LoadedMap::iterator it = mLoadedMap.find(filename);
|
||||||
|
if (it != mLoadedMap.end())
|
||||||
|
return it->second;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
NIFFilePtr file(new Nif::NIFFile(filename));
|
||||||
|
mLoadedMap[filename] = file;
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
50
components/nifcache/nifcache.hpp
Normal file
50
components/nifcache/nifcache.hpp
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
#ifndef OPENMW_COMPONENTS_NIFCACHE_H
|
||||||
|
#define OPENMW_COMPONENTS_NIFCACHE_H
|
||||||
|
|
||||||
|
#include <components/nif/niffile.hpp>
|
||||||
|
|
||||||
|
#include <boost/shared_ptr.hpp>
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
namespace Nif
|
||||||
|
{
|
||||||
|
|
||||||
|
typedef boost::shared_ptr<Nif::NIFFile> NIFFilePtr;
|
||||||
|
|
||||||
|
/// @brief A basic resource manager for NIF files
|
||||||
|
class Cache
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Cache();
|
||||||
|
|
||||||
|
/// Queue this file for background loading. A worker thread will start loading the file.
|
||||||
|
/// To get the loaded NIFFilePtr, use the load method, which will wait until the worker thread is finished
|
||||||
|
/// and then return the loaded file.
|
||||||
|
//void loadInBackground (const std::string& file);
|
||||||
|
|
||||||
|
/// Read and parse the given file. May retrieve from cache if this file has been used previously.
|
||||||
|
/// @note If the file is currently loading in the background, this function will block until
|
||||||
|
/// the background loading finishes, then return the background loaded file.
|
||||||
|
/// @note Returns a SharedPtr to the file and the file will stay loaded as long as the user holds on to this pointer.
|
||||||
|
/// When all external SharedPtrs to a file are released, the cache may decide to unload the file.
|
||||||
|
NIFFilePtr load (const std::string& filename);
|
||||||
|
|
||||||
|
/// Return instance of this class.
|
||||||
|
static Cache& getInstance();
|
||||||
|
static Cache* getInstancePtr();
|
||||||
|
|
||||||
|
private:
|
||||||
|
static Cache* sThis;
|
||||||
|
|
||||||
|
Cache(const Cache&);
|
||||||
|
Cache& operator =(const Cache&);
|
||||||
|
|
||||||
|
typedef std::map<std::string, NIFFilePtr> LoadedMap;
|
||||||
|
|
||||||
|
LoadedMap mLoadedMap;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -15,6 +15,7 @@
|
||||||
#include <OgreKeyFrame.h>
|
#include <OgreKeyFrame.h>
|
||||||
|
|
||||||
#include <components/nif/node.hpp>
|
#include <components/nif/node.hpp>
|
||||||
|
#include <components/nifcache/nifcache.hpp>
|
||||||
#include <components/misc/stringops.hpp>
|
#include <components/misc/stringops.hpp>
|
||||||
|
|
||||||
#include "material.hpp"
|
#include "material.hpp"
|
||||||
|
@ -383,7 +384,7 @@ void NIFMeshLoader::loadResource(Ogre::Resource *resource)
|
||||||
Ogre::Mesh *mesh = dynamic_cast<Ogre::Mesh*>(resource);
|
Ogre::Mesh *mesh = dynamic_cast<Ogre::Mesh*>(resource);
|
||||||
OgreAssert(mesh, "Attempting to load a mesh into a non-mesh resource!");
|
OgreAssert(mesh, "Attempting to load a mesh into a non-mesh resource!");
|
||||||
|
|
||||||
Nif::NIFFile::ptr nif = Nif::NIFFile::create(mName);
|
Nif::NIFFilePtr nif = Nif::Cache::getInstance().load(mName);
|
||||||
if(mShapeIndex >= nif->numRecords())
|
if(mShapeIndex >= nif->numRecords())
|
||||||
{
|
{
|
||||||
Ogre::SkeletonManager *skelMgr = Ogre::SkeletonManager::getSingletonPtr();
|
Ogre::SkeletonManager *skelMgr = Ogre::SkeletonManager::getSingletonPtr();
|
||||||
|
|
|
@ -45,6 +45,7 @@
|
||||||
#include <extern/shiny/Main/Factory.hpp>
|
#include <extern/shiny/Main/Factory.hpp>
|
||||||
|
|
||||||
#include <components/nif/node.hpp>
|
#include <components/nif/node.hpp>
|
||||||
|
#include <components/nifcache/nifcache.hpp>
|
||||||
#include <components/misc/stringops.hpp>
|
#include <components/misc/stringops.hpp>
|
||||||
#include <components/misc/resourcehelpers.hpp>
|
#include <components/misc/resourcehelpers.hpp>
|
||||||
|
|
||||||
|
@ -52,6 +53,24 @@
|
||||||
#include "material.hpp"
|
#include "material.hpp"
|
||||||
#include "mesh.hpp"
|
#include "mesh.hpp"
|
||||||
#include "controller.hpp"
|
#include "controller.hpp"
|
||||||
|
#include "particles.hpp"
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
|
||||||
|
void getAllNiNodes(const Nif::Node* node, std::vector<const Nif::NiNode*>& out)
|
||||||
|
{
|
||||||
|
const Nif::NiNode* ninode = dynamic_cast<const Nif::NiNode*>(node);
|
||||||
|
if (ninode)
|
||||||
|
{
|
||||||
|
out.push_back(ninode);
|
||||||
|
for (unsigned int i=0; i<ninode->children.length(); ++i)
|
||||||
|
if (!ninode->children[i].empty())
|
||||||
|
getAllNiNodes(ninode->children[i].getPtr(), out);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
namespace NifOgre
|
namespace NifOgre
|
||||||
{
|
{
|
||||||
|
@ -390,9 +409,10 @@ public:
|
||||||
class Value : public NodeTargetValue<Ogre::Real>, public ValueInterpolator
|
class Value : public NodeTargetValue<Ogre::Real>, public ValueInterpolator
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
Nif::QuaternionKeyList mRotations;
|
const Nif::QuaternionKeyList* mRotations;
|
||||||
Nif::Vector3KeyList mTranslations;
|
const Nif::Vector3KeyList* mTranslations;
|
||||||
Nif::FloatKeyList mScales;
|
const Nif::FloatKeyList* mScales;
|
||||||
|
Nif::NIFFilePtr mNif; // Hold a SharedPtr to make sure key lists stay valid
|
||||||
|
|
||||||
using ValueInterpolator::interpKey;
|
using ValueInterpolator::interpKey;
|
||||||
|
|
||||||
|
@ -420,31 +440,33 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Value(Ogre::Node *target, const Nif::NiKeyframeData *data)
|
/// @note The NiKeyFrameData must be valid as long as this KeyframeController exists.
|
||||||
|
Value(Ogre::Node *target, const Nif::NIFFilePtr& nif, const Nif::NiKeyframeData *data)
|
||||||
: NodeTargetValue<Ogre::Real>(target)
|
: NodeTargetValue<Ogre::Real>(target)
|
||||||
, mRotations(data->mRotations)
|
, mRotations(&data->mRotations)
|
||||||
, mTranslations(data->mTranslations)
|
, mTranslations(&data->mTranslations)
|
||||||
, mScales(data->mScales)
|
, mScales(&data->mScales)
|
||||||
|
, mNif(nif)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
virtual Ogre::Quaternion getRotation(float time) const
|
virtual Ogre::Quaternion getRotation(float time) const
|
||||||
{
|
{
|
||||||
if(mRotations.mKeys.size() > 0)
|
if(mRotations->mKeys.size() > 0)
|
||||||
return interpKey(mRotations.mKeys, time);
|
return interpKey(mRotations->mKeys, time);
|
||||||
return mNode->getOrientation();
|
return mNode->getOrientation();
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual Ogre::Vector3 getTranslation(float time) const
|
virtual Ogre::Vector3 getTranslation(float time) const
|
||||||
{
|
{
|
||||||
if(mTranslations.mKeys.size() > 0)
|
if(mTranslations->mKeys.size() > 0)
|
||||||
return interpKey(mTranslations.mKeys, time);
|
return interpKey(mTranslations->mKeys, time);
|
||||||
return mNode->getPosition();
|
return mNode->getPosition();
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual Ogre::Vector3 getScale(float time) const
|
virtual Ogre::Vector3 getScale(float time) const
|
||||||
{
|
{
|
||||||
if(mScales.mKeys.size() > 0)
|
if(mScales->mKeys.size() > 0)
|
||||||
return Ogre::Vector3(interpKey(mScales.mKeys, time));
|
return Ogre::Vector3(interpKey(mScales->mKeys, time));
|
||||||
return mNode->getScale();
|
return mNode->getScale();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -456,12 +478,12 @@ public:
|
||||||
|
|
||||||
virtual void setValue(Ogre::Real time)
|
virtual void setValue(Ogre::Real time)
|
||||||
{
|
{
|
||||||
if(mRotations.mKeys.size() > 0)
|
if(mRotations->mKeys.size() > 0)
|
||||||
mNode->setOrientation(interpKey(mRotations.mKeys, time));
|
mNode->setOrientation(interpKey(mRotations->mKeys, time));
|
||||||
if(mTranslations.mKeys.size() > 0)
|
if(mTranslations->mKeys.size() > 0)
|
||||||
mNode->setPosition(interpKey(mTranslations.mKeys, time));
|
mNode->setPosition(interpKey(mTranslations->mKeys, time));
|
||||||
if(mScales.mKeys.size() > 0)
|
if(mScales->mKeys.size() > 0)
|
||||||
mNode->setScale(Ogre::Vector3(interpKey(mScales.mKeys, time)));
|
mNode->setScale(Ogre::Vector3(interpKey(mScales->mKeys, time)));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -898,9 +920,28 @@ class NIFObjectLoader
|
||||||
{
|
{
|
||||||
int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, partctrl->emitter->recIndex);
|
int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, partctrl->emitter->recIndex);
|
||||||
Ogre::Bone *trgtbone = scene->mSkelBase->getSkeleton()->getBone(trgtid);
|
Ogre::Bone *trgtbone = scene->mSkelBase->getSkeleton()->getBone(trgtid);
|
||||||
// Set the emitter bone as user data on the particle system
|
// Set the emitter bone(s) as user data on the particle system
|
||||||
// so the emitters/affectors can access it easily.
|
// so the emitters/affectors can access it easily.
|
||||||
partsys->getUserObjectBindings().setUserAny(Ogre::Any(trgtbone));
|
std::vector<Ogre::Bone*> bones;
|
||||||
|
if (partctrl->recType == Nif::RC_NiBSPArrayController)
|
||||||
|
{
|
||||||
|
std::vector<const Nif::NiNode*> nodes;
|
||||||
|
getAllNiNodes(partctrl->emitter.getPtr(), nodes);
|
||||||
|
if (nodes.empty())
|
||||||
|
throw std::runtime_error("Emitter for NiBSPArrayController must be a NiNode");
|
||||||
|
for (unsigned int i=0; i<nodes.size(); ++i)
|
||||||
|
{
|
||||||
|
bones.push_back(scene->mSkelBase->getSkeleton()->getBone(
|
||||||
|
NIFSkeletonLoader::lookupOgreBoneHandle(name, nodes[i]->recIndex)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bones.push_back(trgtbone);
|
||||||
|
}
|
||||||
|
NiNodeHolder holder;
|
||||||
|
holder.mBones = bones;
|
||||||
|
partsys->getUserObjectBindings().setUserAny(Ogre::Any(holder));
|
||||||
createParticleEmitterAffectors(partsys, partctrl, trgtbone, scene->mSkelBase->getName());
|
createParticleEmitterAffectors(partsys, partctrl, trgtbone, scene->mSkelBase->getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -916,8 +957,10 @@ class NIFObjectLoader
|
||||||
|
|
||||||
scene->mControllers.push_back(Ogre::Controller<Ogre::Real>(srcval, dstval, func));
|
scene->mControllers.push_back(Ogre::Controller<Ogre::Real>(srcval, dstval, func));
|
||||||
|
|
||||||
if (partflags&Nif::NiNode::ParticleFlag_AutoPlay)
|
// Emitting state will be overwritten on frame update by the ParticleSystemController,
|
||||||
partsys->fastForward(1, 0.1);
|
// but set up an initial value anyway so the user can fast-forward particle systems
|
||||||
|
// immediately after creation if desired.
|
||||||
|
partsys->setEmitting(partflags&Nif::NiNode::ParticleFlag_AutoPlay);
|
||||||
}
|
}
|
||||||
ctrl = ctrl->next;
|
ctrl = ctrl->next;
|
||||||
}
|
}
|
||||||
|
@ -929,7 +972,7 @@ class NIFObjectLoader
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void createNodeControllers(const std::string &name, Nif::ControllerPtr ctrl, ObjectScenePtr scene, int animflags)
|
static void createNodeControllers(const Nif::NIFFilePtr& nif, const std::string &name, Nif::ControllerPtr ctrl, ObjectScenePtr scene, int animflags)
|
||||||
{
|
{
|
||||||
do {
|
do {
|
||||||
if (ctrl->flags & Nif::NiNode::ControllerFlag_Active)
|
if (ctrl->flags & Nif::NiNode::ControllerFlag_Active)
|
||||||
|
@ -963,7 +1006,7 @@ class NIFObjectLoader
|
||||||
Ogre::ControllerValueRealPtr srcval((animflags&Nif::NiNode::AnimFlag_AutoPlay) ?
|
Ogre::ControllerValueRealPtr srcval((animflags&Nif::NiNode::AnimFlag_AutoPlay) ?
|
||||||
Ogre::ControllerManager::getSingleton().getFrameTimeSource() :
|
Ogre::ControllerManager::getSingleton().getFrameTimeSource() :
|
||||||
Ogre::ControllerValueRealPtr());
|
Ogre::ControllerValueRealPtr());
|
||||||
Ogre::ControllerValueRealPtr dstval(OGRE_NEW KeyframeController::Value(trgtbone, key->data.getPtr()));
|
Ogre::ControllerValueRealPtr dstval(OGRE_NEW KeyframeController::Value(trgtbone, nif, key->data.getPtr()));
|
||||||
KeyframeController::Function* function = OGRE_NEW KeyframeController::Function(key, (animflags&Nif::NiNode::AnimFlag_AutoPlay));
|
KeyframeController::Function* function = OGRE_NEW KeyframeController::Function(key, (animflags&Nif::NiNode::AnimFlag_AutoPlay));
|
||||||
scene->mMaxControllerLength = std::max(function->mStopTime, scene->mMaxControllerLength);
|
scene->mMaxControllerLength = std::max(function->mStopTime, scene->mMaxControllerLength);
|
||||||
Ogre::ControllerFunctionRealPtr func(function);
|
Ogre::ControllerFunctionRealPtr func(function);
|
||||||
|
@ -1016,7 +1059,7 @@ class NIFObjectLoader
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void createObjects(const std::string &name, const std::string &group,
|
static void createObjects(const Nif::NIFFilePtr& nif, const std::string &name, const std::string &group,
|
||||||
Ogre::SceneNode *sceneNode, const Nif::Node *node,
|
Ogre::SceneNode *sceneNode, const Nif::Node *node,
|
||||||
ObjectScenePtr scene, int flags, int animflags, int partflags)
|
ObjectScenePtr scene, int flags, int animflags, int partflags)
|
||||||
{
|
{
|
||||||
|
@ -1073,7 +1116,7 @@ class NIFObjectLoader
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!node->controller.empty())
|
if(!node->controller.empty())
|
||||||
createNodeControllers(name, node->controller, scene, animflags);
|
createNodeControllers(nif, name, node->controller, scene, animflags);
|
||||||
|
|
||||||
if(node->recType == Nif::RC_NiCamera)
|
if(node->recType == Nif::RC_NiCamera)
|
||||||
{
|
{
|
||||||
|
@ -1098,7 +1141,7 @@ class NIFObjectLoader
|
||||||
for(size_t i = 0;i < children.length();i++)
|
for(size_t i = 0;i < children.length();i++)
|
||||||
{
|
{
|
||||||
if(!children[i].empty())
|
if(!children[i].empty())
|
||||||
createObjects(name, group, sceneNode, children[i].getPtr(), scene, flags, animflags, partflags);
|
createObjects(nif, name, group, sceneNode, children[i].getPtr(), scene, flags, animflags, partflags);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1121,7 +1164,7 @@ class NIFObjectLoader
|
||||||
public:
|
public:
|
||||||
static void load(Ogre::SceneNode *sceneNode, ObjectScenePtr scene, const std::string &name, const std::string &group, int flags=0)
|
static void load(Ogre::SceneNode *sceneNode, ObjectScenePtr scene, const std::string &name, const std::string &group, int flags=0)
|
||||||
{
|
{
|
||||||
Nif::NIFFile::ptr nif = Nif::NIFFile::create(name);
|
Nif::NIFFilePtr nif = Nif::Cache::getInstance().load(name);
|
||||||
if(nif->numRoots() < 1)
|
if(nif->numRoots() < 1)
|
||||||
{
|
{
|
||||||
nif->warn("Found no root nodes in "+name+".");
|
nif->warn("Found no root nodes in "+name+".");
|
||||||
|
@ -1145,13 +1188,13 @@ public:
|
||||||
// Create a base skeleton entity if this NIF needs one
|
// Create a base skeleton entity if this NIF needs one
|
||||||
createSkelBase(name, group, sceneNode->getCreator(), node, scene);
|
createSkelBase(name, group, sceneNode->getCreator(), node, scene);
|
||||||
}
|
}
|
||||||
createObjects(name, group, sceneNode, node, scene, flags, 0, 0);
|
createObjects(nif, name, group, sceneNode, node, scene, flags, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void loadKf(Ogre::Skeleton *skel, const std::string &name,
|
static void loadKf(Ogre::Skeleton *skel, const std::string &name,
|
||||||
TextKeyMap &textKeys, std::vector<Ogre::Controller<Ogre::Real> > &ctrls)
|
TextKeyMap &textKeys, std::vector<Ogre::Controller<Ogre::Real> > &ctrls)
|
||||||
{
|
{
|
||||||
Nif::NIFFile::ptr nif = Nif::NIFFile::create(name);
|
Nif::NIFFilePtr nif = Nif::Cache::getInstance().load(name);
|
||||||
if(nif->numRoots() < 1)
|
if(nif->numRoots() < 1)
|
||||||
{
|
{
|
||||||
nif->warn("Found no root nodes in "+name+".");
|
nif->warn("Found no root nodes in "+name+".");
|
||||||
|
@ -1202,7 +1245,7 @@ public:
|
||||||
|
|
||||||
Ogre::Bone *trgtbone = skel->getBone(strdata->string);
|
Ogre::Bone *trgtbone = skel->getBone(strdata->string);
|
||||||
Ogre::ControllerValueRealPtr srcval;
|
Ogre::ControllerValueRealPtr srcval;
|
||||||
Ogre::ControllerValueRealPtr dstval(OGRE_NEW KeyframeController::Value(trgtbone, key->data.getPtr()));
|
Ogre::ControllerValueRealPtr dstval(OGRE_NEW KeyframeController::Value(trgtbone, nif, key->data.getPtr()));
|
||||||
Ogre::ControllerFunctionRealPtr func(OGRE_NEW KeyframeController::Function(key, false));
|
Ogre::ControllerFunctionRealPtr func(OGRE_NEW KeyframeController::Function(key, false));
|
||||||
|
|
||||||
ctrls.push_back(Ogre::Controller<Ogre::Real>(srcval, dstval, func));
|
ctrls.push_back(Ogre::Controller<Ogre::Real>(srcval, dstval, func));
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
class NifEmitter : public Ogre::ParticleEmitter
|
class NifEmitter : public Ogre::ParticleEmitter
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Ogre::Bone* mEmitterBone;
|
std::vector<Ogre::Bone*> mEmitterBones;
|
||||||
Ogre::Bone* mParticleBone;
|
Ogre::Bone* mParticleBone;
|
||||||
|
|
||||||
Ogre::ParticleSystem* getPartSys() { return mParent; }
|
Ogre::ParticleSystem* getPartSys() { return mParent; }
|
||||||
|
@ -131,7 +131,8 @@ public:
|
||||||
NifEmitter(Ogre::ParticleSystem *psys)
|
NifEmitter(Ogre::ParticleSystem *psys)
|
||||||
: Ogre::ParticleEmitter(psys)
|
: Ogre::ParticleEmitter(psys)
|
||||||
{
|
{
|
||||||
mEmitterBone = Ogre::any_cast<Ogre::Bone*>(psys->getUserObjectBindings().getUserAny());
|
mEmitterBones = Ogre::any_cast<NiNodeHolder>(psys->getUserObjectBindings().getUserAny()).mBones;
|
||||||
|
assert (!mEmitterBones.empty());
|
||||||
Ogre::TagPoint* tag = static_cast<Ogre::TagPoint*>(mParent->getParentNode());
|
Ogre::TagPoint* tag = static_cast<Ogre::TagPoint*>(mParent->getParentNode());
|
||||||
mParticleBone = static_cast<Ogre::Bone*>(tag->getParent());
|
mParticleBone = static_cast<Ogre::Bone*>(tag->getParent());
|
||||||
initDefaults("Nif");
|
initDefaults("Nif");
|
||||||
|
@ -170,8 +171,10 @@ public:
|
||||||
Ogre::Real& timeToLive = particle->timeToLive;
|
Ogre::Real& timeToLive = particle->timeToLive;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
Ogre::Node* emitterBone = mEmitterBones.at((int)(::rand()/(RAND_MAX+1.0)*mEmitterBones.size()));
|
||||||
|
|
||||||
position = xOff + yOff + zOff +
|
position = xOff + yOff + zOff +
|
||||||
mParticleBone->_getDerivedOrientation().Inverse() * (mEmitterBone->_getDerivedPosition()
|
mParticleBone->_getDerivedOrientation().Inverse() * (emitterBone->_getDerivedPosition()
|
||||||
- mParticleBone->_getDerivedPosition());
|
- mParticleBone->_getDerivedPosition());
|
||||||
|
|
||||||
// Generate complex data by reference
|
// Generate complex data by reference
|
||||||
|
@ -181,7 +184,7 @@ public:
|
||||||
Ogre::Radian hdir = mHorizontalDir + mHorizontalAngle*Ogre::Math::SymmetricRandom();
|
Ogre::Radian hdir = mHorizontalDir + mHorizontalAngle*Ogre::Math::SymmetricRandom();
|
||||||
Ogre::Radian vdir = mVerticalDir + mVerticalAngle*Ogre::Math::SymmetricRandom();
|
Ogre::Radian vdir = mVerticalDir + mVerticalAngle*Ogre::Math::SymmetricRandom();
|
||||||
direction = (mParticleBone->_getDerivedOrientation().Inverse()
|
direction = (mParticleBone->_getDerivedOrientation().Inverse()
|
||||||
* mEmitterBone->_getDerivedOrientation() *
|
* emitterBone->_getDerivedOrientation() *
|
||||||
Ogre::Quaternion(hdir, Ogre::Vector3::UNIT_Z) *
|
Ogre::Quaternion(hdir, Ogre::Vector3::UNIT_Z) *
|
||||||
Ogre::Quaternion(vdir, Ogre::Vector3::UNIT_X)) *
|
Ogre::Quaternion(vdir, Ogre::Vector3::UNIT_X)) *
|
||||||
Ogre::Vector3::UNIT_Z;
|
Ogre::Vector3::UNIT_Z;
|
||||||
|
@ -635,7 +638,9 @@ public:
|
||||||
, mPosition(0.0f)
|
, mPosition(0.0f)
|
||||||
, mDirection(0.0f)
|
, mDirection(0.0f)
|
||||||
{
|
{
|
||||||
mEmitterBone = Ogre::any_cast<Ogre::Bone*>(psys->getUserObjectBindings().getUserAny());
|
std::vector<Ogre::Bone*> bones = Ogre::any_cast<NiNodeHolder>(psys->getUserObjectBindings().getUserAny()).mBones;
|
||||||
|
assert (!bones.empty());
|
||||||
|
mEmitterBone = bones[0];
|
||||||
Ogre::TagPoint* tag = static_cast<Ogre::TagPoint*>(mParent->getParentNode());
|
Ogre::TagPoint* tag = static_cast<Ogre::TagPoint*>(mParent->getParentNode());
|
||||||
mParticleBone = static_cast<Ogre::Bone*>(tag->getParent());
|
mParticleBone = static_cast<Ogre::Bone*>(tag->getParent());
|
||||||
|
|
||||||
|
|
|
@ -38,4 +38,13 @@ class GravityAffectorFactory : public Ogre::ParticleAffectorFactory
|
||||||
Ogre::ParticleAffector *createAffector(Ogre::ParticleSystem *psys);
|
Ogre::ParticleAffector *createAffector(Ogre::ParticleSystem *psys);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct NiNodeHolder
|
||||||
|
{
|
||||||
|
std::vector<Ogre::Bone*> mBones;
|
||||||
|
|
||||||
|
// Ogre::Any needs this for some reason
|
||||||
|
friend std::ostream& operator<<(std::ostream& o, const NiNodeHolder& r)
|
||||||
|
{ return o; }
|
||||||
|
};
|
||||||
|
|
||||||
#endif /* OENGINE_OGRE_PARTICLES_H */
|
#endif /* OENGINE_OGRE_PARTICLES_H */
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#include <OgreBone.h>
|
#include <OgreBone.h>
|
||||||
|
|
||||||
#include <components/nif/node.hpp>
|
#include <components/nif/node.hpp>
|
||||||
|
#include <components/nifcache/nifcache.hpp>
|
||||||
#include <components/misc/stringops.hpp>
|
#include <components/misc/stringops.hpp>
|
||||||
|
|
||||||
namespace NifOgre
|
namespace NifOgre
|
||||||
|
@ -83,7 +84,7 @@ void NIFSkeletonLoader::loadResource(Ogre::Resource *resource)
|
||||||
Ogre::Skeleton *skel = dynamic_cast<Ogre::Skeleton*>(resource);
|
Ogre::Skeleton *skel = dynamic_cast<Ogre::Skeleton*>(resource);
|
||||||
OgreAssert(skel, "Attempting to load a skeleton into a non-skeleton resource!");
|
OgreAssert(skel, "Attempting to load a skeleton into a non-skeleton resource!");
|
||||||
|
|
||||||
Nif::NIFFile::ptr nif(Nif::NIFFile::create(skel->getName()));
|
Nif::NIFFilePtr nif(Nif::Cache::getInstance().load(skel->getName()));
|
||||||
const Nif::Node *node = static_cast<const Nif::Node*>(nif->getRoot(0));
|
const Nif::Node *node = static_cast<const Nif::Node*>(nif->getRoot(0));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
2363
docs/Doxyfile
2363
docs/Doxyfile
File diff suppressed because it is too large
Load diff
2
extern/shiny/Main/Factory.cpp
vendored
2
extern/shiny/Main/Factory.cpp
vendored
|
@ -803,7 +803,7 @@ namespace sh
|
||||||
for (MaterialMap::iterator it = mMaterials.begin(); it != mMaterials.end(); ++it)
|
for (MaterialMap::iterator it = mMaterials.begin(); it != mMaterials.end(); ++it)
|
||||||
{
|
{
|
||||||
if (it->second.getMaterial()->isUnreferenced())
|
if (it->second.getMaterial()->isUnreferenced())
|
||||||
it->second.destroyAll();
|
it->second.getMaterial()->unreferenceTextures();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
1
extern/shiny/Main/Platform.hpp
vendored
1
extern/shiny/Main/Platform.hpp
vendored
|
@ -69,6 +69,7 @@ namespace sh
|
||||||
virtual void removeAll () = 0; ///< remove all configurations
|
virtual void removeAll () = 0; ///< remove all configurations
|
||||||
|
|
||||||
virtual bool isUnreferenced() = 0;
|
virtual bool isUnreferenced() = 0;
|
||||||
|
virtual void unreferenceTextures() = 0;
|
||||||
virtual void ensureLoaded() = 0;
|
virtual void ensureLoaded() = 0;
|
||||||
|
|
||||||
virtual void setLodLevels (const std::string& lodLevels) = 0;
|
virtual void setLodLevels (const std::string& lodLevels) = 0;
|
||||||
|
|
5
extern/shiny/Platforms/Ogre/OgreMaterial.cpp
vendored
5
extern/shiny/Platforms/Ogre/OgreMaterial.cpp
vendored
|
@ -35,6 +35,11 @@ namespace sh
|
||||||
return (!mMaterial.isNull() && mMaterial.useCount() <= Ogre::ResourceGroupManager::RESOURCE_SYSTEM_NUM_REFERENCE_COUNTS+1);
|
return (!mMaterial.isNull() && mMaterial.useCount() <= Ogre::ResourceGroupManager::RESOURCE_SYSTEM_NUM_REFERENCE_COUNTS+1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OgreMaterial::unreferenceTextures()
|
||||||
|
{
|
||||||
|
mMaterial->unload();
|
||||||
|
}
|
||||||
|
|
||||||
OgreMaterial::~OgreMaterial()
|
OgreMaterial::~OgreMaterial()
|
||||||
{
|
{
|
||||||
if (!mMaterial.isNull())
|
if (!mMaterial.isNull())
|
||||||
|
|
1
extern/shiny/Platforms/Ogre/OgreMaterial.hpp
vendored
1
extern/shiny/Platforms/Ogre/OgreMaterial.hpp
vendored
|
@ -19,6 +19,7 @@ namespace sh
|
||||||
virtual bool createConfiguration (const std::string& name, unsigned short lodIndex);
|
virtual bool createConfiguration (const std::string& name, unsigned short lodIndex);
|
||||||
|
|
||||||
virtual bool isUnreferenced();
|
virtual bool isUnreferenced();
|
||||||
|
virtual void unreferenceTextures();
|
||||||
virtual void ensureLoaded();
|
virtual void ensureLoaded();
|
||||||
|
|
||||||
virtual void removeAll ();
|
virtual void removeAll ();
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
<!-- Label -->
|
<!-- Label -->
|
||||||
<Widget type="TextBox" skin="HeaderText" position="0 0 186 18" name="LabelT" align="Left Top">
|
<Widget type="TextBox" skin="HeaderText" position="0 0 186 18" name="LabelT" align="Left Top">
|
||||||
<Property key="Caption" value="Choose a Specialization"/>
|
<Property key="Caption" value="Choose a Specialization"/>
|
||||||
<Property key="TextAlign" value="Left Top"/>
|
<Property key="TextAlign" value="HCenter Top"/>
|
||||||
</Widget>
|
</Widget>
|
||||||
|
|
||||||
<!-- Attribute list -->
|
<!-- Attribute list -->
|
||||||
|
|
|
@ -7,6 +7,9 @@
|
||||||
|
|
||||||
<Widget type="AutoSizedTextBox" skin="NormalText">
|
<Widget type="AutoSizedTextBox" skin="NormalText">
|
||||||
<Property key="Caption" value="#{sName}"/>
|
<Property key="Caption" value="#{sName}"/>
|
||||||
|
<UserString key="ToolTipType" value="Layout"/>
|
||||||
|
<UserString key="ToolTipLayout" value="TextToolTip"/>
|
||||||
|
<UserString key="Caption_Text" value="#{sEnchantmentHelp8}"/>
|
||||||
</Widget>
|
</Widget>
|
||||||
|
|
||||||
<Widget type="EditBox" skin="MW_TextEdit" position="0 0 30 30" name="NameEdit">
|
<Widget type="EditBox" skin="MW_TextEdit" position="0 0 30 30" name="NameEdit">
|
||||||
|
@ -25,6 +28,9 @@
|
||||||
|
|
||||||
<Widget type="AutoSizedTextBox" skin="NormalText">
|
<Widget type="AutoSizedTextBox" skin="NormalText">
|
||||||
<Property key="Caption" value="#{sItem}"/>
|
<Property key="Caption" value="#{sItem}"/>
|
||||||
|
<UserString key="ToolTipType" value="Layout"/>
|
||||||
|
<UserString key="ToolTipLayout" value="TextToolTip"/>
|
||||||
|
<UserString key="Caption_Text" value="#{sEnchantmentHelp1}"/>
|
||||||
</Widget>
|
</Widget>
|
||||||
<Widget type="ItemWidget" skin="MW_ItemIconBox" position="0 0 50 50" name="ItemBox">
|
<Widget type="ItemWidget" skin="MW_ItemIconBox" position="0 0 50 50" name="ItemBox">
|
||||||
</Widget>
|
</Widget>
|
||||||
|
@ -33,6 +39,9 @@
|
||||||
|
|
||||||
<Widget type="AutoSizedTextBox" skin="NormalText">
|
<Widget type="AutoSizedTextBox" skin="NormalText">
|
||||||
<Property key="Caption" value="#{sSoulGem}"/>
|
<Property key="Caption" value="#{sSoulGem}"/>
|
||||||
|
<UserString key="ToolTipType" value="Layout"/>
|
||||||
|
<UserString key="ToolTipLayout" value="TextToolTip"/>
|
||||||
|
<UserString key="Caption_Text" value="#{sEnchantmentHelp2}"/>
|
||||||
</Widget>
|
</Widget>
|
||||||
<Widget type="ItemWidget" skin="MW_ItemIconBox" position="0 0 50 50" name="SoulBox">
|
<Widget type="ItemWidget" skin="MW_ItemIconBox" position="0 0 50 50" name="SoulBox">
|
||||||
</Widget>
|
</Widget>
|
||||||
|
@ -70,6 +79,9 @@
|
||||||
<!-- Available effects -->
|
<!-- Available effects -->
|
||||||
<Widget type="TextBox" skin="NormalText" position="12 108 300 24">
|
<Widget type="TextBox" skin="NormalText" position="12 108 300 24">
|
||||||
<Property key="Caption" value="#{sMagicEffects}"/>
|
<Property key="Caption" value="#{sMagicEffects}"/>
|
||||||
|
<UserString key="ToolTipType" value="Layout"/>
|
||||||
|
<UserString key="ToolTipLayout" value="TextToolTip"/>
|
||||||
|
<UserString key="Caption_Text" value="#{sEnchantmentHelp9}"/>
|
||||||
</Widget>
|
</Widget>
|
||||||
<Widget type="MWList" skin="MW_SimpleList" position="12 136 202 209" name="AvailableEffects">
|
<Widget type="MWList" skin="MW_SimpleList" position="12 136 202 209" name="AvailableEffects">
|
||||||
</Widget>
|
</Widget>
|
||||||
|
@ -77,6 +89,9 @@
|
||||||
<!-- Used effects -->
|
<!-- Used effects -->
|
||||||
<Widget type="TextBox" skin="NormalText" position="226 108 300 24">
|
<Widget type="TextBox" skin="NormalText" position="226 108 300 24">
|
||||||
<Property key="Caption" value="#{sEffects}"/>
|
<Property key="Caption" value="#{sEffects}"/>
|
||||||
|
<UserString key="ToolTipType" value="Layout"/>
|
||||||
|
<UserString key="ToolTipLayout" value="TextToolTip"/>
|
||||||
|
<UserString key="Caption_Text" value="#{sEnchantmentHelp10}"/>
|
||||||
</Widget>
|
</Widget>
|
||||||
<Widget type="Widget" skin="MW_Box" position="226 136 316 209">
|
<Widget type="Widget" skin="MW_Box" position="226 136 316 209">
|
||||||
<Widget type="ScrollView" skin="MW_ScrollViewH" position="4 4 308 201" name="UsedEffects">
|
<Widget type="ScrollView" skin="MW_ScrollViewH" position="4 4 308 201" name="UsedEffects">
|
||||||
|
@ -89,6 +104,9 @@
|
||||||
|
|
||||||
<Widget type="AutoSizedButton" skin="MW_Button" name="TypeButton">
|
<Widget type="AutoSizedButton" skin="MW_Button" name="TypeButton">
|
||||||
<Property key="Caption" value="Constant effect"/>
|
<Property key="Caption" value="Constant effect"/>
|
||||||
|
<UserString key="ToolTipType" value="Layout"/>
|
||||||
|
<UserString key="ToolTipLayout" value="TextToolTip"/>
|
||||||
|
<UserString key="Caption_Text" value="#{sEnchantmentHelp7}"/>
|
||||||
</Widget>
|
</Widget>
|
||||||
|
|
||||||
<Widget type="Widget">
|
<Widget type="Widget">
|
||||||
|
@ -100,6 +118,9 @@
|
||||||
</Widget>
|
</Widget>
|
||||||
<Widget type="AutoSizedTextBox" skin="SandText" name="PriceLabel">
|
<Widget type="AutoSizedTextBox" skin="SandText" name="PriceLabel">
|
||||||
<Property key="Caption" value="0"/>
|
<Property key="Caption" value="0"/>
|
||||||
|
<UserString key="ToolTipType" value="Layout"/>
|
||||||
|
<UserString key="ToolTipLayout" value="TextToolTip"/>
|
||||||
|
<UserString key="Caption_Text" value="#{sEnchantmentHelp6}"/>
|
||||||
</Widget>
|
</Widget>
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -113,7 +113,7 @@
|
||||||
<State name="disabled" colour="0.70 0.57 0.33" shift="0"/>
|
<State name="disabled" colour="0.70 0.57 0.33" shift="0"/>
|
||||||
<State name="normal" colour="0.70 0.57 0.33" shift="0"/>
|
<State name="normal" colour="0.70 0.57 0.33" shift="0"/>
|
||||||
<State name="highlighted" colour="0.85 0.76 0.60" shift="0"/>
|
<State name="highlighted" colour="0.85 0.76 0.60" shift="0"/>
|
||||||
<State name="pushed" colour="0.33 0.38 0.67" shift="0"/>
|
<State name="pushed" colour="1 1 1" shift="0"/>
|
||||||
<State name="disabled_checked" colour="0.33 0.38 0.67" shift="0"/>
|
<State name="disabled_checked" colour="0.33 0.38 0.67" shift="0"/>
|
||||||
<State name="normal_checked" colour="0.33 0.38 0.67" shift="0"/>
|
<State name="normal_checked" colour="0.33 0.38 0.67" shift="0"/>
|
||||||
<State name="highlighted_checked" colour="0.33 0.38 0.67" shift="0"/>
|
<State name="highlighted_checked" colour="0.33 0.38 0.67" shift="0"/>
|
||||||
|
|
|
@ -65,6 +65,24 @@
|
||||||
</Widget>
|
</Widget>
|
||||||
</Widget>
|
</Widget>
|
||||||
|
|
||||||
|
<!-- Hand-to-hand tooltip -->
|
||||||
|
<Widget type="HBox" skin="HUD_Box_NoTransp" position="0 0 300 300" align="Stretch" name="HandToHandToolTip">
|
||||||
|
<Property key="AutoResize" value="true"/>
|
||||||
|
<Property key="Padding" value="8"/>
|
||||||
|
|
||||||
|
<Widget type="VBox">
|
||||||
|
<UserString key="VStretch" value="true"/>
|
||||||
|
<Widget type="ImageBox" skin="ImageBox" position="8 8 32 32" align="Left Top" name="HandToHandImage"/>
|
||||||
|
<Widget type="Widget">
|
||||||
|
<UserString key="VStretch" value="true"/>
|
||||||
|
</Widget>
|
||||||
|
</Widget>
|
||||||
|
|
||||||
|
<Widget type="AutoSizedTextBox" skin="SandText" position="44 8 248 284" align="Left Top" name="HandToHandText">
|
||||||
|
<Property key="TextAlign" value="Center"/>
|
||||||
|
</Widget>
|
||||||
|
</Widget>
|
||||||
|
|
||||||
<!-- Health tooltip -->
|
<!-- Health tooltip -->
|
||||||
<Widget type="HBox" skin="HUD_Box_NoTransp" position="0 0 300 300" align="Stretch" name="HealthToolTip">
|
<Widget type="HBox" skin="HUD_Box_NoTransp" position="0 0 300 300" align="Stretch" name="HealthToolTip">
|
||||||
<Property key="AutoResize" value="true"/>
|
<Property key="AutoResize" value="true"/>
|
||||||
|
|
|
@ -32,6 +32,7 @@ namespace Render
|
||||||
void SelectionBuffer::setupRenderTarget()
|
void SelectionBuffer::setupRenderTarget()
|
||||||
{
|
{
|
||||||
mRenderTarget = mTexture->getBuffer()->getRenderTarget();
|
mRenderTarget = mTexture->getBuffer()->getRenderTarget();
|
||||||
|
mRenderTarget->removeAllViewports();
|
||||||
Ogre::Viewport* vp = mRenderTarget->addViewport(mCamera);
|
Ogre::Viewport* vp = mRenderTarget->addViewport(mCamera);
|
||||||
vp->setOverlaysEnabled(false);
|
vp->setOverlaysEnabled(false);
|
||||||
vp->setBackgroundColour(Ogre::ColourValue(0, 0, 0, 0));
|
vp->setBackgroundColour(Ogre::ColourValue(0, 0, 0, 0));
|
||||||
|
@ -65,6 +66,7 @@ namespace Render
|
||||||
{
|
{
|
||||||
Ogre::MaterialManager::getSingleton ().addListener (this);
|
Ogre::MaterialManager::getSingleton ().addListener (this);
|
||||||
|
|
||||||
|
mTexture->load();
|
||||||
if (mRenderTarget == NULL)
|
if (mRenderTarget == NULL)
|
||||||
setupRenderTarget();
|
setupRenderTarget();
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue