From 32e90bb73321602f3c00347d53a822beec248637 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 23 May 2013 17:27:44 +0200 Subject: [PATCH 01/25] 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/25] 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 48386789446ba0f09ce055b0edd60b3f3bd0349e Mon Sep 17 00:00:00 2001 From: Torben Carrington Date: Wed, 29 May 2013 15:59:23 -0700 Subject: [PATCH 03/25] 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 | 140 +++++++++++++----------- apps/openmw/mwmechanics/pathfinding.hpp | 25 +++-- 2 files changed, 87 insertions(+), 78 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; - };*/ +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) {} +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) { 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 04/25] 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 05/25] 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; + + return closestIndex; } - 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; - }; - - - 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 06/25] 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 07/25] 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 a4caec56cf0503196a5d30214ab846df160f79c9 Mon Sep 17 00:00:00 2001 From: Torben Carrington Date: Fri, 31 May 2013 17:01:42 -0700 Subject: [PATCH 08/25] 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 09/25] 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 | 288 ++++++------ apps/openmw/mwmechanics/aitravel.cpp | 149 ++++--- apps/openmw/mwmechanics/aiwander.cpp | 570 ++++++++++++------------ apps/openmw/mwmechanics/pathfinding.cpp | 2 +- 4 files changed, 515 insertions(+), 494 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; - - // 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 + AiEscort::AiEscort(const std::string &actorId, int duration, float x, float y, float z) + : mActorId(actorId), mX(x), mY(y), mZ(z), mDuration(duration) { - 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; - - // 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); - } -} - - -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) - { - MWWorld::TimeStamp current = MWBase::Environment::get().getWorld()->getTimeStamp(); - unsigned int currentSecond = ((current.getHour() - int(current.getHour())) * 100); - if(currentSecond - mStartingSecond >= mDuration) - return true; - } - - 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); - - - 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)) - { - 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)) - { - 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()) - { - 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, 1); - } - - 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]; - - 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]); - - 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; + + // 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 + + 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) { - // 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; + 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; + + else + { + MWWorld::TimeStamp startTime = MWBase::Environment::get().getWorld()->getTimeStamp(); + mStartingSecond = ((startTime.getHour() - int(startTime.getHour())) * 100); + } } - return false; -} - -int MWMechanics::AiEscort::getTypeId() const -{ - return 2; + + AiEscort *MWMechanics::AiEscort::clone() const + { + return new AiEscort(*this); + } + + 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.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.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()) + { + 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); + } + + 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]; + + for (short counter = 0; counter < 3; counter++) + differenceBetween[counter] = (leaderPos[counter] - followerPos[counter]); + + 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; + } + + return false; + } + + int 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() +namespace MWMechanics { -} + AiTravel::AiTravel(float x, float y, float z) + : mX(x),mY(y),mZ(z),mPathFinder() + { + } -MWMechanics::AiTravel *MWMechanics::AiTravel::clone() const -{ - return new AiTravel(*this); -} + AiTravel *MWMechanics::AiTravel::clone() const + { + return new AiTravel(*this); + } -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(); + 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) + { + 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.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()) + { + 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); + } + + if(mPathFinder.checkPathCompleted(pos.pos[0], pos.pos[1], pos.pos[2])) { MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0; return true; } + + 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; } - if(actor.getCell()->mCell->mData.mY != player.getCell()->mCell->mData.mY) + + int AiTravel::getTypeId() const { - 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; - } + return 1; } - - 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()) - { - 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, 1); - } - - if(mPathFinder.checkPathCompleted(pos.pos[0],pos.pos[1],pos.pos[2])) - { - MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0; - return true; - } - - 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; - } - - 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; -} - -MWMechanics::AiPackage * MWMechanics::AiWander::clone() const -{ - return new AiWander(*this); -} - -bool MWMechanics::AiWander::execute (const MWWorld::Ptr& actor) -{ - 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) + for(unsigned short counter = 0; counter < mIdle.size(); counter++) { - if(!mRepeat) - { - stopWalking(actor); - return true; - } - else - mStartTime = currentTime; + if(mIdle[counter] >= 127 || mIdle[counter] < 0) + mIdle[counter] = 0; } - else if(int(currentTime.getHour()) == 0 && currentTime.getDay() != mStartTime.getDay()) - { - if(!mRepeat) - { - stopWalking(actor); - 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(!mPathgrid) - mDistance = 0; - else if(mPathgrid->mPoints.empty()) + if(mDistance < 0) mDistance = 0; + if(mDuration < 0) + mDuration = 0; + if(mDuration == 0) + mTimeOfDay = 0; - if(mDistance) - { - 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); - } - - 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; - - 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)) - { - 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)) - { - 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) - { + srand(time(NULL)); + mStartTime = MWBase::Environment::get().getWorld()->getTimeStamp(); mPlayedIdle = 0; - unsigned short idleRoll = 0; + mPathgrid = NULL; + mIdleChanceMultiplier = + MWBase::Environment::get().getWorld()->getStore().get().find("fIdleChanceMultiplier")->getFloat(); - for(unsigned int counter = 1; counter < mIdle.size(); counter++) + mStoredAvailableNodes = false; + mChooseAction = true; + mIdleNow = false; + mMoveNow = false; + mWalking = false; + } + + AiPackage * MWMechanics::AiWander::clone() const + { + return new AiWander(*this); + } + + bool AiWander::execute (const MWWorld::Ptr& actor) + { + if(mDuration) { - unsigned short idleChance = mIdleChanceMultiplier * mIdle[counter]; - unsigned short randSelect = (int)(rand() / ((double)RAND_MAX + 1) * int(100 / mIdleChanceMultiplier)); - if(randSelect < idleChance && randSelect > idleRoll) + // End package if duration is complete or mid-night hits: + MWWorld::TimeStamp currentTime = MWBase::Environment::get().getWorld()->getTimeStamp(); + if(currentTime.getHour() >= mStartTime.getHour() + mDuration) { - mPlayedIdle = counter; - idleRoll = randSelect; + if(!mRepeat) + { + stopWalking(actor); + return true; + } + else + mStartTime = currentTime; + } + else if(int(currentTime.getHour()) == 0 && currentTime.getDay() != mStartTime.getDay()) + { + if(!mRepeat) + { + stopWalking(actor); + return true; + } + else + mStartTime = currentTime; } } - 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; - } - } + ESM::Position pos = actor.getRefData().getPosition(); - if(mIdleNow) - { - if(!checkIdle(actor, mPlayedIdle + 1)) + 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(!mPathgrid) + mDistance = 0; + else if(mPathgrid->mPoints.empty()) + mDistance = 0; + + if(mDistance) + { + 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); + } + + 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; + + 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)) + { + 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)) + { + 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; - mIdleNow = false; - mChooseAction = true; - } - } + unsigned short idleRoll = 0; - if(mMoveNow && mDistance) - { - 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 start; - start.mX = pos.pos[0]; - start.mY = pos.pos[1]; - start.mZ = pos.pos[2]; - - mPathFinder.buildPath(start, dest, mPathgrid, mXCell, mYCell, 0); - - if(mPathFinder.isPathConstructed()) + for(unsigned int counter = 1; counter < mIdle.size(); counter++) { - // 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; + 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; } - // Choose a different node and delete this one from possible nodes because it is uncreachable: else - mAllowedNodes.erase(mAllowedNodes.begin() + randNode); + { + // 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(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])) + if(mIdleNow) { - stopWalking(actor); - mMoveNow = false; - mWalking = false; - mChooseAction = true; + if(!checkIdle(actor, mPlayedIdle + 1)) + { + mPlayedIdle = 0; + mIdleNow = false; + mChooseAction = true; + } } + + if(mMoveNow && mDistance) + { + 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 start; + start.mX = pos.pos[0]; + start.mY = pos.pos[1]; + start.mZ = pos.pos[2]; + + 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; + + 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 = false; + mChooseAction = true; + } + } + + return false; } - 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 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; + int AiWander::getTypeId() const + { + return 0; + } + + void AiWander::stopWalking(const MWWorld::Ptr& actor) + { + mPathFinder.clearPath(); + MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0; + } + + 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 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 10/25] 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 11/25] 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 12/25] 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 10165d3c6b7f68113c38904892eb9145506f9594 Mon Sep 17 00:00:00 2001 From: Glorf Date: Sun, 9 Jun 2013 00:34:27 +0200 Subject: [PATCH 13/25] 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 14/25] 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 15/25] 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 4eede86ce64dbee18c54928ed9a5ad22bbc34b3e Mon Sep 17 00:00:00 2001 From: Rohit Nirmal Date: Sun, 9 Jun 2013 23:27:47 -0500 Subject: [PATCH 16/25] Moved journal open/close sound effect playback to JournalWindowImpl, and have opening sound play only if the player has the journal. --- apps/openmw/mwgui/journalwindow.cpp | 10 +++++++--- apps/openmw/mwinput/inputmanagerimp.cpp | 3 +-- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwgui/journalwindow.cpp b/apps/openmw/mwgui/journalwindow.cpp index 5b84c99a5..e7cb9916f 100644 --- a/apps/openmw/mwgui/journalwindow.cpp +++ b/apps/openmw/mwgui/journalwindow.cpp @@ -183,7 +183,12 @@ namespace if (!MWBase::Environment::get().getWindowManager ()->getJournalAllowed ()) { MWBase::Environment::get().getWindowManager()->popGuiMode (); - } + } + else + { + // play opening sound only if the player has the journal + MWBase::Environment::get().getSoundManager()->playSound ("book open", 1.0, 1.0); + } mModel->load (); setBookMode (); @@ -213,6 +218,7 @@ namespace void close() { + MWBase::Environment::get().getSoundManager()->playSound ("book close", 1.0, 1.0); mModel->unload (); getPage (LeftBookPage)->showPage (Book (), 0); @@ -432,8 +438,6 @@ namespace void notifyClose(MyGUI::Widget* _sender) { - MWBase::Environment::get().getSoundManager()->playSound ("book close", 1.0, 1.0); - MWBase::Environment::get().getWindowManager ()->popGuiMode (); } diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 00c520de9..e9a0e5089 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -658,12 +658,11 @@ namespace MWInput if(gameMode) { - MWBase::Environment::get().getSoundManager()->playSound ("book open", 1.0, 1.0); mWindows.pushGuiMode(MWGui::GM_Journal); } else if(mWindows.getMode() == MWGui::GM_Journal) { - MWBase::Environment::get().getSoundManager()->playSound ("book close", 1.0, 1.0); + mWindows.popGuiMode(); } // .. but don't touch any other mode. From 9d6d200d228e2f03cecc1264f8333442eb6c2c93 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 10 Jun 2013 10:25:02 +0200 Subject: [PATCH 17/25] 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 18/25] 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 b5caa25e5c5b80cd3526083aeec47902995c2617 Mon Sep 17 00:00:00 2001 From: Rohit Nirmal Date: Mon, 10 Jun 2013 19:42:38 -0500 Subject: [PATCH 19/25] Just move check if player owns journal to inputmanagerimp.cpp - prevents playing sound when going to main menu. --- apps/openmw/mwgui/journalwindow.cpp | 10 +++------- apps/openmw/mwinput/inputmanagerimp.cpp | 5 +++-- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwgui/journalwindow.cpp b/apps/openmw/mwgui/journalwindow.cpp index e7cb9916f..89ee42934 100644 --- a/apps/openmw/mwgui/journalwindow.cpp +++ b/apps/openmw/mwgui/journalwindow.cpp @@ -184,11 +184,6 @@ namespace { MWBase::Environment::get().getWindowManager()->popGuiMode (); } - else - { - // play opening sound only if the player has the journal - MWBase::Environment::get().getSoundManager()->playSound ("book open", 1.0, 1.0); - } mModel->load (); setBookMode (); @@ -218,7 +213,7 @@ namespace void close() { - MWBase::Environment::get().getSoundManager()->playSound ("book close", 1.0, 1.0); + mModel->unload (); getPage (LeftBookPage)->showPage (Book (), 0); @@ -438,6 +433,7 @@ namespace void notifyClose(MyGUI::Widget* _sender) { + MWBase::Environment::get().getSoundManager()->playSound ("book close", 1.0, 1.0); MWBase::Environment::get().getWindowManager ()->popGuiMode (); } @@ -476,4 +472,4 @@ namespace MWGui::JournalWindow * MWGui::JournalWindow::create (JournalViewModel::Ptr Model) { return new JournalWindowImpl (Model); -} +} \ No newline at end of file diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index e9a0e5089..9f149ac33 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -656,13 +656,14 @@ namespace MWInput // Toggle between game mode and journal mode bool gameMode = !mWindows.isGuiMode(); - if(gameMode) + if(gameMode && MWBase::Environment::get().getWindowManager ()->getJournalAllowed()) { + MWBase::Environment::get().getSoundManager()->playSound ("book open", 1.0, 1.0); mWindows.pushGuiMode(MWGui::GM_Journal); } else if(mWindows.getMode() == MWGui::GM_Journal) { - + MWBase::Environment::get().getSoundManager()->playSound ("book close", 1.0, 1.0); mWindows.popGuiMode(); } // .. but don't touch any other mode. From fc0f04324c4b7ee26355efbd8d9191bd920023b0 Mon Sep 17 00:00:00 2001 From: darkf Date: Tue, 11 Jun 2013 20:56:40 -0700 Subject: [PATCH 20/25] 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 21/25] 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 22/25] 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(); - return instance; - } + static const UserSettings& instance(); - QFile *openFile (const QString &); - bool writeFile(QFile *file, QMap §ions); - void getSettings (QTextStream &stream, SectionMap &settings); - QString getSettingValue(QString section, QString setting); + void readSettings(); + void setSettingsFiles(QStringList files); + + 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(); From aac3ada14bb2f266a650e8e5a018c24ff8f8507e Mon Sep 17 00:00:00 2001 From: Rohit Nirmal Date: Thu, 13 Jun 2013 00:50:07 -0500 Subject: [PATCH 23/25] Use mousewheel to turn book pages. --- apps/openmw/mwgui/bookwindow.cpp | 41 +++++++++++++++---------- apps/openmw/mwgui/bookwindow.hpp | 3 +- apps/openmw/mwinput/inputmanagerimp.cpp | 10 ++++++ 3 files changed, 37 insertions(+), 17 deletions(-) diff --git a/apps/openmw/mwgui/bookwindow.cpp b/apps/openmw/mwgui/bookwindow.cpp index 3b5deb5ac..672503154 100644 --- a/apps/openmw/mwgui/bookwindow.cpp +++ b/apps/openmw/mwgui/bookwindow.cpp @@ -130,26 +130,12 @@ namespace MWGui void BookWindow::onNextPageButtonClicked (MyGUI::Widget* sender) { - if ((mCurrentPage+1)*2 < mPages.size()) - { - MWBase::Environment::get().getSoundManager()->playSound ("book page2", 1.0, 1.0); - - ++mCurrentPage; - - updatePages(); - } + nextPage(); } void BookWindow::onPrevPageButtonClicked (MyGUI::Widget* sender) { - if (mCurrentPage > 0) - { - MWBase::Environment::get().getSoundManager()->playSound ("book page", 1.0, 1.0); - - --mCurrentPage; - - updatePages(); - } + prevPage(); } void BookWindow::updatePages() @@ -194,5 +180,28 @@ namespace MWGui if (button->getAlign().isRight()) button->setPosition(button->getPosition() + MyGUI::IntPoint(diff.width,0)); } + + void BookWindow::nextPage() + { + if ((mCurrentPage+1)*2 < mPages.size()) + { + MWBase::Environment::get().getSoundManager()->playSound ("book page2", 1.0, 1.0); + + ++mCurrentPage; + + updatePages(); + } + } + void BookWindow::prevPage() + { + if (mCurrentPage > 0) + { + MWBase::Environment::get().getSoundManager()->playSound ("book page", 1.0, 1.0); + + --mCurrentPage; + + updatePages(); + } + } } diff --git a/apps/openmw/mwgui/bookwindow.hpp b/apps/openmw/mwgui/bookwindow.hpp index c6ea486d4..ef87dd9c4 100644 --- a/apps/openmw/mwgui/bookwindow.hpp +++ b/apps/openmw/mwgui/bookwindow.hpp @@ -16,7 +16,8 @@ namespace MWGui void open(MWWorld::Ptr book); void setTakeButtonShow(bool show); - + void nextPage(); + void prevPage(); void setInventoryAllowed(bool allowed); protected: diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 00c520de9..f60ec6797 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -25,6 +25,7 @@ #include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" #include "../mwbase/soundmanager.hpp" +#include "../mwgui/bookwindow.hpp" namespace MWInput { @@ -552,6 +553,15 @@ namespace MWInput if (arg.state.Z.rel) MWBase::Environment::get().getWorld()->changeVanityModeScale(arg.state.Z.rel); } + + //if the player is reading a book and flicking the mouse wheel + if (MWBase::Environment::get().getWindowManager()->getMode() == MWGui::GM_Book && arg.state.Z.rel) + { + if (arg.state.Z.rel < 0) + MWBase::Environment::get().getWindowManager()->getBookWindow()->nextPage(); + else + MWBase::Environment::get().getWindowManager()->getBookWindow()->prevPage(); + } return true; } From 9d4ecc3e7351a37141ff0597a0d1588f5e3d6057 Mon Sep 17 00:00:00 2001 From: Rohit Nirmal Date: Thu, 13 Jun 2013 00:52:26 -0500 Subject: [PATCH 24/25] replace tabs with spaces. --- apps/openmw/mwgui/bookwindow.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/bookwindow.cpp b/apps/openmw/mwgui/bookwindow.cpp index 672503154..f24922e23 100644 --- a/apps/openmw/mwgui/bookwindow.cpp +++ b/apps/openmw/mwgui/bookwindow.cpp @@ -183,7 +183,7 @@ namespace MWGui void BookWindow::nextPage() { - if ((mCurrentPage+1)*2 < mPages.size()) + if ((mCurrentPage+1)*2 < mPages.size()) { MWBase::Environment::get().getSoundManager()->playSound ("book page2", 1.0, 1.0); @@ -194,7 +194,7 @@ namespace MWGui } void BookWindow::prevPage() { - if (mCurrentPage > 0) + if (mCurrentPage > 0) { MWBase::Environment::get().getSoundManager()->playSound ("book page", 1.0, 1.0); From e5ddaaf6768095a1ce62e3029cea187c145c089e Mon Sep 17 00:00:00 2001 From: Rohit Nirmal Date: Thu, 13 Jun 2013 11:17:34 -0500 Subject: [PATCH 25/25] Fix wrong indenting from my last commits. --- apps/openmw/mwgui/journalwindow.cpp | 5 ++--- apps/openmw/mwinput/inputmanagerimp.cpp | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwgui/journalwindow.cpp b/apps/openmw/mwgui/journalwindow.cpp index 89ee42934..ab8dc1584 100644 --- a/apps/openmw/mwgui/journalwindow.cpp +++ b/apps/openmw/mwgui/journalwindow.cpp @@ -213,7 +213,6 @@ namespace void close() { - mModel->unload (); getPage (LeftBookPage)->showPage (Book (), 0); @@ -433,7 +432,7 @@ namespace void notifyClose(MyGUI::Widget* _sender) { - MWBase::Environment::get().getSoundManager()->playSound ("book close", 1.0, 1.0); + MWBase::Environment::get().getSoundManager()->playSound ("book close", 1.0, 1.0); MWBase::Environment::get().getWindowManager ()->popGuiMode (); } @@ -472,4 +471,4 @@ namespace MWGui::JournalWindow * MWGui::JournalWindow::create (JournalViewModel::Ptr Model) { return new JournalWindowImpl (Model); -} \ No newline at end of file +} diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index cb4f08b9c..1f1dc53b0 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -668,7 +668,7 @@ namespace MWInput if(gameMode && MWBase::Environment::get().getWindowManager ()->getJournalAllowed()) { - MWBase::Environment::get().getSoundManager()->playSound ("book open", 1.0, 1.0); + MWBase::Environment::get().getSoundManager()->playSound ("book open", 1.0, 1.0); mWindows.pushGuiMode(MWGui::GM_Journal); } else if(mWindows.getMode() == MWGui::GM_Journal)