1
0
Fork 1
mirror of https://github.com/TES3MP/openmw-tes3mp.git synced 2025-03-01 12:09:47 +00:00

Add OpenMW commits up to 22 Feb 2019

# Conflicts:
#	CMakeLists.txt
#	apps/openmw/mwmechanics/spellcasting.cpp
#	apps/openmw/mwscript/containerextensions.cpp
This commit is contained in:
David Cernat 2019-08-21 17:29:24 +03:00
commit 95a5607509
166 changed files with 6193 additions and 711 deletions

View file

@ -17,9 +17,9 @@ Debian:
# - apt-get install -y libmygui-dev libbullet-dev # to be updated to latest below because stretch is too old # - apt-get install -y libmygui-dev libbullet-dev # to be updated to latest below because stretch is too old
- curl -L http://archive.ubuntu.com/ubuntu/pool/universe/b/bullet/libbullet-dev_2.87+dfsg-2_amd64.deb -o libbullet-dev_2.87+dfsg-2_amd64.deb - curl -L http://archive.ubuntu.com/ubuntu/pool/universe/b/bullet/libbullet-dev_2.87+dfsg-2_amd64.deb -o libbullet-dev_2.87+dfsg-2_amd64.deb
- curl -L http://archive.ubuntu.com/ubuntu/pool/universe/b/bullet/libbullet2.87_2.87+dfsg-2_amd64.deb -o libbullet2.87_2.87+dfsg-2_amd64.deb - curl -L http://archive.ubuntu.com/ubuntu/pool/universe/b/bullet/libbullet2.87_2.87+dfsg-2_amd64.deb -o libbullet2.87_2.87+dfsg-2_amd64.deb
- curl -L https://http.kali.org/pool/main/m/mygui/libmygui.openglplatform0debian1v5_3.2.2+dfsg-1_amd64.deb -o libmygui.openglplatform0debian1v5_3.2.2+dfsg-1_amd64.deb - curl -L http://archive.ubuntu.com/ubuntu/pool/universe/m/mygui/libmygui.openglplatform0debian1v5_3.2.2+dfsg-1_amd64.deb -o libmygui.openglplatform0debian1v5_3.2.2+dfsg-1_amd64.deb
- curl -L https://http.kali.org/pool/main/m/mygui/libmyguiengine3debian1v5_3.2.2+dfsg-1_amd64.deb -o libmyguiengine3debian1v5_3.2.2+dfsg-1_amd64.deb - curl -L http://archive.ubuntu.com/ubuntu/pool/universe/m/mygui/libmyguiengine3debian1v5_3.2.2+dfsg-1_amd64.deb -o libmyguiengine3debian1v5_3.2.2+dfsg-1_amd64.deb
- curl -L https://http.kali.org/pool/main/m/mygui/libmygui-dev_3.2.2+dfsg-1_amd64.deb -o libmygui-dev_3.2.2+dfsg-1_amd64.deb - curl -L http://archive.ubuntu.com/ubuntu/pool/universe/m/mygui/libmygui-dev_3.2.2+dfsg-1_amd64.deb -o libmygui-dev_3.2.2+dfsg-1_amd64.deb
- dpkg --ignore-depends=libmygui.ogreplatform0debian1v5 -i *.deb - dpkg --ignore-depends=libmygui.ogreplatform0debian1v5 -i *.deb
stage: build stage: build
script: script:

View file

@ -1,9 +1,11 @@
0.46.0 0.46.0
------ ------
Bug #2969: Scripted items can stack
Bug #2987: Editor: some chance and AI data fields can overflow Bug #2987: Editor: some chance and AI data fields can overflow
Bug #3623: Fix HiDPI on Windows Bug #3623: Fix HiDPI on Windows
Bug #3733: Normal maps are inverted on mirrored UVs Bug #3733: Normal maps are inverted on mirrored UVs
Bug #3765: DisableTeleporting makes Mark/Recall/Intervention effects undetectable
Bug #4329: Removed birthsign abilities are restored after reloading the save Bug #4329: Removed birthsign abilities are restored after reloading the save
Bug #4383: Bow model obscures crosshair when arrow is drawn Bug #4383: Bow model obscures crosshair when arrow is drawn
Bug #4411: Reloading a saved game while falling prevents damage in some cases Bug #4411: Reloading a saved game while falling prevents damage in some cases
@ -15,23 +17,31 @@
Bug #4723: ResetActors command works incorrectly Bug #4723: ResetActors command works incorrectly
Bug #4745: Editor: Interior cell lighting field values are not displayed as colors Bug #4745: Editor: Interior cell lighting field values are not displayed as colors
Bug #4746: Non-solid player can't run or sneak Bug #4746: Non-solid player can't run or sneak
Bug #4747: Bones are not read from X.NIF file for NPC animation
Bug #4750: Sneaking doesn't work in first person view if the player is in attack ready state Bug #4750: Sneaking doesn't work in first person view if the player is in attack ready state
Bug #4768: Fallback numerical value recovery chokes on invalid arguments Bug #4768: Fallback numerical value recovery chokes on invalid arguments
Bug #4775: Slowfall effect resets player jumping flag Bug #4775: Slowfall effect resets player jumping flag
Bug #4778: Interiors of Illusion puzzle in Sotha Sil Expanded mod is broken Bug #4778: Interiors of Illusion puzzle in Sotha Sil Expanded mod is broken
Bug #4797: Player sneaking and running stances are not accounted for when in air
Bug #4800: Standing collisions are not updated immediately when an object is teleported without a cell change Bug #4800: Standing collisions are not updated immediately when an object is teleported without a cell change
Bug #4803: Stray special characters before begin statement break script compilation Bug #4803: Stray special characters before begin statement break script compilation
Bug #4804: Particle system with the "Has Sizes = false" causes an exception Bug #4804: Particle system with the "Has Sizes = false" causes an exception
Bug #4813: Creatures with known file but no "Sound Gen Creature" assigned use default sounds Bug #4813: Creatures with known file but no "Sound Gen Creature" assigned use default sounds
Bug #4815: "Finished" journal entry with lower index doesn't close journal, SetJournalIndex closes journal
Bug #4820: Spell absorption is broken Bug #4820: Spell absorption is broken
Bug #4827: NiUVController is handled incorrectly Bug #4827: NiUVController is handled incorrectly
Bug #4828: Potion looping effects VFX are not shown for NPCs Bug #4828: Potion looping effects VFX are not shown for NPCs
Bug #4837: CTD when a mesh with NiLODNode root node with particles is loaded
Bug #4860: Actors outside of processing range visible for one frame after spawning
Feature #2229: Improve pathfinding AI Feature #2229: Improve pathfinding AI
Feature #3442: Default values for fallbacks from ini file Feature #3442: Default values for fallbacks from ini file
Feature #3610: Option to invert X axis Feature #3610: Option to invert X axis
Feature #3980: In-game option to disable controller
Feature #4209: Editor: Faction rank sub-table
Feature #4673: Weapon sheathing Feature #4673: Weapon sheathing
Feature #4730: Native animated containers support Feature #4730: Native animated containers support
Feature #4812: Support NiSwitchNode Feature #4812: Support NiSwitchNode
Feature #4836: Daytime node switch
Task #4686: Upgrade media decoder to a more current FFmpeg API Task #4686: Upgrade media decoder to a more current FFmpeg API
0.45.0 0.45.0

View file

@ -2,7 +2,7 @@
brew update brew update
brew unlink cmake || true brew unlink cmake || true
brew install https://raw.githubusercontent.com/Homebrew/homebrew-core/a3b64391ebace30b84de8e7997665a1621c0b2c0/Formula/cmake.rb brew install https://gist.githubusercontent.com/nikolaykasyanov/f36da224bdef42025e480f99fa21a82d/raw/7dd8b5ed2750198757f81c6bc6456e03541999bd/cmake.rb
brew switch cmake 3.12.4 brew switch cmake 3.12.4
brew outdated pkgconfig || brew upgrade pkgconfig brew outdated pkgconfig || brew upgrade pkgconfig
brew install qt brew install qt

View file

@ -608,9 +608,9 @@ printf "OSG 3.4.1-scrawl... "
SUFFIX="" SUFFIX=""
fi fi
add_runtime_dlls "$(pwd)/OSG/bin/"{OpenThreads,zlib,libpng*}${SUFFIX}.dll \ add_runtime_dlls "$(pwd)/OSG/bin/"{OpenThreads,zlib,libpng*}${SUFFIX}.dll \
"$(pwd)/OSG/bin/osg"{,Animation,DB,FX,GA,Particle,Text,Util,Viewer}${SUFFIX}.dll "$(pwd)/OSG/bin/osg"{,Animation,DB,FX,GA,Particle,Text,Util,Viewer,Shadow}${SUFFIX}.dll
add_osg_dlls "$(pwd)/OSG/bin/osgPlugins-3.4.1/osgdb_"{bmp,dds,jpeg,osg,png,tga}${SUFFIX}.dll add_osg_dlls "$(pwd)/OSG/bin/osgPlugins-3.4.1/osgdb_"{bmp,dds,jpeg,osg,png,tga}${SUFFIX}.dll
add_osg_dlls "$(pwd)/OSG/bin/osgPlugins-3.4.1/osgdb_serializers_osg"{,animation,fx,ga,particle,text,util,viewer}${SUFFIX}.dll add_osg_dlls "$(pwd)/OSG/bin/osgPlugins-3.4.1/osgdb_serializers_osg"{,animation,fx,ga,particle,text,util,viewer,shadow}${SUFFIX}.dll
echo Done. echo Done.
} }
cd $DEPS cd $DEPS

View file

@ -266,7 +266,7 @@ endif()
IF(BUILD_OPENMW OR BUILD_OPENCS) IF(BUILD_OPENMW OR BUILD_OPENCS)
find_package(OpenSceneGraph 3.3.4 REQUIRED osgDB osgViewer osgText osgGA osgParticle osgUtil osgFX) find_package(OpenSceneGraph 3.3.4 REQUIRED osgDB osgViewer osgText osgGA osgParticle osgUtil osgFX osgShadow)
include_directories(${OPENSCENEGRAPH_INCLUDE_DIRS}) include_directories(${OPENSCENEGRAPH_INCLUDE_DIRS})
set(USED_OSG_PLUGINS set(USED_OSG_PLUGINS

View file

@ -84,6 +84,8 @@ namespace ESSImport
mGlobalMapState.mBounds.mMaxX = 0; mGlobalMapState.mBounds.mMaxX = 0;
mGlobalMapState.mBounds.mMinY = 0; mGlobalMapState.mBounds.mMinY = 0;
mGlobalMapState.mBounds.mMaxY = 0; mGlobalMapState.mBounds.mMaxY = 0;
mPlayerBase.blank();
} }
int generateActorId() int generateActorId()

View file

@ -530,6 +530,10 @@ namespace CSMWorld
RaceDataPtr raceData = getRaceData(npc.mRace); RaceDataPtr raceData = getRaceData(npc.mRace);
data->reset_data(id, "", false, !npc.isMale(), raceData); data->reset_data(id, "", false, !npc.isMale(), raceData);
// Add head and hair
data->setPart(ESM::PRT_Head, npc.mHead, 0);
data->setPart(ESM::PRT_Hair, npc.mHair, 0);
// Add inventory items // Add inventory items
for (auto& item : npc.mInventory.mList) for (auto& item : npc.mInventory.mList)
{ {
@ -537,10 +541,6 @@ namespace CSMWorld
std::string itemId = item.mItem.toString(); std::string itemId = item.mItem.toString();
addNpcItem(itemId, data); addNpcItem(itemId, data);
} }
// Add head and hair
data->setPart(ESM::PRT_Head, npc.mHead, 0);
data->setPart(ESM::PRT_Hair, npc.mHair, 0);
} }
void ActorAdapter::addNpcItem(const std::string& itemId, ActorDataPtr data) void ActorAdapter::addNpcItem(const std::string& itemId, ActorDataPtr data)
@ -574,6 +574,10 @@ namespace CSMWorld
partId = part.mMale; partId = part.mMale;
data->setPart(partType, partId, priority); data->setPart(partType, partId, priority);
// An another vanilla quirk: hide hairs if an item replaces Head part
if (partType == ESM::PRT_Head)
data->setPart(ESM::PRT_Hair, "", priority);
} }
}; };

View file

@ -30,6 +30,7 @@ bool CSMWorld::ColumnBase::isId (Display display)
Display_Skill, Display_Skill,
Display_Class, Display_Class,
Display_Faction, Display_Faction,
Display_Rank,
Display_Race, Display_Race,
Display_Sound, Display_Sound,
Display_Region, Display_Region,

View file

@ -46,6 +46,7 @@ namespace CSMWorld
Display_Skill, Display_Skill,
Display_Class, Display_Class,
Display_Faction, Display_Faction,
Display_Rank,
Display_Race, Display_Race,
Display_Sound, Display_Sound,
Display_Region, Display_Region,

View file

@ -234,9 +234,17 @@ namespace CSMWorld
{ ColumnId_SoundChance, "Chance" }, { ColumnId_SoundChance, "Chance" },
{ ColumnId_FactionReactions, "Reactions" }, { ColumnId_FactionReactions, "Reactions" },
{ ColumnId_FactionRanks, "Ranks" },
//{ ColumnId_FactionID, "Faction ID" }, //{ ColumnId_FactionID, "Faction ID" },
{ ColumnId_FactionReaction, "Reaction" }, { ColumnId_FactionReaction, "Reaction" },
{ ColumnId_FactionAttrib1, "Attrib 1" },
{ ColumnId_FactionAttrib2, "Attrib 2" },
{ ColumnId_FactionPrimSkill, "Prim Skill" },
{ ColumnId_FactionFavSkill, "Fav Skill" },
{ ColumnId_FactionRep, "Fact Rep" },
{ ColumnId_RankName, "Rank Name" },
{ ColumnId_EffectList, "Effects" }, { ColumnId_EffectList, "Effects" },
{ ColumnId_EffectId, "Effect" }, { ColumnId_EffectId, "Effect" },
//{ ColumnId_EffectAttribute, "Attrib" }, //{ ColumnId_EffectAttribute, "Attrib" },

View file

@ -338,6 +338,14 @@ namespace CSMWorld
ColumnId_LandColoursIndex = 304, ColumnId_LandColoursIndex = 304,
ColumnId_LandTexturesIndex = 305, ColumnId_LandTexturesIndex = 305,
ColumnId_RankName = 306,
ColumnId_FactionRanks = 307,
ColumnId_FactionPrimSkill = 308,
ColumnId_FactionFavSkill = 309,
ColumnId_FactionRep = 310,
ColumnId_FactionAttrib1 = 311,
ColumnId_FactionAttrib2 = 312,
// Allocated to a separate value range, so we don't get a collision should we ever need // Allocated to a separate value range, so we don't get a collision should we ever need
// to extend the number of use values. // to extend the number of use values.
ColumnId_UseValue1 = 0x10000, ColumnId_UseValue1 = 0x10000,

View file

@ -132,6 +132,23 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, bool fsStrict, const Files::Pat
mFactions.getNestableColumn(index)->addColumn( mFactions.getNestableColumn(index)->addColumn(
new NestedChildColumn (Columns::ColumnId_FactionReaction, ColumnBase::Display_Integer)); new NestedChildColumn (Columns::ColumnId_FactionReaction, ColumnBase::Display_Integer));
// Faction Ranks
mFactions.addColumn (new NestedParentColumn<ESM::Faction> (Columns::ColumnId_FactionRanks));
index = mFactions.getColumns()-1;
mFactions.addAdapter (std::make_pair(&mFactions.getColumn(index), new FactionRanksAdapter ()));
mFactions.getNestableColumn(index)->addColumn(
new NestedChildColumn (Columns::ColumnId_RankName, ColumnBase::Display_Rank));
mFactions.getNestableColumn(index)->addColumn(
new NestedChildColumn (Columns::ColumnId_FactionAttrib1, ColumnBase::Display_Integer));
mFactions.getNestableColumn(index)->addColumn(
new NestedChildColumn (Columns::ColumnId_FactionAttrib2, ColumnBase::Display_Integer));
mFactions.getNestableColumn(index)->addColumn(
new NestedChildColumn (Columns::ColumnId_FactionPrimSkill, ColumnBase::Display_Integer));
mFactions.getNestableColumn(index)->addColumn(
new NestedChildColumn (Columns::ColumnId_FactionFavSkill, ColumnBase::Display_Integer));
mFactions.getNestableColumn(index)->addColumn(
new NestedChildColumn (Columns::ColumnId_FactionRep, ColumnBase::Display_Integer));
mRaces.addColumn (new StringIdColumn<ESM::Race>); mRaces.addColumn (new StringIdColumn<ESM::Race>);
mRaces.addColumn (new RecordStateColumn<ESM::Race>); mRaces.addColumn (new RecordStateColumn<ESM::Race>);
mRaces.addColumn (new FixedRecordTypeColumn<ESM::Race> (UniversalId::Type_Race)); mRaces.addColumn (new FixedRecordTypeColumn<ESM::Race> (UniversalId::Type_Race));

