1
0
Fork 1
mirror of https://github.com/TES3MP/openmw-tes3mp.git synced 2025-03-01 09:09:41 +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
- 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 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 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 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.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/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/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
stage: build
script:

View file

@ -1,9 +1,11 @@
0.46.0
------
Bug #2969: Scripted items can stack
Bug #2987: Editor: some chance and AI data fields can overflow
Bug #3623: Fix HiDPI on Windows
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 #4383: Bow model obscures crosshair when arrow is drawn
Bug #4411: Reloading a saved game while falling prevents damage in some cases
@ -15,23 +17,31 @@
Bug #4723: ResetActors command works incorrectly
Bug #4745: Editor: Interior cell lighting field values are not displayed as colors
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 #4768: Fallback numerical value recovery chokes on invalid arguments
Bug #4775: Slowfall effect resets player jumping flag
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 #4803: Stray special characters before begin statement break script compilation
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 #4815: "Finished" journal entry with lower index doesn't close journal, SetJournalIndex closes journal
Bug #4820: Spell absorption is broken
Bug #4827: NiUVController is handled incorrectly
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 #3442: Default values for fallbacks from ini file
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 #4730: Native animated containers support
Feature #4812: Support NiSwitchNode
Feature #4836: Daytime node switch
Task #4686: Upgrade media decoder to a more current FFmpeg API
0.45.0

View file

@ -2,7 +2,7 @@
brew update
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 outdated pkgconfig || brew upgrade pkgconfig
brew install qt

View file

@ -608,9 +608,9 @@ printf "OSG 3.4.1-scrawl... "
SUFFIX=""
fi
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_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.
}
cd $DEPS

View file

@ -266,7 +266,7 @@ endif()
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})
set(USED_OSG_PLUGINS

View file

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

View file

@ -530,6 +530,10 @@ namespace CSMWorld
RaceDataPtr raceData = getRaceData(npc.mRace);
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
for (auto& item : npc.mInventory.mList)
{
@ -537,10 +541,6 @@ namespace CSMWorld
std::string itemId = item.mItem.toString();
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)
@ -574,6 +574,10 @@ namespace CSMWorld
partId = part.mMale;
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_Class,
Display_Faction,
Display_Rank,
Display_Race,
Display_Sound,
Display_Region,

View file

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

View file

@ -234,9 +234,17 @@ namespace CSMWorld
{ ColumnId_SoundChance, "Chance" },
{ ColumnId_FactionReactions, "Reactions" },
{ ColumnId_FactionRanks, "Ranks" },
//{ ColumnId_FactionID, "Faction ID" },
{ 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_EffectId, "Effect" },
//{ ColumnId_EffectAttribute, "Attrib" },

View file

@ -338,6 +338,14 @@ namespace CSMWorld
ColumnId_LandColoursIndex = 304,
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
// to extend the number of use values.
ColumnId_UseValue1 = 0x10000,

View file

@ -132,6 +132,23 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, bool fsStrict, const Files::Pat
mFactions.getNestableColumn(index)->addColumn(
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 RecordStateColumn<ESM::Race>);
mRaces.addColumn (new FixedRecordTypeColumn<ESM::Race> (UniversalId::Type_Race));

View file

@ -1090,4 +1090,83 @@ namespace CSMWorld
{
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;
};
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>
{
public:

View file

@ -1,5 +1,38 @@
#include "lighting.hpp"
#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() {}
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) {}
virtual ~Lighting();
virtual void activate (osg::Group* rootNode) = 0;
virtual void activate (osg::Group* rootNode, bool isExterior) = 0;
virtual void deactivate() = 0;
@ -27,6 +27,8 @@ namespace CSVRender
protected:
void updateDayNightMode(int index);
osg::ref_ptr<osg::LightSource> mLightSource;
osg::Group* mRootNode;
};

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -28,6 +28,11 @@ void CSVRender::UnpagedWorldspaceWidget::update()
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
flagAsModified();

View file

