From 32e90bb73321602f3c00347d53a822beec248637 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 23 May 2013 17:27:44 +0200 Subject: [PATCH 01/52] Fix chargen statssheet --- apps/openmw/mwgui/formatting.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwgui/formatting.cpp b/apps/openmw/mwgui/formatting.cpp index aebaf16a2..fbb2b74b2 100644 --- a/apps/openmw/mwgui/formatting.cpp +++ b/apps/openmw/mwgui/formatting.cpp @@ -251,10 +251,8 @@ namespace MWGui MyGUI::Gui::getInstance().destroyWidget(mParent->getChildAt(0)); } - boost::algorithm::replace_all(text, "\n", "\n"); - boost::algorithm::replace_all(text, "\r", "\r"); - boost::algorithm::replace_all(text, "
", "\n\n"); - boost::algorithm::replace_all(text, "

", "\n\n"); // tweaking by adding another newline to see if that spaces out better + boost::algorithm::replace_all(text, "
", "\n"); + boost::algorithm::replace_all(text, "

", "\n\n"); boost::algorithm::trim_left(text); // remove trailing " From 3ae02547d2c774f0bd7c4beccbe0ea0473d1c3ba Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 23 May 2013 22:42:36 +0200 Subject: [PATCH 02/52] increased version number --- CMakeLists.txt | 2 +- readme.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b989297b3..7ee938206 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,7 +15,7 @@ include (OpenMWMacros) # Version set (OPENMW_VERSION_MAJOR 0) -set (OPENMW_VERSION_MINOR 23) +set (OPENMW_VERSION_MINOR 24) set (OPENMW_VERSION_RELEASE 0) set (OPENMW_VERSION "${OPENMW_VERSION_MAJOR}.${OPENMW_VERSION_MINOR}.${OPENMW_VERSION_RELEASE}") diff --git a/readme.txt b/readme.txt index f8361780c..230150d6e 100644 --- a/readme.txt +++ b/readme.txt @@ -3,7 +3,7 @@ OpenMW: A reimplementation of The Elder Scrolls III: Morrowind OpenMW is an attempt at recreating the engine for the popular role-playing game Morrowind by Bethesda Softworks. You need to own and install the original game for OpenMW to work. -Version: 0.23.0 +Version: 0.24.0 License: GPL (see GPL3.txt for more information) Website: http://www.openmw.org From 56b1384c90a0a0b5df144d5d6b556a71cc85e1be Mon Sep 17 00:00:00 2001 From: Torben Carrington Date: Fri, 24 May 2013 18:16:35 -0700 Subject: [PATCH 03/52] AITravel Cleanup - Removed unnecessary includes and other varius cleanups. --- apps/openmw/mwmechanics/aitravel.cpp | 136 +++++++++++++-------------- apps/openmw/mwmechanics/aitravel.hpp | 4 +- 2 files changed, 64 insertions(+), 76 deletions(-) diff --git a/apps/openmw/mwmechanics/aitravel.cpp b/apps/openmw/mwmechanics/aitravel.cpp index b22185667..fbae5c1d2 100644 --- a/apps/openmw/mwmechanics/aitravel.cpp +++ b/apps/openmw/mwmechanics/aitravel.cpp @@ -1,110 +1,100 @@ #include "aitravel.hpp" -#include -#include "character.hpp" +#include "movement.hpp" #include "../mwworld/class.hpp" #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" -#include "movement.hpp" #include "../mwworld/player.hpp" -#include -#include -#include "boost/tuple/tuple.hpp" - namespace { float sgn(float a) { - if(a>0) return 1.; + if(a > 0) return 1.; else return -1.; } } -namespace MWMechanics +MWMechanics::AiTravel::AiTravel(float x, float y, float z) +: mX(x),mY(y),mZ(z),mPathFinder() { +} - AiTravel::AiTravel(float x, float y, float z) - : mX(x),mY(y),mZ(z),mPathFinder() - { - } - - AiTravel * AiTravel::clone() const - { - return new AiTravel(*this); - } +MWMechanics::AiTravel *MWMechanics::AiTravel::clone() const +{ + return new AiTravel(*this); +} - bool AiTravel::execute (const MWWorld::Ptr& actor) - { - const ESM::Pathgrid *pathgrid = - MWBase::Environment::get().getWorld()->getStore().get().search(*actor.getCell()->mCell); +bool MWMechanics::AiTravel::execute (const MWWorld::Ptr& actor) +{ + const ESM::Pathgrid *pathgrid = + MWBase::Environment::get().getWorld()->getStore().get().search(*actor.getCell()->mCell); - ESM::Position pos = actor.getRefData().getPosition(); + ESM::Position pos = actor.getRefData().getPosition(); bool cellChange = actor.getCell()->mCell->mData.mX != cellX || actor.getCell()->mCell->mData.mY != cellY; - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); - if(actor.getCell()->mCell->mData.mX != player.getCell()->mCell->mData.mX) + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + if(actor.getCell()->mCell->mData.mX != player.getCell()->mCell->mData.mX) + { + int sideX = sgn(actor.getCell()->mCell->mData.mX - player.getCell()->mCell->mData.mX); + //check if actor is near the border of an inactive cell. If so, disable aitravel. + if(sideX*(pos.pos[0] - actor.getCell()->mCell->mData.mX * ESM::Land::REAL_SIZE) > sideX*(ESM::Land::REAL_SIZE/2. - 200)) { - int sideX = sgn(actor.getCell()->mCell->mData.mX - player.getCell()->mCell->mData.mX); - //check if actor is near the border of an inactive cell. If so, disable aitravel. - if(sideX*(pos.pos[0] - actor.getCell()->mCell->mData.mX * ESM::Land::REAL_SIZE) > sideX*(ESM::Land::REAL_SIZE/2. - 200)) - { - MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0; - return true; - } + MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0; + return true; } - if(actor.getCell()->mCell->mData.mY != player.getCell()->mCell->mData.mY) + } + if(actor.getCell()->mCell->mData.mY != player.getCell()->mCell->mData.mY) + { + int sideY = sgn(actor.getCell()->mCell->mData.mY - player.getCell()->mCell->mData.mY); + //check if actor is near the border of an inactive cell. If so, disable aitravel. + if(sideY*(pos.pos[1] - actor.getCell()->mCell->mData.mY * ESM::Land::REAL_SIZE) > sideY*(ESM::Land::REAL_SIZE/2. - 200)) { - int sideY = sgn(actor.getCell()->mCell->mData.mY - player.getCell()->mCell->mData.mY); - //check if actor is near the border of an inactive cell. If so, disable aitravel. - if(sideY*(pos.pos[1] - actor.getCell()->mCell->mData.mY * ESM::Land::REAL_SIZE) > sideY*(ESM::Land::REAL_SIZE/2. - 200)) - { - MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0; - return true; - } + MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0; + return true; } + } - if(!mPathFinder.isPathConstructed() ||cellChange) + if(!mPathFinder.isPathConstructed() ||cellChange) + { + cellX = actor.getCell()->mCell->mData.mX; + cellY = actor.getCell()->mCell->mData.mY; + float xCell = 0; + float yCell = 0; + if (actor.getCell()->mCell->isExterior()) { - cellX = actor.getCell()->mCell->mData.mX; - cellY = actor.getCell()->mCell->mData.mY; - float xCell = 0; - float yCell = 0; - if (actor.getCell()->mCell->isExterior()) - { - xCell = actor.getCell()->mCell->mData.mX * ESM::Land::REAL_SIZE; - yCell = actor.getCell()->mCell->mData.mY * ESM::Land::REAL_SIZE; - } - - ESM::Pathgrid::Point dest; - dest.mX = mX; - dest.mY = mY; - dest.mZ = mZ; - - ESM::Pathgrid::Point start; - start.mX = pos.pos[0]; - start.mY = pos.pos[1]; - start.mZ = pos.pos[2]; - - mPathFinder.buildPath(start,dest,pathgrid,xCell,yCell); - } - if(mPathFinder.checkIfNextPointReached(pos.pos[0],pos.pos[1],pos.pos[2])) - { - MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0; - return true; + xCell = actor.getCell()->mCell->mData.mX * ESM::Land::REAL_SIZE; + yCell = actor.getCell()->mCell->mData.mY * ESM::Land::REAL_SIZE; } - float zAngle = mPathFinder.getZAngleToNext(pos.pos[0],pos.pos[1],pos.pos[2]); - MWBase::Environment::get().getWorld()->rotateObject(actor,0,0,zAngle,false); - MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 1; + ESM::Pathgrid::Point dest; + dest.mX = mX; + dest.mY = mY; + dest.mZ = mZ; - return false; + ESM::Pathgrid::Point start; + start.mX = pos.pos[0]; + start.mY = pos.pos[1]; + start.mZ = pos.pos[2]; + + mPathFinder.buildPath(start,dest,pathgrid,xCell,yCell); } - int AiTravel::getTypeId() const + if(mPathFinder.checkIfNextPointReached(pos.pos[0],pos.pos[1],pos.pos[2])) { - return 1; + MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0; + return true; } + float zAngle = mPathFinder.getZAngleToNext(pos.pos[0],pos.pos[1],pos.pos[2]); + MWBase::Environment::get().getWorld()->rotateObject(actor,0,0,zAngle,false); + MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 1; + + return false; +} + +int MWMechanics::AiTravel::getTypeId() const +{ + return 1; } diff --git a/apps/openmw/mwmechanics/aitravel.hpp b/apps/openmw/mwmechanics/aitravel.hpp index 52b41850f..6eb9af8ce 100644 --- a/apps/openmw/mwmechanics/aitravel.hpp +++ b/apps/openmw/mwmechanics/aitravel.hpp @@ -2,6 +2,7 @@ #define GAME_MWMECHANICS_AITRAVEL_H #include "aipackage.hpp" + #include "pathfinding.hpp" namespace MWMechanics @@ -25,10 +26,7 @@ namespace MWMechanics int cellX; int cellY; - //bool isPathConstructed; - //std::list mPath; PathFinder mPathFinder; - }; } From 1e7cf4ae1c3fd90ebace6f0de1e34fe9387be1e7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 25 May 2013 04:15:24 +0200 Subject: [PATCH 04/52] GLES2 experiment --- apps/openmw/mwrender/renderingmanager.cpp | 13 +++++++++---- extern/shiny/Docs/Materials.dox | 2 ++ extern/shiny/Editor/Actions.hpp | 2 +- extern/shiny/Editor/Query.hpp | 2 +- files/materials/core.h | 2 +- libs/openengine/ogre/renderer.cpp | 1 + 6 files changed, 15 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 9061f8402..a5dc8ec68 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -64,13 +64,16 @@ RenderingManager::RenderingManager(OEngine::Render::OgreRenderer& _rend, const b { // select best shader mode bool openGL = (Ogre::Root::getSingleton ().getRenderSystem ()->getName().find("OpenGL") != std::string::npos); + bool glES = (Ogre::Root::getSingleton ().getRenderSystem ()->getName().find("OpenGL ES") != std::string::npos); // glsl is only supported in opengl mode and hlsl only in direct3d mode. - if (Settings::Manager::getString("shader mode", "General") == "" - || (openGL && Settings::Manager::getString("shader mode", "General") == "hlsl") - || (!openGL && Settings::Manager::getString("shader mode", "General") == "glsl")) + std::string currentMode = Settings::Manager::getString("shader mode", "General"); + if (currentMode == "" + || (openGL && currentMode == "hlsl") + || (!openGL && currentMode == "glsl") + || (glES && currentMode != "glsles")) { - Settings::Manager::setString("shader mode", "General", openGL ? "glsl" : "hlsl"); + Settings::Manager::setString("shader mode", "General", openGL ? (glES ? "glsles" : "glsl") : "hlsl"); } mRendering.createScene("PlayerCam", Settings::Manager::getFloat("field of view", "General"), 5); @@ -93,6 +96,8 @@ RenderingManager::RenderingManager(OEngine::Render::OgreRenderer& _rend, const b std::string l = Settings::Manager::getString("shader mode", "General"); if (l == "glsl") lang = sh::Language_GLSL; + else if (l == "glsles") + lang = sh::Language_GLSLES; else if (l == "hlsl") lang = sh::Language_HLSL; else diff --git a/extern/shiny/Docs/Materials.dox b/extern/shiny/Docs/Materials.dox index 91e9be4b3..d08599a04 100644 --- a/extern/shiny/Docs/Materials.dox +++ b/extern/shiny/Docs/Materials.dox @@ -87,6 +87,8 @@ Now, let's get into writing our shader! As you can guess from above, the filename should be 'example.shader'. Make sure to also copy the 'core.h' file to the same location. It is included in shiny's source tree under 'Extra/'. + Important: a newline at the end of the file is required. Many editors do this automatically or can be configured to do so. If there is no newline at the end of the file, and the last line is '#endif', you will get the rather cryptic error message " ill formed preprocessor directive: #endif" from boost::wave. + \code #include "core.h" diff --git a/extern/shiny/Editor/Actions.hpp b/extern/shiny/Editor/Actions.hpp index e5cb6df6a..1bbdbe5a9 100644 --- a/extern/shiny/Editor/Actions.hpp +++ b/extern/shiny/Editor/Actions.hpp @@ -10,7 +10,7 @@ namespace sh { public: virtual void execute() = 0; - virtual ~Action(); + virtual ~Action() {} }; class ActionDeleteMaterial : public Action diff --git a/extern/shiny/Editor/Query.hpp b/extern/shiny/Editor/Query.hpp index 7aec68488..d98c8c9b2 100644 --- a/extern/shiny/Editor/Query.hpp +++ b/extern/shiny/Editor/Query.hpp @@ -15,7 +15,7 @@ class Query public: Query() : mDone(false) {} - virtual ~Query(); + virtual ~Query() {} void execute(); diff --git a/files/materials/core.h b/files/materials/core.h index 3385e5fac..c15ec6bad 100644 --- a/files/materials/core.h +++ b/files/materials/core.h @@ -58,7 +58,7 @@ #endif -#if SH_GLSL == 1 +#if SH_GLSL == 1 || SH_GLSLES == 1 #define shFract(val) fract(val) diff --git a/libs/openengine/ogre/renderer.cpp b/libs/openengine/ogre/renderer.cpp index 7be713796..e699fbbcc 100644 --- a/libs/openengine/ogre/renderer.cpp +++ b/libs/openengine/ogre/renderer.cpp @@ -206,6 +206,7 @@ void OgreRenderer::configure(const std::string &logPath, pluginDir = absPluginPath.string(); Files::loadOgrePlugin(pluginDir, "RenderSystem_GL", *mRoot); + Files::loadOgrePlugin(pluginDir, "RenderSystem_GLES2", *mRoot); Files::loadOgrePlugin(pluginDir, "RenderSystem_GL3Plus", *mRoot); Files::loadOgrePlugin(pluginDir, "RenderSystem_Direct3D9", *mRoot); Files::loadOgrePlugin(pluginDir, "Plugin_CgProgramManager", *mRoot); From cc747d8ae4c8f46c789fe024b7c5489291ca9057 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 25 May 2013 04:23:07 +0200 Subject: [PATCH 05/52] GLSL ES: precision qualifiers are required --- files/materials/core.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/files/materials/core.h b/files/materials/core.h index c15ec6bad..d53d8d4a9 100644 --- a/files/materials/core.h +++ b/files/materials/core.h @@ -64,6 +64,11 @@ @version 120 +#if SH_GLSLES == 1 +precision mediump int; +precision mediump float; +#endif + #define float2 vec2 #define float3 vec3 #define float4 vec4 From c2c88acc7b83cf40e3f367dfd8ca50157d570a9a Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 25 May 2013 04:26:40 +0200 Subject: [PATCH 06/52] GLSLES: only the fragment shader needs precision explicitely set. --- files/materials/core.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/materials/core.h b/files/materials/core.h index d53d8d4a9..e5d58ba25 100644 --- a/files/materials/core.h +++ b/files/materials/core.h @@ -64,7 +64,7 @@ @version 120 -#if SH_GLSLES == 1 +#if SH_GLSLES == 1 && SH_FRAGMENT_SHADER precision mediump int; precision mediump float; #endif From c8c1ddd927525ab3b1d71a7fb365cf8276b94b37 Mon Sep 17 00:00:00 2001 From: Torben Carrington Date: Fri, 24 May 2013 20:10:07 -0700 Subject: [PATCH 07/52] Adds functionality for checking if the animation group passed is currently playing on the actor passed. This is needed for AIWander. --- apps/openmw/mwbase/mechanicsmanager.hpp | 2 ++ apps/openmw/mwmechanics/actors.cpp | 8 ++++++++ apps/openmw/mwmechanics/actors.hpp | 1 + apps/openmw/mwmechanics/character.cpp | 8 ++++++++ apps/openmw/mwmechanics/character.hpp | 1 + apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 7 +++++++ apps/openmw/mwmechanics/mechanicsmanagerimp.hpp | 1 + 7 files changed, 28 insertions(+) diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index 38794269b..7e09f9b4d 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -112,6 +112,8 @@ namespace MWBase virtual void skipAnimation(const MWWorld::Ptr& ptr) = 0; ///< Skip the animation for the given MW-reference for one frame. Calls to this function for /// references that are currently not in the scene should be ignored. + + virtual bool checkAnimationPlaying(const MWWorld::Ptr& ptr, const std::string& groupName) = 0; }; } diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 4db574cb8..00f2ac6fe 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -309,4 +309,12 @@ namespace MWMechanics if(iter != mActors.end()) iter->second.skipAnim(); } + + bool Actors::checkAnimationPlaying(const MWWorld::Ptr& ptr, const std::string& groupName) + { + PtrControllerMap::iterator iter = mActors.find(ptr); + if(iter != mActors.end()) + return iter->second.isAnimPlaying(groupName); + return false; + } } diff --git a/apps/openmw/mwmechanics/actors.hpp b/apps/openmw/mwmechanics/actors.hpp index c01d63093..386840e3a 100644 --- a/apps/openmw/mwmechanics/actors.hpp +++ b/apps/openmw/mwmechanics/actors.hpp @@ -82,6 +82,7 @@ namespace MWMechanics void playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number); void skipAnimation(const MWWorld::Ptr& ptr); + bool checkAnimationPlaying(const MWWorld::Ptr& ptr, const std::string& groupName); }; } diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 31ba83392..c7aeb1b5f 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -509,6 +509,14 @@ void CharacterController::skipAnim() mSkipAnim = true; } +bool CharacterController::isAnimPlaying(const std::string &groupName) +{ + if(mAnimation == NULL) + return false; + else + return mAnimation->isPlaying(groupName); +} + void CharacterController::clearAnimQueue() { diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 7ffefab47..7067176e0 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -125,6 +125,7 @@ public: void playGroup(const std::string &groupname, int mode, int count); void skipAnim(); + bool isAnimPlaying(const std::string &groupName); void setState(CharacterState state); CharacterState getState() const diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index b83cfb365..29880291d 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -668,5 +668,12 @@ namespace MWMechanics else mObjects.skipAnimation(ptr); } + bool MechanicsManager::checkAnimationPlaying(const MWWorld::Ptr& ptr, const std::string &groupName) + { + if(MWWorld::Class::get(ptr).isActor()) + return mActors.checkAnimationPlaying(ptr, groupName); + else + return false; + } } diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index f3a38bf36..95f760d11 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -100,6 +100,7 @@ namespace MWMechanics virtual void playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number); virtual void skipAnimation(const MWWorld::Ptr& ptr); + virtual bool checkAnimationPlaying(const MWWorld::Ptr& ptr, const std::string &groupName); }; } From de5a08a07d359841828827f8b72fdc87ca1421c8 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 25 May 2013 05:40:35 +0200 Subject: [PATCH 08/52] Version should be 100 for GLSLES --- files/materials/core.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/files/materials/core.h b/files/materials/core.h index e5d58ba25..6f8179c08 100644 --- a/files/materials/core.h +++ b/files/materials/core.h @@ -62,7 +62,11 @@ #define shFract(val) fract(val) +#if SH_GLSLES == 1 + @version 100 +#else @version 120 +#endif #if SH_GLSLES == 1 && SH_FRAGMENT_SHADER precision mediump int; From ddf28ca201a25aa28dac65bf1dcfa0f349923ab5 Mon Sep 17 00:00:00 2001 From: Torben Carrington Date: Sat, 25 May 2013 04:36:21 -0700 Subject: [PATCH 09/52] AIEscort Cleanup - Fixed spacing, removed unnecessary includes, fixed branch itself. The other pull requests were fine, it was just this one with the problem. --- apps/openmw/mwmechanics/aiescort.cpp | 48 ++++++++++++---------------- apps/openmw/mwmechanics/aiescort.hpp | 23 +------------ 2 files changed, 21 insertions(+), 50 deletions(-) diff --git a/apps/openmw/mwmechanics/aiescort.cpp b/apps/openmw/mwmechanics/aiescort.cpp index 7c28dd216..5b94c4938 100644 --- a/apps/openmw/mwmechanics/aiescort.cpp +++ b/apps/openmw/mwmechanics/aiescort.cpp @@ -1,6 +1,5 @@ #include "aiescort.hpp" -#include "character.hpp" #include "movement.hpp" #include "../mwworld/class.hpp" @@ -10,16 +9,12 @@ #include "../mwbase/environment.hpp" #include "../mwbase/mechanicsmanager.hpp" -#include -#include -#include "boost/tuple/tuple.hpp" - namespace { float sgn(float a) { - if(a>0) return 1.; - else return -1.; + if(a > 0) return 1.0; + else return -1.0; } } @@ -77,11 +72,8 @@ bool MWMechanics::AiEscort::execute (const MWWorld::Ptr& actor) { MWWorld::TimeStamp current = MWBase::Environment::get().getWorld()->getTimeStamp(); unsigned int currentSecond = ((current.getHour() - int(current.getHour())) * 100); - std::cout << "AiEscort: " << currentSecond << " time: " << currentSecond - mStartingSecond << std::endl; if(currentSecond - mStartingSecond >= mDuration) - { return true; - } } ESM::Position pos = actor.getRefData().getPosition(); @@ -91,28 +83,28 @@ bool MWMechanics::AiEscort::execute (const MWWorld::Ptr& actor) MWBase::Environment::get().getWorld()->getStore().get().search(*actor.getCell()->mCell); - if(actor.getCell()->mCell->mData.mX != player.getCell()->mCell->mData.mX) + if(actor.getCell()->mCell->mData.mX != player.getCell()->mCell->mData.mX) + { + int sideX = sgn(actor.getCell()->mCell->mData.mX - player.getCell()->mCell->mData.mX); + // Check if actor is near the border of an inactive cell. If so, disable AiEscort. + // FIXME: This *should* pause the AiEscort package instead of terminating it. + if(sideX*(pos.pos[0] - actor.getCell()->mCell->mData.mX * ESM::Land::REAL_SIZE) > sideX * (ESM::Land::REAL_SIZE / 2. - 200)) { - int sideX = sgn(actor.getCell()->mCell->mData.mX - player.getCell()->mCell->mData.mX); - // Check if actor is near the border of an inactive cell. If so, disable AiEscort. - // FIXME: This *should* pause the AiEscort package instead of terminating it. - if(sideX*(pos.pos[0] - actor.getCell()->mCell->mData.mX * ESM::Land::REAL_SIZE) > sideX*(ESM::Land::REAL_SIZE/2. - 200)) - { - MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0; - return true; - } + MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0; + return true; } - if(actor.getCell()->mCell->mData.mY != player.getCell()->mCell->mData.mY) + } + if(actor.getCell()->mCell->mData.mY != player.getCell()->mCell->mData.mY) + { + int sideY = sgn(actor.getCell()->mCell->mData.mY - player.getCell()->mCell->mData.mY); + // Check if actor is near the border of an inactive cell. If so, disable AiEscort. + // FIXME: This *should* pause the AiEscort package instead of terminating it. + if(sideY*(pos.pos[1] - actor.getCell()->mCell->mData.mY * ESM::Land::REAL_SIZE) > sideY * (ESM::Land::REAL_SIZE / 2. - 200)) { - int sideY = sgn(actor.getCell()->mCell->mData.mY - player.getCell()->mCell->mData.mY); - // Check if actor is near the border of an inactive cell. If so, disable AiEscort. - // FIXME: This *should* pause the AiEscort package instead of terminating it. - if(sideY*(pos.pos[1] - actor.getCell()->mCell->mData.mY * ESM::Land::REAL_SIZE) > sideY*(ESM::Land::REAL_SIZE/2. - 200)) - { - MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0; - return true; - } + MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0; + return true; } + } if(!mPathFinder.isPathConstructed() || cellChange) diff --git a/apps/openmw/mwmechanics/aiescort.hpp b/apps/openmw/mwmechanics/aiescort.hpp index 667b88e31..3ae604035 100644 --- a/apps/openmw/mwmechanics/aiescort.hpp +++ b/apps/openmw/mwmechanics/aiescort.hpp @@ -2,30 +2,9 @@ #define GAME_MWMECHANICS_AIESCORT_H #include "aipackage.hpp" -#include "pathfinding.hpp" #include -/* From CS: -Escort - -Makes the actor escort another actor to a location or for a specified period of time. During this time the actor will also protect the actor it is escorting. - -If you are not doing this package with the player as the target, you’ll want to also put a follow package on the target Actor, since escorting an actor makes the escorter wait for the other actor. If the Target does not know they are supposed to follow, the escorter will most likely just stand there. - -Target: The ActorID to Escort. Remember that since all ActorIDs share the same AI packages, putting this on an Actor with multiple references will cause ALL references of that actor to attempt to escort the same actor. Thus, this type of AI should only be placed on specific or unique sets of Actors. - -Duration: The duration the actor should escort for. Trumped by providing a location. - -Escort to: Check this to use location data for the escort. - -Cell: The Cell to escort to. - -XYZ: Like Travel, specify the XYZ location to escort to. - -View Location: A red X will appear in the render window that you can move around with the standard render window object controls. Place the X on the escort destination. - - -*/ +#include "pathfinding.hpp" namespace MWMechanics { From 2850032d9e442f77cec9e6ebac90ac09bd645db8 Mon Sep 17 00:00:00 2001 From: eroen Date: Sun, 26 May 2013 10:36:17 +0200 Subject: [PATCH 10/52] libc++ fixes: avcodec/avformat workaround With libc++, string includes stdint.h, which breaks the fragile avformat.h workaround, which depends on __STDC_CONSTANT_MACROS being defined before stdint.h is included. Moving the string inclusion after that eyesore shouldn't break anything. --- apps/openmw/mwsound/ffmpeg_decoder.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwsound/ffmpeg_decoder.hpp b/apps/openmw/mwsound/ffmpeg_decoder.hpp index 32b2797ed..a5e5b5083 100644 --- a/apps/openmw/mwsound/ffmpeg_decoder.hpp +++ b/apps/openmw/mwsound/ffmpeg_decoder.hpp @@ -1,8 +1,6 @@ #ifndef GAME_SOUND_FFMPEG_DECODER_H #define GAME_SOUND_FFMPEG_DECODER_H -#include - // FIXME: This can't be right? The headers refuse to build without UINT64_C, // which only gets defined in stdint.h in either C99 mode or with this macro // defined... @@ -14,6 +12,8 @@ extern "C" #include } +#include + #include "sound_decoder.hpp" From 886bc7e2f6563aaa6bd01608991dfec54a95a488 Mon Sep 17 00:00:00 2001 From: eroen Date: Sun, 26 May 2013 12:44:10 +0200 Subject: [PATCH 11/52] libc++ fixes: don't rely on tr1 libc++ doesn't ship tr1, but ships unordered_map as it is part of c++11. Since this is the only tr1 header used in openmw, add a check for c++11 unordered_map and fallback to tr1 unordered_map if it's not found. --- CMakeLists.txt | 6 ++++++ components/files/configurationmanager.hpp | 8 +++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b989297b3..43415c953 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -181,6 +181,12 @@ if (UNIX AND NOT APPLE) find_package (Threads) endif() +include (CheckIncludeFileCXX) +check_include_file_cxx(unordered_map HAVE_UNORDERED_MAP) +if (HAVE_UNORDERED_MAP) + add_definitions(-DHAVE_UNORDERED_MAP) +endif () + set(BOOST_COMPONENTS system filesystem program_options thread date_time wave) diff --git a/components/files/configurationmanager.hpp b/components/files/configurationmanager.hpp index 9056e792d..765f1cebf 100644 --- a/components/files/configurationmanager.hpp +++ b/components/files/configurationmanager.hpp @@ -3,6 +3,8 @@ #ifdef _WIN32 #include +#elif defined HAVE_UNORDERED_MAP +#include #else #include #endif @@ -48,7 +50,11 @@ struct ConfigurationManager typedef Files::FixedPath<> FixedPathType; typedef const boost::filesystem::path& (FixedPathType::*path_type_f)() const; - typedef std::tr1::unordered_map TokensMappingContainer; + #if defined HAVE_UNORDERED_MAP + typedef std::unordered_map TokensMappingContainer; + #else + typedef std::tr1::unordered_map TokensMappingContainer; + #endif void loadConfig(const boost::filesystem::path& path, boost::program_options::variables_map& variables, From e37324b967aa99406ebfed37c33585c5d169de05 Mon Sep 17 00:00:00 2001 From: Torben Carrington Date: Sun, 26 May 2013 08:49:44 -0700 Subject: [PATCH 12/52] AIWander everything works. only two things to do: Implement limiting selection on z axis, and correcting decision algorithm. --- apps/openmw/mwmechanics/aiwander.cpp | 297 ++++++++++++++++++++++++++- apps/openmw/mwmechanics/aiwander.hpp | 35 ++++ 2 files changed, 330 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index a73047548..52ab34f24 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -1,9 +1,54 @@ #include "aiwander.hpp" #include +#include "movement.hpp" + +#include "../mwworld/class.hpp" +#include "../mwworld/player.hpp" +#include "../mwbase/world.hpp" +#include "../mwbase/environment.hpp" +#include "../mwbase/mechanicsmanager.hpp" + +#include + +namespace +{ + float sgn(float a) + { + if(a > 0) return 1.0; + else return -1.0; + } +} + MWMechanics::AiWander::AiWander(int distance, int duration, int timeOfDay, const std::vector& idle, bool repeat): mDistance(distance), mDuration(duration), mTimeOfDay(timeOfDay), mIdle(idle), mRepeat(repeat) { + std::cout << "AIWander: " << mDistance << " " << mDuration << " " << mTimeOfDay << " "; + for(unsigned short counter = 0; counter < mIdle.size(); counter++) + { + std::cout << mIdle[counter] << " "; + if(mIdle[counter] >= 127 || mIdle[counter] < 0) + mIdle[counter] = 0; + } + std::cout << mRepeat << std::endl; + + if(mDistance < 0) + mDistance = 0; + if(mDuration < 0) + mDuration = 0; + if(mDuration == 0) + mTimeOfDay = 0; + + srand(time(NULL)); + mStartTime = MWBase::Environment::get().getWorld()->getTimeStamp(); + mChanceMultiplyer = 0.75; + mPlayedIdle = 0; + + mStoredAvailableNodes = false; + mChooseAction = true; + mIdleNow = false; + mMoveNow = false; + mWalking = false; } MWMechanics::AiPackage * MWMechanics::AiWander::clone() const @@ -13,11 +58,259 @@ MWMechanics::AiPackage * MWMechanics::AiWander::clone() const bool MWMechanics::AiWander::execute (const MWWorld::Ptr& actor) { - // Return completed - return true; + if(mDuration) + { + // End package if duration is complete or mid-night hits: + MWWorld::TimeStamp currentTime = MWBase::Environment::get().getWorld()->getTimeStamp(); + if(currentTime.getHour() >= mStartTime.getHour() + mDuration) + { + if(!mRepeat) + { + stopWalking(actor, mPathFinder); + return true; + } + else + mStartTime = currentTime; + } + else if(int(currentTime.getHour()) == 0 && currentTime.getDay() != mStartTime.getDay()) + { + stopWalking(actor, mPathFinder); + + if(!mRepeat) + { + stopWalking(actor, mPathFinder); + return true; + } + else + mStartTime = currentTime; + } + } + + ESM::Position pos = actor.getRefData().getPosition(); + + if(!mStoredAvailableNodes) + { + mStoredAvailableNodes = true; + mPathgrid = + MWBase::Environment::get().getWorld()->getStore().get().search(*actor.getCell()->mCell); + + mCellX = actor.getCell()->mCell->mData.mX; + mCellY = actor.getCell()->mCell->mData.mY; + + if(mDistance != 0 && !mPathgrid->mPoints.empty()) + { + // TODO: Limit selecting range in the Z axis. + mXCell = 0; + mYCell = 0; + if(actor.getCell()->mCell->isExterior()) + { + mXCell = mCellX * ESM::Land::REAL_SIZE; + mYCell = mCellY * ESM::Land::REAL_SIZE; + } + + Ogre::Vector3 npcPos(actor.getRefData().getPosition().pos); + npcPos[0] = npcPos[0] - mXCell; + npcPos[1] = npcPos[1] - mYCell; + + for(unsigned int counter = 0; counter < mPathgrid->mPoints.size(); counter++) + { + Ogre::Vector3 nodePos(mPathgrid->mPoints[counter].mX, mPathgrid->mPoints[counter].mY, mPathgrid->mPoints[counter].mZ); + if(npcPos.squaredDistance(nodePos) <= mDistance * mDistance) + mAllowedNodes.push_back(mPathgrid->mPoints[counter]); + } + if(!mAllowedNodes.empty()) + { + Ogre::Vector3 firstNodePos(mAllowedNodes[0].mX, mAllowedNodes[0].mY, mAllowedNodes[0].mZ); + float closestNode = npcPos.squaredDistance(firstNodePos); + unsigned int index = 0; + for(unsigned int counterThree = 1; counterThree < mAllowedNodes.size(); counterThree++) + { + Ogre::Vector3 nodePos(mAllowedNodes[counterThree].mX, mAllowedNodes[counterThree].mY, mAllowedNodes[counterThree].mZ); + float tempDist = npcPos.squaredDistance(nodePos); + if(tempDist < closestNode) + index = counterThree; + } + mCurrentNode = mAllowedNodes[index]; + mAllowedNodes.erase(mAllowedNodes.begin() + index); + } + } + } + + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + bool cellChange = actor.getCell()->mCell->mData.mX != mCellX || actor.getCell()->mCell->mData.mY != mCellY; + + if(actor.getCell()->mCell->mData.mX != player.getCell()->mCell->mData.mX) + { + int sideX = sgn(actor.getCell()->mCell->mData.mX - player.getCell()->mCell->mData.mX); + // Check if actor is near the border of an inactive cell. If so, disable AiWander. + // FIXME: This *should* pause the AiWander package instead of terminating it. + if(sideX*(pos.pos[0] - actor.getCell()->mCell->mData.mX * ESM::Land::REAL_SIZE) > sideX * (ESM::Land::REAL_SIZE / 2.0 - 200)) + { + MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0; + return true; + } + } + + if(actor.getCell()->mCell->mData.mY != player.getCell()->mCell->mData.mY) + { + int sideY = sgn(actor.getCell()->mCell->mData.mY - player.getCell()->mCell->mData.mY); + // Check if actor is near the border of an inactive cell. If so, disable AiWander. + // FIXME: This *should* pause the AiWander package instead of terminating it. + if(sideY*(pos.pos[1] - actor.getCell()->mCell->mData.mY * ESM::Land::REAL_SIZE) > sideY * (ESM::Land::REAL_SIZE / 2.0 - 200)) + { + MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0; + return true; + } + } + + // Don't try to move if you are in a new cell (ie: positioncell command called) but still play idles. + if(cellChange || (mCellX != actor.getCell()->mCell->mData.mX || mCellY != actor.getCell()->mCell->mData.mY)) + mDistance = 0; + + if(mChooseAction) + { + mPlayedIdle = 0; + unsigned short idleRoll = 0; + + for(unsigned int counter = 1; counter < mIdle.size(); counter++) + { + unsigned short idleChance = mChanceMultiplyer * mIdle[counter]; + unsigned short randSelect = (int)(rand() / ((double)RAND_MAX + 1) * int(100 / mChanceMultiplyer)); + if(randSelect < idleChance && randSelect > idleRoll) + { + mPlayedIdle = counter; + idleRoll = randSelect; + } + } + + if(!mPlayedIdle && mDistance) + { + std::cout << "Walking!" << std::endl; + mChooseAction = false; + mMoveNow = true; + } + else + { + // Play idle animation and recreate vanilla (broken?) behavior of resetting start time of AIWander: + std::cout << "Idling!" << std::endl; + MWWorld::TimeStamp currentTime = MWBase::Environment::get().getWorld()->getTimeStamp(); + mStartTime = currentTime; + playIdle(actor, mPlayedIdle + 1); + mChooseAction = false; + mIdleNow = true; + } + } + + if(mIdleNow) + { + // TODO: This is where we should be checking to see if the current idle animation is done, if it is then + // set mChooseAction to true, because there is no function for this yet we will only set mChooseAction to true. + if(!checkIdle(actor, mPlayedIdle + 1)) + { + std::cout << "Idle Really Completed" << std::endl; + mPlayedIdle = 0; + mIdleNow = false; + mChooseAction = true; + } + } + + if(mMoveNow == true && (mDistance != 0 && !mAllowedNodes.empty())) + { + if(!mPathFinder.isPathConstructed()) + { + unsigned int randNode = (int)(rand() / ((double)RAND_MAX + 1) * mAllowedNodes.size()); + Ogre::Vector3 destNodePos(mAllowedNodes[randNode].mX, mAllowedNodes[randNode].mY, mAllowedNodes[randNode].mZ); + + // Remove this node as an option and add back the previously used node (stops NPC from picking the same node): + ESM::Pathgrid::Point temp = mAllowedNodes[randNode]; + mAllowedNodes.erase(mAllowedNodes.begin() + randNode); + mAllowedNodes.push_back(mCurrentNode); + mCurrentNode = temp; + + ESM::Pathgrid::Point dest; + dest.mX = destNodePos[0] + mXCell; + dest.mY = destNodePos[1] + mYCell; + dest.mZ = destNodePos[2]; + + ESM::Pathgrid::Point start; + start.mX = pos.pos[0]; + start.mY = pos.pos[1]; + start.mZ = pos.pos[2]; + + mPathFinder.buildPath(start,dest,mPathgrid,mXCell,mYCell); + mWalking = true; + } + } + + if(mWalking) + { + float zAngle = mPathFinder.getZAngleToNext(pos.pos[0],pos.pos[1],pos.pos[2]); + MWBase::Environment::get().getWorld()->rotateObject(actor,0,0,zAngle,false); + MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 1; + } + + if(mWalking && mPathFinder.checkIfNextPointReached(pos.pos[0],pos.pos[1],pos.pos[2])) + { + stopWalking(actor, mPathFinder); + mMoveNow = false; + mWalking = false; + mChooseAction = true; + } + + return false; } int MWMechanics::AiWander::getTypeId() const { return 0; } + +void MWMechanics::AiWander::stopWalking(const MWWorld::Ptr& actor, PathFinder& path) +{ + PathFinder pathClearer; + path = pathClearer; + MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0; +} + +void MWMechanics::AiWander::playIdle(const MWWorld::Ptr& actor, unsigned short idleSelect) +{ + if(idleSelect == 2) + MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, "idle2", 0, 1); + else if(idleSelect == 3) + MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, "idle3", 0, 1); + else if(idleSelect == 4) + MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, "idle4", 0, 1); + else if(idleSelect == 5) + MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, "idle5", 0, 1); + else if(idleSelect == 6) + MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, "idle6", 0, 1); + else if(idleSelect == 7) + MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, "idle7", 0, 1); + else if(idleSelect == 8) + MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, "idle8", 0, 1); + else if(idleSelect == 9) + MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, "idle9", 0, 1); +} + +bool MWMechanics::AiWander::checkIdle(const MWWorld::Ptr& actor, unsigned short idleSelect) +{ + if(idleSelect == 2) + return MWBase::Environment::get().getMechanicsManager()->checkAnimationPlaying(actor, "idle2"); + else if(idleSelect == 3) + return MWBase::Environment::get().getMechanicsManager()->checkAnimationPlaying(actor, "idle3"); + else if(idleSelect == 4) + return MWBase::Environment::get().getMechanicsManager()->checkAnimationPlaying(actor, "idle4"); + else if(idleSelect == 5) + return MWBase::Environment::get().getMechanicsManager()->checkAnimationPlaying(actor, "idle5"); + else if(idleSelect == 6) + return MWBase::Environment::get().getMechanicsManager()->checkAnimationPlaying(actor, "idle6"); + else if(idleSelect == 7) + return MWBase::Environment::get().getMechanicsManager()->checkAnimationPlaying(actor, "idle7"); + else if(idleSelect == 8) + return MWBase::Environment::get().getMechanicsManager()->checkAnimationPlaying(actor, "idle8"); + else if(idleSelect == 9) + return MWBase::Environment::get().getMechanicsManager()->checkAnimationPlaying(actor, "idle9"); + else + return false; +} + diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index e06e714bc..0a00059cc 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -4,6 +4,10 @@ #include "aipackage.hpp" #include +#include "pathfinding.hpp" + +#include "../mwworld/timestamp.hpp" + namespace MWMechanics { class AiWander : public AiPackage @@ -18,11 +22,42 @@ namespace MWMechanics ///< 0: Wander private: + void stopWalking(const MWWorld::Ptr& actor, PathFinder& path); + void playIdle(const MWWorld::Ptr& actor, unsigned short idleSelect); + bool checkIdle(const MWWorld::Ptr& actor, unsigned short idleSelect); + int mDistance; int mDuration; int mTimeOfDay; std::vector mIdle; bool mRepeat; + + float mX; + float mY; + float mZ; + + int mCellX; + int mCellY; + float mXCell; + float mYCell; + + bool mStoredAvailableNodes; + bool mChooseAction; + bool mIdleNow; + bool mMoveNow; + bool mWalking; + + float mChanceMultiplyer; + unsigned short mPlayedIdle; + + MWWorld::TimeStamp mStartTime; + + std::vector mAllowedNodes; + ESM::Pathgrid::Point mCurrentNode; + + PathFinder mPathFinder; + const ESM::Pathgrid *mPathgrid; + }; } From 96daad7a226e0fe83bd2e9c92e3c752c283a5286 Mon Sep 17 00:00:00 2001 From: Torben Carrington Date: Sun, 26 May 2013 09:31:56 -0700 Subject: [PATCH 13/52] AIWander - shortened some if statements and made super minor optimizations to others, now using proper GMST to load proper idlechance instead of hacky set value." --- apps/openmw/mwmechanics/aiwander.cpp | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 52ab34f24..fd96071cc 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -41,8 +41,9 @@ MWMechanics::AiWander::AiWander(int distance, int duration, int timeOfDay, const srand(time(NULL)); mStartTime = MWBase::Environment::get().getWorld()->getTimeStamp(); - mChanceMultiplyer = 0.75; mPlayedIdle = 0; + mChanceMultiplyer = + MWBase::Environment::get().getWorld()->getStore().get().find("fIdleChanceMultiplier")->getFloat(); mStoredAvailableNodes = false; mChooseAction = true; @@ -74,8 +75,6 @@ bool MWMechanics::AiWander::execute (const MWWorld::Ptr& actor) } else if(int(currentTime.getHour()) == 0 && currentTime.getDay() != mStartTime.getDay()) { - stopWalking(actor, mPathFinder); - if(!mRepeat) { stopWalking(actor, mPathFinder); @@ -97,7 +96,7 @@ bool MWMechanics::AiWander::execute (const MWWorld::Ptr& actor) mCellX = actor.getCell()->mCell->mData.mX; mCellY = actor.getCell()->mCell->mData.mY; - if(mDistance != 0 && !mPathgrid->mPoints.empty()) + if(mDistance && !mPathgrid->mPoints.empty()) { // TODO: Limit selecting range in the Z axis. mXCell = 0; @@ -164,7 +163,7 @@ bool MWMechanics::AiWander::execute (const MWWorld::Ptr& actor) } // Don't try to move if you are in a new cell (ie: positioncell command called) but still play idles. - if(cellChange || (mCellX != actor.getCell()->mCell->mData.mX || mCellY != actor.getCell()->mCell->mData.mY)) + if(mDistance && (cellChange || (mCellX != actor.getCell()->mCell->mData.mX || mCellY != actor.getCell()->mCell->mData.mY))) mDistance = 0; if(mChooseAction) @@ -185,14 +184,12 @@ bool MWMechanics::AiWander::execute (const MWWorld::Ptr& actor) if(!mPlayedIdle && mDistance) { - std::cout << "Walking!" << std::endl; mChooseAction = false; mMoveNow = true; } else { // Play idle animation and recreate vanilla (broken?) behavior of resetting start time of AIWander: - std::cout << "Idling!" << std::endl; MWWorld::TimeStamp currentTime = MWBase::Environment::get().getWorld()->getTimeStamp(); mStartTime = currentTime; playIdle(actor, mPlayedIdle + 1); @@ -203,18 +200,15 @@ bool MWMechanics::AiWander::execute (const MWWorld::Ptr& actor) if(mIdleNow) { - // TODO: This is where we should be checking to see if the current idle animation is done, if it is then - // set mChooseAction to true, because there is no function for this yet we will only set mChooseAction to true. if(!checkIdle(actor, mPlayedIdle + 1)) { - std::cout << "Idle Really Completed" << std::endl; mPlayedIdle = 0; mIdleNow = false; mChooseAction = true; } } - if(mMoveNow == true && (mDistance != 0 && !mAllowedNodes.empty())) + if(mMoveNow && mDistance && !mAllowedNodes.empty()) { if(!mPathFinder.isPathConstructed()) { From fd96d47fe4ab81af86d8dc89b39b399f9d6bf014 Mon Sep 17 00:00:00 2001 From: Torben Carrington Date: Sun, 26 May 2013 11:30:42 -0700 Subject: [PATCH 14/52] AIWander Completed. Replicates vanilla as best possible, pathfinding needs fixing before this looks correct but once the pathfinding files are edited this will behave pretty much exactly as vanilla. Major credit to Hrnchamd for major research. --- apps/openmw/mwmechanics/aiwander.cpp | 34 ++++++++++++++++------------ apps/openmw/mwmechanics/aiwander.hpp | 2 +- 2 files changed, 20 insertions(+), 16 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index fd96071cc..67f9cc112 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -1,5 +1,4 @@ #include "aiwander.hpp" -#include #include "movement.hpp" @@ -23,14 +22,11 @@ namespace MWMechanics::AiWander::AiWander(int distance, int duration, int timeOfDay, const std::vector& idle, bool repeat): mDistance(distance), mDuration(duration), mTimeOfDay(timeOfDay), mIdle(idle), mRepeat(repeat) { - std::cout << "AIWander: " << mDistance << " " << mDuration << " " << mTimeOfDay << " "; for(unsigned short counter = 0; counter < mIdle.size(); counter++) { - std::cout << mIdle[counter] << " "; if(mIdle[counter] >= 127 || mIdle[counter] < 0) mIdle[counter] = 0; } - std::cout << mRepeat << std::endl; if(mDistance < 0) mDistance = 0; @@ -42,7 +38,7 @@ MWMechanics::AiWander::AiWander(int distance, int duration, int timeOfDay, const srand(time(NULL)); mStartTime = MWBase::Environment::get().getWorld()->getTimeStamp(); mPlayedIdle = 0; - mChanceMultiplyer = + mIdleChanceMultiplier = MWBase::Environment::get().getWorld()->getStore().get().find("fIdleChanceMultiplier")->getFloat(); mStoredAvailableNodes = false; @@ -98,7 +94,6 @@ bool MWMechanics::AiWander::execute (const MWWorld::Ptr& actor) if(mDistance && !mPathgrid->mPoints.empty()) { - // TODO: Limit selecting range in the Z axis. mXCell = 0; mYCell = 0; if(actor.getCell()->mCell->isExterior()) @@ -173,8 +168,8 @@ bool MWMechanics::AiWander::execute (const MWWorld::Ptr& actor) for(unsigned int counter = 1; counter < mIdle.size(); counter++) { - unsigned short idleChance = mChanceMultiplyer * mIdle[counter]; - unsigned short randSelect = (int)(rand() / ((double)RAND_MAX + 1) * int(100 / mChanceMultiplyer)); + unsigned short idleChance = mIdleChanceMultiplier * mIdle[counter]; + unsigned short randSelect = (int)(rand() / ((double)RAND_MAX + 1) * int(100 / mIdleChanceMultiplier)); if(randSelect < idleChance && randSelect > idleRoll) { mPlayedIdle = counter; @@ -241,14 +236,23 @@ bool MWMechanics::AiWander::execute (const MWWorld::Ptr& actor) float zAngle = mPathFinder.getZAngleToNext(pos.pos[0],pos.pos[1],pos.pos[2]); MWBase::Environment::get().getWorld()->rotateObject(actor,0,0,zAngle,false); MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 1; - } - if(mWalking && mPathFinder.checkIfNextPointReached(pos.pos[0],pos.pos[1],pos.pos[2])) - { - stopWalking(actor, mPathFinder); - mMoveNow = false; - mWalking = false; - mChooseAction = true; + // Unclog path nodes by allowing the NPC to be a small distance away from the center. This way two NPCs can be + // at the same path node at the same time and both will complete instead of endlessly walking into eachother: + Ogre::Vector3 destNodePos(mCurrentNode.mX, mCurrentNode.mY, mCurrentNode.mZ); + Ogre::Vector3 actorPos(actor.getRefData().getPosition().pos); + actorPos[0] = actorPos[0] - mXCell; + actorPos[1] = actorPos[1] - mYCell; + float distance = actorPos.squaredDistance(destNodePos); + + if(distance < 1200 || mPathFinder.checkIfNextPointReached(pos.pos[0],pos.pos[1],pos.pos[2])) + { + stopWalking(actor, mPathFinder); + mMoveNow = false; + mWalking = false; + mChooseAction = true; + } + } return false; diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index 0a00059cc..cf3820527 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -47,7 +47,7 @@ namespace MWMechanics bool mMoveNow; bool mWalking; - float mChanceMultiplyer; + float mIdleChanceMultiplier; unsigned short mPlayedIdle; MWWorld::TimeStamp mStartTime; From 3a6e54c4f515d1643506a5a672f4bd76c6b786e6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 27 May 2013 02:18:36 +0200 Subject: [PATCH 15/52] Sell owned items in the cell --- apps/openmw/mwbase/world.hpp | 2 + apps/openmw/mwgui/containeritemmodel.cpp | 71 +++++++++++++++++++++-- apps/openmw/mwgui/containeritemmodel.hpp | 3 +- apps/openmw/mwgui/itemmodel.cpp | 34 +++++++++-- apps/openmw/mwgui/sortfilteritemmodel.cpp | 2 +- apps/openmw/mwgui/tradewindow.cpp | 4 +- apps/openmw/mwworld/worldimp.cpp | 27 +++++++++ apps/openmw/mwworld/worldimp.hpp | 2 + 8 files changed, 131 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index de1a34792..86a6a89d2 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -342,6 +342,8 @@ namespace MWBase virtual void getContainersOwnedBy (const MWWorld::Ptr& npc, std::vector& out) = 0; ///< get all containers in active cells owned by this Npc + virtual void getItemsOwnedBy (const MWWorld::Ptr& npc, std::vector& out) = 0; + ///< get all items in active cells owned by this Npc virtual void setupExternalRendering (MWRender::ExternalRendering& rendering) = 0; diff --git a/apps/openmw/mwgui/containeritemmodel.cpp b/apps/openmw/mwgui/containeritemmodel.cpp index 79351c6ca..5d23744b2 100644 --- a/apps/openmw/mwgui/containeritemmodel.cpp +++ b/apps/openmw/mwgui/containeritemmodel.cpp @@ -3,11 +3,39 @@ #include "../mwworld/containerstore.hpp" #include "../mwworld/class.hpp" +#include "../mwbase/world.hpp" +#include "../mwbase/environment.hpp" + +namespace +{ + + bool stacks (const MWWorld::Ptr& left, const MWWorld::Ptr& right) + { + if (left == right) + return true; + + // If one of the items is in an inventory and currently equipped, we need to check stacking both ways to be sure + if (left.getContainerStore() && right.getContainerStore()) + return left.getContainerStore()->stacks(left, right) + && right.getContainerStore()->stacks(left, right); + + if (left.getContainerStore()) + return left.getContainerStore()->stacks(left, right); + if (right.getContainerStore()) + return right.getContainerStore()->stacks(left, right); + + MWWorld::ContainerStore store; + return store.stacks(left, right); + } + +} + namespace MWGui { -ContainerItemModel::ContainerItemModel(const std::vector& itemSources) +ContainerItemModel::ContainerItemModel(const std::vector& itemSources, const std::vector& worldItems) : mItemSources(itemSources) + , mWorldItems(worldItems) { assert (mItemSources.size()); } @@ -65,8 +93,7 @@ void ContainerItemModel::removeItem (const ItemStack& item, size_t count) for (MWWorld::ContainerStoreIterator it = store.begin(); it != store.end(); ++it) { - // If one of the items is in an inventory and currently equipped, we need to check stacking both ways to be sure - if (*it == item.mBase || (store.stacks(*it, item.mBase) && item.mBase.getContainerStore()->stacks(*it, item.mBase))) + if (stacks(*it, item.mBase)) { int refCount = it->getRefData().getCount(); it->getRefData().setCount(std::max(0, refCount - toRemove)); @@ -76,6 +103,21 @@ void ContainerItemModel::removeItem (const ItemStack& item, size_t count) } } } + for (std::vector::iterator source = mWorldItems.begin(); source != mWorldItems.end(); ++source) + { + if (stacks(*source, item.mBase)) + { + int refCount = source->getRefData().getCount(); + if (refCount - toRemove <= 0) + MWBase::Environment::get().getWorld()->deleteObject(*source); + else + source->getRefData().setCount(std::max(0, refCount - toRemove)); + toRemove -= refCount; + if (toRemove <= 0) + return; + } + } + throw std::runtime_error("Not enough items to remove could be found"); } @@ -91,8 +133,7 @@ void ContainerItemModel::update() std::vector::iterator itemStack = mItems.begin(); for (; itemStack != mItems.end(); ++itemStack) { - // If one of the items is in an inventory and currently equipped, we need to check stacking both ways to be sure - if (store.stacks(itemStack->mBase, *it) && it->getContainerStore()->stacks(itemStack->mBase, *it)) + if (stacks(*it, itemStack->mBase)) { // we already have an item stack of this kind, add to it itemStack->mCount += it->getRefData().getCount(); @@ -108,6 +149,26 @@ void ContainerItemModel::update() } } } + for (std::vector::iterator source = mWorldItems.begin(); source != mWorldItems.end(); ++source) + { + std::vector::iterator itemStack = mItems.begin(); + for (; itemStack != mItems.end(); ++itemStack) + { + if (stacks(*source, itemStack->mBase)) + { + // we already have an item stack of this kind, add to it + itemStack->mCount += source->getRefData().getCount(); + break; + } + } + + if (itemStack == mItems.end()) + { + // no stack yet, create one + ItemStack newItem (*source, this, source->getRefData().getCount()); + mItems.push_back(newItem); + } + } } } diff --git a/apps/openmw/mwgui/containeritemmodel.hpp b/apps/openmw/mwgui/containeritemmodel.hpp index 2f4c708ba..22595582e 100644 --- a/apps/openmw/mwgui/containeritemmodel.hpp +++ b/apps/openmw/mwgui/containeritemmodel.hpp @@ -11,7 +11,7 @@ namespace MWGui class ContainerItemModel : public ItemModel { public: - ContainerItemModel (const std::vector& itemSources); + ContainerItemModel (const std::vector& itemSources, const std::vector& worldItems); ///< @note The order of elements \a itemSources matters here. The first element has the highest priority for removal, /// while the last element will be used to add new items to. @@ -28,6 +28,7 @@ namespace MWGui private: std::vector mItemSources; + std::vector mWorldItems; std::vector mItems; }; diff --git a/apps/openmw/mwgui/itemmodel.cpp b/apps/openmw/mwgui/itemmodel.cpp index 0dc2bb62c..58e89c4fc 100644 --- a/apps/openmw/mwgui/itemmodel.cpp +++ b/apps/openmw/mwgui/itemmodel.cpp @@ -13,8 +13,6 @@ namespace MWGui , mType(Type_Normal) , mBase(base) { - assert(base.getContainerStore()); - if (MWWorld::Class::get(base).getEnchantment(base) != "") mFlags |= Flag_Enchanted; } @@ -31,18 +29,42 @@ namespace MWGui { if(mBase == other.mBase) return true; - return mBase.getContainerStore()->stacks(mBase, other.mBase) - && other.mBase.getContainerStore()->stacks(mBase, other.mBase); + + // If one of the items is in an inventory and currently equipped, we need to check stacking both ways to be sure + if (mBase.getContainerStore() && other.mBase.getContainerStore()) + return mBase.getContainerStore()->stacks(mBase, other.mBase) + && other.mBase.getContainerStore()->stacks(mBase, other.mBase); + + if (mBase.getContainerStore()) + return mBase.getContainerStore()->stacks(mBase, other.mBase); + if (other.mBase.getContainerStore()) + return other.mBase.getContainerStore()->stacks(mBase, other.mBase); + + MWWorld::ContainerStore store; + return store.stacks(mBase, other.mBase); + } bool operator == (const ItemStack& left, const ItemStack& right) { if (left.mType != right.mType) return false; + if(left.mBase == right.mBase) return true; - return left.mBase.getContainerStore()->stacks(left.mBase, right.mBase) - && right.mBase.getContainerStore()->stacks(left.mBase, right.mBase); + + // If one of the items is in an inventory and currently equipped, we need to check stacking both ways to be sure + if (left.mBase.getContainerStore() && right.mBase.getContainerStore()) + return left.mBase.getContainerStore()->stacks(left.mBase, right.mBase) + && right.mBase.getContainerStore()->stacks(left.mBase, right.mBase); + + if (left.mBase.getContainerStore()) + return left.mBase.getContainerStore()->stacks(left.mBase, right.mBase); + if (right.mBase.getContainerStore()) + return right.mBase.getContainerStore()->stacks(left.mBase, right.mBase); + + MWWorld::ContainerStore store; + return store.stacks(left.mBase, right.mBase); } ItemModel::ItemModel() diff --git a/apps/openmw/mwgui/sortfilteritemmodel.cpp b/apps/openmw/mwgui/sortfilteritemmodel.cpp index 60cc2fb0e..b88ec7c0b 100644 --- a/apps/openmw/mwgui/sortfilteritemmodel.cpp +++ b/apps/openmw/mwgui/sortfilteritemmodel.cpp @@ -71,7 +71,7 @@ namespace MWGui if (item.mType == ItemStack::Type_Equipped && !mShowEquipped) return false; - int category; + int category = 0; if (base.getTypeName() == typeid(ESM::Armor).name() || base.getTypeName() == typeid(ESM::Clothing).name()) category = Category_Apparel; diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index 6a46478af..01f7e2419 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -88,8 +88,10 @@ namespace MWGui MWBase::Environment::get().getWorld()->getContainersOwnedBy(actor, itemSources); // Important: actor goes last, so that items purchased by the merchant go into his inventory itemSources.push_back(actor); + std::vector worldItems; + MWBase::Environment::get().getWorld()->getItemsOwnedBy(actor, worldItems); - mTradeModel = new TradeItemModel(new ContainerItemModel(itemSources), mPtr); + mTradeModel = new TradeItemModel(new ContainerItemModel(itemSources, worldItems), mPtr); mSortModel = new SortFilterItemModel(mTradeModel); mItemView->setModel (mSortModel); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 8b76efdae..16cba2ea8 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1724,4 +1724,31 @@ namespace MWWorld } } } + + struct ListHandlesFunctor + { + std::vector mHandles; + + bool operator() (ESM::CellRef& ref, RefData& data) + { + Ogre::SceneNode* handle = data.getBaseNode(); + if (handle) + mHandles.push_back(handle->getName()); + return true; + } + }; + + void World::getItemsOwnedBy (const MWWorld::Ptr& npc, std::vector& out) + { + const Scene::CellStoreCollection& collection = mWorldScene->getActiveCells(); + for (Scene::CellStoreCollection::const_iterator cellIt = collection.begin(); cellIt != collection.end(); ++cellIt) + { + ListHandlesFunctor functor; + (*cellIt)->forEach(functor); + + for (std::vector::iterator it = functor.mHandles.begin(); it != functor.mHandles.end(); ++it) + if (Misc::StringUtils::ciEqual(searchPtrViaHandle(*it).mCellRef->mOwner, npc.getCellRef().mRefID)) + out.push_back(searchPtrViaHandle(*it)); + } + } } diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 1baf3d4ba..12438efd4 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -391,6 +391,8 @@ namespace MWWorld virtual void getContainersOwnedBy (const MWWorld::Ptr& npc, std::vector& out); ///< get all containers in active cells owned by this Npc + virtual void getItemsOwnedBy (const MWWorld::Ptr& npc, std::vector& out); + ///< get all items in active cells owned by this Npc virtual void setupExternalRendering (MWRender::ExternalRendering& rendering); From feb180724cb5a94ad856d1a2c8f0b71947cf0d8b Mon Sep 17 00:00:00 2001 From: Torben Carrington Date: Sun, 26 May 2013 19:33:45 -0700 Subject: [PATCH 16/52] AI Execution Fix - Preiovusly AiExecute was being called even when in a menu, this was not correct behavior. --- apps/openmw/mwmechanics/actors.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 00f2ac6fe..37bba6d3a 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -30,7 +30,8 @@ namespace MWMechanics // AI CreatureStats& creatureStats = MWWorld::Class::get (ptr).getCreatureStats (ptr); - creatureStats.getAiSequence().execute (ptr); + if(!MWBase::Environment::get().getWindowManager()->isGuiMode()) + creatureStats.getAiSequence().execute (ptr); } void Actors::updateNpc (const MWWorld::Ptr& ptr, float duration, bool paused) From 3b43ee751e2999d9599b476f0367507eed5079eb Mon Sep 17 00:00:00 2001 From: Torben Carrington Date: Sun, 26 May 2013 19:54:59 -0700 Subject: [PATCH 17/52] AI Execute Fix - May as well not create the object either to save extra time. --- apps/openmw/mwmechanics/actors.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 37bba6d3a..e85aa9b83 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -29,9 +29,11 @@ namespace MWMechanics calculateCreatureStatModifiers (ptr); // AI - CreatureStats& creatureStats = MWWorld::Class::get (ptr).getCreatureStats (ptr); if(!MWBase::Environment::get().getWindowManager()->isGuiMode()) + { + CreatureStats& creatureStats = MWWorld::Class::get (ptr).getCreatureStats (ptr); creatureStats.getAiSequence().execute (ptr); + } } void Actors::updateNpc (const MWWorld::Ptr& ptr, float duration, bool paused) From bd6d54cc8fdeafeaaa4328484aa978ef17f2d41b Mon Sep 17 00:00:00 2001 From: Torben Carrington Date: Mon, 27 May 2013 03:24:41 -0700 Subject: [PATCH 18/52] AIWander Minor Patch - Forgot an else statement and another check on an empty node vector, previously no nodes in range or only one would cause the AIWander to not do anything, now they will play idles correctly still. --- apps/openmw/mwmechanics/aiwander.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 67f9cc112..4f7b69016 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -126,7 +126,11 @@ bool MWMechanics::AiWander::execute (const MWWorld::Ptr& actor) } mCurrentNode = mAllowedNodes[index]; mAllowedNodes.erase(mAllowedNodes.begin() + index); + if(mAllowedNodes.empty()) + mDistance = 0; } + else + mDistance = 0; } } @@ -203,7 +207,7 @@ bool MWMechanics::AiWander::execute (const MWWorld::Ptr& actor) } } - if(mMoveNow && mDistance && !mAllowedNodes.empty()) + if(mMoveNow && mDistance) { if(!mPathFinder.isPathConstructed()) { From 56edc1b2139bbcf152c0a8285b92352f923d3c93 Mon Sep 17 00:00:00 2001 From: Miroslav Puda Date: Mon, 27 May 2013 12:26:06 +0200 Subject: [PATCH 19/52] Correction of getting spell range "Target". --- apps/openmw/mwmechanics/enchanting.cpp | 2 +- apps/openmw/mwmechanics/enchanting.hpp | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/enchanting.cpp b/apps/openmw/mwmechanics/enchanting.cpp index ded75f03a..e53a14120 100644 --- a/apps/openmw/mwmechanics/enchanting.cpp +++ b/apps/openmw/mwmechanics/enchanting.cpp @@ -160,7 +160,7 @@ namespace MWMechanics cost1 *= constDurationMultipler; cost2 *= 2; } - if(effect->mData.mFlags & ESM::MagicEffect::CastTarget) + if(it->mRange == ESM::RT_Target) cost1 *= 1.5; float fullcost = cost1+cost2; diff --git a/apps/openmw/mwmechanics/enchanting.hpp b/apps/openmw/mwmechanics/enchanting.hpp index 2831f9ddb..d7acf60e7 100644 --- a/apps/openmw/mwmechanics/enchanting.hpp +++ b/apps/openmw/mwmechanics/enchanting.hpp @@ -3,6 +3,7 @@ #include #include "../mwworld/ptr.hpp" #include +#include #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" namespace MWMechanics From 4788b5e2261c6ab0d1b8a63f1d3a6d70c6f87f7b Mon Sep 17 00:00:00 2001 From: Miroslav Puda Date: Mon, 27 May 2013 14:42:08 +0200 Subject: [PATCH 20/52] Better formula for enchantment cost and code refactorization. --- apps/openmw/mwgui/enchantingdialog.cpp | 6 +- apps/openmw/mwmechanics/enchanting.cpp | 97 +++++++++++++++----------- apps/openmw/mwmechanics/enchanting.hpp | 6 +- components/esm/defs.hpp | 9 +++ 4 files changed, 73 insertions(+), 45 deletions(-) diff --git a/apps/openmw/mwgui/enchantingdialog.cpp b/apps/openmw/mwgui/enchantingdialog.cpp index 799a89ab5..3672c2aec 100644 --- a/apps/openmw/mwgui/enchantingdialog.cpp +++ b/apps/openmw/mwgui/enchantingdialog.cpp @@ -70,7 +70,7 @@ namespace MWGui mPrice->setCaption(boost::lexical_cast(mEnchanting.getEnchantPrice())); - switch(mEnchanting.getEnchantType()) + switch(mEnchanting.getCastStyle()) { case 0: mTypeButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sItemCastOnce","Cast Once")); @@ -169,7 +169,7 @@ namespace MWGui image->eventMouseButtonClick += MyGUI::newDelegate(this, &EnchantingDialog::onRemoveItem); mEnchanting.setOldItem(item); - mEnchanting.nextEnchantType(); + mEnchanting.nextCastStyle(); updateLabels(); } @@ -248,7 +248,7 @@ namespace MWGui void EnchantingDialog::onTypeButtonClicked(MyGUI::Widget* sender) { - mEnchanting.nextEnchantType(); + mEnchanting.nextCastStyle(); updateLabels(); } diff --git a/apps/openmw/mwmechanics/enchanting.cpp b/apps/openmw/mwmechanics/enchanting.cpp index e53a14120..8efbf3c8c 100644 --- a/apps/openmw/mwmechanics/enchanting.cpp +++ b/apps/openmw/mwmechanics/enchanting.cpp @@ -12,7 +12,7 @@ namespace MWMechanics { Enchanting::Enchanting(): - mEnchantType(0) + mCastStyle(ESM::CS_CastOnce) {} void Enchanting::setOldItem(MWWorld::Ptr oldItem) @@ -41,9 +41,9 @@ namespace MWMechanics mEffectList=effectList; } - int Enchanting::getEnchantType() const + int Enchanting::getCastStyle() const { - return mEnchantType; + return mCastStyle; } void Enchanting::setSoulGem(MWWorld::Ptr soulGem) @@ -74,11 +74,11 @@ namespace MWMechanics MWWorld::Class::get (mEnchanter).skillUsageSucceeded (mEnchanter, ESM::Skill::Enchant, 1); } - if(mEnchantType==3) + if(mCastStyle==3) { enchantment.mData.mCharge=0; } - enchantment.mData.mType = mEnchantType; + enchantment.mData.mType = mCastStyle; enchantment.mData.mCost = getEnchantCost(); enchantment.mEffects = mEffectList; @@ -98,78 +98,97 @@ namespace MWMechanics return true; } - void Enchanting::nextEnchantType() + void Enchanting::nextCastStyle() { - mEnchantType++; + mCastStyle++; if (itemEmpty()) { - mEnchantType = 0; + mCastStyle = 0; return; } if ((mObjectType == typeid(ESM::Armor).name())||(mObjectType == typeid(ESM::Clothing).name())) { int soulConstAmount = MWBase::Environment::get().getWorld()->getStore().get().find ("iSoulAmountForConstantEffect")->getInt(); - switch(mEnchantType) + switch(mCastStyle) { case 1: - mEnchantType = 2; + mCastStyle = 2; case 3: if(getGemCharge() 2 or (2 + 0) == (1 + 2) => 3 + * + * Formula on UESPWiki is not entirely correct. + */ float Enchanting::getEnchantCost() const { + if (mEffectList.mList.empty()) + // No effects added, cost = 0 + return 0; + const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); - float cost = 0; std::vector mEffects = mEffectList.mList; - int i=mEffects.size(); - if(i<=0) - return 0; - /* - Formula from http://www.uesp.net/wiki/Morrowind:Enchant - */ + float enchantmentCost = 0; + int effectsLeftCnt = mEffects.size(); + float baseCost, magnitudeCost, areaCost; + int magMin, magMax, area; for (std::vector::const_iterator it = mEffects.begin(); it != mEffects.end(); ++it) { - const ESM::MagicEffect* effect = store.get().find(it->mEffectID); + baseCost = (store.get().find(it->mEffectID))->mData.mBaseCost; + // To reflect vanilla behavior + magMin = (it->mMagnMin == 0) ? 1 : it->mMagnMin; + magMax = (it->mMagnMax == 0) ? 1 : it->mMagnMax; + area = (it->mArea == 0) ? 1 : it->mArea; - float cost1 = ((it->mMagnMin + it->mMagnMax)*it->mDuration*effect->mData.mBaseCost*0.025); - - float cost2 = (std::max(1, it->mArea)*0.125*effect->mData.mBaseCost); - - if(mEnchantType==3) + if (mCastStyle == ESM::CS_ConstantEffect) { - int constDurationMultipler = MWBase::Environment::get().getWorld()->getStore().get().find ("fEnchantmentConstantDurationMult")->getFloat(); - cost1 *= constDurationMultipler; - cost2 *= 2; + magnitudeCost = (magMin + magMax) * baseCost * 2.5; + } + else + { + magnitudeCost = (magMin + magMax) * it->mDuration * baseCost * 0.025; + if(it->mRange == ESM::RT_Target) + magnitudeCost *= 1.5; } - if(it->mRange == ESM::RT_Target) - cost1 *= 1.5; - float fullcost = cost1+cost2; - fullcost*= i; - i--; + areaCost = area * 0.025 * baseCost; + if (it->mRange == ESM::RT_Target) + areaCost *= 1.5; - cost+=fullcost; + enchantmentCost += (magnitudeCost + areaCost) * effectsLeftCnt; + --effectsLeftCnt; } - return cost; + + return enchantmentCost; } int Enchanting::getEnchantPrice() const @@ -236,7 +255,7 @@ namespace MWMechanics + (0.125 * creatureStats.getAttribute (ESM::Attribute::Luck).getModified())); float chance2 = 2.5 * getEnchantCost(); - if(mEnchantType==3) + if(mCastStyle==3) { float constantChance = MWBase::Environment::get().getWorld()->getStore().get().find ("fEnchantmentConstantChanceMult")->getFloat(); chance2 /= constantChance; diff --git a/apps/openmw/mwmechanics/enchanting.hpp b/apps/openmw/mwmechanics/enchanting.hpp index d7acf60e7..a04bd86e9 100644 --- a/apps/openmw/mwmechanics/enchanting.hpp +++ b/apps/openmw/mwmechanics/enchanting.hpp @@ -14,7 +14,7 @@ namespace MWMechanics MWWorld::Ptr mSoulGemPtr; MWWorld::Ptr mEnchanter; - int mEnchantType; + int mCastStyle; bool mSelfEnchanting; @@ -34,8 +34,8 @@ namespace MWMechanics void setEffect(ESM::EffectList effectList); void setSoulGem(MWWorld::Ptr soulGem); bool create(); //Return true if created, false if failed. - void nextEnchantType(); //Set enchant type to next possible type (for mOldItemPtr object) - int getEnchantType() const; + void nextCastStyle(); //Set enchant type to next possible type (for mOldItemPtr object) + int getCastStyle() const; float getEnchantCost() const; int getEnchantPrice() const; float getMaxEnchantValue() const; diff --git a/components/esm/defs.hpp b/components/esm/defs.hpp index bd86f9ba0..f47463891 100644 --- a/components/esm/defs.hpp +++ b/components/esm/defs.hpp @@ -23,6 +23,15 @@ enum RangeType RT_Target = 2 }; +// Casting style (in enchanting) +enum Type +{ + CS_CastOnce = 0, + CS_WhenStrikes = 1, + CS_WhenUsed = 2, + CS_ConstantEffect = 3 +}; + #pragma pack(push) #pragma pack(1) From cfbdf3f7797427e2bf9004ef05209adc06e05a0e Mon Sep 17 00:00:00 2001 From: Miroslav Puda Date: Mon, 27 May 2013 15:37:31 +0200 Subject: [PATCH 21/52] Enum Type renamed to CastingStyle --- components/esm/defs.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esm/defs.hpp b/components/esm/defs.hpp index f47463891..7586413a6 100644 --- a/components/esm/defs.hpp +++ b/components/esm/defs.hpp @@ -24,7 +24,7 @@ enum RangeType }; // Casting style (in enchanting) -enum Type +enum CastingStyle { CS_CastOnce = 0, CS_WhenStrikes = 1, From 252a1d92231777ddf66247caba69a4abe62e59f8 Mon Sep 17 00:00:00 2001 From: Miroslav Puda Date: Mon, 27 May 2013 15:50:47 +0200 Subject: [PATCH 22/52] Replacement of some magical constants --- apps/openmw/mwgui/enchantingdialog.cpp | 8 ++++---- apps/openmw/mwmechanics/enchanting.cpp | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwgui/enchantingdialog.cpp b/apps/openmw/mwgui/enchantingdialog.cpp index 3672c2aec..86bdc25fc 100644 --- a/apps/openmw/mwgui/enchantingdialog.cpp +++ b/apps/openmw/mwgui/enchantingdialog.cpp @@ -72,19 +72,19 @@ namespace MWGui switch(mEnchanting.getCastStyle()) { - case 0: + case ESM::CS_CastOnce: mTypeButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sItemCastOnce","Cast Once")); mAddEffectDialog.constantEffect=false; break; - case 1: + case ESM::CS_WhenStrikes: mTypeButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sItemCastWhenStrikes", "When Strikes")); mAddEffectDialog.constantEffect=false; break; - case 2: + case ESM::CS_WhenUsed: mTypeButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sItemCastWhenUsed", "When Used")); mAddEffectDialog.constantEffect=false; break; - case 3: + case ESM::CS_ConstantEffect: mTypeButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sItemCastConstant", "Cast Constant")); mAddEffectDialog.constantEffect=true; break; diff --git a/apps/openmw/mwmechanics/enchanting.cpp b/apps/openmw/mwmechanics/enchanting.cpp index 8efbf3c8c..c7a67e7cb 100644 --- a/apps/openmw/mwmechanics/enchanting.cpp +++ b/apps/openmw/mwmechanics/enchanting.cpp @@ -74,7 +74,7 @@ namespace MWMechanics MWWorld::Class::get (mEnchanter).skillUsageSucceeded (mEnchanter, ESM::Skill::Enchant, 1); } - if(mCastStyle==3) + if(mCastStyle==ESM::CS_ConstantEffect) { enchantment.mData.mCharge=0; } @@ -255,7 +255,7 @@ namespace MWMechanics + (0.125 * creatureStats.getAttribute (ESM::Attribute::Luck).getModified())); float chance2 = 2.5 * getEnchantCost(); - if(mCastStyle==3) + if(mCastStyle==ESM::CS_ConstantEffect) { float constantChance = MWBase::Environment::get().getWorld()->getStore().get().find ("fEnchantmentConstantChanceMult")->getFloat(); chance2 /= constantChance; From 1c7b94e94f27df9d8d078db7178109650ccb4cfd Mon Sep 17 00:00:00 2001 From: Miroslav Puda Date: Mon, 27 May 2013 16:08:58 +0200 Subject: [PATCH 23/52] Switching in nextCastStyle() is now based on enum CastingStyle. --- apps/openmw/mwmechanics/enchanting.cpp | 49 +++++++++++++++++--------- 1 file changed, 32 insertions(+), 17 deletions(-) diff --git a/apps/openmw/mwmechanics/enchanting.cpp b/apps/openmw/mwmechanics/enchanting.cpp index c7a67e7cb..25aa0ea64 100644 --- a/apps/openmw/mwmechanics/enchanting.cpp +++ b/apps/openmw/mwmechanics/enchanting.cpp @@ -100,38 +100,53 @@ namespace MWMechanics void Enchanting::nextCastStyle() { - mCastStyle++; if (itemEmpty()) { - mCastStyle = 0; + mCastStyle = ESM::CS_WhenUsed; return; } - if ((mObjectType == typeid(ESM::Armor).name())||(mObjectType == typeid(ESM::Clothing).name())) - { - int soulConstAmount = MWBase::Environment::get().getWorld()->getStore().get().find ("iSoulAmountForConstantEffect")->getInt(); + + const bool powerfulSoul = getGemCharge() >= \ + MWBase::Environment::get().getWorld()->getStore().get().find ("iSoulAmountForConstantEffect")->getInt(); + if ((mObjectType == typeid(ESM::Armor).name()) || (mObjectType == typeid(ESM::Clothing).name())) + { // Armor or Clothing switch(mCastStyle) { - case 1: - mCastStyle = 2; - case 3: - if(getGemCharge() Date: Mon, 27 May 2013 18:03:06 +0200 Subject: [PATCH 24/52] Implement movement for creatures (formula is a stub) --- apps/openmw/mwclass/creature.cpp | 53 ++++++++++++++++++++++++++++++++ apps/openmw/mwclass/creature.hpp | 15 +++++++++ 2 files changed, 68 insertions(+) diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index a4eda7126..a263af464 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -5,6 +5,7 @@ #include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/magiceffects.hpp" +#include "../mwmechanics/movement.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/mechanicsmanager.hpp" @@ -29,6 +30,7 @@ namespace { MWMechanics::CreatureStats mCreatureStats; MWWorld::ContainerStore mContainerStore; + MWMechanics::Movement mMovement; virtual MWWorld::CustomData *clone() const; }; @@ -47,6 +49,18 @@ namespace MWClass { std::auto_ptr data (new CustomData); + static bool inited = false; + if(!inited) + { + const MWBase::World *world = MWBase::Environment::get().getWorld(); + const MWWorld::Store &gmst = world->getStore().get(); + + fMinWalkSpeedCreature = gmst.find("fMinWalkSpeedCreature"); + fMaxWalkSpeedCreature = gmst.find("fMaxWalkSpeedCreature"); + + inited = true; + } + MWWorld::LiveCellRef *ref = ptr.get(); // creature stats @@ -181,6 +195,42 @@ namespace MWClass return true; } + float Creature::getSpeed(const MWWorld::Ptr &ptr) const + { + MWMechanics::CreatureStats& stats = getCreatureStats(ptr); + float walkSpeed = fMinWalkSpeedCreature->getFloat() + 0.01 * stats.getAttribute(ESM::Attribute::Speed).getModified() + * (fMaxWalkSpeedCreature->getFloat() - fMinWalkSpeedCreature->getFloat()); + /// \todo what about the rest? + return walkSpeed; + } + + MWMechanics::Movement& Creature::getMovementSettings (const MWWorld::Ptr& ptr) const + { + ensureCustomData (ptr); + + return dynamic_cast (*ptr.getRefData().getCustomData()).mMovement; + } + + Ogre::Vector3 Creature::getMovementVector (const MWWorld::Ptr& ptr) const + { + MWMechanics::Movement &movement = getMovementSettings(ptr); + Ogre::Vector3 vec(movement.mPosition); + movement.mPosition[0] = 0.0f; + movement.mPosition[1] = 0.0f; + movement.mPosition[2] = 0.0f; + return vec; + } + + Ogre::Vector3 Creature::getRotationVector (const MWWorld::Ptr& ptr) const + { + MWMechanics::Movement &movement = getMovementSettings(ptr); + Ogre::Vector3 vec(movement.mRotation); + movement.mRotation[0] = 0.0f; + movement.mRotation[1] = 0.0f; + movement.mRotation[2] = 0.0f; + return vec; + } + MWGui::ToolTipInfo Creature::getToolTipInfo (const MWWorld::Ptr& ptr) const { MWWorld::LiveCellRef *ref = @@ -249,4 +299,7 @@ namespace MWClass return MWWorld::Ptr(&cell.mCreatures.insert(*ref), &cell); } + + const ESM::GameSetting* Creature::fMinWalkSpeedCreature; + const ESM::GameSetting* Creature::fMaxWalkSpeedCreature; } diff --git a/apps/openmw/mwclass/creature.hpp b/apps/openmw/mwclass/creature.hpp index b5657e265..5c30004cd 100644 --- a/apps/openmw/mwclass/creature.hpp +++ b/apps/openmw/mwclass/creature.hpp @@ -12,6 +12,9 @@ namespace MWClass virtual MWWorld::Ptr copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const; + static const ESM::GameSetting *fMinWalkSpeedCreature; + static const ESM::GameSetting *fMaxWalkSpeedCreature; + public: virtual std::string getId (const MWWorld::Ptr& ptr) const; @@ -66,6 +69,18 @@ namespace MWClass virtual bool isPersistent (const MWWorld::Ptr& ptr) const; + virtual MWMechanics::Movement& getMovementSettings (const MWWorld::Ptr& ptr) const; + ///< Return desired movement. + + virtual Ogre::Vector3 getMovementVector (const MWWorld::Ptr& ptr) const; + ///< Return desired movement vector (determined based on movement settings, + /// stance and stats). + + virtual Ogre::Vector3 getRotationVector (const MWWorld::Ptr& ptr) const; + ///< Return desired rotations, as euler angles. + + float getSpeed (const MWWorld::Ptr& ptr) const; + static void registerSelf(); virtual std::string getModel(const MWWorld::Ptr &ptr) const; From ebc1fdd017dfadcc45326bca8e6e4ee0ec330485 Mon Sep 17 00:00:00 2001 From: Torben Carrington Date: Mon, 27 May 2013 09:05:42 -0700 Subject: [PATCH 25/52] AIWander Patch - fixed another possibility of a bug occuring, best to fix it now then wait until it happens. --- apps/openmw/mwmechanics/aiwander.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 4f7b69016..0a7815ca4 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -92,7 +92,10 @@ bool MWMechanics::AiWander::execute (const MWWorld::Ptr& actor) mCellX = actor.getCell()->mCell->mData.mX; mCellY = actor.getCell()->mCell->mData.mY; - if(mDistance && !mPathgrid->mPoints.empty()) + if(mPathgrid->mPoints.empty()) + mDistance = 0; + + if(mDistance) { mXCell = 0; mYCell = 0; @@ -126,10 +129,9 @@ bool MWMechanics::AiWander::execute (const MWWorld::Ptr& actor) } mCurrentNode = mAllowedNodes[index]; mAllowedNodes.erase(mAllowedNodes.begin() + index); - if(mAllowedNodes.empty()) - mDistance = 0; } - else + + if(mAllowedNodes.empty()) mDistance = 0; } } From 9a9b075a02f55047ce861a5a20872f9f5dc5341d Mon Sep 17 00:00:00 2001 From: Miroslav Puda Date: Mon, 27 May 2013 18:08:12 +0200 Subject: [PATCH 26/52] Correct cast cost for enchantments. --- apps/openmw/mwgui/enchantingdialog.cpp | 2 +- apps/openmw/mwmechanics/enchanting.cpp | 18 ++++++++++++++++++ apps/openmw/mwmechanics/enchanting.hpp | 1 + 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/enchantingdialog.cpp b/apps/openmw/mwgui/enchantingdialog.cpp index 86bdc25fc..8353cf99e 100644 --- a/apps/openmw/mwgui/enchantingdialog.cpp +++ b/apps/openmw/mwgui/enchantingdialog.cpp @@ -66,7 +66,7 @@ namespace MWGui mCharge->setCaption(boost::lexical_cast(mEnchanting.getGemCharge())); - mCastCost->setCaption(boost::lexical_cast(mEnchanting.getEnchantCost())); + mCastCost->setCaption(boost::lexical_cast(mEnchanting.getCastCost())); mPrice->setCaption(boost::lexical_cast(mEnchanting.getEnchantPrice())); diff --git a/apps/openmw/mwmechanics/enchanting.cpp b/apps/openmw/mwmechanics/enchanting.cpp index 25aa0ea64..95d7694dc 100644 --- a/apps/openmw/mwmechanics/enchanting.cpp +++ b/apps/openmw/mwmechanics/enchanting.cpp @@ -206,6 +206,24 @@ namespace MWMechanics return enchantmentCost; } + + float Enchanting::getCastCost() const + { + const float enchantCost = getEnchantCost(); + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + MWMechanics::NpcStats &stats = MWWorld::Class::get(player).getNpcStats(player); + int eSkill = stats.getSkill(ESM::Skill::Enchant).getModified(); + + /* + * Each point of enchant skill above/under 10 subtracts/adds + * one percent of enchantment cost while minimum is 1. + */ + const float castCost = enchantCost - (enchantCost / 100) * (eSkill - 10); + + return (castCost < 1) ? 1 : castCost; + } + + int Enchanting::getEnchantPrice() const { if(mEnchanter.isEmpty()) diff --git a/apps/openmw/mwmechanics/enchanting.hpp b/apps/openmw/mwmechanics/enchanting.hpp index a04bd86e9..fefabd308 100644 --- a/apps/openmw/mwmechanics/enchanting.hpp +++ b/apps/openmw/mwmechanics/enchanting.hpp @@ -37,6 +37,7 @@ namespace MWMechanics void nextCastStyle(); //Set enchant type to next possible type (for mOldItemPtr object) int getCastStyle() const; float getEnchantCost() const; + float getCastCost() const; int getEnchantPrice() const; float getMaxEnchantValue() const; int getGemCharge() const; From 4e17bc1499e64fd9aee851b9dc91a3a606b261a2 Mon Sep 17 00:00:00 2001 From: Miroslav Puda Date: Mon, 27 May 2013 20:16:57 +0200 Subject: [PATCH 27/52] Fix for display of cast cost decimal value --- apps/openmw/mwgui/enchantingdialog.cpp | 4 +++- apps/openmw/mwmechanics/enchanting.cpp | 3 +++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/enchantingdialog.cpp b/apps/openmw/mwgui/enchantingdialog.cpp index 8353cf99e..7f71716ed 100644 --- a/apps/openmw/mwgui/enchantingdialog.cpp +++ b/apps/openmw/mwgui/enchantingdialog.cpp @@ -66,7 +66,9 @@ namespace MWGui mCharge->setCaption(boost::lexical_cast(mEnchanting.getGemCharge())); - mCastCost->setCaption(boost::lexical_cast(mEnchanting.getCastCost())); + std::stringstream castCost; + castCost << std::setprecision(1) << std::fixed << mEnchanting.getCastCost(); + mCastCost->setCaption(boost::lexical_cast(castCost.str())); mPrice->setCaption(boost::lexical_cast(mEnchanting.getEnchantPrice())); diff --git a/apps/openmw/mwmechanics/enchanting.cpp b/apps/openmw/mwmechanics/enchanting.cpp index 95d7694dc..821df8fba 100644 --- a/apps/openmw/mwmechanics/enchanting.cpp +++ b/apps/openmw/mwmechanics/enchanting.cpp @@ -209,6 +209,9 @@ namespace MWMechanics float Enchanting::getCastCost() const { + if (mCastStyle == ESM::CS_ConstantEffect) + return 0; + const float enchantCost = getEnchantCost(); MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); MWMechanics::NpcStats &stats = MWWorld::Class::get(player).getNpcStats(player); From b40e24c50c5461892911d30ed997b49fc1d07ba0 Mon Sep 17 00:00:00 2001 From: Miroslav Puda Date: Mon, 27 May 2013 20:23:04 +0200 Subject: [PATCH 28/52] Refactorization --- apps/openmw/mwgui/enchantingdialog.cpp | 12 +++---- apps/openmw/mwmechanics/enchanting.cpp | 44 +++++++++++++------------- apps/openmw/mwmechanics/enchanting.hpp | 2 +- components/esm/defs.hpp | 8 ++--- 4 files changed, 33 insertions(+), 33 deletions(-) diff --git a/apps/openmw/mwgui/enchantingdialog.cpp b/apps/openmw/mwgui/enchantingdialog.cpp index 7f71716ed..0db577de2 100644 --- a/apps/openmw/mwgui/enchantingdialog.cpp +++ b/apps/openmw/mwgui/enchantingdialog.cpp @@ -61,7 +61,7 @@ namespace MWGui void EnchantingDialog::updateLabels() { std::stringstream enchantCost; - enchantCost << std::setprecision(1) << std::fixed << mEnchanting.getEnchantCost(); + enchantCost << std::setprecision(1) << std::fixed << mEnchanting.getEnchantPoints(); mEnchantmentPoints->setCaption(enchantCost.str() + " / " + boost::lexical_cast(mEnchanting.getMaxEnchantValue())); mCharge->setCaption(boost::lexical_cast(mEnchanting.getGemCharge())); @@ -74,19 +74,19 @@ namespace MWGui switch(mEnchanting.getCastStyle()) { - case ESM::CS_CastOnce: + case ESM::CastingStyle_CastOnce: mTypeButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sItemCastOnce","Cast Once")); mAddEffectDialog.constantEffect=false; break; - case ESM::CS_WhenStrikes: + case ESM::CastingStyle_WhenStrikes: mTypeButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sItemCastWhenStrikes", "When Strikes")); mAddEffectDialog.constantEffect=false; break; - case ESM::CS_WhenUsed: + case ESM::CastingStyle_WhenUsed: mTypeButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sItemCastWhenUsed", "When Used")); mAddEffectDialog.constantEffect=false; break; - case ESM::CS_ConstantEffect: + case ESM::CastingStyle_ConstantEffect: mTypeButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sItemCastConstant", "Cast Constant")); mAddEffectDialog.constantEffect=true; break; @@ -280,7 +280,7 @@ namespace MWGui return; } - if (mEnchanting.getEnchantCost() > mEnchanting.getMaxEnchantValue()) + if (mEnchanting.getEnchantPoints() > mEnchanting.getMaxEnchantValue()) { MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage29}"); return; diff --git a/apps/openmw/mwmechanics/enchanting.cpp b/apps/openmw/mwmechanics/enchanting.cpp index 821df8fba..5be0d83e7 100644 --- a/apps/openmw/mwmechanics/enchanting.cpp +++ b/apps/openmw/mwmechanics/enchanting.cpp @@ -12,7 +12,7 @@ namespace MWMechanics { Enchanting::Enchanting(): - mCastStyle(ESM::CS_CastOnce) + mCastStyle(ESM::CastingStyle_CastOnce) {} void Enchanting::setOldItem(MWWorld::Ptr oldItem) @@ -74,12 +74,12 @@ namespace MWMechanics MWWorld::Class::get (mEnchanter).skillUsageSucceeded (mEnchanter, ESM::Skill::Enchant, 1); } - if(mCastStyle==ESM::CS_ConstantEffect) + if(mCastStyle==ESM::CastingStyle_ConstantEffect) { enchantment.mData.mCharge=0; } enchantment.mData.mType = mCastStyle; - enchantment.mData.mCost = getEnchantCost(); + enchantment.mData.mCost = getEnchantPoints(); enchantment.mEffects = mEffectList; const ESM::Enchantment *enchantmentPtr = MWBase::Environment::get().getWorld()->createRecord (enchantment); @@ -102,7 +102,7 @@ namespace MWMechanics { if (itemEmpty()) { - mCastStyle = ESM::CS_WhenUsed; + mCastStyle = ESM::CastingStyle_WhenUsed; return; } @@ -112,12 +112,12 @@ namespace MWMechanics { // Armor or Clothing switch(mCastStyle) { - case ESM::CS_WhenUsed: + case ESM::CastingStyle_WhenUsed: if (powerfulSoul) - mCastStyle = ESM::CS_ConstantEffect; + mCastStyle = ESM::CastingStyle_ConstantEffect; return; default: // takes care of Constant effect too - mCastStyle = ESM::CS_WhenUsed; + mCastStyle = ESM::CastingStyle_WhenUsed; return; } } @@ -125,28 +125,28 @@ namespace MWMechanics { // Weapon switch(mCastStyle) { - case ESM::CS_WhenStrikes: - mCastStyle = ESM::CS_WhenUsed; + case ESM::CastingStyle_WhenStrikes: + mCastStyle = ESM::CastingStyle_WhenUsed; return; - case ESM::CS_WhenUsed: + case ESM::CastingStyle_WhenUsed: if (powerfulSoul) - mCastStyle = ESM::CS_ConstantEffect; + mCastStyle = ESM::CastingStyle_ConstantEffect; else - mCastStyle = ESM::CS_WhenStrikes; + mCastStyle = ESM::CastingStyle_WhenStrikes; return; default: // takes care of Constant effect too - mCastStyle = ESM::CS_WhenStrikes; + mCastStyle = ESM::CastingStyle_WhenStrikes; return; } } else if(mObjectType == typeid(ESM::Book).name()) { // Scroll or Book - mCastStyle = ESM::CS_CastOnce; + mCastStyle = ESM::CastingStyle_CastOnce; return; } // Fail case - mCastStyle = ESM::CS_CastOnce; + mCastStyle = ESM::CastingStyle_CastOnce; } /* @@ -163,7 +163,7 @@ namespace MWMechanics * * Formula on UESPWiki is not entirely correct. */ - float Enchanting::getEnchantCost() const + float Enchanting::getEnchantPoints() const { if (mEffectList.mList.empty()) // No effects added, cost = 0 @@ -184,7 +184,7 @@ namespace MWMechanics magMax = (it->mMagnMax == 0) ? 1 : it->mMagnMax; area = (it->mArea == 0) ? 1 : it->mArea; - if (mCastStyle == ESM::CS_ConstantEffect) + if (mCastStyle == ESM::CastingStyle_ConstantEffect) { magnitudeCost = (magMin + magMax) * baseCost * 2.5; } @@ -209,10 +209,10 @@ namespace MWMechanics float Enchanting::getCastCost() const { - if (mCastStyle == ESM::CS_ConstantEffect) + if (mCastStyle == ESM::CastingStyle_ConstantEffect) return 0; - const float enchantCost = getEnchantCost(); + const float enchantCost = getEnchantPoints(); MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); MWMechanics::NpcStats &stats = MWWorld::Class::get(player).getNpcStats(player); int eSkill = stats.getSkill(ESM::Skill::Enchant).getModified(); @@ -233,7 +233,7 @@ namespace MWMechanics return 0; float priceMultipler = MWBase::Environment::get().getWorld()->getStore().get().find ("fEnchantmentValueMult")->getFloat(); - int price = MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mEnchanter, (getEnchantCost() * priceMultipler), true); + int price = MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mEnchanter, (getEnchantPoints() * priceMultipler), true); return price; } @@ -290,8 +290,8 @@ namespace MWMechanics (0.25 * creatureStats.getAttribute (ESM::Attribute::Intelligence).getModified()) + (0.125 * creatureStats.getAttribute (ESM::Attribute::Luck).getModified())); - float chance2 = 2.5 * getEnchantCost(); - if(mCastStyle==ESM::CS_ConstantEffect) + float chance2 = 2.5 * getEnchantPoints(); + if(mCastStyle==ESM::CastingStyle_ConstantEffect) { float constantChance = MWBase::Environment::get().getWorld()->getStore().get().find ("fEnchantmentConstantChanceMult")->getFloat(); chance2 /= constantChance; diff --git a/apps/openmw/mwmechanics/enchanting.hpp b/apps/openmw/mwmechanics/enchanting.hpp index fefabd308..4321e5bd6 100644 --- a/apps/openmw/mwmechanics/enchanting.hpp +++ b/apps/openmw/mwmechanics/enchanting.hpp @@ -36,7 +36,7 @@ namespace MWMechanics bool create(); //Return true if created, false if failed. void nextCastStyle(); //Set enchant type to next possible type (for mOldItemPtr object) int getCastStyle() const; - float getEnchantCost() const; + float getEnchantPoints() const; float getCastCost() const; int getEnchantPrice() const; float getMaxEnchantValue() const; diff --git a/components/esm/defs.hpp b/components/esm/defs.hpp index 7586413a6..cf7b586fc 100644 --- a/components/esm/defs.hpp +++ b/components/esm/defs.hpp @@ -26,10 +26,10 @@ enum RangeType // Casting style (in enchanting) enum CastingStyle { - CS_CastOnce = 0, - CS_WhenStrikes = 1, - CS_WhenUsed = 2, - CS_ConstantEffect = 3 + CastingStyle_CastOnce = 0, + CastingStyle_WhenStrikes = 1, + CastingStyle_WhenUsed = 2, + CastingStyle_ConstantEffect = 3 }; #pragma pack(push) From dbbc96f60032ed42ea427982b7206cf5922a2c7d Mon Sep 17 00:00:00 2001 From: Torben Carrington Date: Mon, 27 May 2013 11:44:46 -0700 Subject: [PATCH 29/52] AIWander Segmentation Fault Fix - Fixes the segmentation fault that used to occur when there was no pathgrid in the cell and a range was passed to AIWander. --- apps/openmw/mwmechanics/aiwander.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 0a7815ca4..46c5598cc 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -38,6 +38,7 @@ MWMechanics::AiWander::AiWander(int distance, int duration, int timeOfDay, const srand(time(NULL)); mStartTime = MWBase::Environment::get().getWorld()->getTimeStamp(); mPlayedIdle = 0; + mPathgrid = NULL; mIdleChanceMultiplier = MWBase::Environment::get().getWorld()->getStore().get().find("fIdleChanceMultiplier")->getFloat(); @@ -92,7 +93,9 @@ bool MWMechanics::AiWander::execute (const MWWorld::Ptr& actor) mCellX = actor.getCell()->mCell->mData.mX; mCellY = actor.getCell()->mCell->mData.mY; - if(mPathgrid->mPoints.empty()) + if(!mPathgrid) + mDistance = 0; + else if(mPathgrid->mPoints.empty()) mDistance = 0; if(mDistance) From 7a4a386cbe069c5e127efc97241dc9aa38ecd4ce Mon Sep 17 00:00:00 2001 From: Miroslav Puda Date: Mon, 27 May 2013 20:47:53 +0200 Subject: [PATCH 30/52] Removal of tab characters. --- apps/openmw/mwmechanics/enchanting.cpp | 88 +++++++++++++------------- 1 file changed, 44 insertions(+), 44 deletions(-) diff --git a/apps/openmw/mwmechanics/enchanting.cpp b/apps/openmw/mwmechanics/enchanting.cpp index 5be0d83e7..05d4c635f 100644 --- a/apps/openmw/mwmechanics/enchanting.cpp +++ b/apps/openmw/mwmechanics/enchanting.cpp @@ -107,7 +107,7 @@ namespace MWMechanics } const bool powerfulSoul = getGemCharge() >= \ - MWBase::Environment::get().getWorld()->getStore().get().find ("iSoulAmountForConstantEffect")->getInt(); + MWBase::Environment::get().getWorld()->getStore().get().find ("iSoulAmountForConstantEffect")->getInt(); if ((mObjectType == typeid(ESM::Armor).name()) || (mObjectType == typeid(ESM::Clothing).name())) { // Armor or Clothing switch(mCastStyle) @@ -126,17 +126,17 @@ namespace MWMechanics switch(mCastStyle) { case ESM::CastingStyle_WhenStrikes: - mCastStyle = ESM::CastingStyle_WhenUsed; - return; + mCastStyle = ESM::CastingStyle_WhenUsed; + return; case ESM::CastingStyle_WhenUsed: - if (powerfulSoul) - mCastStyle = ESM::CastingStyle_ConstantEffect; - else - mCastStyle = ESM::CastingStyle_WhenStrikes; - return; + if (powerfulSoul) + mCastStyle = ESM::CastingStyle_ConstantEffect; + else + mCastStyle = ESM::CastingStyle_WhenStrikes; + return; default: // takes care of Constant effect too - mCastStyle = ESM::CastingStyle_WhenStrikes; - return; + mCastStyle = ESM::CastingStyle_WhenStrikes; + return; } } else if(mObjectType == typeid(ESM::Book).name()) @@ -149,25 +149,25 @@ namespace MWMechanics mCastStyle = ESM::CastingStyle_CastOnce; } - /* - * Vanilla enchant cost formula: - * - * Touch/Self: (min + max) * baseCost * 0.025 * duration + area * baseCost * 0.025 - * Target: 1.5 * ((min + max) * baseCost * 0.025 * duration + area * baseCost * 0.025) - * Constant eff: (min + max) * baseCost * 2.5 + area * baseCost * 0.025 - * - * For multiple effects - cost of each effect is multiplied by number of effects that follows +1. - * - * Note: Minimal value inside formula for 'min' and 'max' is 1. So in vanilla: - * (0 + 0) == (1 + 0) == (1 + 1) => 2 or (2 + 0) == (1 + 2) => 3 - * - * Formula on UESPWiki is not entirely correct. - */ + /* + * Vanilla enchant cost formula: + * + * Touch/Self: (min + max) * baseCost * 0.025 * duration + area * baseCost * 0.025 + * Target: 1.5 * ((min + max) * baseCost * 0.025 * duration + area * baseCost * 0.025) + * Constant eff: (min + max) * baseCost * 2.5 + area * baseCost * 0.025 + * + * For multiple effects - cost of each effect is multiplied by number of effects that follows +1. + * + * Note: Minimal value inside formula for 'min' and 'max' is 1. So in vanilla: + * (0 + 0) == (1 + 0) == (1 + 1) => 2 or (2 + 0) == (1 + 2) => 3 + * + * Formula on UESPWiki is not entirely correct. + */ float Enchanting::getEnchantPoints() const { - if (mEffectList.mList.empty()) - // No effects added, cost = 0 - return 0; + if (mEffectList.mList.empty()) + // No effects added, cost = 0 + return 0; const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); std::vector mEffects = mEffectList.mList; @@ -186,18 +186,18 @@ namespace MWMechanics if (mCastStyle == ESM::CastingStyle_ConstantEffect) { - magnitudeCost = (magMin + magMax) * baseCost * 2.5; + magnitudeCost = (magMin + magMax) * baseCost * 2.5; } else { - magnitudeCost = (magMin + magMax) * it->mDuration * baseCost * 0.025; - if(it->mRange == ESM::RT_Target) - magnitudeCost *= 1.5; + magnitudeCost = (magMin + magMax) * it->mDuration * baseCost * 0.025; + if(it->mRange == ESM::RT_Target) + magnitudeCost *= 1.5; } areaCost = area * 0.025 * baseCost; if (it->mRange == ESM::RT_Target) - areaCost *= 1.5; + areaCost *= 1.5; enchantmentCost += (magnitudeCost + areaCost) * effectsLeftCnt; --effectsLeftCnt; @@ -209,21 +209,21 @@ namespace MWMechanics float Enchanting::getCastCost() const { - if (mCastStyle == ESM::CastingStyle_ConstantEffect) - return 0; + if (mCastStyle == ESM::CastingStyle_ConstantEffect) + return 0; - const float enchantCost = getEnchantPoints(); - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); - MWMechanics::NpcStats &stats = MWWorld::Class::get(player).getNpcStats(player); - int eSkill = stats.getSkill(ESM::Skill::Enchant).getModified(); + const float enchantCost = getEnchantPoints(); + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + MWMechanics::NpcStats &stats = MWWorld::Class::get(player).getNpcStats(player); + int eSkill = stats.getSkill(ESM::Skill::Enchant).getModified(); - /* - * Each point of enchant skill above/under 10 subtracts/adds - * one percent of enchantment cost while minimum is 1. - */ - const float castCost = enchantCost - (enchantCost / 100) * (eSkill - 10); + /* + * Each point of enchant skill above/under 10 subtracts/adds + * one percent of enchantment cost while minimum is 1. + */ + const float castCost = enchantCost - (enchantCost / 100) * (eSkill - 10); - return (castCost < 1) ? 1 : castCost; + return (castCost < 1) ? 1 : castCost; } From 9a4392707849456594ebbf17d8dc0bfe040a84a8 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 28 May 2013 03:15:13 +0200 Subject: [PATCH 31/52] Fix weapons not appearing in Enchantable filter --- apps/openmw/mwgui/sortfilteritemmodel.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwgui/sortfilteritemmodel.cpp b/apps/openmw/mwgui/sortfilteritemmodel.cpp index b88ec7c0b..3cf514dc5 100644 --- a/apps/openmw/mwgui/sortfilteritemmodel.cpp +++ b/apps/openmw/mwgui/sortfilteritemmodel.cpp @@ -106,6 +106,7 @@ namespace MWGui if ((mFilter & Filter_OnlyEnchantable) && (item.mFlags & ItemStack::Flag_Enchanted || (base.getTypeName() != typeid(ESM::Armor).name() && base.getTypeName() != typeid(ESM::Clothing).name() + && base.getTypeName() != typeid(ESM::Weapon).name() && base.getTypeName() != typeid(ESM::Book).name()))) return false; if ((mFilter & Filter_OnlyEnchantable) && base.getTypeName() == typeid(ESM::Book).name() From dc17fa16365fd3697d9443e898005bf9130fd05d Mon Sep 17 00:00:00 2001 From: Miroslav Puda Date: Wed, 29 May 2013 00:01:18 +0200 Subject: [PATCH 32/52] Removal of duplicit enumeration and unnecessary conditions. --- apps/openmw/mwgui/enchantingdialog.cpp | 8 ++--- apps/openmw/mwmechanics/enchanting.cpp | 42 ++++++++++++-------------- apps/openmw/mwmechanics/enchanting.hpp | 1 - components/esm/defs.hpp | 9 ------ 4 files changed, 23 insertions(+), 37 deletions(-) diff --git a/apps/openmw/mwgui/enchantingdialog.cpp b/apps/openmw/mwgui/enchantingdialog.cpp index 0db577de2..98ba8ec2f 100644 --- a/apps/openmw/mwgui/enchantingdialog.cpp +++ b/apps/openmw/mwgui/enchantingdialog.cpp @@ -74,19 +74,19 @@ namespace MWGui switch(mEnchanting.getCastStyle()) { - case ESM::CastingStyle_CastOnce: + case ESM::Enchantment::CastOnce: mTypeButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sItemCastOnce","Cast Once")); mAddEffectDialog.constantEffect=false; break; - case ESM::CastingStyle_WhenStrikes: + case ESM::Enchantment::WhenStrikes: mTypeButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sItemCastWhenStrikes", "When Strikes")); mAddEffectDialog.constantEffect=false; break; - case ESM::CastingStyle_WhenUsed: + case ESM::Enchantment::WhenUsed: mTypeButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sItemCastWhenUsed", "When Used")); mAddEffectDialog.constantEffect=false; break; - case ESM::CastingStyle_ConstantEffect: + case ESM::Enchantment::ConstantEffect: mTypeButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sItemCastConstant", "Cast Constant")); mAddEffectDialog.constantEffect=true; break; diff --git a/apps/openmw/mwmechanics/enchanting.cpp b/apps/openmw/mwmechanics/enchanting.cpp index 05d4c635f..faa450df7 100644 --- a/apps/openmw/mwmechanics/enchanting.cpp +++ b/apps/openmw/mwmechanics/enchanting.cpp @@ -12,7 +12,7 @@ namespace MWMechanics { Enchanting::Enchanting(): - mCastStyle(ESM::CastingStyle_CastOnce) + mCastStyle(ESM::Enchantment::CastOnce) {} void Enchanting::setOldItem(MWWorld::Ptr oldItem) @@ -74,7 +74,7 @@ namespace MWMechanics MWWorld::Class::get (mEnchanter).skillUsageSucceeded (mEnchanter, ESM::Skill::Enchant, 1); } - if(mCastStyle==ESM::CastingStyle_ConstantEffect) + if(mCastStyle==ESM::Enchantment::ConstantEffect) { enchantment.mData.mCharge=0; } @@ -102,7 +102,7 @@ namespace MWMechanics { if (itemEmpty()) { - mCastStyle = ESM::CastingStyle_WhenUsed; + mCastStyle = ESM::Enchantment::WhenUsed; return; } @@ -112,12 +112,12 @@ namespace MWMechanics { // Armor or Clothing switch(mCastStyle) { - case ESM::CastingStyle_WhenUsed: + case ESM::Enchantment::WhenUsed: if (powerfulSoul) - mCastStyle = ESM::CastingStyle_ConstantEffect; + mCastStyle = ESM::Enchantment::ConstantEffect; return; default: // takes care of Constant effect too - mCastStyle = ESM::CastingStyle_WhenUsed; + mCastStyle = ESM::Enchantment::WhenUsed; return; } } @@ -125,28 +125,28 @@ namespace MWMechanics { // Weapon switch(mCastStyle) { - case ESM::CastingStyle_WhenStrikes: - mCastStyle = ESM::CastingStyle_WhenUsed; + case ESM::Enchantment::WhenStrikes: + mCastStyle = ESM::Enchantment::WhenUsed; return; - case ESM::CastingStyle_WhenUsed: + case ESM::Enchantment::WhenUsed: if (powerfulSoul) - mCastStyle = ESM::CastingStyle_ConstantEffect; + mCastStyle = ESM::Enchantment::ConstantEffect; else - mCastStyle = ESM::CastingStyle_WhenStrikes; + mCastStyle = ESM::Enchantment::WhenStrikes; return; default: // takes care of Constant effect too - mCastStyle = ESM::CastingStyle_WhenStrikes; + mCastStyle = ESM::Enchantment::WhenStrikes; return; } } else if(mObjectType == typeid(ESM::Book).name()) { // Scroll or Book - mCastStyle = ESM::CastingStyle_CastOnce; + mCastStyle = ESM::Enchantment::CastOnce; return; } // Fail case - mCastStyle = ESM::CastingStyle_CastOnce; + mCastStyle = ESM::Enchantment::CastOnce; } /* @@ -184,7 +184,7 @@ namespace MWMechanics magMax = (it->mMagnMax == 0) ? 1 : it->mMagnMax; area = (it->mArea == 0) ? 1 : it->mArea; - if (mCastStyle == ESM::CastingStyle_ConstantEffect) + if (mCastStyle == ESM::Enchantment::ConstantEffect) { magnitudeCost = (magMin + magMax) * baseCost * 2.5; } @@ -209,7 +209,7 @@ namespace MWMechanics float Enchanting::getCastCost() const { - if (mCastStyle == ESM::CastingStyle_ConstantEffect) + if (mCastStyle == ESM::Enchantment::ConstantEffect) return 0; const float enchantCost = getEnchantPoints(); @@ -256,16 +256,12 @@ namespace MWMechanics } bool Enchanting::soulEmpty() const { - if (mSoulGemPtr.isEmpty()) - return true; - return false; + return mSoulGemPtr.isEmpty(); } bool Enchanting::itemEmpty() const { - if(mOldItemPtr.isEmpty()) - return true; - return false; + return mOldItemPtr.isEmpty(); } void Enchanting::setSelfEnchanting(bool selfEnchanting) @@ -291,7 +287,7 @@ namespace MWMechanics + (0.125 * creatureStats.getAttribute (ESM::Attribute::Luck).getModified())); float chance2 = 2.5 * getEnchantPoints(); - if(mCastStyle==ESM::CastingStyle_ConstantEffect) + if(mCastStyle==ESM::Enchantment::ConstantEffect) { float constantChance = MWBase::Environment::get().getWorld()->getStore().get().find ("fEnchantmentConstantChanceMult")->getFloat(); chance2 /= constantChance; diff --git a/apps/openmw/mwmechanics/enchanting.hpp b/apps/openmw/mwmechanics/enchanting.hpp index 4321e5bd6..a25fd43ab 100644 --- a/apps/openmw/mwmechanics/enchanting.hpp +++ b/apps/openmw/mwmechanics/enchanting.hpp @@ -3,7 +3,6 @@ #include #include "../mwworld/ptr.hpp" #include -#include #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" namespace MWMechanics diff --git a/components/esm/defs.hpp b/components/esm/defs.hpp index cf7b586fc..bd86f9ba0 100644 --- a/components/esm/defs.hpp +++ b/components/esm/defs.hpp @@ -23,15 +23,6 @@ enum RangeType RT_Target = 2 }; -// Casting style (in enchanting) -enum CastingStyle -{ - CastingStyle_CastOnce = 0, - CastingStyle_WhenStrikes = 1, - CastingStyle_WhenUsed = 2, - CastingStyle_ConstantEffect = 3 -}; - #pragma pack(push) #pragma pack(1) From 48386789446ba0f09ce055b0edd60b3f3bd0349e Mon Sep 17 00:00:00 2001 From: Torben Carrington Date: Wed, 29 May 2013 15:59:23 -0700 Subject: [PATCH 33/52] Pathfinding Overhaul - Cleanup, removed unnecessary include, fixed spacing, added a function for clearing a path, overall preperation to begin working on fixing pathfinding. --- apps/openmw/mwmechanics/pathfinding.cpp | 144 +++++++++++++----------- apps/openmw/mwmechanics/pathfinding.hpp | 25 ++-- 2 files changed, 89 insertions(+), 80 deletions(-) diff --git a/apps/openmw/mwmechanics/pathfinding.cpp b/apps/openmw/mwmechanics/pathfinding.cpp index 62c825be7..6d9089455 100644 --- a/apps/openmw/mwmechanics/pathfinding.cpp +++ b/apps/openmw/mwmechanics/pathfinding.cpp @@ -3,46 +3,48 @@ #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" +#include "OgreMath.h" + #include #include -#include "boost/tuple/tuple.hpp" -#include "OgreMath.h" namespace { - //helpers functions +//helpers functions float distanceZCorrected(ESM::Pathgrid::Point point,float x,float y,float z) { - return sqrt((point.mX - x)*(point.mX - x)+(point.mY - y)*(point.mY - y)+0.1*(point.mZ - z)*(point.mZ - z)); + return sqrt((point.mX - x) * (point.mX - x) + (point.mY - y) * (point.mY - y) + 0.1 * (point.mZ - z) * (point.mZ - z)); } float distance(ESM::Pathgrid::Point point,float x,float y,float z) { - return sqrt((point.mX - x)*(point.mX - x)+(point.mY - y)*(point.mY - y)+(point.mZ - z)*(point.mZ - z)); + return sqrt((point.mX - x) * (point.mX - x) + (point.mY - y) * (point.mY - y) + (point.mZ - z) * (point.mZ - z)); } float distance(ESM::Pathgrid::Point a,ESM::Pathgrid::Point b) { - return sqrt(float(a.mX - b.mX)*(a.mX - b.mX)+(a.mY - b.mY)*(a.mY - b.mY)+(a.mZ - b.mZ)*(a.mZ - b.mZ)); + return sqrt(float(a.mX - b.mX) * (a.mX - b.mX) + (a.mY - b.mY) * (a.mY - b.mY) + (a.mZ - b.mZ) * (a.mZ - b.mZ)); } static float sgn(float a) { - if(a>0) return 1.; - else return -1.; + if(a > 0) return 1.0; + else return -1.0; } int getClosestPoint(const ESM::Pathgrid* grid,float x,float y,float z) { - if(!grid) return -1; - if(grid->mPoints.empty()) return -1; + if(!grid) + return -1; + if(grid->mPoints.empty()) + return -1; float m = distance(grid->mPoints[0],x,y,z); int i0 = 0; - for(unsigned int i=1; imPoints.size();++i) + for(unsigned int i = 1; i < grid->mPoints.size(); ++i) { - if(distance(grid->mPoints[i],x,y,z)mPoints[i],x,y,z) < m) { m = distance(grid->mPoints[i],x,y,z); i0 = i; @@ -55,64 +57,64 @@ namespace boost::property,boost::property > PathGridGraph; typedef boost::property_map::type WeightMap; typedef PathGridGraph::vertex_descriptor PointID; - typedef PathGridGraph::edge_descriptor PointConnectionID; + typedef PathGridGraph::edge_descriptor PointConnectionID; struct found_path {}; /*class goalVisited : public boost::default_astar_visitor - { - public: - goalVisited(PointID goal) : mGoal(goal) {} +{ +public: +goalVisited(PointID goal) : mGoal(goal) {} - void examine_vertex(PointID u, const PathGridGraph g) - { - if(u == mGoal) - throw found_path(); - } - private: - PointID mGoal; - }; +void examine_vertex(PointID u, const PathGridGraph g) +{ +if(u == mGoal) +throw found_path(); +} +private: +PointID mGoal; +}; - class DistanceHeuristic : public boost::atasr_heuristic - { - public: - DistanceHeuristic(const PathGridGraph & l, PointID goal) - : mGraph(l), mGoal(goal) {} +class DistanceHeuristic : public boost::atasr_heuristic +{ +public: +DistanceHeuristic(const PathGridGraph & l, PointID goal) +: mGraph(l), mGoal(goal) {} - float operator()(PointID u) - { - const ESM::Pathgrid::Point & U = mGraph[u]; - const ESM::Pathgrid::Point & V = mGraph[mGoal]; - float dx = U.mX - V.mX; - float dy = U.mY - V.mY; - float dz = U.mZ - V.mZ; - return sqrt(dx * dx + dy * dy + dz * dz); - } - private: - const PathGridGraph & mGraph; - PointID mGoal; - };*/ - - class goalVisited : public boost::default_dijkstra_visitor - { - public: - goalVisited(PointID goal) : mGoal(goal) {} - - void examine_vertex(PointID u, const PathGridGraph g) - { - if(u == mGoal) - throw found_path(); - } - private: - PointID mGoal; - }; +float operator()(PointID u) +{ +const ESM::Pathgrid::Point & U = mGraph[u]; +const ESM::Pathgrid::Point & V = mGraph[mGoal]; +float dx = U.mX - V.mX; +float dy = U.mY - V.mY; +float dz = U.mZ - V.mZ; +return sqrt(dx * dx + dy * dy + dz * dz); +} +private: +const PathGridGraph & mGraph; +PointID mGoal; +};*/ + +class goalVisited : public boost::default_dijkstra_visitor +{ +public: +goalVisited(PointID goal) : mGoal(goal) {} + +void examine_vertex(PointID u, const PathGridGraph g) +{ +if(u == mGoal) +throw found_path(); +} +private: +PointID mGoal; +}; PathGridGraph buildGraph(const ESM::Pathgrid* pathgrid,float xCell = 0,float yCell = 0) { PathGridGraph graph; - for(unsigned int i = 0;imPoints.size();++i) + for(unsigned int i = 0; i < pathgrid->mPoints.size(); ++i) { PointID pID = boost::add_vertex(graph); graph[pID].mX = pathgrid->mPoints[i].mX + xCell; @@ -130,7 +132,6 @@ namespace boost::tie(edge,done) = boost::add_edge(u,v,graph); WeightMap weightmap = boost::get(boost::edge_weight, graph); weightmap[edge] = distance(graph[u],graph[v]); - } return graph; @@ -147,10 +148,10 @@ namespace graph, start, boost::predecessor_map(&p[0]).distance_map(&d[0]).visitor(goalVisited(end))//.weight_map(boost::get(&Edge::distance, graph)) - ); +); } catch(found_path fg) { - for(PointID v = end;; v = p[v]) { + for(PointID v = end; ; v = p[v]) { shortest_path.push_front(graph[v]); if(p[v] == v) break; @@ -170,6 +171,13 @@ namespace MWMechanics mIsPathConstructed = false; } + void PathFinder::clearPath() + { + if(!mPath.empty()) + mPath.clear(); + mIsPathConstructed = false; + } + void PathFinder::buildPath(ESM::Pathgrid::Point startPoint,ESM::Pathgrid::Point endPoint, const ESM::Pathgrid* pathGrid,float xCell,float yCell) { @@ -193,9 +201,8 @@ namespace MWMechanics float PathFinder::getZAngleToNext(float x,float y,float z) { if(mPath.empty()) - { - return 0;/// shouldn't happen! - } + return 0; /// shouldn't happen! + ESM::Pathgrid::Point nextPoint = *mPath.begin(); float dX = nextPoint.mX - x; float dY = nextPoint.mY - y; @@ -206,17 +213,16 @@ namespace MWMechanics bool PathFinder::checkIfNextPointReached(float x,float y,float z) { if(mPath.empty()) - { return true; - } + ESM::Pathgrid::Point nextPoint = *mPath.begin(); if(distanceZCorrected(nextPoint,x,y,z) < 20) { mPath.pop_front(); + if(mPath.empty()) - { return true; - } + nextPoint = *mPath.begin(); } return false; @@ -226,8 +232,10 @@ namespace MWMechanics { return mPath; } + bool PathFinder::isPathConstructed() { return mIsPathConstructed; } -} \ No newline at end of file +} + diff --git a/apps/openmw/mwmechanics/pathfinding.hpp b/apps/openmw/mwmechanics/pathfinding.hpp index b1bbab37a..dc380afb4 100644 --- a/apps/openmw/mwmechanics/pathfinding.hpp +++ b/apps/openmw/mwmechanics/pathfinding.hpp @@ -8,22 +8,23 @@ namespace MWMechanics { class PathFinder { - public: - PathFinder(); + public: + PathFinder(); - void buildPath(ESM::Pathgrid::Point startPoint,ESM::Pathgrid::Point endPoint, - const ESM::Pathgrid* pathGrid,float xCell = 0,float yCell = 0); + void clearPath(); + void buildPath(ESM::Pathgrid::Point startPoint,ESM::Pathgrid::Point endPoint, + const ESM::Pathgrid* pathGrid,float xCell = 0,float yCell = 0); - bool checkIfNextPointReached(float x,float y,float z);//returns true if the last point of the path has been reached. - float getZAngleToNext(float x,float y,float z); + bool checkIfNextPointReached(float x,float y,float z);//returns true if the last point of the path has been reached. + float getZAngleToNext(float x,float y,float z); - std::list getPath(); - bool isPathConstructed(); + std::list getPath(); + bool isPathConstructed(); - private: - std::list mPath; - bool mIsPathConstructed; + private: + std::list mPath; + bool mIsPathConstructed; }; } -#endif \ No newline at end of file +#endif From 96fdaf74109ce79065224d7787ce08563bf8326e Mon Sep 17 00:00:00 2001 From: Torben Carrington Date: Wed, 29 May 2013 16:10:15 -0700 Subject: [PATCH 34/52] Pathfinding Overhaul - More cleanup. --- apps/openmw/mwmechanics/pathfinding.cpp | 37 +++++++++++++------------ 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/apps/openmw/mwmechanics/pathfinding.cpp b/apps/openmw/mwmechanics/pathfinding.cpp index 6d9089455..b13bfa7af 100644 --- a/apps/openmw/mwmechanics/pathfinding.cpp +++ b/apps/openmw/mwmechanics/pathfinding.cpp @@ -10,7 +10,7 @@ namespace { -//helpers functions + // helpers functions float distanceZCorrected(ESM::Pathgrid::Point point,float x,float y,float z) { return sqrt((point.mX - x) * (point.mX - x) + (point.mY - y) * (point.mY - y) + 0.1 * (point.mZ - z) * (point.mZ - z)); @@ -28,8 +28,10 @@ namespace static float sgn(float a) { - if(a > 0) return 1.0; - else return -1.0; + if(a > 0) + return 1.0; + else + return -1.0; } int getClosestPoint(const ESM::Pathgrid* grid,float x,float y,float z) @@ -95,19 +97,20 @@ const PathGridGraph & mGraph; PointID mGoal; };*/ -class goalVisited : public boost::default_dijkstra_visitor -{ -public: -goalVisited(PointID goal) : mGoal(goal) {} + class goalVisited : public boost::default_dijkstra_visitor + { + public: + goalVisited(PointID goal) : mGoal(goal) {} -void examine_vertex(PointID u, const PathGridGraph g) -{ -if(u == mGoal) -throw found_path(); -} -private: -PointID mGoal; -}; + void examine_vertex(PointID u, const PathGridGraph g) + { + if(u == mGoal) + throw found_path(); + } + + private: + PointID mGoal; + }; PathGridGraph buildGraph(const ESM::Pathgrid* pathgrid,float xCell = 0,float yCell = 0) @@ -206,8 +209,8 @@ namespace MWMechanics ESM::Pathgrid::Point nextPoint = *mPath.begin(); float dX = nextPoint.mX - x; float dY = nextPoint.mY - y; - float h = sqrt(dX*dX+dY*dY); - return Ogre::Radian(acos(dY/h)*sgn(asin(dX/h))).valueDegrees(); + float h = sqrt(dX * dX + dY * dY); + return Ogre::Radian(acos(dY / h) * sgn(asin(dX / h))).valueDegrees(); } bool PathFinder::checkIfNextPointReached(float x,float y,float z) From 7b465ae4f1703f19182538658a58d74462d71b96 Mon Sep 17 00:00:00 2001 From: Torben Carrington Date: Wed, 29 May 2013 17:33:33 -0700 Subject: [PATCH 35/52] Pathfinding Overhaul - Even more cleanup and spacing corrections, small renaming (more to come), removed a few unnecessary actions that wasted CPU time and tmp RAM. --- apps/openmw/mwmechanics/pathfinding.cpp | 169 +++++++++--------------- apps/openmw/mwmechanics/pathfinding.hpp | 3 +- 2 files changed, 65 insertions(+), 107 deletions(-) diff --git a/apps/openmw/mwmechanics/pathfinding.cpp b/apps/openmw/mwmechanics/pathfinding.cpp index b13bfa7af..e319116f1 100644 --- a/apps/openmw/mwmechanics/pathfinding.cpp +++ b/apps/openmw/mwmechanics/pathfinding.cpp @@ -10,18 +10,36 @@ namespace { - // helpers functions - float distanceZCorrected(ESM::Pathgrid::Point point,float x,float y,float z) + struct found_path {}; + + typedef boost::adjacency_list< boost::vecS, boost::vecS, boost::undirectedS, + boost::property, boost::property > + PathGridGraph; + typedef boost::property_map::type WeightMap; + typedef PathGridGraph::vertex_descriptor PointID; + typedef PathGridGraph::edge_descriptor PointConnectionID; + + class goalVisited : public boost::default_dijkstra_visitor + { + public: + goalVisited(PointID goal) {mGoal = goal;}; + void examine_vertex(PointID u, const PathGridGraph g) {if(u == mGoal) throw found_path();}; + + private: + PointID mGoal; + }; + + float distanceZCorrected(ESM::Pathgrid::Point point, float x, float y, float z) { return sqrt((point.mX - x) * (point.mX - x) + (point.mY - y) * (point.mY - y) + 0.1 * (point.mZ - z) * (point.mZ - z)); } - float distance(ESM::Pathgrid::Point point,float x,float y,float z) + float distance(ESM::Pathgrid::Point point, float x, float y, float z) { return sqrt((point.mX - x) * (point.mX - x) + (point.mY - y) * (point.mY - y) + (point.mZ - z) * (point.mZ - z)); } - float distance(ESM::Pathgrid::Point a,ESM::Pathgrid::Point b) + float distance(ESM::Pathgrid::Point a, ESM::Pathgrid::Point b) { return sqrt(float(a.mX - b.mX) * (a.mX - b.mX) + (a.mY - b.mY) * (a.mY - b.mY) + (a.mZ - b.mZ) * (a.mZ - b.mZ)); } @@ -30,90 +48,30 @@ namespace { if(a > 0) return 1.0; - else - return -1.0; + return -1.0; } - int getClosestPoint(const ESM::Pathgrid* grid,float x,float y,float z) + int getClosestPoint(const ESM::Pathgrid* grid, float x, float y, float z) { - if(!grid) - return -1; - if(grid->mPoints.empty()) + if(!grid || grid->mPoints.empty()) return -1; - float m = distance(grid->mPoints[0],x,y,z); - int i0 = 0; + float distanceBetween = distance(grid->mPoints[0], x, y, z); + int closestIndex = 0; - for(unsigned int i = 1; i < grid->mPoints.size(); ++i) + for(unsigned int counter = 1; counter < grid->mPoints.size(); counter++) { - if(distance(grid->mPoints[i],x,y,z) < m) + if(distance(grid->mPoints[counter], x, y, z) < distanceBetween) { - m = distance(grid->mPoints[i],x,y,z); - i0 = i; + distanceBetween = distance(grid->mPoints[counter], x, y, z); + closestIndex = counter; } } - return i0; - } - - typedef boost::adjacency_list,boost::property > PathGridGraph; - typedef boost::property_map::type WeightMap; - typedef PathGridGraph::vertex_descriptor PointID; - typedef PathGridGraph::edge_descriptor PointConnectionID; - - struct found_path {}; - - /*class goalVisited : public boost::default_astar_visitor -{ -public: -goalVisited(PointID goal) : mGoal(goal) {} - -void examine_vertex(PointID u, const PathGridGraph g) -{ -if(u == mGoal) -throw found_path(); -} -private: -PointID mGoal; -}; - -class DistanceHeuristic : public boost::atasr_heuristic -{ -public: -DistanceHeuristic(const PathGridGraph & l, PointID goal) -: mGraph(l), mGoal(goal) {} - -float operator()(PointID u) -{ -const ESM::Pathgrid::Point & U = mGraph[u]; -const ESM::Pathgrid::Point & V = mGraph[mGoal]; -float dx = U.mX - V.mX; -float dy = U.mY - V.mY; -float dz = U.mZ - V.mZ; -return sqrt(dx * dx + dy * dy + dz * dz); -} -private: -const PathGridGraph & mGraph; -PointID mGoal; -};*/ - - class goalVisited : public boost::default_dijkstra_visitor - { - public: - goalVisited(PointID goal) : mGoal(goal) {} - - void examine_vertex(PointID u, const PathGridGraph g) - { - if(u == mGoal) - throw found_path(); - } - - private: - PointID mGoal; - }; + return closestIndex; + } - PathGridGraph buildGraph(const ESM::Pathgrid* pathgrid,float xCell = 0,float yCell = 0) + PathGridGraph buildGraph(const ESM::Pathgrid* pathgrid, float xCell = 0, float yCell = 0) { PathGridGraph graph; @@ -132,39 +90,38 @@ PointID mGoal; PointConnectionID edge; bool done; - boost::tie(edge,done) = boost::add_edge(u,v,graph); + boost::tie(edge, done) = boost::add_edge(u, v, graph); WeightMap weightmap = boost::get(boost::edge_weight, graph); - weightmap[edge] = distance(graph[u],graph[v]); + weightmap[edge] = distance(graph[u], graph[v]); } return graph; } - std::list findPath(PointID start,PointID end,PathGridGraph graph){ + std::list findPath(PointID start, PointID end, PathGridGraph graph) + { std::vector p(boost::num_vertices(graph)); std::vector d(boost::num_vertices(graph)); std::list shortest_path; - try { - boost::dijkstra_shortest_paths - ( - graph, - start, - boost::predecessor_map(&p[0]).distance_map(&d[0]).visitor(goalVisited(end))//.weight_map(boost::get(&Edge::distance, graph)) -); + try + { + boost::dijkstra_shortest_paths(graph, start, + boost::predecessor_map(&p[0]).distance_map(&d[0]).visitor(goalVisited(end))); + } - } catch(found_path fg) { - for(PointID v = end; ; v = p[v]) { + catch(found_path fg) + { + for(PointID v = end; ; v = p[v]) + { shortest_path.push_front(graph[v]); if(p[v] == v) break; } } + return shortest_path; } - - //end of helpers functions - } namespace MWMechanics @@ -181,53 +138,53 @@ namespace MWMechanics mIsPathConstructed = false; } - void PathFinder::buildPath(ESM::Pathgrid::Point startPoint,ESM::Pathgrid::Point endPoint, - const ESM::Pathgrid* pathGrid,float xCell,float yCell) + void PathFinder::buildPath(ESM::Pathgrid::Point startPoint, ESM::Pathgrid::Point endPoint, + const ESM::Pathgrid* pathGrid, float xCell, float yCell) { //first check if there is an obstacle - if(MWBase::Environment::get().getWorld()->castRay(startPoint.mX,startPoint.mY,startPoint.mZ, - endPoint.mX,endPoint.mY,endPoint.mZ) ) + if(MWBase::Environment::get().getWorld()->castRay(startPoint.mX, startPoint.mY, startPoint.mZ, + endPoint.mX, endPoint.mY, endPoint.mZ) ) { - int start = getClosestPoint(pathGrid,startPoint.mX - xCell,startPoint.mY - yCell,startPoint.mZ); - int end = getClosestPoint(pathGrid,endPoint.mX - xCell,endPoint.mY - yCell,endPoint.mZ); + int start = getClosestPoint(pathGrid, startPoint.mX - xCell, startPoint.mY - yCell,startPoint.mZ); + int end = getClosestPoint(pathGrid, endPoint.mX - xCell, endPoint.mY - yCell, endPoint.mZ); if(start != -1 && end != -1) { - PathGridGraph graph = buildGraph(pathGrid,xCell,yCell); - mPath = findPath(start,end,graph); + PathGridGraph graph = buildGraph(pathGrid, xCell, yCell); + mPath = findPath(start, end, graph); } } + mPath.push_back(endPoint); mIsPathConstructed = true; } - float PathFinder::getZAngleToNext(float x,float y,float z) + float PathFinder::getZAngleToNext(float x, float y, float z) { if(mPath.empty()) - return 0; /// shouldn't happen! + return 0; // shouldn't happen! ESM::Pathgrid::Point nextPoint = *mPath.begin(); float dX = nextPoint.mX - x; float dY = nextPoint.mY - y; float h = sqrt(dX * dX + dY * dY); + return Ogre::Radian(acos(dY / h) * sgn(asin(dX / h))).valueDegrees(); } - bool PathFinder::checkIfNextPointReached(float x,float y,float z) + bool PathFinder::checkIfNextPointReached(float x, float y, float z) { if(mPath.empty()) return true; ESM::Pathgrid::Point nextPoint = *mPath.begin(); - if(distanceZCorrected(nextPoint,x,y,z) < 20) + if(distanceZCorrected(nextPoint, x, y, z) < 20) { mPath.pop_front(); - if(mPath.empty()) return true; - - nextPoint = *mPath.begin(); } + return false; } diff --git a/apps/openmw/mwmechanics/pathfinding.hpp b/apps/openmw/mwmechanics/pathfinding.hpp index dc380afb4..90c72ebcf 100644 --- a/apps/openmw/mwmechanics/pathfinding.hpp +++ b/apps/openmw/mwmechanics/pathfinding.hpp @@ -15,7 +15,8 @@ namespace MWMechanics void buildPath(ESM::Pathgrid::Point startPoint,ESM::Pathgrid::Point endPoint, const ESM::Pathgrid* pathGrid,float xCell = 0,float yCell = 0); - bool checkIfNextPointReached(float x,float y,float z);//returns true if the last point of the path has been reached. + bool checkIfNextPointReached(float x,float y,float z); + ///< \Returns true if the last point of the path has been reached. float getZAngleToNext(float x,float y,float z); std::list getPath(); From c0807852356af8ec06b558ebb799480da8f3d7ea Mon Sep 17 00:00:00 2001 From: Torben Carrington Date: Wed, 29 May 2013 19:26:45 -0700 Subject: [PATCH 36/52] Pathfinding Overhaul - Finished cleaning, removed unnecessary parameter in one function, fixed use of the function in ai packages and added use of clearPath() function in aiwander, fixed algorithms and got rid of excess subtractions in getDistance functions (thanks to Chris!). --- apps/openmw/mwmechanics/aiescort.cpp | 2 +- apps/openmw/mwmechanics/aitravel.cpp | 2 +- apps/openmw/mwmechanics/aiwander.cpp | 17 +++++----- apps/openmw/mwmechanics/aiwander.hpp | 2 +- apps/openmw/mwmechanics/pathfinding.cpp | 42 +++++++++++++++---------- apps/openmw/mwmechanics/pathfinding.hpp | 8 ++--- 6 files changed, 41 insertions(+), 32 deletions(-) diff --git a/apps/openmw/mwmechanics/aiescort.cpp b/apps/openmw/mwmechanics/aiescort.cpp index 5b94c4938..b873844a2 100644 --- a/apps/openmw/mwmechanics/aiescort.cpp +++ b/apps/openmw/mwmechanics/aiescort.cpp @@ -151,7 +151,7 @@ bool MWMechanics::AiEscort::execute (const MWWorld::Ptr& actor) if(distanceBetweenResult <= mMaxDist * mMaxDist) { - float zAngle = mPathFinder.getZAngleToNext(pos.pos[0],pos.pos[1],pos.pos[2]); + float zAngle = mPathFinder.getZAngleToNext(pos.pos[0],pos.pos[1]); MWBase::Environment::get().getWorld()->rotateObject(actor,0,0,zAngle,false); MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 1; mMaxDist = 470; diff --git a/apps/openmw/mwmechanics/aitravel.cpp b/apps/openmw/mwmechanics/aitravel.cpp index fbae5c1d2..99df68a91 100644 --- a/apps/openmw/mwmechanics/aitravel.cpp +++ b/apps/openmw/mwmechanics/aitravel.cpp @@ -87,7 +87,7 @@ bool MWMechanics::AiTravel::execute (const MWWorld::Ptr& actor) return true; } - float zAngle = mPathFinder.getZAngleToNext(pos.pos[0],pos.pos[1],pos.pos[2]); + float zAngle = mPathFinder.getZAngleToNext(pos.pos[0],pos.pos[1]); MWBase::Environment::get().getWorld()->rotateObject(actor,0,0,zAngle,false); MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 1; diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 46c5598cc..310cc3274 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -64,7 +64,7 @@ bool MWMechanics::AiWander::execute (const MWWorld::Ptr& actor) { if(!mRepeat) { - stopWalking(actor, mPathFinder); + stopWalking(actor); return true; } else @@ -74,7 +74,7 @@ bool MWMechanics::AiWander::execute (const MWWorld::Ptr& actor) { if(!mRepeat) { - stopWalking(actor, mPathFinder); + stopWalking(actor); return true; } else @@ -149,7 +149,7 @@ bool MWMechanics::AiWander::execute (const MWWorld::Ptr& actor) // FIXME: This *should* pause the AiWander package instead of terminating it. if(sideX*(pos.pos[0] - actor.getCell()->mCell->mData.mX * ESM::Land::REAL_SIZE) > sideX * (ESM::Land::REAL_SIZE / 2.0 - 200)) { - MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0; + stopWalking(actor); return true; } } @@ -161,7 +161,7 @@ bool MWMechanics::AiWander::execute (const MWWorld::Ptr& actor) // FIXME: This *should* pause the AiWander package instead of terminating it. if(sideY*(pos.pos[1] - actor.getCell()->mCell->mData.mY * ESM::Land::REAL_SIZE) > sideY * (ESM::Land::REAL_SIZE / 2.0 - 200)) { - MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0; + stopWalking(actor); return true; } } @@ -242,7 +242,7 @@ bool MWMechanics::AiWander::execute (const MWWorld::Ptr& actor) if(mWalking) { - float zAngle = mPathFinder.getZAngleToNext(pos.pos[0],pos.pos[1],pos.pos[2]); + float zAngle = mPathFinder.getZAngleToNext(pos.pos[0],pos.pos[1]); MWBase::Environment::get().getWorld()->rotateObject(actor,0,0,zAngle,false); MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 1; @@ -256,7 +256,7 @@ bool MWMechanics::AiWander::execute (const MWWorld::Ptr& actor) if(distance < 1200 || mPathFinder.checkIfNextPointReached(pos.pos[0],pos.pos[1],pos.pos[2])) { - stopWalking(actor, mPathFinder); + stopWalking(actor); mMoveNow = false; mWalking = false; mChooseAction = true; @@ -272,10 +272,9 @@ int MWMechanics::AiWander::getTypeId() const return 0; } -void MWMechanics::AiWander::stopWalking(const MWWorld::Ptr& actor, PathFinder& path) +void MWMechanics::AiWander::stopWalking(const MWWorld::Ptr& actor) { - PathFinder pathClearer; - path = pathClearer; + mPathFinder.clearPath(); MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0; } diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index cf3820527..c82ccc215 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -22,7 +22,7 @@ namespace MWMechanics ///< 0: Wander private: - void stopWalking(const MWWorld::Ptr& actor, PathFinder& path); + void stopWalking(const MWWorld::Ptr& actor); void playIdle(const MWWorld::Ptr& actor, unsigned short idleSelect); bool checkIdle(const MWWorld::Ptr& actor, unsigned short idleSelect); diff --git a/apps/openmw/mwmechanics/pathfinding.cpp b/apps/openmw/mwmechanics/pathfinding.cpp index e319116f1..3c15b050e 100644 --- a/apps/openmw/mwmechanics/pathfinding.cpp +++ b/apps/openmw/mwmechanics/pathfinding.cpp @@ -31,17 +31,26 @@ namespace float distanceZCorrected(ESM::Pathgrid::Point point, float x, float y, float z) { - return sqrt((point.mX - x) * (point.mX - x) + (point.mY - y) * (point.mY - y) + 0.1 * (point.mZ - z) * (point.mZ - z)); + x -= point.mX; + y -= point.mY; + z -= point.mZ; + return sqrt(x * x + y * y + 0.1 * z * z); } float distance(ESM::Pathgrid::Point point, float x, float y, float z) { - return sqrt((point.mX - x) * (point.mX - x) + (point.mY - y) * (point.mY - y) + (point.mZ - z) * (point.mZ - z)); + x -= point.mX; + y -= point.mY; + z -= point.mZ; + return sqrt(x * x + y * y + z * z); } float distance(ESM::Pathgrid::Point a, ESM::Pathgrid::Point b) { - return sqrt(float(a.mX - b.mX) * (a.mX - b.mX) + (a.mY - b.mY) * (a.mY - b.mY) + (a.mZ - b.mZ) * (a.mZ - b.mZ)); + float x = a.mX - b.mX; + float y = a.mY - b.mY; + float z = a.mZ - b.mZ; + return sqrt(x * x + y * y + z * z); } static float sgn(float a) @@ -75,18 +84,18 @@ namespace { PathGridGraph graph; - for(unsigned int i = 0; i < pathgrid->mPoints.size(); ++i) + for(unsigned int counter = 0; counter < pathgrid->mPoints.size(); counter++) { PointID pID = boost::add_vertex(graph); - graph[pID].mX = pathgrid->mPoints[i].mX + xCell; - graph[pID].mY = pathgrid->mPoints[i].mY + yCell; - graph[pID].mZ = pathgrid->mPoints[i].mZ; + graph[pID].mX = pathgrid->mPoints[counter].mX + xCell; + graph[pID].mY = pathgrid->mPoints[counter].mY + yCell; + graph[pID].mZ = pathgrid->mPoints[counter].mZ; } - for(unsigned int i = 0;imEdges.size();++i) + for(unsigned int counterTwo = 0; counterTwo < pathgrid->mEdges.size(); counterTwo++) { - PointID u = pathgrid->mEdges[i].mV0; - PointID v = pathgrid->mEdges[i].mV1; + PointID u = pathgrid->mEdges[counterTwo].mV0; + PointID v = pathgrid->mEdges[counterTwo].mV1; PointConnectionID edge; bool done; @@ -145,13 +154,13 @@ namespace MWMechanics if(MWBase::Environment::get().getWorld()->castRay(startPoint.mX, startPoint.mY, startPoint.mZ, endPoint.mX, endPoint.mY, endPoint.mZ) ) { - int start = getClosestPoint(pathGrid, startPoint.mX - xCell, startPoint.mY - yCell,startPoint.mZ); - int end = getClosestPoint(pathGrid, endPoint.mX - xCell, endPoint.mY - yCell, endPoint.mZ); + int startNode = getClosestPoint(pathGrid, startPoint.mX - xCell, startPoint.mY - yCell,startPoint.mZ); + int endNode = getClosestPoint(pathGrid, endPoint.mX - xCell, endPoint.mY - yCell, endPoint.mZ); - if(start != -1 && end != -1) + if(startNode != -1 && endNode != -1) { PathGridGraph graph = buildGraph(pathGrid, xCell, yCell); - mPath = findPath(start, end, graph); + mPath = findPath(startNode, endNode, graph); } } @@ -159,10 +168,11 @@ namespace MWMechanics mIsPathConstructed = true; } - float PathFinder::getZAngleToNext(float x, float y, float z) + float PathFinder::getZAngleToNext(float x, float y) { + // This if should never be true: if(mPath.empty()) - return 0; // shouldn't happen! + return 0; ESM::Pathgrid::Point nextPoint = *mPath.begin(); float dX = nextPoint.mX - x; diff --git a/apps/openmw/mwmechanics/pathfinding.hpp b/apps/openmw/mwmechanics/pathfinding.hpp index 90c72ebcf..fcd609c8e 100644 --- a/apps/openmw/mwmechanics/pathfinding.hpp +++ b/apps/openmw/mwmechanics/pathfinding.hpp @@ -12,12 +12,12 @@ namespace MWMechanics PathFinder(); void clearPath(); - void buildPath(ESM::Pathgrid::Point startPoint,ESM::Pathgrid::Point endPoint, - const ESM::Pathgrid* pathGrid,float xCell = 0,float yCell = 0); + void buildPath(ESM::Pathgrid::Point startPoint, ESM::Pathgrid::Point endPoint, + const ESM::Pathgrid* pathGrid, float xCell = 0, float yCell = 0); - bool checkIfNextPointReached(float x,float y,float z); + bool checkIfNextPointReached(float x, float y, float z); ///< \Returns true if the last point of the path has been reached. - float getZAngleToNext(float x,float y,float z); + float getZAngleToNext(float x, float y); std::list getPath(); bool isPathConstructed(); From 73a967174267891896e03d9ddc3c369bc3e81961 Mon Sep 17 00:00:00 2001 From: Torben Carrington Date: Wed, 29 May 2013 20:05:17 -0700 Subject: [PATCH 37/52] Pathfinding Overhaul - Changed the name of checkIfNextPointReached to a more intuitive name considering what it does (checkPathCompleted) and fixed a minor bug in it, modified buildPath() to take one final parameter, a bool which dictates whether or not to always use pathfinding (like AIWander should be doing) or to allow for "shortcuts", modified all ai packages to work with these two changes. --- apps/openmw/mwmechanics/aiescort.cpp | 4 ++-- apps/openmw/mwmechanics/aitravel.cpp | 4 ++-- apps/openmw/mwmechanics/aiwander.cpp | 4 ++-- apps/openmw/mwmechanics/pathfinding.cpp | 24 ++++++++++++++++-------- apps/openmw/mwmechanics/pathfinding.hpp | 4 ++-- 5 files changed, 24 insertions(+), 16 deletions(-) diff --git a/apps/openmw/mwmechanics/aiescort.cpp b/apps/openmw/mwmechanics/aiescort.cpp index b873844a2..755994622 100644 --- a/apps/openmw/mwmechanics/aiescort.cpp +++ b/apps/openmw/mwmechanics/aiescort.cpp @@ -129,10 +129,10 @@ bool MWMechanics::AiEscort::execute (const MWWorld::Ptr& actor) start.mY = pos.pos[1]; start.mZ = pos.pos[2]; - mPathFinder.buildPath(start,dest,pathgrid,xCell,yCell); + mPathFinder.buildPath(start, dest, pathgrid, xCell, yCell, 1); } - if(mPathFinder.checkIfNextPointReached(pos.pos[0],pos.pos[1],pos.pos[2])) + if(mPathFinder.checkPathCompleted(pos.pos[0],pos.pos[1],pos.pos[2])) { MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0; return true; diff --git a/apps/openmw/mwmechanics/aitravel.cpp b/apps/openmw/mwmechanics/aitravel.cpp index 99df68a91..4307ed284 100644 --- a/apps/openmw/mwmechanics/aitravel.cpp +++ b/apps/openmw/mwmechanics/aitravel.cpp @@ -78,10 +78,10 @@ bool MWMechanics::AiTravel::execute (const MWWorld::Ptr& actor) start.mY = pos.pos[1]; start.mZ = pos.pos[2]; - mPathFinder.buildPath(start,dest,pathgrid,xCell,yCell); + mPathFinder.buildPath(start, dest, pathgrid, xCell, yCell, 1); } - if(mPathFinder.checkIfNextPointReached(pos.pos[0],pos.pos[1],pos.pos[2])) + if(mPathFinder.checkPathCompleted(pos.pos[0],pos.pos[1],pos.pos[2])) { MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0; return true; diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 310cc3274..b7d391a9f 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -235,7 +235,7 @@ bool MWMechanics::AiWander::execute (const MWWorld::Ptr& actor) start.mY = pos.pos[1]; start.mZ = pos.pos[2]; - mPathFinder.buildPath(start,dest,mPathgrid,mXCell,mYCell); + mPathFinder.buildPath(start, dest, mPathgrid, mXCell, mYCell, 0); mWalking = true; } } @@ -254,7 +254,7 @@ bool MWMechanics::AiWander::execute (const MWWorld::Ptr& actor) actorPos[1] = actorPos[1] - mYCell; float distance = actorPos.squaredDistance(destNodePos); - if(distance < 1200 || mPathFinder.checkIfNextPointReached(pos.pos[0],pos.pos[1],pos.pos[2])) + if(distance < 1200 || mPathFinder.checkPathCompleted(pos.pos[0],pos.pos[1],pos.pos[2])) { stopWalking(actor); mMoveNow = false; diff --git a/apps/openmw/mwmechanics/pathfinding.cpp b/apps/openmw/mwmechanics/pathfinding.cpp index 3c15b050e..78be90804 100644 --- a/apps/openmw/mwmechanics/pathfinding.cpp +++ b/apps/openmw/mwmechanics/pathfinding.cpp @@ -148,11 +148,16 @@ namespace MWMechanics } void PathFinder::buildPath(ESM::Pathgrid::Point startPoint, ESM::Pathgrid::Point endPoint, - const ESM::Pathgrid* pathGrid, float xCell, float yCell) + const ESM::Pathgrid* pathGrid, float xCell, float yCell, bool allowShortcuts) { + if(allowShortcuts) + { + if(MWBase::Environment::get().getWorld()->castRay(startPoint.mX, startPoint.mY, startPoint.mZ, endPoint.mX, endPoint.mY, + endPoint.mZ)) + allowShortcuts = false; + } //first check if there is an obstacle - if(MWBase::Environment::get().getWorld()->castRay(startPoint.mX, startPoint.mY, startPoint.mZ, - endPoint.mX, endPoint.mY, endPoint.mZ) ) + if(!allowShortcuts) { int startNode = getClosestPoint(pathGrid, startPoint.mX - xCell, startPoint.mY - yCell,startPoint.mZ); int endNode = getClosestPoint(pathGrid, endPoint.mX - xCell, endPoint.mY - yCell, endPoint.mZ); @@ -175,14 +180,14 @@ namespace MWMechanics return 0; ESM::Pathgrid::Point nextPoint = *mPath.begin(); - float dX = nextPoint.mX - x; - float dY = nextPoint.mY - y; - float h = sqrt(dX * dX + dY * dY); + float directionX = nextPoint.mX - x; + float directionY = nextPoint.mY - y; + float directionResult = sqrt(directionX * directionX + directionY * directionY); - return Ogre::Radian(acos(dY / h) * sgn(asin(dX / h))).valueDegrees(); + return Ogre::Radian(acos(directionY / directionResult) * sgn(asin(directionX / directionResult))).valueDegrees(); } - bool PathFinder::checkIfNextPointReached(float x, float y, float z) + bool PathFinder::checkPathCompleted(float x, float y, float z) { if(mPath.empty()) return true; @@ -192,7 +197,10 @@ namespace MWMechanics { mPath.pop_front(); if(mPath.empty()) + { + mIsPathConstructed = false; return true; + } } return false; diff --git a/apps/openmw/mwmechanics/pathfinding.hpp b/apps/openmw/mwmechanics/pathfinding.hpp index fcd609c8e..1727c650f 100644 --- a/apps/openmw/mwmechanics/pathfinding.hpp +++ b/apps/openmw/mwmechanics/pathfinding.hpp @@ -13,9 +13,9 @@ namespace MWMechanics void clearPath(); void buildPath(ESM::Pathgrid::Point startPoint, ESM::Pathgrid::Point endPoint, - const ESM::Pathgrid* pathGrid, float xCell = 0, float yCell = 0); + const ESM::Pathgrid* pathGrid, float xCell = 0, float yCell = 0, bool allowShortcuts = 1); - bool checkIfNextPointReached(float x, float y, float z); + bool checkPathCompleted(float x, float y, float z); ///< \Returns true if the last point of the path has been reached. float getZAngleToNext(float x, float y); From 8bd712cc95fdfe1f0ccb1a8db301f4c265f3c376 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 31 May 2013 04:08:44 +0200 Subject: [PATCH 38/52] Fix being able to move slowly when over encumbered --- apps/openmw/mwmechanics/character.cpp | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index c7aeb1b5f..aa20e1414 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -461,15 +461,18 @@ void CharacterController::update(float duration, Movement &movement) Ogre::Vector3 moved = mAnimation->runAnimation(duration); // Ensure we're moving in generally the right direction - if((movement.mPosition[0] < 0.0f && movement.mPosition[0] < moved.x*2.0f) || - (movement.mPosition[0] > 0.0f && movement.mPosition[0] > moved.x*2.0f)) - moved.x = movement.mPosition[0]; - if((movement.mPosition[1] < 0.0f && movement.mPosition[1] < moved.y*2.0f) || - (movement.mPosition[1] > 0.0f && movement.mPosition[1] > moved.y*2.0f)) - moved.y = movement.mPosition[1]; - if((movement.mPosition[2] < 0.0f && movement.mPosition[2] < moved.z*2.0f) || - (movement.mPosition[2] > 0.0f && movement.mPosition[2] > moved.z*2.0f)) - moved.z = movement.mPosition[2]; + if (speed > 0.f) + { + if((movement.mPosition[0] < 0.0f && movement.mPosition[0] < moved.x*2.0f) || + (movement.mPosition[0] > 0.0f && movement.mPosition[0] > moved.x*2.0f)) + moved.x = movement.mPosition[0]; + if((movement.mPosition[1] < 0.0f && movement.mPosition[1] < moved.y*2.0f) || + (movement.mPosition[1] > 0.0f && movement.mPosition[1] > moved.y*2.0f)) + moved.y = movement.mPosition[1]; + if((movement.mPosition[2] < 0.0f && movement.mPosition[2] < moved.z*2.0f) || + (movement.mPosition[2] > 0.0f && movement.mPosition[2] > moved.z*2.0f)) + moved.z = movement.mPosition[2]; + } movement.mPosition[0] = moved.x; movement.mPosition[1] = moved.y; From a4caec56cf0503196a5d30214ab846df160f79c9 Mon Sep 17 00:00:00 2001 From: Torben Carrington Date: Fri, 31 May 2013 17:01:42 -0700 Subject: [PATCH 39/52] Pathfinding Overhaul - Fixed selecting cells that are inaccessable from AIWander and pathfinding in general (sadly requires minor effort on the AI Packages implementation but it is the quickest way I can see), minor cleanup again (there is a lot to cleanup, this will prolly be in every commit). --- apps/openmw/mwmechanics/aiwander.cpp | 25 ++++++++++++++++--------- apps/openmw/mwmechanics/pathfinding.cpp | 20 ++++++++++++++++---- 2 files changed, 32 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index b7d391a9f..1530804cd 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -219,12 +219,6 @@ bool MWMechanics::AiWander::execute (const MWWorld::Ptr& actor) unsigned int randNode = (int)(rand() / ((double)RAND_MAX + 1) * mAllowedNodes.size()); Ogre::Vector3 destNodePos(mAllowedNodes[randNode].mX, mAllowedNodes[randNode].mY, mAllowedNodes[randNode].mZ); - // Remove this node as an option and add back the previously used node (stops NPC from picking the same node): - ESM::Pathgrid::Point temp = mAllowedNodes[randNode]; - mAllowedNodes.erase(mAllowedNodes.begin() + randNode); - mAllowedNodes.push_back(mCurrentNode); - mCurrentNode = temp; - ESM::Pathgrid::Point dest; dest.mX = destNodePos[0] + mXCell; dest.mY = destNodePos[1] + mYCell; @@ -236,7 +230,21 @@ bool MWMechanics::AiWander::execute (const MWWorld::Ptr& actor) start.mZ = pos.pos[2]; mPathFinder.buildPath(start, dest, mPathgrid, mXCell, mYCell, 0); - mWalking = true; + + if(mPathFinder.isPathConstructed()) + { + // Remove this node as an option and add back the previously used node (stops NPC from picking the same node): + ESM::Pathgrid::Point temp = mAllowedNodes[randNode]; + mAllowedNodes.erase(mAllowedNodes.begin() + randNode); + mAllowedNodes.push_back(mCurrentNode); + mCurrentNode = temp; + + mMoveNow = false; + mWalking = true; + } + // Choose a different node and delete this one from possible nodes because it is uncreachable: + else + mAllowedNodes.erase(mAllowedNodes.begin() + randNode); } } @@ -254,14 +262,13 @@ bool MWMechanics::AiWander::execute (const MWWorld::Ptr& actor) actorPos[1] = actorPos[1] - mYCell; float distance = actorPos.squaredDistance(destNodePos); - if(distance < 1200 || mPathFinder.checkPathCompleted(pos.pos[0],pos.pos[1],pos.pos[2])) + if(distance < 1200 || mPathFinder.checkPathCompleted(pos.pos[0], pos.pos[1], pos.pos[2])) { stopWalking(actor); mMoveNow = false; mWalking = false; mChooseAction = true; } - } return false; diff --git a/apps/openmw/mwmechanics/pathfinding.cpp b/apps/openmw/mwmechanics/pathfinding.cpp index 78be90804..d3a44e0f9 100644 --- a/apps/openmw/mwmechanics/pathfinding.cpp +++ b/apps/openmw/mwmechanics/pathfinding.cpp @@ -156,7 +156,7 @@ namespace MWMechanics endPoint.mZ)) allowShortcuts = false; } - //first check if there is an obstacle + if(!allowShortcuts) { int startNode = getClosestPoint(pathGrid, startPoint.mX - xCell, startPoint.mY - yCell,startPoint.mZ); @@ -166,16 +166,28 @@ namespace MWMechanics { PathGridGraph graph = buildGraph(pathGrid, xCell, yCell); mPath = findPath(startNode, endNode, graph); + + if(!mPath.empty()) + { + mPath.push_back(endPoint); + mIsPathConstructed = true; + } } } + else + { + mPath.push_back(endPoint); + mIsPathConstructed = true; + } - mPath.push_back(endPoint); - mIsPathConstructed = true; + if(mPath.empty()) + mIsPathConstructed = false; } float PathFinder::getZAngleToNext(float x, float y) { - // This if should never be true: + // This should never happen (programmers should have an if statement checking mIsPathConstructed that prevents this call + // if otherwise). if(mPath.empty()) return 0; From 09beafd044f822bf8af9570225d3ac1419762a2a Mon Sep 17 00:00:00 2001 From: Torben Carrington Date: Fri, 31 May 2013 17:49:52 -0700 Subject: [PATCH 40/52] Pathfinding Overhaul - Master cleanup! Cleaned pathfinding entirely, all AI packages that are implemented as well, Increased buffer! This makes the intro guard no longer walk into you or go to far into the room (not tested against vanilla distances but it seems accurate enough until the next itteration of pathfinding fixes). --- apps/openmw/mwmechanics/aiescort.cpp | 238 +++++------ apps/openmw/mwmechanics/aitravel.cpp | 135 ++++--- apps/openmw/mwmechanics/aiwander.cpp | 508 ++++++++++++------------ apps/openmw/mwmechanics/pathfinding.cpp | 2 +- 4 files changed, 452 insertions(+), 431 deletions(-) diff --git a/apps/openmw/mwmechanics/aiescort.cpp b/apps/openmw/mwmechanics/aiescort.cpp index 755994622..6af87e8bd 100644 --- a/apps/openmw/mwmechanics/aiescort.cpp +++ b/apps/openmw/mwmechanics/aiescort.cpp @@ -13,8 +13,9 @@ namespace { float sgn(float a) { - if(a > 0) return 1.0; - else return -1.0; + if(a > 0) + return 1.0; + return -1.0; } } @@ -24,151 +25,156 @@ namespace TODO: Take account for actors being in different cells. */ -MWMechanics::AiEscort::AiEscort(const std::string &actorId,int duration, float x, float y, float z) -: mActorId(actorId), mX(x), mY(y), mZ(z), mDuration(duration) +namespace MWMechanics { - mMaxDist = 470; + AiEscort::AiEscort(const std::string &actorId, int duration, float x, float y, float z) + : mActorId(actorId), mX(x), mY(y), mZ(z), mDuration(duration) + { + mMaxDist = 470; - // The CS Help File states that if a duration is givin, the AI package will run for that long - // BUT if a location is givin, it "trumps" the duration so it will simply escort to that location. - if(mX != 0 || mY != 0 || mZ != 0) - mDuration = 0; + // The CS Help File states that if a duration is givin, the AI package will run for that long + // BUT if a location is givin, it "trumps" the duration so it will simply escort to that location. + if(mX != 0 || mY != 0 || mZ != 0) + mDuration = 0; - else - { - MWWorld::TimeStamp startTime = MWBase::Environment::get().getWorld()->getTimeStamp(); - mStartingSecond = ((startTime.getHour() - int(startTime.getHour())) * 100); + else + { + MWWorld::TimeStamp startTime = MWBase::Environment::get().getWorld()->getTimeStamp(); + mStartingSecond = ((startTime.getHour() - int(startTime.getHour())) * 100); + } } -} -MWMechanics::AiEscort::AiEscort(const std::string &actorId,const std::string &cellId,int duration, float x, float y, float z) -: mActorId(actorId), mCellId(cellId), mX(x), mY(y), mZ(z), mDuration(duration) -{ - mMaxDist = 470; + AiEscort::AiEscort(const std::string &actorId, const std::string &cellId,int duration, float x, float y, float z) + : mActorId(actorId), mCellId(cellId), mX(x), mY(y), mZ(z), mDuration(duration) + { + mMaxDist = 470; - // The CS Help File states that if a duration is givin, the AI package will run for that long - // BUT if a location is givin, it "trumps" the duration so it will simply escort to that location. - if(mX != 0 || mY != 0 || mZ != 0) - mDuration = 0; + // The CS Help File states that if a duration is givin, the AI package will run for that long + // BUT if a location is givin, it "trumps" the duration so it will simply escort to that location. + if(mX != 0 || mY != 0 || mZ != 0) + mDuration = 0; - else - { - MWWorld::TimeStamp startTime = MWBase::Environment::get().getWorld()->getTimeStamp(); - mStartingSecond = ((startTime.getHour() - int(startTime.getHour())) * 100); + else + { + MWWorld::TimeStamp startTime = MWBase::Environment::get().getWorld()->getTimeStamp(); + mStartingSecond = ((startTime.getHour() - int(startTime.getHour())) * 100); + } } -} -MWMechanics::AiEscort *MWMechanics::AiEscort::clone() const -{ - return new AiEscort(*this); -} - -bool MWMechanics::AiEscort::execute (const MWWorld::Ptr& actor) -{ - // If AiEscort has ran for as long or longer then the duration specified - // and the duration is not infinite, the package is complete. - if(mDuration != 0) + AiEscort *MWMechanics::AiEscort::clone() const { - MWWorld::TimeStamp current = MWBase::Environment::get().getWorld()->getTimeStamp(); - unsigned int currentSecond = ((current.getHour() - int(current.getHour())) * 100); - if(currentSecond - mStartingSecond >= mDuration) - return true; + return new AiEscort(*this); } - ESM::Position pos = actor.getRefData().getPosition(); - bool cellChange = actor.getCell()->mCell->mData.mX != cellX || actor.getCell()->mCell->mData.mY != cellY; - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); - const ESM::Pathgrid *pathgrid = - MWBase::Environment::get().getWorld()->getStore().get().search(*actor.getCell()->mCell); + bool AiEscort::execute (const MWWorld::Ptr& actor) + { + // If AiEscort has ran for as long or longer then the duration specified + // and the duration is not infinite, the package is complete. + if(mDuration != 0) + { + MWWorld::TimeStamp current = MWBase::Environment::get().getWorld()->getTimeStamp(); + unsigned int currentSecond = ((current.getHour() - int(current.getHour())) * 100); + if(currentSecond - mStartingSecond >= mDuration) + return true; + } + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + ESM::Position pos = actor.getRefData().getPosition(); + bool cellChange = actor.getCell()->mCell->mData.mX != cellX || actor.getCell()->mCell->mData.mY != cellY; + const ESM::Pathgrid *pathgrid = + MWBase::Environment::get().getWorld()->getStore().get().search(*actor.getCell()->mCell); - if(actor.getCell()->mCell->mData.mX != player.getCell()->mCell->mData.mX) - { - int sideX = sgn(actor.getCell()->mCell->mData.mX - player.getCell()->mCell->mData.mX); - // Check if actor is near the border of an inactive cell. If so, disable AiEscort. - // FIXME: This *should* pause the AiEscort package instead of terminating it. - if(sideX*(pos.pos[0] - actor.getCell()->mCell->mData.mX * ESM::Land::REAL_SIZE) > sideX * (ESM::Land::REAL_SIZE / 2. - 200)) + if(actor.getCell()->mCell->mData.mX != player.getCell()->mCell->mData.mX) { - MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0; - return true; + int sideX = sgn(actor.getCell()->mCell->mData.mX - player.getCell()->mCell->mData.mX); + // Check if actor is near the border of an inactive cell. If so, disable AiEscort. + // FIXME: This *should* pause the AiEscort package instead of terminating it. + if(sideX * (pos.pos[0] - actor.getCell()->mCell->mData.mX * ESM::Land::REAL_SIZE) > sideX * (ESM::Land::REAL_SIZE / + 2.0 - 200)) + { + MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0; + return true; + } } - } - if(actor.getCell()->mCell->mData.mY != player.getCell()->mCell->mData.mY) - { - int sideY = sgn(actor.getCell()->mCell->mData.mY - player.getCell()->mCell->mData.mY); - // Check if actor is near the border of an inactive cell. If so, disable AiEscort. - // FIXME: This *should* pause the AiEscort package instead of terminating it. - if(sideY*(pos.pos[1] - actor.getCell()->mCell->mData.mY * ESM::Land::REAL_SIZE) > sideY * (ESM::Land::REAL_SIZE / 2. - 200)) + if(actor.getCell()->mCell->mData.mY != player.getCell()->mCell->mData.mY) { - MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0; - return true; + int sideY = sgn(actor.getCell()->mCell->mData.mY - player.getCell()->mCell->mData.mY); + // Check if actor is near the border of an inactive cell. If so, disable AiEscort. + // FIXME: This *should* pause the AiEscort package instead of terminating it. + if(sideY*(pos.pos[1] - actor.getCell()->mCell->mData.mY * ESM::Land::REAL_SIZE) > sideY * (ESM::Land::REAL_SIZE / + 2.0 - 200)) + { + MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0; + return true; + } } - } - if(!mPathFinder.isPathConstructed() || cellChange) - { - cellX = actor.getCell()->mCell->mData.mX; - cellY = actor.getCell()->mCell->mData.mY; - float xCell = 0; - float yCell = 0; - if (actor.getCell()->mCell->isExterior()) + if(!mPathFinder.isPathConstructed() || cellChange) { - xCell = actor.getCell()->mCell->mData.mX * ESM::Land::REAL_SIZE; - yCell = actor.getCell()->mCell->mData.mY * ESM::Land::REAL_SIZE; + cellX = actor.getCell()->mCell->mData.mX; + cellY = actor.getCell()->mCell->mData.mY; + float xCell = 0; + float yCell = 0; + if (actor.getCell()->mCell->isExterior()) + { + xCell = actor.getCell()->mCell->mData.mX * ESM::Land::REAL_SIZE; + yCell = actor.getCell()->mCell->mData.mY * ESM::Land::REAL_SIZE; + } + + ESM::Pathgrid::Point dest; + dest.mX = mX; + dest.mY = mY; + dest.mZ = mZ; + + ESM::Pathgrid::Point start; + start.mX = pos.pos[0]; + start.mY = pos.pos[1]; + start.mZ = pos.pos[2]; + + mPathFinder.buildPath(start, dest, pathgrid, xCell, yCell, true); } - ESM::Pathgrid::Point dest; - dest.mX = mX; - dest.mY = mY; - dest.mZ = mZ; - - ESM::Pathgrid::Point start; - start.mX = pos.pos[0]; - start.mY = pos.pos[1]; - start.mZ = pos.pos[2]; - - mPathFinder.buildPath(start, dest, pathgrid, xCell, yCell, 1); - } + if(mPathFinder.checkPathCompleted(pos.pos[0],pos.pos[1],pos.pos[2])) + { + MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0; + return true; + } - if(mPathFinder.checkPathCompleted(pos.pos[0],pos.pos[1],pos.pos[2])) - { - MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0; - return true; - } + const MWWorld::Ptr follower = MWBase::Environment::get().getWorld()->getPtr(mActorId, false); + const float* const leaderPos = actor.getRefData().getPosition().pos; + const float* const followerPos = follower.getRefData().getPosition().pos; + double differenceBetween[3]; - const MWWorld::Ptr follower = MWBase::Environment::get().getWorld()->getPtr(mActorId, false); - const float* const leaderPos = actor.getRefData().getPosition().pos; - const float* const followerPos = follower.getRefData().getPosition().pos; - double differenceBetween[3]; + for (short counter = 0; counter < 3; counter++) + differenceBetween[counter] = (leaderPos[counter] - followerPos[counter]); - for (short i = 0; i < 3; ++i) - differenceBetween[i] = (leaderPos[i] - followerPos[i]); + float distanceBetweenResult = + (differenceBetween[0] * differenceBetween[0]) + (differenceBetween[1] * differenceBetween[1]) + (differenceBetween[2] * + differenceBetween[2]); - float distanceBetweenResult = - (differenceBetween[0] * differenceBetween[0]) + (differenceBetween[1] * differenceBetween[1]) + (differenceBetween[2] * differenceBetween[2]); + if(distanceBetweenResult <= mMaxDist * mMaxDist) + { + float zAngle = mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]); + MWBase::Environment::get().getWorld()->rotateObject(actor, 0, 0, zAngle, false); + MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 1; + mMaxDist = 470; + } + else + { + // Stop moving if the player is to far away + MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, "idle3", 0, 1); + MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0; + mMaxDist = 330; + } - if(distanceBetweenResult <= mMaxDist * mMaxDist) - { - float zAngle = mPathFinder.getZAngleToNext(pos.pos[0],pos.pos[1]); - MWBase::Environment::get().getWorld()->rotateObject(actor,0,0,zAngle,false); - MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 1; - mMaxDist = 470; + return false; } - else + + int AiEscort::getTypeId() const { - // Stop moving if the player is to far away - MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, "idle3", 0, 1); - MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0; - mMaxDist = 330; + return 2; } - - return false; -} - -int MWMechanics::AiEscort::getTypeId() const -{ - return 2; } diff --git a/apps/openmw/mwmechanics/aitravel.cpp b/apps/openmw/mwmechanics/aitravel.cpp index 4307ed284..90365c16b 100644 --- a/apps/openmw/mwmechanics/aitravel.cpp +++ b/apps/openmw/mwmechanics/aitravel.cpp @@ -2,99 +2,106 @@ #include "movement.hpp" -#include "../mwworld/class.hpp" #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" +#include "../mwworld/class.hpp" #include "../mwworld/player.hpp" namespace { float sgn(float a) { - if(a > 0) return 1.; - else return -1.; + if(a > 0) + return 1.0; + return -1.0; } } -MWMechanics::AiTravel::AiTravel(float x, float y, float z) -: mX(x),mY(y),mZ(z),mPathFinder() -{ -} - -MWMechanics::AiTravel *MWMechanics::AiTravel::clone() const +namespace MWMechanics { - return new AiTravel(*this); -} + AiTravel::AiTravel(float x, float y, float z) + : mX(x),mY(y),mZ(z),mPathFinder() + { + } -bool MWMechanics::AiTravel::execute (const MWWorld::Ptr& actor) -{ - const ESM::Pathgrid *pathgrid = - MWBase::Environment::get().getWorld()->getStore().get().search(*actor.getCell()->mCell); + AiTravel *MWMechanics::AiTravel::clone() const + { + return new AiTravel(*this); + } - ESM::Position pos = actor.getRefData().getPosition(); + bool AiTravel::execute (const MWWorld::Ptr& actor) + { + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + ESM::Position pos = actor.getRefData().getPosition(); bool cellChange = actor.getCell()->mCell->mData.mX != cellX || actor.getCell()->mCell->mData.mY != cellY; + const ESM::Pathgrid *pathgrid = + MWBase::Environment::get().getWorld()->getStore().get().search(*actor.getCell()->mCell); - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); - if(actor.getCell()->mCell->mData.mX != player.getCell()->mCell->mData.mX) - { - int sideX = sgn(actor.getCell()->mCell->mData.mX - player.getCell()->mCell->mData.mX); - //check if actor is near the border of an inactive cell. If so, disable aitravel. - if(sideX*(pos.pos[0] - actor.getCell()->mCell->mData.mX * ESM::Land::REAL_SIZE) > sideX*(ESM::Land::REAL_SIZE/2. - 200)) + if(actor.getCell()->mCell->mData.mX != player.getCell()->mCell->mData.mX) { - MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0; - return true; + int sideX = sgn(actor.getCell()->mCell->mData.mX - player.getCell()->mCell->mData.mX); + //check if actor is near the border of an inactive cell. If so, disable aitravel. + if(sideX * (pos.pos[0] - actor.getCell()->mCell->mData.mX * ESM::Land::REAL_SIZE) > sideX * (ESM::Land::REAL_SIZE / + 2.0 - 200)) + { + MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0; + return true; + } } - } - if(actor.getCell()->mCell->mData.mY != player.getCell()->mCell->mData.mY) - { - int sideY = sgn(actor.getCell()->mCell->mData.mY - player.getCell()->mCell->mData.mY); - //check if actor is near the border of an inactive cell. If so, disable aitravel. - if(sideY*(pos.pos[1] - actor.getCell()->mCell->mData.mY * ESM::Land::REAL_SIZE) > sideY*(ESM::Land::REAL_SIZE/2. - 200)) + if(actor.getCell()->mCell->mData.mY != player.getCell()->mCell->mData.mY) { - MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0; - return true; + int sideY = sgn(actor.getCell()->mCell->mData.mY - player.getCell()->mCell->mData.mY); + //check if actor is near the border of an inactive cell. If so, disable aitravel. + if(sideY * (pos.pos[1] - actor.getCell()->mCell->mData.mY * ESM::Land::REAL_SIZE) > sideY * (ESM::Land::REAL_SIZE / + 2.0 - 200)) + { + MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0; + return true; + } } - } - if(!mPathFinder.isPathConstructed() ||cellChange) - { - cellX = actor.getCell()->mCell->mData.mX; - cellY = actor.getCell()->mCell->mData.mY; - float xCell = 0; - float yCell = 0; - if (actor.getCell()->mCell->isExterior()) + if(!mPathFinder.isPathConstructed() || cellChange) { - xCell = actor.getCell()->mCell->mData.mX * ESM::Land::REAL_SIZE; - yCell = actor.getCell()->mCell->mData.mY * ESM::Land::REAL_SIZE; + cellX = actor.getCell()->mCell->mData.mX; + cellY = actor.getCell()->mCell->mData.mY; + float xCell = 0; + float yCell = 0; + + if (actor.getCell()->mCell->isExterior()) + { + xCell = actor.getCell()->mCell->mData.mX * ESM::Land::REAL_SIZE; + yCell = actor.getCell()->mCell->mData.mY * ESM::Land::REAL_SIZE; + } + + ESM::Pathgrid::Point dest; + dest.mX = mX; + dest.mY = mY; + dest.mZ = mZ; + + ESM::Pathgrid::Point start; + start.mX = pos.pos[0]; + start.mY = pos.pos[1]; + start.mZ = pos.pos[2]; + + mPathFinder.buildPath(start, dest, pathgrid, xCell, yCell, true); } - ESM::Pathgrid::Point dest; - dest.mX = mX; - dest.mY = mY; - dest.mZ = mZ; + if(mPathFinder.checkPathCompleted(pos.pos[0], pos.pos[1], pos.pos[2])) + { + MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0; + return true; + } - ESM::Pathgrid::Point start; - start.mX = pos.pos[0]; - start.mY = pos.pos[1]; - start.mZ = pos.pos[2]; + float zAngle = mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]); + MWBase::Environment::get().getWorld()->rotateObject(actor, 0, 0, zAngle, false); + MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 1; - mPathFinder.buildPath(start, dest, pathgrid, xCell, yCell, 1); + return false; } - if(mPathFinder.checkPathCompleted(pos.pos[0],pos.pos[1],pos.pos[2])) + int AiTravel::getTypeId() const { - MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0; - return true; + return 1; } - - float zAngle = mPathFinder.getZAngleToNext(pos.pos[0],pos.pos[1]); - MWBase::Environment::get().getWorld()->rotateObject(actor,0,0,zAngle,false); - MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 1; - - return false; } -int MWMechanics::AiTravel::getTypeId() const -{ - return 1; -} diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 1530804cd..8f7926236 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -14,316 +14,324 @@ namespace { float sgn(float a) { - if(a > 0) return 1.0; - else return -1.0; + if(a > 0) + return 1.0; + return -1.0; } } -MWMechanics::AiWander::AiWander(int distance, int duration, int timeOfDay, const std::vector& idle, bool repeat): - mDistance(distance), mDuration(duration), mTimeOfDay(timeOfDay), mIdle(idle), mRepeat(repeat) +namespace MWMechanics { - for(unsigned short counter = 0; counter < mIdle.size(); counter++) + AiWander::AiWander(int distance, int duration, int timeOfDay, const std::vector& idle, bool repeat): + mDistance(distance), mDuration(duration), mTimeOfDay(timeOfDay), mIdle(idle), mRepeat(repeat) { - if(mIdle[counter] >= 127 || mIdle[counter] < 0) - mIdle[counter] = 0; - } + for(unsigned short counter = 0; counter < mIdle.size(); counter++) + { + if(mIdle[counter] >= 127 || mIdle[counter] < 0) + mIdle[counter] = 0; + } - if(mDistance < 0) - mDistance = 0; - if(mDuration < 0) - mDuration = 0; - if(mDuration == 0) - mTimeOfDay = 0; - - srand(time(NULL)); - mStartTime = MWBase::Environment::get().getWorld()->getTimeStamp(); - mPlayedIdle = 0; - mPathgrid = NULL; - mIdleChanceMultiplier = - MWBase::Environment::get().getWorld()->getStore().get().find("fIdleChanceMultiplier")->getFloat(); - - mStoredAvailableNodes = false; - mChooseAction = true; - mIdleNow = false; - mMoveNow = false; - mWalking = false; -} + if(mDistance < 0) + mDistance = 0; + if(mDuration < 0) + mDuration = 0; + if(mDuration == 0) + mTimeOfDay = 0; -MWMechanics::AiPackage * MWMechanics::AiWander::clone() const -{ - return new AiWander(*this); -} + srand(time(NULL)); + mStartTime = MWBase::Environment::get().getWorld()->getTimeStamp(); + mPlayedIdle = 0; + mPathgrid = NULL; + mIdleChanceMultiplier = + MWBase::Environment::get().getWorld()->getStore().get().find("fIdleChanceMultiplier")->getFloat(); + + mStoredAvailableNodes = false; + mChooseAction = true; + mIdleNow = false; + mMoveNow = false; + mWalking = false; + } -bool MWMechanics::AiWander::execute (const MWWorld::Ptr& actor) -{ - if(mDuration) + AiPackage * MWMechanics::AiWander::clone() const { - // End package if duration is complete or mid-night hits: - MWWorld::TimeStamp currentTime = MWBase::Environment::get().getWorld()->getTimeStamp(); - if(currentTime.getHour() >= mStartTime.getHour() + mDuration) + return new AiWander(*this); + } + + bool AiWander::execute (const MWWorld::Ptr& actor) + { + if(mDuration) { - if(!mRepeat) + // End package if duration is complete or mid-night hits: + MWWorld::TimeStamp currentTime = MWBase::Environment::get().getWorld()->getTimeStamp(); + if(currentTime.getHour() >= mStartTime.getHour() + mDuration) { - stopWalking(actor); - return true; + if(!mRepeat) + { + stopWalking(actor); + return true; + } + else + mStartTime = currentTime; } - else - mStartTime = currentTime; - } - else if(int(currentTime.getHour()) == 0 && currentTime.getDay() != mStartTime.getDay()) - { - if(!mRepeat) + else if(int(currentTime.getHour()) == 0 && currentTime.getDay() != mStartTime.getDay()) { - stopWalking(actor); - return true; + if(!mRepeat) + { + stopWalking(actor); + return true; + } + else + mStartTime = currentTime; } - else - mStartTime = currentTime; } - } - ESM::Position pos = actor.getRefData().getPosition(); + ESM::Position pos = actor.getRefData().getPosition(); - if(!mStoredAvailableNodes) - { - mStoredAvailableNodes = true; - mPathgrid = - MWBase::Environment::get().getWorld()->getStore().get().search(*actor.getCell()->mCell); + if(!mStoredAvailableNodes) + { + mStoredAvailableNodes = true; + mPathgrid = + MWBase::Environment::get().getWorld()->getStore().get().search(*actor.getCell()->mCell); - mCellX = actor.getCell()->mCell->mData.mX; - mCellY = actor.getCell()->mCell->mData.mY; + mCellX = actor.getCell()->mCell->mData.mX; + mCellY = actor.getCell()->mCell->mData.mY; - if(!mPathgrid) - mDistance = 0; - else if(mPathgrid->mPoints.empty()) - mDistance = 0; + if(!mPathgrid) + mDistance = 0; + else if(mPathgrid->mPoints.empty()) + mDistance = 0; - if(mDistance) - { - mXCell = 0; - mYCell = 0; - if(actor.getCell()->mCell->isExterior()) + if(mDistance) { - mXCell = mCellX * ESM::Land::REAL_SIZE; - mYCell = mCellY * ESM::Land::REAL_SIZE; - } + mXCell = 0; + mYCell = 0; + if(actor.getCell()->mCell->isExterior()) + { + mXCell = mCellX * ESM::Land::REAL_SIZE; + mYCell = mCellY * ESM::Land::REAL_SIZE; + } - Ogre::Vector3 npcPos(actor.getRefData().getPosition().pos); - npcPos[0] = npcPos[0] - mXCell; - npcPos[1] = npcPos[1] - mYCell; + Ogre::Vector3 npcPos(actor.getRefData().getPosition().pos); + npcPos[0] = npcPos[0] - mXCell; + npcPos[1] = npcPos[1] - mYCell; - for(unsigned int counter = 0; counter < mPathgrid->mPoints.size(); counter++) - { - Ogre::Vector3 nodePos(mPathgrid->mPoints[counter].mX, mPathgrid->mPoints[counter].mY, mPathgrid->mPoints[counter].mZ); - if(npcPos.squaredDistance(nodePos) <= mDistance * mDistance) - mAllowedNodes.push_back(mPathgrid->mPoints[counter]); - } - if(!mAllowedNodes.empty()) - { - Ogre::Vector3 firstNodePos(mAllowedNodes[0].mX, mAllowedNodes[0].mY, mAllowedNodes[0].mZ); - float closestNode = npcPos.squaredDistance(firstNodePos); - unsigned int index = 0; - for(unsigned int counterThree = 1; counterThree < mAllowedNodes.size(); counterThree++) + for(unsigned int counter = 0; counter < mPathgrid->mPoints.size(); counter++) { - Ogre::Vector3 nodePos(mAllowedNodes[counterThree].mX, mAllowedNodes[counterThree].mY, mAllowedNodes[counterThree].mZ); - float tempDist = npcPos.squaredDistance(nodePos); - if(tempDist < closestNode) - index = counterThree; + Ogre::Vector3 nodePos(mPathgrid->mPoints[counter].mX, mPathgrid->mPoints[counter].mY, + mPathgrid->mPoints[counter].mZ); + if(npcPos.squaredDistance(nodePos) <= mDistance * mDistance) + mAllowedNodes.push_back(mPathgrid->mPoints[counter]); + } + if(!mAllowedNodes.empty()) + { + Ogre::Vector3 firstNodePos(mAllowedNodes[0].mX, mAllowedNodes[0].mY, mAllowedNodes[0].mZ); + float closestNode = npcPos.squaredDistance(firstNodePos); + unsigned int index = 0; + for(unsigned int counterThree = 1; counterThree < mAllowedNodes.size(); counterThree++) + { + Ogre::Vector3 nodePos(mAllowedNodes[counterThree].mX, mAllowedNodes[counterThree].mY, + mAllowedNodes[counterThree].mZ); + float tempDist = npcPos.squaredDistance(nodePos); + if(tempDist < closestNode) + index = counterThree; + } + mCurrentNode = mAllowedNodes[index]; + mAllowedNodes.erase(mAllowedNodes.begin() + index); } - mCurrentNode = mAllowedNodes[index]; - mAllowedNodes.erase(mAllowedNodes.begin() + index); - } - if(mAllowedNodes.empty()) - mDistance = 0; + if(mAllowedNodes.empty()) + mDistance = 0; + } } - } - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); - bool cellChange = actor.getCell()->mCell->mData.mX != mCellX || actor.getCell()->mCell->mData.mY != mCellY; + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + bool cellChange = actor.getCell()->mCell->mData.mX != mCellX || actor.getCell()->mCell->mData.mY != mCellY; - if(actor.getCell()->mCell->mData.mX != player.getCell()->mCell->mData.mX) - { - int sideX = sgn(actor.getCell()->mCell->mData.mX - player.getCell()->mCell->mData.mX); - // Check if actor is near the border of an inactive cell. If so, disable AiWander. - // FIXME: This *should* pause the AiWander package instead of terminating it. - if(sideX*(pos.pos[0] - actor.getCell()->mCell->mData.mX * ESM::Land::REAL_SIZE) > sideX * (ESM::Land::REAL_SIZE / 2.0 - 200)) + if(actor.getCell()->mCell->mData.mX != player.getCell()->mCell->mData.mX) { - stopWalking(actor); - return true; + int sideX = sgn(actor.getCell()->mCell->mData.mX - player.getCell()->mCell->mData.mX); + // Check if actor is near the border of an inactive cell. If so, disable AiWander. + // FIXME: This *should* pause the AiWander package instead of terminating it. + if(sideX * (pos.pos[0] - actor.getCell()->mCell->mData.mX * ESM::Land::REAL_SIZE) > sideX * (ESM::Land::REAL_SIZE / + 2.0 - 200)) + { + stopWalking(actor); + return true; + } } - } - if(actor.getCell()->mCell->mData.mY != player.getCell()->mCell->mData.mY) - { - int sideY = sgn(actor.getCell()->mCell->mData.mY - player.getCell()->mCell->mData.mY); - // Check if actor is near the border of an inactive cell. If so, disable AiWander. - // FIXME: This *should* pause the AiWander package instead of terminating it. - if(sideY*(pos.pos[1] - actor.getCell()->mCell->mData.mY * ESM::Land::REAL_SIZE) > sideY * (ESM::Land::REAL_SIZE / 2.0 - 200)) + if(actor.getCell()->mCell->mData.mY != player.getCell()->mCell->mData.mY) { - stopWalking(actor); - return true; + int sideY = sgn(actor.getCell()->mCell->mData.mY - player.getCell()->mCell->mData.mY); + // Check if actor is near the border of an inactive cell. If so, disable AiWander. + // FIXME: This *should* pause the AiWander package instead of terminating it. + if(sideY * (pos.pos[1] - actor.getCell()->mCell->mData.mY * ESM::Land::REAL_SIZE) > sideY * (ESM::Land::REAL_SIZE / + 2.0 - 200)) + { + stopWalking(actor); + return true; + } } - } - // Don't try to move if you are in a new cell (ie: positioncell command called) but still play idles. - if(mDistance && (cellChange || (mCellX != actor.getCell()->mCell->mData.mX || mCellY != actor.getCell()->mCell->mData.mY))) - mDistance = 0; - - if(mChooseAction) - { - mPlayedIdle = 0; - unsigned short idleRoll = 0; + // Don't try to move if you are in a new cell (ie: positioncell command called) but still play idles. + if(mDistance && (cellChange || (mCellX != actor.getCell()->mCell->mData.mX || mCellY != actor.getCell()->mCell->mData.mY))) + mDistance = 0; - for(unsigned int counter = 1; counter < mIdle.size(); counter++) + if(mChooseAction) { - unsigned short idleChance = mIdleChanceMultiplier * mIdle[counter]; - unsigned short randSelect = (int)(rand() / ((double)RAND_MAX + 1) * int(100 / mIdleChanceMultiplier)); - if(randSelect < idleChance && randSelect > idleRoll) + mPlayedIdle = 0; + unsigned short idleRoll = 0; + + for(unsigned int counter = 1; counter < mIdle.size(); counter++) { - mPlayedIdle = counter; - idleRoll = randSelect; + unsigned short idleChance = mIdleChanceMultiplier * mIdle[counter]; + unsigned short randSelect = (int)(rand() / ((double)RAND_MAX + 1) * int(100 / mIdleChanceMultiplier)); + if(randSelect < idleChance && randSelect > idleRoll) + { + mPlayedIdle = counter; + idleRoll = randSelect; + } } - } - if(!mPlayedIdle && mDistance) - { - mChooseAction = false; - mMoveNow = true; - } - else - { - // Play idle animation and recreate vanilla (broken?) behavior of resetting start time of AIWander: - MWWorld::TimeStamp currentTime = MWBase::Environment::get().getWorld()->getTimeStamp(); - mStartTime = currentTime; - playIdle(actor, mPlayedIdle + 1); - mChooseAction = false; - mIdleNow = true; + if(!mPlayedIdle && mDistance) + { + mChooseAction = false; + mMoveNow = true; + } + else + { + // Play idle animation and recreate vanilla (broken?) behavior of resetting start time of AIWander: + MWWorld::TimeStamp currentTime = MWBase::Environment::get().getWorld()->getTimeStamp(); + mStartTime = currentTime; + playIdle(actor, mPlayedIdle + 1); + mChooseAction = false; + mIdleNow = true; + } } - } - if(mIdleNow) - { - if(!checkIdle(actor, mPlayedIdle + 1)) + if(mIdleNow) { - mPlayedIdle = 0; - mIdleNow = false; - mChooseAction = true; + if(!checkIdle(actor, mPlayedIdle + 1)) + { + mPlayedIdle = 0; + mIdleNow = false; + mChooseAction = true; + } } - } - if(mMoveNow && mDistance) - { - if(!mPathFinder.isPathConstructed()) + if(mMoveNow && mDistance) { - unsigned int randNode = (int)(rand() / ((double)RAND_MAX + 1) * mAllowedNodes.size()); - Ogre::Vector3 destNodePos(mAllowedNodes[randNode].mX, mAllowedNodes[randNode].mY, mAllowedNodes[randNode].mZ); + if(!mPathFinder.isPathConstructed()) + { + unsigned int randNode = (int)(rand() / ((double)RAND_MAX + 1) * mAllowedNodes.size()); + Ogre::Vector3 destNodePos(mAllowedNodes[randNode].mX, mAllowedNodes[randNode].mY, mAllowedNodes[randNode].mZ); - ESM::Pathgrid::Point dest; - dest.mX = destNodePos[0] + mXCell; - dest.mY = destNodePos[1] + mYCell; - dest.mZ = destNodePos[2]; + ESM::Pathgrid::Point dest; + dest.mX = destNodePos[0] + mXCell; + dest.mY = destNodePos[1] + mYCell; + dest.mZ = destNodePos[2]; - ESM::Pathgrid::Point start; - start.mX = pos.pos[0]; - start.mY = pos.pos[1]; - start.mZ = pos.pos[2]; + ESM::Pathgrid::Point start; + start.mX = pos.pos[0]; + start.mY = pos.pos[1]; + start.mZ = pos.pos[2]; - mPathFinder.buildPath(start, dest, mPathgrid, mXCell, mYCell, 0); + mPathFinder.buildPath(start, dest, mPathgrid, mXCell, mYCell, false); - if(mPathFinder.isPathConstructed()) - { - // Remove this node as an option and add back the previously used node (stops NPC from picking the same node): - ESM::Pathgrid::Point temp = mAllowedNodes[randNode]; - mAllowedNodes.erase(mAllowedNodes.begin() + randNode); - mAllowedNodes.push_back(mCurrentNode); - mCurrentNode = temp; + if(mPathFinder.isPathConstructed()) + { + // Remove this node as an option and add back the previously used node (stops NPC from picking the same node): + ESM::Pathgrid::Point temp = mAllowedNodes[randNode]; + mAllowedNodes.erase(mAllowedNodes.begin() + randNode); + mAllowedNodes.push_back(mCurrentNode); + mCurrentNode = temp; + + mMoveNow = false; + mWalking = true; + } + // Choose a different node and delete this one from possible nodes because it is uncreachable: + else + mAllowedNodes.erase(mAllowedNodes.begin() + randNode); + } + } + if(mWalking) + { + float zAngle = mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]); + MWBase::Environment::get().getWorld()->rotateObject(actor, 0, 0, zAngle,false); + MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 1; + + // Unclog path nodes by allowing the NPC to be a small distance away from the center. This way two NPCs can be + // at the same path node at the same time and both will complete instead of endlessly walking into eachother: + Ogre::Vector3 destNodePos(mCurrentNode.mX, mCurrentNode.mY, mCurrentNode.mZ); + Ogre::Vector3 actorPos(actor.getRefData().getPosition().pos); + actorPos[0] = actorPos[0] - mXCell; + actorPos[1] = actorPos[1] - mYCell; + float distance = actorPos.squaredDistance(destNodePos); + + if(distance < 1200 || mPathFinder.checkPathCompleted(pos.pos[0], pos.pos[1], pos.pos[2])) + { + stopWalking(actor); mMoveNow = false; - mWalking = true; + mWalking = false; + mChooseAction = true; } - // Choose a different node and delete this one from possible nodes because it is uncreachable: - else - mAllowedNodes.erase(mAllowedNodes.begin() + randNode); } + + return false; } - if(mWalking) + int AiWander::getTypeId() const { - float zAngle = mPathFinder.getZAngleToNext(pos.pos[0],pos.pos[1]); - MWBase::Environment::get().getWorld()->rotateObject(actor,0,0,zAngle,false); - MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 1; - - // Unclog path nodes by allowing the NPC to be a small distance away from the center. This way two NPCs can be - // at the same path node at the same time and both will complete instead of endlessly walking into eachother: - Ogre::Vector3 destNodePos(mCurrentNode.mX, mCurrentNode.mY, mCurrentNode.mZ); - Ogre::Vector3 actorPos(actor.getRefData().getPosition().pos); - actorPos[0] = actorPos[0] - mXCell; - actorPos[1] = actorPos[1] - mYCell; - float distance = actorPos.squaredDistance(destNodePos); - - if(distance < 1200 || mPathFinder.checkPathCompleted(pos.pos[0], pos.pos[1], pos.pos[2])) - { - stopWalking(actor); - mMoveNow = false; - mWalking = false; - mChooseAction = true; - } + return 0; } - return false; -} - -int MWMechanics::AiWander::getTypeId() const -{ - return 0; -} - -void MWMechanics::AiWander::stopWalking(const MWWorld::Ptr& actor) -{ - mPathFinder.clearPath(); - MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0; -} + void AiWander::stopWalking(const MWWorld::Ptr& actor) + { + mPathFinder.clearPath(); + MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0; + } -void MWMechanics::AiWander::playIdle(const MWWorld::Ptr& actor, unsigned short idleSelect) -{ - if(idleSelect == 2) - MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, "idle2", 0, 1); - else if(idleSelect == 3) - MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, "idle3", 0, 1); - else if(idleSelect == 4) - MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, "idle4", 0, 1); - else if(idleSelect == 5) - MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, "idle5", 0, 1); - else if(idleSelect == 6) - MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, "idle6", 0, 1); - else if(idleSelect == 7) - MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, "idle7", 0, 1); - else if(idleSelect == 8) - MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, "idle8", 0, 1); - else if(idleSelect == 9) - MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, "idle9", 0, 1); -} + void AiWander::playIdle(const MWWorld::Ptr& actor, unsigned short idleSelect) + { + if(idleSelect == 2) + MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, "idle2", 0, 1); + else if(idleSelect == 3) + MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, "idle3", 0, 1); + else if(idleSelect == 4) + MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, "idle4", 0, 1); + else if(idleSelect == 5) + MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, "idle5", 0, 1); + else if(idleSelect == 6) + MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, "idle6", 0, 1); + else if(idleSelect == 7) + MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, "idle7", 0, 1); + else if(idleSelect == 8) + MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, "idle8", 0, 1); + else if(idleSelect == 9) + MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, "idle9", 0, 1); + } -bool MWMechanics::AiWander::checkIdle(const MWWorld::Ptr& actor, unsigned short idleSelect) -{ - if(idleSelect == 2) - return MWBase::Environment::get().getMechanicsManager()->checkAnimationPlaying(actor, "idle2"); - else if(idleSelect == 3) - return MWBase::Environment::get().getMechanicsManager()->checkAnimationPlaying(actor, "idle3"); - else if(idleSelect == 4) - return MWBase::Environment::get().getMechanicsManager()->checkAnimationPlaying(actor, "idle4"); - else if(idleSelect == 5) - return MWBase::Environment::get().getMechanicsManager()->checkAnimationPlaying(actor, "idle5"); - else if(idleSelect == 6) - return MWBase::Environment::get().getMechanicsManager()->checkAnimationPlaying(actor, "idle6"); - else if(idleSelect == 7) - return MWBase::Environment::get().getMechanicsManager()->checkAnimationPlaying(actor, "idle7"); - else if(idleSelect == 8) - return MWBase::Environment::get().getMechanicsManager()->checkAnimationPlaying(actor, "idle8"); - else if(idleSelect == 9) - return MWBase::Environment::get().getMechanicsManager()->checkAnimationPlaying(actor, "idle9"); - else - return false; + bool AiWander::checkIdle(const MWWorld::Ptr& actor, unsigned short idleSelect) + { + if(idleSelect == 2) + return MWBase::Environment::get().getMechanicsManager()->checkAnimationPlaying(actor, "idle2"); + else if(idleSelect == 3) + return MWBase::Environment::get().getMechanicsManager()->checkAnimationPlaying(actor, "idle3"); + else if(idleSelect == 4) + return MWBase::Environment::get().getMechanicsManager()->checkAnimationPlaying(actor, "idle4"); + else if(idleSelect == 5) + return MWBase::Environment::get().getMechanicsManager()->checkAnimationPlaying(actor, "idle5"); + else if(idleSelect == 6) + return MWBase::Environment::get().getMechanicsManager()->checkAnimationPlaying(actor, "idle6"); + else if(idleSelect == 7) + return MWBase::Environment::get().getMechanicsManager()->checkAnimationPlaying(actor, "idle7"); + else if(idleSelect == 8) + return MWBase::Environment::get().getMechanicsManager()->checkAnimationPlaying(actor, "idle8"); + else if(idleSelect == 9) + return MWBase::Environment::get().getMechanicsManager()->checkAnimationPlaying(actor, "idle9"); + else + return false; + } } diff --git a/apps/openmw/mwmechanics/pathfinding.cpp b/apps/openmw/mwmechanics/pathfinding.cpp index d3a44e0f9..986595a9a 100644 --- a/apps/openmw/mwmechanics/pathfinding.cpp +++ b/apps/openmw/mwmechanics/pathfinding.cpp @@ -205,7 +205,7 @@ namespace MWMechanics return true; ESM::Pathgrid::Point nextPoint = *mPath.begin(); - if(distanceZCorrected(nextPoint, x, y, z) < 20) + if(distanceZCorrected(nextPoint, x, y, z) < 40) { mPath.pop_front(); if(mPath.empty()) From 512dcdc73575f9fdd2be21ef0ecef5f1c246059c Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 2 Jun 2013 09:50:29 +0200 Subject: [PATCH 41/52] updated changelog --- readme.txt | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/readme.txt b/readme.txt index 230150d6e..2cf5c5551 100644 --- a/readme.txt +++ b/readme.txt @@ -94,6 +94,53 @@ Allowed options: CHANGELOG +0.24.0 + +Bug #284: Book's text misalignment +Bug #445: Camera able to get slightly below floor / terrain +Bug #582: Seam issue in Red Mountain +Bug #632: Journal Next Button shows white square +Bug #653: IndexedStore ignores index +Bug #694: Parser does not recognize float values starting with . +Bug #699: Resource handling broken with Ogre 1.9 trunk +Bug #718: components/esm/loadcell is using the mwworld subsystem +Bug #729: Levelled item list tries to add nonexistent item +Bug #730: Arrow buttons in the settings menu do not work. +Bug #732: Erroneous behavior when binding keys +Bug #733: Unclickable dialogue topic +Bug #734: Book empty line problem +Bug #738: OnDeath only works with implicit references +Bug #740: Script compiler fails on scripts with special names +Bug #742: Wait while no clipping +Bug #743: Problem with changeweather console command +Bug #744: No wait dialogue after starting a new game +Bug #748: Player is not able to unselect objects with the console +Bug #751: AddItem should only spawn a message box when called from dialogue +Bug #752: The enter button has several functions in trade and looting that is not impelemted. +Bug #753: Fargoth's Ring Quest Strange Behavior +Bug #759: Second quest in mages guild does not work +Bug #763: Enchantment cast cost is wrong +Bug #770: The "Take" and "Close" buttons in the scroll GUI are stretched incorrectly +Bug #773: AIWander Isn't Being Passed The Correct idle Values +Bug #778: The journal can be opened at the start of a new game +Bug #779: Divayth Fyr starts as dead +Bug #787: "Batch count" on detailed FPS counter gets cut-off +Bug #788: chargen scroll layout does not match vanilla +Feature #60: Atlethics Skill +Feature #65: Security Skill +Feature #74: Interaction with non-load-doors +Feature #98: Render Weapon and Shield +Feature #102: AI Package: Escort, EscortCell +Feature #182: Advanced Journal GUI +Feature #288: Trading enhancements +Feature #405: Integrate "new game" into the menu +Feature #537: Highlight dialogue topic links +Feature #658: Rotate, RotateWorld script instructions and local rotations +Feature #690: Animation Layering +Feature #722: Night Eye/Blind magic effects +Feature #735: Move, MoveWorld script instructions. +Feature #760: Non-removable corpses + 0.23.0 Bug #522: Player collides with placeable items From b3595a6a2e42d715f3345bced12d346e7f1b4d07 Mon Sep 17 00:00:00 2001 From: pvdk Date: Sun, 2 Jun 2013 21:43:22 +0200 Subject: [PATCH 42/52] Fix for duplicate key/value pairs being written to settings.cfg, Bug #755 --- apps/launcher/maindialog.cpp | 4 ++++ apps/launcher/settings/gamesettings.cpp | 4 ++-- apps/launcher/settings/settingsbase.hpp | 20 ++++++++++++++++---- files/ui/playpage.ui | 19 +++++++++---------- 4 files changed, 31 insertions(+), 16 deletions(-) diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index e5da3431a..8cc476f53 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -310,6 +310,8 @@ void MainDialog::changePage(QListWidgetItem *current, QListWidgetItem *previous) bool MainDialog::setupLauncherSettings() { + mLauncherSettings.setMultiValueEnabled(true); + QString userPath = QString::fromStdString(mCfgMgr.getUserPath().string()); QStringList paths; @@ -427,6 +429,8 @@ bool MainDialog::setupGameSettings() bool MainDialog::setupGraphicsSettings() { + mGraphicsSettings.setMultiValueEnabled(false); + QString userPath = QString::fromStdString(mCfgMgr.getUserPath().string()); QString globalPath = QString::fromStdString(mCfgMgr.getGlobalPath().string()); diff --git a/apps/launcher/settings/gamesettings.cpp b/apps/launcher/settings/gamesettings.cpp index 9a9b8df41..1b0a2e9bf 100644 --- a/apps/launcher/settings/gamesettings.cpp +++ b/apps/launcher/settings/gamesettings.cpp @@ -103,8 +103,8 @@ bool GameSettings::readFile(QTextStream &stream) if (keyRe.indexIn(line) != -1) { - QString key = keyRe.cap(1); - QString value = keyRe.cap(2); + QString key = keyRe.cap(1).trimmed(); + QString value = keyRe.cap(2).trimmed(); // Don't remove existing data entries if (key != QLatin1String("data")) diff --git a/apps/launcher/settings/settingsbase.hpp b/apps/launcher/settings/settingsbase.hpp index 21029b3ad..6bf2eff66 100644 --- a/apps/launcher/settings/settingsbase.hpp +++ b/apps/launcher/settings/settingsbase.hpp @@ -14,7 +14,7 @@ class SettingsBase { public: - SettingsBase() {} + SettingsBase() { mMultiValue = false; } ~SettingsBase() {} inline QString value(const QString &key, const QString &defaultValue = QString()) @@ -36,6 +36,11 @@ public: mSettings.insertMulti(key, value); } + inline void setMultiValueEnabled(bool enable) + { + mMultiValue = enable; + } + inline void remove(const QString &key) { mSettings.remove(key); @@ -66,8 +71,8 @@ public: if (keyRe.indexIn(line) != -1) { - QString key = keyRe.cap(1); - QString value = keyRe.cap(2); + QString key = keyRe.cap(1).trimmed(); + QString value = keyRe.cap(2).trimmed(); if (!sectionPrefix.isEmpty()) key.prepend(sectionPrefix); @@ -75,8 +80,13 @@ public: mSettings.remove(key); QStringList values = mCache.values(key); + if (!values.contains(value)) { - mCache.insertMulti(key, value); + if (mMultiValue) { + mCache.insertMulti(key, value); + } else { + mCache.insert(key, value); + } } } } @@ -94,6 +104,8 @@ public: private: Map mSettings; Map mCache; + + bool mMultiValue; }; #endif // SETTINGSBASE_HPP diff --git a/files/ui/playpage.ui b/files/ui/playpage.ui index c0320de1e..bf883b96e 100644 --- a/files/ui/playpage.ui +++ b/files/ui/playpage.ui @@ -2,9 +2,17 @@ PlayPage + + + 0 + 0 + 274 + 317 + + - + #Scroll { background-image: url(":/images/playpage-background.png"); @@ -13,15 +21,6 @@ } - - QFrame::StyledPanel - - - QFrame::Plain - - - 0 - 30 From 68bef59d89610fdcbb535df7f22296a7808901b2 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 3 Jun 2013 10:15:19 +0200 Subject: [PATCH 43/52] updated changelog again --- readme.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/readme.txt b/readme.txt index 2cf5c5551..67c02cc61 100644 --- a/readme.txt +++ b/readme.txt @@ -118,6 +118,7 @@ Bug #748: Player is not able to unselect objects with the console Bug #751: AddItem should only spawn a message box when called from dialogue Bug #752: The enter button has several functions in trade and looting that is not impelemted. Bug #753: Fargoth's Ring Quest Strange Behavior +Bug #755: Launcher writes duplicate lines into settings.cfg Bug #759: Second quest in mages guild does not work Bug #763: Enchantment cast cost is wrong Bug #770: The "Take" and "Close" buttons in the scroll GUI are stretched incorrectly From daab4f55a3648a2adfb4f71780909e4b88752efc Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 6 Jun 2013 22:13:30 +0200 Subject: [PATCH 44/52] Use Morrowind's fonts --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/engine.cpp | 2 +- apps/openmw/mwgui/bookpage.cpp | 15 +- apps/openmw/mwgui/dialogue.cpp | 10 +- apps/openmw/mwgui/fontloader.cpp | 238 +++++++++++++++++++++++ apps/openmw/mwgui/fontloader.hpp | 25 +++ apps/openmw/mwgui/formatting.cpp | 4 +- apps/openmw/mwgui/journalbooks.cpp | 24 +-- apps/openmw/mwgui/windowmanagerimp.cpp | 7 +- apps/openmw/mwgui/windowmanagerimp.hpp | 2 +- components/to_utf8/gen_iconv.cpp | 4 +- components/to_utf8/tables_gen.hpp | 259 +++++++++++++++++++++++++ components/to_utf8/to_utf8.cpp | 6 + components/to_utf8/to_utf8.hpp | 3 +- files/mygui/core.skin | 1 - files/mygui/openmw_font.xml | 45 +---- files/mygui/openmw_settings.xml | 2 +- 17 files changed, 579 insertions(+), 70 deletions(-) create mode 100644 apps/openmw/mwgui/fontloader.cpp create mode 100644 apps/openmw/mwgui/fontloader.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 660e45115..31f6fca79 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -33,7 +33,7 @@ add_openmw_dir (mwgui enchantingdialog trainingwindow travelwindow imagebutton exposedwindow cursor spellicons merchantrepair repair soulgemdialog companionwindow bookpage journalviewmodel journalbooks keywordsearch itemmodel containeritemmodel inventoryitemmodel sortfilteritemmodel itemview - tradeitemmodel companionitemmodel pickpocketitemmodel + tradeitemmodel companionitemmodel pickpocketitemmodel fontloader ) add_openmw_dir (mwdialogue diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index abc951726..89d34bd41 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -380,7 +380,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) mEnvironment.setWindowManager (new MWGui::WindowManager( mExtensions, mFpsLevel, mOgre, mCfgMgr.getLogPath().string() + std::string("/"), - mCfgMgr.getCachePath ().string(), mScriptConsoleMode, mTranslationDataStorage)); + mCfgMgr.getCachePath ().string(), mScriptConsoleMode, mTranslationDataStorage, mEncoding)); if (mNewGame) mEnvironment.getWindowManager()->setNewGame(true); diff --git a/apps/openmw/mwgui/bookpage.cpp b/apps/openmw/mwgui/bookpage.cpp index ef688be1b..94f834a4d 100644 --- a/apps/openmw/mwgui/bookpage.cpp +++ b/apps/openmw/mwgui/bookpage.cpp @@ -223,6 +223,9 @@ struct TypesetBookImpl::Typesetter : BookTypesetter Style * createStyle (char const * fontName, Colour fontColour) { + if (strcmp(fontName, "") == 0) + return createStyle(MyGUI::FontManager::getInstance().getDefaultFont().c_str(), fontColour); + for (Styles::iterator i = mBook->mStyles.begin (); i != mBook->mStyles.end (); ++i) if (i->match (fontName, fontColour, fontColour, fontColour, 0)) return &*i; @@ -405,7 +408,8 @@ struct TypesetBookImpl::Typesetter : BookTypesetter while (!stream.eof () && !ucsLineBreak (stream.peek ()) && ucsBreakingSpace (stream.peek ())) { MyGUI::GlyphInfo* gi = style->mFont->getGlyphInfo (stream.peek ()); - space_width += gi->advance; + if (gi) + space_width += gi->advance + gi->bearingX; stream.consume (); } @@ -414,7 +418,8 @@ struct TypesetBookImpl::Typesetter : BookTypesetter while (!stream.eof () && !ucsLineBreak (stream.peek ()) && !ucsBreakingSpace (stream.peek ())) { MyGUI::GlyphInfo* gi = style->mFont->getGlyphInfo (stream.peek ()); - word_width += gi->advance + gi->bearingX; + if (gi) + word_width += gi->advance + gi->bearingX; word_height = line_height; ++character_count; stream.consume (); @@ -628,6 +633,9 @@ namespace { MyGUI::GlyphInfo* gi = mFont->getGlyphInfo (ch); + if (!gi) + return; + MyGUI::FloatRect vr; vr.left = mCursor.left + gi->bearingX; @@ -647,7 +655,8 @@ namespace { MyGUI::GlyphInfo* gi = mFont->getGlyphInfo (ch); - mCursor.left += gi->bearingX + gi->advance; + if (gi) + mCursor.left += gi->bearingX + gi->advance; } private: diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 2eacd973e..64c61abc0 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -115,7 +115,7 @@ namespace MWGui void Response::write(BookTypesetter::Ptr typesetter, KeywordSearchT* keywordSearch, std::map& topicLinks) const { - BookTypesetter::Style* title = typesetter->createStyle("EB Garamond", MyGUI::Colour(223/255.f, 201/255.f, 159/255.f)); + BookTypesetter::Style* title = typesetter->createStyle("", MyGUI::Colour(223/255.f, 201/255.f, 159/255.f)); typesetter->sectionBreak(9); if (mTitle != "") typesetter->write(title, to_utf8_span(mTitle.c_str())); @@ -159,7 +159,7 @@ namespace MWGui if (hyperLinks.size() && MWBase::Environment::get().getWindowManager()->getTranslationDataStorage().hasTranslation()) { - BookTypesetter::Style* style = typesetter->createStyle("EB Garamond", MyGUI::Colour(202/255.f, 165/255.f, 96/255.f)); + BookTypesetter::Style* style = typesetter->createStyle("", MyGUI::Colour(202/255.f, 165/255.f, 96/255.f)); size_t formatted = 0; // points to the first character that is not laid out yet for (std::map::iterator it = hyperLinks.begin(); it != hyperLinks.end(); ++it) { @@ -197,7 +197,7 @@ namespace MWGui void Response::addTopicLink(BookTypesetter::Ptr typesetter, intptr_t topicId, size_t begin, size_t end) const { - BookTypesetter::Style* style = typesetter->createStyle("EB Garamond", MyGUI::Colour(202/255.f, 165/255.f, 96/255.f)); + BookTypesetter::Style* style = typesetter->createStyle("", MyGUI::Colour(202/255.f, 165/255.f, 96/255.f)); const MyGUI::Colour linkHot (143/255.f, 155/255.f, 218/255.f); const MyGUI::Colour linkNormal (112/255.f, 126/255.f, 207/255.f); @@ -215,7 +215,7 @@ namespace MWGui void Message::write(BookTypesetter::Ptr typesetter, KeywordSearchT* keywordSearch, std::map& topicLinks) const { - BookTypesetter::Style* title = typesetter->createStyle("EB Garamond", MyGUI::Colour(223/255.f, 201/255.f, 159/255.f)); + BookTypesetter::Style* title = typesetter->createStyle("", MyGUI::Colour(223/255.f, 201/255.f, 159/255.f)); typesetter->sectionBreak(9); typesetter->write(title, to_utf8_span(mText.c_str())); } @@ -465,7 +465,7 @@ namespace MWGui (*it)->write(typesetter, &mKeywordSearch, mTopicLinks); - BookTypesetter::Style* body = typesetter->createStyle("EB Garamond", MyGUI::Colour::White); + BookTypesetter::Style* body = typesetter->createStyle("", MyGUI::Colour::White); // choices const MyGUI::Colour linkHot (223/255.f, 201/255.f, 159/255.f); diff --git a/apps/openmw/mwgui/fontloader.cpp b/apps/openmw/mwgui/fontloader.cpp new file mode 100644 index 000000000..ff160105a --- /dev/null +++ b/apps/openmw/mwgui/fontloader.cpp @@ -0,0 +1,238 @@ +#include "fontloader.hpp" + +#include +#include + +#include +#include +#include +#include +#include + +#include + +namespace +{ + unsigned long utf8ToUnicode(const std::string& utf8) + { + size_t i = 0; + unsigned long unicode; + size_t todo; + unsigned char ch = utf8[i++]; + if (ch <= 0x7F) + { + unicode = ch; + todo = 0; + } + else if (ch <= 0xBF) + { + throw std::logic_error("not a UTF-8 string"); + } + else if (ch <= 0xDF) + { + unicode = ch&0x1F; + todo = 1; + } + else if (ch <= 0xEF) + { + unicode = ch&0x0F; + todo = 2; + } + else if (ch <= 0xF7) + { + unicode = ch&0x07; + todo = 3; + } + else + { + throw std::logic_error("not a UTF-8 string"); + } + for (size_t j = 0; j < todo; ++j) + { + unsigned char ch = utf8[i++]; + if (ch < 0x80 || ch > 0xBF) + throw std::logic_error("not a UTF-8 string"); + unicode <<= 6; + unicode += ch & 0x3F; + } + if (unicode >= 0xD800 && unicode <= 0xDFFF) + throw std::logic_error("not a UTF-8 string"); + if (unicode > 0x10FFFF) + throw std::logic_error("not a UTF-8 string"); + + return unicode; + } +} + +namespace MWGui +{ + + FontLoader::FontLoader(ToUTF8::FromType encoding) + { + if (encoding == ToUTF8::WINDOWS_1252) + mEncoding = ToUTF8::CP437; + else + mEncoding = encoding; + } + + void FontLoader::loadAllFonts() + { + Ogre::StringVector groups = Ogre::ResourceGroupManager::getSingleton().getResourceGroups (); + for (Ogre::StringVector::iterator it = groups.begin(); it != groups.end(); ++it) + { + Ogre::StringVectorPtr resourcesInThisGroup = Ogre::ResourceGroupManager::getSingleton ().findResourceNames (*it, "*.fnt"); + for (Ogre::StringVector::iterator resource = resourcesInThisGroup->begin(); resource != resourcesInThisGroup->end(); ++resource) + { + loadFont(*resource); + } + } + } + + + typedef struct + { + float x; + float y; + } Point; + + typedef struct + { + float u1; // appears unused, always 0 + Point top_left; + Point top_right; + Point bottom_left; + Point bottom_right; + float width; + float height; + float u2; // appears unused, always 0 + float kerning; + float ascent; + } GlyphInfo; + + void FontLoader::loadFont(const std::string &fileName) + { + Ogre::DataStreamPtr file = Ogre::ResourceGroupManager::getSingleton().openResource(fileName); + + float fontSize; + int one; + file->read(&fontSize, sizeof(fontSize)); + + file->read(&one, sizeof(int)); + assert(one == 1); + file->read(&one, sizeof(int)); + assert(one == 1); + + char name_[284]; + file->read(name_, sizeof(name_)); + std::string name(name_); + + GlyphInfo data[256]; + file->read(data, sizeof(data)); + file->close(); + + // Create the font texture + std::string bitmapFilename = "Fonts/" + std::string(name) + ".tex"; + Ogre::DataStreamPtr bitmapFile = Ogre::ResourceGroupManager::getSingleton().openResource(bitmapFilename); + + int width, height; + bitmapFile->read(&width, sizeof(int)); + bitmapFile->read(&height, sizeof(int)); + + std::vector textureData; + textureData.resize(width*height*4); + bitmapFile->read(&textureData[0], width*height*4); + bitmapFile->close(); + + std::string textureName = name; + Ogre::Image image; + image.loadDynamicImage(&textureData[0], width, height, Ogre::PF_BYTE_RGBA); + Ogre::TexturePtr texture = Ogre::TextureManager::getSingleton().createManual(textureName, + Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, + Ogre::TEX_TYPE_2D, + width, height, 0, Ogre::PF_BYTE_RGBA); + texture->loadImage(image); + + // Register the font with MyGUI + MyGUI::ResourceManualFont* font = static_cast( + MyGUI::FactoryManager::getInstance().createObject("Resource", "ResourceManualFont")); + // We need to emulate loading from XML because the data members are private as of mygui 3.2.0 + MyGUI::xml::Document xmlDocument; + MyGUI::xml::ElementPtr root = xmlDocument.createRoot("ResourceManualFont"); + + if (name.size() >= 5 && Misc::StringUtils::ciEqual(name.substr(0, 5), "magic")) + root->addAttribute("name", "Magic Cards"); + else if (name.size() >= 7 && Misc::StringUtils::ciEqual(name.substr(0, 7), "century")) + root->addAttribute("name", "Century Gothic"); + else if (name.size() >= 7 && Misc::StringUtils::ciEqual(name.substr(0, 7), "daedric")) + root->addAttribute("name", "Daedric"); + else + return; // no point in loading it, since there is no way of using additional fonts + + MyGUI::xml::ElementPtr defaultHeight = root->createChild("Property"); + defaultHeight->addAttribute("key", "DefaultHeight"); + defaultHeight->addAttribute("value", fontSize); + MyGUI::xml::ElementPtr source = root->createChild("Property"); + source->addAttribute("key", "Source"); + source->addAttribute("value", std::string(textureName)); + MyGUI::xml::ElementPtr codes = root->createChild("Codes"); + + for(int i = 0; i < 256; i++) + { + int x1 = data[i].top_left.x*width; + int y1 = data[i].top_left.y*height; + int w = data[i].top_right.x*width - x1; + int h = data[i].bottom_left.y*height - y1; + + ToUTF8::Utf8Encoder encoder(mEncoding); + unsigned long unicodeVal = utf8ToUnicode(encoder.getUtf8(std::string(1, (unsigned char)(i)))); + + MyGUI::xml::ElementPtr code = codes->createChild("Code"); + code->addAttribute("index", unicodeVal); + code->addAttribute("coord", MyGUI::utility::toString(x1) + " " + + MyGUI::utility::toString(y1) + " " + + MyGUI::utility::toString(w) + " " + + MyGUI::utility::toString(h)); + code->addAttribute("advance", data[i].width); + code->addAttribute("bearing", MyGUI::utility::toString(data[i].kerning) + " " + + MyGUI::utility::toString((fontSize-data[i].ascent))); + + // ASCII vertical bar, use this as text input cursor + if (i == 124) + { + MyGUI::xml::ElementPtr cursorCode = codes->createChild("Code"); + cursorCode->addAttribute("index", MyGUI::FontCodeType::Cursor); + cursorCode->addAttribute("coord", MyGUI::utility::toString(x1) + " " + + MyGUI::utility::toString(y1) + " " + + MyGUI::utility::toString(w) + " " + + MyGUI::utility::toString(h)); + cursorCode->addAttribute("advance", data[i].width); + cursorCode->addAttribute("bearing", MyGUI::utility::toString(data[i].kerning) + " " + + MyGUI::utility::toString((fontSize-data[i].ascent))); + } + } + + // These are required as well, but the fonts don't provide them + for (int i=0; i<3; ++i) + { + MyGUI::FontCodeType::Enum type; + if(i == 0) + type = MyGUI::FontCodeType::Selected; + else if (i == 1) + type = MyGUI::FontCodeType::SelectedBack; + else if (i == 2) + type = MyGUI::FontCodeType::NotDefined; + + MyGUI::xml::ElementPtr cursorCode = codes->createChild("Code"); + cursorCode->addAttribute("index", type); + cursorCode->addAttribute("coord", "0 0 0 0"); + cursorCode->addAttribute("advance", "0"); + cursorCode->addAttribute("bearing", "0 0"); + + } + + font->deserialization(root, MyGUI::Version(3,2,0)); + + MyGUI::ResourceManager::getInstance().addResource(font); + } + +} diff --git a/apps/openmw/mwgui/fontloader.hpp b/apps/openmw/mwgui/fontloader.hpp new file mode 100644 index 000000000..7954b0875 --- /dev/null +++ b/apps/openmw/mwgui/fontloader.hpp @@ -0,0 +1,25 @@ +#ifndef MWGUI_FONTLOADER_H +#define MWGUI_FONTLOADER_H + +#include + +namespace MWGui +{ + + + /// @brief loads Morrowind's .fnt/.tex fonts for use with MyGUI and Ogre + class FontLoader + { + public: + FontLoader (ToUTF8::FromType encoding); + void loadAllFonts (); + + private: + ToUTF8::FromType mEncoding; + + void loadFont (const std::string& fileName); + }; + +} + +#endif diff --git a/apps/openmw/mwgui/formatting.cpp b/apps/openmw/mwgui/formatting.cpp index aebaf16a2..aeff573ae 100644 --- a/apps/openmw/mwgui/formatting.cpp +++ b/apps/openmw/mwgui/formatting.cpp @@ -202,14 +202,14 @@ namespace MWGui float BookTextParser::widthForCharGlyph(unsigned unicodeChar) const { - std::string fontName(mTextStyle.mFont == "Default" ? "EB Garamond" : mTextStyle.mFont); + std::string fontName(mTextStyle.mFont == "Default" ? MyGUI::FontManager::getInstance().getDefaultFont() : mTextStyle.mFont); return MyGUI::FontManager::getInstance().getByName(fontName) ->getGlyphInfo(unicodeChar)->width; } float BookTextParser::currentFontHeight() const { - std::string fontName(mTextStyle.mFont == "Default" ? "EB Garamond" : mTextStyle.mFont); + std::string fontName(mTextStyle.mFont == "Default" ? MyGUI::FontManager::getInstance().getDefaultFont() : mTextStyle.mFont); return MyGUI::FontManager::getInstance().getByName(fontName)->getDefaultHeight(); } diff --git a/apps/openmw/mwgui/journalbooks.cpp b/apps/openmw/mwgui/journalbooks.cpp index 273985e3e..dbea10e77 100644 --- a/apps/openmw/mwgui/journalbooks.cpp +++ b/apps/openmw/mwgui/journalbooks.cpp @@ -189,14 +189,14 @@ book JournalBooks::createEmptyJournalBook () { BookTypesetter::Ptr typesetter = createTypesetter (); - BookTypesetter::Style* header = typesetter->createStyle ("EB Garamond", MyGUI::Colour (0.60f, 0.00f, 0.00f)); - BookTypesetter::Style* body = typesetter->createStyle ("EB Garamond", MyGUI::Colour::Black); + BookTypesetter::Style* header = typesetter->createStyle ("", MyGUI::Colour (0.60f, 0.00f, 0.00f)); + BookTypesetter::Style* body = typesetter->createStyle ("", MyGUI::Colour::Black); typesetter->write (header, to_utf8_span ("You have no journal entries!")); typesetter->lineBreak (); typesetter->write (body, to_utf8_span ("You should have gone though the starting quest and got an initial quest.")); - BookTypesetter::Style* big = typesetter->createStyle ("EB Garamond 24", MyGUI::Colour::Black); + BookTypesetter::Style* big = typesetter->createStyle ("", MyGUI::Colour::Black); BookTypesetter::Style* test = typesetter->createStyle ("MonoFont", MyGUI::Colour::Blue); typesetter->sectionBreak (20); @@ -231,8 +231,8 @@ book JournalBooks::createJournalBook () { BookTypesetter::Ptr typesetter = createTypesetter (); - BookTypesetter::Style* header = typesetter->createStyle ("EB Garamond", MyGUI::Colour (0.60f, 0.00f, 0.00f)); - BookTypesetter::Style* body = typesetter->createStyle ("EB Garamond", MyGUI::Colour::Black); + BookTypesetter::Style* header = typesetter->createStyle ("", MyGUI::Colour (0.60f, 0.00f, 0.00f)); + BookTypesetter::Style* body = typesetter->createStyle ("", MyGUI::Colour::Black); mModel->visitJournalEntries (0, AddJournalEntry (typesetter, body, header, true)); @@ -243,8 +243,8 @@ book JournalBooks::createTopicBook (uintptr_t topicId) { BookTypesetter::Ptr typesetter = createTypesetter (); - BookTypesetter::Style* header = typesetter->createStyle ("EB Garamond", MyGUI::Colour (0.60f, 0.00f, 0.00f)); - BookTypesetter::Style* body = typesetter->createStyle ("EB Garamond", MyGUI::Colour::Black); + BookTypesetter::Style* header = typesetter->createStyle ("", MyGUI::Colour (0.60f, 0.00f, 0.00f)); + BookTypesetter::Style* body = typesetter->createStyle ("", MyGUI::Colour::Black); mModel->visitTopicName (topicId, AddTopicName (typesetter, header)); @@ -259,8 +259,8 @@ book JournalBooks::createQuestBook (uintptr_t questId) { BookTypesetter::Ptr typesetter = createTypesetter (); - BookTypesetter::Style* header = typesetter->createStyle ("EB Garamond", MyGUI::Colour (0.60f, 0.00f, 0.00f)); - BookTypesetter::Style* body = typesetter->createStyle ("EB Garamond", MyGUI::Colour::Black); + BookTypesetter::Style* header = typesetter->createStyle ("", MyGUI::Colour (0.60f, 0.00f, 0.00f)); + BookTypesetter::Style* body = typesetter->createStyle ("", MyGUI::Colour::Black); mModel->visitQuestName (questId, AddQuestName (typesetter, header)); @@ -275,7 +275,7 @@ book JournalBooks::createTopicIndexBook () typesetter->setSectionAlignment (BookTypesetter::AlignCenter); - BookTypesetter::Style* body = typesetter->createStyle ("EB Garamond", MyGUI::Colour::Black); + BookTypesetter::Style* body = typesetter->createStyle ("", MyGUI::Colour::Black); for (int i = 0; i < 26; ++i) { @@ -300,7 +300,7 @@ book JournalBooks::createTopicIndexBook () book JournalBooks::createTopicIndexBook (char character) { BookTypesetter::Ptr typesetter = BookTypesetter::create (0x7FFFFFFF, 0x7FFFFFFF); - BookTypesetter::Style* style = typesetter->createStyle ("EB Garamond", MyGUI::Colour::Black); + BookTypesetter::Style* style = typesetter->createStyle ("", MyGUI::Colour::Black); mModel->visitTopicNamesStartingWith (character, AddTopicLink (typesetter, style)); @@ -310,7 +310,7 @@ book JournalBooks::createTopicIndexBook (char character) book JournalBooks::createQuestIndexBook (bool activeOnly) { BookTypesetter::Ptr typesetter = BookTypesetter::create (0x7FFFFFFF, 0x7FFFFFFF); - BookTypesetter::Style* base = typesetter->createStyle ("EB Garamond", MyGUI::Colour::Black); + BookTypesetter::Style* base = typesetter->createStyle ("", MyGUI::Colour::Black); mModel->visitQuestNames (activeOnly, AddQuestLink (typesetter, base)); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 48c5aba6b..09ceb843d 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -42,6 +42,7 @@ #include "inventorywindow.hpp" #include "bookpage.hpp" #include "itemview.hpp" +#include "fontloader.hpp" namespace MWGui { @@ -49,7 +50,7 @@ namespace MWGui WindowManager::WindowManager( const Compiler::Extensions& extensions, int fpsLevel, OEngine::Render::OgreRenderer *ogre, const std::string& logpath, const std::string& cacheDir, bool consoleOnlyScripts, - Translation::Storage& translationDataStorage) + Translation::Storage& translationDataStorage, ToUTF8::FromType encoding) : mGuiManager(NULL) , mRendering(ogre) , mHud(NULL) @@ -109,6 +110,10 @@ namespace MWGui mGuiManager = new OEngine::GUI::MyGUIManager(mRendering->getWindow(), mRendering->getScene(), false, logpath); mGui = mGuiManager->getGui(); + // Load fonts + FontLoader fontLoader (encoding); + fontLoader.loadAllFonts(); + //Register own widgets with MyGUI MyGUI::FactoryManager::getInstance().registerFactory("Widget"); MyGUI::FactoryManager::getInstance().registerFactory("Widget"); diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 71bd2c9a7..71686d59b 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -83,7 +83,7 @@ namespace MWGui WindowManager(const Compiler::Extensions& extensions, int fpsLevel, OEngine::Render::OgreRenderer *mOgre, const std::string& logpath, const std::string& cacheDir, bool consoleOnlyScripts, - Translation::Storage& translationDataStorage); + Translation::Storage& translationDataStorage, ToUTF8::FromType encoding); virtual ~WindowManager(); /** diff --git a/components/to_utf8/gen_iconv.cpp b/components/to_utf8/gen_iconv.cpp index dea68c1fa..8198b305d 100644 --- a/components/to_utf8/gen_iconv.cpp +++ b/components/to_utf8/gen_iconv.cpp @@ -46,7 +46,7 @@ void writeMissing(bool last) int write_table(const std::string &charset, const std::string &tableName) { // Write table header - cout << "static char " << tableName << "[] =\n{\n"; + cout << "static signed char " << tableName << "[] =\n{\n"; // Open conversion system iconv_t cd = iconv_open ("UTF-8", charset.c_str()); @@ -106,6 +106,8 @@ int main() "\n"; write_table("WINDOWS-1252", "windows_1252"); + write_table("CP437", "cp437"); + // Close namespace cout << "\n}\n\n"; diff --git a/components/to_utf8/tables_gen.hpp b/components/to_utf8/tables_gen.hpp index a1d4b6d80..14e66eac1 100644 --- a/components/to_utf8/tables_gen.hpp +++ b/components/to_utf8/tables_gen.hpp @@ -790,6 +790,265 @@ static signed char windows_1252[] = 2, -61, -66, 0, 0, 0, 2, -61, -65, 0, 0, 0 }; +static signed char cp437[] = +{ + 1, 0, 0, 0, 0, 0, + 1, 1, 0, 0, 0, 0, + 1, 2, 0, 0, 0, 0, + 1, 3, 0, 0, 0, 0, + 1, 4, 0, 0, 0, 0, + 1, 5, 0, 0, 0, 0, + 1, 6, 0, 0, 0, 0, + 1, 7, 0, 0, 0, 0, + 1, 8, 0, 0, 0, 0, + 1, 9, 0, 0, 0, 0, + 1, 10, 0, 0, 0, 0, + 1, 11, 0, 0, 0, 0, + 1, 12, 0, 0, 0, 0, + 1, 13, 0, 0, 0, 0, + 1, 14, 0, 0, 0, 0, + 1, 15, 0, 0, 0, 0, + 1, 16, 0, 0, 0, 0, + 1, 17, 0, 0, 0, 0, + 1, 18, 0, 0, 0, 0, + 1, 19, 0, 0, 0, 0, + 1, 20, 0, 0, 0, 0, + 1, 21, 0, 0, 0, 0, + 1, 22, 0, 0, 0, 0, + 1, 23, 0, 0, 0, 0, + 1, 24, 0, 0, 0, 0, + 1, 25, 0, 0, 0, 0, + 1, 26, 0, 0, 0, 0, + 1, 27, 0, 0, 0, 0, + 1, 28, 0, 0, 0, 0, + 1, 29, 0, 0, 0, 0, + 1, 30, 0, 0, 0, 0, + 1, 31, 0, 0, 0, 0, + 1, 32, 0, 0, 0, 0, + 1, 33, 0, 0, 0, 0, + 1, 34, 0, 0, 0, 0, + 1, 35, 0, 0, 0, 0, + 1, 36, 0, 0, 0, 0, + 1, 37, 0, 0, 0, 0, + 1, 38, 0, 0, 0, 0, + 1, 39, 0, 0, 0, 0, + 1, 40, 0, 0, 0, 0, + 1, 41, 0, 0, 0, 0, + 1, 42, 0, 0, 0, 0, + 1, 43, 0, 0, 0, 0, + 1, 44, 0, 0, 0, 0, + 1, 45, 0, 0, 0, 0, + 1, 46, 0, 0, 0, 0, + 1, 47, 0, 0, 0, 0, + 1, 48, 0, 0, 0, 0, + 1, 49, 0, 0, 0, 0, + 1, 50, 0, 0, 0, 0, + 1, 51, 0, 0, 0, 0, + 1, 52, 0, 0, 0, 0, + 1, 53, 0, 0, 0, 0, + 1, 54, 0, 0, 0, 0, + 1, 55, 0, 0, 0, 0, + 1, 56, 0, 0, 0, 0, + 1, 57, 0, 0, 0, 0, + 1, 58, 0, 0, 0, 0, + 1, 59, 0, 0, 0, 0, + 1, 60, 0, 0, 0, 0, + 1, 61, 0, 0, 0, 0, + 1, 62, 0, 0, 0, 0, + 1, 63, 0, 0, 0, 0, + 1, 64, 0, 0, 0, 0, + 1, 65, 0, 0, 0, 0, + 1, 66, 0, 0, 0, 0, + 1, 67, 0, 0, 0, 0, + 1, 68, 0, 0, 0, 0, + 1, 69, 0, 0, 0, 0, + 1, 70, 0, 0, 0, 0, + 1, 71, 0, 0, 0, 0, + 1, 72, 0, 0, 0, 0, + 1, 73, 0, 0, 0, 0, + 1, 74, 0, 0, 0, 0, + 1, 75, 0, 0, 0, 0, + 1, 76, 0, 0, 0, 0, + 1, 77, 0, 0, 0, 0, + 1, 78, 0, 0, 0, 0, + 1, 79, 0, 0, 0, 0, + 1, 80, 0, 0, 0, 0, + 1, 81, 0, 0, 0, 0, + 1, 82, 0, 0, 0, 0, + 1, 83, 0, 0, 0, 0, + 1, 84, 0, 0, 0, 0, + 1, 85, 0, 0, 0, 0, + 1, 86, 0, 0, 0, 0, + 1, 87, 0, 0, 0, 0, + 1, 88, 0, 0, 0, 0, + 1, 89, 0, 0, 0, 0, + 1, 90, 0, 0, 0, 0, + 1, 91, 0, 0, 0, 0, + 1, 92, 0, 0, 0, 0, + 1, 93, 0, 0, 0, 0, + 1, 94, 0, 0, 0, 0, + 1, 95, 0, 0, 0, 0, + 1, 96, 0, 0, 0, 0, + 1, 97, 0, 0, 0, 0, + 1, 98, 0, 0, 0, 0, + 1, 99, 0, 0, 0, 0, + 1, 100, 0, 0, 0, 0, + 1, 101, 0, 0, 0, 0, + 1, 102, 0, 0, 0, 0, + 1, 103, 0, 0, 0, 0, + 1, 104, 0, 0, 0, 0, + 1, 105, 0, 0, 0, 0, + 1, 106, 0, 0, 0, 0, + 1, 107, 0, 0, 0, 0, + 1, 108, 0, 0, 0, 0, + 1, 109, 0, 0, 0, 0, + 1, 110, 0, 0, 0, 0, + 1, 111, 0, 0, 0, 0, + 1, 112, 0, 0, 0, 0, + 1, 113, 0, 0, 0, 0, + 1, 114, 0, 0, 0, 0, + 1, 115, 0, 0, 0, 0, + 1, 116, 0, 0, 0, 0, + 1, 117, 0, 0, 0, 0, + 1, 118, 0, 0, 0, 0, + 1, 119, 0, 0, 0, 0, + 1, 120, 0, 0, 0, 0, + 1, 121, 0, 0, 0, 0, + 1, 122, 0, 0, 0, 0, + 1, 123, 0, 0, 0, 0, + 1, 124, 0, 0, 0, 0, + 1, 125, 0, 0, 0, 0, + 1, 126, 0, 0, 0, 0, + 1, 127, 0, 0, 0, 0, + 2, -61, -121, 0, 0, 0, + 2, -61, -68, 0, 0, 0, + 2, -61, -87, 0, 0, 0, + 2, -61, -94, 0, 0, 0, + 2, -61, -92, 0, 0, 0, + 2, -61, -96, 0, 0, 0, + 2, -61, -91, 0, 0, 0, + 2, -61, -89, 0, 0, 0, + 2, -61, -86, 0, 0, 0, + 2, -61, -85, 0, 0, 0, + 2, -61, -88, 0, 0, 0, + 2, -61, -81, 0, 0, 0, + 2, -61, -82, 0, 0, 0, + 2, -61, -84, 0, 0, 0, + 2, -61, -124, 0, 0, 0, + 2, -61, -123, 0, 0, 0, + 2, -61, -119, 0, 0, 0, + 2, -61, -90, 0, 0, 0, + 2, -61, -122, 0, 0, 0, + 2, -61, -76, 0, 0, 0, + 2, -61, -74, 0, 0, 0, + 2, -61, -78, 0, 0, 0, + 2, -61, -69, 0, 0, 0, + 2, -61, -71, 0, 0, 0, + 2, -61, -65, 0, 0, 0, + 2, -61, -106, 0, 0, 0, + 2, -61, -100, 0, 0, 0, + 2, -62, -94, 0, 0, 0, + 2, -62, -93, 0, 0, 0, + 2, -62, -91, 0, 0, 0, + 3, -30, -126, -89, 0, 0, + 2, -58, -110, 0, 0, 0, + 2, -61, -95, 0, 0, 0, + 2, -61, -83, 0, 0, 0, + 2, -61, -77, 0, 0, 0, + 2, -61, -70, 0, 0, 0, + 2, -61, -79, 0, 0, 0, + 2, -61, -111, 0, 0, 0, + 2, -62, -86, 0, 0, 0, + 2, -62, -70, 0, 0, 0, + 2, -62, -65, 0, 0, 0, + 3, -30, -116, -112, 0, 0, + 2, -62, -84, 0, 0, 0, + 2, -62, -67, 0, 0, 0, + 2, -62, -68, 0, 0, 0, + 2, -62, -95, 0, 0, 0, + 2, -62, -85, 0, 0, 0, + 2, -62, -69, 0, 0, 0, + 3, -30, -106, -111, 0, 0, + 3, -30, -106, -110, 0, 0, + 3, -30, -106, -109, 0, 0, + 3, -30, -108, -126, 0, 0, + 3, -30, -108, -92, 0, 0, + 3, -30, -107, -95, 0, 0, + 3, -30, -107, -94, 0, 0, + 3, -30, -107, -106, 0, 0, + 3, -30, -107, -107, 0, 0, + 3, -30, -107, -93, 0, 0, + 3, -30, -107, -111, 0, 0, + 3, -30, -107, -105, 0, 0, + 3, -30, -107, -99, 0, 0, + 3, -30, -107, -100, 0, 0, + 3, -30, -107, -101, 0, 0, + 3, -30, -108, -112, 0, 0, + 3, -30, -108, -108, 0, 0, + 3, -30, -108, -76, 0, 0, + 3, -30, -108, -84, 0, 0, + 3, -30, -108, -100, 0, 0, + 3, -30, -108, -128, 0, 0, + 3, -30, -108, -68, 0, 0, + 3, -30, -107, -98, 0, 0, + 3, -30, -107, -97, 0, 0, + 3, -30, -107, -102, 0, 0, + 3, -30, -107, -108, 0, 0, + 3, -30, -107, -87, 0, 0, + 3, -30, -107, -90, 0, 0, + 3, -30, -107, -96, 0, 0, + 3, -30, -107, -112, 0, 0, + 3, -30, -107, -84, 0, 0, + 3, -30, -107, -89, 0, 0, + 3, -30, -107, -88, 0, 0, + 3, -30, -107, -92, 0, 0, + 3, -30, -107, -91, 0, 0, + 3, -30, -107, -103, 0, 0, + 3, -30, -107, -104, 0, 0, + 3, -30, -107, -110, 0, 0, + 3, -30, -107, -109, 0, 0, + 3, -30, -107, -85, 0, 0, + 3, -30, -107, -86, 0, 0, + 3, -30, -108, -104, 0, 0, + 3, -30, -108, -116, 0, 0, + 3, -30, -106, -120, 0, 0, + 3, -30, -106, -124, 0, 0, + 3, -30, -106, -116, 0, 0, + 3, -30, -106, -112, 0, 0, + 3, -30, -106, -128, 0, 0, + 2, -50, -79, 0, 0, 0, + 2, -61, -97, 0, 0, 0, + 2, -50, -109, 0, 0, 0, + 2, -49, -128, 0, 0, 0, + 2, -50, -93, 0, 0, 0, + 2, -49, -125, 0, 0, 0, + 2, -62, -75, 0, 0, 0, + 2, -49, -124, 0, 0, 0, + 2, -50, -90, 0, 0, 0, + 2, -50, -104, 0, 0, 0, + 2, -50, -87, 0, 0, 0, + 2, -50, -76, 0, 0, 0, + 3, -30, -120, -98, 0, 0, + 2, -49, -122, 0, 0, 0, + 2, -50, -75, 0, 0, 0, + 3, -30, -120, -87, 0, 0, + 3, -30, -119, -95, 0, 0, + 2, -62, -79, 0, 0, 0, + 3, -30, -119, -91, 0, 0, + 3, -30, -119, -92, 0, 0, + 3, -30, -116, -96, 0, 0, + 3, -30, -116, -95, 0, 0, + 2, -61, -73, 0, 0, 0, + 3, -30, -119, -120, 0, 0, + 2, -62, -80, 0, 0, 0, + 3, -30, -120, -103, 0, 0, + 2, -62, -73, 0, 0, 0, + 3, -30, -120, -102, 0, 0, + 3, -30, -127, -65, 0, 0, + 2, -62, -78, 0, 0, 0, + 3, -30, -106, -96, 0, 0, + 2, -62, -96, 0, 0, 0 +}; } diff --git a/components/to_utf8/to_utf8.cpp b/components/to_utf8/to_utf8.cpp index 1de15d79c..59a9aff80 100644 --- a/components/to_utf8/to_utf8.cpp +++ b/components/to_utf8/to_utf8.cpp @@ -63,6 +63,12 @@ Utf8Encoder::Utf8Encoder(const FromType sourceEncoding): translationArray = ToUTF8::windows_1251; break; } + case ToUTF8::CP437: + { + translationArray = ToUTF8::cp437; + break; + } + default: { assert(0); diff --git a/components/to_utf8/to_utf8.hpp b/components/to_utf8/to_utf8.hpp index 839aa36aa..3f20a51f8 100644 --- a/components/to_utf8/to_utf8.hpp +++ b/components/to_utf8/to_utf8.hpp @@ -12,8 +12,9 @@ namespace ToUTF8 { WINDOWS_1250, // Central ane Eastern European languages WINDOWS_1251, // Cyrillic languages - WINDOWS_1252 // Used by English version of Morrowind (and + WINDOWS_1252, // Used by English version of Morrowind (and // probably others) + CP437 // Used for fonts (*.fnt) if data files encoding is 1252. Otherwise, uses the same encoding as the data files. }; FromType calculateEncoding(const std::string& encodingName); diff --git a/files/mygui/core.skin b/files/mygui/core.skin index e52080fe0..ea3e2debc 100644 --- a/files/mygui/core.skin +++ b/files/mygui/core.skin @@ -2,7 +2,6 @@ - diff --git a/files/mygui/openmw_font.xml b/files/mygui/openmw_font.xml index ef4300326..726bfb281 100644 --- a/files/mygui/openmw_font.xml +++ b/files/mygui/openmw_font.xml @@ -23,56 +23,21 @@ - - - - + + + + - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/files/mygui/openmw_settings.xml b/files/mygui/openmw_settings.xml index c63f962fb..37d235968 100644 --- a/files/mygui/openmw_settings.xml +++ b/files/mygui/openmw_settings.xml @@ -1,7 +1,7 @@ - + From 10165d3c6b7f68113c38904892eb9145506f9594 Mon Sep 17 00:00:00 2001 From: Glorf Date: Sun, 9 Jun 2013 00:34:27 +0200 Subject: [PATCH 45/52] Feature #468 --- apps/opencs/CMakeLists.txt | 1 + apps/opencs/model/settings/usersettings.cpp | 56 +++++++++ apps/opencs/model/settings/usersettings.hpp | 1 + apps/opencs/view/doc/view.cpp | 8 +- .../view/settings/usersettingsdialog.cpp | 22 +++- .../view/settings/usersettingsdialog.hpp | 3 + apps/opencs/view/settings/windowpage.cpp | 114 ++++++++++++++++++ apps/opencs/view/settings/windowpage.hpp | 28 +++++ 8 files changed, 229 insertions(+), 4 deletions(-) create mode 100644 apps/opencs/view/settings/windowpage.cpp create mode 100644 apps/opencs/view/settings/windowpage.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 9787719af..158f7d7f1 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -79,6 +79,7 @@ opencs_units (view/settings abstractwidget usersettingsdialog editorpage + windowpage ) opencs_units_noqt (view/settings diff --git a/apps/opencs/model/settings/usersettings.cpp b/apps/opencs/model/settings/usersettings.cpp index aabda86b3..c7305a888 100644 --- a/apps/opencs/model/settings/usersettings.cpp +++ b/apps/opencs/model/settings/usersettings.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include @@ -135,3 +136,58 @@ void CSMSettings::UserSettings::getSettings(QTextStream &stream, SectionMap &sec } sections.insert(section, settings); } + +QString CSMSettings::UserSettings::getSettingValue(QString section, QString setting) +{ + Files::ConfigurationManager configMgr; + QString userPath = QString::fromStdString(configMgr.getUserPath().string()); + QStringList list; + + list.append(QString("opencs.cfg")); + list.append(userPath + QString("opencs.cfg")); + + + CSMSettings::SectionMap sectionMap; + + foreach (const QString &path, list) + { + qDebug() << "Loading config file:" << qPrintable(path); + QFile file(path); + + if (file.exists()) + { + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) + { + QMessageBox msgBox; + msgBox.setWindowTitle(tr("Error opening OpenCS configuration file")); + msgBox.setIcon(QMessageBox::Critical); + msgBox.setStandardButtons(QMessageBox::Ok); + msgBox.setText(QObject::tr("
Could not open %0 for reading

\ + Please make sure you have the right permissions \ + and try again.
").arg(file.fileName())); + msgBox.exec(); + return QString(); + } + + QTextStream stream(&file); + stream.setCodec(QTextCodec::codecForName("UTF-8")); + + getSettings(stream, sectionMap); + } + + file.close(); + } + + if(sectionMap.find(section) == sectionMap.end()) + return QString(); + + CSMSettings::SettingMap *settings = sectionMap.value(section); + + if(settings->find(setting) == settings->end()) + return QString(); + + CSMSettings::SettingContainer *settingContainer = settings->value(setting); + + return settingContainer->getValue(); +} + diff --git a/apps/opencs/model/settings/usersettings.hpp b/apps/opencs/model/settings/usersettings.hpp index 343702eda..4c82054db 100644 --- a/apps/opencs/model/settings/usersettings.hpp +++ b/apps/opencs/model/settings/usersettings.hpp @@ -34,6 +34,7 @@ namespace CSMSettings { QFile *openFile (const QString &); bool writeFile(QFile *file, QMap §ions); void getSettings (QTextStream &stream, SectionMap &settings); + QString getSettingValue(QString section, QString setting); private: diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 2857f4a54..1e19e6db4 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include "../../model/doc/document.hpp" #include "../world/subviews.hpp" @@ -179,7 +180,12 @@ CSVDoc::View::View (ViewManager& viewManager, CSMDoc::Document *document, int to : mViewManager (viewManager), mDocument (document), mViewIndex (totalViews-1), mViewTotal (totalViews) { - resize (300, 300); /// \todo get default size from settings and set reasonable minimal size + QString width = CSMSettings::UserSettings::instance().getSettingValue(QString("Window Size"), QString("Width")); + QString height = CSMSettings::UserSettings::instance().getSettingValue(QString("Window Size"), QString("Height")); + if(width==QString() || height==QString()) + resize(800, 600); + else + resize (width.toInt(), height.toInt()); mSubViewWindow.setDockOptions (QMainWindow::AllowNestedDocks); diff --git a/apps/opencs/view/settings/usersettingsdialog.cpp b/apps/opencs/view/settings/usersettingsdialog.cpp index 012fc0408..4474f6e46 100644 --- a/apps/opencs/view/settings/usersettingsdialog.cpp +++ b/apps/opencs/view/settings/usersettingsdialog.cpp @@ -9,13 +9,14 @@ #include #include #include +#include #include "blankpage.hpp" #include "editorpage.hpp" +#include "windowpage.hpp" #include "../../model/settings/support.hpp" #include "settingwidget.hpp" -#include CSVSettings::UserSettingsDialog::UserSettingsDialog(QMainWindow *parent) : QMainWindow (parent), mStackedWidget (0) @@ -76,9 +77,10 @@ void CSVSettings::UserSettingsDialog::buildPages() setDockOptions (QMainWindow::AllowNestedDocks); //uncomment to test with sample editor page. //createSamplePage(); - createPage("Page1"); + /*createPage("Page1"); createPage("Page2"); - createPage("Page3"); + createPage("Page3");*/ + createWindowPage(); } void CSVSettings::UserSettingsDialog::createSamplePage() @@ -95,6 +97,20 @@ void CSVSettings::UserSettingsDialog::createSamplePage() &(CSMSettings::UserSettings::instance()), SIGNAL ( signalUpdateEditorSetting (const QString &, const QString &))); } +void CSVSettings::UserSettingsDialog::createWindowPage() +{ + //add pages to stackedwidget and items to listwidget + CSVSettings::AbstractPage *page + = new CSVSettings::WindowPage(this); + + mStackedWidget->addWidget (page); + + new QListWidgetItem (page->objectName(), mListWidget); + + connect ( page, SIGNAL ( signalUpdateEditorSetting (const QString &, const QString &)), + &(CSMSettings::UserSettings::instance()), SIGNAL ( signalUpdateEditorSetting (const QString &, const QString &))); +} + void CSVSettings::UserSettingsDialog::positionWindow () { QRect scr = QApplication::desktop()->screenGeometry(); diff --git a/apps/opencs/view/settings/usersettingsdialog.hpp b/apps/opencs/view/settings/usersettingsdialog.hpp index 31d40ca01..8407493ee 100644 --- a/apps/opencs/view/settings/usersettingsdialog.hpp +++ b/apps/opencs/view/settings/usersettingsdialog.hpp @@ -45,6 +45,9 @@ namespace CSVSettings { void writeSettings(); void createSamplePage(); + //Pages + void createWindowPage(); + template void createPage (const QString &title) { diff --git a/apps/opencs/view/settings/windowpage.cpp b/apps/opencs/view/settings/windowpage.cpp new file mode 100644 index 000000000..e8677fa42 --- /dev/null +++ b/apps/opencs/view/settings/windowpage.cpp @@ -0,0 +1,114 @@ +#include "windowpage.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef Q_OS_MAC +#include +#endif + +#include "../../model/settings/usersettings.hpp" +#include "groupblock.hpp" +#include "toggleblock.hpp" + +CSVSettings::WindowPage::WindowPage(QWidget *parent): + AbstractPage("Window Size", parent) +{ + // Hacks to get the stylesheet look properly +#ifdef Q_OS_MAC + QPlastiqueStyle *style = new QPlastiqueStyle; + //profilesComboBox->setStyle(style); +#endif + + setupUi(); +} + +void CSVSettings::WindowPage::setupUi() +{ + GroupBlockDef customWindowSize (QString ("Custom Window Size")); + GroupBlockDef definedWindowSize (QString ("Pre-Defined Window Size")); + GroupBlockDef windowSizeToggle (QString ("Window Size")); + CustomBlockDef windowSize (QString ("Window Size")); + + + /////////////////////////////// + //custom window size properties + /////////////////////////////// + + //custom width + SettingsItemDef *widthItem = new SettingsItemDef ("Width", "640"); + widthItem->widget = WidgetDef (Widget_LineEdit); + widthItem->widget.widgetWidth = 45; + + //custom height + SettingsItemDef *heightItem = new SettingsItemDef ("Height", "480"); + heightItem->widget = WidgetDef (Widget_LineEdit); + heightItem->widget.widgetWidth = 45; + heightItem->widget.caption = "x"; + + customWindowSize.properties << widthItem << heightItem; + customWindowSize.widgetOrientation = Orient_Horizontal; + customWindowSize.isVisible = false; + + + //pre-defined + SettingsItemDef *widthByHeightItem = new SettingsItemDef ("Window Size", "640x480"); + WidgetDef widthByHeightWidget = WidgetDef (Widget_ComboBox); + widthByHeightWidget.widgetWidth = 90; + *(widthByHeightItem->valueList) << "640x480" << "800x600" << "1024x768" << "1440x900"; + + QStringList *widthProxy = new QStringList; + QStringList *heightProxy = new QStringList; + + (*widthProxy) << "Width" << "640" << "800" << "1024" << "1440"; + (*heightProxy) << "Height" << "480" << "600" << "768" << "900"; + + *(widthByHeightItem->proxyList) << widthProxy << heightProxy; + + widthByHeightItem->widget = widthByHeightWidget; + + definedWindowSize.properties << widthByHeightItem; + definedWindowSize.isProxy = true; + definedWindowSize.isVisible = false; + + // window size toggle + windowSizeToggle.captions << "Pre-Defined" << "Custom"; + windowSizeToggle.widgetOrientation = Orient_Vertical; + windowSizeToggle.isVisible = false; + + //define a widget for each group in the toggle + for (int i = 0; i < 2; i++) + windowSizeToggle.widgets << new WidgetDef (Widget_RadioButton); + + windowSizeToggle.widgets.at(0)->isDefault = false; + + windowSize.blockDefList << &windowSizeToggle << &definedWindowSize << &customWindowSize; + windowSize.defaultValue = "Custom"; + + QGridLayout *pageLayout = new QGridLayout(this); + + setLayout (pageLayout); + + mAbstractBlocks << buildBlock (windowSize); + + foreach (AbstractBlock *block, mAbstractBlocks) + { + connect (block, SIGNAL (signalUpdateSetting (const QString &, const QString &)), + this, SIGNAL (signalUpdateEditorSetting (const QString &, const QString &)) ); + } +} + +void CSVSettings::WindowPage::initializeWidgets (const CSMSettings::SettingMap &settings) +{ + //iterate each item in each blocks in this section + //validate the corresponding setting against the defined valuelist if any. + for (AbstractBlockList::Iterator it_block = mAbstractBlocks.begin(); + it_block != mAbstractBlocks.end(); ++it_block) + (*it_block)->updateSettings (settings); +} diff --git a/apps/opencs/view/settings/windowpage.hpp b/apps/opencs/view/settings/windowpage.hpp new file mode 100644 index 000000000..7978263fc --- /dev/null +++ b/apps/opencs/view/settings/windowpage.hpp @@ -0,0 +1,28 @@ +#ifndef WINDOWPAGE_H +#define WINDOWPAGE_H + +#include "abstractpage.hpp" + +class QGroupBox; + +namespace CSVSettings { + + class UserSettings; + class AbstractBlock; + + class WindowPage : public AbstractPage + { + Q_OBJECT + + public: + + WindowPage(QWidget *parent = 0); + + void setupUi(); + void initializeWidgets (const CSMSettings::SettingMap &settings); + + signals: + void signalUpdateEditorSetting (const QString &settingName, const QString &settingValue); + }; +} +#endif //WINDOWPAGE_H From d13430e2b874512b87cd556ef9915e1d9b4c57ec Mon Sep 17 00:00:00 2001 From: Nikolay Kasyanov Date: Sun, 9 Jun 2013 20:59:31 +0400 Subject: [PATCH 46/52] Fix for CMake > 2.8.9 on OS X --- CMakeLists.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7ee938206..04ff2fe17 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,6 +4,10 @@ if (APPLE) set(APP_BUNDLE_NAME "${CMAKE_PROJECT_NAME}.app") set(APP_BUNDLE_DIR "${OpenMW_BINARY_DIR}/${APP_BUNDLE_NAME}") + + set(CMAKE_EXE_LINKER_FLAGS "-F /Library/Frameworks") + set(CMAKE_SHARED_LINKER_FLAGS "-F /Library/Frameworks") + set(CMAKE_MODULE_LINKER_FLAGS "-F /Library/Frameworks") endif (APPLE) # Macros From a3b2a76e608f8765658475a4283b63c73aac2e94 Mon Sep 17 00:00:00 2001 From: fstp Date: Sun, 9 Jun 2013 23:08:57 +0200 Subject: [PATCH 47/52] Added virtual destructors to classes LocalMapBase and EffectEditorBase. --- apps/openmw/mwgui/mapwindow.cpp | 4 ++++ apps/openmw/mwgui/mapwindow.hpp | 1 + apps/openmw/mwgui/spellcreationdialog.cpp | 4 ++++ apps/openmw/mwgui/spellcreationdialog.hpp | 2 +- 4 files changed, 10 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index 4a78238ce..7098853af 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -34,6 +34,10 @@ namespace MWGui { } + LocalMapBase::~LocalMapBase() + { + } + void LocalMapBase::init(MyGUI::ScrollView* widget, MyGUI::ImageBox* compass, OEngine::GUI::Layout* layout, bool mapDragAndDrop) { mLocalMap = widget; diff --git a/apps/openmw/mwgui/mapwindow.hpp b/apps/openmw/mwgui/mapwindow.hpp index 18c81a060..3aefc398c 100644 --- a/apps/openmw/mwgui/mapwindow.hpp +++ b/apps/openmw/mwgui/mapwindow.hpp @@ -14,6 +14,7 @@ namespace MWGui { public: LocalMapBase(); + virtual ~LocalMapBase(); void init(MyGUI::ScrollView* widget, MyGUI::ImageBox* compass, OEngine::GUI::Layout* layout, bool mapDragAndDrop=false); void setCellPrefix(const std::string& prefix); diff --git a/apps/openmw/mwgui/spellcreationdialog.cpp b/apps/openmw/mwgui/spellcreationdialog.cpp index 45cf1b0aa..c4c1be711 100644 --- a/apps/openmw/mwgui/spellcreationdialog.cpp +++ b/apps/openmw/mwgui/spellcreationdialog.cpp @@ -416,6 +416,10 @@ namespace MWGui mAddEffectDialog.setVisible (false); } + EffectEditorBase::~EffectEditorBase() + { + } + void EffectEditorBase::startEditing () { // get the list of magic effects that are known to the player diff --git a/apps/openmw/mwgui/spellcreationdialog.hpp b/apps/openmw/mwgui/spellcreationdialog.hpp index 5ad306fbe..61b888491 100644 --- a/apps/openmw/mwgui/spellcreationdialog.hpp +++ b/apps/openmw/mwgui/spellcreationdialog.hpp @@ -84,7 +84,7 @@ namespace MWGui { public: EffectEditorBase(); - + virtual ~EffectEditorBase(); protected: std::map mButtonMapping; // maps button ID to effect ID From 9d6d200d228e2f03cecc1264f8333442eb6c2c93 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 10 Jun 2013 10:25:02 +0200 Subject: [PATCH 48/52] updated credits file --- credits.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/credits.txt b/credits.txt index 390a2d721..630f6ff39 100644 --- a/credits.txt +++ b/credits.txt @@ -32,6 +32,7 @@ Jacob Essex (Yacoby) Jannik Heller (scrawl) Jason Hooks (jhooks) Joel Graff (graffy) +John Blomberg (fstp) Jordan Milne Julien Voisin (jvoisin/ap0) Karl-Felix Glatzer (k1ll) From 98e5cb6d7b6b33144bec9649e2f92ec4e570474d Mon Sep 17 00:00:00 2001 From: fstp Date: Mon, 10 Jun 2013 15:10:39 +0200 Subject: [PATCH 49/52] Added ifdef to keep backward compatibility with the FFmpeg library. --- apps/openmw/mwrender/videoplayer.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index 87ae8175d..1b5eddc21 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -32,9 +32,16 @@ namespace MWRender extern "C" { -#include -#include -#include + #include + #include + #include + + // From libavformat version 55.0.100 and onward the declaration of av_gettime() is removed from libavformat/avformat.h and moved + // to libavutil/time.h + // https://github.com/FFmpeg/FFmpeg/commit/06a83505992d5f49846c18507a6c3eb8a47c650e + #if AV_VERSION_INT(55, 0, 100) <= AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, LIBAVFORMAT_VERSION_MINOR, LIBAVFORMAT_VERSION_MICRO) + #include + #endif } #define MAX_AUDIOQ_SIZE (5 * 16 * 1024) From fc0f04324c4b7ee26355efbd8d9191bd920023b0 Mon Sep 17 00:00:00 2001 From: darkf Date: Tue, 11 Jun 2013 20:56:40 -0700 Subject: [PATCH 50/52] Remove some superfluous mSkyManager NULL checks --- apps/openmw/mwrender/renderingmanager.cpp | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index a5dc8ec68..34a792435 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -401,29 +401,24 @@ void RenderingManager::setWaterHeight(const float height) void RenderingManager::skyEnable () { - if(mSkyManager) mSkyManager->enable(); - mOcclusionQuery->setSunNode(mSkyManager->getSunNode()); } void RenderingManager::skyDisable () { - if(mSkyManager) - mSkyManager->disable(); + mSkyManager->disable(); } void RenderingManager::skySetHour (double hour) { - if(mSkyManager) - mSkyManager->setHour(hour); + mSkyManager->setHour(hour); } void RenderingManager::skySetDate (int day, int month) { - if(mSkyManager) - mSkyManager->setDate(day, month); + mSkyManager->setDate(day, month); } int RenderingManager::skyGetMasserPhase() const @@ -438,8 +433,7 @@ int RenderingManager::skyGetSecundaPhase() const } void RenderingManager::skySetMoonColour (bool red){ - if(mSkyManager) - mSkyManager->setMoonColour(red); + mSkyManager->setMoonColour(red); } bool RenderingManager::toggleRenderMode(int mode) From 2fd4d71774e25703c6c4e3c4b7b952297ba3e390 Mon Sep 17 00:00:00 2001 From: Rohit Nirmal Date: Tue, 11 Jun 2013 23:00:12 -0500 Subject: [PATCH 51/52] trim whitespace from key and value while reading settings file - stops ugly buildup in settings.cfg, and correctly reads settings from it. --- apps/launcher/settings/settingsbase.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/launcher/settings/settingsbase.hpp b/apps/launcher/settings/settingsbase.hpp index 21029b3ad..8320d56a1 100644 --- a/apps/launcher/settings/settingsbase.hpp +++ b/apps/launcher/settings/settingsbase.hpp @@ -66,8 +66,8 @@ public: if (keyRe.indexIn(line) != -1) { - QString key = keyRe.cap(1); - QString value = keyRe.cap(2); + QString key = keyRe.cap(1).trimmed(); + QString value = keyRe.cap(2).trimmed(); if (!sectionPrefix.isEmpty()) key.prepend(sectionPrefix); From 548f4d683f0105ce4d2dd85382350108f275706d Mon Sep 17 00:00:00 2001 From: Glorf Date: Wed, 12 Jun 2013 12:36:35 +0200 Subject: [PATCH 52/52] Globalization of user settings --- apps/opencs/editor.cpp | 11 ++++ apps/opencs/editor.hpp | 2 + apps/opencs/model/settings/usersettings.cpp | 54 +++++++++++++------ apps/opencs/model/settings/usersettings.hpp | 28 +++++----- .../view/settings/usersettingsdialog.cpp | 46 ++-------------- .../view/settings/usersettingsdialog.hpp | 2 - 6 files changed, 70 insertions(+), 73 deletions(-) diff --git a/apps/opencs/editor.cpp b/apps/opencs/editor.cpp index 8dc5366a9..991d59537 100644 --- a/apps/opencs/editor.cpp +++ b/apps/opencs/editor.cpp @@ -61,6 +61,17 @@ void CS::Editor::setupDataFiles() QString path = QString::fromStdString(iter->string()); mFileDialog.addFiles(path); } + + //Settings setup + QStringList settingFiles; + QString userPath = QString::fromStdString(mCfgMgr.getUserPath().string()); + + settingFiles.append(QString("opencs.cfg")); + settingFiles.append(userPath + QString("opencs.cfg")); + + mUserSettings.setSettingsFiles(settingFiles); + mUserSettings.readSettings(); + } void CS::Editor::createDocument() diff --git a/apps/opencs/editor.hpp b/apps/opencs/editor.hpp index 1c4bcb1ee..380e434c2 100644 --- a/apps/opencs/editor.hpp +++ b/apps/opencs/editor.hpp @@ -10,6 +10,7 @@ #include "view/doc/viewmanager.hpp" #include "view/doc/startup.hpp" #include "view/doc/filedialog.hpp" +#include "model/settings/usersettings.hpp" namespace CS { @@ -17,6 +18,7 @@ namespace CS { Q_OBJECT + CSMSettings::UserSettings mUserSettings; CSMDoc::DocumentManager mDocumentManager; CSVDoc::ViewManager mViewManager; CSVDoc::StartupDialogue mStartup; diff --git a/apps/opencs/model/settings/usersettings.cpp b/apps/opencs/model/settings/usersettings.cpp index c7305a888..79de124c2 100644 --- a/apps/opencs/model/settings/usersettings.cpp +++ b/apps/opencs/model/settings/usersettings.cpp @@ -30,17 +30,25 @@ namespace boost } /* namespace boost */ #endif /* (BOOST_VERSION <= 104600) */ +CSMSettings::UserSettings *CSMSettings::UserSettings::mUserSettingsInstance = 0; CSMSettings::UserSettings::UserSettings() { + assert(!mUserSettingsInstance); mUserSettingsInstance = this; } CSMSettings::UserSettings::~UserSettings() { + mUserSettingsInstance = 0; } -QFile *CSMSettings::UserSettings::openFile (const QString &filename) +CSMSettings::SectionMap CSMSettings::UserSettings::getSettingsMap() const +{ + return mSectionMap; +} + +QFile *CSMSettings::UserSettings::openFile (const QString &filename) const { QFile *file = new QFile(filename); @@ -64,7 +72,7 @@ QFile *CSMSettings::UserSettings::openFile (const QString &filename) return file; } -bool CSMSettings::UserSettings::writeFile(QFile *file, QMap &settings) +bool CSMSettings::UserSettings::writeFile(QFile *file, QMap &settings) const { if (!file) return false; @@ -89,7 +97,7 @@ bool CSMSettings::UserSettings::writeFile(QFile *file, QMap").arg(file.fileName())); msgBox.exec(); - return QString(); + return; } QTextStream stream(&file); stream.setCodec(QTextCodec::codecForName("UTF-8")); + - getSettings(stream, sectionMap); + getSettings(stream, mSectionMap); } file.close(); } +} - if(sectionMap.find(section) == sectionMap.end()) +void CSMSettings::UserSettings::setSettingsFiles(QStringList files) +{ + mSettingsFiles = files; +} + +QStringList CSMSettings::UserSettings::getSettingsFiles () const +{ + return mSettingsFiles; +} + +QString CSMSettings::UserSettings::getSettingValue(QString section, QString setting) const +{ + if(mSectionMap.find(section) == mSectionMap.end()) return QString(); - CSMSettings::SettingMap *settings = sectionMap.value(section); + CSMSettings::SettingMap *settings = mSectionMap.value(section); if(settings->find(setting) == settings->end()) return QString(); @@ -191,3 +205,9 @@ QString CSMSettings::UserSettings::getSettingValue(QString section, QString sett return settingContainer->getValue(); } +const CSMSettings::UserSettings& CSMSettings::UserSettings::instance() +{ + assert(mUserSettingsInstance); + return *mUserSettingsInstance; +} + diff --git a/apps/opencs/model/settings/usersettings.hpp b/apps/opencs/model/settings/usersettings.hpp index 4c82054db..6a2628fd1 100644 --- a/apps/opencs/model/settings/usersettings.hpp +++ b/apps/opencs/model/settings/usersettings.hpp @@ -24,23 +24,27 @@ namespace CSMSettings { public: - static UserSettings &instance() - { - static UserSettings instance; + UserSettings(); + ~UserSettings(); + + static const UserSettings& instance(); - return instance; - } + void readSettings(); + void setSettingsFiles(QStringList files); - QFile *openFile (const QString &); - bool writeFile(QFile *file, QMap §ions); - void getSettings (QTextStream &stream, SectionMap &settings); - QString getSettingValue(QString section, QString setting); + QFile *openFile (const QString &) const; + bool writeFile(QFile *file, QMap §ions) const; + void getSettings (QTextStream &stream, SectionMap &settings) const; + QStringList getSettingsFiles () const; + CSMSettings::SectionMap getSettingsMap() const; + QString getSettingValue(QString section, QString setting) const; private: - UserSettings *mUserSettingsInstance; - UserSettings(); - ~UserSettings(); + static UserSettings *mUserSettingsInstance; + + CSMSettings::SectionMap mSectionMap; + QStringList mSettingsFiles; UserSettings (UserSettings const &); //not implemented void operator= (UserSettings const &); //not implemented diff --git a/apps/opencs/view/settings/usersettingsdialog.cpp b/apps/opencs/view/settings/usersettingsdialog.cpp index 4474f6e46..d657ba06b 100644 --- a/apps/opencs/view/settings/usersettingsdialog.cpp +++ b/apps/opencs/view/settings/usersettingsdialog.cpp @@ -23,7 +23,7 @@ CSVSettings::UserSettingsDialog::UserSettingsDialog(QMainWindow *parent) : { setWindowTitle(QString::fromUtf8 ("User Settings")); buildPages(); - setWidgetStates (loadSettings()); + setWidgetStates (CSMSettings::UserSettings::instance().getSettingsMap()); positionWindow (); connect (mListWidget, @@ -119,46 +119,6 @@ void CSVSettings::UserSettingsDialog::positionWindow () } -CSMSettings::SectionMap CSVSettings::UserSettingsDialog::loadSettings () -{ - QString userPath = QString::fromStdString(mCfgMgr.getUserPath().string()); - - mPaths.append(QString("opencs.cfg")); - mPaths.append(userPath + QString("opencs.cfg")); - - CSMSettings::SectionMap settingsMap; - - foreach (const QString &path, mPaths) - { - qDebug() << "Loading config file:" << qPrintable(path); - QFile file(path); - - if (file.exists()) - { - if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) - { - QMessageBox msgBox; - msgBox.setWindowTitle(tr("Error opening OpenCS configuration file")); - msgBox.setIcon(QMessageBox::Critical); - msgBox.setStandardButtons(QMessageBox::Ok); - msgBox.setText(QObject::tr("
Could not open %0 for reading

\ - Please make sure you have the right permissions \ - and try again.
").arg(file.fileName())); - msgBox.exec(); - return settingsMap; - } - - QTextStream stream(&file); - stream.setCodec(QTextCodec::codecForName("UTF-8")); - - CSMSettings::UserSettings::instance().getSettings(stream, settingsMap); - } - - file.close(); - } - - return settingsMap; -} void CSVSettings::UserSettingsDialog::writeSettings() { @@ -170,7 +130,9 @@ void CSVSettings::UserSettingsDialog::writeSettings() settings [page->objectName()] = page->getSettings(); } - CSMSettings::UserSettings::instance().writeFile(CSMSettings::UserSettings::instance().openFile(mPaths.back()), settings); + QStringList paths = CSMSettings::UserSettings::instance().getSettingsFiles(); + + CSMSettings::UserSettings::instance().writeFile(CSMSettings::UserSettings::instance().openFile(paths.back()), settings); } diff --git a/apps/opencs/view/settings/usersettingsdialog.hpp b/apps/opencs/view/settings/usersettingsdialog.hpp index 8407493ee..71a4cb2f8 100644 --- a/apps/opencs/view/settings/usersettingsdialog.hpp +++ b/apps/opencs/view/settings/usersettingsdialog.hpp @@ -25,7 +25,6 @@ namespace CSVSettings { { Q_OBJECT - QStringList mPaths; QListWidget *mListWidget; QStackedWidget *mStackedWidget; Files::ConfigurationManager mCfgMgr; @@ -41,7 +40,6 @@ namespace CSVSettings { void setWidgetStates (CSMSettings::SectionMap settingsMap); void buildPages(); void positionWindow (); - CSMSettings::SectionMap loadSettings(); void writeSettings(); void createSamplePage();