View file

@ -1090,4 +1090,83 @@ namespace CSMWorld
{ {
return 10; return 10;
} }
FactionRanksAdapter::FactionRanksAdapter () {}
void FactionRanksAdapter::addRow(Record<ESM::Faction>& record, int position) const
{
throw std::logic_error ("cannot add a row to a fixed table");
}
void FactionRanksAdapter::removeRow(Record<ESM::Faction>& record, int rowToRemove) const
{
throw std::logic_error ("cannot remove a row from a fixed table");
}
void FactionRanksAdapter::setTable(Record<ESM::Faction>& record,
const NestedTableWrapperBase& nestedTable) const
{
throw std::logic_error ("table operation not supported");
}
NestedTableWrapperBase* FactionRanksAdapter::table(const Record<ESM::Faction>& record) const
{
throw std::logic_error ("table operation not supported");
}
QVariant FactionRanksAdapter::getData(const Record<ESM::Faction>& record,
int subRowIndex, int subColIndex) const
{
ESM::Faction faction = record.get();
if (subRowIndex < 0 || subRowIndex >= static_cast<int>(sizeof(faction.mData.mRankData)/sizeof(faction.mData.mRankData[0])))
throw std::runtime_error ("index out of range");
auto& rankData = faction.mData.mRankData[subRowIndex];
switch (subColIndex)
{
case 0: return QString(faction.mRanks[subRowIndex].c_str());
case 1: return rankData.mAttribute1;
case 2: return rankData.mAttribute2;
case 3: return rankData.mSkill1;
case 4: return rankData.mSkill2;
case 5: return rankData.mFactReaction;
default: throw std::runtime_error("Rank subcolumn index out of range");
}
}
void FactionRanksAdapter::setData(Record<ESM::Faction>& record,
const QVariant& value, int subRowIndex, int subColIndex) const
{
ESM::Faction faction = record.get();
if (subRowIndex < 0 || subRowIndex >= static_cast<int>(sizeof(faction.mData.mRankData)/sizeof(faction.mData.mRankData[0])))
throw std::runtime_error ("index out of range");
auto& rankData = faction.mData.mRankData[subRowIndex];
switch (subColIndex)
{
case 0: faction.mRanks[subRowIndex] = value.toString().toUtf8().constData(); break;
case 1: rankData.mAttribute1 = value.toInt(); break;
case 2: rankData.mAttribute2 = value.toInt(); break;
case 3: rankData.mSkill1 = value.toInt(); break;
case 4: rankData.mSkill2 = value.toInt(); break;
case 5: rankData.mFactReaction = value.toInt(); break;
default: throw std::runtime_error("Rank index out of range");
}
record.setModified (faction);
}
int FactionRanksAdapter::getColumnsCount(const Record<ESM::Faction>& record) const
{
return 6;
}
int FactionRanksAdapter::getRowsCount(const Record<ESM::Faction>& record) const
{
return 10;
}
} }

View file

@ -100,6 +100,31 @@ namespace CSMWorld
virtual int getRowsCount(const Record<ESM::Faction>& record) const; virtual int getRowsCount(const Record<ESM::Faction>& record) const;
}; };
class FactionRanksAdapter : public NestedColumnAdapter<ESM::Faction>
{
public:
FactionRanksAdapter ();
virtual void addRow(Record<ESM::Faction>& record, int position) const;
virtual void removeRow(Record<ESM::Faction>& record, int rowToRemove) const;
virtual void setTable(Record<ESM::Faction>& record,
const NestedTableWrapperBase& nestedTable) const;
virtual NestedTableWrapperBase* table(const Record<ESM::Faction>& record) const;
virtual QVariant getData(const Record<ESM::Faction>& record,
int subRowIndex, int subColIndex) const;
virtual void setData(Record<ESM::Faction>& record,
const QVariant& value, int subRowIndex, int subColIndex) const;
virtual int getColumnsCount(const Record<ESM::Faction>& record) const;
virtual int getRowsCount(const Record<ESM::Faction>& record) const;
};
class RegionSoundListAdapter : public NestedColumnAdapter<ESM::Region> class RegionSoundListAdapter : public NestedColumnAdapter<ESM::Region>
{ {
public: public:

View file

@ -1,5 +1,38 @@
#include "lighting.hpp" #include "lighting.hpp"
#include <osg/LightSource> #include <osg/LightSource>
#include <osg/NodeVisitor>
#include <osg/Switch>
#include <components/misc/constants.hpp>
class DayNightSwitchVisitor : public osg::NodeVisitor
{
public:
DayNightSwitchVisitor(int index)
: osg::NodeVisitor(TRAVERSE_ALL_CHILDREN)
, mIndex(index)
{ }
virtual void apply(osg::Switch &switchNode)
{
if (switchNode.getName() == Constants::NightDayLabel)
switchNode.setSingleChildOn(mIndex);
traverse(switchNode);
}
private:
int mIndex;
};
CSVRender::Lighting::~Lighting() {} CSVRender::Lighting::~Lighting() {}
void CSVRender::Lighting::updateDayNightMode(int index)
{
if (mRootNode == nullptr)
return;
DayNightSwitchVisitor visitor(index);
mRootNode->accept(visitor);
}

View file

@ -19,7 +19,7 @@ namespace CSVRender
Lighting() : mRootNode(0) {} Lighting() : mRootNode(0) {}
virtual ~Lighting(); virtual ~Lighting();
virtual void activate (osg::Group* rootNode) = 0; virtual void activate (osg::Group* rootNode, bool isExterior) = 0;
virtual void deactivate() = 0; virtual void deactivate() = 0;
@ -27,6 +27,8 @@ namespace CSVRender
protected: protected:
void updateDayNightMode(int index);
osg::ref_ptr<osg::LightSource> mLightSource; osg::ref_ptr<osg::LightSource> mLightSource;
osg::Group* mRootNode; osg::Group* mRootNode;
}; };

View file

@ -4,7 +4,7 @@
CSVRender::LightingBright::LightingBright() {} CSVRender::LightingBright::LightingBright() {}
void CSVRender::LightingBright::activate (osg::Group* rootNode) void CSVRender::LightingBright::activate (osg::Group* rootNode, bool /*isExterior*/)
{ {
mRootNode = rootNode; mRootNode = rootNode;
@ -20,6 +20,8 @@ void CSVRender::LightingBright::activate (osg::Group* rootNode)
mLightSource->setLight(light); mLightSource->setLight(light);
mRootNode->addChild(mLightSource); mRootNode->addChild(mLightSource);
updateDayNightMode(0);
} }
void CSVRender::LightingBright::deactivate() void CSVRender::LightingBright::deactivate()

View file

@ -17,7 +17,7 @@ namespace CSVRender
LightingBright(); LightingBright();
virtual void activate (osg::Group* rootNode); virtual void activate (osg::Group* rootNode, bool /*isExterior*/);
virtual void deactivate(); virtual void deactivate();

View file

@ -4,7 +4,7 @@
CSVRender::LightingDay::LightingDay(){} CSVRender::LightingDay::LightingDay(){}
void CSVRender::LightingDay::activate (osg::Group* rootNode) void CSVRender::LightingDay::activate (osg::Group* rootNode, bool /*isExterior*/)
{ {
mRootNode = rootNode; mRootNode = rootNode;
@ -19,6 +19,8 @@ void CSVRender::LightingDay::activate (osg::Group* rootNode)
mLightSource->setLight(light); mLightSource->setLight(light);
mRootNode->addChild(mLightSource); mRootNode->addChild(mLightSource);
updateDayNightMode(0);
} }
void CSVRender::LightingDay::deactivate() void CSVRender::LightingDay::deactivate()

View file

@ -11,7 +11,7 @@ namespace CSVRender
LightingDay(); LightingDay();
virtual void activate (osg::Group* rootNode); virtual void activate (osg::Group* rootNode, bool /*isExterior*/);
virtual void deactivate(); virtual void deactivate();

View file

@ -4,7 +4,7 @@
CSVRender::LightingNight::LightingNight() {} CSVRender::LightingNight::LightingNight() {}
void CSVRender::LightingNight::activate (osg::Group* rootNode) void CSVRender::LightingNight::activate (osg::Group* rootNode, bool isExterior)
{ {
mRootNode = rootNode; mRootNode = rootNode;
@ -20,6 +20,8 @@ void CSVRender::LightingNight::activate (osg::Group* rootNode)
mLightSource->setLight(light); mLightSource->setLight(light);
mRootNode->addChild(mLightSource); mRootNode->addChild(mLightSource);
updateDayNightMode(isExterior ? 1 : 0);
} }
void CSVRender::LightingNight::deactivate() void CSVRender::LightingNight::deactivate()

View file

@ -11,7 +11,7 @@ namespace CSVRender
LightingNight(); LightingNight();
virtual void activate (osg::Group* rootNode); virtual void activate (osg::Group* rootNode, bool isExterior);
virtual void deactivate(); virtual void deactivate();
virtual osg::Vec4f getAmbientColour(osg::Vec4f *defaultAmbient); virtual osg::Vec4f getAmbientColour(osg::Vec4f *defaultAmbient);

View file