@ -82,6 +82,7 @@ void CSVWidget::ColorEditor::setColor(const int colorInt)
void CSVWidget::ColorEditor::showPicker()
{
mColorPicker->showPicker(calculatePopupPosition(), mColor);
emit pickingFinished();
}
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
QColor color = mColorPicker->getColor(initialColor);
mColorPicker->setCurrentColor(color);
if (color.isValid())
mColorPicker->setCurrentColor(color);
}
void CSVWidget::ColorPickerPopup::mousePressEvent(QMouseEvent *event)

View file

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

View file

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

View file

@ -58,7 +58,7 @@ namespace MWMechanics
namespace DetourNavigator
{
class Navigator;
struct Navigator;
}
namespace MWWorld
@ -332,6 +332,8 @@ namespace MWBase
virtual int getCurrentWeather() const = 0;
virtual unsigned int getNightDayMode() const = 0;
virtual int getMasserPhase() 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 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 toggleCollisionMode() = 0;

View file

@ -895,7 +895,7 @@ namespace MWClass
MWWorld::Ptr armor = ((armorslot != inv.end()) ? *armorslot : MWWorld::Ptr());
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);
armorhealth -= std::min(damageDiff, armorhealth);
@ -1120,8 +1120,12 @@ namespace MWClass
const float normalizedEncumbrance = getNormalizedEncumbrance(ptr);
bool sneaking = MWBase::Environment::get().getMechanicsManager()->isSneaking(ptr) && stats.getStance(MWMechanics::CreatureStats::Stance_Sneak);
bool running = MWBase::Environment::get().getMechanicsManager()->isRunning(ptr) && stats.getStance(MWMechanics::CreatureStats::Stance_Run);
bool swimming = world->isSwimming(ptr);
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()*
(gmst.fMaxWalkSpeed->mValue.getFloat() - gmst.fMinWalkSpeed->mValue.getFloat());
@ -1146,7 +1150,7 @@ namespace MWClass
flySpeed = std::max(0.0f, flySpeed);
moveSpeed = flySpeed;
}
else if (world->isSwimming(ptr))
else if (swimming)
{
float swimSpeed = walkSpeed;
if(running)
@ -1156,7 +1160,7 @@ namespace MWClass
gmst.fSwimRunAthleticsMult->mValue.getFloat();
moveSpeed = swimSpeed;
}
else if (running)
else if (running && !sneaking)
moveSpeed = runSpeed;
else
moveSpeed = walkSpeed;

View file

@ -41,19 +41,6 @@ namespace MWDialogue
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
mIndex = index;
}
@ -81,8 +68,18 @@ namespace MWDialogue
if (index==-1)
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)
setIndex (index);
mIndex = index;
for (TEntryIter iter (mEntries.begin()); iter!=mEntries.end(); ++iter)
if (iter->mInfoId==entry.mInfoId)

View file

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

View file

@ -302,7 +302,7 @@ namespace MWGui
if (mode == GM_Console)
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
if (!object.isEmpty())

View file

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

View file

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

View file

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

View file

@ -41,7 +41,7 @@ namespace MWGui
else if (skill < ESM::Skill::Length)
setSkillId(static_cast<ESM::Skill::SkillEnum>(skill));
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)

View file

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

View file

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

View file

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

View file