@ -20,6 +20,8 @@ CSVRender::PreviewWidget::PreviewWidget (CSMWorld::Data& data,
connect (&mData, SIGNAL (assetTablesChanged ()), connect (&mData, SIGNAL (assetTablesChanged ()),
this, SLOT (assetTablesChanged ())); this, SLOT (assetTablesChanged ()));
setExterior(false);
if (!referenceable) if (!referenceable)
{ {
QAbstractItemModel *references = QAbstractItemModel *references =

View file

@ -195,6 +195,7 @@ SceneWidget::SceneWidget(std::shared_ptr<Resource::ResourceSystem> resourceSyste
, mResourceSystem(resourceSystem) , mResourceSystem(resourceSystem)
, mLighting(nullptr) , mLighting(nullptr)
, mHasDefaultAmbient(false) , mHasDefaultAmbient(false)
, mIsExterior(true)
, mPrevMouseX(0) , mPrevMouseX(0)
, mPrevMouseY(0) , mPrevMouseY(0)
, mCamPositionSet(false) , mCamPositionSet(false)
@ -250,7 +251,7 @@ void SceneWidget::setLighting(Lighting *lighting)
mLighting->deactivate(); mLighting->deactivate();
mLighting = lighting; mLighting = lighting;
mLighting->activate (mRootNode); mLighting->activate (mRootNode, mIsExterior);
osg::Vec4f ambient = mLighting->getAmbientColour(mHasDefaultAmbient ? &mDefaultAmbient : 0); osg::Vec4f ambient = mLighting->getAmbientColour(mHasDefaultAmbient ? &mDefaultAmbient : 0);
setAmbient(ambient); setAmbient(ambient);
@ -315,6 +316,11 @@ void SceneWidget::setDefaultAmbient (const osg::Vec4f& colour)
setAmbient(mLighting->getAmbientColour(&mDefaultAmbient)); setAmbient(mLighting->getAmbientColour(&mDefaultAmbient));
} }
void SceneWidget::setExterior (bool isExterior)
{
mIsExterior = isExterior;
}
void SceneWidget::mouseMoveEvent (QMouseEvent *event) void SceneWidget::mouseMoveEvent (QMouseEvent *event)
{ {
mCurrentCamControl->handleMouseMoveEvent(event->x() - mPrevMouseX, event->y() - mPrevMouseY); mCurrentCamControl->handleMouseMoveEvent(event->x() - mPrevMouseX, event->y() - mPrevMouseY);

View file

@ -89,6 +89,8 @@ namespace CSVRender
void setDefaultAmbient (const osg::Vec4f& colour); void setDefaultAmbient (const osg::Vec4f& colour);
///< \note The actual ambient colour may differ based on lighting settings. ///< \note The actual ambient colour may differ based on lighting settings.
void setExterior (bool isExterior);
protected: protected:
void setLighting (Lighting *lighting); void setLighting (Lighting *lighting);
///< \attention The ownership of \a lighting is not transferred to *this. ///< \attention The ownership of \a lighting is not transferred to *this.
@ -104,6 +106,7 @@ namespace CSVRender
osg::Vec4f mDefaultAmbient; osg::Vec4f mDefaultAmbient;
bool mHasDefaultAmbient; bool mHasDefaultAmbient;
bool mIsExterior;
LightingDay mLightingDay; LightingDay mLightingDay;
LightingNight mLightingNight; LightingNight mLightingNight;
LightingBright mLightingBright; LightingBright mLightingBright;

View file

@ -28,6 +28,11 @@ void CSVRender::UnpagedWorldspaceWidget::update()
setDefaultAmbient (colour); setDefaultAmbient (colour);
bool isInterior = (record.get().mData.mFlags & ESM::Cell::Interior) != 0;
bool behaveLikeExterior = (record.get().mData.mFlags & ESM::Cell::QuasiEx) != 0;
setExterior(behaveLikeExterior || !isInterior);
/// \todo deal with mSunlight and mFog/mForDensity /// \todo deal with mSunlight and mFog/mForDensity
flagAsModified(); flagAsModified();

View file

@ -82,6 +82,7 @@ void CSVWidget::ColorEditor::setColor(const int colorInt)
void CSVWidget::ColorEditor::showPicker() void CSVWidget::ColorEditor::showPicker()
{ {
mColorPicker->showPicker(calculatePopupPosition(), mColor); mColorPicker->showPicker(calculatePopupPosition(), mColor);
emit pickingFinished();
} }
void CSVWidget::ColorEditor::pickerColorChanged(const QColor &color) void CSVWidget::ColorEditor::pickerColorChanged(const QColor &color)

View file

@ -39,7 +39,8 @@ void CSVWidget::ColorPickerPopup::showPicker(const QPoint &position, const QColo
// Calling getColor() creates a blocking dialog that will continue execution once the user chooses OK or Cancel // Calling getColor() creates a blocking dialog that will continue execution once the user chooses OK or Cancel
QColor color = mColorPicker->getColor(initialColor); QColor color = mColorPicker->getColor(initialColor);
mColorPicker->setCurrentColor(color); if (color.isValid())
mColorPicker->setCurrentColor(color);
} }
void CSVWidget::ColorPickerPopup::mousePressEvent(QMouseEvent *event) void CSVWidget::ColorPickerPopup::mousePressEvent(QMouseEvent *event)

View file

@ -170,6 +170,7 @@ target_link_libraries(tes3mp
${OSGDB_LIBRARIES} ${OSGDB_LIBRARIES}
${OSGVIEWER_LIBRARIES} ${OSGVIEWER_LIBRARIES}
${OSGGA_LIBRARIES} ${OSGGA_LIBRARIES}
${OSGSHADOW_LIBRARIES}
${Boost_SYSTEM_LIBRARY} ${Boost_SYSTEM_LIBRARY}
${Boost_THREAD_LIBRARY} ${Boost_THREAD_LIBRARY}
${Boost_FILESYSTEM_LIBRARY} ${Boost_FILESYSTEM_LIBRARY}

View file

@ -369,6 +369,9 @@ OMW::Engine::~Engine()
mViewer = nullptr; mViewer = nullptr;
delete mEncoder;
mEncoder = nullptr;
if (mWindow) if (mWindow)
{ {
SDL_DestroyWindow(mWindow); SDL_DestroyWindow(mWindow);
@ -789,8 +792,7 @@ void OMW::Engine::go()
settingspath = loadSettings (settings); settingspath = loadSettings (settings);
// Create encoder // Create encoder
ToUTF8::Utf8Encoder encoder (mEncoding); mEncoder = new ToUTF8::Utf8Encoder(mEncoding);
mEncoder = &encoder;
// Setup viewer // Setup viewer
mViewer = new osgViewer::Viewer; mViewer = new osgViewer::Viewer;

View file

@ -58,7 +58,7 @@ namespace MWMechanics
namespace DetourNavigator namespace DetourNavigator
{ {
class Navigator; struct Navigator;
} }
namespace MWWorld namespace MWWorld
@ -332,6 +332,8 @@ namespace MWBase
virtual int getCurrentWeather() const = 0; virtual int getCurrentWeather() const = 0;
virtual unsigned int getNightDayMode() const = 0;
virtual int getMasserPhase() const = 0; virtual int getMasserPhase() const = 0;
virtual int getSecundaPhase() const = 0; virtual int getSecundaPhase() const = 0;
@ -458,7 +460,7 @@ namespace MWBase
virtual bool castRay (float x1, float y1, float z1, float x2, float y2, float z2) = 0; virtual bool castRay (float x1, float y1, float z1, float x2, float y2, float z2) = 0;
virtual void setActorCollisionMode(const MWWorld::Ptr& ptr, bool enabled) = 0; virtual void setActorCollisionMode(const MWWorld::Ptr& ptr, bool internal, bool external) = 0;
virtual bool isActorCollisionEnabled(const MWWorld::Ptr& ptr) = 0; virtual bool isActorCollisionEnabled(const MWWorld::Ptr& ptr) = 0;
virtual bool toggleCollisionMode() = 0; virtual bool toggleCollisionMode() = 0;

View file

@ -895,7 +895,7 @@ namespace MWClass
MWWorld::Ptr armor = ((armorslot != inv.end()) ? *armorslot : MWWorld::Ptr()); MWWorld::Ptr armor = ((armorslot != inv.end()) ? *armorslot : MWWorld::Ptr());
if(!armor.isEmpty() && armor.getTypeName() == typeid(ESM::Armor).name()) if(!armor.isEmpty() && armor.getTypeName() == typeid(ESM::Armor).name())
{ {
if (attacker.isEmpty() || (!attacker.isEmpty() && !(object.isEmpty() && !attacker.getClass().isNpc()))) // Unarmed creature attacks don't affect armor condition if (!object.isEmpty() || attacker.isEmpty() || attacker.getClass().isNpc()) // Unarmed creature attacks don't affect armor condition
{ {
int armorhealth = armor.getClass().getItemHealth(armor); int armorhealth = armor.getClass().getItemHealth(armor);
armorhealth -= std::min(damageDiff, armorhealth); armorhealth -= std::min(damageDiff, armorhealth);
@ -1120,8 +1120,12 @@ namespace MWClass
const float normalizedEncumbrance = getNormalizedEncumbrance(ptr); const float normalizedEncumbrance = getNormalizedEncumbrance(ptr);
bool sneaking = MWBase::Environment::get().getMechanicsManager()->isSneaking(ptr) && stats.getStance(MWMechanics::CreatureStats::Stance_Sneak); bool swimming = world->isSwimming(ptr);
bool running = MWBase::Environment::get().getMechanicsManager()->isRunning(ptr) && stats.getStance(MWMechanics::CreatureStats::Stance_Run); bool inair = !world->isOnGround(ptr) && !swimming && !world->isFlying(ptr);
bool sneaking = stats.getStance(MWMechanics::CreatureStats::Stance_Sneak);
sneaking = sneaking && (inair || MWBase::Environment::get().getMechanicsManager()->isSneaking(ptr));
bool running = stats.getStance(MWMechanics::CreatureStats::Stance_Run);
running = running && (inair || MWBase::Environment::get().getMechanicsManager()->isRunning(ptr));
float walkSpeed = gmst.fMinWalkSpeed->mValue.getFloat() + 0.01f*npcdata->mNpcStats.getAttribute(ESM::Attribute::Speed).getModified()* float walkSpeed = gmst.fMinWalkSpeed->mValue.getFloat() + 0.01f*npcdata->mNpcStats.getAttribute(ESM::Attribute::Speed).getModified()*
(gmst.fMaxWalkSpeed->mValue.getFloat() - gmst.fMinWalkSpeed->mValue.getFloat()); (gmst.fMaxWalkSpeed->mValue.getFloat() - gmst.fMinWalkSpeed->mValue.getFloat());
@ -1146,7 +1150,7 @@ namespace MWClass
flySpeed = std::max(0.0f, flySpeed); flySpeed = std::max(0.0f, flySpeed);
moveSpeed = flySpeed; moveSpeed = flySpeed;
} }
else if (world->isSwimming(ptr)) else if (swimming)
{ {
float swimSpeed = walkSpeed; float swimSpeed = walkSpeed;
if(running) if(running)
@ -1156,7 +1160,7 @@ namespace MWClass
gmst.fSwimRunAthleticsMult->mValue.getFloat(); gmst.fSwimRunAthleticsMult->mValue.getFloat();
moveSpeed = swimSpeed; moveSpeed = swimSpeed;
} }
else if (running) else if (running && !sneaking)
moveSpeed = runSpeed; moveSpeed = runSpeed;
else else
moveSpeed = walkSpeed; moveSpeed = walkSpeed;

View file

@ -41,19 +41,6 @@ namespace MWDialogue
void Quest::setIndex (int index) void Quest::setIndex (int index)
{ {
const ESM::Dialogue *dialogue =
MWBase::Environment::get().getWorld()->getStore().get<ESM::Dialogue>().find (mTopic);
for (ESM::Dialogue::InfoContainer::const_iterator iter (dialogue->mInfo.begin());
iter!=dialogue->mInfo.end(); ++iter)
if (iter->mData.mDisposition==index && iter->mQuestStatus!=ESM::DialInfo::QS_Name)
{
if (iter->mQuestStatus==ESM::DialInfo::QS_Finished)
mFinished = true;
else if (iter->mQuestStatus==ESM::DialInfo::QS_Restart)
mFinished = false;
}
// The index must be set even if no related journal entry was found // The index must be set even if no related journal entry was found
mIndex = index; mIndex = index;
} }
@ -81,8 +68,18 @@ namespace MWDialogue
if (index==-1) if (index==-1)
throw std::runtime_error ("unknown journal entry for topic " + mTopic); throw std::runtime_error ("unknown journal entry for topic " + mTopic);
for (auto &info : dialogue->mInfo)
{
if (info.mData.mJournalIndex == index
&& (info.mQuestStatus == ESM::DialInfo::QS_Finished || info.mQuestStatus == ESM::DialInfo::QS_Restart))
{
mFinished = (info.mQuestStatus == ESM::DialInfo::QS_Finished);
break;
}
}
if (index > mIndex) if (index > mIndex)
setIndex (index); mIndex = index;
for (TEntryIter iter (mEntries.begin()); iter!=mEntries.end(); ++iter) for (TEntryIter iter (mEntries.begin()); iter!=mEntries.end(); ++iter)
if (iter->mInfoId==entry.mInfoId) if (iter->mInfoId==entry.mInfoId)

View file

@ -9,7 +9,10 @@
#include <components/widgets/list.hpp> #include <components/widgets/list.hpp>
#include <components/settings/settings.hpp> #include <components/settings/settings.hpp>
#include "../mwbase/environment.hpp"
#include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/mechanicsmanager.hpp"
#include "../mwbase/world.hpp"
#include "../mwworld/class.hpp" #include "../mwworld/class.hpp"
#include "../mwworld/containerstore.hpp" #include "../mwworld/containerstore.hpp"
#include "../mwworld/esmstore.hpp" #include "../mwworld/esmstore.hpp"

View file

@ -302,7 +302,7 @@ namespace MWGui
if (mode == GM_Console) if (mode == GM_Console)
MWBase::Environment::get().getWindowManager()->setConsoleSelectedObject(object); MWBase::Environment::get().getWindowManager()->setConsoleSelectedObject(object);
else if ((mode == GM_Container) || (mode == GM_Inventory)) else //if ((mode == GM_Container) || (mode == GM_Inventory))
{ {
// pick up object // pick up object
if (!object.isEmpty()) if (!object.isEmpty())

View file

@ -554,7 +554,7 @@ namespace
mQuestMode = true; mQuestMode = true;
setVisible (LeftTopicIndex, false); setVisible (LeftTopicIndex, false);
setVisible (CenterTopicIndex, true); setVisible (CenterTopicIndex, false);
setVisible (RightTopicIndex, false); setVisible (RightTopicIndex, false);
setVisible (TopicsList, false); setVisible (TopicsList, false);
setVisible (QuestsList, true); setVisible (QuestsList, true);
@ -631,7 +631,7 @@ namespace
if (page+2 < book->pageCount()) if (page+2 < book->pageCount())
{ {
MWBase::Environment::get().getWindowManager()->playSound("book page", true); MWBase::Environment::get().getWindowManager()->playSound("book page");
page += 2; page += 2;
updateShowingPages (); updateShowingPages ();
@ -649,7 +649,7 @@ namespace
if(page >= 2) if(page >= 2)
{ {
MWBase::Environment::get().getWindowManager()->playSound("book page", true); MWBase::Environment::get().getWindowManager()->playSound("book page");
page -= 2; page -= 2;
updateShowingPages (); updateShowingPages ();

View file

@ -327,11 +327,9 @@ namespace MWGui
addGroup(MWBase::Environment::get().getWindowManager()->getGameSettingString(titleId, titleDefault), coord1, coord2); addGroup(MWBase::Environment::get().getWindowManager()->getGameSettingString(titleId, titleDefault), coord1, coord2);
SkillList::const_iterator end = skills.end(); for (const int& skillId : skills)
for (SkillList::const_iterator it = skills.begin(); it != end; ++it)
{ {
int skillId = *it; if (skillId < 0 || skillId >= ESM::Skill::Length) // Skip unknown skill indexes
if (skillId < 0 || skillId > ESM::Skill::Length) // Skip unknown skill indexes
continue; continue;
assert(skillId >= 0 && skillId < ESM::Skill::Length); assert(skillId >= 0 && skillId < ESM::Skill::Length);
const std::string &skillNameId = ESM::Skill::sSkillNameIds[skillId]; const std::string &skillNameId = ESM::Skill::sSkillNameIds[skillId];

View file

@ -4,7 +4,10 @@
#include "windowbase.hpp" #include "windowbase.hpp"
#include "referenceinterface.hpp" #include "referenceinterface.hpp"
#include "../mwworld/esmstore.hpp" namespace ESM
{
struct Spell;
}
namespace MyGUI namespace MyGUI
{ {
@ -17,7 +20,6 @@ namespace MWGui
class WindowManager; class WindowManager;
} }
namespace MWGui namespace MWGui
{ {
class SpellBuyingWindow : public ReferenceInterface, public WindowBase class SpellBuyingWindow : public ReferenceInterface, public WindowBase

View file

@ -41,7 +41,7 @@ namespace MWGui
else if (skill < ESM::Skill::Length) else if (skill < ESM::Skill::Length)
setSkillId(static_cast<ESM::Skill::SkillEnum>(skill)); setSkillId(static_cast<ESM::Skill::SkillEnum>(skill));
else else
throw new std::runtime_error("Skill number out of range"); throw std::runtime_error("Skill number out of range");
} }
void MWSkill::setSkillValue(const SkillValue& value) void MWSkill::setSkillValue(const SkillValue& value)

View file

@ -66,6 +66,7 @@
#include "../mwbase/inputmanager.hpp" #include "../mwbase/inputmanager.hpp"
#include "../mwbase/statemanager.hpp" #include "../mwbase/statemanager.hpp"
#include "../mwbase/soundmanager.hpp" #include "../mwbase/soundmanager.hpp"
#include "../mwbase/world.hpp"
#include "../mwrender/vismask.hpp" #include "../mwrender/vismask.hpp"

View file

@ -67,6 +67,7 @@ namespace MWInput
, mInvertX (Settings::Manager::getBool("invert x axis", "Input")) , mInvertX (Settings::Manager::getBool("invert x axis", "Input"))
, mInvertY (Settings::Manager::getBool("invert y axis", "Input")) , mInvertY (Settings::Manager::getBool("invert y axis", "Input"))
, mControlsDisabled(false) , mControlsDisabled(false)
, mJoystickEnabled (Settings::Manager::getBool("enable controller", "Input"))
, mCameraSensitivity (Settings::Manager::getFloat("camera sensitivity", "Input")) , mCameraSensitivity (Settings::Manager::getFloat("camera sensitivity", "Input"))
, mCameraYMultiplier (Settings::Manager::getFloat("camera y multiplier", "Input")) , mCameraYMultiplier (Settings::Manager::getFloat("camera y multiplier", "Input"))
, mPreviewPOVDelay(0.f) , mPreviewPOVDelay(0.f)
@ -671,6 +672,9 @@ namespace MWInput
if (it->first == "Input" && it->second == "grab cursor") if (it->first == "Input" && it->second == "grab cursor")
mGrabCursor = Settings::Manager::getBool("grab cursor", "Input"); mGrabCursor = Settings::Manager::getBool("grab cursor", "Input");
if (it->first == "Input" && it->second == "enable controller")
mJoystickEnabled = Settings::Manager::getBool("enable controller", "Input");
if (it->first == "Video" && ( if (it->first == "Video" && (
it->second == "resolution x" it->second == "resolution x"
|| it->second == "resolution y" || it->second == "resolution y"
@ -871,6 +875,9 @@ namespace MWInput
void InputManager::buttonPressed(int deviceID, const SDL_ControllerButtonEvent &arg ) void InputManager::buttonPressed(int deviceID, const SDL_ControllerButtonEvent &arg )
{ {
if (!mJoystickEnabled)
return;
mJoystickLastUsed = true; mJoystickLastUsed = true;
bool guiMode = false; bool guiMode = false;
@ -905,6 +912,9 @@ namespace MWInput
void InputManager::buttonReleased(int deviceID, const SDL_ControllerButtonEvent &arg ) void InputManager::buttonReleased(int deviceID, const SDL_ControllerButtonEvent &arg )
{ {
if (!mJoystickEnabled)
return;
mJoystickLastUsed = true; mJoystickLastUsed = true;
if(mInputBinder->detectingBindingState()) if(mInputBinder->detectingBindingState())
mInputBinder->buttonReleased(deviceID, arg); mInputBinder->buttonReleased(deviceID, arg);
@ -928,7 +938,7 @@ namespace MWInput
void InputManager::axisMoved(int deviceID, const SDL_ControllerAxisEvent &arg ) void InputManager::axisMoved(int deviceID, const SDL_ControllerAxisEvent &arg )
{ {
if (!mControlsDisabled) if (!mControlsDisabled && mJoystickEnabled)
mInputBinder->axisMoved(deviceID, arg); mInputBinder->axisMoved(deviceID, arg);
} }

View file

@ -179,6 +179,7 @@ namespace MWInput
bool mInvertY; bool mInvertY;
bool mControlsDisabled; bool mControlsDisabled;
bool mJoystickEnabled;
float mCameraSensitivity; float mCameraSensitivity;
float mCameraYMultiplier; float mCameraYMultiplier;

View file

@ -1,13 +1,11 @@
#include "actors.hpp" #include "actors.hpp"
#include <typeinfo>
#include <iostream>
#include <components/esm/esmreader.hpp> #include <components/esm/esmreader.hpp>
#include <components/esm/esmwriter.hpp> #include <components/esm/esmwriter.hpp>
#include <components/esm/loadnpc.hpp>
#include <components/sceneutil/positionattitudetransform.hpp> #include <components/sceneutil/positionattitudetransform.hpp>
#include <components/debug/debuglog.hpp> #include <components/debug/debuglog.hpp>
#include <components/misc/rng.hpp>
#include <components/settings/settings.hpp> #include <components/settings/settings.hpp>
/* /*
@ -43,6 +41,8 @@
#include "../mwmechanics/aibreathe.hpp" #include "../mwmechanics/aibreathe.hpp"
#include "../mwrender/vismask.hpp"
#include "spellcasting.hpp" #include "spellcasting.hpp"
#include "npcstats.hpp" #include "npcstats.hpp"
#include "creaturestats.hpp" #include "creaturestats.hpp"
@ -379,6 +379,33 @@ namespace MWMechanics
} }
} }
void Actors::playIdleDialogue(const MWWorld::Ptr& actor)
{
if (!actor.getClass().isActor() || actor == getPlayer() || !MWBase::Environment::get().getSoundManager()->sayDone(actor))
return;
const CreatureStats &stats = actor.getClass().getCreatureStats(actor);
if (stats.getAiSetting(CreatureStats::AI_Hello).getModified() == 0)
return;
const MWMechanics::AiSequence& seq = stats.getAiSequence();
if (seq.isInCombat() || seq.hasPackage(AiPackage::TypeIdFollow) || seq.hasPackage(AiPackage::TypeIdEscort))
return;
const osg::Vec3f playerPos(getPlayer().getRefData().getPosition().asVec3());
const osg::Vec3f actorPos(actor.getRefData().getPosition().asVec3());
MWBase::World* world = MWBase::Environment::get().getWorld();
if (world->isSwimming(actor) || (playerPos - actorPos).length2() >= 3000 * 3000)
return;
// Our implementation is not FPS-dependent unlike Morrowind's so it needs to be recalibrated.
// We chose to use the chance MW would have when run at 60 FPS with the default value of the GMST.
const float delta = MWBase::Environment::get().getFrameDuration() * 6.f;
static const float fVoiceIdleOdds = world->getStore().get<ESM::GameSetting>().find("fVoiceIdleOdds")->mValue.getFloat();
if (Misc::Rng::rollProbability() * 10000.f < fVoiceIdleOdds * delta && world->getLOS(getPlayer(), actor))
MWBase::Environment::get().getDialogueManager()->say(actor, "idle");
}
void Actors::engageCombat (const MWWorld::Ptr& actor1, const MWWorld::Ptr& actor2, std::map<const MWWorld::Ptr, const std::set<MWWorld::Ptr> >& cachedAllies, bool againstPlayer) void Actors::engageCombat (const MWWorld::Ptr& actor1, const MWWorld::Ptr& actor2, std::map<const MWWorld::Ptr, const std::set<MWWorld::Ptr> >& cachedAllies, bool againstPlayer)
{ {
// No combat for totally static creatures // No combat for totally static creatures
@ -550,7 +577,7 @@ namespace MWMechanics
MagicEffects now = creatureStats.getSpells().getMagicEffects(); MagicEffects now = creatureStats.getSpells().getMagicEffects();
if (creature.getTypeName()==typeid (ESM::NPC).name()) if (creature.getClass().isNpc())
{ {
MWWorld::InventoryStore& store = creature.getClass().getInventoryStore (creature); MWWorld::InventoryStore& store = creature.getClass().getInventoryStore (creature);
now += store.getMagicEffects(); now += store.getMagicEffects();
@ -1286,8 +1313,46 @@ namespace MWMechanics
if (!anim) if (!anim)
return; return;
mActors.insert(std::make_pair(ptr, new Actor(ptr, anim))); mActors.insert(std::make_pair(ptr, new Actor(ptr, anim)));
CharacterController* ctrl = mActors[ptr]->getCharacterController();
if (updateImmediately) if (updateImmediately)
mActors[ptr]->getCharacterController()->update(0); ctrl->update(0);
// We should initially hide actors outside of processing range.
// Note: since we update player after other actors, distance will be incorrect during teleportation.
// Do not update visibility if player was teleported, so actors will be visible during teleportation frame.
if (MWBase::Environment::get().getWorld()->getPlayer().wasTeleported())
return;
updateVisibility(ptr, ctrl);
}
void Actors::updateVisibility (const MWWorld::Ptr& ptr, CharacterController* ctrl)
{
MWWorld::Ptr player = MWMechanics::getPlayer();
if (ptr == player)
return;
const float dist = (player.getRefData().getPosition().asVec3() - ptr.getRefData().getPosition().asVec3()).length();
if (dist > mActorsProcessingRange)
{
ptr.getRefData().getBaseNode()->setNodeMask(0);
return;
}
else
ptr.getRefData().getBaseNode()->setNodeMask(MWRender::Mask_Actor);
// Fade away actors on large distance (>90% of actor's processing distance)
float visibilityRatio = 1.0;
float fadeStartDistance = mActorsProcessingRange*0.9f;
float fadeEndDistance = mActorsProcessingRange;
float fadeRatio = (dist - fadeStartDistance)/(fadeEndDistance - fadeStartDistance);
if (fadeRatio > 0)
visibilityRatio -= std::max(0.f, fadeRatio);
visibilityRatio = std::min(1.f, visibilityRatio);
ctrl->setVisibility(visibilityRatio);
} }
void Actors::removeActor (const MWWorld::Ptr& ptr) void Actors::removeActor (const MWWorld::Ptr& ptr)
@ -1524,7 +1589,10 @@ namespace MWMechanics
End of tes3mp change (major) End of tes3mp change (major)
*/ */
if (!iter->first.getClass().getCreatureStats(iter->first).isDead()) // For dead actors we need to remove looping spell particles
if (iter->first.getClass().getCreatureStats(iter->first).isDead())
ctrl->updateContinuousVfx();
else
{ {
bool cellChanged = world->hasCellChanged(); bool cellChanged = world->hasCellChanged();
MWWorld::Ptr actor = iter->first; // make a copy of the map key to avoid it being invalidated when the player teleports MWWorld::Ptr actor = iter->first; // make a copy of the map key to avoid it being invalidated when the player teleports
@ -1599,14 +1667,17 @@ namespace MWMechanics
{ {
CreatureStats &stats = iter->first.getClass().getCreatureStats(iter->first); CreatureStats &stats = iter->first.getClass().getCreatureStats(iter->first);
if (isConscious(iter->first)) if (isConscious(iter->first))
{
stats.getAiSequence().execute(iter->first, *ctrl, duration); stats.getAiSequence().execute(iter->first, *ctrl, duration);
playIdleDialogue(iter->first);
}
} }
} }
/* /*
End of tes3mp change (major) End of tes3mp change (major)
*/ */
if(iter->first.getTypeName() == typeid(ESM::NPC).name()) if(iter->first.getClass().isNpc())
{ {
updateDrowning(iter->first, duration, ctrl->isKnockedOut(), isPlayer); updateDrowning(iter->first, duration, ctrl->isKnockedOut(), isPlayer);
calculateNpcStatModifiers(iter->first, duration); calculateNpcStatModifiers(iter->first, duration);
@ -1640,11 +1711,11 @@ namespace MWMechanics
if (!inRange) if (!inRange)
{ {
iter->first.getRefData().getBaseNode()->setNodeMask(0); iter->first.getRefData().getBaseNode()->setNodeMask(0);
world->setActorCollisionMode(iter->first, false); world->setActorCollisionMode(iter->first, false, false);
continue; continue;
} }
else if (!isPlayer) else if (!isPlayer)
iter->first.getRefData().getBaseNode()->setNodeMask(1<<3); iter->first.getRefData().getBaseNode()->setNodeMask(MWRender::Mask_Actor);
if (iter->first.getClass().getCreatureStats(iter->first).isParalyzed()) if (iter->first.getClass().getCreatureStats(iter->first).isParalyzed())
ctrl->skipAnim(); ctrl->skipAnim();
@ -1657,20 +1728,10 @@ namespace MWMechanics
continue; continue;
} }
world->setActorCollisionMode(iter->first, true); world->setActorCollisionMode(iter->first, true, !iter->first.getClass().getCreatureStats(iter->first).isDeathAnimationFinished());
ctrl->update(duration); ctrl->update(duration);
// Fade away actors on large distance (>90% of actor's processing distance) updateVisibility(iter->first, ctrl);
float visibilityRatio = 1.0;
float fadeStartDistance = mActorsProcessingRange*0.9f;
float fadeEndDistance = mActorsProcessingRange;
float fadeRatio = (dist - fadeStartDistance)/(fadeEndDistance - fadeStartDistance);
if (fadeRatio > 0)
visibilityRatio -= std::max(0.f, fadeRatio);
visibilityRatio = std::min(1.f, visibilityRatio);
ctrl->setVisibility(visibilityRatio);
} }
if (playerCharacter) if (playerCharacter)
@ -1699,72 +1760,7 @@ namespace MWMechanics
} }
killDeadActors(); killDeadActors();
updateSneaking(playerCharacter, duration);
static float sneakTimer = 0.f; // times update of sneak icon
// if player is in sneak state see if anyone detects him
if (playerCharacter && playerCharacter->isSneaking())
{
static float sneakSkillTimer = 0.f; // times sneak skill progress from "avoid notice"
const MWWorld::ESMStore& esmStore = MWBase::Environment::get().getWorld()->getStore();
const int radius = esmStore.get<ESM::GameSetting>().find("fSneakUseDist")->mValue.getInteger();
static float fSneakUseDelay = esmStore.get<ESM::GameSetting>().find("fSneakUseDelay")->mValue.getFloat();
if (sneakTimer >= fSneakUseDelay)
sneakTimer = 0.f;
if (sneakTimer == 0.f)
{
// Set when an NPC is within line of sight and distance, but is still unaware. Used for skill progress.
bool avoidedNotice = false;
bool detected = false;
for (PtrActorMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter)
{
MWWorld::Ptr observer = iter->first;
if (iter->first == player) // not the player
continue;
if (observer.getClass().getCreatureStats(observer).isDead())
continue;
// is the player in range and can they be detected
if ((observer.getRefData().getPosition().asVec3() - playerPos).length2() <= radius*radius
&& MWBase::Environment::get().getWorld()->getLOS(player, observer))
{
if (MWBase::Environment::get().getMechanicsManager()->awarenessCheck(player, observer))
{
detected = true;
avoidedNotice = false;
MWBase::Environment::get().getWindowManager()->setSneakVisibility(false);
break;
}
else
avoidedNotice = true;
}
}
if (sneakSkillTimer >= fSneakUseDelay)
sneakSkillTimer = 0.f;
if (avoidedNotice && sneakSkillTimer == 0.f)
player.getClass().skillUsageSucceeded(player, ESM::Skill::Sneak, 0);
if (!detected)
MWBase::Environment::get().getWindowManager()->setSneakVisibility(true);
}
sneakTimer += duration;
sneakSkillTimer += duration;
}
else
{
sneakTimer = 0.f;
MWBase::Environment::get().getWindowManager()->setSneakVisibility(false);
}
} }
updateCombatMusic(); updateCombatMusic();
@ -1967,6 +1963,86 @@ namespace MWMechanics
fastForwardAi(); fastForwardAi();
} }
void Actors::updateSneaking(CharacterController* ctrl, float duration)
{
static float sneakTimer = 0.f; // Times update of sneak icon
if (!ctrl)
{
MWBase::Environment::get().getWindowManager()->setSneakVisibility(false);
return;
}
MWWorld::Ptr player = getPlayer();
CreatureStats& stats = player.getClass().getCreatureStats(player);
MWBase::World* world = MWBase::Environment::get().getWorld();
bool sneaking = stats.getStance(MWMechanics::CreatureStats::Stance_Sneak);
bool inair = !world->isOnGround(player) && !world->isSwimming(player) && !world->isFlying(player);
sneaking = sneaking && (ctrl->isSneaking() || inair);
if (!sneaking)
{
MWBase::Environment::get().getWindowManager()->setSneakVisibility(false);
return;
}
static float sneakSkillTimer = 0.f; // Times sneak skill progress from "avoid notice"
const MWWorld::Store<ESM::GameSetting>& gmst = world->getStore().get<ESM::GameSetting>();
static const float fSneakUseDist = gmst.find("fSneakUseDist")->mValue.getFloat();
static const float fSneakUseDelay = gmst.find("fSneakUseDelay")->mValue.getFloat();
if (sneakTimer >= fSneakUseDelay)
sneakTimer = 0.f;
if (sneakTimer == 0.f)
{
// Set when an NPC is within line of sight and distance, but is still unaware. Used for skill progress.
bool avoidedNotice = false;
bool detected = false;
std::vector<MWWorld::Ptr> observers;
osg::Vec3f position(player.getRefData().getPosition().asVec3());
float radius = std::min(fSneakUseDist, mActorsProcessingRange);
getObjectsInRange(position, radius, observers);
for (const MWWorld::Ptr &observer : observers)
{
if (observer == player || observer.getClass().getCreatureStats(observer).isDead())
continue;
if (world->getLOS(player, observer))
{
if (MWBase::Environment::get().getMechanicsManager()->awarenessCheck(player, observer))
{
detected = true;
avoidedNotice = false;
MWBase::Environment::get().getWindowManager()->setSneakVisibility(false);
break;
}
else
{
avoidedNotice = true;
}
}
}
if (sneakSkillTimer >= fSneakUseDelay)
sneakSkillTimer = 0.f;
if (avoidedNotice && sneakSkillTimer == 0.f)
player.getClass().skillUsageSucceeded(player, ESM::Skill::Sneak, 0);
if (!detected)
MWBase::Environment::get().getWindowManager()->setSneakVisibility(true);
}
sneakTimer += duration;
sneakSkillTimer += duration;
}
int Actors::getHoursToRest(const MWWorld::Ptr &ptr) const int Actors::getHoursToRest(const MWWorld::Ptr &ptr) const
{ {
float healthPerHour, magickaPerHour; float healthPerHour, magickaPerHour;

View file

@ -5,10 +5,23 @@
#include <vector> #include <vector>
#include <string> #include <string>
#include <list> #include <list>
#include <map>
#include "../mwbase/world.hpp" namespace ESM
{
class ESMReader;
class ESMWriter;
}
#include "movement.hpp" namespace osg
{
class Vec3f;
}
namespace Loading
{
class Listener;
}
namespace MWWorld namespace MWWorld
{ {
@ -19,6 +32,7 @@ namespace MWWorld
namespace MWMechanics namespace MWMechanics
{ {
class Actor; class Actor;
class CharacterController;
class CreatureStats; class CreatureStats;
class Actors class Actors
@ -102,12 +116,17 @@ namespace MWMechanics
*/ */
void engageCombat(const MWWorld::Ptr& actor1, const MWWorld::Ptr& actor2, std::map<const MWWorld::Ptr, const std::set<MWWorld::Ptr> >& cachedAllies, bool againstPlayer); void engageCombat(const MWWorld::Ptr& actor1, const MWWorld::Ptr& actor2, std::map<const MWWorld::Ptr, const std::set<MWWorld::Ptr> >& cachedAllies, bool againstPlayer);
void playIdleDialogue(const MWWorld::Ptr& actor);
void updateHeadTracking(const MWWorld::Ptr& actor, const MWWorld::Ptr& targetActor, void updateHeadTracking(const MWWorld::Ptr& actor, const MWWorld::Ptr& targetActor,
MWWorld::Ptr& headTrackTarget, float& sqrHeadTrackDistance); MWWorld::Ptr& headTrackTarget, float& sqrHeadTrackDistance);
void rest(bool sleep); void rest(bool sleep);
///< Update actors while the player is waiting or sleeping. This should be called every hour. ///< Update actors while the player is waiting or sleeping. This should be called every hour.
void updateSneaking(CharacterController* ctrl, float duration);
///< Update the sneaking indicator state according to the given player character controller.
void restoreDynamicStats(const MWWorld::Ptr& actor, bool sleep); void restoreDynamicStats(const MWWorld::Ptr& actor, bool sleep);
int getHoursToRest(const MWWorld::Ptr& ptr) const; int getHoursToRest(const MWWorld::Ptr& ptr) const;
@ -179,6 +198,8 @@ namespace MWMechanics
bool isAttackingOrSpell(const MWWorld::Ptr& ptr) const; bool isAttackingOrSpell(const MWWorld::Ptr& ptr) const;
private: private:
void updateVisibility (const MWWorld::Ptr& ptr, CharacterController* ctrl);
PtrActorMap mActors; PtrActorMap mActors;
float mTimerDisposeSummonsCorpses; float mTimerDisposeSummonsCorpses;
float mActorsProcessingRange; float mActorsProcessingRange;

View file

@ -1,7 +1,10 @@
#ifndef OPENMW_MWMECHANICS_ACTORUTIL_H #ifndef OPENMW_MWMECHANICS_ACTORUTIL_H
#define OPENMW_MWMECHANICS_ACTORUTIL_H #define OPENMW_MWMECHANICS_ACTORUTIL_H
#include "../mwworld/ptr.hpp" namespace MWWorld
{
class Ptr;
}
namespace MWMechanics namespace MWMechanics
{ {

View file

@ -12,7 +12,7 @@
#include "steering.hpp" #include "steering.hpp"
MWMechanics::AiAvoidDoor::AiAvoidDoor(const MWWorld::ConstPtr& doorPtr) MWMechanics::AiAvoidDoor::AiAvoidDoor(const MWWorld::ConstPtr& doorPtr)
: AiPackage(), mDuration(1), mDoorPtr(doorPtr), mAdjAngle(0) : AiPackage(), mDuration(1), mDoorPtr(doorPtr), mLastPos(ESM::Position()), mAdjAngle(0)
{ {
} }

View file

@ -2,6 +2,7 @@
#include "../mwbase/environment.hpp" #include "../mwbase/environment.hpp"
#include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/mechanicsmanager.hpp"
#include "../mwbase/world.hpp"
#include "../mwworld/class.hpp" #include "../mwworld/class.hpp"

View file

@ -1,10 +1,13 @@
#ifndef GAME_MWMECHANICS_AICAST_H #ifndef GAME_MWMECHANICS_AICAST_H
#define GAME_MWMECHANICS_AICAST_H #define GAME_MWMECHANICS_AICAST_H
#include "../mwbase/world.hpp"
#include "aipackage.hpp" #include "aipackage.hpp"
namespace MWWorld
{
class Ptr;
}
namespace MWMechanics namespace MWMechanics
{ {
/// AiPackage which makes an actor to cast given spell. /// AiPackage which makes an actor to cast given spell.

View file

@ -639,13 +639,13 @@ namespace MWMechanics
if (actor.getClass().isNpc()) if (actor.getClass().isNpc())
{ {
baseDelay = store.get<ESM::GameSetting>().find("fCombatDelayNPC")->mValue.getFloat(); baseDelay = store.get<ESM::GameSetting>().find("fCombatDelayNPC")->mValue.getFloat();
}
//say a provoking combat phrase // Say a provoking combat phrase
int chance = store.get<ESM::GameSetting>().find("iVoiceAttackOdds")->mValue.getInteger(); const int iVoiceAttackOdds = store.get<ESM::GameSetting>().find("iVoiceAttackOdds")->mValue.getInteger();
if (Misc::Rng::roll0to99() < chance) if (Misc::Rng::roll0to99() < iVoiceAttackOdds)
{ {
MWBase::Environment::get().getDialogueManager()->say(actor, "attack"); MWBase::Environment::get().getDialogueManager()->say(actor, "attack");
}
} }
mAttackCooldown = std::min(baseDelay + 0.01 * Misc::Rng::roll0to99(), baseDelay + 0.9); mAttackCooldown = std::min(baseDelay + 0.01 * Misc::Rng::roll0to99(), baseDelay + 0.9);
} }

View file

@ -5,8 +5,6 @@
#include <string> #include <string>
#include "pathfinding.hpp"
namespace ESM namespace ESM
{ {
namespace AiSequence namespace AiSequence

View file

@ -1,6 +1,6 @@
#include "aiface.hpp" #include "aiface.hpp"
#include "../mwbase/world.hpp" #include "../mwworld/ptr.hpp"
#include "steering.hpp" #include "steering.hpp"

View file

@ -7,8 +7,6 @@
#include "obstacle.hpp" #include "obstacle.hpp"
#include "aistate.hpp" #include "aistate.hpp"
#include <boost/optional.hpp>
namespace MWWorld namespace MWWorld
{ {
class Ptr; class Ptr;

View file

@ -4,6 +4,7 @@
#include <components/esm/loadmgef.hpp> #include <components/esm/loadmgef.hpp>
#include "../mwbase/environment.hpp" #include "../mwbase/environment.hpp"
#include "../mwbase/world.hpp"
#include "../mwworld/class.hpp" #include "../mwworld/class.hpp"
#include "../mwworld/action.hpp" #include "../mwworld/action.hpp"

View file

@ -3,10 +3,6 @@
#include "aipackage.hpp" #include "aipackage.hpp"
#include "../mwbase/world.hpp"
#include "pathfinding.hpp"
namespace ESM namespace ESM
{ {
namespace AiSequence namespace AiSequence

View file

@ -2,7 +2,6 @@
#define AISTATE_H #define AISTATE_H
#include <typeinfo> #include <typeinfo>
#include <stdexcept>
namespace MWMechanics namespace MWMechanics
{ {

View file

@ -3,8 +3,6 @@
#include "aipackage.hpp" #include "aipackage.hpp"
#include "pathfinding.hpp"
namespace ESM namespace ESM
{ {
namespace AiSequence namespace AiSequence

View file

@ -8,7 +8,6 @@
#include "../mwbase/environment.hpp" #include "../mwbase/environment.hpp"
#include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/mechanicsmanager.hpp"
#include "../mwbase/dialoguemanager.hpp" #include "../mwbase/dialoguemanager.hpp"
#include "../mwbase/soundmanager.hpp"
#include "../mwworld/class.hpp" #include "../mwworld/class.hpp"
#include "../mwworld/esmstore.hpp" #include "../mwworld/esmstore.hpp"
@ -167,8 +166,6 @@ namespace MWMechanics
doPerFrameActionsForState(actor, duration, storage); doPerFrameActionsForState(actor, duration, storage);
playIdleDialogueRandomly(actor);
float& lastReaction = storage.mReaction; float& lastReaction = storage.mReaction;
lastReaction += duration; lastReaction += duration;
if (AI_REACTION_TIME <= lastReaction) if (AI_REACTION_TIME <= lastReaction)
@ -492,36 +489,6 @@ namespace MWMechanics
} }
} }
void AiWander::playIdleDialogueRandomly(const MWWorld::Ptr& actor)
{
int hello = actor.getClass().getCreatureStats(actor).getAiSetting(CreatureStats::AI_Hello).getModified();
if (hello > 0 && !MWBase::Environment::get().getWorld()->isSwimming(actor)
&& MWBase::Environment::get().getSoundManager()->sayDone(actor))
{
MWWorld::Ptr player = getPlayer();
static float fVoiceIdleOdds = MWBase::Environment::get().getWorld()->getStore()
.get<ESM::GameSetting>().find("fVoiceIdleOdds")->mValue.getFloat();
float roll = Misc::Rng::rollProbability() * 10000.0f;
// In vanilla MW the chance was FPS dependent, and did not allow proper changing of fVoiceIdleOdds
// due to the roll being an integer.
// Our implementation does not have these issues, so needs to be recalibrated. We chose to
// use the chance MW would have when run at 60 FPS with the default value of the GMST for calibration.
float x = fVoiceIdleOdds * 0.6f * (MWBase::Environment::get().getFrameDuration() / 0.1f);
// Only say Idle voices when player is in LOS
// A bit counterintuitive, likely vanilla did this to reduce the appearance of
// voices going through walls?
const osg::Vec3f playerPos(player.getRefData().getPosition().asVec3());
const osg::Vec3f actorPos(actor.getRefData().getPosition().asVec3());
if (roll < x && (playerPos - actorPos).length2() < 3000 * 3000 // maybe should be fAudioVoiceDefaultMaxDistance*fAudioMaxDistanceMult instead
&& MWBase::Environment::get().getWorld()->getLOS(player, actor))
MWBase::Environment::get().getDialogueManager()->say(actor, "idle");
}
}
void AiWander::playGreetingIfPlayerGetsTooClose(const MWWorld::Ptr& actor, AiWanderStorage& storage) void AiWander::playGreetingIfPlayerGetsTooClose(const MWWorld::Ptr& actor, AiWanderStorage& storage)
{ {
// Play a random voice greeting if the player gets too close // Play a random voice greeting if the player gets too close

View file

@ -138,7 +138,6 @@ namespace MWMechanics
void setPathToAnAllowedNode(const MWWorld::Ptr& actor, AiWanderStorage& storage, const ESM::Position& actorPos); void setPathToAnAllowedNode(const MWWorld::Ptr& actor, AiWanderStorage& storage, const ESM::Position& actorPos);
void playGreetingIfPlayerGetsTooClose(const MWWorld::Ptr& actor, AiWanderStorage& storage); void playGreetingIfPlayerGetsTooClose(const MWWorld::Ptr& actor, AiWanderStorage& storage);
void evadeObstacles(const MWWorld::Ptr& actor, AiWanderStorage& storage); void evadeObstacles(const MWWorld::Ptr& actor, AiWanderStorage& storage);
void playIdleDialogueRandomly(const MWWorld::Ptr& actor);
void turnActorToFacePlayer(const osg::Vec3f& actorPosition, const osg::Vec3f& playerPosition, AiWanderStorage& storage); void turnActorToFacePlayer(const osg::Vec3f& actorPosition, const osg::Vec3f& playerPosition, AiWanderStorage& storage);
void doPerFrameActionsForState(const MWWorld::Ptr& actor, float duration, AiWanderStorage& storage); void doPerFrameActionsForState(const MWWorld::Ptr& actor, float duration, AiWanderStorage& storage);
void onIdleStatePerFrameActions(const MWWorld::Ptr& actor, float duration, AiWanderStorage& storage); void onIdleStatePerFrameActions(const MWWorld::Ptr& actor, float duration, AiWanderStorage& storage);

View file

@ -1,9 +1,14 @@
#ifndef OPENMW_AUTOCALCSPELL_H #ifndef OPENMW_AUTOCALCSPELL_H
#define OPENMW_AUTOCALCSPELL_H #define OPENMW_AUTOCALCSPELL_H
#include <components/esm/loadspel.hpp> #include <string>
#include <components/esm/loadskil.hpp> #include <vector>
#include <components/esm/loadrace.hpp>
namespace ESM
{
struct Spell;
struct Race;
}
namespace MWMechanics namespace MWMechanics
{ {

View file

@ -361,15 +361,14 @@ void CharacterController::refreshHitRecoilAnims(CharacterState& idle)
idle = CharState_None; idle = CharState_None;
} }
void CharacterController::refreshJumpAnims(const WeaponInfo* weap, JumpingState jump, CharacterState& idle, CharacterState& movement, bool force) void CharacterController::refreshJumpAnims(const WeaponInfo* weap, JumpingState jump, CharacterState& idle, bool force)
{ {
if (!force && jump == mJumpState && idle == CharState_None && movement == CharState_None) if (!force && jump == mJumpState && idle == CharState_None)
return; return;
if (jump != JumpState_None && !(mPtr == MWMechanics::getPlayer() && MWBase::Environment::get().getWorld()->isFirstPerson())) // FIXME if (jump == JumpState_InAir)
{ {
idle = CharState_None; idle = CharState_None;
movement = CharState_None;
} }
std::string jumpAnimName; std::string jumpAnimName;
@ -400,6 +399,7 @@ void CharacterController::refreshJumpAnims(const WeaponInfo* weap, JumpingState
if (!force && jump == mJumpState) if (!force && jump == mJumpState)
return; return;
bool startAtLoop = (jump == mJumpState);
mJumpState = jump; mJumpState = jump;
if (!mCurrentJump.empty()) if (!mCurrentJump.empty())
@ -413,7 +413,7 @@ void CharacterController::refreshJumpAnims(const WeaponInfo* weap, JumpingState
if (mAnimation->hasAnimation(jumpAnimName)) if (mAnimation->hasAnimation(jumpAnimName))
{ {
mAnimation->play(jumpAnimName, Priority_Jump, jumpmask, false, mAnimation->play(jumpAnimName, Priority_Jump, jumpmask, false,
1.0f, "start", "stop", 0.f, ~0ul); 1.0f, startAtLoop ? "loop start" : "start", "stop", 0.f, ~0ul);
mCurrentJump = jumpAnimName; mCurrentJump = jumpAnimName;
} }
} }
@ -691,7 +691,7 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat
if (!mPtr.getClass().hasInventoryStore(mPtr)) if (!mPtr.getClass().hasInventoryStore(mPtr))
weap = sWeaponTypeListEnd; weap = sWeaponTypeListEnd;
refreshJumpAnims(weap, jump, idle, movement, force); refreshJumpAnims(weap, jump, idle, force);
refreshMovementAnims(weap, movement, idle, force); refreshMovementAnims(weap, movement, idle, force);
// idle handled last as it can depend on the other states // idle handled last as it can depend on the other states
@ -2259,12 +2259,6 @@ void CharacterController::update(float duration, bool animationOnly)
inJump = false; inJump = false;
// Do not play turning animation for player if rotation speed is very slow.
// Actual threshold should take framerate in account.
float rotationThreshold = 0;
if (isPlayer)
rotationThreshold = 0.015 * 60 * duration;
if(std::abs(vec.x()/2.0f) > std::abs(vec.y())) if(std::abs(vec.x()/2.0f) > std::abs(vec.y()))
{ {
if(vec.x() > 0.0f) if(vec.x() > 0.0f)
@ -2289,10 +2283,16 @@ void CharacterController::update(float duration, bool animationOnly)
} }
else if(rot.z() != 0.0f) else if(rot.z() != 0.0f)
{ {
// Do not play turning animation for player if rotation speed is very slow.
// Actual threshold should take framerate in account.
float rotationThreshold = 0.f;
if (isPlayer)
rotationThreshold = 0.015 * 60 * duration;
// It seems only bipedal actors use turning animations. // It seems only bipedal actors use turning animations.
// Also do not use turning animations in the first-person view and when sneaking. // Also do not use turning animations in the first-person view and when sneaking.
bool isFirstPlayer = isPlayer && MWBase::Environment::get().getWorld()->isFirstPerson(); bool isFirstPlayer = isPlayer && MWBase::Environment::get().getWorld()->isFirstPerson();
if (!sneak && !isFirstPlayer && mPtr.getClass().isBipedal(mPtr)) if (!sneak && jumpstate == JumpState_None && !isFirstPlayer && mPtr.getClass().isBipedal(mPtr))
{ {
if(rot.z() > rotationThreshold) if(rot.z() > rotationThreshold)
movestate = inwater ? CharState_SwimTurnRight : CharState_TurnRight; movestate = inwater ? CharState_SwimTurnRight : CharState_TurnRight;
@ -2305,12 +2305,15 @@ void CharacterController::update(float duration, bool animationOnly)
if (playLandingSound) if (playLandingSound)
{ {
MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager();
std::string sound = "DefaultLand"; std::string sound;
osg::Vec3f pos(mPtr.getRefData().getPosition().asVec3()); osg::Vec3f pos(mPtr.getRefData().getPosition().asVec3());
if (world->isUnderwater(mPtr.getCell(), pos) || world->isWalkingOnWater(mPtr)) if (world->isUnderwater(mPtr.getCell(), pos) || world->isWalkingOnWater(mPtr))
sound = "DefaultLandWater"; sound = "DefaultLandWater";
else if (onground)
sound = "DefaultLand";
sndMgr->playSound3D(mPtr, sound, 1.f, 1.f, MWSound::Type::Foot, MWSound::PlayMode::NoPlayerLocal); if (!sound.empty())
sndMgr->playSound3D(mPtr, sound, 1.f, 1.f, MWSound::Type::Foot, MWSound::PlayMode::NoPlayerLocal);
} }
// Player can not use smooth turning as NPCs, so we play turning animation a bit to avoid jittering // Player can not use smooth turning as NPCs, so we play turning animation a bit to avoid jittering
@ -2319,7 +2322,7 @@ void CharacterController::update(float duration, bool animationOnly)
float threshold = mCurrentMovement.find("swim") == std::string::npos ? 0.4f : 0.8f; float threshold = mCurrentMovement.find("swim") == std::string::npos ? 0.4f : 0.8f;
float complete; float complete;
bool animPlaying = mAnimation->getInfo(mCurrentMovement, &complete); bool animPlaying = mAnimation->getInfo(mCurrentMovement, &complete);
if (movestate == CharState_None && isTurning()) if (movestate == CharState_None && jumpstate == JumpState_None && isTurning())
{ {
if (animPlaying && complete < threshold) if (animPlaying && complete < threshold)
movestate = mMovementState; movestate = mMovementState;

View file

@ -31,10 +31,8 @@ enum Priority {
Priority_WeaponLowerBody, Priority_WeaponLowerBody,
Priority_SneakIdleLowerBody, Priority_SneakIdleLowerBody,
Priority_SwimIdle, Priority_SwimIdle,
Priority_Movement,
// Note: in vanilla movement anims have higher priority than jump ones.
// It causes issues with landing animations during movement.
Priority_Jump, Priority_Jump,
Priority_Movement,
Priority_Hit, Priority_Hit,
Priority_Weapon, Priority_Weapon,
Priority_Block, Priority_Block,
@ -214,7 +212,7 @@ class CharacterController : public MWRender::Animation::TextKeyListener
void refreshCurrentAnims(CharacterState idle, CharacterState movement, JumpingState jump, bool force=false); void refreshCurrentAnims(CharacterState idle, CharacterState movement, JumpingState jump, bool force=false);
void refreshHitRecoilAnims(CharacterState& idle); void refreshHitRecoilAnims(CharacterState& idle);
void refreshJumpAnims(const WeaponInfo* weap, JumpingState jump, CharacterState& idle, CharacterState& movement, bool force=false); void refreshJumpAnims(const WeaponInfo* weap, JumpingState jump, CharacterState& idle, bool force=false);
void refreshMovementAnims(const WeaponInfo* weap, CharacterState movement, CharacterState& idle, bool force=false); void refreshMovementAnims(const WeaponInfo* weap, CharacterState movement, CharacterState& idle, bool force=false);
void refreshIdleAnims(const WeaponInfo* weap, CharacterState idle, bool force=false); void refreshIdleAnims(const WeaponInfo* weap, CharacterState idle, bool force=false);

View file

@ -1,7 +1,15 @@
#ifndef OPENMW_MECHANICS_COMBAT_H #ifndef OPENMW_MECHANICS_COMBAT_H
#define OPENMW_MECHANICS_COMBAT_H #define OPENMW_MECHANICS_COMBAT_H
#include "../mwworld/ptr.hpp" namespace osg
{
class Vec3f;
}
namespace MWWorld
{
class Ptr;
}
namespace MWMechanics namespace MWMechanics
{ {

View file

@ -20,6 +20,8 @@
#include "../mwworld/containerstore.hpp" #include "../mwworld/containerstore.hpp"
#include "../mwworld/esmstore.hpp" #include "../mwworld/esmstore.hpp"
#include "../mwbase/world.hpp"
#include "../mwbase/environment.hpp"
#include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/mechanicsmanager.hpp"
#include "creaturestats.hpp" #include "creaturestats.hpp"

View file

@ -7,9 +7,6 @@
#include "../mwworld/ptr.hpp" #include "../mwworld/ptr.hpp"
#include "../mwbase/world.hpp"
#include "../mwbase/environment.hpp"
namespace MWMechanics namespace MWMechanics
{ {
class Enchanting class Enchanting

View file

@ -1252,8 +1252,7 @@ namespace MWMechanics
if (!Misc::StringUtils::ciEqual(item.getCellRef().getRefId(), MWWorld::ContainerStore::sGoldId)) if (!Misc::StringUtils::ciEqual(item.getCellRef().getRefId(), MWWorld::ContainerStore::sGoldId))
{ {
const MWWorld::Ptr victimRef = MWBase::Environment::get().getWorld()->searchPtr(ownerCellRef->getOwner(), true); if (victim.isEmpty() || (victim.getClass().isActor() && !victim.getClass().getCreatureStats(victim).isDead()))
if (victimRef.isEmpty() || !victimRef.getClass().getCreatureStats(victimRef).isDead())
mStolenItems[Misc::StringUtils::lowerCase(item.getCellRef().getRefId())][owner] += count; mStolenItems[Misc::StringUtils::lowerCase(item.getCellRef().getRefId())][owner] += count;
} }
if (alarm) if (alarm)

View file

@ -7,6 +7,7 @@
#include "../mwbase/windowmanager.hpp" #include "../mwbase/windowmanager.hpp"
#include "../mwbase/world.hpp" #include "../mwbase/world.hpp"
#include "character.hpp"
#include "movement.hpp" #include "movement.hpp"
namespace MWMechanics namespace MWMechanics

View file

@ -3,8 +3,12 @@
#include <string> #include <string>
#include <map> #include <map>
#include <vector>
#include "character.hpp" namespace osg
{
class Vec3f;
}
namespace MWWorld namespace MWWorld
{ {
@ -14,6 +18,8 @@ namespace MWWorld
namespace MWMechanics namespace MWMechanics
{ {
class CharacterController;
class Objects class Objects
{ {
typedef std::map<MWWorld::Ptr,CharacterController*> PtrControllerMap; typedef std::map<MWWorld::Ptr,CharacterController*> PtrControllerMap;

View file

@ -312,17 +312,6 @@ namespace MWMechanics
return true; // must still apply to get visual effect and have target regard it as attack return true; // must still apply to get visual effect and have target regard it as attack
} }
break; break;
case ESM::MagicEffect::AlmsiviIntervention:
case ESM::MagicEffect::DivineIntervention:
case ESM::MagicEffect::Mark:
case ESM::MagicEffect::Recall:
if (!MWBase::Environment::get().getWorld()->isTeleportingEnabled())
{
if (castByPlayer)
MWBase::Environment::get().getWindowManager()->messageBox("#{sTeleportDisabled}");
return false;
}
break;
case ESM::MagicEffect::WaterWalking: case ESM::MagicEffect::WaterWalking:
if (target.getClass().isPureWaterCreature(target) && MWBase::Environment::get().getWorld()->isSwimming(target)) if (target.getClass().isPureWaterCreature(target) && MWBase::Environment::get().getWorld()->isSwimming(target))
return false; return false;
@ -849,21 +838,19 @@ namespace MWMechanics
else if (target.getClass().isActor() && target == getPlayer()) else if (target.getClass().isActor() && target == getPlayer())
{ {
MWRender::Animation* anim = MWBase::Environment::get().getWorld()->getAnimation(mCaster); MWRender::Animation* anim = MWBase::Environment::get().getWorld()->getAnimation(mCaster);
bool teleportingEnabled = MWBase::Environment::get().getWorld()->isTeleportingEnabled();
if (effectId == ESM::MagicEffect::DivineIntervention) if (effectId == ESM::MagicEffect::DivineIntervention || effectId == ESM::MagicEffect::AlmsiviIntervention)
{ {
MWBase::Environment::get().getWorld()->teleportToClosestMarker(target, "divinemarker"); if (!teleportingEnabled)
anim->removeEffect(ESM::MagicEffect::DivineIntervention); {
const ESM::Static* fx = MWBase::Environment::get().getWorld()->getStore().get<ESM::Static>() if (caster == getPlayer())
.search("VFX_Summon_end"); MWBase::Environment::get().getWindowManager()->messageBox("#{sTeleportDisabled}");
if (fx) return true;
anim->addEffect("meshes\\" + fx->mModel, -1); }
return true; std::string marker = (effectId == ESM::MagicEffect::DivineIntervention) ? "divinemarker" : "templemarker";
} MWBase::Environment::get().getWorld()->teleportToClosestMarker(target, marker);
else if (effectId == ESM::MagicEffect::AlmsiviIntervention) anim->removeEffect(effectId);
{
MWBase::Environment::get().getWorld()->teleportToClosestMarker(target, "templemarker");
anim->removeEffect(ESM::MagicEffect::AlmsiviIntervention);
const ESM::Static* fx = MWBase::Environment::get().getWorld()->getStore().get<ESM::Static>() const ESM::Static* fx = MWBase::Environment::get().getWorld()->getStore().get<ESM::Static>()
.search("VFX_Summon_end"); .search("VFX_Summon_end");
if (fx) if (fx)
@ -872,8 +859,15 @@ namespace MWMechanics
} }
else if (effectId == ESM::MagicEffect::Mark) else if (effectId == ESM::MagicEffect::Mark)
{ {
MWBase::Environment::get().getWorld()->getPlayer().markPosition( if (teleportingEnabled)
target.getCell(), target.getRefData().getPosition()); {
MWBase::Environment::get().getWorld()->getPlayer().markPosition(
target.getCell(), target.getRefData().getPosition());
}
else if (caster == getPlayer())
{
MWBase::Environment::get().getWindowManager()->messageBox("#{sTeleportDisabled}");
}
/* /*
Start of tes3mp addition Start of tes3mp addition
@ -889,6 +883,13 @@ namespace MWMechanics
} }
else if (effectId == ESM::MagicEffect::Recall) else if (effectId == ESM::MagicEffect::Recall)
{ {
if (!teleportingEnabled)
{
if (caster == getPlayer())
MWBase::Environment::get().getWindowManager()->messageBox("#{sTeleportDisabled}");
return true;
}
MWWorld::CellStore* markedCell = nullptr; MWWorld::CellStore* markedCell = nullptr;
ESM::Position markedPosition; ESM::Position markedPosition;
@ -898,7 +899,7 @@ namespace MWMechanics
MWWorld::ActionTeleport action(markedCell->isExterior() ? "" : markedCell->getCell()->mName, MWWorld::ActionTeleport action(markedCell->isExterior() ? "" : markedCell->getCell()->mName,
markedPosition, false); markedPosition, false);
action.execute(target); action.execute(target);
anim->removeEffect(ESM::MagicEffect::Recall); anim->removeEffect(effectId);
} }
return true; return true;
} }

View file

@ -3,6 +3,7 @@
#include <components/esm/loadench.hpp> #include <components/esm/loadench.hpp>
#include <components/esm/loadmgef.hpp> #include <components/esm/loadmgef.hpp>
#include <components/esm/loadspel.hpp>
#include "../mwbase/environment.hpp" #include "../mwbase/environment.hpp"
#include "../mwbase/world.hpp" #include "../mwbase/world.hpp"

View file

@ -1,9 +1,17 @@
#ifndef OPENMW_SPELL_PRIORITY_H #ifndef OPENMW_SPELL_PRIORITY_H
#define OPENMW_SPELL_PRIORITY_H #define OPENMW_SPELL_PRIORITY_H
#include <components/esm/loadspel.hpp> namespace ESM
{
struct Spell;
struct EffectList;
struct ENAMstruct;
}
#include "../mwworld/ptr.hpp" namespace MWWorld
{
class Ptr;
}
namespace MWMechanics namespace MWMechanics
{ {

View file

@ -1,7 +1,10 @@
#ifndef OPENMW_MECHANICS_TRADING_H #ifndef OPENMW_MECHANICS_TRADING_H
#define OPENMW_MECHANICS_TRADING_H #define OPENMW_MECHANICS_TRADING_H
#include "../mwworld/ptr.hpp" namespace MWWorld
{
class Ptr;
}
namespace MWMechanics namespace MWMechanics
{ {

View file

@ -16,6 +16,7 @@
#include "../mwmechanics/actor.hpp" #include "../mwmechanics/actor.hpp"
#include "../mwmechanics/aitravel.hpp" #include "../mwmechanics/aitravel.hpp"
#include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/creaturestats.hpp"
#include "../mwmechanics/movement.hpp"
#include "../mwmechanics/npcstats.hpp" #include "../mwmechanics/npcstats.hpp"
#include "../mwmechanics/mechanicsmanagerimp.hpp" #include "../mwmechanics/mechanicsmanagerimp.hpp"
#include "../mwmechanics/spellcasting.hpp" #include "../mwmechanics/spellcasting.hpp"

View file

@ -1238,33 +1238,6 @@ namespace MWPhysics
return false; return false;
} }
void PhysicsSystem::setActorCollisionMode(const MWWorld::Ptr& ptr, bool enabled)
{
ActorMap::iterator found = mActors.find(ptr);
if (found != mActors.end())
{
bool cmode = found->second->getCollisionMode();
if (cmode == enabled)
return;
cmode = enabled;
found->second->enableCollisionMode(cmode);
found->second->enableCollisionBody(cmode);
}
}
bool PhysicsSystem::isActorCollisionEnabled(const MWWorld::Ptr& ptr)
{
ActorMap::iterator found = mActors.find(ptr);
if (found != mActors.end())
{
bool cmode = found->second->getCollisionMode();
return cmode;
}
return false;
}
void PhysicsSystem::queueObjectMovement(const MWWorld::Ptr &ptr, const osg::Vec3f &movement) void PhysicsSystem::queueObjectMovement(const MWWorld::Ptr &ptr, const osg::Vec3f &movement)
{ {
PtrVelocityList::iterator iter = mMovementQueue.begin(); PtrVelocityList::iterator iter = mMovementQueue.begin();

View file

@ -92,8 +92,6 @@ namespace MWPhysics
const HeightField* getHeightField(int x, int y) const; const HeightField* getHeightField(int x, int y) const;
bool toggleCollisionMode(); bool toggleCollisionMode();
bool isActorCollisionEnabled(const MWWorld::Ptr& ptr);
void setActorCollisionMode(const MWWorld::Ptr& ptr, bool enabled);
void stepSimulation(float dt); void stepSimulation(float dt);
void debugDraw(); void debugDraw();

View file

@ -328,32 +328,32 @@ void ActorAnimation::updateQuiver()
suitableAmmo = ammo->get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::Arrow; suitableAmmo = ammo->get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::Arrow;
} }
if (ammoNode && suitableAmmo) if (!suitableAmmo)
return;
// We should not show more ammo than equipped and more than quiver mesh has
ammoCount = std::min(ammoCount, ammoNode->getNumChildren());
// Remove existing ammo nodes
for (unsigned int i=0; i<ammoNode->getNumChildren(); ++i)
{ {
// We should not show more ammo than equipped and more than quiver mesh has osg::ref_ptr<osg::Group> arrowNode = ammoNode->getChild(i)->asGroup();
ammoCount = std::min(ammoCount, ammoNode->getNumChildren()); if (!arrowNode->getNumChildren())
continue;
// Remove existing ammo nodes osg::ref_ptr<osg::Node> arrowChildNode = arrowNode->getChild(0);
for (unsigned int i=0; i<ammoNode->getNumChildren(); ++i) arrowNode->removeChild(arrowChildNode);
{ }
osg::ref_ptr<osg::Group> arrowNode = ammoNode->getChild(i)->asGroup();
if (!arrowNode->getNumChildren())
continue;
osg::ref_ptr<osg::Node> arrowChildNode = arrowNode->getChild(0); // Add new ones
arrowNode->removeChild(arrowChildNode); osg::Vec4f glowColor = getEnchantmentColor(*ammo);
} std::string model = ammo->getClass().getModel(*ammo);
for (unsigned int i=0; i<ammoCount; ++i)
// Add new ones {
osg::Vec4f glowColor = getEnchantmentColor(*ammo); osg::ref_ptr<osg::Group> arrowNode = ammoNode->getChild(i)->asGroup();
std::string model = ammo->getClass().getModel(*ammo); osg::ref_ptr<osg::Node> arrow = mResourceSystem->getSceneManager()->getInstance(model, arrowNode);
for (unsigned int i=0; i<ammoCount; ++i) if (!ammo->getClass().getEnchantment(*ammo).empty())
{ addGlow(arrow, glowColor);
osg::ref_ptr<osg::Group> arrowNode = ammoNode->getChild(i)->asGroup();
osg::ref_ptr<osg::Node> arrow = mResourceSystem->getSceneManager()->getInstance(model, arrowNode);
if (!ammo->getClass().getEnchantment(*ammo).empty())
addGlow(arrow, glowColor);
}
} }
} }

View file

@ -9,6 +9,7 @@
#include <osg/BlendFunc> #include <osg/BlendFunc>
#include <osg/Material> #include <osg/Material>
#include <osg/PositionAttitudeTransform> #include <osg/PositionAttitudeTransform>
#include <osg/Switch>
#include <osgParticle/ParticleSystem> #include <osgParticle/ParticleSystem>
#include <osgParticle/ParticleProcessor> #include <osgParticle/ParticleProcessor>
@ -33,6 +34,7 @@
#include <components/sceneutil/lightutil.hpp> #include <components/sceneutil/lightutil.hpp>
#include <components/sceneutil/skeleton.hpp> #include <components/sceneutil/skeleton.hpp>
#include <components/sceneutil/positionattitudetransform.hpp> #include <components/sceneutil/positionattitudetransform.hpp>
#include <components/sceneutil/util.hpp>
#include <components/settings/settings.hpp> #include <components/settings/settings.hpp>
@ -91,6 +93,47 @@ namespace
std::vector<osg::ref_ptr<osg::Node> > mToRemove; std::vector<osg::ref_ptr<osg::Node> > mToRemove;
}; };
class DayNightCallback : public osg::NodeCallback
{
public:
DayNightCallback() : mCurrentState(0)
{
}
virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
{
unsigned int state = MWBase::Environment::get().getWorld()->getNightDayMode();
const unsigned int newState = node->asGroup()->getNumChildren() > state ? state : 0;
if (newState != mCurrentState)
{
mCurrentState = newState;
node->asSwitch()->setSingleChildOn(mCurrentState);
}
traverse(node, nv);
}
private:
unsigned int mCurrentState;
};
class AddSwitchCallbacksVisitor : public osg::NodeVisitor
{
public:
AddSwitchCallbacksVisitor()
: osg::NodeVisitor(TRAVERSE_ALL_CHILDREN)
{ }
virtual void apply(osg::Switch &switchNode)
{
if (switchNode.getName() == Constants::NightDayLabel)
switchNode.addUpdateCallback(new DayNightCallback());
traverse(switchNode);
}
};
NifOsg::TextKeyMap::const_iterator findGroupStart(const NifOsg::TextKeyMap &keys, const std::string &groupname) NifOsg::TextKeyMap::const_iterator findGroupStart(const NifOsg::TextKeyMap &keys, const std::string &groupname)
{ {
NifOsg::TextKeyMap::const_iterator iter(keys.begin()); NifOsg::TextKeyMap::const_iterator iter(keys.begin());
@ -641,8 +684,6 @@ namespace MWRender
mAnimationTimePtr[i].reset(new AnimationTime); mAnimationTimePtr[i].reset(new AnimationTime);
mLightListCallback = new SceneUtil::LightListCallback; mLightListCallback = new SceneUtil::LightListCallback;
mUseAdditionalSources = Settings::Manager::getBool ("use additional anim sources", "Game");
} }
Animation::~Animation() Animation::~Animation()
@ -754,7 +795,8 @@ namespace MWRender
addSingleAnimSource(kfname, baseModel); addSingleAnimSource(kfname, baseModel);
if (mUseAdditionalSources) static const bool useAdditionalSources = Settings::Manager::getBool ("use additional anim sources", "Game");
if (useAdditionalSources)
loadAllAnimationsInFolder(kfname, baseModel); loadAllAnimationsInFolder(kfname, baseModel);
} }
@ -1934,6 +1976,12 @@ namespace MWRender
mObjectRoot->accept(visitor); mObjectRoot->accept(visitor);
visitor.remove(); visitor.remove();
} }
if (SceneUtil::hasUserDescription(mObjectRoot, Constants::NightDayLabel))
{
AddSwitchCallbacksVisitor visitor;
mObjectRoot->accept(visitor);
}
} }
Animation::AnimState::~AnimState() Animation::AnimState::~AnimState()

View file

@ -273,8 +273,6 @@ protected:
osg::ref_ptr<SceneUtil::LightListCallback> mLightListCallback; osg::ref_ptr<SceneUtil::LightListCallback> mLightListCallback;
bool mUseAdditionalSources;
const NodeMap& getNodeMap() const; const NodeMap& getNodeMap() const;
/* Sets the appropriate animations on the bone groups based on priority. /* Sets the appropriate animations on the bone groups based on priority.

View file

@ -16,6 +16,7 @@
#include <components/debug/debuglog.hpp> #include <components/debug/debuglog.hpp>
#include <components/fallback/fallback.hpp> #include <components/fallback/fallback.hpp>
#include <components/sceneutil/lightmanager.hpp> #include <components/sceneutil/lightmanager.hpp>
#include <components/sceneutil/shadow.hpp>
#include "../mwbase/environment.hpp" #include "../mwbase/environment.hpp"
#include "../mwbase/world.hpp" #include "../mwbase/world.hpp"
@ -136,6 +137,7 @@ namespace MWRender
mCamera->attach(osg::Camera::COLOR_BUFFER, mTexture); mCamera->attach(osg::Camera::COLOR_BUFFER, mTexture);
mCamera->setName("CharacterPreview"); mCamera->setName("CharacterPreview");
mCamera->setComputeNearFarMode(osg::Camera::COMPUTE_NEAR_FAR_USING_BOUNDING_VOLUMES); mCamera->setComputeNearFarMode(osg::Camera::COMPUTE_NEAR_FAR_USING_BOUNDING_VOLUMES);
mCamera->setCullMask(~(Mask_UpdateVisitor));
mCamera->setNodeMask(Mask_RenderToTexture); mCamera->setNodeMask(Mask_RenderToTexture);
@ -152,6 +154,8 @@ namespace MWRender
defaultMat->setSpecular(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f, 0.f, 0.f, 0.f)); defaultMat->setSpecular(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f, 0.f, 0.f, 0.f));
stateset->setAttribute(defaultMat); stateset->setAttribute(defaultMat);
SceneUtil::ShadowManager::disableShadowsForStateSet(stateset);
// assign large value to effectively turn off fog // assign large value to effectively turn off fog
// shaders don't respect glDisable(GL_FOG) // shaders don't respect glDisable(GL_FOG)
osg::ref_ptr<osg::Fog> fog (new osg::Fog); osg::ref_ptr<osg::Fog> fog (new osg::Fog);

View file

@ -17,6 +17,7 @@
#include <components/misc/constants.hpp> #include <components/misc/constants.hpp>
#include <components/settings/settings.hpp> #include <components/settings/settings.hpp>
#include <components/sceneutil/visitor.hpp> #include <components/sceneutil/visitor.hpp>
#include <components/sceneutil/shadow.hpp>
#include <components/files/memorystream.hpp> #include <components/files/memorystream.hpp>
#include "../mwbase/environment.hpp" #include "../mwbase/environment.hpp"
@ -177,7 +178,7 @@ osg::ref_ptr<osg::Camera> LocalMap::createOrthographicCamera(float x, float y, f
camera->setClearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); camera->setClearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
camera->setRenderOrder(osg::Camera::PRE_RENDER); camera->setRenderOrder(osg::Camera::PRE_RENDER);
camera->setCullMask(Mask_Scene|Mask_SimpleWater|Mask_Terrain); camera->setCullMask(Mask_Scene | Mask_SimpleWater | Mask_Terrain | Mask_Object);
camera->setNodeMask(Mask_RenderToTexture); camera->setNodeMask(Mask_RenderToTexture);
osg::ref_ptr<osg::StateSet> stateset = new osg::StateSet; osg::ref_ptr<osg::StateSet> stateset = new osg::StateSet;
@ -209,6 +210,8 @@ osg::ref_ptr<osg::Camera> LocalMap::createOrthographicCamera(float x, float y, f
lightSource->setStateSetModes(*stateset, osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); lightSource->setStateSetModes(*stateset, osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE);
SceneUtil::ShadowManager::disableShadowsForStateSet(stateset);
camera->addChild(lightSource); camera->addChild(lightSource);
camera->setStateSet(stateset); camera->setStateSet(stateset);
camera->setViewport(0, 0, mMapResolution, mMapResolution); camera->setViewport(0, 0, mMapResolution, mMapResolution);
@ -377,7 +380,7 @@ void LocalMap::requestExteriorMap(const MWWorld::CellStore* cell)
void LocalMap::requestInteriorMap(const MWWorld::CellStore* cell) void LocalMap::requestInteriorMap(const MWWorld::CellStore* cell)
{ {
osg::ComputeBoundsVisitor computeBoundsVisitor; osg::ComputeBoundsVisitor computeBoundsVisitor;
computeBoundsVisitor.setTraversalMask(Mask_Scene|Mask_Terrain); computeBoundsVisitor.setTraversalMask(Mask_Scene | Mask_Terrain | Mask_Object);
mSceneRoot->accept(computeBoundsVisitor); mSceneRoot->accept(computeBoundsVisitor);
osg::BoundingBox bounds = computeBoundsVisitor.getBoundingBox(); osg::BoundingBox bounds = computeBoundsVisitor.getBoundingBox();

View file

@ -362,11 +362,16 @@ public:
if (cv->getProjectionMatrix()->getPerspective(fov, aspect, zNear, zFar)) if (cv->getProjectionMatrix()->getPerspective(fov, aspect, zNear, zFar))
{ {
fov = mFov; fov = mFov;
osg::RefMatrix* newProjectionMatrix = new osg::RefMatrix(*cv->getProjectionMatrix()); osg::ref_ptr<osg::RefMatrix> newProjectionMatrix = new osg::RefMatrix();
newProjectionMatrix->makePerspective(fov, aspect, zNear, zFar); newProjectionMatrix->makePerspective(fov, aspect, zNear, zFar);
cv->pushProjectionMatrix(newProjectionMatrix); osg::ref_ptr<osg::RefMatrix> invertedOldMatrix = cv->getProjectionMatrix();
invertedOldMatrix = new osg::RefMatrix(osg::RefMatrix::inverse(*invertedOldMatrix));
osg::ref_ptr<osg::RefMatrix> viewMatrix = new osg::RefMatrix(*cv->getModelViewMatrix());
viewMatrix->postMult(*newProjectionMatrix);
viewMatrix->postMult(*invertedOldMatrix);
cv->pushModelViewMatrix(viewMatrix, osg::Transform::ReferenceFrame::ABSOLUTE_RF);
traverse(node, nv); traverse(node, nv);
cv->popProjectionMatrix(); cv->popModelViewMatrix();
} }
else else
traverse(node, nv); traverse(node, nv);
@ -465,8 +470,12 @@ void NpcAnimation::updateNpcBase()
bool is1stPerson = mViewMode == VM_FirstPerson; bool is1stPerson = mViewMode == VM_FirstPerson;
bool isBeast = (race->mData.mFlags & ESM::Race::Beast) != 0; bool isBeast = (race->mData.mFlags & ESM::Race::Beast) != 0;
std::string smodel = SceneUtil::getActorSkeleton(is1stPerson, isFemale, isBeast, isWerewolf); std::string defaultSkeleton = SceneUtil::getActorSkeleton(is1stPerson, isFemale, isBeast, isWerewolf);
smodel = Misc::ResourceHelpers::correctActorModelPath(smodel, mResourceSystem->getVFS()); defaultSkeleton = Misc::ResourceHelpers::correctActorModelPath(defaultSkeleton, mResourceSystem->getVFS());
std::string smodel = defaultSkeleton;
if (!is1stPerson && !isWerewolf & !mNpc->mModel.empty())
smodel = Misc::ResourceHelpers::correctActorModelPath("meshes\\" + mNpc->mModel, mResourceSystem->getVFS());
setObjectRoot(smodel, true, true, false); setObjectRoot(smodel, true, true, false);
@ -481,15 +490,13 @@ void NpcAnimation::updateNpcBase()
if (smodel != base) if (smodel != base)
addAnimSource(base, smodel); addAnimSource(base, smodel);
if (smodel != defaultSkeleton && base != defaultSkeleton)
addAnimSource(defaultSkeleton, smodel);
addAnimSource(smodel, smodel); addAnimSource(smodel, smodel);
if(!isWerewolf) if(!isWerewolf && Misc::StringUtils::lowerCase(mNpc->mRace).find("argonian") != std::string::npos)
{ addAnimSource("meshes\\xargonian_swimkna.nif", smodel);
if(mNpc->mModel.length() > 0)
addAnimSource(Misc::ResourceHelpers::correctActorModelPath("meshes\\" + mNpc->mModel, mResourceSystem->getVFS()), smodel);
if(Misc::StringUtils::lowerCase(mNpc->mRace).find("argonian") != std::string::npos)
addAnimSource("meshes\\xargonian_swimkna.nif", smodel);
}
} }
else else
{ {

View file

@ -71,6 +71,7 @@ void Objects::insertBegin(const MWWorld::Ptr& ptr)
void Objects::insertModel(const MWWorld::Ptr &ptr, const std::string &mesh, bool animated, bool allowLight) void Objects::insertModel(const MWWorld::Ptr &ptr, const std::string &mesh, bool animated, bool allowLight)
{ {
insertBegin(ptr); insertBegin(ptr);
ptr.getRefData().getBaseNode()->setNodeMask(Mask_Object);
osg::ref_ptr<ObjectAnimation> anim (new ObjectAnimation(ptr, mesh, mResourceSystem, animated, allowLight)); osg::ref_ptr<ObjectAnimation> anim (new ObjectAnimation(ptr, mesh, mResourceSystem, animated, allowLight));

View file

@ -39,6 +39,7 @@
#include <components/sceneutil/workqueue.hpp> #include <components/sceneutil/workqueue.hpp>
#include <components/sceneutil/unrefqueue.hpp> #include <components/sceneutil/unrefqueue.hpp>
#include <components/sceneutil/writescene.hpp> #include <components/sceneutil/writescene.hpp>
#include <components/sceneutil/shadow.hpp>
#include <components/terrain/terraingrid.hpp> #include <components/terrain/terraingrid.hpp>
#include <components/terrain/quadtreeworld.hpp> #include <components/terrain/quadtreeworld.hpp>
@ -219,7 +220,7 @@ namespace MWRender
{ {
resourceSystem->getSceneManager()->setParticleSystemMask(MWRender::Mask_ParticleSystem); resourceSystem->getSceneManager()->setParticleSystemMask(MWRender::Mask_ParticleSystem);
resourceSystem->getSceneManager()->setShaderPath(resourcePath + "/shaders"); resourceSystem->getSceneManager()->setShaderPath(resourcePath + "/shaders");
resourceSystem->getSceneManager()->setForceShaders(Settings::Manager::getBool("force shaders", "Shaders")); resourceSystem->getSceneManager()->setForceShaders(Settings::Manager::getBool("force shaders", "Shaders") || Settings::Manager::getBool("enable shadows", "Shadows")); // Shadows have problems with fixed-function mode
resourceSystem->getSceneManager()->setClampLighting(Settings::Manager::getBool("clamp lighting", "Shaders")); resourceSystem->getSceneManager()->setClampLighting(Settings::Manager::getBool("clamp lighting", "Shaders"));
resourceSystem->getSceneManager()->setForcePerPixelLighting(Settings::Manager::getBool("force per pixel lighting", "Shaders")); resourceSystem->getSceneManager()->setForcePerPixelLighting(Settings::Manager::getBool("force per pixel lighting", "Shaders"));
resourceSystem->getSceneManager()->setAutoUseNormalMaps(Settings::Manager::getBool("auto use object normal maps", "Shaders")); resourceSystem->getSceneManager()->setAutoUseNormalMaps(Settings::Manager::getBool("auto use object normal maps", "Shaders"));
@ -233,7 +234,28 @@ namespace MWRender
mSceneRoot = sceneRoot; mSceneRoot = sceneRoot;
sceneRoot->setStartLight(1); sceneRoot->setStartLight(1);
mRootNode->addChild(mSceneRoot); int shadowCastingTraversalMask = Mask_Scene;
if (Settings::Manager::getBool("actor shadows", "Shadows"))
shadowCastingTraversalMask |= Mask_Actor;
if (Settings::Manager::getBool("player shadows", "Shadows"))
shadowCastingTraversalMask |= Mask_Player;
if (Settings::Manager::getBool("terrain shadows", "Shadows"))
shadowCastingTraversalMask |= Mask_Terrain;
int indoorShadowCastingTraversalMask = shadowCastingTraversalMask;
if (Settings::Manager::getBool("object shadows", "Shadows"))
shadowCastingTraversalMask |= Mask_Object;
mShadowManager.reset(new SceneUtil::ShadowManager(sceneRoot, mRootNode, shadowCastingTraversalMask, indoorShadowCastingTraversalMask, mResourceSystem->getSceneManager()->getShaderManager()));
Shader::ShaderManager::DefineMap shadowDefines = mShadowManager->getShadowDefines();
Shader::ShaderManager::DefineMap globalDefines = mResourceSystem->getSceneManager()->getShaderManager().getGlobalDefines();
for (auto itr = shadowDefines.begin(); itr != shadowDefines.end(); itr++)
globalDefines[itr->first] = itr->second;
// It is unnecessary to stop/start the viewer as no frames are being rendered yet.
mResourceSystem->getSceneManager()->getShaderManager().setGlobalDefines(globalDefines);
mNavMesh.reset(new NavMesh(mRootNode, Settings::Manager::getBool("enable nav mesh render", "Navigator"))); mNavMesh.reset(new NavMesh(mRootNode, Settings::Manager::getBool("enable nav mesh render", "Navigator")));
mActorsPaths.reset(new ActorsPaths(mRootNode, Settings::Manager::getBool("enable agents paths render", "Navigator"))); mActorsPaths.reset(new ActorsPaths(mRootNode, Settings::Manager::getBool("enable agents paths render", "Navigator")));
@ -443,7 +465,7 @@ namespace MWRender
osg::Vec4f diffuse = SceneUtil::colourFromRGB(cell->mAmbi.mSunlight); osg::Vec4f diffuse = SceneUtil::colourFromRGB(cell->mAmbi.mSunlight);
mSunLight->setDiffuse(diffuse); mSunLight->setDiffuse(diffuse);
mSunLight->setSpecular(diffuse); mSunLight->setSpecular(diffuse);
mSunLight->setDirection(osg::Vec3f(1.f,-1.f,-1.f)); mSunLight->setPosition(osg::Vec4f(-0.15f, 0.15f, 1.f, 0.f));
} }
void RenderingManager::setSunColour(const osg::Vec4f& diffuse, const osg::Vec4f& specular) void RenderingManager::setSunColour(const osg::Vec4f& diffuse, const osg::Vec4f& specular)
@ -491,6 +513,10 @@ namespace MWRender
void RenderingManager::setSkyEnabled(bool enabled) void RenderingManager::setSkyEnabled(bool enabled)
{ {
mSky->setEnabled(enabled); mSky->setEnabled(enabled);
if (enabled)
mShadowManager->enableOutdoorMode();
else
mShadowManager->enableIndoorMode();
} }
bool RenderingManager::toggleBorders() bool RenderingManager::toggleBorders()

View file

@ -53,13 +53,14 @@ namespace Fallback
namespace SceneUtil namespace SceneUtil
{ {
class ShadowManager;
class WorkQueue; class WorkQueue;
class UnrefQueue; class UnrefQueue;
} }
namespace DetourNavigator namespace DetourNavigator
{ {
class Navigator; struct Navigator;
struct Settings; struct Settings;
} }
@ -267,6 +268,7 @@ namespace MWRender
TerrainStorage* mTerrainStorage; TerrainStorage* mTerrainStorage;
std::unique_ptr<SkyManager> mSky; std::unique_ptr<SkyManager> mSky;
std::unique_ptr<EffectManager> mEffectManager; std::unique_ptr<EffectManager> mEffectManager;
std::unique_ptr<SceneUtil::ShadowManager> mShadowManager;
osg::ref_ptr<NpcAnimation> mPlayerAnimation; osg::ref_ptr<NpcAnimation> mPlayerAnimation;
osg::ref_ptr<SceneUtil::PositionAttitudeTransform> mPlayerNode; osg::ref_ptr<SceneUtil::PositionAttitudeTransform> mPlayerNode;
std::unique_ptr<Camera> mCamera; std::unique_ptr<Camera> mCamera;

View file

@ -42,6 +42,7 @@
#include <components/sceneutil/statesetupdater.hpp> #include <components/sceneutil/statesetupdater.hpp>
#include <components/sceneutil/controller.hpp> #include <components/sceneutil/controller.hpp>
#include <components/sceneutil/visitor.hpp> #include <components/sceneutil/visitor.hpp>
#include <components/sceneutil/shadow.hpp>
#include "../mwbase/environment.hpp" #include "../mwbase/environment.hpp"
#include "../mwbase/world.hpp" #include "../mwbase/world.hpp"
@ -1127,7 +1128,8 @@ SkyManager::SkyManager(osg::Group* parentNode, Resource::SceneManager* sceneMana
skyroot->setName("Sky Root"); skyroot->setName("Sky Root");
// Assign empty program to specify we don't want shaders // Assign empty program to specify we don't want shaders
// The shaders generated by the SceneManager can't handle everything we need // The shaders generated by the SceneManager can't handle everything we need
skyroot->getOrCreateStateSet()->setAttributeAndModes(new osg::Program(), osg::StateAttribute::OVERRIDE); skyroot->getOrCreateStateSet()->setAttributeAndModes(new osg::Program(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::PROTECTED|osg::StateAttribute::ON);
SceneUtil::ShadowManager::disableShadowsForStateSet(skyroot->getOrCreateStateSet());
skyroot->setNodeMask(Mask_Sky); skyroot->setNodeMask(Mask_Sky);
parentNode->addChild(skyroot); parentNode->addChild(skyroot);

View file

@ -33,25 +33,26 @@ namespace MWRender
Mask_SimpleWater = (1<<7), Mask_SimpleWater = (1<<7),
Mask_Terrain = (1<<8), Mask_Terrain = (1<<8),
Mask_FirstPerson = (1<<9), Mask_FirstPerson = (1<<9),
Mask_Object = (1<<10),
// child of Sky // child of Sky
Mask_Sun = (1<<10), Mask_Sun = (1<<11),
Mask_WeatherParticles = (1<<11), Mask_WeatherParticles = (1<<12),
// top level masks // top level masks
Mask_Scene = (1<<12), Mask_Scene = (1<<13),
Mask_GUI = (1<<13), Mask_GUI = (1<<14),
// Set on a ParticleSystem Drawable // Set on a ParticleSystem Drawable
Mask_ParticleSystem = (1<<14), Mask_ParticleSystem = (1<<15),
// Set on cameras within the main scene graph // Set on cameras within the main scene graph
Mask_RenderToTexture = (1<<15), Mask_RenderToTexture = (1<<16),
Mask_PreCompile = (1<<16), Mask_PreCompile = (1<<17),
// Set on a camera's cull mask to enable the LightManager // Set on a camera's cull mask to enable the LightManager
Mask_Lighting = (1<<17) Mask_Lighting = (1<<18)
}; };
} }

View file

@ -25,6 +25,7 @@
#include <components/resource/imagemanager.hpp> #include <components/resource/imagemanager.hpp>
#include <components/resource/scenemanager.hpp> #include <components/resource/scenemanager.hpp>
#include <components/sceneutil/shadow.hpp>
#include <components/sceneutil/waterutil.hpp> #include <components/sceneutil/waterutil.hpp>
#include <components/misc/constants.hpp> #include <components/misc/constants.hpp>
@ -224,7 +225,7 @@ public:
setSmallFeatureCullingPixelSize(Settings::Manager::getInt("small feature culling pixel size", "Water")); setSmallFeatureCullingPixelSize(Settings::Manager::getInt("small feature culling pixel size", "Water"));
setName("RefractionCamera"); setName("RefractionCamera");
setCullMask(Mask_Effect|Mask_Scene|Mask_Terrain|Mask_Actor|Mask_ParticleSystem|Mask_Sky|Mask_Sun|Mask_Player|Mask_Lighting); setCullMask(Mask_Effect|Mask_Scene|Mask_Object|Mask_Terrain|Mask_Actor|Mask_ParticleSystem|Mask_Sky|Mask_Sun|Mask_Player|Mask_Lighting);
setNodeMask(Mask_RenderToTexture); setNodeMask(Mask_RenderToTexture);
setViewport(0, 0, rttSize, rttSize); setViewport(0, 0, rttSize, rttSize);
@ -263,6 +264,8 @@ public:
mRefractionDepthTexture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR); mRefractionDepthTexture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR);
attach(osg::Camera::DEPTH_BUFFER, mRefractionDepthTexture); attach(osg::Camera::DEPTH_BUFFER, mRefractionDepthTexture);
SceneUtil::ShadowManager::disableShadowsForStateSet(getOrCreateStateSet());
} }
void setScene(osg::Node* scene) void setScene(osg::Node* scene)
@ -315,7 +318,7 @@ public:
bool reflectActors = Settings::Manager::getBool("reflect actors", "Water"); bool reflectActors = Settings::Manager::getBool("reflect actors", "Water");
setCullMask(Mask_Effect|Mask_Scene|Mask_Terrain|Mask_ParticleSystem|Mask_Sky|Mask_Player|Mask_Lighting|(reflectActors ? Mask_Actor : 0)); setCullMask(Mask_Effect|Mask_Scene|Mask_Object|Mask_Terrain|Mask_ParticleSystem|Mask_Sky|Mask_Player|Mask_Lighting|(reflectActors ? Mask_Actor : 0));
setNodeMask(Mask_RenderToTexture); setNodeMask(Mask_RenderToTexture);
unsigned int rttSize = Settings::Manager::getInt("rtt size", "Water"); unsigned int rttSize = Settings::Manager::getInt("rtt size", "Water");
@ -341,6 +344,8 @@ public:
mClipCullNode = new ClipCullNode; mClipCullNode = new ClipCullNode;
addChild(mClipCullNode); addChild(mClipCullNode);
SceneUtil::ShadowManager::disableShadowsForStateSet(getOrCreateStateSet());
} }
void setWaterLevel(float waterLevel) void setWaterLevel(float waterLevel)

View file

@ -79,6 +79,8 @@ namespace MWScript
|| ::Misc::StringUtils::ciEqual(item, "gold_100")) || ::Misc::StringUtils::ciEqual(item, "gold_100"))
item = "gold_001"; item = "gold_001";
MWWorld::ContainerStore& store = ptr.getClass().getContainerStore(ptr);
/* /*
Start of tes3mp change (major) Start of tes3mp change (major)
@ -92,7 +94,21 @@ namespace MWScript
MWWorld::Ptr itemPtr; MWWorld::Ptr itemPtr;
if (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr() || packetOrigin != mwmp::CLIENT_CONSOLE) if (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr() || packetOrigin != mwmp::CLIENT_CONSOLE)
itemPtr = *ptr.getClass().getContainerStore(ptr).add(item, count, ptr); {
// Create a Ptr for the first added item to recover the item name later
itemPtr = *store.add(item, 1, ptr);
if (itemPtr.getClass().getScript(itemPtr).empty())
{
store.add(item, count - 1, ptr);
}
else
{
// Adding just one item per time to make sure there isn't a stack of scripted items
for (int i = 1; i < count; i++)
store.add(item, 1, ptr);
}
}
/* /*
End of tes3mp change (major) End of tes3mp change (major)
*/ */
@ -205,8 +221,13 @@ namespace MWScript
std::string itemName; std::string itemName;
for (MWWorld::ConstContainerStoreIterator iter(store.cbegin()); iter != store.cend(); ++iter) for (MWWorld::ConstContainerStoreIterator iter(store.cbegin()); iter != store.cend(); ++iter)
{
if (::Misc::StringUtils::ciEqual(iter->getCellRef().getRefId(), item)) if (::Misc::StringUtils::ciEqual(iter->getCellRef().getRefId(), item))
{
itemName = iter->getClass().getName(*iter); itemName = iter->getClass().getName(*iter);
break;
}
}
/* /*
Start of tes3mp change (major) Start of tes3mp change (major)

View file

@ -16,7 +16,6 @@
#include "../mwworld/ptr.hpp" #include "../mwworld/ptr.hpp"
#include "../mwmechanics/npcstats.hpp" #include "../mwmechanics/npcstats.hpp"
#include "../mwmechanics/movement.hpp"
#include "interpretercontext.hpp" #include "interpretercontext.hpp"
#include "ref.hpp" #include "ref.hpp"
@ -168,12 +167,15 @@ namespace MWScript
virtual void execute (Interpreter::Runtime& runtime) virtual void execute (Interpreter::Runtime& runtime)
{ {
MWWorld::Ptr ptr = MWBase::Environment::get().getWorld ()->getPlayerPtr(); MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getPlayerPtr();
const MWWorld::Class &cls = ptr.getClass(); MWMechanics::CreatureStats& stats = ptr.getClass().getCreatureStats(ptr);
MWBase::World* world = MWBase::Environment::get().getWorld();
bool isRunning = MWBase::Environment::get().getMechanicsManager()->isRunning(ptr); bool stanceOn = stats.getStance(MWMechanics::CreatureStats::Stance_Run);
bool running = MWBase::Environment::get().getMechanicsManager()->isRunning(ptr);
bool inair = !world->isOnGround(ptr) && !world->isSwimming(ptr) && !world->isFlying(ptr);
runtime.push (isRunning && cls.getCreatureStats(ptr).getStance(MWMechanics::CreatureStats::Stance_Run)); runtime.push(stanceOn && (running || inair));
} }
}; };
@ -184,11 +186,14 @@ namespace MWScript
virtual void execute (Interpreter::Runtime& runtime) virtual void execute (Interpreter::Runtime& runtime)
{ {
MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getPlayerPtr(); MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getPlayerPtr();
const MWWorld::Class &cls = ptr.getClass(); MWMechanics::CreatureStats& stats = ptr.getClass().getCreatureStats(ptr);
MWBase::World* world = MWBase::Environment::get().getWorld();
bool isSneaking = MWBase::Environment::get().getMechanicsManager()->isSneaking(ptr); bool stanceOn = stats.getStance(MWMechanics::CreatureStats::Stance_Sneak);
bool sneaking = MWBase::Environment::get().getMechanicsManager()->isSneaking(ptr);
bool inair = !world->isOnGround(ptr) && !world->isSwimming(ptr) && !world->isFlying(ptr);
runtime.push (isSneaking && cls.getCreatureStats(ptr).getStance(MWMechanics::CreatureStats::Stance_Sneak)); runtime.push(stanceOn && (sneaking || inair));
} }
}; };

View file

@ -2,9 +2,7 @@
#include "../mwbase/environment.hpp" #include "../mwbase/environment.hpp"
#include "../mwbase/windowmanager.hpp" #include "../mwbase/windowmanager.hpp"
#include "../mwbase/world.hpp"
#include "../mwworld/player.hpp"
#include "../mwmechanics/actorutil.hpp" #include "../mwmechanics/actorutil.hpp"
namespace MWWorld namespace MWWorld

View file

@ -4,7 +4,6 @@
#include <string> #include <string>
#include "action.hpp" #include "action.hpp"
#include "ptr.hpp"
namespace MWWorld namespace MWWorld
{ {

View file

@ -2,9 +2,6 @@
#include <components/esm/loadskil.hpp> #include <components/esm/loadskil.hpp>
#include "../mwbase/environment.hpp"
#include "../mwbase/world.hpp"
#include "../mwworld/containerstore.hpp" #include "../mwworld/containerstore.hpp"
#include "../mwmechanics/actorutil.hpp" #include "../mwmechanics/actorutil.hpp"

View file

@ -2,7 +2,6 @@
#define GAME_MWWORLD_ACTIONEAT_H #define GAME_MWWORLD_ACTIONEAT_H
#include "action.hpp" #include "action.hpp"
#include "ptr.hpp"
namespace MWWorld namespace MWWorld
{ {

View file

@ -1,7 +1,6 @@
#include "actionequip.hpp" #include "actionequip.hpp"
#include "../mwbase/environment.hpp" #include "../mwbase/environment.hpp"
#include "../mwbase/world.hpp"
#include "../mwbase/windowmanager.hpp" #include "../mwbase/windowmanager.hpp"
#include "../mwmechanics/actorutil.hpp" #include "../mwmechanics/actorutil.hpp"

View file

@ -6,9 +6,6 @@
#include "../mwmechanics/disease.hpp" #include "../mwmechanics/disease.hpp"
#include "class.hpp"
#include "containerstore.hpp"
namespace MWWorld namespace MWWorld
{ {
ActionOpen::ActionOpen (const MWWorld::Ptr& container) ActionOpen::ActionOpen (const MWWorld::Ptr& container)

View file

@ -2,8 +2,6 @@
#define GAME_MWWORLD_ACTIONOPEN_H #define GAME_MWWORLD_ACTIONOPEN_H
#include "action.hpp" #include "action.hpp"
#include "ptr.hpp"
namespace MWWorld namespace MWWorld
{ {

View file

@ -2,7 +2,6 @@
#define GAME_MWWORLD_ACTIONREAD_H #define GAME_MWWORLD_ACTIONREAD_H
#include "action.hpp" #include "action.hpp"
#include "ptr.hpp"
namespace MWWorld namespace MWWorld
{ {

View file

@ -2,8 +2,7 @@
#include "../mwbase/windowmanager.hpp" #include "../mwbase/windowmanager.hpp"
#include "../mwbase/environment.hpp" #include "../mwbase/environment.hpp"
#include "../mwbase/world.hpp"
#include "../mwworld/player.hpp"
#include "../mwmechanics/actorutil.hpp" #include "../mwmechanics/actorutil.hpp"
namespace MWWorld namespace MWWorld

View file

@ -2,7 +2,6 @@
#define GAME_MWWORLD_ACTIONSOULGEM_H #define GAME_MWWORLD_ACTIONSOULGEM_H
#include "action.hpp" #include "action.hpp"
#include "ptr.hpp"
namespace MWWorld namespace MWWorld
{ {

View file

@ -2,7 +2,6 @@
#define GAME_MWWORLD_ACTIONTAKE_H #define GAME_MWWORLD_ACTIONTAKE_H
#include "action.hpp" #include "action.hpp"
#include "ptr.hpp"
namespace MWWorld namespace MWWorld
{ {

View file

@ -1,7 +1,6 @@
#ifndef GAME_MWWORLD_ACTIONTALK_H #ifndef GAME_MWWORLD_ACTIONTALK_H
#define GAME_MWWORLD_ACTIONTALK_H #define GAME_MWWORLD_ACTIONTALK_H
#include "ptr.hpp"
#include "action.hpp" #include "action.hpp"
namespace MWWorld namespace MWWorld

Some files were not shown because too many files have changed in this diff Show more