@ -1,13 +1,11 @@
#include "actors.hpp"
#include <typeinfo>
#include <iostream>
#include <components/esm/esmreader.hpp>
#include <components/esm/esmwriter.hpp>
#include <components/esm/loadnpc.hpp>
#include <components/sceneutil/positionattitudetransform.hpp>
#include <components/debug/debuglog.hpp>
#include <components/misc/rng.hpp>
#include <components/settings/settings.hpp>
/*
@ -43,6 +41,8 @@
#include "../mwmechanics/aibreathe.hpp"
#include "../mwrender/vismask.hpp"
#include "spellcasting.hpp"
#include "npcstats.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)
{
// No combat for totally static creatures
@ -550,7 +577,7 @@ namespace MWMechanics
MagicEffects now = creatureStats.getSpells().getMagicEffects();
if (creature.getTypeName()==typeid (ESM::NPC).name())
if (creature.getClass().isNpc())
{
MWWorld::InventoryStore& store = creature.getClass().getInventoryStore (creature);
now += store.getMagicEffects();
@ -1286,8 +1313,46 @@ namespace MWMechanics
if (!anim)
return;
mActors.insert(std::make_pair(ptr, new Actor(ptr, anim)));
CharacterController* ctrl = mActors[ptr]->getCharacterController();
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)
@ -1524,7 +1589,10 @@ namespace MWMechanics
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();
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);
if (isConscious(iter->first))
{
stats.getAiSequence().execute(iter->first, *ctrl, duration);
playIdleDialogue(iter->first);
}
}
}
/*
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);
calculateNpcStatModifiers(iter->first, duration);
@ -1640,11 +1711,11 @@ namespace MWMechanics
if (!inRange)
{
iter->first.getRefData().getBaseNode()->setNodeMask(0);
world->setActorCollisionMode(iter->first, false);
world->setActorCollisionMode(iter->first, false, false);
continue;
}
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())
ctrl->skipAnim();
@ -1657,20 +1728,10 @@ namespace MWMechanics
continue;
}
world->setActorCollisionMode(iter->first, true);
world->setActorCollisionMode(iter->first, true, !iter->first.getClass().getCreatureStats(iter->first).isDeathAnimationFinished());
ctrl->update(duration);
// 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);
updateVisibility(iter->first, ctrl);
}
if (playerCharacter)
@ -1699,72 +1760,7 @@ namespace MWMechanics
}
killDeadActors();
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);
}
updateSneaking(playerCharacter, duration);
}
updateCombatMusic();
@ -1967,6 +1963,86 @@ namespace MWMechanics
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
{
float healthPerHour, magickaPerHour;

View file

@ -5,10 +5,23 @@
#include <vector>
#include <string>
#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
{
@ -19,6 +32,7 @@ namespace MWWorld
namespace MWMechanics
{
class Actor;
class CharacterController;
class CreatureStats;
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 playIdleDialogue(const MWWorld::Ptr& actor);
void updateHeadTracking(const MWWorld::Ptr& actor, const MWWorld::Ptr& targetActor,
MWWorld::Ptr& headTrackTarget, float& sqrHeadTrackDistance);
void rest(bool sleep);
///< 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);
int getHoursToRest(const MWWorld::Ptr& ptr) const;
@ -179,6 +198,8 @@ namespace MWMechanics
bool isAttackingOrSpell(const MWWorld::Ptr& ptr) const;
private:
void updateVisibility (const MWWorld::Ptr& ptr, CharacterController* ctrl);
PtrActorMap mActors;
float mTimerDisposeSummonsCorpses;
float mActorsProcessingRange;

View file

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

View file

@ -12,7 +12,7 @@
#include "steering.hpp"
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/mechanicsmanager.hpp"
#include "../mwbase/world.hpp"
#include "../mwworld/class.hpp"

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -8,7 +8,6 @@
#include "../mwbase/environment.hpp"
#include "../mwbase/mechanicsmanager.hpp"
#include "../mwbase/dialoguemanager.hpp"
#include "../mwbase/soundmanager.hpp"
#include "../mwworld/class.hpp"
#include "../mwworld/esmstore.hpp"
@ -167,8 +166,6 @@ namespace MWMechanics
doPerFrameActionsForState(actor, duration, storage);
playIdleDialogueRandomly(actor);
float& lastReaction = storage.mReaction;
lastReaction += duration;
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)
{
// 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 playGreetingIfPlayerGetsTooClose(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 doPerFrameActionsForState(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
#define OPENMW_AUTOCALCSPELL_H
#include <components/esm/loadspel.hpp>
#include <components/esm/loadskil.hpp>
#include <components/esm/loadrace.hpp>
#include <string>
#include <vector>
namespace ESM
{
struct Spell;
struct Race;
}
namespace MWMechanics
{

View file

@ -361,15 +361,14 @@ void CharacterController::refreshHitRecoilAnims(CharacterState& idle)
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;
if (jump != JumpState_None && !(mPtr == MWMechanics::getPlayer() && MWBase::Environment::get().getWorld()->isFirstPerson())) // FIXME
if (jump == JumpState_InAir)
{
idle = CharState_None;
movement = CharState_None;
}
std::string jumpAnimName;
@ -400,6 +399,7 @@ void CharacterController::refreshJumpAnims(const WeaponInfo* weap, JumpingState
if (!force && jump == mJumpState)
return;
bool startAtLoop = (jump == mJumpState);
mJumpState = jump;
if (!mCurrentJump.empty())
@ -413,7 +413,7 @@ void CharacterController::refreshJumpAnims(const WeaponInfo* weap, JumpingState
if (mAnimation->hasAnimation(jumpAnimName))
{
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;
}
}
@ -691,7 +691,7 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat
if (!mPtr.getClass().hasInventoryStore(mPtr))
weap = sWeaponTypeListEnd;
refreshJumpAnims(weap, jump, idle, movement, force);
refreshJumpAnims(weap, jump, idle, force);
refreshMovementAnims(weap, movement, idle, force);
// idle handled last as it can depend on the other states
@ -2259,12 +2259,6 @@ void CharacterController::update(float duration, bool animationOnly)
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(vec.x() > 0.0f)
@ -2289,10 +2283,16 @@ void CharacterController::update(float duration, bool animationOnly)
}
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.
// Also do not use turning animations in the first-person view and when sneaking.
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)
movestate = inwater ? CharState_SwimTurnRight : CharState_TurnRight;
@ -2305,12 +2305,15 @@ void CharacterController::update(float duration, bool animationOnly)
if (playLandingSound)
{
MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager();
std::string sound = "DefaultLand";
std::string sound;
osg::Vec3f pos(mPtr.getRefData().getPosition().asVec3());
if (world->isUnderwater(mPtr.getCell(), pos) || world->isWalkingOnWater(mPtr))
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
@ -2319,7 +2322,7 @@ void CharacterController::update(float duration, bool animationOnly)
float threshold = mCurrentMovement.find("swim") == std::string::npos ? 0.4f : 0.8f;
float complete;
bool animPlaying = mAnimation->getInfo(mCurrentMovement, &complete);
if (movestate == CharState_None && isTurning())
if (movestate == CharState_None && jumpstate == JumpState_None && isTurning())
{
if (animPlaying && complete < threshold)
movestate = mMovementState;

View file

@ -31,10 +31,8 @@ enum Priority {
Priority_WeaponLowerBody,
Priority_SneakIdleLowerBody,
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_Movement,
Priority_Hit,
Priority_Weapon,
Priority_Block,
@ -214,7 +212,7 @@ class CharacterController : public MWRender::Animation::TextKeyListener
void refreshCurrentAnims(CharacterState idle, CharacterState movement, JumpingState jump, bool force=false);
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 refreshIdleAnims(const WeaponInfo* weap, CharacterState idle, bool force=false);

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -3,8 +3,12 @@
#include <string>
#include <map>
#include <vector>
#include "character.hpp"
namespace osg
{
class Vec3f;
}
namespace MWWorld
{
@ -14,6 +18,8 @@ namespace MWWorld
namespace MWMechanics
{
class CharacterController;
class Objects
{
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
}
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:
if (target.getClass().isPureWaterCreature(target) && MWBase::Environment::get().getWorld()->isSwimming(target))
return false;
@ -849,21 +838,19 @@ namespace MWMechanics
else if (target.getClass().isActor() && target == getPlayer())
{
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");
anim->removeEffect(ESM::MagicEffect::DivineIntervention);
const ESM::Static* fx = MWBase::Environment::get().getWorld()->getStore().get<ESM::Static>()
.search("VFX_Summon_end");
if (fx)
anim->addEffect("meshes\\" + fx->mModel, -1);
return true;
}
else if (effectId == ESM::MagicEffect::AlmsiviIntervention)
{
MWBase::Environment::get().getWorld()->teleportToClosestMarker(target, "templemarker");
anim->removeEffect(ESM::MagicEffect::AlmsiviIntervention);
if (!teleportingEnabled)
{
if (caster == getPlayer())
MWBase::Environment::get().getWindowManager()->messageBox("#{sTeleportDisabled}");
return true;
}
std::string marker = (effectId == ESM::MagicEffect::DivineIntervention) ? "divinemarker" : "templemarker";
MWBase::Environment::get().getWorld()->teleportToClosestMarker(target, marker);
anim->removeEffect(effectId);
const ESM::Static* fx = MWBase::Environment::get().getWorld()->getStore().get<ESM::Static>()
.search("VFX_Summon_end");
if (fx)
@ -872,8 +859,15 @@ namespace MWMechanics
}
else if (effectId == ESM::MagicEffect::Mark)
{
MWBase::Environment::get().getWorld()->getPlayer().markPosition(
target.getCell(), target.getRefData().getPosition());
if (teleportingEnabled)
{
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
@ -889,6 +883,13 @@ namespace MWMechanics
}
else if (effectId == ESM::MagicEffect::Recall)
{
if (!teleportingEnabled)
{
if (caster == getPlayer())
MWBase::Environment::get().getWindowManager()->messageBox("#{sTeleportDisabled}");
return true;
}
MWWorld::CellStore* markedCell = nullptr;
ESM::Position markedPosition;
@ -898,7 +899,7 @@ namespace MWMechanics
MWWorld::ActionTeleport action(markedCell->isExterior() ? "" : markedCell->getCell()->mName,
markedPosition, false);
action.execute(target);
anim->removeEffect(ESM::MagicEffect::Recall);
anim->removeEffect(effectId);
}
return true;
}

View file

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

View file

@ -1,9 +1,17 @@
#ifndef 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
{

View file

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

View file

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

View file

@ -1238,33 +1238,6 @@ namespace MWPhysics
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)
{
PtrVelocityList::iterator iter = mMovementQueue.begin();

View file

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

View file

@ -328,32 +328,32 @@ void ActorAnimation::updateQuiver()
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
ammoCount = std::min(ammoCount, ammoNode->getNumChildren());
osg::ref_ptr<osg::Group> arrowNode = ammoNode->getChild(i)->asGroup();
if (!arrowNode->getNumChildren())
continue;
// Remove existing ammo nodes
for (unsigned int i=0; i<ammoNode->getNumChildren(); ++i)
{
osg::ref_ptr<osg::Group> arrowNode = ammoNode->getChild(i)->asGroup();
if (!arrowNode->getNumChildren())
continue;
osg::ref_ptr<osg::Node> arrowChildNode = arrowNode->getChild(0);
arrowNode->removeChild(arrowChildNode);
}
osg::ref_ptr<osg::Node> arrowChildNode = arrowNode->getChild(0);
arrowNode->removeChild(arrowChildNode);
}
// Add new ones
osg::Vec4f glowColor = getEnchantmentColor(*ammo);
std::string model = ammo->getClass().getModel(*ammo);
for (unsigned int i=0; i<ammoCount; ++i)
{
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);
}
// Add new ones
osg::Vec4f glowColor = getEnchantmentColor(*ammo);
std::string model = ammo->getClass().getModel(*ammo);
for (unsigned int i=0; i<ammoCount; ++i)
{
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/Material>
#include <osg/PositionAttitudeTransform>
#include <osg/Switch>
#include <osgParticle/ParticleSystem>
#include <osgParticle/ParticleProcessor>
@ -33,6 +34,7 @@
#include <components/sceneutil/lightutil.hpp>
#include <components/sceneutil/skeleton.hpp>
#include <components/sceneutil/positionattitudetransform.hpp>
#include <components/sceneutil/util.hpp>
#include <components/settings/settings.hpp>
@ -91,6 +93,47 @@ namespace
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 iter(keys.begin());
@ -641,8 +684,6 @@ namespace MWRender
mAnimationTimePtr[i].reset(new AnimationTime);
mLightListCallback = new SceneUtil::LightListCallback;
mUseAdditionalSources = Settings::Manager::getBool ("use additional anim sources", "Game");
}
Animation::~Animation()
@ -754,7 +795,8 @@ namespace MWRender
addSingleAnimSource(kfname, baseModel);
if (mUseAdditionalSources)
static const bool useAdditionalSources = Settings::Manager::getBool ("use additional anim sources", "Game");
if (useAdditionalSources)
loadAllAnimationsInFolder(kfname, baseModel);
}
@ -1934,6 +1976,12 @@ namespace MWRender
mObjectRoot->accept(visitor);
visitor.remove();
}
if (SceneUtil::hasUserDescription(mObjectRoot, Constants::NightDayLabel))
{
AddSwitchCallbacksVisitor visitor;
mObjectRoot->accept(visitor);
}
}
Animation::AnimState::~AnimState()

View file

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

View file

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

View file

@ -17,6 +17,7 @@
#include <components/misc/constants.hpp>
#include <components/settings/settings.hpp>
#include <components/sceneutil/visitor.hpp>
#include <components/sceneutil/shadow.hpp>
#include <components/files/memorystream.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->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);
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);
SceneUtil::ShadowManager::disableShadowsForStateSet(stateset);
camera->addChild(lightSource);
camera->setStateSet(stateset);
camera->setViewport(0, 0, mMapResolution, mMapResolution);
@ -377,7 +380,7 @@ void LocalMap::requestExteriorMap(const MWWorld::CellStore* cell)
void LocalMap::requestInteriorMap(const MWWorld::CellStore* cell)
{
osg::ComputeBoundsVisitor computeBoundsVisitor;
computeBoundsVisitor.setTraversalMask(Mask_Scene|Mask_Terrain);
computeBoundsVisitor.setTraversalMask(Mask_Scene | Mask_Terrain | Mask_Object);
mSceneRoot->accept(computeBoundsVisitor);
osg::BoundingBox bounds = computeBoundsVisitor.getBoundingBox();

View file

@ -362,11 +362,16 @@ public:
if (cv->getProjectionMatrix()->getPerspective(fov, aspect, zNear, zFar))
{
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);
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);
cv->popProjectionMatrix();
cv->popModelViewMatrix();
}
else
traverse(node, nv);
@ -465,8 +470,12 @@ void NpcAnimation::updateNpcBase()
bool is1stPerson = mViewMode == VM_FirstPerson;
bool isBeast = (race->mData.mFlags & ESM::Race::Beast) != 0;
std::string smodel = SceneUtil::getActorSkeleton(is1stPerson, isFemale, isBeast, isWerewolf);
smodel = Misc::ResourceHelpers::correctActorModelPath(smodel, mResourceSystem->getVFS());
std::string defaultSkeleton = SceneUtil::getActorSkeleton(is1stPerson, isFemale, isBeast, isWerewolf);
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);
@ -481,15 +490,13 @@ void NpcAnimation::updateNpcBase()
if (smodel != base)
addAnimSource(base, smodel);
if (smodel != defaultSkeleton && base != defaultSkeleton)
addAnimSource(defaultSkeleton, smodel);
addAnimSource(smodel, smodel);
if(!isWerewolf)
{
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);
}
if(!isWerewolf && Misc::StringUtils::lowerCase(mNpc->mRace).find("argonian") != std::string::npos)
addAnimSource("meshes\\xargonian_swimkna.nif", smodel);
}
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)
{
insertBegin(ptr);
ptr.getRefData().getBaseNode()->setNodeMask(Mask_Object);
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/unrefqueue.hpp>
#include <components/sceneutil/writescene.hpp>
#include <components/sceneutil/shadow.hpp>
#include <components/terrain/terraingrid.hpp>
#include <components/terrain/quadtreeworld.hpp>
@ -219,7 +220,7 @@ namespace MWRender
{
resourceSystem->getSceneManager()->setParticleSystemMask(MWRender::Mask_ParticleSystem);
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()->setForcePerPixelLighting(Settings::Manager::getBool("force per pixel lighting", "Shaders"));
resourceSystem->getSceneManager()->setAutoUseNormalMaps(Settings::Manager::getBool("auto use object normal maps", "Shaders"));
@ -233,7 +234,28 @@ namespace MWRender
mSceneRoot = sceneRoot;
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")));
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);
mSunLight->setDiffuse(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)
@ -491,6 +513,10 @@ namespace MWRender
void RenderingManager::setSkyEnabled(bool enabled)
{
mSky->setEnabled(enabled);
if (enabled)
mShadowManager->enableOutdoorMode();
else
mShadowManager->enableIndoorMode();
}
bool RenderingManager::toggleBorders()

View file

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

View file

@ -42,6 +42,7 @@
#include <components/sceneutil/statesetupdater.hpp>
#include <components/sceneutil/controller.hpp>
#include <components/sceneutil/visitor.hpp>
#include <components/sceneutil/shadow.hpp>
#include "../mwbase/environment.hpp"
#include "../mwbase/world.hpp"
@ -1127,7 +1128,8 @@ SkyManager::SkyManager(osg::Group* parentNode, Resource::SceneManager* sceneMana
skyroot->setName("Sky Root");
// Assign empty program to specify we don't want shaders
// 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);
parentNode->addChild(skyroot);

View file

@ -33,25 +33,26 @@ namespace MWRender
Mask_SimpleWater = (1<<7),
Mask_Terrain = (1<<8),
Mask_FirstPerson = (1<<9),
Mask_Object = (1<<10),
// child of Sky
Mask_Sun = (1<<10),
Mask_WeatherParticles = (1<<11),
Mask_Sun = (1<<11),
Mask_WeatherParticles = (1<<12),
// top level masks
Mask_Scene = (1<<12),
Mask_GUI = (1<<13),
Mask_Scene = (1<<13),
Mask_GUI = (1<<14),
// Set on a ParticleSystem Drawable
Mask_ParticleSystem = (1<<14),
Mask_ParticleSystem = (1<<15),
// 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
Mask_Lighting = (1<<17)
Mask_Lighting = (1<<18)
};
}

View file

@ -25,6 +25,7 @@
#include <components/resource/imagemanager.hpp>
#include <components/resource/scenemanager.hpp>
#include <components/sceneutil/shadow.hpp>
#include <components/sceneutil/waterutil.hpp>
#include <components/misc/constants.hpp>
@ -224,7 +225,7 @@ public:
setSmallFeatureCullingPixelSize(Settings::Manager::getInt("small feature culling pixel size", "Water"));
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);
setViewport(0, 0, rttSize, rttSize);
@ -263,6 +264,8 @@ public:
mRefractionDepthTexture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR);
attach(osg::Camera::DEPTH_BUFFER, mRefractionDepthTexture);
SceneUtil::ShadowManager::disableShadowsForStateSet(getOrCreateStateSet());
}
void setScene(osg::Node* scene)
@ -315,7 +318,7 @@ public:
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);
unsigned int rttSize = Settings::Manager::getInt("rtt size", "Water");
@ -341,6 +344,8 @@ public:
mClipCullNode = new ClipCullNode;
addChild(mClipCullNode);
SceneUtil::ShadowManager::disableShadowsForStateSet(getOrCreateStateSet());
}
void setWaterLevel(float waterLevel)

View file

@ -79,6 +79,8 @@ namespace MWScript
|| ::Misc::StringUtils::ciEqual(item, "gold_100"))
item = "gold_001";
MWWorld::ContainerStore& store = ptr.getClass().getContainerStore(ptr);
/*
Start of tes3mp change (major)
@ -92,7 +94,21 @@ namespace MWScript
MWWorld::Ptr itemPtr;
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)
*/
@ -205,8 +221,13 @@ namespace MWScript
std::string itemName;
for (MWWorld::ConstContainerStoreIterator iter(store.cbegin()); iter != store.cend(); ++iter)
{
if (::Misc::StringUtils::ciEqual(iter->getCellRef().getRefId(), item))
{
itemName = iter->getClass().getName(*iter);
break;
}
}
/*
Start of tes3mp change (major)

View file

@ -16,7 +16,6 @@
#include "../mwworld/ptr.hpp"
#include "../mwmechanics/npcstats.hpp"
#include "../mwmechanics/movement.hpp"
#include "interpretercontext.hpp"
#include "ref.hpp"
@ -168,12 +167,15 @@ namespace MWScript
virtual void execute (Interpreter::Runtime& runtime)
{
MWWorld::Ptr ptr = MWBase::Environment::get().getWorld ()->getPlayerPtr();
const MWWorld::Class &cls = ptr.getClass();
MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getPlayerPtr();
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)
{
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/windowmanager.hpp"
#include "../mwbase/world.hpp"
#include "../mwworld/player.hpp"
#include "../mwmechanics/actorutil.hpp"
namespace MWWorld

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

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