From 4e7ee970504334321c15654ce2ecceddcebfe783 Mon Sep 17 00:00:00 2001 From: mrcheko Date: Mon, 14 Apr 2014 17:18:29 +0400 Subject: [PATCH 001/118] fix for windows builds --- apps/openmw/mwgui/savegamedialog.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/openmw/mwgui/savegamedialog.cpp b/apps/openmw/mwgui/savegamedialog.cpp index caa082646..3ff583264 100644 --- a/apps/openmw/mwgui/savegamedialog.cpp +++ b/apps/openmw/mwgui/savegamedialog.cpp @@ -259,7 +259,11 @@ namespace MWGui timeinfo = localtime(&time); // Use system/environment locale settings for datetime formatting +#if defined(_WIN32) || defined(__WINDOWS__) + setlocale(LC_TIME, ""); +#else std::setlocale(LC_TIME, ""); +#endif const int size=1024; char buffer[size]; From f811abb752efdd8306c081df67d92edd57d86728 Mon Sep 17 00:00:00 2001 From: mrcheko Date: Sun, 20 Apr 2014 20:35:07 +0400 Subject: [PATCH 002/118] pathgrid shortcutting extended --- apps/openmw/mwbase/world.hpp | 2 + apps/openmw/mwmechanics/aicombat.cpp | 204 ++++++++++++++++-------- apps/openmw/mwmechanics/aicombat.hpp | 5 +- apps/openmw/mwmechanics/pathfinding.cpp | 11 +- apps/openmw/mwmechanics/pathfinding.hpp | 13 +- apps/openmw/mwmechanics/steering.cpp | 3 +- apps/openmw/mwmechanics/steering.hpp | 3 + apps/openmw/mwworld/worldimp.cpp | 15 +- apps/openmw/mwworld/worldimp.hpp | 2 + 9 files changed, 181 insertions(+), 77 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index f03a9197d..98ec9cfce 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -407,6 +407,8 @@ namespace MWBase virtual bool getLOS(const MWWorld::Ptr& npc,const MWWorld::Ptr& targetNpc) = 0; ///< get Line of Sight (morrowind stupid implementation) + virtual float getDistToNearestRayHit(const Ogre::Vector3& from, const Ogre::Vector3& dir, float maxDist) = 0; + virtual void enableActorCollision(const MWWorld::Ptr& actor, bool enable) = 0; virtual int canRest() = 0; diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index fd2fa61ba..84798ca02 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -31,6 +31,40 @@ namespace //chooses an attack depending on probability to avoid uniformity void chooseBestAttack(const ESM::Weapon* weapon, MWMechanics::Movement &movement); + + float getZAngleToDir(const Ogre::Vector3& dir, float dirLen = 0.0f) + { + float len = (dirLen >= 0.0f)? dirLen : dir.length(); + return Ogre::Radian( Ogre::Math::ACos(dir.y / len) * sgn(Ogre::Math::ASin(dir.x / len)) ).valueDegrees(); + } + + const float PATHFIND_Z_REACH = 50.0f; + // distance at which actor pays more attention to decide whether to shortcut or stick to pathgrid + const float PATHFIND_CAUTION_DIST = 500.0f; + // distance after which actor (failed previously to shortcut) will try again + const float PATHFIND_SHORTCUT_RETRY_DIST = 300.0f; + + // cast up-down ray with some offset from actor position to check for pits/obstacles on the way to target; + // magnitude of pits/obstacles is defined by PATHFIND_Z_REACH + bool checkWayIsClear(const Ogre::Vector3& from, const Ogre::Vector3& to, float offset) + { + if((to - from).length() >= PATHFIND_CAUTION_DIST || abs(from.z - to.z) <= PATHFIND_Z_REACH) + { + Ogre::Vector3 dir = to - from; + dir.z = 0; + dir.normalise(); + float verticalOffset = 200; // instead of '200' here we want the height of the actor + Ogre::Vector3 _from = from + dir*offset + Ogre::Vector3::UNIT_Z * verticalOffset; + + // cast up-down ray and find height in world space of hit + float h = _from.z - MWBase::Environment::get().getWorld()->getDistToNearestRayHit(_from, -Ogre::Vector3::UNIT_Z, verticalOffset + PATHFIND_Z_REACH + 1); + + if(abs(from.z - h) <= PATHFIND_Z_REACH) + return true; + } + + return false; + } } namespace MWMechanics @@ -44,9 +78,10 @@ namespace MWMechanics mReadyToAttack(false), mStrike(false), mCombatMove(false), - mRotate(false), mMovement(), - mTargetAngle(0) + mTargetAngle(0), + mForceNoShortcut(false), + mShortcutFailPos() { } @@ -71,13 +106,12 @@ namespace MWMechanics mCombatMove = false; } } - + actor.getClass().getMovementSettings(actor) = mMovement; - if (mRotate) + if(actor.getRefData().getPosition().rot[2] != mTargetAngle) { - if (zTurn(actor, Ogre::Degree(mTargetAngle))) - mRotate = false; + zTurn(actor, Ogre::Degree(mTargetAngle)); } @@ -92,7 +126,7 @@ namespace MWMechanics } //Update with period = tReaction - + mTimerReact = 0; //actual attacking logic @@ -136,6 +170,7 @@ namespace MWMechanics actor.getClass().getCreatureStats(actor).setMovementFlag(CreatureStats::Flag_Run, true); + // Get weapon characteristics if (actor.getClass().hasInventoryStore(actor)) { MWMechanics::DrawState_ state = actor.getClass().getCreatureStats(actor).getDrawState(); @@ -166,15 +201,13 @@ namespace MWMechanics weapRange = 150; //TODO: use true attack range (the same problem in Creature::hit) } - ESM::Position pos = actor.getRefData().getPosition(); - float rangeMelee; float rangeCloseUp; bool distantCombat = false; if (weaptype==WeapType_BowAndArrow || weaptype==WeapType_Crossbow || weaptype==WeapType_Thrown) { rangeMelee = 1000; // TODO: should depend on archer skill - rangeCloseUp = 0; //doesn't needed when attacking from distance + rangeCloseUp = 0; // not needed in ranged combat distantCombat = true; } else @@ -182,23 +215,27 @@ namespace MWMechanics rangeMelee = weapRange; rangeCloseUp = 300; } + + ESM::Position pos = actor.getRefData().getPosition(); + Ogre::Vector3 vActorPos(pos.pos); + Ogre::Vector3 vTargetPos(mTarget.getRefData().getPosition().pos); + Ogre::Vector3 vDirToTarget = vTargetPos - vActorPos; + float distToTarget = vDirToTarget.length(); - Ogre::Vector3 vStart(pos.pos[0], pos.pos[1], pos.pos[2]); - ESM::Position targetPos = mTarget.getRefData().getPosition(); - Ogre::Vector3 vDest(targetPos.pos[0], targetPos.pos[1], targetPos.pos[2]); - Ogre::Vector3 vDir = vDest - vStart; - float distBetween = vDir.length(); + bool isStuck = false; + float speed = 0.0f; + if(mMovement.mPosition[1] && (Ogre::Vector3(mLastPos.pos) - vActorPos).length() < (speed = cls.getSpeed(actor)) / 10.0f) + isStuck = true; - if(distBetween < rangeMelee || (distBetween <= rangeCloseUp && mFollowTarget) ) + mLastPos = pos; + + if(distToTarget < rangeMelee || (distToTarget <= rangeCloseUp && mFollowTarget && !isStuck) ) { //Melee and Close-up combat - vDir.z = 0; - float dirLen = vDir.length(); - mTargetAngle = Ogre::Radian( Ogre::Math::ACos(vDir.y / dirLen) * sgn(Ogre::Math::ASin(vDir.x / dirLen)) ).valueDegrees(); - mRotate = true; + vDirToTarget.z = 0; + mTargetAngle = getZAngleToDir(vDirToTarget, distToTarget); - //bool LOS = MWBase::Environment::get().getWorld()->getLOS(actor, mTarget); - if (mFollowTarget && distBetween > rangeMelee) + if (mFollowTarget && distToTarget > rangeMelee) { //Close-up combat: just run up on target mMovement.mPosition[1] = 1; @@ -228,7 +265,7 @@ namespace MWMechanics } } - if(distantCombat && distBetween < rangeMelee/4) + if(distantCombat && distToTarget < rangeMelee/4) { mMovement.mPosition[1] = -1; } @@ -238,32 +275,80 @@ namespace MWMechanics mFollowTarget = true; } } - else + else // remote pathfinding { - //target is at far distance: build path to target OR follow target (if previously actor had reached it once) - mFollowTarget = false; + bool preferShortcut = false; + bool inLOS; - buildNewPath(actor); //may fail to build a path, check before use - - //delete visited path node - mPathFinder.checkPathCompleted(pos.pos[0],pos.pos[1],pos.pos[2]); - - //if no new path leave mTargetAngle unchanged - if(!mPathFinder.getPath().empty()) + if(mReadyToAttack) isStuck = false; + + // check if shortcut is available + if(!isStuck + && (!mForceNoShortcut + || (Ogre::Vector3(mShortcutFailPos.pos) - vActorPos).length() >= PATHFIND_SHORTCUT_RETRY_DIST) + && (inLOS = MWBase::Environment::get().getWorld()->getLOS(actor, mTarget))) { - //try shortcut - if(vDir.length() < mPathFinder.getDistToNext(pos.pos[0],pos.pos[1],pos.pos[2]) && MWBase::Environment::get().getWorld()->getLOS(actor, mTarget)) - mTargetAngle = Ogre::Radian( Ogre::Math::ACos(vDir.y / vDir.length()) * sgn(Ogre::Math::ASin(vDir.x / vDir.length())) ).valueDegrees(); - else - mTargetAngle = mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]); - mRotate = true; + if(speed == 0.0f) speed = cls.getSpeed(actor); + // maximum dist before pit/obstacle for actor to avoid them depending on his speed + float maxAvoidDist = tReaction * speed + speed / MAX_VEL_ANGULAR.valueRadians() * 2; + //if(actor.getRefData().getPosition().rot[2] != mTargetAngle) + preferShortcut = checkWayIsClear(vActorPos, vTargetPos, distToTarget > maxAvoidDist*1.5? maxAvoidDist : maxAvoidDist/2); + } + + if(preferShortcut) + { + mTargetAngle = getZAngleToDir(vDirToTarget, distToTarget); + mForceNoShortcut = false; + mShortcutFailPos.pos[0] = mShortcutFailPos.pos[1] = mShortcutFailPos.pos[2] = 0; + if(mPathFinder.isPathConstructed()) + mPathFinder.clearPath(); + } + else // if shortcut failed stick to path grid + { + if(!isStuck && mShortcutFailPos.pos[0] == 0.0f && mShortcutFailPos.pos[1] == 0.0f && mShortcutFailPos.pos[2] == 0.0f) + { + mForceNoShortcut = true; + mShortcutFailPos = pos; + } + + mFollowTarget = false; + + buildNewPath(actor); //may fail to build a path, check before use + + //delete visited path node + mPathFinder.checkWaypoint(pos.pos[0],pos.pos[1],pos.pos[2]); + + // This works on the borders between the path grid and areas with no waypoints. + if(inLOS && mPathFinder.getPath().size() > 1) + { + // get point just before target + std::list::iterator pntIter = --mPathFinder.getPath().end(); + --pntIter; + Ogre::Vector3 vBeforeTarget = Ogre::Vector3(pntIter->mX, pntIter->mY, pntIter->mZ); + + // if current actor pos is closer to target then last point of path (excluding target itself) then go straight on target + if(distToTarget <= (vTargetPos - vBeforeTarget).length()) + { + mTargetAngle = getZAngleToDir(vDirToTarget, distToTarget); + preferShortcut = true; + } + } + + // if there is no new path, then go straight on target + if(!preferShortcut) + { + if(!mPathFinder.getPath().empty()) + mTargetAngle = mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]); + else + mTargetAngle = getZAngleToDir(vDirToTarget, distToTarget); + } } mMovement.mPosition[1] = 1; mReadyToAttack = false; } - if(distBetween > rangeMelee) + if(distToTarget > rangeMelee) { //special run attack; it shouldn't affect melee combat tactics if(actor.getClass().getMovementSettings(actor).mPosition[1] == 1) @@ -277,7 +362,7 @@ namespace MWMechanics && mTarget.getClass().getMovementSettings(mTarget).mPosition[1] == 0) speed2 = 0; - float s1 = distBetween - weapRange; + float s1 = distToTarget - weapRange; float t = s1/speed1; float s2 = speed2 * t; float t_swing = 0.17f/weapSpeed;//instead of 0.17 should be the time of playing weapon anim from 'start' to 'hit' tags @@ -300,31 +385,23 @@ namespace MWMechanics void AiCombat::buildNewPath(const MWWorld::Ptr& actor) { - //Construct path to target - ESM::Pathgrid::Point dest; - dest.mX = mTarget.getRefData().getPosition().pos[0]; - dest.mY = mTarget.getRefData().getPosition().pos[1]; - dest.mZ = mTarget.getRefData().getPosition().pos[2]; - Ogre::Vector3 newPathTarget = Ogre::Vector3(dest.mX, dest.mY, dest.mZ); + Ogre::Vector3 newPathTarget = Ogre::Vector3(mTarget.getRefData().getPosition().pos); - float dist = -1; //hack to indicate first time, to construct a new path + float dist; + if(!mPathFinder.getPath().empty()) { ESM::Pathgrid::Point lastPt = mPathFinder.getPath().back(); Ogre::Vector3 currPathTarget(lastPt.mX, lastPt.mY, lastPt.mZ); - dist = Ogre::Math::Abs((newPathTarget - currPathTarget).length()); + dist = (newPathTarget - currPathTarget).length(); } + else dist = 1e+38F; // necessarily construct a new path - float targetPosThreshold; - bool isOutside = actor.getCell()->getCell()->isExterior(); - if (isOutside) - targetPosThreshold = 300; - else - targetPosThreshold = 100; + float targetPosThreshold = (actor.getCell()->getCell()->isExterior())? 300 : 100; - if((dist < 0) || (dist > targetPosThreshold)) + //construct new path only if target has moved away more than on [targetPosThreshold] + if(dist > targetPosThreshold) { - //construct new path only if target has moved away more than on ESM::Position pos = actor.getRefData().getPosition(); ESM::Pathgrid::Point start; @@ -332,17 +409,18 @@ namespace MWMechanics start.mY = pos.pos[1]; start.mZ = pos.pos[2]; + ESM::Pathgrid::Point dest; + dest.mX = newPathTarget.x; + dest.mY = newPathTarget.y; + dest.mZ = newPathTarget.z; + if(!mPathFinder.isPathConstructed()) - mPathFinder.buildPath(start, dest, actor.getCell(), isOutside); + mPathFinder.buildPath(start, dest, actor.getCell(), false); else { PathFinder newPathFinder; - newPathFinder.buildPath(start, dest, actor.getCell(), isOutside); + newPathFinder.buildPath(start, dest, actor.getCell(), false); - //TO EXPLORE: - //maybe here is a mistake (?): PathFinder::getPathSize() returns number of grid points in the path, - //not the actual path length. Here we should know if the new path is actually more effective. - //if(pathFinder2.getPathSize() < mPathFinder.getPathSize()) if(!mPathFinder.getPath().empty()) { newPathFinder.syncStart(mPathFinder.getPath()); diff --git a/apps/openmw/mwmechanics/aicombat.hpp b/apps/openmw/mwmechanics/aicombat.hpp index 767a36292..b71dd9cf0 100644 --- a/apps/openmw/mwmechanics/aicombat.hpp +++ b/apps/openmw/mwmechanics/aicombat.hpp @@ -43,8 +43,11 @@ namespace MWMechanics bool mReadyToAttack, mStrike; bool mFollowTarget; bool mCombatMove; - bool mRotate; + bool mForceNoShortcut; + ESM::Position mShortcutFailPos; + + ESM::Position mLastPos; MWMechanics::Movement mMovement; MWWorld::Ptr mTarget; diff --git a/apps/openmw/mwmechanics/pathfinding.cpp b/apps/openmw/mwmechanics/pathfinding.cpp index 3ecd40743..4aee6f6e4 100644 --- a/apps/openmw/mwmechanics/pathfinding.cpp +++ b/apps/openmw/mwmechanics/pathfinding.cpp @@ -384,22 +384,21 @@ namespace MWMechanics return false; } - void PathFinder::syncStart(const std::list &path) + bool PathFinder::syncStart(const std::list &path) { if (mPath.size() < 2) - return; //nothing to pop + return false; //nothing to pop std::list::const_iterator oldStart = path.begin(); std::list::iterator iter = ++mPath.begin(); if( (*iter).mX == oldStart->mX && (*iter).mY == oldStart->mY - && (*iter).mZ == oldStart->mZ - && (*iter).mAutogenerated == oldStart->mAutogenerated - && (*iter).mConnectionNum == oldStart->mConnectionNum ) + && (*iter).mZ == oldStart->mZ) { mPath.pop_front(); + return true; } - + return false; } } diff --git a/apps/openmw/mwmechanics/pathfinding.hpp b/apps/openmw/mwmechanics/pathfinding.hpp index ecaaef568..86fa3b6bc 100644 --- a/apps/openmw/mwmechanics/pathfinding.hpp +++ b/apps/openmw/mwmechanics/pathfinding.hpp @@ -64,10 +64,15 @@ namespace MWMechanics return mPath; } - //When first point of newly created path is the nearest to actor point, then - //the cituation can occure when this point is undesirable (if the 2nd point of new path == the 1st point of old path) - //This functions deletes that point. - void syncStart(const std::list &path); + /** Synchronize new path with old one to avoid visiting 1 waypoint 2 times + @note + If the first point is chosen as the nearest one + the cituation can occure when the 1st point of the new path is undesirable + (i.e. the 2nd point of new path == the 1st point of old path). + @param path - old path + @return true if such point was found and deleted + */ + bool syncStart(const std::list &path); void addPointToPath(ESM::Pathgrid::Point &point) { diff --git a/apps/openmw/mwmechanics/steering.cpp b/apps/openmw/mwmechanics/steering.cpp index d911fd81b..7646e832d 100644 --- a/apps/openmw/mwmechanics/steering.cpp +++ b/apps/openmw/mwmechanics/steering.cpp @@ -31,8 +31,7 @@ bool zTurn(const MWWorld::Ptr& actor, Ogre::Radian targetAngle) if (absDiff < epsilon) return true; - // Max. speed of 10 radian per sec - Ogre::Radian limit = Ogre::Radian(10) * MWBase::Environment::get().getFrameDuration(); + Ogre::Radian limit = MAX_VEL_ANGULAR * MWBase::Environment::get().getFrameDuration(); if (absDiff > limit) diff = Ogre::Math::Sign(diff) * limit; diff --git a/apps/openmw/mwmechanics/steering.hpp b/apps/openmw/mwmechanics/steering.hpp index 504dc3ac3..9bdf7d4a3 100644 --- a/apps/openmw/mwmechanics/steering.hpp +++ b/apps/openmw/mwmechanics/steering.hpp @@ -10,6 +10,9 @@ class Ptr; namespace MWMechanics { +// Max rotating speed, radian/sec +const Ogre::Radian MAX_VEL_ANGULAR(10); + /// configure rotation settings for an actor to reach this target angle (eventually) /// @return have we reached the target angle? bool zTurn(const MWWorld::Ptr& actor, Ogre::Radian targetAngle); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 594a9f7f4..47536ab6c 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1875,7 +1875,7 @@ namespace MWWorld out.push_back(searchPtrViaHandle(*it)); } } - + bool World::getLOS(const MWWorld::Ptr& npc,const MWWorld::Ptr& targetNpc) { if (!targetNpc.getRefData().isEnabled() || !npc.getRefData().isEnabled()) @@ -1893,6 +1893,19 @@ namespace MWWorld return false; } + float World::getDistToNearestRayHit(const Ogre::Vector3& from, const Ogre::Vector3& dir, float maxDist) + { + btVector3 btFrom(from.x, from.y, from.z); + btVector3 btTo = btVector3(dir.x, dir.y, dir.z); + btTo.normalize(); + btTo = btFrom + btTo * maxDist; + + std::pair result = mPhysEngine->rayTest(btFrom, btTo, false); + + if(result.second == -1) return maxDist; + else return result.second*(btTo-btFrom).length(); + } + void World::enableActorCollision(const MWWorld::Ptr& actor, bool enable) { OEngine::Physic::PhysicActor *physicActor = mPhysEngine->getCharacter(actor.getRefData().getHandle()); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index f1e89bf6b..0eea3c6a0 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -510,6 +510,8 @@ namespace MWWorld virtual bool getLOS(const MWWorld::Ptr& npc,const MWWorld::Ptr& targetNpc); ///< get Line of Sight (morrowind stupid implementation) + virtual float getDistToNearestRayHit(const Ogre::Vector3& from, const Ogre::Vector3& dir, float maxDist); + virtual void enableActorCollision(const MWWorld::Ptr& actor, bool enable); virtual int canRest(); From 79f32546e194d435e877f29b6216ea165be1218c Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 20 Apr 2014 19:28:25 +0200 Subject: [PATCH 003/118] Dead link fix --- cmake/FindLIBUNSHIELD.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/FindLIBUNSHIELD.cmake b/cmake/FindLIBUNSHIELD.cmake index 4f4e98a1c..f0fa4cc82 100644 --- a/cmake/FindLIBUNSHIELD.cmake +++ b/cmake/FindLIBUNSHIELD.cmake @@ -4,7 +4,7 @@ # LIBUNSHIELD_FOUND, if false, do not try to link to LibUnshield # LIBUNSHIELD_INCLUDE_DIR, where to find the headers # -# Created by Tom Mason (wheybags) for OpenMW (http://openmw.com), based on FindMPG123.cmake +# Created by Tom Mason (wheybags) for OpenMW (http://openmw.org), based on FindMPG123.cmake # # Ripped off from other sources. In fact, this file is so generic (I # just did a search and replace on another file) that I wonder why the From 262e9596996bb29d4e000ded8235682988818613 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 20 Apr 2014 19:28:39 +0200 Subject: [PATCH 004/118] Remove unused slice_array --- components/CMakeLists.txt | 2 +- components/misc/slice_array.hpp | 82 --------------------------------- 2 files changed, 1 insertion(+), 83 deletions(-) delete mode 100644 components/misc/slice_array.hpp diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 2b06babe7..38be5b11a 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -49,7 +49,7 @@ add_component_dir (esm ) add_component_dir (misc - slice_array stringops + utf8stream stringops ) add_component_dir (files diff --git a/components/misc/slice_array.hpp b/components/misc/slice_array.hpp deleted file mode 100644 index cd58e7bd6..000000000 --- a/components/misc/slice_array.hpp +++ /dev/null @@ -1,82 +0,0 @@ -/* - OpenMW - The completely unofficial reimplementation of Morrowind - Copyright (C) 2008-2010 Nicolay Korslund - Email: < korslund@gmail.com > - WWW: http://openmw.sourceforge.net/ - - This file (slice_array.h) is part of the OpenMW package. - - OpenMW is distributed as free software: you can redistribute it - and/or modify it under the terms of the GNU General Public License - version 3, as published by the Free Software Foundation. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - version 3 along with this program. If not, see - http://www.gnu.org/licenses/ . - - */ - -#ifndef MISC_SLICE_ARRAY_H -#define MISC_SLICE_ARRAY_H - -// A simple array implementation containing a pointer and a -// length. Used for holding slices into a data buffer. -#include -#include - -namespace Misc -{ - -template -struct SliceArray -{ - const T* ptr; - size_t length; - - /// Initialize to zero length - SliceArray() : ptr(0), length(0) {} - - /// Initialize from pointer + length - SliceArray(const T* _ptr, size_t _length) - : ptr(_ptr), length(_length) {} - - /// Initialize from null-terminated string - SliceArray(const char* str) - { - ptr = str; - length = strlen(str); - } - - bool operator==(SliceArray &t) - { - return - length == t.length && - (memcmp(ptr,t.ptr, length*sizeof(T)) == 0); - } - - /// Only use this for stings - bool operator==(const char* str) - { - return - str[length] == 0 && - (strncmp(ptr, str, length) == 0); - } - - /** This allocates a copy of the data. Only use this for debugging - and error messages. */ - std::string toString() - { return std::string(ptr,length); } -}; - -typedef SliceArray SString; -typedef SliceArray IntArray; -typedef SliceArray FloatArray; - -} - -#endif From 2cb9f38a45596859f2f3dc7fe1db51cf2b78bf36 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 20 Apr 2014 19:34:58 +0200 Subject: [PATCH 005/118] Changed crime IDs for legacy savegames. Not an issue, but it was inconsistent. --- components/esm/player.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/esm/player.cpp b/components/esm/player.cpp index 7a2c03b48..70f795afe 100644 --- a/components/esm/player.cpp +++ b/components/esm/player.cpp @@ -26,9 +26,9 @@ void ESM::Player::load (ESMReader &esm) mBirthsign = esm.getHNString ("SIGN"); - mCurrentCrimeId = 0; + mCurrentCrimeId = -1; esm.getHNOT (mCurrentCrimeId, "CURD"); - mPayedCrimeId = 0; + mPayedCrimeId = -1; esm.getHNOT (mPayedCrimeId, "PAYD"); } From 6929e541ddd21b211faa2b3817d0a763f0f31777 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 21 Apr 2014 05:30:14 +0200 Subject: [PATCH 006/118] Fix texture name issue with Vality's Bitter Coast Mod --- components/nifogre/material.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/components/nifogre/material.cpp b/components/nifogre/material.cpp index 4dae1a93d..3a87e1d52 100644 --- a/components/nifogre/material.cpp +++ b/components/nifogre/material.cpp @@ -67,6 +67,10 @@ std::string NIFMaterialLoader::findTextureName(const std::string &filename) std::string texname = filename; Misc::StringUtils::toLower(texname); + // Apparently, leading separators are allowed + while (texname.size() && (texname[0] == '/' || texname[0] == '\\')) + texname.erase(0, 1); + if(texname.compare(0, sizeof(path)-1, path) != 0 && texname.compare(0, sizeof(path2)-1, path2) != 0) texname = path + texname; From 9998c2783eb4813137c61451085615f7ba8f70bc Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 21 Apr 2014 17:37:06 +0200 Subject: [PATCH 007/118] Fix travis Why again do we need a unit test for something that was never used? --- .../components/misc/test_slicearray.cpp | 33 ------------------- 1 file changed, 33 deletions(-) delete mode 100644 apps/openmw_test_suite/components/misc/test_slicearray.cpp diff --git a/apps/openmw_test_suite/components/misc/test_slicearray.cpp b/apps/openmw_test_suite/components/misc/test_slicearray.cpp deleted file mode 100644 index ab63e56c4..000000000 --- a/apps/openmw_test_suite/components/misc/test_slicearray.cpp +++ /dev/null @@ -1,33 +0,0 @@ -#include -#include "components/misc/slice_array.hpp" - -struct SliceArrayTest : public ::testing::Test -{ - protected: - virtual void SetUp() - { - } - - virtual void TearDown() - { - } -}; - -TEST_F(SliceArrayTest, hello_string) -{ - Misc::SString s("hello"); - ASSERT_EQ(sizeof("hello") - 1, s.length); - ASSERT_FALSE(s=="hel"); - ASSERT_FALSE(s=="hell"); - ASSERT_TRUE(s=="hello"); -} - -TEST_F(SliceArrayTest, othello_string_with_offset_2_and_size_4) -{ - Misc::SString s("othello" + 2, 4); - ASSERT_EQ(sizeof("hell") - 1, s.length); - ASSERT_FALSE(s=="hel"); - ASSERT_TRUE(s=="hell"); - ASSERT_FALSE(s=="hello"); -} - From 1ab51306c3dfafdc5007dc8f15a96d9daf103118 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 21 Apr 2014 17:47:20 +0200 Subject: [PATCH 008/118] updated credits file --- credits.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/credits.txt b/credits.txt index eb427a22b..499c55eeb 100644 --- a/credits.txt +++ b/credits.txt @@ -70,6 +70,7 @@ Sebastian Wick (swick) Sergey Shambir sir_herrbatka Sylvain Thesnieres (Garvek) +Thomas Luppi (Digmaster) Tom Mason (wheybags) Torben Leif Carrington (TorbenC) From fbd0ffe86ff00da9bac3ae24670d1cbca32c1860 Mon Sep 17 00:00:00 2001 From: mrcheko Date: Tue, 22 Apr 2014 22:59:39 +0400 Subject: [PATCH 009/118] enable z-moving for flying/water combatants --- apps/openmw/mwmechanics/aicombat.cpp | 32 +++++++++++++++++++-------- apps/openmw/mwmechanics/character.cpp | 10 +++++---- 2 files changed, 29 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index 84798ca02..807e08c1d 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -38,7 +38,7 @@ namespace return Ogre::Radian( Ogre::Math::ACos(dir.y / len) * sgn(Ogre::Math::ASin(dir.x / len)) ).valueDegrees(); } - const float PATHFIND_Z_REACH = 50.0f; + const float PATHFIND_Z_REACH = 50.0f; // distance at which actor pays more attention to decide whether to shortcut or stick to pathgrid const float PATHFIND_CAUTION_DIST = 500.0f; // distance after which actor (failed previously to shortcut) will try again @@ -115,6 +115,7 @@ namespace MWMechanics } + mTimerAttack -= duration; actor.getClass().getCreatureStats(actor).setAttackingOrSpell(mStrike); @@ -229,6 +230,17 @@ namespace MWMechanics mLastPos = pos; + // check if can move along z-axis + bool canMoveByZ; + if(canMoveByZ = ((actor.getClass().isNpc() || actor.getClass().canSwim(actor)) && MWBase::Environment::get().getWorld()->isSwimming(actor)) + || (actor.getClass().canFly(actor) && MWBase::Environment::get().getWorld()->isFlying(actor))) + { + float zToTarget = vTargetPos.z - pos.pos[2]; + + mMovement.mPosition[1] = sqrt(distToTarget*distToTarget - zToTarget*zToTarget); // XY-plane vec length + mMovement.mPosition[2] = zToTarget; + } + if(distToTarget < rangeMelee || (distToTarget <= rangeCloseUp && mFollowTarget && !isStuck) ) { //Melee and Close-up combat @@ -238,12 +250,13 @@ namespace MWMechanics if (mFollowTarget && distToTarget > rangeMelee) { //Close-up combat: just run up on target - mMovement.mPosition[1] = 1; + if(!canMoveByZ) mMovement.mPosition[1] = 1; } else { //Melee: stop running and attack mMovement.mPosition[1] = 0; + if(canMoveByZ) mMovement.mPosition[2] = 0; // When attacking with a weapon, choose between slash, thrust or chop if (actor.getClass().hasInventoryStore(actor)) @@ -295,15 +308,16 @@ namespace MWMechanics preferShortcut = checkWayIsClear(vActorPos, vTargetPos, distToTarget > maxAvoidDist*1.5? maxAvoidDist : maxAvoidDist/2); } - if(preferShortcut) - { + if(canMoveByZ) preferShortcut = true; + + if(preferShortcut) + { mTargetAngle = getZAngleToDir(vDirToTarget, distToTarget); mForceNoShortcut = false; mShortcutFailPos.pos[0] = mShortcutFailPos.pos[1] = mShortcutFailPos.pos[2] = 0; - if(mPathFinder.isPathConstructed()) - mPathFinder.clearPath(); - } - else // if shortcut failed stick to path grid + mPathFinder.clearPath(); + } + else // if shortcut failed stick to path grid { if(!isStuck && mShortcutFailPos.pos[0] == 0.0f && mShortcutFailPos.pos[1] == 0.0f && mShortcutFailPos.pos[2] == 0.0f) { @@ -344,7 +358,7 @@ namespace MWMechanics } } - mMovement.mPosition[1] = 1; + if(!canMoveByZ) mMovement.mPosition[1] = 1; mReadyToAttack = false; } diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 93c789af1..2c63d5a14 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1018,6 +1018,7 @@ void CharacterController::update(float duration) vec.x *= mMovementSpeed; vec.y *= mMovementSpeed; + if(inwater || flying) vec.z *= mMovementSpeed; CharacterState movestate = CharState_None; CharacterState idlestate = CharState_SpecialIdle; @@ -1084,7 +1085,8 @@ void CharacterController::update(float duration) fatigue.setCurrent(fatigue.getCurrent() - fatigueLoss, fatigue.getCurrent() < 0); cls.getCreatureStats(mPtr).setFatigue(fatigue); - if(sneak || inwater || flying) + // kind of hack, reason - creatures can move along z when in water/flying + if(sneak || ((inwater || flying) && mPtr.getRefData().getHandle() == "player")) vec.z = 0.0f; if (inwater || flying) @@ -1119,7 +1121,7 @@ void CharacterController::update(float duration) vec.y *= mult; vec.z = 0.0f; } - else if(vec.z > 0.0f && mJumpState == JumpState_None) + else if(!inwater && !flying && vec.z > 0.0f && mJumpState == JumpState_None) { // Started a jump. float z = cls.getJump(mPtr); @@ -1179,9 +1181,9 @@ void CharacterController::update(float duration) } else { - if(!(vec.z > 0.0f)) + if(!(vec.z > 0.0f)) mJumpState = JumpState_None; - vec.z = 0.0f; + if(!inwater && !flying) vec.z = 0.0f; if(std::abs(vec.x/2.0f) > std::abs(vec.y)) { From d3148555fad4ed85bb9e592003804e4f185f9b14 Mon Sep 17 00:00:00 2001 From: graffy76 Date: Tue, 22 Apr 2014 22:16:14 -0500 Subject: [PATCH 010/118] Delete old framework files --- .../model/settings/settingcontainer.cpp | 82 ------- .../model/settings/settingcontainer.hpp | 47 ---- apps/opencs/model/settings/settingsitem.cpp | 104 --------- apps/opencs/model/settings/settingsitem.hpp | 67 ------ apps/opencs/view/settings/abstractblock.cpp | 112 --------- apps/opencs/view/settings/abstractblock.hpp | 82 ------- apps/opencs/view/settings/abstractpage.cpp | 44 ---- apps/opencs/view/settings/abstractpage.hpp | 70 ------ apps/opencs/view/settings/abstractwidget.cpp | 78 ------- apps/opencs/view/settings/abstractwidget.hpp | 69 ------ apps/opencs/view/settings/blankpage.cpp | 50 ---- apps/opencs/view/settings/blankpage.hpp | 28 --- apps/opencs/view/settings/customblock.cpp | 121 ---------- apps/opencs/view/settings/customblock.hpp | 47 ---- .../view/settings/datadisplayformatpage.cpp | 57 ----- .../view/settings/datadisplayformatpage.hpp | 33 --- apps/opencs/view/settings/editorpage.cpp | 53 ----- apps/opencs/view/settings/editorpage.hpp | 33 --- apps/opencs/view/settings/groupblock.cpp | 108 --------- apps/opencs/view/settings/groupblock.hpp | 43 ---- apps/opencs/view/settings/groupbox.cpp | 56 ----- apps/opencs/view/settings/groupbox.hpp | 28 --- apps/opencs/view/settings/itemblock.cpp | 115 ---------- apps/opencs/view/settings/itemblock.hpp | 48 ---- apps/opencs/view/settings/proxyblock.cpp | 152 ------------- apps/opencs/view/settings/proxyblock.hpp | 52 ----- apps/opencs/view/settings/settingwidget.cpp | 1 - apps/opencs/view/settings/settingwidget.hpp | 214 ------------------ apps/opencs/view/settings/toggleblock.cpp | 80 ------- apps/opencs/view/settings/toggleblock.hpp | 29 --- .../view/settings/usersettingsdialog.cpp | 119 ---------- .../view/settings/usersettingsdialog.hpp | 71 ------ apps/opencs/view/settings/windowpage.cpp | 144 ------------ apps/opencs/view/settings/windowpage.hpp | 34 --- 34 files changed, 2471 deletions(-) delete mode 100644 apps/opencs/model/settings/settingcontainer.cpp delete mode 100644 apps/opencs/model/settings/settingcontainer.hpp delete mode 100644 apps/opencs/model/settings/settingsitem.cpp delete mode 100644 apps/opencs/model/settings/settingsitem.hpp delete mode 100644 apps/opencs/view/settings/abstractblock.cpp delete mode 100644 apps/opencs/view/settings/abstractblock.hpp delete mode 100644 apps/opencs/view/settings/abstractpage.cpp delete mode 100644 apps/opencs/view/settings/abstractpage.hpp delete mode 100644 apps/opencs/view/settings/abstractwidget.cpp delete mode 100644 apps/opencs/view/settings/abstractwidget.hpp delete mode 100644 apps/opencs/view/settings/blankpage.cpp delete mode 100644 apps/opencs/view/settings/blankpage.hpp delete mode 100644 apps/opencs/view/settings/customblock.cpp delete mode 100644 apps/opencs/view/settings/customblock.hpp delete mode 100755 apps/opencs/view/settings/datadisplayformatpage.cpp delete mode 100755 apps/opencs/view/settings/datadisplayformatpage.hpp delete mode 100644 apps/opencs/view/settings/editorpage.cpp delete mode 100644 apps/opencs/view/settings/editorpage.hpp delete mode 100644 apps/opencs/view/settings/groupblock.cpp delete mode 100644 apps/opencs/view/settings/groupblock.hpp delete mode 100644 apps/opencs/view/settings/groupbox.cpp delete mode 100644 apps/opencs/view/settings/groupbox.hpp delete mode 100644 apps/opencs/view/settings/itemblock.cpp delete mode 100644 apps/opencs/view/settings/itemblock.hpp delete mode 100644 apps/opencs/view/settings/proxyblock.cpp delete mode 100644 apps/opencs/view/settings/proxyblock.hpp delete mode 100644 apps/opencs/view/settings/settingwidget.cpp delete mode 100644 apps/opencs/view/settings/settingwidget.hpp delete mode 100644 apps/opencs/view/settings/toggleblock.cpp delete mode 100644 apps/opencs/view/settings/toggleblock.hpp delete mode 100644 apps/opencs/view/settings/usersettingsdialog.cpp delete mode 100644 apps/opencs/view/settings/usersettingsdialog.hpp delete mode 100644 apps/opencs/view/settings/windowpage.cpp delete mode 100644 apps/opencs/view/settings/windowpage.hpp diff --git a/apps/opencs/model/settings/settingcontainer.cpp b/apps/opencs/model/settings/settingcontainer.cpp deleted file mode 100644 index a75a84ec5..000000000 --- a/apps/opencs/model/settings/settingcontainer.cpp +++ /dev/null @@ -1,82 +0,0 @@ -#include "settingcontainer.hpp" - -#include - -CSMSettings::SettingContainer::SettingContainer(QObject *parent) : - QObject(parent), mValue (0), mValues (0) -{ -} - -CSMSettings::SettingContainer::SettingContainer(const QString &value, QObject *parent) : - QObject(parent), mValue (new QString (value)), mValues (0) -{ -} - -void CSMSettings::SettingContainer::insert (const QString &value) -{ - if (mValue) - { - mValues = new QStringList; - mValues->push_back (*mValue); - mValues->push_back (value); - - delete mValue; - mValue = 0; - } - else - { - delete mValue; - mValue = new QString (value); - } - -} - -void CSMSettings::SettingContainer::update (const QString &value, int index) -{ - if (isEmpty()) - mValue = new QString(value); - - else if (mValue) - *mValue = value; - - else if (mValues) - mValues->replace(index, value); -} - -QString CSMSettings::SettingContainer::getValue (int index) const -{ - QString retVal(""); - - //if mValue is valid, it's a single-value property. - //ignore the index and return the value - if (mValue) - retVal = *mValue; - - //otherwise, if it's a multivalued property - //return the appropriate value at the index - else if (mValues) - { - if (index == -1) - retVal = mValues->at(0); - - else if (index < mValues->size()) - retVal = mValues->at(index); - } - - return retVal; -} - -int CSMSettings::SettingContainer::count () const -{ - int retVal = 0; - - if (!isEmpty()) - { - if (mValues) - retVal = mValues->size(); - else - retVal = 1; - } - - return retVal; -} diff --git a/apps/opencs/model/settings/settingcontainer.hpp b/apps/opencs/model/settings/settingcontainer.hpp deleted file mode 100644 index 5af298a57..000000000 --- a/apps/opencs/model/settings/settingcontainer.hpp +++ /dev/null @@ -1,47 +0,0 @@ -#ifndef SETTINGCONTAINER_HPP -#define SETTINGCONTAINER_HPP - -#include - -class QStringList; - -namespace CSMSettings -{ - class SettingContainer : public QObject - { - Q_OBJECT - - QString *mValue; - QStringList *mValues; - - public: - - explicit SettingContainer (QObject *parent = 0); - explicit SettingContainer (const QString &value, QObject *parent = 0); - - /// add a value to the container - /// multiple values supported - void insert (const QString &value); - - /// update an existing value - /// index specifies multiple values - void update (const QString &value, int index = 0); - - /// return value at specified index - QString getValue (int index = -1) const; - - /// retrieve list of all values - inline QStringList *getValues() const { return mValues; } - - /// return size of list - int count() const; - - /// test for empty container - /// useful for default-constructed containers returned by QMap when invalid key is passed - inline bool isEmpty() const { return (!mValue && !mValues); } - - inline bool isMultiValue() const { return (mValues); } - }; -} - -#endif // SETTINGCONTAINER_HPP diff --git a/apps/opencs/model/settings/settingsitem.cpp b/apps/opencs/model/settings/settingsitem.cpp deleted file mode 100644 index 5d897448a..000000000 --- a/apps/opencs/model/settings/settingsitem.cpp +++ /dev/null @@ -1,104 +0,0 @@ -#include "settingsitem.hpp" - -#include - -bool CSMSettings::SettingsItem::updateItem (const QStringList *values) -{ - QStringList::ConstIterator it = values->begin(); - - //if the item is not multivalued, - //save the last value passed in the container - if (!mIsMultiValue) - { - it = values->end(); - it--; - } - - bool isValid = true; - QString value (""); - - for (; it != values->end(); ++it) - { - value = *it; - isValid = validate(value); - - //skip only the invalid values - if (!isValid) - continue; - - insert(value); - } - - return isValid; -} - -bool CSMSettings::SettingsItem::updateItem (const QString &value) -{ - //takes a value or a SettingsContainer and updates itself accordingly - //after validating the data against it's own definition - - QString newValue = value; - - if (!validate (newValue)) - newValue = mDefaultValue; - - bool success = (getValue() != newValue); - - if (success) - { - if (mIsMultiValue) - insert (newValue); - else - update (newValue); - } - return success; -} - -bool CSMSettings::SettingsItem::updateItem(int valueListIndex) -{ - bool success = false; - - if (mValueList) - { - if (mValueList->size() > valueListIndex) - success = updateItem (mValueList->at(valueListIndex)); - } - return success; -} - -bool CSMSettings::SettingsItem::validate (const QString &value) -{ - //if there is no value list or value pair, there is no validation to do - bool isValid = !(!mValueList->isEmpty() || mValuePair); - - if (!isValid && !mValueList->isEmpty()) - { - for (QStringList::Iterator it = mValueList->begin(); it != mValueList->end(); ++it) - // foreach (QString listItem, *mValueList) - { - isValid = (value == *it); - - if (isValid) - break; - } - } - else if (!isValid && mValuePair) - { - int numVal = value.toInt(); - - isValid = (numVal > mValuePair->left.toInt() && numVal < mValuePair->right.toInt()); - } - - return isValid; -} - -void CSMSettings::SettingsItem::setDefaultValue (const QString &value) -{ - mDefaultValue = value; - update (value); -} - -QString CSMSettings::SettingsItem::getDefaultValue() const -{ - return mDefaultValue; -} diff --git a/apps/opencs/model/settings/settingsitem.hpp b/apps/opencs/model/settings/settingsitem.hpp deleted file mode 100644 index 87a85e8e4..000000000 --- a/apps/opencs/model/settings/settingsitem.hpp +++ /dev/null @@ -1,67 +0,0 @@ -#ifndef SETTINGSITEM_HPP -#define SETTINGSITEM_HPP - -#include -#include "support.hpp" -#include "settingcontainer.hpp" - -namespace CSMSettings -{ - /// Represents a setting including metadata - /// (valid values, ranges, defaults, and multivalue status - class SettingsItem : public SettingContainer - { - QStringPair *mValuePair; - QStringList *mValueList; - bool mIsMultiValue; - QString mDefaultValue; - - public: - explicit SettingsItem(QString name, bool isMultiValue, - const QString& defaultValue, QObject *parent = 0) - : SettingContainer(defaultValue, parent), - mIsMultiValue (isMultiValue), mValueList (0), - mValuePair (0), mDefaultValue (defaultValue) - { - QObject::setObjectName(name); - } - - /// updateItem overloads for updating setting value - /// provided a list of values (multi-valued), - /// a specific value - /// or an index value corresponding to the mValueList - bool updateItem (const QStringList *values); - bool updateItem (const QString &value); - bool updateItem (int valueListIndex); - - /// retrieve list of valid values for setting - inline QStringList *getValueList() { return mValueList; } - - /// write list of valid values for setting - inline void setValueList (QStringList *valueList) { mValueList = valueList; } - - /// valuePair used for spin boxes (max / min) - inline QStringPair *getValuePair() { return mValuePair; } - - /// set value range (spinbox / integer use) - inline void setValuePair (QStringPair valuePair) - { - delete mValuePair; - mValuePair = new QStringPair(valuePair); - } - - inline bool isMultivalue () { return mIsMultiValue; } - - void setDefaultValue (const QString &value); - QString getDefaultValue () const; - - private: - - /// Verifies that the supplied value is one of the following: - /// 1. Within the limits of the value pair (min / max) - /// 2. One of the values indicated in the value list - bool validate (const QString &value); - }; -} -#endif // SETTINGSITEM_HPP - diff --git a/apps/opencs/view/settings/abstractblock.cpp b/apps/opencs/view/settings/abstractblock.cpp deleted file mode 100644 index 65825ce8b..000000000 --- a/apps/opencs/view/settings/abstractblock.cpp +++ /dev/null @@ -1,112 +0,0 @@ -#include "abstractblock.hpp" - -CSVSettings::AbstractBlock::AbstractBlock(QWidget* parent) - : QObject (parent), mBox ( new GroupBox (parent) ), mWidgetParent (parent) -{} - -CSVSettings::AbstractBlock::AbstractBlock(bool isVisible, QWidget* parent) - : QObject (parent), mBox ( new GroupBox (isVisible, parent)), mWidgetParent (parent) -{} - -QLayout *CSVSettings::AbstractBlock::createLayout (Orientation direction, - bool isZeroMargin, QWidget* parent) -{ - QLayout *layout = 0; - - if (direction == Orient_Vertical) - layout = new QVBoxLayout (parent); - else - layout = new QHBoxLayout (parent); - - if (isZeroMargin) - layout->setContentsMargins(0, 0, 0, 0); - - return layout; -} - -QGroupBox *CSVSettings::AbstractBlock::getGroupBox() -{ - return mBox; -} - -CSVSettings::AbstractWidget *CSVSettings::AbstractBlock::buildWidget (const QString& widgetName, WidgetDef &def, - QLayout *layout, bool isConnected) const -{ - AbstractWidget *widg = 0; - - switch (def.type) - { - - case Widget_RadioButton: - widg = new SettingWidget (def, layout, mBox); - break; - - case Widget_SpinBox: - widg = new SettingWidget (def, layout, mBox); - break; - - case Widget_CheckBox: - widg = new SettingWidget (def, layout, mBox); - break; - - case Widget_LineEdit: - widg = new SettingWidget (def, layout, mBox); - break; - - case Widget_ListBox: - widg = new SettingWidget (def, layout, mBox); - break; - - case Widget_ComboBox: - widg = new SettingWidget (def, layout, mBox); - break; - - default: - break; - }; - - if (!mBox->layout()) - mBox->setLayout(widg->getLayout()); - - widg->widget()->setObjectName(widgetName); - - if (isConnected) - connect (widg, SIGNAL (signalUpdateItem (const QString &)), this, SLOT (slotUpdate (const QString &))); - connect (this, SIGNAL (signalUpdateWidget (const QString &)), widg, SLOT (slotUpdateWidget (const QString &) )); - - return widg; -} - -void CSVSettings::AbstractBlock::setVisible (bool isVisible) -{ - mBox->setBorderVisibility (isVisible); -} - -bool CSVSettings::AbstractBlock::isVisible () const -{ - return mBox->borderVisibile(); -} - -QWidget *CSVSettings::AbstractBlock::getParent() const -{ - return mWidgetParent; -} - -void CSVSettings::AbstractBlock::slotUpdate (const QString &value) -{ - slotUpdateSetting (objectName(), value); -} - -void CSVSettings::AbstractBlock::slotSetEnabled(bool value) -{ - mBox->setEnabled(value); -} - -void CSVSettings::AbstractBlock::slotUpdateSetting (const QString &settingName, const QString &settingValue) -{ - bool doEmit = true; - updateBySignal (settingName, settingValue, doEmit); - - if (doEmit) - emit signalUpdateSetting (settingName, settingValue); -} diff --git a/apps/opencs/view/settings/abstractblock.hpp b/apps/opencs/view/settings/abstractblock.hpp deleted file mode 100644 index 361339fe2..000000000 --- a/apps/opencs/view/settings/abstractblock.hpp +++ /dev/null @@ -1,82 +0,0 @@ -#ifndef ABSTRACTBLOCK_HPP -#define ABSTRACTBLOCK_HPP - -#include -#include - -#include "settingwidget.hpp" -#include "../../model/settings/settingsitem.hpp" -#include "groupbox.hpp" - -namespace CSVSettings -{ - - /// Abstract base class for all blocks - class AbstractBlock : public QObject - { - Q_OBJECT - - protected: - - typedef QMap SettingsItemMap; - GroupBox *mBox; - QWidget *mWidgetParent; - - public: - - explicit AbstractBlock (QWidget *parent = 0); - explicit AbstractBlock (bool isVisible, QWidget *parent = 0); - - QGroupBox *getGroupBox(); - void setVisible (bool isVisible); - bool isVisible() const; - - virtual CSMSettings::SettingList *getSettings() = 0; - - /// update settings found in the passed map and are encapsulated by the block - virtual bool updateSettings (const CSMSettings::SettingMap &settings) = 0; - - /// update callback function called from update slot - /// used for updating application-level settings in the editor - virtual bool updateBySignal (const QString &name, const QString &value, bool &doEmit) - { return false; } - - protected: - - /// Creates the layout for the block's QGroupBox - QLayout *createLayout (Orientation direction, bool isZeroMargin, QWidget* parent = 0); - - /// Creates widgets that exist as direct children of the block - AbstractWidget *buildWidget (const QString &widgetName, WidgetDef &wDef, - QLayout *layout = 0, bool isConnected = true) const; - - QWidget *getParent() const; - - public slots: - - /// enables / disables block-level widgets based on signals from other widgets - /// used in ToggleBlock - void slotSetEnabled (bool value); - - /// receives updates to applicaion-level settings in the Editor - void slotUpdateSetting (const QString &settingName, const QString &settingValue); - - private slots: - - /// receives updates to a setting in the block pushed from the application level - void slotUpdate (const QString &value); - - signals: - - /// signal to UserSettings instance - void signalUpdateSetting (const QString &propertyName, const QString &propertyValue); - - /// signal to widget for updating widget value - void signalUpdateWidget (const QString & value); - - /// ProxyBlock use only. - /// Name and value correspond to settings for which the block is a proxy. - void signalUpdateProxySetting (const QString &propertyName, const QString &propertyValue); - }; -} -#endif // ABSTRACTBLOCK_HPP diff --git a/apps/opencs/view/settings/abstractpage.cpp b/apps/opencs/view/settings/abstractpage.cpp deleted file mode 100644 index e6c605275..000000000 --- a/apps/opencs/view/settings/abstractpage.cpp +++ /dev/null @@ -1,44 +0,0 @@ -#include "abstractpage.hpp" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -CSVSettings::AbstractPage::AbstractPage(QWidget *parent): - QWidget(parent) -{ - QGridLayout *pageLayout = new QGridLayout(this); - setLayout (pageLayout); -} - -CSVSettings::AbstractPage::AbstractPage(const QString &pageName, QWidget *parent): - QWidget(parent) -{ - QWidget::setObjectName (pageName); - - QGridLayout *pageLayout = new QGridLayout(this); - setLayout (pageLayout); -} - -CSVSettings::AbstractPage::~AbstractPage() -{ -} - -CSMSettings::SettingList *CSVSettings::AbstractPage::getSettings() -{ - CSMSettings::SettingList *settings = new CSMSettings::SettingList(); - - foreach (AbstractBlock *block, mAbstractBlocks) - { - CSMSettings::SettingList *groupSettings = block->getSettings(); - settings->append (*groupSettings); - } - - return settings; -} diff --git a/apps/opencs/view/settings/abstractpage.hpp b/apps/opencs/view/settings/abstractpage.hpp deleted file mode 100644 index 77ef4524f..000000000 --- a/apps/opencs/view/settings/abstractpage.hpp +++ /dev/null @@ -1,70 +0,0 @@ -#ifndef ABSTRACTPAGE_HPP -#define ABSTRACTPAGE_HPP - -#include -#include -#include - -#include "abstractblock.hpp" - -class SettingMap; -class SettingList; - -namespace CSVSettings { - - typedef QList AbstractBlockList; - - /// Abstract base class for all setting pages in the dialog - - /// \todo Scripted implementation of settings should eliminate the need - /// \todo derive page classes. - /// \todo AbstractPage should be replaced with a general page construction class. - class AbstractPage: public QWidget - { - - protected: - - AbstractBlockList mAbstractBlocks; - - public: - - AbstractPage(QWidget *parent = 0); - AbstractPage (const QString &pageName, QWidget* parent = 0); - - ~AbstractPage(); - - virtual void setupUi() = 0; - - /// triggers widgiet initialization at the page level. All widgets updated to - /// current setting values - virtual void initializeWidgets (const CSMSettings::SettingMap &settings) = 0; - - /// retrieve the list of settings local to the page. - CSMSettings::SettingList *getSettings(); - - void setObjectName(); - - protected: - - /// Create a block for the page. - /// Block is constructed using passed definition struct - /// Page level-layout is created and assigned - template - AbstractBlock *buildBlock (T *def) - { - S *block = new S (this); - int ret = block->build (def); - - if (ret < 0) - return 0; - - QGroupBox *box = block->getGroupBox(); - QWidget::layout()->addWidget (box); - - return block; - } - - }; -} - -#endif // ABSTRACTPAGE_HPP diff --git a/apps/opencs/view/settings/abstractwidget.cpp b/apps/opencs/view/settings/abstractwidget.cpp deleted file mode 100644 index f268d3b27..000000000 --- a/apps/opencs/view/settings/abstractwidget.cpp +++ /dev/null @@ -1,78 +0,0 @@ -#include "abstractwidget.hpp" - -#include -#include - -void CSVSettings::AbstractWidget::build(QWidget *widget, WidgetDef &def, bool noLabel) -{ - if (!mLayout) - createLayout(def.orientation, true); - - buildLabelAndWidget (widget, def, noLabel); - -} - -void CSVSettings::AbstractWidget::buildLabelAndWidget (QWidget *widget, WidgetDef &def, bool noLabel) -{ - if (def.widgetWidth > -1) - widget->setFixedWidth (def.widgetWidth); - - if (!(def.caption.isEmpty() || noLabel) ) - { - QLabel *label = new QLabel (def.caption, &dynamic_cast( *parent())); - label->setBuddy (widget); - mLayout->addWidget (label); - - if (def.labelWidth > -1) - label->setFixedWidth(def.labelWidth); - } - - mLayout->addWidget (widget); - mLayout->setAlignment (widget, getAlignment (def.widgetAlignment)); -} - -void CSVSettings::AbstractWidget::createLayout - (Orientation direction, bool isZeroMargin) -{ - if (direction == Orient_Vertical) - mLayout = new QVBoxLayout (); - else - mLayout = new QHBoxLayout (); - - if (isZeroMargin) - mLayout->setContentsMargins(0, 0, 0, 0); -} - -QFlags CSVSettings::AbstractWidget::getAlignment (CSVSettings::Alignment flag) -{ - return QFlags(static_cast(flag)); -} - -QLayout *CSVSettings::AbstractWidget::getLayout() -{ - return mLayout; -} - -void CSVSettings::AbstractWidget::slotUpdateWidget (const QString &value) -{ - updateWidget (value); -} - -void CSVSettings::AbstractWidget::slotUpdateItem(const QString &value) -{ - emit signalUpdateItem (value); -} - -void CSVSettings::AbstractWidget::slotUpdateItem(bool value) -{ - if (value) - emit signalUpdateItem (widget()->objectName()); -} - -void CSVSettings::AbstractWidget::slotUpdateItem(int value) -{ - emit signalUpdateItem (QString::number(value)); -} - -void CSVSettings::AbstractWidget::slotUpdateItem (QListWidgetItem* current, QListWidgetItem* previous) -{} diff --git a/apps/opencs/view/settings/abstractwidget.hpp b/apps/opencs/view/settings/abstractwidget.hpp deleted file mode 100644 index 325de2bd2..000000000 --- a/apps/opencs/view/settings/abstractwidget.hpp +++ /dev/null @@ -1,69 +0,0 @@ -#ifndef ABSTRACTWIDGET_HPP -#define ABSTRACTWIDGET_HPP - -#include -#include "support.hpp" - -class QLayout; - -namespace CSVSettings -{ - /// Abstract base class for widgets which are used in user preferences dialog - class AbstractWidget : public QObject - { - Q_OBJECT - - QLayout *mLayout; - - public: - - /// Passed layout is assigned the constructed widget. - /// if no layout is passed, one is created. - explicit AbstractWidget (QLayout *layout = 0, QWidget* parent = 0) - : QObject (parent), mLayout (layout) - {} - - /// retrieve layout for insertion into itemblock - QLayout *getLayout(); - - /// create the derived widget instance - void build (QWidget* widget, WidgetDef &def, bool noLabel = false); - - /// reference to the derived widget instance - virtual QWidget *widget() = 0; - - protected: - - /// Callback called by receiving slot for widget udpates - virtual void updateWidget (const QString &value) = 0; - - /// Converts user-defined enum to Qt equivalents - QFlags getAlignment (Alignment flag); - - private: - - /// Creates layout and assigns label and widget as appropriate - void createLayout (Orientation direction, bool isZeroMargin); - - /// Creates label and widget according to passed definition - void buildLabelAndWidget (QWidget *widget, WidgetDef &def, bool noLabel); - - - signals: - - /// outbound update signal - void signalUpdateItem (const QString &value); - - public slots: - - /// receives inbound updates - void slotUpdateWidget (const QString &value); - - /// Overloads for outbound updates from derived widget signal - void slotUpdateItem (const QString &value); - void slotUpdateItem (bool value); - void slotUpdateItem (int value); - void slotUpdateItem (QListWidgetItem* current, QListWidgetItem* previous); - }; -} -#endif // ABSTRACTWIDGET_HPP diff --git a/apps/opencs/view/settings/blankpage.cpp b/apps/opencs/view/settings/blankpage.cpp deleted file mode 100644 index 837a31bee..000000000 --- a/apps/opencs/view/settings/blankpage.cpp +++ /dev/null @@ -1,50 +0,0 @@ -#include "blankpage.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::BlankPage::BlankPage(QWidget *parent): - AbstractPage("Blank", parent) -{ - -} - -CSVSettings::BlankPage::BlankPage(const QString &title, QWidget *parent): - AbstractPage(title, parent) -{ - // Hacks to get the stylesheet look properly -#ifdef Q_OS_MAC - QPlastiqueStyle *style = new QPlastiqueStyle; - //profilesComboBox->setStyle(style); -#endif - - setupUi(); -} - -void CSVSettings::BlankPage::setupUi() -{ - QGroupBox *pageBox = new QGroupBox(this); - layout()->addWidget(pageBox); -} - -void CSVSettings::BlankPage::initializeWidgets (const CSMSettings::SettingMap &settings) -{ - //iterate each item in each blocks in this section - //validate the corresponding setting against the defined valuelist if any. - foreach (AbstractBlock *block, mAbstractBlocks) - block->updateSettings (settings); -} diff --git a/apps/opencs/view/settings/blankpage.hpp b/apps/opencs/view/settings/blankpage.hpp deleted file mode 100644 index 07049fb71..000000000 --- a/apps/opencs/view/settings/blankpage.hpp +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef BLANKPAGE_HPP -#define BLANKPAGE_HPP - -#include "abstractpage.hpp" - -class QGroupBox; - -namespace CSVSettings { - - class UserSettings; - class AbstractBlock; - - /// Derived page with no widgets - /// Reference use only. - class BlankPage : public AbstractPage - { - - public: - - BlankPage (QWidget *parent = 0); - BlankPage (const QString &title, QWidget *parent); - - void setupUi(); - void initializeWidgets (const CSMSettings::SettingMap &settings); - }; -} - -#endif // BLANKPAGE_HPP diff --git a/apps/opencs/view/settings/customblock.cpp b/apps/opencs/view/settings/customblock.cpp deleted file mode 100644 index bbceafabe..000000000 --- a/apps/opencs/view/settings/customblock.cpp +++ /dev/null @@ -1,121 +0,0 @@ -#include "customblock.hpp" -#include "groupblock.hpp" -#include "itemblock.hpp" -#include "proxyblock.hpp" - -CSVSettings::CustomBlock::CustomBlock (QWidget *parent) : AbstractBlock (parent) -{ -} - -int CSVSettings::CustomBlock::build(GroupBlockDefList &defList, GroupBlockDefList::iterator *it) -{ - int retVal = 0; - - GroupBlockDefList::iterator defaultIt; - GroupBlockDefList::iterator listIt = defList.begin(); - GroupBlockDefList::iterator proxyIt = defaultIt; - - if (it) - listIt = *it; - - ProxyBlock *proxyBlock = new ProxyBlock(getParent()); - - for (; listIt != defList.end(); ++listIt) - { - if (!(*listIt)->isProxy) - retVal = buildGroupBlock (*listIt); - else - { - mGroupList << proxyBlock; - proxyIt = listIt; - } - } - - if (proxyIt != defaultIt) - retVal = buildProxyBlock (*proxyIt, proxyBlock); - - return retVal; -} - -CSVSettings::GroupBox *CSVSettings::CustomBlock::buildGroupBox (Orientation orientation) -{ - GroupBox *box = new GroupBox (false, mBox); - createLayout (orientation, true, box); - - return box; -} - -int CSVSettings::CustomBlock::buildGroupBlock(GroupBlockDef *def) -{ - GroupBlock *block = new GroupBlock (getParent()); - - mGroupList << block; - - connect (block, SIGNAL (signalUpdateSetting(const QString &, const QString &)), - this, SLOT (slotUpdateSetting (const QString &, const QString &))); - - return block->build(def); -} - -int CSVSettings::CustomBlock::buildProxyBlock(GroupBlockDef *def, ProxyBlock *block) -{ - if (def->settingItems.size() != 1) - return -1; - - int retVal = block->build(def); - - if (retVal != 0) - return retVal; - - // The first settingItem is the proxy setting, containing the list of settings bound to it. - foreach (QStringList *list, *(def->settingItems.at(0)->proxyList)) - { - QString proxiedBlockName = list->at(0); - - //iterate each group in the custom block, matching it to each proxied setting - //and connecting it appropriately - foreach (GroupBlock *groupBlock, mGroupList) - { - ItemBlock *proxiedBlock = groupBlock->getItemBlock (proxiedBlockName); - - if (proxiedBlock) - { - block->addSetting(proxiedBlock, list); - - //connect the proxy block's update signal to the custom block's slot - connect (block, SIGNAL (signalUpdateSetting (const QString &, const QString &)), - this, SLOT (slotUpdateSetting (const QString &, const QString &))); - } - } - } - - return 0; -} - -CSMSettings::SettingList *CSVSettings::CustomBlock::getSettings() -{ - CSMSettings::SettingList *settings = new CSMSettings::SettingList(); - - foreach (GroupBlock *block, mGroupList) - { - CSMSettings::SettingList *groupSettings = block->getSettings(); - - if (groupSettings) - settings->append(*groupSettings); - } - - return settings; -} - -bool CSVSettings::CustomBlock::updateSettings (const CSMSettings::SettingMap &settings) -{ - bool success = true; - - foreach (GroupBlock *block, mGroupList) - { - bool success2 = block->updateSettings (settings); - success = success && success2; - } - - return success; -} diff --git a/apps/opencs/view/settings/customblock.hpp b/apps/opencs/view/settings/customblock.hpp deleted file mode 100644 index 54c50f395..000000000 --- a/apps/opencs/view/settings/customblock.hpp +++ /dev/null @@ -1,47 +0,0 @@ -#ifndef CUSTOMBLOCK_HPP -#define CUSTOMBLOCK_HPP - -#include "abstractblock.hpp" - -namespace CSVSettings -{ - - class ProxyBlock; - - /// Base class for customized user preference setting blocks - /// Special block classes should be derived from CustomBlock - class CustomBlock : public AbstractBlock - { - - protected: - - GroupBlockList mGroupList; - - public: - - explicit CustomBlock (QWidget *parent = 0); - - /// Update settings local to the block - bool updateSettings (const CSMSettings::SettingMap &settings); - - /// Retrieve settings local to the block - CSMSettings::SettingList *getSettings(); - - /// construct the block using the passed definition - int build (GroupBlockDefList &defList, GroupBlockDefList::Iterator *it = 0); - - protected: - - /// construct the block groupbox - GroupBox *buildGroupBox (Orientation orientation); - - private: - - /// Construction function for creating a standard GroupBlock child - int buildGroupBlock(GroupBlockDef *def); - - /// Construction function for creating a standard ProxyBlock child - int buildProxyBlock(GroupBlockDef *def, ProxyBlock *block); - }; -} -#endif // CUSTOMBLOCK_HPP diff --git a/apps/opencs/view/settings/datadisplayformatpage.cpp b/apps/opencs/view/settings/datadisplayformatpage.cpp deleted file mode 100755 index 332b68f5c..000000000 --- a/apps/opencs/view/settings/datadisplayformatpage.cpp +++ /dev/null @@ -1,57 +0,0 @@ -#include "datadisplayformatpage.hpp" -#include "groupblock.hpp" -#include "../../model/settings/usersettings.hpp" - -CSVSettings::DataDisplayFormatPage::DataDisplayFormatPage(QWidget* parent) : - AbstractPage("Display Format", parent) -{ - setupUi(); -} - -CSVSettings::GroupBlockDef *CSVSettings::DataDisplayFormatPage::setupDataDisplay( const QString &title) -{ - GroupBlockDef *statusBlock = new GroupBlockDef(QString(title)); - - SettingsItemDef *statusItem = new SettingsItemDef (statusBlock->title, "Icon Only"); - *(statusItem->valueList) << QString("Icon and Text") << QString("Icon Only") << QString("Text Only"); - - WidgetDef statusWidget (Widget_RadioButton); - statusWidget.valueList = statusItem->valueList; - - statusItem->widget = statusWidget; - - statusBlock->settingItems << statusItem; - - statusBlock->isZeroMargin = false; - - return statusBlock; -} - - -void CSVSettings::DataDisplayFormatPage::setupUi() -{ - - mAbstractBlocks << buildBlock (setupDataDisplay ("Record Status Display")); - mAbstractBlocks << buildBlock (setupDataDisplay ("Referenceable ID Type Display")); - - foreach (AbstractBlock *block, mAbstractBlocks) - { - connect (block, SIGNAL (signalUpdateSetting (const QString &, const QString &)), - this, SIGNAL (signalUpdateEditorSetting (const QString &, const QString &)) ); - } - - connect ( this, - SIGNAL ( signalUpdateEditorSetting (const QString &, const QString &)), - &(CSMSettings::UserSettings::instance()), - SIGNAL ( signalUpdateEditorSetting (const QString &, const QString &))); - -} - -void CSVSettings::DataDisplayFormatPage::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/datadisplayformatpage.hpp b/apps/opencs/view/settings/datadisplayformatpage.hpp deleted file mode 100755 index b785bbd23..000000000 --- a/apps/opencs/view/settings/datadisplayformatpage.hpp +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef EDITORPAGE_HPP -#define EDITORPAGE_HPP - -#include "support.hpp" -#include "abstractpage.hpp" - -namespace CSVSettings -{ - class DataDisplayFormatPage : public AbstractPage - { - Q_OBJECT - - public: - explicit DataDisplayFormatPage(QWidget *parent = 0); - - void initializeWidgets (const CSMSettings::SettingMap &settings); - void setupUi(); - - private: - - /// User preference view of the record status delegate's icon / text setting - GroupBlockDef *setupDataDisplay(const QString &); - - signals: - - /// Signals up for changes to editor application-level settings - void signalUpdateEditorSetting (const QString &settingName, const QString &settingValue); - - public slots: - }; -} - -#endif // EDITORPAGE_HPP diff --git a/apps/opencs/view/settings/editorpage.cpp b/apps/opencs/view/settings/editorpage.cpp deleted file mode 100644 index 153ac1551..000000000 --- a/apps/opencs/view/settings/editorpage.cpp +++ /dev/null @@ -1,53 +0,0 @@ -#include "editorpage.hpp" -#include "groupblock.hpp" -#include "../../model/settings/usersettings.hpp" - -CSVSettings::EditorPage::EditorPage(QWidget* parent) : - AbstractPage("Display Format", parent) -{ - setupUi(); -} - -CSVSettings::GroupBlockDef *CSVSettings::EditorPage::setupRecordStatusDisplay() -{ - GroupBlockDef *statusBlock = new GroupBlockDef(QString("Record Status Display")); - - SettingsItemDef *statusItem = new SettingsItemDef (statusBlock->title, "Icon and Text"); - *(statusItem->valueList) << QString("Icon and Text") << QString("Icon Only") << QString("Text Only"); - - WidgetDef statusWidget (Widget_RadioButton); - statusWidget.valueList = statusItem->valueList; - - statusItem->widget = statusWidget; - - statusBlock->settingItems << statusItem; - - return statusBlock; -} - -void CSVSettings::EditorPage::setupUi() -{ - - mAbstractBlocks << buildBlock(setupRecordStatusDisplay()); - - foreach (AbstractBlock *block, mAbstractBlocks) - { - connect (block, SIGNAL (signalUpdateSetting (const QString &, const QString &)), - this, SIGNAL (signalUpdateEditorSetting (const QString &, const QString &)) ); - } - - connect ( this, - SIGNAL ( signalUpdateEditorSetting (const QString &, const QString &)), - &(CSMSettings::UserSettings::instance()), - SIGNAL ( signalUpdateEditorSetting (const QString &, const QString &))); - -} - -void CSVSettings::EditorPage::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/editorpage.hpp b/apps/opencs/view/settings/editorpage.hpp deleted file mode 100644 index 85215edab..000000000 --- a/apps/opencs/view/settings/editorpage.hpp +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef EDITORPAGE_HPP -#define EDITORPAGE_HPP - -#include "support.hpp" -#include "abstractpage.hpp" - -namespace CSVSettings -{ - class EditorPage : public AbstractPage - { - Q_OBJECT - - public: - explicit EditorPage(QWidget *parent = 0); - - void initializeWidgets (const CSMSettings::SettingMap &settings); - void setupUi(); - - private: - - /// User preference view of the record status delegate's icon / text setting - GroupBlockDef *setupRecordStatusDisplay(); - - signals: - - /// Signals up for changes to editor application-level settings - void signalUpdateEditorSetting (const QString &settingName, const QString &settingValue); - - public slots: - }; -} - -#endif // EDITORPAGE_HPP diff --git a/apps/opencs/view/settings/groupblock.cpp b/apps/opencs/view/settings/groupblock.cpp deleted file mode 100644 index e31e526c0..000000000 --- a/apps/opencs/view/settings/groupblock.cpp +++ /dev/null @@ -1,108 +0,0 @@ -#include "groupblock.hpp" -#include "itemblock.hpp" - -CSVSettings::GroupBlock::GroupBlock (QWidget* parent) - : AbstractBlock (parent) -{} - -CSVSettings::GroupBlock::GroupBlock (bool isVisible, QWidget *parent) - : AbstractBlock (isVisible, parent) -{} - -int CSVSettings::GroupBlock::build (GroupBlockDef *def) -{ - - if (def->settingItems.size() == 0) - return -1; - - int retVal = 0; - - setVisible (def->isVisible); - - mBox->setLayout(createLayout (def->widgetOrientation, def->isZeroMargin)); - - setObjectName (def->title); - mBox->setTitle (def->title); - - foreach (SettingsItemDef *itemDef, def->settingItems) - { - ItemBlock *block = new ItemBlock (mBox); - - if (block->build (*itemDef) < 0) - { - retVal = -2; - break; - } - - mItemBlockList << block; - mBox->layout()->addWidget (block->getGroupBox()); - - connect (block, SIGNAL (signalUpdateSetting (const QString &, const QString &)), - this, SLOT (slotUpdateSetting (const QString &, const QString &) )); - } - - return retVal; -} - -CSMSettings::SettingList *CSVSettings::GroupBlock::getSettings() -{ - CSMSettings::SettingList *settings = 0; - - foreach (ItemBlock *block, mItemBlockList) - { - if (!settings) - settings = new CSMSettings::SettingList(); - - settings->append(*(block->getSettings ())); - } - - return settings; -} - -CSVSettings::ItemBlock *CSVSettings::GroupBlock::getItemBlock (const QString &name, ItemBlockList *blockList) -{ - ItemBlock *retBlock = 0; - - if (!blockList) - blockList = &mItemBlockList; - - foreach (ItemBlock *block, *blockList) - { - if (block->objectName() == name) - { - retBlock = block; - break; - } - } - - return retBlock; -} - -CSVSettings::ItemBlock *CSVSettings::GroupBlock::getItemBlock (int index) -{ - ItemBlock *retBlock = 0; - - if (mItemBlockList.size() > index) - retBlock = mItemBlockList.at(index); - - return retBlock; -} - -bool CSVSettings::GroupBlock::updateSettings (const CSMSettings::SettingMap &settings) -{ - bool success = true; - - //update all non-proxy settings - foreach (ItemBlock *block, mItemBlockList) - { - CSMSettings::SettingContainer *setting = settings[block->objectName()]; - - if (setting) - { - bool success2 = block->update (setting->getValue()); - success = success && success2; - } - } - - return success; -} diff --git a/apps/opencs/view/settings/groupblock.hpp b/apps/opencs/view/settings/groupblock.hpp deleted file mode 100644 index 5c0754193..000000000 --- a/apps/opencs/view/settings/groupblock.hpp +++ /dev/null @@ -1,43 +0,0 @@ -#ifndef GROUPBLOCK_HPP -#define GROUPBLOCK_HPP - -#include -#include "abstractblock.hpp" - -namespace CSVSettings -{ - class ItemBlock; - - /// Base class for group blocks. - /// Derived block classes should use CustomBlock - class GroupBlock : public AbstractBlock - { - ItemBlockList mItemBlockList; - - public: - GroupBlock (QWidget* parent = 0); - GroupBlock (bool isVisible, QWidget *parent = 0); - - /// build the gorup block based on passed definition - int build (GroupBlockDef *def); - - /// update settings local to the group block - bool updateSettings (const CSMSettings::SettingMap &settings); - - /// retrieve setting list local to the group block - CSMSettings::SettingList *getSettings(); - - /// retrieve item block by name from the passed list or local list - ItemBlock *getItemBlock (const QString &name, ItemBlockList *blockList = 0); - - /// retrieve the item block by index from the local list - ItemBlock *getItemBlock (int index); - - protected: - - /// create block layout based on passed definition - int buildLayout (GroupBlockDef &def); - - }; -} -#endif // GROUPBLOCK_HPP diff --git a/apps/opencs/view/settings/groupbox.cpp b/apps/opencs/view/settings/groupbox.cpp deleted file mode 100644 index da2cc2571..000000000 --- a/apps/opencs/view/settings/groupbox.cpp +++ /dev/null @@ -1,56 +0,0 @@ -#include "groupbox.hpp" - -const QString CSVSettings::GroupBox::INVISIBLE_BOX_STYLE = - QString::fromUtf8("QGroupBox { border: 0px; padding 0px; margin: 0px;}"); - -CSVSettings::GroupBox::GroupBox(QWidget *parent) : - QGroupBox (parent) -{ - initBox(); -} - -CSVSettings::GroupBox::GroupBox (bool isVisible, QWidget *parent) : - QGroupBox (parent) -{ - initBox(isVisible); -} - -void CSVSettings::GroupBox::initBox(bool isVisible) -{ - setFlat (true); - VISIBLE_BOX_STYLE = styleSheet(); - - if (!isVisible) - setStyleSheet (INVISIBLE_BOX_STYLE); -} - -bool CSVSettings::GroupBox::borderVisibile() const -{ - return (styleSheet() != INVISIBLE_BOX_STYLE); -} - -void CSVSettings::GroupBox::setTitle (const QString &title) -{ - if (borderVisibile() ) - { - QGroupBox::setTitle (title); - setMinimumWidth(); - } -} - -void CSVSettings::GroupBox::setBorderVisibility (bool value) -{ - if (value) - setStyleSheet(VISIBLE_BOX_STYLE); - else - setStyleSheet(INVISIBLE_BOX_STYLE); -} - -void CSVSettings::GroupBox::setMinimumWidth() -{ - //set minimum width to accommodate title, if needed - //1.5 multiplier to account for bold title. - QFontMetrics fm (font()); - int minWidth = fm.width(title()); - QGroupBox::setMinimumWidth (minWidth * 1.5); -} diff --git a/apps/opencs/view/settings/groupbox.hpp b/apps/opencs/view/settings/groupbox.hpp deleted file mode 100644 index 9d3a01936..000000000 --- a/apps/opencs/view/settings/groupbox.hpp +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef GROUPBOX_HPP -#define GROUPBOX_HPP - -#include - -namespace CSVSettings -{ - /// Custom implementation of QGroupBox to be used with block classes - class GroupBox : public QGroupBox - { - static const QString INVISIBLE_BOX_STYLE; - QString VISIBLE_BOX_STYLE; //not a const... - - public: - explicit GroupBox (QWidget *parent = 0); - explicit GroupBox (bool isVisible, QWidget *parent = 0); - - void setTitle (const QString &title); - void setBorderVisibility (bool value); - bool borderVisibile() const; - - private: - void setMinimumWidth(); - void initBox(bool isVisible = true); - }; -} - -#endif // GROUPBOX_HPP diff --git a/apps/opencs/view/settings/itemblock.cpp b/apps/opencs/view/settings/itemblock.cpp deleted file mode 100644 index 9cb0ae1a1..000000000 --- a/apps/opencs/view/settings/itemblock.cpp +++ /dev/null @@ -1,115 +0,0 @@ -#include "itemblock.hpp" - -#include - -CSVSettings::ItemBlock::ItemBlock (QWidget* parent) - : mSetting (0), AbstractBlock (false, parent) -{ -} - -int CSVSettings::ItemBlock::build(SettingsItemDef &iDef) -{ - buildItemBlock (iDef); - buildItemBlockWidgets (iDef); - - return 0; -} - -void CSVSettings::ItemBlock::buildItemBlockWidgets (SettingsItemDef &iDef) -{ - WidgetDef wDef = iDef.widget; - QLayout *blockLayout = 0; - QString defaultValue = iDef.defaultValue; - - switch (wDef.type) - { - - case Widget_CheckBox: - case Widget_RadioButton: - - foreach (QString item, *(iDef.valueList)) - { - wDef.caption = item; - wDef.isDefault = (item == defaultValue); - - blockLayout = buildWidget (item, wDef, blockLayout)->getLayout(); - } - - break; - - case Widget_ComboBox: - case Widget_ListBox: - - //assign the item's value list to the widget's value list. - //pass through to default to finish widget construction. - if (!wDef.valueList) - wDef.valueList = iDef.valueList; - - default: - //only one instance of this non-list widget type. - //Set it's value to the default value for the item and build the widget. - - if (wDef.value.isEmpty()) - wDef.value = iDef.defaultValue; - - buildWidget (iDef.name, wDef); - } -} - -void CSVSettings::ItemBlock::buildItemBlock (SettingsItemDef &iDef) -{ - QString defaultValue = iDef.defaultValue; - - setObjectName(iDef.name); - - mSetting = new CSMSettings::SettingsItem (objectName(), - iDef.hasMultipleValues, iDef.defaultValue, - parent()); - - if (iDef.valueList) - mSetting->setValueList(iDef.valueList); - - if (!iDef.minMax.isEmpty()) - mSetting->setValuePair(iDef.minMax); -} - - -bool CSVSettings::ItemBlock::update (const QString &value) -{ - bool success = updateItem (value); - - if (success) - signalUpdateWidget (value); - - return success; -} - - -bool CSVSettings::ItemBlock::updateItem (const QString &value) -{ - return mSetting->updateItem(value); -} - - -bool CSVSettings::ItemBlock::updateBySignal(const QString &name, const QString &value, bool &doEmit) -{ - bool success = (mSetting->getValue() != value); - - if (success) - success = updateItem(value); - - return success; -} - -CSMSettings::SettingList *CSVSettings::ItemBlock::getSettings () -{ - CSMSettings::SettingList *list = new CSMSettings::SettingList(); - list->push_back(mSetting); - - return list; -} - -QString CSVSettings::ItemBlock::getValue() const -{ - return mSetting->getValue(); -} diff --git a/apps/opencs/view/settings/itemblock.hpp b/apps/opencs/view/settings/itemblock.hpp deleted file mode 100644 index 2d1d45d41..000000000 --- a/apps/opencs/view/settings/itemblock.hpp +++ /dev/null @@ -1,48 +0,0 @@ -#ifndef ITEMBLOCK_HPP -#define ITEMBLOCK_HPP - -#include "abstractblock.hpp" - -namespace CSVSettings -{ - - class ItemBlock : public AbstractBlock - { - CSMSettings::SettingsItem *mSetting; - WidgetList mWidgetList; - - public: - - ItemBlock (QWidget* parent = 0); - - /// pure virtual function not implemented - bool updateSettings (const CSMSettings::SettingMap &settings) { return false; } - - CSMSettings::SettingList *getSettings (); - - QString getValue () const; - - /// item blocks encapsulate only one setting - int getSettingCount(); - - /// update setting value and corresponding widget - bool update (const QString &value); - - /// virtual construction function - int build(SettingsItemDef &iDef); - - private: - - /// custom construction function - void buildItemBlock (SettingsItemDef& iDef); - void buildItemBlockWidgets (SettingsItemDef& iDef); - - /// update the setting value - bool updateItem (const QString &); - - /// callback function triggered when update to application level is signalled - bool updateBySignal (const QString &name, const QString &value, bool &doEmit); - }; -} - -#endif // ITEMBLOCK_HPP diff --git a/apps/opencs/view/settings/proxyblock.cpp b/apps/opencs/view/settings/proxyblock.cpp deleted file mode 100644 index 81cc54fca..000000000 --- a/apps/opencs/view/settings/proxyblock.cpp +++ /dev/null @@ -1,152 +0,0 @@ -#include "proxyblock.hpp" -#include "itemblock.hpp" - -CSVSettings::ProxyBlock::ProxyBlock (QWidget *parent) - : GroupBlock (parent) -{ -} -int CSVSettings::ProxyBlock::build (GroupBlockDef *proxyDef) -{ - //get the list of pre-defined values for the proxy - mValueList = proxyDef->settingItems.at(0)->valueList; - - bool success = GroupBlock::build(proxyDef); - - //connect the item block of the proxy setting to the proxy-update slot - connect (getItemBlock(0), SIGNAL (signalUpdateSetting(const QString &, const QString &)), - this, SLOT (slotUpdateProxySetting (const QString &, const QString &))); - - return success; -} - -void CSVSettings::ProxyBlock::addSetting (ItemBlock *settingBlock, QStringList *proxyList) -{ - //connect the item block of the proxied seting to the generic update slot - connect (settingBlock, SIGNAL (signalUpdateSetting(const QString &, const QString &)), - this, SLOT (slotUpdateProxySetting(const QString &, const QString &))); - - mProxiedItemBlockList << settingBlock; - mProxyList << proxyList; -} - -bool CSVSettings::ProxyBlock::updateSettings (const CSMSettings::SettingMap &settings) -{ - return updateByProxiedSettings(&settings); -} - -bool CSVSettings::ProxyBlock::updateBySignal(const QString &name, const QString &value, bool &doEmit) -{ - doEmit = false; - return updateProxiedSettings(); -} - -void CSVSettings::ProxyBlock::slotUpdateProxySetting (const QString &name, const QString &value) -{ - updateByProxiedSettings(); -} - -bool CSVSettings::ProxyBlock::updateProxiedSettings() -{ - foreach (ItemBlock *block, mProxiedItemBlockList) - { - QString value = getItemBlock(0)->getValue(); - - bool success = false; - int i = 0; - - //find the value index of the selected value in the proxy setting - for (; i < mValueList->size(); ++i) - { - success = (value == mValueList->at(i)); - - if (success) - break; - } - - if (!success) - return false; - - // update the containing the proxied item's name - foreach (QStringList *list, mProxyList) - { - if ( list->at(0) == block->objectName()) - block->update (list->at(++i)); - } - } - - return true; -} - -bool CSVSettings::ProxyBlock::updateByProxiedSettings(const CSMSettings::SettingMap *settings) -{ - bool success = false; - int commonIndex = -1; - - //update all proxy settings based on values from non-proxies - foreach (QStringList *list, mProxyList) - { - //Iterate each proxy item's proxied setting list, getting the current values - //Compare those value indices. - //If indices match, they correlate to one of the proxy's values in it's value list - - //first value is always the name of the setting the proxy setting manages - QStringList::Iterator itProxyValue = list->begin(); - QString proxiedSettingName = (*itProxyValue); - QString proxiedSettingValue = ""; - itProxyValue++; - - if (!settings) - { - //get the actual setting value - ItemBlock *block = getProxiedItemBlock (proxiedSettingName); - - if (block) - proxiedSettingValue = block->getValue(); - } - else - proxiedSettingValue = (*settings)[proxiedSettingName]->getValue(); - - int j = 0; - - //iterate each value in the proxy string list - for (; itProxyValue != (list)->end(); ++itProxyValue) - { - success = ((*itProxyValue) == proxiedSettingValue); - - if (success) - break; - - j++; - } - - //break if no match was found - if ( !success ) - break; - - if (commonIndex != -1) - success = (commonIndex == j); - else - commonIndex = j; - - //break if indices were found, but mismatch - if (!success) - break; - } - - //if successful, the proxied setting values match a pre-defined value in the - //proxy's value list. Set the proxy to that value index - if (success) - { - ItemBlock *block = getItemBlock(0); - - if (block) - block->update (mValueList->at(commonIndex)); - } - - return success; -} - -CSVSettings::ItemBlock *CSVSettings::ProxyBlock::getProxiedItemBlock (const QString &name) -{ - return getItemBlock (name, &mProxiedItemBlockList); -} diff --git a/apps/opencs/view/settings/proxyblock.hpp b/apps/opencs/view/settings/proxyblock.hpp deleted file mode 100644 index 90fb9bc97..000000000 --- a/apps/opencs/view/settings/proxyblock.hpp +++ /dev/null @@ -1,52 +0,0 @@ -#ifndef PROXYBLOCK_HPP -#define PROXYBLOCK_HPP - -#include "groupblock.hpp" - -namespace CSVSettings -{ - class ProxyBlock : public GroupBlock - { - Q_OBJECT - - /// TODO: Combine mProxyItemBlockList and mProxyList. - ItemBlockList mProxiedItemBlockList; - ProxyList mProxyList; - QStringList *mValueList; - - public: - - explicit ProxyBlock (QWidget *parent = 0); - explicit ProxyBlock (ItemBlock *proxyItemBlock, QWidget *parent = 0); - - /// Add a block that contains a proxied setting to the proxy block. - void addSetting (ItemBlock* settingBlock, QStringList *proxyList); - - int build (GroupBlockDef *def); - - CSMSettings::SettingList *getSettings() { return 0; } - - /// Update settings local to the proxy block pushed from application level - bool updateSettings (const CSMSettings::SettingMap &settings); - - /// callback function triggered when update to the application level is signaled. - bool updateBySignal (const QString &name, const QString &value, bool &doEmit); - - private: - - /// return the item block of a proxied setting - ItemBlock *getProxiedItemBlock (const QString &name); - - /// update the proxy setting with data from the proxied settings - bool updateByProxiedSettings(const CSMSettings::SettingMap *settings = 0); - - /// update proxied settings with data from the proxy setting - bool updateProxiedSettings(); - - private slots: - - void slotUpdateProxySetting (const QString &name, const QString &value); - - }; -} -#endif // PROXYBLOCK_HPP diff --git a/apps/opencs/view/settings/settingwidget.cpp b/apps/opencs/view/settings/settingwidget.cpp deleted file mode 100644 index 2c93986e7..000000000 --- a/apps/opencs/view/settings/settingwidget.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "settingwidget.hpp" diff --git a/apps/opencs/view/settings/settingwidget.hpp b/apps/opencs/view/settings/settingwidget.hpp deleted file mode 100644 index 9f4513671..000000000 --- a/apps/opencs/view/settings/settingwidget.hpp +++ /dev/null @@ -1,214 +0,0 @@ -#ifndef SETTINGWIDGET_HPP -#define SETTINGWIDGET_HPP - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "abstractwidget.hpp" - -namespace CSVSettings -{ - - /// Generic template for radiobuttons / checkboxes - template - class SettingWidget : public AbstractWidget - { - - T1 *mWidget; - - public: - - explicit SettingWidget (WidgetDef &def, QLayout *layout, QWidget* parent = 0) - : AbstractWidget (layout, parent), mWidget (new T1 (parent)) - { - mWidget->setText(def.caption); - build (mWidget, def, true); - mWidget->setChecked(def.isDefault); - - connect (mWidget, SIGNAL (toggled (bool)), - this, SLOT (slotUpdateItem (bool))); - } - - QWidget *widget() { return mWidget; } - - private: - - void updateWidget (const QString &value) - { - if ( value == mWidget->objectName() && !mWidget->isChecked() ) - mWidget->setChecked (true); - } - }; - - /// spin box template - template <> - class SettingWidget : public AbstractWidget - { - - QSpinBox *mWidget; - - public: - - SettingWidget (WidgetDef &def, QLayout *layout, QWidget *parent = 0) - : AbstractWidget (layout, parent), mWidget (new QSpinBox (parent)) - { - def.caption += tr(" (%1 to %2)").arg(def.minMax->left).arg(def.minMax->right); - - mWidget->setMaximum (def.minMax->right.toInt()); - mWidget->setMinimum (def.minMax->left.toInt()); - mWidget->setValue (def.value.toInt()); - - build (mWidget, def); - - connect (mWidget, SIGNAL (valueChanged (int)), - this, SLOT (slotUpdateItem (int))); - - mWidget->setAlignment (getAlignment(def.valueAlignment)); - - - } - - QWidget *widget() { return mWidget; } - - private: - - void updateWidget (const QString &value) - { - int intVal = value.toInt(); - - if (intVal >= mWidget->minimum() && intVal <= mWidget->maximum() && intVal != mWidget->value()) - mWidget->setValue (intVal); - } - - signals: - - }; - - /// combo box template - template <> - class SettingWidget : public CSVSettings::AbstractWidget - { - - QComboBox *mWidget; - - - public: - - explicit SettingWidget(WidgetDef &def, QLayout *layout, QWidget *parent = 0) - : AbstractWidget (layout, parent), mWidget (new QComboBox (parent)) - { - int i = 0; - - foreach (QString item, *(def.valueList)) - { - mWidget->addItem (item); - - if (item == def.value) - mWidget->setCurrentIndex(i); - - i++; - } - - build (mWidget, def); - - connect (mWidget, SIGNAL (currentIndexChanged (const QString &)), - this, SLOT (slotUpdateItem (const QString &))); - - //center the combo box items - mWidget->setEditable (true); - mWidget->lineEdit()->setReadOnly (true); - mWidget->lineEdit()->setAlignment (getAlignment(def.valueAlignment)); - - QFlags alignment = mWidget->lineEdit()->alignment(); - - for (int j = 0; j < mWidget->count(); j++) - mWidget->setItemData (j, QVariant(alignment), Qt::TextAlignmentRole); - } - - QWidget *widget() { return mWidget; } - - private: - - void updateWidget (const QString &value) - { - if (mWidget->currentText() != value) - mWidget->setCurrentIndex(mWidget->findText(value)); - } - - }; - - /// line edit template - template <> - class SettingWidget : public CSVSettings::AbstractWidget - { - - QLineEdit *mWidget; - - public: - - explicit SettingWidget(WidgetDef &def, QLayout *layout, QWidget *parent = 0) - : AbstractWidget (layout, parent), mWidget (new QLineEdit (parent)) - { - if (!def.inputMask.isEmpty()) - mWidget->setInputMask (def.inputMask); - - mWidget->setText (def.value); - - build (mWidget, def); - - connect (mWidget, SIGNAL (textChanged (const QString &)), - this, SLOT (slotUpdateItem (const QString &))); - - mWidget->setAlignment (getAlignment(def.valueAlignment)); - } - - QWidget *widget() { return mWidget; } - - void updateWidget (const QString &value) - { - if (mWidget->text() != value) - mWidget->setText(value); - } - }; - - /// list widget template - /// \todo Not fully implemented. Only widget supporting multi-valued settings - template <> - class SettingWidget : public CSVSettings::AbstractWidget - { - - QListWidget *mWidget; - - public: - - explicit SettingWidget(WidgetDef &def, QLayout *layout, QWidget *parent = 0 ) - : AbstractWidget (layout, parent), mWidget (new QListWidget (parent)) - { - int i = 0; - - foreach (QString item, *(def.valueList)) - { - mWidget->addItem (item); - - if (item == def.value) {} - i++; - } - build (mWidget, def); - } - - QWidget *widget() { return mWidget; } - - private: - void updateWidget (const QString &value) {} - }; - -} -#endif // SETTINGWIDGET_HPP diff --git a/apps/opencs/view/settings/toggleblock.cpp b/apps/opencs/view/settings/toggleblock.cpp deleted file mode 100644 index 3406a62c4..000000000 --- a/apps/opencs/view/settings/toggleblock.cpp +++ /dev/null @@ -1,80 +0,0 @@ -#include "toggleblock.hpp" -#include "groupblock.hpp" -#include "groupbox.hpp" -#include "itemblock.hpp" - -CSVSettings::ToggleBlock::ToggleBlock(QWidget *parent) : - CustomBlock(parent) -{} - -int CSVSettings::ToggleBlock::build(CustomBlockDef *def) -{ - if (def->blockDefList.size()==0) - return -1; - - QList::Iterator it = def->blockDefList.begin(); - - //first def in the list is the def for the toggle block - GroupBlockDef *toggleDef = *it++; - - if (toggleDef->captions.size() != def->blockDefList.size()-1 ) - return -2; - - if (toggleDef->widgets.size() == 0) - return -3; - - //create the toogle block UI structure - QLayout *blockLayout = createLayout (def->blockOrientation, true); - GroupBox *propertyBox = buildGroupBox (toggleDef->widgetOrientation); - - mBox->setLayout(blockLayout); - mBox->setTitle (toggleDef->title); - - //build the blocks contained in the def list - //this manages proxy block construction. - //Any settings managed by the proxy setting - //must be included in the blocks defined in the list. - CustomBlock::build (def->blockDefList, &it); - - for (GroupBlockList::iterator it = mGroupList.begin(); it != mGroupList.end(); ++it) - propertyBox->layout()->addWidget ((*it)->getGroupBox()); - - //build togle widgets, linking them to the settings - GroupBox *toggleBox = buildToggleWidgets (toggleDef, def->defaultValue); - - blockLayout->addWidget(toggleBox); - blockLayout->addWidget(propertyBox); - blockLayout->setAlignment (propertyBox, Qt::AlignRight); - - return 0; -} - -CSVSettings::GroupBox *CSVSettings::ToggleBlock::buildToggleWidgets (GroupBlockDef *def, QString &defaultToggle) -{ - GroupBox *box = new GroupBox (false, getParent()); - - QLayout *layout = createLayout (def->widgetOrientation, true, static_cast(box)); - - for (int i = 0; i < def->widgets.size(); ++i) - { - QString caption = def->captions.at(i); - WidgetDef *wDef = def->widgets.at(i); - - wDef->caption = caption; - wDef->widgetAlignment = Align_Left; - - AbstractWidget *widg = buildWidget (caption, *wDef, layout, false); - - GroupBlock *block = mGroupList.at(i); - - //connect widget's update to the property block's enabled status - connect (widg->widget(), SIGNAL (toggled (bool)), block, SLOT (slotSetEnabled(bool))); - - //enable the default toggle option - block->getGroupBox()->setEnabled( caption == defaultToggle ); - - layout = widg->getLayout(); - } - - return box; -} diff --git a/apps/opencs/view/settings/toggleblock.hpp b/apps/opencs/view/settings/toggleblock.hpp deleted file mode 100644 index 4b6e8e344..000000000 --- a/apps/opencs/view/settings/toggleblock.hpp +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef TOGGLEBLOCK_HPP -#define TOGGLEBLOCK_HPP - -#include - -#include "customblock.hpp" - -namespace CSVSettings -{ - class GroupBlock; - class GroupBox; - class ToggleWidget; - class ItemBlock; - - class ToggleBlock : public CustomBlock - { - - public: - explicit ToggleBlock(QWidget *parent = 0); - - int build (CustomBlockDef *def); - - private: - /// Constructor for toggle widgets that are specific to toggle block - /// Widgets are not a part of the user preference settings - GroupBox *buildToggleWidgets (GroupBlockDef *def, QString &defaultToggle); - }; -} -#endif // TOGGLEBLOCK_HPP diff --git a/apps/opencs/view/settings/usersettingsdialog.cpp b/apps/opencs/view/settings/usersettingsdialog.cpp deleted file mode 100644 index e73e24dcb..000000000 --- a/apps/opencs/view/settings/usersettingsdialog.cpp +++ /dev/null @@ -1,119 +0,0 @@ -#include "usersettingsdialog.hpp" - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "../../model/settings/support.hpp" - -#include "datadisplayformatpage.hpp" -#include "windowpage.hpp" -#include "settingwidget.hpp" - -CSVSettings::UserSettingsDialog::UserSettingsDialog(QMainWindow *parent) : - QMainWindow (parent), mStackedWidget (0) -{ - setWindowTitle(QString::fromUtf8 ("User Settings")); - buildPages(); - setWidgetStates (); - - connect (mListWidget, - SIGNAL (currentItemChanged(QListWidgetItem*, QListWidgetItem*)), - this, - SLOT (slotChangePage (QListWidgetItem*, QListWidgetItem*))); - - QRect scr = QApplication::desktop()->screenGeometry(); - QRect rect = geometry(); - move (scr.center().x() - rect.center().x(), scr.center().y() - rect.center().y()); -} - -CSVSettings::UserSettingsDialog::~UserSettingsDialog() -{ -} - -void CSVSettings::UserSettingsDialog::closeEvent (QCloseEvent *event) -{ - writeSettings(); -} - -void CSVSettings::UserSettingsDialog::setWidgetStates () -{ - CSMSettings::UserSettings::instance().loadSettings("opencs.cfg"); - - //iterate the tabWidget's pages (sections) - for (int i = 0; i < mStackedWidget->count(); i++) - { - //get the settings defined for the entire section - //and update widget - QString pageName = mStackedWidget->widget(i)->objectName(); - - const CSMSettings::SettingMap *settings = CSMSettings::UserSettings::instance().getSettings(pageName); - AbstractPage &page = getAbstractPage (i); - page.initializeWidgets(*settings); - } -} - -void CSVSettings::UserSettingsDialog::buildPages() -{ - //craete central widget with it's layout and immediate children - QWidget *centralWidget = new QWidget (this); - - mListWidget = new QListWidget (centralWidget); - mStackedWidget = new QStackedWidget (centralWidget); - - QGridLayout* dialogLayout = new QGridLayout(); - - mListWidget->setMinimumWidth(0); - mListWidget->setSizePolicy (QSizePolicy::Preferred, QSizePolicy::Expanding); - - mStackedWidget->setSizePolicy (QSizePolicy::Fixed, QSizePolicy::Fixed); - - dialogLayout->addWidget (mListWidget,0,0); - dialogLayout->addWidget (mStackedWidget,0,1, Qt::AlignTop); - - centralWidget->setLayout (dialogLayout); - - setCentralWidget (centralWidget); - setDockOptions (QMainWindow::AllowNestedDocks); - - createPage(); - createPage(); - -} - -void CSVSettings::UserSettingsDialog::writeSettings() -{ - QMap settings; - - for (int i = 0; i < mStackedWidget->count(); ++i) - { - AbstractPage &page = getAbstractPage (i); - settings [page.objectName()] = page.getSettings(); - } - CSMSettings::UserSettings::instance().writeSettings(settings); -} - -CSVSettings::AbstractPage &CSVSettings::UserSettingsDialog::getAbstractPage (int index) -{ - return dynamic_cast (*(mStackedWidget->widget (index))); -} - -void CSVSettings::UserSettingsDialog::slotChangePage(QListWidgetItem *current, QListWidgetItem *previous) -{ - if (!current) - current = previous; - - if (!(current == previous)) - mStackedWidget->setCurrentIndex (mListWidget->row(current)); -} diff --git a/apps/opencs/view/settings/usersettingsdialog.hpp b/apps/opencs/view/settings/usersettingsdialog.hpp deleted file mode 100644 index 3b3fa5b79..000000000 --- a/apps/opencs/view/settings/usersettingsdialog.hpp +++ /dev/null @@ -1,71 +0,0 @@ -#ifndef USERSETTINGSDIALOG_H -#define USERSETTINGSDIALOG_H - -#include -#include -#include -#include - -#include "../../model/settings/usersettings.hpp" -#include "../../model/settings/support.hpp" - -class QHBoxLayout; -class AbstractWidget; -class QStackedWidget; -class QListWidget; - -namespace CSVSettings { - - class AbstractPage; - - class UserSettingsDialog : public QMainWindow - { - Q_OBJECT - - QListWidget *mListWidget; - QStackedWidget *mStackedWidget; - - public: - UserSettingsDialog(QMainWindow *parent = 0); - ~UserSettingsDialog(); - - private: - - /// Settings are written on close - void closeEvent (QCloseEvent *event); - - /// return the setting page by name - /// performs dynamic cast to AbstractPage * - AbstractPage &getAbstractPage (int index); - void setWidgetStates (); - void buildPages(); - void writeSettings(); - - /// Templated function to create a custom user preference page - template - void createPage () - { - T *page = new T(mStackedWidget); - - mStackedWidget->addWidget (&dynamic_cast(*page)); - - new QListWidgetItem (page->objectName(), mListWidget); - - //finishing touches - QFontMetrics fm (QApplication::font()); - int textWidth = fm.width(page->objectName()); - - if ((textWidth + 50) > mListWidget->minimumWidth()) - mListWidget->setMinimumWidth(textWidth + 50); - - resize (mStackedWidget->sizeHint()); - } - - public slots: - - /// Called when a different page is selected in the left-hand list widget - void slotChangePage (QListWidgetItem*, QListWidgetItem*); - }; - -} -#endif // USERSETTINGSDIALOG_H diff --git a/apps/opencs/view/settings/windowpage.cpp b/apps/opencs/view/settings/windowpage.cpp deleted file mode 100644 index ae42623b7..000000000 --- a/apps/opencs/view/settings/windowpage.cpp +++ /dev/null @@ -1,144 +0,0 @@ -#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" -#include "../../view/settings/abstractblock.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(); -} - -CSVSettings::GroupBlockDef * CSVSettings::WindowPage::buildDefinedWindowSize() -{ - GroupBlockDef *block = new GroupBlockDef ( "Defined Size"); - - 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; - - block->settingItems << widthByHeightItem; - block->isProxy = true; - block->isVisible = false; - - return block; -} - -CSVSettings::GroupBlockDef *CSVSettings::WindowPage::buildCustomWindowSize() -{ - GroupBlockDef *block = new GroupBlockDef ("Custom Size"); - - //custom width - SettingsItemDef *widthItem = new SettingsItemDef ("Width", "640"); - widthItem->widget = WidgetDef (Widget_LineEdit); - widthItem->widget.widgetWidth = 45; - widthItem->widget.inputMask = "9999"; - - //custom height - SettingsItemDef *heightItem = new SettingsItemDef ("Height", "480"); - heightItem->widget = WidgetDef (Widget_LineEdit); - heightItem->widget.widgetWidth = 45; - heightItem->widget.caption = "x"; - heightItem->widget.inputMask = "9999"; - - block->settingItems << widthItem << heightItem; - block->widgetOrientation = Orient_Horizontal; - block->isVisible = false; - - return block; -} - -CSVSettings::GroupBlockDef *CSVSettings::WindowPage::buildWindowSizeToggle() -{ - GroupBlockDef *block = new GroupBlockDef (objectName()); - - // window size toggle - block->captions << "Pre-Defined" << "Custom"; - block->widgetOrientation = Orient_Vertical; - block->isVisible = false; - - //define a widget for each group in the toggle - for (int i = 0; i < 2; i++) - block->widgets << new WidgetDef (Widget_RadioButton); - - block->widgets.at(0)->isDefault = false; - - return block; -} - -CSVSettings::CustomBlockDef *CSVSettings::WindowPage::buildWindowSize(GroupBlockDef *toggle_def, - GroupBlockDef *defined_def, - GroupBlockDef *custom_def) -{ - CustomBlockDef *block = new CustomBlockDef(QString ("Window Size")); - - block->blockDefList << toggle_def << defined_def << custom_def; - block->defaultValue = "Custom"; - - return block; - -} - -void CSVSettings::WindowPage::setupUi() -{ - CustomBlockDef *windowSize = buildWindowSize(buildWindowSizeToggle(), - buildDefinedWindowSize(), - buildCustomWindowSize() - ); - - mAbstractBlocks << buildBlock (windowSize); - - foreach (AbstractBlock *block, mAbstractBlocks) - { - connect (block, SIGNAL (signalUpdateSetting (const QString &, const QString &)), - this, SIGNAL (signalUpdateEditorSetting (const QString &, const QString &)) ); - } - - connect ( this, - SIGNAL ( signalUpdateEditorSetting (const QString &, const QString &)), - &(CSMSettings::UserSettings::instance()), - 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 deleted file mode 100644 index 2f2830625..000000000 --- a/apps/opencs/view/settings/windowpage.hpp +++ /dev/null @@ -1,34 +0,0 @@ -#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); - - /// - GroupBlockDef *buildCustomWindowSize(); - GroupBlockDef *buildDefinedWindowSize(); - GroupBlockDef *buildWindowSizeToggle(); - CustomBlockDef *buildWindowSize (GroupBlockDef *, GroupBlockDef *, GroupBlockDef *); - - signals: - void signalUpdateEditorSetting (const QString &settingName, const QString &settingValue); - }; -} -#endif //WINDOWPAGE_H From 331df17b48fb66f9305aea041a094f919df5707c Mon Sep 17 00:00:00 2001 From: graffy76 Date: Tue, 22 Apr 2014 22:17:19 -0500 Subject: [PATCH 011/118] Added new framework files --- apps/opencs/model/settings/connector.cpp | 127 +++++++ apps/opencs/model/settings/connector.hpp | 55 +++ apps/opencs/model/settings/setting.cpp | 281 +++++++++++++++ apps/opencs/model/settings/setting.hpp | 119 +++++++ apps/opencs/model/settings/settingmanager.cpp | 330 ++++++++++++++++++ apps/opencs/model/settings/settingmanager.hpp | 82 +++++ apps/opencs/view/settings/booleanview.cpp | 91 +++++ apps/opencs/view/settings/booleanview.hpp | 44 +++ apps/opencs/view/settings/dialog.cpp | 132 +++++++ apps/opencs/view/settings/dialog.hpp | 55 +++ apps/opencs/view/settings/frame.cpp | 103 ++++++ apps/opencs/view/settings/frame.hpp | 58 +++ apps/opencs/view/settings/listview.cpp | 106 ++++++ apps/opencs/view/settings/listview.hpp | 63 ++++ apps/opencs/view/settings/page.cpp | 88 +++++ apps/opencs/view/settings/page.hpp | 54 +++ .../view/settings/resizeablestackedwidget.cpp | 40 +++ .../view/settings/resizeablestackedwidget.hpp | 23 ++ apps/opencs/view/settings/settingwindow.cpp | 114 ++++++ apps/opencs/view/settings/settingwindow.hpp | 49 +++ apps/opencs/view/settings/textview.cpp | 73 ++++ apps/opencs/view/settings/textview.hpp | 56 +++ apps/opencs/view/settings/view.cpp | 218 ++++++++++++ apps/opencs/view/settings/view.hpp | 163 +++++++++ 24 files changed, 2524 insertions(+) create mode 100644 apps/opencs/model/settings/connector.cpp create mode 100644 apps/opencs/model/settings/connector.hpp create mode 100644 apps/opencs/model/settings/setting.cpp create mode 100644 apps/opencs/model/settings/setting.hpp create mode 100644 apps/opencs/model/settings/settingmanager.cpp create mode 100644 apps/opencs/model/settings/settingmanager.hpp create mode 100644 apps/opencs/view/settings/booleanview.cpp create mode 100644 apps/opencs/view/settings/booleanview.hpp create mode 100644 apps/opencs/view/settings/dialog.cpp create mode 100644 apps/opencs/view/settings/dialog.hpp create mode 100644 apps/opencs/view/settings/frame.cpp create mode 100644 apps/opencs/view/settings/frame.hpp create mode 100644 apps/opencs/view/settings/listview.cpp create mode 100644 apps/opencs/view/settings/listview.hpp create mode 100644 apps/opencs/view/settings/page.cpp create mode 100644 apps/opencs/view/settings/page.hpp create mode 100644 apps/opencs/view/settings/resizeablestackedwidget.cpp create mode 100644 apps/opencs/view/settings/resizeablestackedwidget.hpp create mode 100644 apps/opencs/view/settings/settingwindow.cpp create mode 100644 apps/opencs/view/settings/settingwindow.hpp create mode 100644 apps/opencs/view/settings/textview.cpp create mode 100644 apps/opencs/view/settings/textview.hpp create mode 100644 apps/opencs/view/settings/view.cpp create mode 100644 apps/opencs/view/settings/view.hpp diff --git a/apps/opencs/model/settings/connector.cpp b/apps/opencs/model/settings/connector.cpp new file mode 100644 index 000000000..05a9ba8f9 --- /dev/null +++ b/apps/opencs/model/settings/connector.cpp @@ -0,0 +1,127 @@ +#include "connector.hpp" +#include "../../view/settings/view.hpp" +#include "../../view/settings/page.hpp" + +CSMSettings::Connector::Connector(CSVSettings::View *master, + QObject *parent) + : mMasterView (master), QObject(parent) +{} + +void CSMSettings::Connector::addSlaveView (CSVSettings::View *view, + QList &masterProxyValues) +{ + mSlaveViews.append (view); + + mProxyListMap[view->viewKey()].append (masterProxyValues); +} + +QList CSMSettings::Connector::getSlaveViewValues() const +{ + QList list; + + foreach (const CSVSettings::View *view, mSlaveViews) + list.append (view->selectedValues()); + + return list; +} + +bool CSMSettings::Connector::proxyListsMatch ( + const QList &list1, + const QList &list2) const +{ + bool success = true; + + for (int i = 0; i < list1.size(); i++) + { + success = stringListsMatch (list1.at(i), list2.at(i)); + + if (!success) + break; + } + return success; +} + +void CSMSettings::Connector::slotUpdateMaster() const +{ + //list of the current values for each slave. + QList slaveValueList = getSlaveViewValues(); + + int masterColumn = -1; + + /* + * A row in the master view is one of the values in the + * master view's data model. This corresponds directly to the number of + * values in a proxy list contained in the ProxyListMap member. + * Thus, we iterate each "column" in the master proxy list + * (one for each vlaue in the master. Each column represents + * one master value's corresponding list of slave values. We examine + * each master value's list, comparing it to the current slave value list, + * stopping when we find a match using proxyListsMatch(). + * + * If no match is found, clear the master view's value + */ + + for (int i = 0; i < mMasterView->rowCount(); i++) + { + QList proxyValueList; + + foreach (const QString &settingKey, mProxyListMap.keys()) + { + // append the proxy value list stored in the i'th column + // for each setting key. A setting key is the id of the setting + // in page.name format. + proxyValueList.append (mProxyListMap.value(settingKey).at(i)); + } + + if (proxyListsMatch (slaveValueList, proxyValueList)) + { + masterColumn = i; + break; + } + } + + QString masterValue = mMasterView->value (masterColumn); + mMasterView->setSelectedValue (masterValue); +} + +void CSMSettings::Connector::slotUpdateSlaves() const +{ + int row = mMasterView->currentIndex(); + + if (row == -1) + return; + + //iterate the proxy lists for the chosen master index + //and pass the list to each slave for updating + for (int i = 0; i < mSlaveViews.size(); i++) + { + QList proxyList = + mProxyListMap.value(mSlaveViews.at(i)->viewKey()); + + mSlaveViews.at(i)->setSelectedValues (proxyList.at(row)); + } +} + +bool CSMSettings::Connector::stringListsMatch ( + const QStringList &list1, + const QStringList &list2) const +{ + //returns a "sloppy" match, verifying that each list contains all the same + //items, though not necessarily in the same order. + + if (list1.size() != list2.size()) + return false; + + QStringList tempList(list2); + + //iterate each value in the list, removing one occurrence of the value in + //the other list. If no corresponding value is found, test fails + foreach (const QString &value, list1) + { + if (!tempList.contains(value)) + return false; + + tempList.removeOne(value); + } + return true; +} diff --git a/apps/opencs/model/settings/connector.hpp b/apps/opencs/model/settings/connector.hpp new file mode 100644 index 000000000..da4c36d44 --- /dev/null +++ b/apps/opencs/model/settings/connector.hpp @@ -0,0 +1,55 @@ +#ifndef CSMSETTINGS_CONNECTOR_HPP +#define CSMSETTINGS_CONNECTOR_HPP + +#include +#include +#include +#include + +#include "support.hpp" + +namespace CSVSettings { + class View; +} + +namespace CSMSettings { + + class Connector : public QObject + { + Q_OBJECT + + CSVSettings::View *mMasterView; + + //map using the view pointer as a key to it's index value + QList mSlaveViews; + + //list of proxy values for each master value. + //value list order is indexed to the master value index. + QMap < QString, QList > mProxyListMap; + + public: + explicit Connector(CSVSettings::View *master, + QObject *parent = 0); + + void setMasterView (CSVSettings::View *view); + void addSlaveView (CSVSettings::View *view, + QList &masterProxyValues); + + private: + + bool proxyListsMatch (const QList &list1, + const QList &list2) const; + + bool stringListsMatch (const QStringList &list1, + const QStringList &list2) const; + + QList getSlaveViewValues() const; + + public slots: + + void slotUpdateSlaves() const; + void slotUpdateMaster() const; + }; +} + +#endif // CSMSETTINGS_CONNECTOR_HPP diff --git a/apps/opencs/model/settings/setting.cpp b/apps/opencs/model/settings/setting.cpp new file mode 100644 index 000000000..6c7e78087 --- /dev/null +++ b/apps/opencs/model/settings/setting.cpp @@ -0,0 +1,281 @@ +#include "setting.hpp" +#include "support.hpp" + +CSMSettings::Setting::Setting() +{ + buildDefaultSetting(); +} + +CSMSettings::Setting::Setting(SettingType typ, const QString &settingName, + const QString &pageName, const QStringList &values) + : mIsEditorSetting (false) +{ + buildDefaultSetting(); + + int vType = static_cast (typ); + + if ((vType % 2) == 0) + setProperty (Property_IsMultiValue, + QVariant(true).toString()); + else + vType--; + + setProperty (Property_ViewType, QVariant (vType / 2).toString()); + setProperty (Property_Page, pageName); + setProperty (Property_Name, settingName); + setProperty (Property_DeclaredValues, values); +} + +void CSMSettings::Setting::buildDefaultSetting() +{ + int arrLen = sizeof(sPropertyDefaults) / sizeof (*sPropertyDefaults); + + for (int i = 0; i < arrLen; i++) + { + QStringList propertyList; + + if (i list; + + foreach (const QString &val, vals) + list << (QStringList() << val); + + mProxies [setting->page() + '.' + setting->name()] = list; +} + +void CSMSettings::Setting::addProxy (const Setting *setting, + const QList &list) +{ + if (serializable()) + setProperty (Property_Serializable, false); + + mProxies [setting->page() + '.' + setting->name()] = list; +} + +void CSMSettings::Setting::setColumnSpan (int value) +{ + setProperty (Property_ColumnSpan, value); +} + +int CSMSettings::Setting::columnSpan() const +{ + return property (Property_ColumnSpan).at(0).toInt(); +} + +QStringList CSMSettings::Setting::declaredValues() const +{ + return property (Property_DeclaredValues); +} + +void CSMSettings::Setting::setDefinedValues (QStringList list) +{ + setProperty (Property_DefinedValues, list); +} + +QStringList CSMSettings::Setting::definedValues() const +{ + return property (Property_DefinedValues); +} + +QStringList CSMSettings::Setting::property (SettingProperty prop) const +{ + if (prop >= mProperties.size()) + return QStringList(); + + return mProperties.at(prop); +} + +void CSMSettings::Setting::setDefaultValue (const QString &value) +{ + setDefaultValues (QStringList() << value); +} + +void CSMSettings::Setting::setDefaultValues (const QStringList &values) +{ + setProperty (Property_DefaultValues, values); +} + +QStringList CSMSettings::Setting::defaultValues() const +{ + return property (Property_DefaultValues); +} + +void CSMSettings::Setting::setDelimiter (const QString &value) +{ + setProperty (Property_Delimiter, value); +} + +QString CSMSettings::Setting::delimiter() const +{ + return property (Property_Delimiter).at(0); +} + +void CSMSettings::Setting::setEditorSetting(bool state) +{ + mIsEditorSetting = true; +} + +bool CSMSettings::Setting::isEditorSetting() const +{ + return mIsEditorSetting; +} +void CSMSettings::Setting::setIsMultiLine (bool state) +{ + setProperty (Property_IsMultiLine, state); +} + +bool CSMSettings::Setting::isMultiLine() const +{ + return (property (Property_IsMultiLine).at(0) == "true"); +} + +void CSMSettings::Setting::setIsMultiValue (bool state) +{ + setProperty (Property_IsMultiValue, state); +} + +bool CSMSettings::Setting::isMultiValue() const +{ + return (property (Property_IsMultiValue).at(0) == "true"); +} + +const CSMSettings::ProxyValueMap &CSMSettings::Setting::proxyLists() const +{ + return mProxies; +} + +void CSMSettings::Setting::setSerializable (bool state) +{ + setProperty (Property_Serializable, state); +} + +bool CSMSettings::Setting::serializable() const +{ + return (property (Property_Serializable).at(0) == "true"); +} + +void CSMSettings::Setting::setName (const QString &value) +{ + setProperty (Property_Name, value); +} + +QString CSMSettings::Setting::name() const +{ + return property (Property_Name).at(0); +} + +void CSMSettings::Setting::setPage (const QString &value) +{ + setProperty (Property_Page, value); +} + +QString CSMSettings::Setting::page() const +{ + return property (Property_Page).at(0); +} + +void CSMSettings::Setting::setRowSpan (const int value) +{ + setProperty (Property_RowSpan, value); +} + +int CSMSettings::Setting::rowSpan () const +{ + return property (Property_RowSpan).at(0).toInt(); +} + +void CSMSettings::Setting::setViewType (int vType) +{ + setProperty (Property_ViewType, vType); +} + +CSVSettings::ViewType CSMSettings::Setting::viewType() const +{ + return static_cast + (property(Property_ViewType).at(0).toInt()); +} + +void CSMSettings::Setting::setViewColumn (int value) +{ + setProperty (Property_ViewColumn, value); +} + +int CSMSettings::Setting::viewColumn() const +{ + return property (Property_ViewColumn).at(0).toInt(); +} + +void CSMSettings::Setting::setViewLocation (int row, int column) +{ + setViewRow (row); + setViewColumn (column); +} + +void CSMSettings::Setting::setViewRow (int value) +{ + setProperty (Property_ViewRow, value); +} + +int CSMSettings::Setting::viewRow() const +{ + return property (Property_ViewRow).at(0).toInt(); +} + +void CSMSettings::Setting::setWidgetWidth (int value) +{ + setProperty (Property_WidgetWidth, value); +} + +int CSMSettings::Setting::widgetWidth() const +{ + return property (Property_WidgetWidth).at(0).toInt(); +} +void CSMSettings::Setting::setProperty (SettingProperty prop, bool value) +{ + setProperty (prop, QStringList() << QVariant (value).toString()); +} + +void CSMSettings::Setting::setProperty (SettingProperty prop, int value) +{ + setProperty (prop, QStringList() << QVariant (value).toString()); +} + +void CSMSettings::Setting::setProperty (SettingProperty prop, + const QString &value) +{ + setProperty (prop, QStringList() << value); +} + +void CSMSettings::Setting::setProperty (SettingProperty prop, + const QStringList &value) +{ + if (prop < mProperties.size()) + mProperties.replace (prop, value); +} + +QDataStream &operator <<(QDataStream &stream, const CSMSettings::Setting& setting) +{ + stream << setting.properties(); + + stream << setting.proxies(); + return stream; +} + +QDataStream &operator >>(QDataStream& stream, CSMSettings::Setting& setting) +{ + // stream >> setting.properties(); + // stream >> setting.proxies(); + return stream; +} diff --git a/apps/opencs/model/settings/setting.hpp b/apps/opencs/model/settings/setting.hpp new file mode 100644 index 000000000..1463e4d7d --- /dev/null +++ b/apps/opencs/model/settings/setting.hpp @@ -0,0 +1,119 @@ +#ifndef CSMSETTINGS_SETTING_HPP +#define CSMSETTINGS_SETTING_HPP + +#include +#include +#include "support.hpp" + +namespace CSMSettings +{ + //Maps setting id ("page.name") to a list of corresponding proxy values. + //Order of proxy value stringlists corresponds to order of master proxy's + //values in it's declared value list + typedef QMap > ProxyValueMap; + + class Setting + { + QList mProperties; + QStringList mDefaults; + + bool mIsEditorSetting; + + //QString is the setting id in the form of "page.name" + //QList is a list of stringlists of proxy values. + //Order is important! Proxy stringlists are matched against + //master values by their position in the QList. + ProxyValueMap mProxies; + + public: + + + explicit Setting(); + + explicit Setting(SettingType typ, const QString &settingName, + const QString &pageName, + const QStringList &values = QStringList()); + + void addProxy (const Setting *setting, const QStringList &vals); + void addProxy (const Setting *setting, const QList &list); + + const QList &properties() const { return mProperties; } + const ProxyValueMap &proxies() const { return mProxies; } + + void setColumnSpan (int value); + int columnSpan() const; + + void setDeclaredValues (QStringList list); + QStringList declaredValues() const; + + void setDefinedValues (QStringList list); + QStringList definedValues() const; + + void setDefaultValue (const QString &value); + + void setDefaultValues (const QStringList &values); + QStringList defaultValues() const; + + void setDelimiter (const QString &value); + QString delimiter() const; + + void setEditorSetting (bool state); + bool isEditorSetting() const; + + void setIsMultiLine (bool state); + bool isMultiLine() const; + + void setIsMultiValue (bool state); + bool isMultiValue() const; + + void setName (const QString &value); + QString name() const; + + void setPage (const QString &value); + QString page() const; + + void setRowSpan (const int value); + int rowSpan() const; + + const ProxyValueMap &proxyLists() const; + + void setSerializable (bool state); + bool serializable() const; + + void setViewColumn (int value); + int viewColumn() const; + + void setViewLocation (int row = -1, int column = -1); + + void setViewRow (int value); + int viewRow() const; + + void setViewType (int vType); + CSVSettings::ViewType viewType() const; + + void setWidgetWidth (int value); + int widgetWidth() const; + + ///returns the specified property value + QStringList property (SettingProperty prop) const; + + ///boilerplate code to convert setting values of common types + void setProperty (SettingProperty prop, bool value); + void setProperty (SettingProperty prop, int value); + void setProperty (SettingProperty prop, const QString &value); + void setProperty (SettingProperty prop, const QStringList &value); + + void addProxy (Setting* setting, + QMap &proxyMap); + + protected: + void buildDefaultSetting(); + }; +} + +Q_DECLARE_METATYPE(CSMSettings::Setting) + +QDataStream &operator <<(QDataStream &stream, const CSMSettings::Setting& setting); +QDataStream &operator >>(QDataStream &stream, CSMSettings::Setting& setting); + +#endif // CSMSETTINGS_SETTING_HPP diff --git a/apps/opencs/model/settings/settingmanager.cpp b/apps/opencs/model/settings/settingmanager.cpp new file mode 100644 index 000000000..70b91ee40 --- /dev/null +++ b/apps/opencs/model/settings/settingmanager.cpp @@ -0,0 +1,330 @@ +#include +#include +#include +#include +#include + +#include "setting.hpp" +#include "settingmanager.hpp" + +CSMSettings::SettingManager::SettingManager(QObject *parent) : + QObject(parent) +{ + mReadWriteMessage = QObject::tr("
Could not open or create file for \ + writing

Please make sure you have the right\ + permissions and try again.
"); + + mReadOnlyMessage = QObject::tr("
Could not open file for \ + reading

Please make sure you have the \ + right permissions and try again.
"); + +} + +void CSMSettings::SettingManager::dumpModel() +{ + foreach (Setting *setting, mSettings) + { + if (setting->proxyLists().isEmpty()) + continue; + } +} + +CSMSettings::Setting *CSMSettings::SettingManager::createSetting + (CSMSettings::SettingType typ, const QString &page, const QString &name, + const QStringList &values) +{ + //get list of all settings for the current setting name + if (findSetting (page, name)) + { + qWarning() << "Duplicate declaration encountered: " + << (name + '.' + page); + return 0; + } + + Setting *setting = new Setting (typ, name, page, values); + + //add declaration to the model + mSettings.append (setting); + + return setting; +} + +CSMSettings::DefinitionPageMap + CSMSettings::SettingManager::readFilestream (QTextStream *stream) +{ + //regEx's for page names and keys / values + QRegExp pageRegEx ("^\\[([^]]+)\\]"); + QRegExp keyRegEx ("^([^=]+)\\s*=\\s*(.+)$"); + + QString currPage = "Unassigned"; + + DefinitionPageMap pageMap; + + if (!stream) + { + displayFileErrorMessage(mReadWriteMessage, false); + return pageMap; + } + + if (stream->atEnd()) + return pageMap; + + DefinitionMap *settingMap = new DefinitionMap(); + pageMap[currPage] = settingMap; + + while (!stream->atEnd()) + { + QString line = stream->readLine().simplified(); + + if (line.isEmpty() || line.startsWith("#")) + continue; + + //page name found + if (pageRegEx.exactMatch(line)) + { + currPage = pageRegEx.cap(1).simplified().trimmed(); + settingMap = new DefinitionMap(); + pageMap[currPage] = settingMap; + continue; + } + + //setting definition found + if ( (keyRegEx.indexIn(line) != -1)) + { + QString settingName = keyRegEx.cap(1).simplified(); + QString settingValue = keyRegEx.cap(2).simplified(); + + if (!settingMap->contains (settingName)) + settingMap->insert (settingName, new QStringList()); + + settingMap->value(settingName)->append(settingValue); + } + } + + //return empty map if no settings were ever added to + if (pageMap.size() == 1) + { + QString pageKey = pageMap.keys().at(0); + if (pageMap[pageKey]->size() == 0) + pageMap.clear(); + } + + return pageMap; +} + +bool CSMSettings::SettingManager::writeFilestream(QTextStream *stream, + const QMap &settingListMap) +{ + if (!stream) + { + displayFileErrorMessage(mReadWriteMessage, false); + return false; + } + //disabled after rolling selector class into view. Need to + //iterate views to get setting definitions before writing to file + + QStringList sectionKeys; + + foreach (const QString &key, settingListMap.keys()) + { + QStringList names = key.split('.'); + QString section = names.at(0); + + if (!sectionKeys.contains(section)) + if (!settingListMap.value(key).isEmpty()) + sectionKeys.append (section); + } + + foreach (const QString §ion, sectionKeys) + { + *stream << '[' << section << "]\n"; + foreach (const QString &key, settingListMap.keys()) + { + QStringList names = key.split('.'); + + if (names.at(0) != section) + continue; + + QStringList list = settingListMap.value(key); + + if (list.isEmpty()) + continue; + + QString name = names.at(1); + + foreach (const QString value, list) + { + if (value.isEmpty()) + continue; + + *stream << name << " = " << value << '\n'; + } + } + } + + destroyStream (stream); + return true; +} + +void CSMSettings::SettingManager::mergeSettings(DefinitionPageMap &destMap, DefinitionPageMap &srcMap) +{ + if (srcMap.isEmpty()) + return; + + foreach (const QString &pageKey, srcMap.keys()) + { + DefinitionMap *srcSetting = srcMap.value(pageKey); + //Unique Page: + //insertfrom the source map + if (!destMap.keys().contains (pageKey)) + { + destMap.insert (pageKey, srcSetting); + continue; + } + + DefinitionMap *destSetting = destMap.value(pageKey); + + //Duplicate Page: + //iterate the settings in the source and check for duplicates in the + //destination + foreach (const QString &srcKey, srcSetting->keys()) + { + //insert into destination if unique + if (!destSetting->keys().contains (srcKey)) + destSetting->insert(srcKey, srcSetting->value (srcKey)); + } + } +} + +QTextStream *CSMSettings::SettingManager::openFilestream (const QString &filePath, + bool isReadOnly) const +{ + QIODevice::OpenMode openFlags = QIODevice::Text; + + if (isReadOnly) + openFlags = QIODevice::ReadOnly | openFlags; + else + openFlags = QIODevice::ReadWrite | QIODevice::Truncate | openFlags; + + QFile *file = new QFile(filePath); + QTextStream *stream = 0; + + if (file->open(openFlags)) + stream = new QTextStream(file); + + if (stream) + stream->setCodec(QTextCodec::codecForName("UTF-8")); + + return stream; +} + +void CSMSettings::SettingManager::destroyStream(QTextStream *stream) const +{ + stream->device()->close(); + + delete stream; +} + +void CSMSettings::SettingManager::displayFileErrorMessage(const QString &message, + bool isReadOnly) const +{ + // File cannot be opened or created + QMessageBox msgBox; + msgBox.setWindowTitle(QObject::tr("OpenCS configuration file I/O error")); + msgBox.setIcon(QMessageBox::Critical); + msgBox.setStandardButtons(QMessageBox::Ok); + + if (!isReadOnly) + msgBox.setText (mReadWriteMessage + message); + else + msgBox.setText (message); + + msgBox.exec(); +} + +void CSMSettings::SettingManager::addDefinitions (DefinitionPageMap &pageMap) +{ + foreach (QString pageName, pageMap.keys()) + { + DefinitionMap *settingMap = pageMap.value (pageName); + + foreach (QString settingName, (*settingMap).keys()) + { + QStringList *values = settingMap->value (settingName); + Setting *setting = findSetting (pageName, settingName); + + if (!setting) + { + qWarning() << "Found definitions for undeclared setting " + << pageName << "." << settingName; + continue; + } + + if (values->size() == 0) + values->append (setting->defaultValues()); + + setting->setDefinedValues (*values); + } + } +} + +QList CSMSettings::SettingManager::findSettings + (const QStringList &list) +{ + QList settings; + + foreach (const QString &value, list) + { + QStringList names = value.split(".", QString::SkipEmptyParts); + + if (names.size() != 2) + continue; + + Setting *setting = findSetting (names.at(0), names.at(1)); + + if (!setting) + continue; + + settings.append (setting); + } + + return settings; +} + + +CSMSettings::Setting *CSMSettings::SettingManager::findSetting + (const QString &pageName, const QString &settingName) +{ + foreach (Setting *setting, mSettings) + { + if (setting->name() == settingName) + { + if (setting->page() == pageName) + return setting; + } + } + return 0; +} + +QList CSMSettings::SettingManager::findSettings + (const QString &pageName) +{ + QList settings; + + foreach (Setting *setting, mSettings) + { + if (setting->page() == pageName) + settings.append (setting); + } + return settings; +} + +CSMSettings::SettingPageMap CSMSettings::SettingManager::settingPageMap() const +{ + SettingPageMap pageMap; + + foreach (Setting *setting, mSettings) + pageMap[setting->page()].append (setting); + + return pageMap; +} diff --git a/apps/opencs/model/settings/settingmanager.hpp b/apps/opencs/model/settings/settingmanager.hpp new file mode 100644 index 000000000..8819096ad --- /dev/null +++ b/apps/opencs/model/settings/settingmanager.hpp @@ -0,0 +1,82 @@ +#ifndef CSMSETTINGS_SETTINGMANAGER_HPP +#define CSMSETTINGS_SETTINGMANAGER_HPP + +#include +#include +#include +#include + +#include "support.hpp" +#include "setting.hpp" + +namespace CSMSettings +{ + + typedef QMap DefinitionMap; + typedef QMap DefinitionPageMap; + + typedef QMap > SettingPageMap; + + class SettingManager : public QObject + { + Q_OBJECT + + QString mReadOnlyMessage; + QString mReadWriteMessage; + QList mSettings; + + public: + explicit SettingManager(QObject *parent = 0); + + ///retrieve a setting object from a given page and setting name + Setting *findSetting + (const QString &pageName, const QString &settingName); + + ///retrieve all settings for a specified page + QList findSettings (const QString &pageName); + + ///retrieve all settings named in the attached list. + ///Setting names are specified in "PageName.SettingName" format. + QList findSettings (const QStringList &list); + + ///Retreive a map of the settings, keyed by page name + SettingPageMap settingPageMap() const; + + protected: + + ///add a new setting to the model and return it + Setting *createSetting (CSMSettings::SettingType typ, + const QString &page, const QString &name, + const QStringList &values = QStringList()); + + ///add definitions to the settings specified in the page map + void addDefinitions (DefinitionPageMap &pageMap); + + ///read setting definitions from file + DefinitionPageMap readFilestream(QTextStream *stream); + + ///write setting definitions to file + bool writeFilestream (QTextStream *stream, + const QMap &settingMap); + + ///merge PageMaps of settings when loading from multiple files + void mergeSettings (DefinitionPageMap &destMap, DefinitionPageMap &srcMap); + + QTextStream *openFilestream (const QString &filePath, + bool isReadOnly) const; + + void destroyStream(QTextStream *stream) const; + + void displayFileErrorMessage(const QString &message, + bool isReadOnly) const; + + QList settings() const { return mSettings; } + void dumpModel(); + + signals: + + public slots: + + }; +} +#endif // CSMSETTINGS_SETTINGMANAGER_HPP diff --git a/apps/opencs/view/settings/booleanview.cpp b/apps/opencs/view/settings/booleanview.cpp new file mode 100644 index 000000000..1c48199d1 --- /dev/null +++ b/apps/opencs/view/settings/booleanview.cpp @@ -0,0 +1,91 @@ +#include +#include + +#include +#include +#include + +#include + +#include "booleanview.hpp" +#include "../../model/settings/setting.hpp" + +CSVSettings::BooleanView::BooleanView (CSMSettings::Setting *setting, + Page *parent) + : View (setting, parent) +{ + foreach (const QString &value, setting->declaredValues()) + { + QAbstractButton *button = 0; + + if (isMultiValue()) + button = new QCheckBox (value, this); + else + button = new QRadioButton (value, this); + + connect (button, SIGNAL (clicked (bool)), + this, SLOT (slotToggled (bool))); + + button->setObjectName (value); + + addWidget (button); + + mButtons[value] = button; + } +} + +void CSVSettings::BooleanView::slotToggled (bool state) +{ + //test only for true to avoid multiple selection updates with radiobuttons + if (!isMultiValue() && !state) + return; + + QStringList values; + + foreach (QString key, mButtons.keys()) + { + if (mButtons.value(key)->isChecked()) + values.append (key); + } + setSelectedValues (values, false); + + View::updateView(); +} + +void CSVSettings::BooleanView::updateView (bool signalUpdate) const +{ + + QStringList values = selectedValues(); + + foreach (const QString &buttonName, mButtons.keys()) + { + QAbstractButton *button = mButtons[buttonName]; + + //if the value is not found in the list, the widget is checked false + bool buttonValue = values.contains(buttonName); + + //skip if the butotn value will not change + if (button->isChecked() == buttonValue) + continue; + + //disable autoexclusive if it's enabled and we're setting + //the button value to false + bool switchExclusive = (!buttonValue && button->autoExclusive()); + + if (switchExclusive) + button->setAutoExclusive (false); + + button->setChecked (buttonValue); + + if (switchExclusive) + button->setAutoExclusive(true); + } + View::updateView (signalUpdate); +} + +CSVSettings::BooleanView *CSVSettings::BooleanViewFactory::createView + (CSMSettings::Setting *setting, + Page *parent) +{ + return new BooleanView (setting, parent); +} diff --git a/apps/opencs/view/settings/booleanview.hpp b/apps/opencs/view/settings/booleanview.hpp new file mode 100644 index 000000000..52f9e05f1 --- /dev/null +++ b/apps/opencs/view/settings/booleanview.hpp @@ -0,0 +1,44 @@ +#ifndef CSVSETTINGS_BOOLEANVIEW_HPP +#define CSVSETTINGS_BOOELANVIEW_HPP + +#include +#include + +#include "view.hpp" +#include "../../model/settings/support.hpp" + +class QStringListModel; + +namespace CSVSettings +{ + class BooleanView : public View + { + Q_OBJECT + + QMap mButtons; + + public: + explicit BooleanView (CSMSettings::Setting *setting, + Page *parent); + + protected: + void updateView (bool signalUpdate = true) const; + + private slots: + void slotToggled (bool state); + }; + + class BooleanViewFactory : public QObject, public IViewFactory + { + Q_OBJECT + + public: + explicit BooleanViewFactory (QWidget *parent = 0) + : QObject (parent) + {} + + BooleanView *createView (CSMSettings::Setting *setting, + Page *parent); + }; +} +#endif // CSVSETTINGS_BOOLEANVIEW_HPP diff --git a/apps/opencs/view/settings/dialog.cpp b/apps/opencs/view/settings/dialog.cpp new file mode 100644 index 000000000..d9d5830d9 --- /dev/null +++ b/apps/opencs/view/settings/dialog.cpp @@ -0,0 +1,132 @@ +#include "dialog.hpp" + +#include +#include +#include +#include +#include + +#include "../../model/settings/usersettings.hpp" + +#include "page.hpp" + +#include + +#include + +#include +#include +#include + +#include +#include + +CSVSettings::Dialog::Dialog(QMainWindow *parent) + : mStackedWidget (0), mDebugMode (false), SettingWindow (parent) +{ + setWindowTitle(QString::fromUtf8 ("User Settings")); + + setupDialog(); + + connect (mPageListWidget, + SIGNAL (currentItemChanged(QListWidgetItem*, QListWidgetItem*)), + this, + SLOT (slotChangePage (QListWidgetItem*, QListWidgetItem*))); +} + +void CSVSettings::Dialog::slotChangePage + (QListWidgetItem *cur, QListWidgetItem *prev) +{ + mStackedWidget->changePage + (mPageListWidget->row (cur), mPageListWidget->row (prev)); + + layout()->activate(); + setFixedSize(minimumSizeHint()); +} + +void CSVSettings::Dialog::setupDialog() +{ + //create central widget with it's layout and immediate children + QWidget *centralWidget = new QGroupBox (this); + + centralWidget->setLayout (new QHBoxLayout()); + centralWidget->setSizePolicy (QSizePolicy::Expanding, QSizePolicy::Preferred); + setCentralWidget (centralWidget); + setDockOptions (QMainWindow::AllowNestedDocks); + + buildPageListWidget (centralWidget); + buildStackedWidget (centralWidget); +} + +void CSVSettings::Dialog::buildPages() +{ + SettingWindow::createPages (); + + QFontMetrics fm (QApplication::font()); + + foreach (Page *page, SettingWindow::pages()) + { + QString pageName = page->objectName(); + + int textWidth = fm.width(pageName); + + new QListWidgetItem (pageName, mPageListWidget); + mPageListWidget->setFixedWidth (textWidth + 50); + + mStackedWidget->addWidget (&dynamic_cast(*(page))); + } + + addDebugPage(); + + resize (mStackedWidget->sizeHint()); +} + +void CSVSettings::Dialog::addDebugPage() +{ + /* + QTreeView *tree = new QTreeView(); + + //tree->setModel( &CSMSettings::UserSettings::instance().model() ); + + mStackedWidget->addWidget(tree); + new QListWidgetItem ("Standard Item Model", mPageListWidget);*/ +} + +void CSVSettings::Dialog::buildPageListWidget (QWidget *centralWidget) +{ + mPageListWidget = new QListWidget (centralWidget); + mPageListWidget->setMinimumWidth(50); + mPageListWidget->setSizePolicy (QSizePolicy::Fixed, QSizePolicy::Expanding); + + mPageListWidget->setSelectionBehavior (QAbstractItemView::SelectItems); + + centralWidget->layout()->addWidget(mPageListWidget); +} + +void CSVSettings::Dialog::buildStackedWidget (QWidget *centralWidget) +{ + mStackedWidget = new ResizeableStackedWidget (centralWidget); + + centralWidget->layout()->addWidget (mStackedWidget); +} + +void CSVSettings::Dialog::closeEvent (QCloseEvent *event) +{ + //SettingWindow::closeEvent() must be called first to ensure + //model is updated + SettingWindow::closeEvent (event); + + saveSettings(); +} + +void CSVSettings::Dialog::show() +{ + if (pages().isEmpty()) + buildPages(); + + QPoint screenCenter = QApplication::desktop()->screenGeometry().center(); + + move (screenCenter - geometry().center()); + + QWidget::show(); +} diff --git a/apps/opencs/view/settings/dialog.hpp b/apps/opencs/view/settings/dialog.hpp new file mode 100644 index 000000000..0cfd415ac --- /dev/null +++ b/apps/opencs/view/settings/dialog.hpp @@ -0,0 +1,55 @@ +#ifndef CSVSETTINGS_DIALOG_H +#define CSVSETTINGS_DIALOG_H + +#include "settingwindow.hpp" +#include "resizeablestackedwidget.hpp" +#include + +class QStackedWidget; +class QListWidget; +class QListWidgetItem; + +namespace CSVSettings { + + class Page; + + class Dialog : public SettingWindow + { + Q_OBJECT + + QListWidget *mPageListWidget; + ResizeableStackedWidget *mStackedWidget; + bool mDebugMode; + + public: + + explicit Dialog (QMainWindow *parent = 0); + + ///Enables setting debug mode. When the dialog opens, a page is created + ///which displays the SettingModel's contents in a Tree view. + void enableDebugMode (bool state, QStandardItemModel *model = 0); + + protected: + + /// Settings are written on close + void closeEvent (QCloseEvent *event); + + void setupDialog(); + + private: + + void buildPages(); + void buildPageListWidget (QWidget *centralWidget); + void buildStackedWidget (QWidget *centralWidget); + void addDebugPage(); + + public slots: + + void show(); + + private slots: + + void slotChangePage (QListWidgetItem *, QListWidgetItem *); + }; +} +#endif // CSVSETTINGS_DIALOG_H diff --git a/apps/opencs/view/settings/frame.cpp b/apps/opencs/view/settings/frame.cpp new file mode 100644 index 000000000..db5091999 --- /dev/null +++ b/apps/opencs/view/settings/frame.cpp @@ -0,0 +1,103 @@ +#include "frame.hpp" + +#include + +const QString CSVSettings::Frame::sInvisibleBoxStyle = + QString::fromUtf8("Frame { border:2px; padding 2px; margin: 2px;}"); + +CSVSettings::Frame::Frame (bool isVisible, const QString &title, + QWidget *parent) + : mIsHorizontal (true), mLayout (new SettingLayout()), + QGroupBox (title, parent) +{ + setFlat (true); + mVisibleBoxStyle = styleSheet(); + + if (!isVisible) + setStyleSheet (sInvisibleBoxStyle); + + setLayout (mLayout); +} + +void CSVSettings::Frame::hideWidgets() +{ + for (int i = 0; i < children().size(); i++) + { + QObject *obj = children().at(i); + + Frame *widgFrame = dynamic_cast (obj); + + if (widgFrame) + { + widgFrame->hideWidgets(); + continue; + } + + QWidget *widg = static_cast (obj); + if (widg->property("sizePolicy").isValid()) + widg->setSizePolicy (QSizePolicy::Ignored, QSizePolicy::Ignored); + } + + layout()->activate(); + setFixedSize(minimumSizeHint()); + +} + +void CSVSettings::Frame::showWidgets() +{ + for (int i = 0; i < children().size(); i++) + { + QObject *obj = children().at(i); + + Frame *widgFrame = dynamic_cast (obj); + + if (widgFrame) + { + widgFrame->showWidgets(); + continue; + } + + QWidget *widg = static_cast (obj); + + if (widg->property("sizePolicy").isValid()) + widg->setSizePolicy + (QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); + } + layout()->activate(); + setFixedSize(minimumSizeHint()); +} + +void CSVSettings::Frame::addWidget (QWidget *widget, int row, int column, + int rowSpan, int columnSpan) +{ + if (row == -1) + row = getNextRow(); + + if (column == -1) + column = getNextColumn(); + + mLayout->addWidget (widget, row, column, rowSpan, columnSpan); + //, Qt::AlignLeft | Qt::AlignTop); + + widget->setSizePolicy (QSizePolicy::Ignored, QSizePolicy::Ignored); +} + +int CSVSettings::Frame::getNextRow () const +{ + int row = mLayout->rowCount(); + + if (mIsHorizontal && row > 0) + row--; + + return row; +} + +int CSVSettings::Frame::getNextColumn () const +{ + int column = 0; + + if (mIsHorizontal) + column = mLayout->columnCount(); + + return column; +} diff --git a/apps/opencs/view/settings/frame.hpp b/apps/opencs/view/settings/frame.hpp new file mode 100644 index 000000000..2b52dfd1f --- /dev/null +++ b/apps/opencs/view/settings/frame.hpp @@ -0,0 +1,58 @@ +#ifndef CSVSETTINGS_FRAME_HPP +#define CSVSETTINGS_FRAME_HPP + +#include +#include +#include +#include "../../model/settings/support.hpp" + +namespace CSVSettings +{ + class SettingLayout : public QGridLayout + { + public: + explicit SettingLayout (QWidget *parent = 0) + : QGridLayout (parent) + { + setContentsMargins(0,0,0,0); + setAlignment(Qt::AlignLeft | Qt::AlignTop); + } + }; + + /// Custom implementation of QGroupBox to act as a base for view classes + class Frame : public QGroupBox + { + static const QString sInvisibleBoxStyle; + + QString mVisibleBoxStyle; + + bool mIsHorizontal; + + SettingLayout *mLayout; + + public: + explicit Frame (bool isVisible, const QString &title = "", + QWidget *parent = 0); + + ///Adds a widget to the grid layout, setting the position + ///relative to the last added widgets, or absolutely for positive + ///row / column values + void addWidget (QWidget *widget, int row = -1, int column = -1, + int rowSpan = 1, int columnSpan = 1); + + ///Force the grid to lay out in horizontal or vertical alignments + void setHLayout() { mIsHorizontal = true; } + void setVLayout() { mIsHorizontal = false; } + + void showWidgets(); + void hideWidgets(); + + private: + + int getNextColumn() const; + int getNextRow() const; + + }; +} + +#endif // CSVSETTINGS_FRAME_HPP diff --git a/apps/opencs/view/settings/listview.cpp b/apps/opencs/view/settings/listview.cpp new file mode 100644 index 000000000..b2a47903f --- /dev/null +++ b/apps/opencs/view/settings/listview.cpp @@ -0,0 +1,106 @@ +#include "listview.hpp" +#include "../../model/settings/setting.hpp" + +#include +#include +#include + +CSVSettings::ListView::ListView(CSMSettings::Setting *setting, + Page *parent) + : mComboBox (0), mAbstractItemView (0), View(setting, parent) +{ + QWidget *widget = + buildWidget(setting->isMultiLine(), setting->widgetWidth()); + + addWidget (widget, setting->viewRow(), setting->viewColumn()); + + if (mComboBox) + buildComboBoxModel(); + + else if (mAbstractItemView) + buildAbstractItemViewModel(); +} + +void CSVSettings::ListView::buildComboBoxModel() +{ + mComboBox->setModel (dataModel()); + mComboBox->setModelColumn (0); + mComboBox->view()->setSelectionModel (selectionModel()); + + int curIdx = -1; + + if (!selectionModel()->selection().isEmpty()) + curIdx = selectionModel()->selectedIndexes().at(0).row(); + + mComboBox->setCurrentIndex (curIdx); + + connect (mComboBox, SIGNAL(currentIndexChanged(int)), + this, SLOT(emitItemViewUpdate(int))); +} + +void CSVSettings::ListView::buildAbstractItemViewModel() +{ + mAbstractItemView->setModel (dataModel()); + mAbstractItemView->setSelectionModel (selectionModel()); + + //connection needs to go here for list view update to signal to + //the outside +} + +void CSVSettings::ListView::emitItemViewUpdate (int idx) +{ + emit viewUpdated (objectName(), selectedValues()); +} + +QWidget *CSVSettings::ListView::buildWidget(bool isMultiLine, int width) +{ + QWidget *widget = 0; + + if (isMultiLine) + { + mAbstractItemView = new QListView (this); + widget = mAbstractItemView; + + if (width > 0) + widget->setFixedWidth (widgetWidth (width)); + } + else + { + mComboBox = new QComboBox (this); + widget = mComboBox; + + if (width > 0) + mComboBox->setMinimumContentsLength (width); + } + + return widget; +} + +void CSVSettings::ListView::showEvent ( QShowEvent * event ) +{ + View::showEvent (event); +} + +void CSVSettings::ListView::updateView (bool signalUpdate) const +{ + QStringList values = selectedValues(); + + if (mComboBox) + { + int idx = -1; + + if (values.size() > 0) + idx = (mComboBox->findText(values.at(0))); + + mComboBox->setCurrentIndex (idx); + } + + View::updateView (signalUpdate); +} + +CSVSettings::ListView *CSVSettings::ListViewFactory::createView + (CSMSettings::Setting *setting, + Page *parent) +{ + return new ListView(setting, parent); +} diff --git a/apps/opencs/view/settings/listview.hpp b/apps/opencs/view/settings/listview.hpp new file mode 100644 index 000000000..c2860d769 --- /dev/null +++ b/apps/opencs/view/settings/listview.hpp @@ -0,0 +1,63 @@ +#ifndef CSVSETTINGS_LISTVIEW_HPP +#define CSVSETTINGS_LISTVIEW_HPP + +#include "view.hpp" + + +class QStringListModel; +class QComboBox; +class QAbstractItemView; + +namespace CSVSettings +{ + class ListView : public View + { + Q_OBJECT + + QAbstractItemView *mAbstractItemView; + QComboBox *mComboBox; + + public: + explicit ListView (CSMSettings::Setting *setting, + Page *parent); + + protected: + + void updateView (bool signalUpdate = true) const; + void showEvent ( QShowEvent * event ); + + ///Receives signal from widget and signals viwUpdated() + void slotTextEdited (QString value); + + private: + + ///Helper function to construct a model for an AbstractItemView + void buildAbstractItemViewModel(); + + ///Helper function to construct a model for a combobox + void buildComboBoxModel(); + + ///Helper function to build the view widget + QWidget *buildWidget (bool isMultiLine, int width); + + private slots: + + ///Receives updates from single-select widgets (like combobox) and + ///signals viewUpdated with the selected values. + void emitItemViewUpdate (int idx); + }; + + class ListViewFactory : public QObject, public IViewFactory + { + Q_OBJECT + + public: + explicit ListViewFactory (QWidget *parent = 0) + : QObject (parent) + {} + + ListView *createView (CSMSettings::Setting *setting, + Page *parent); + }; +} +#endif // CSVSETTINGS_LISTVIEW_HPP diff --git a/apps/opencs/view/settings/page.cpp b/apps/opencs/view/settings/page.cpp new file mode 100644 index 000000000..665326c2c --- /dev/null +++ b/apps/opencs/view/settings/page.cpp @@ -0,0 +1,88 @@ +#include "page.hpp" +#include "view.hpp" +#include "booleanview.hpp" +#include "textview.hpp" +#include "listview.hpp" + +#include "../../model/settings/usersettings.hpp" +#include "../../model/settings/connector.hpp" +#include "settingwindow.hpp" + +QMap + CSVSettings::Page::mViewFactories; + +CSVSettings::Page::Page(const QString &pageName, + QList settingList, + SettingWindow *parent) : + mParent(parent), mIsEditorPage (false), Frame(false, "", parent) +{ + setObjectName (pageName); + + if (mViewFactories.size() == 0) + buildFactories(); + + setVLayout(); + setupViews (settingList); +} + +void CSVSettings::Page::setupViews + (QList &settingList) +{ + foreach (CSMSettings::Setting *setting, settingList) + addView (setting); +} + +void CSVSettings::Page::addView (CSMSettings::Setting *setting) +{ + if (setting->viewType() == ViewType_Undefined) + return; + + View *view = mViewFactories[setting->viewType()]->createView(setting, this); + + if (!view) + return; + + mViews.append (view); + + addWidget (view, setting->viewRow(), setting->viewColumn(), + setting->rowSpan(), setting->columnSpan() ); + + //if this page is an editor page, connect each of it's views up to the + //UserSettings singleton for signaling back to OpenCS + if (setting->isEditorSetting()) { + connect (view, SIGNAL (viewUpdated(const QString&, const QStringList&)), + &CSMSettings::UserSettings::instance(), + SIGNAL (userSettingUpdated (const QString &, const QStringList &))); + } +} + +CSVSettings::View *CSVSettings::Page::findView (const QString &page, + const QString &setting) const +{ + + //if this is not the page we're looking for, + //appeal to the parent setting window to find the appropriate view + if (page != objectName()) + return mParent->findView (page, setting); + + //otherwise, return the matching view + for (int i = 0; i < mViews.size(); i++) + { + View *view = mViews.at(i); + + if (view->parentPage()->objectName() != page) + continue; + + if (view->objectName() == setting) + return view; + } + + return 0; +} + +void CSVSettings::Page::buildFactories() +{ + mViewFactories[ViewType_Boolean] = new BooleanViewFactory (this); + mViewFactories[ViewType_Text] = new TextViewFactory (this); + mViewFactories[ViewType_List] = new ListViewFactory (this); +} diff --git a/apps/opencs/view/settings/page.hpp b/apps/opencs/view/settings/page.hpp new file mode 100644 index 000000000..7f24f6a62 --- /dev/null +++ b/apps/opencs/view/settings/page.hpp @@ -0,0 +1,54 @@ +#ifndef CSVSETTINGS_PAGE_HPP +#define CSVSETTINGS_PAGE_HPP + +#include +#include +#include +#include + +#include "frame.hpp" + +#include "../../model/settings/support.hpp" + +namespace CSMSettings { class Setting; } + +namespace CSVSettings +{ + class View; + class IViewFactory; + class SettingWindow; + + class Page : public Frame + { + Q_OBJECT + + QList mViews; + SettingWindow *mParent; + static QMap mViewFactories; + bool mIsEditorPage; + + public: + explicit Page(const QString &pageName, + QList settingList, + SettingWindow *parent); + + ///Creates a new view based on the passed setting and adds it to + ///the page. + void addView (CSMSettings::Setting *setting); + + ///Iterates the views created for this page based on the passed setting + ///and returns it. + View *findView (const QString &page, const QString &setting) const; + + const QList &views () const { return mViews; } + + private: + + ///Creates views based on the passed setting list + void setupViews (QList &settingList); + + ///Creates factory objects for view construction + void buildFactories(); + }; +} +#endif // CSVSETTINGS_PAGE_HPP diff --git a/apps/opencs/view/settings/resizeablestackedwidget.cpp b/apps/opencs/view/settings/resizeablestackedwidget.cpp new file mode 100644 index 000000000..cb127cb76 --- /dev/null +++ b/apps/opencs/view/settings/resizeablestackedwidget.cpp @@ -0,0 +1,40 @@ +#include "resizeablestackedwidget.hpp" +#include "page.hpp" + +#include + +CSVSettings::ResizeableStackedWidget::ResizeableStackedWidget(QWidget *parent) : + QStackedWidget(parent) +{} + +void CSVSettings::ResizeableStackedWidget::addWidget(QWidget* pWidget) +{ + QStackedWidget::addWidget(pWidget); +} + +void CSVSettings::ResizeableStackedWidget::changePage + (int current, int previous) +{ + if (current == previous) + return; + + Page *prevPage = 0; + Page *curPage = 0; + + if (previous > -1) + prevPage = static_cast (widget (previous)); + + if (current > -1) + curPage = static_cast (widget (current)); + + if (prevPage) + prevPage->hideWidgets(); + + if (curPage) + curPage->showWidgets(); + + layout()->activate(); + setFixedSize(minimumSizeHint()); + + setCurrentIndex (current); +} diff --git a/apps/opencs/view/settings/resizeablestackedwidget.hpp b/apps/opencs/view/settings/resizeablestackedwidget.hpp new file mode 100644 index 000000000..5e894d8df --- /dev/null +++ b/apps/opencs/view/settings/resizeablestackedwidget.hpp @@ -0,0 +1,23 @@ +#ifndef CSVSETTINGS_RESIZEABLESTACKEDWIDGET_HPP +#define CSVSETTINGS_RESIZEABLESTACKEDWIDGET_HPP + +#include + +class QListWidgetItem; + +namespace CSVSettings +{ + class ResizeableStackedWidget : public QStackedWidget + { + Q_OBJECT + + public: + explicit ResizeableStackedWidget(QWidget *parent = 0); + + void addWidget(QWidget* pWidget); + + void changePage (int, int); + }; +} + +#endif // CSVSETTINGS_RESIZEABLESTACKEDWIDGET_HPP diff --git a/apps/opencs/view/settings/settingwindow.cpp b/apps/opencs/view/settings/settingwindow.cpp new file mode 100644 index 000000000..9283bbf51 --- /dev/null +++ b/apps/opencs/view/settings/settingwindow.cpp @@ -0,0 +1,114 @@ +#include +#include + +#include "../../model/settings/setting.hpp" +#include "../../model/settings/connector.hpp" +#include "../../model/settings/usersettings.hpp" +#include "settingwindow.hpp" +#include "page.hpp" +#include "view.hpp" + +CSVSettings::SettingWindow::SettingWindow(QWidget *parent) + : QMainWindow(parent) +{} + +void CSVSettings::SettingWindow::createPages() +{ + CSMSettings::SettingPageMap pageMap = mModel->settingPageMap(); + + QList connectedSettings; + + foreach (const QString &pageName, pageMap.keys()) + { + QList pageSettings = pageMap.value (pageName); + + mPages.append (new Page (pageName, pageSettings, this)); + + for (int i = 0; i < pageSettings.size(); i++) + { + CSMSettings::Setting *setting = pageSettings.at(i); + + if (!setting->proxyLists().isEmpty()) + connectedSettings.append (setting); + } + } + + if (!connectedSettings.isEmpty()) + createConnections(connectedSettings); +} + +void CSVSettings::SettingWindow::createConnections + (const QList &list) +{ + foreach (const CSMSettings::Setting *setting, list) + { + View *masterView = findView (setting->page(), setting->name()); + + CSMSettings::Connector *connector = + new CSMSettings::Connector (masterView, this); + + connect (masterView, + SIGNAL (viewUpdated(const QString &, const QStringList &)), + connector, + SLOT (slotUpdateSlaves()) + ); + + const CSMSettings::ProxyValueMap &proxyMap = setting->proxyLists(); + + foreach (const QString &key, proxyMap.keys()) + { + QStringList keyPair = key.split('.'); + + if (keyPair.size() != 2) + continue; + + View *slaveView = findView (keyPair.at(0), keyPair.at(1)); + + if (!slaveView) + { + qWarning () << "Unable to create connection for view " + << key; + continue; + } + + QList proxyList = proxyMap.value (key); + connector->addSlaveView (slaveView, proxyList); + + connect (slaveView, + SIGNAL (viewUpdated(const QString &, const QStringList &)), + connector, + SLOT (slotUpdateMaster())); + } + } +} + +CSVSettings::View *CSVSettings::SettingWindow::findView + (const QString &pageName, const QString &setting) +{ + foreach (const Page *page, mPages) + { + if (page->objectName() == pageName) + return page->findView (pageName, setting); + } + return 0; +} + +void CSVSettings::SettingWindow::saveSettings() +{ + QMap settingMap; + + foreach (const Page *page, mPages) + { + foreach (const View *view, page->views()) + { + if (view->serializable()) + settingMap[view->viewKey()] = view->selectedValues(); + } + } + CSMSettings::UserSettings::instance().saveSettings (settingMap); +} + +void CSVSettings::SettingWindow::closeEvent (QCloseEvent *event) +{ + QApplication::focusWidget()->clearFocus(); +} diff --git a/apps/opencs/view/settings/settingwindow.hpp b/apps/opencs/view/settings/settingwindow.hpp new file mode 100644 index 000000000..35ae4c068 --- /dev/null +++ b/apps/opencs/view/settings/settingwindow.hpp @@ -0,0 +1,49 @@ +#ifndef CSVSETTINGS_SETTINGWINDOW_HPP +#define CSVSETTINGS_SETTINGWINDOW_HPP + +#include +#include + +#include "../../model/settings/support.hpp" + +namespace CSMSettings { + class Setting; + class SettingManager; +} + +namespace CSVSettings { + + class Page; + class View; + + typedef QList PageList; + + class SettingWindow : public QMainWindow + { + Q_OBJECT + + PageList mPages; + CSMSettings::SettingManager *mModel; + + public: + explicit SettingWindow(QWidget *parent = 0); + + View *findView (const QString &pageName, const QString &setting); + void setModel (CSMSettings::SettingManager &model) { mModel = &model; } + + protected: + + virtual void closeEvent (QCloseEvent *event); + + void createPages(); + + const PageList &pages() const { return mPages; } + + void saveSettings(); + + private: + void createConnections (const QList &list); + }; +} + +#endif // CSVSETTINGS_SETTINGWINDOW_HPP diff --git a/apps/opencs/view/settings/textview.cpp b/apps/opencs/view/settings/textview.cpp new file mode 100644 index 000000000..5e10c346f --- /dev/null +++ b/apps/opencs/view/settings/textview.cpp @@ -0,0 +1,73 @@ +#include +#include + +#include "textview.hpp" +#include "../../model/settings/setting.hpp" + +CSVSettings::TextView::TextView(CSMSettings::Setting *setting, Page *parent) + : mDelimiter (setting->delimiter()), View (setting, parent) + +{ + if (setting->isMultiLine()) + mTextWidget = new QTextEdit ("", this); + else + mTextWidget = new QLineEdit ("", this); + + if (setting->widgetWidth() > 0) + mTextWidget->setFixedWidth (widgetWidth (setting->widgetWidth())); + + connect (mTextWidget, SIGNAL (textEdited (QString)), + this, SLOT (slotTextEdited (QString))); + + addWidget (mTextWidget, setting->viewRow(), setting->viewColumn()); +} + +bool CSVSettings::TextView::isEquivalent + (const QString &lhs, const QString &rhs) const +{ + return (lhs.trimmed() == rhs.trimmed()); +} + +void CSVSettings::TextView::setWidgetText (const QString &value) const +{ + mTextWidget->setProperty ("text", value); +} + +void CSVSettings::TextView::slotTextEdited (QString value) +{ + QStringList values = value.split (mDelimiter, QString::SkipEmptyParts); + + QStringList returnValues; + + foreach (const QString &splitValue, values) + returnValues.append (splitValue.trimmed()); + + setSelectedValues (returnValues, false); + + View::updateView(); +} + +void CSVSettings::TextView::updateView(bool signalUpdate) const +{ + QString values = selectedValues().join (mDelimiter); + + if (isEquivalent (widgetText(), values)) + return; + + setWidgetText (values); + + View::updateView (signalUpdate); +} + +QString CSVSettings::TextView::widgetText() const +{ + return mTextWidget->property("text").toString(); +} + +CSVSettings::TextView *CSVSettings::TextViewFactory::createView + (CSMSettings::Setting *setting, + Page *parent) +{ + return new TextView (setting, parent); +} + diff --git a/apps/opencs/view/settings/textview.hpp b/apps/opencs/view/settings/textview.hpp new file mode 100644 index 000000000..6d718aad8 --- /dev/null +++ b/apps/opencs/view/settings/textview.hpp @@ -0,0 +1,56 @@ +#ifndef CSVSETTINGS_TEXTVIEW_HPP +#define CSVSETTINGS_TEXTVIEW_HPP + +#include "view.hpp" +#include "../../model/settings/setting.hpp" + +namespace CSVSettings +{ + class TextView : public View + { + Q_OBJECT + + QWidget *mTextWidget; + + QString mDelimiter; + + public: + explicit TextView (CSMSettings::Setting *setting, + Page *parent = 0); + + protected: + + void updateView (bool signalUpdate = true) const; + + protected slots: + + ///Receives updates to the widget for signalling + void slotTextEdited (QString value); + + private: + + ///Comparison function that returns true if the trimmed() strings + ///are equal + bool isEquivalent (const QString &lhs, const QString &rhs) const; + + ///Convenience function to return the text of the widget + QString widgetText() const; + + ///Convenience function to set the text of the widget + void setWidgetText (const QString &value) const; + }; + + class TextViewFactory : public QObject, public IViewFactory + { + Q_OBJECT + + public: + explicit TextViewFactory (QWidget *parent = 0) + : QObject (parent) + {} + + TextView *createView (CSMSettings::Setting *setting, + Page *parent); + }; +} +#endif // CSVSETTINGS_TEXTVIEW_HPP diff --git a/apps/opencs/view/settings/view.cpp b/apps/opencs/view/settings/view.cpp new file mode 100644 index 000000000..259dd518b --- /dev/null +++ b/apps/opencs/view/settings/view.cpp @@ -0,0 +1,218 @@ +#include +#include +#include +#include + +#include "view.hpp" +#include "../../model/settings/support.hpp" +#include "../../model/settings/setting.hpp" +#include "page.hpp" + +CSVSettings::View::View(CSMSettings::Setting *setting, + Page *parent) + + : mDataModel(0), mParentPage (parent), + mHasFixedValues (!setting->declaredValues().isEmpty()), + mIsMultiValue (setting->isMultiValue()), + mViewKey (setting->page() + '.' + setting->name()), + mSerializable (setting->serializable()), + Frame(true, setting->name(), parent) +{ + setObjectName (setting->name()); + buildView(); + buildModel (setting); +} + +void CSVSettings::View::buildModel (const CSMSettings::Setting *setting) +{ + QStringList values = setting->definedValues(); + + if (values.isEmpty()) + values.append (setting->defaultValues()); + + if (mHasFixedValues) + buildFixedValueModel (setting->declaredValues()); + else + buildUpdatableValueModel (values); + + mSelectionModel = new QItemSelectionModel (mDataModel, this); + + setSelectedValues (values, false); +} + +void CSVSettings::View::buildFixedValueModel (const QStringList &values) +{ + mDataModel = new QStringListModel (values, this); +} + +void CSVSettings::View::buildUpdatableValueModel (const QStringList &values) +{ + QList itemList; + + foreach (const QString &value, values) + itemList.append (new QStandardItem(value)); + +// QSortFilterProxyModel *filter = new QSortFilterProxyModel (this); + QStandardItemModel *model = new QStandardItemModel (this); + model->appendColumn (itemList); + +// filter->setSourceModel (model); + /* filter->setFilterRegExp ("*"); + filter->setFilterKeyColumn (0); + filter->setFilterRole (Qt::DisplayRole);*/ + mDataModel = model; +} + +void CSVSettings::View::buildView() +{ + setFlat (true); + setHLayout(); +} + +int CSVSettings::View::currentIndex () const +{ + if (selectedValues().isEmpty()) + return -1; + + QString currentValue = selectedValues().at(0); + + for (int i = 0; i < mDataModel->rowCount(); i++) + if (value(i) == currentValue) + return i; + + return -1; +} + +void CSVSettings::View::refresh() const +{ + select (mSelectionModel->selection()); + updateView(); +} + +int CSVSettings::View::rowCount() const +{ + return mDataModel->rowCount(); +} + +void CSVSettings::View::select (const QItemSelection &selection) const +{ + mSelectionModel->clear(); + mSelectionModel->select(selection, QItemSelectionModel::Select); +} + +QStringList CSVSettings::View::selectedValues() const +{ + QStringList selValues; + + foreach (const QModelIndex &idx, mSelectionModel->selectedIndexes()) + selValues.append (value(idx.row())); + + return selValues; +} + +void CSVSettings::View::setSelectedValue (const QString &value, + bool doViewUpdate, bool signalUpdate) +{ + setSelectedValues (QStringList() << value, doViewUpdate, signalUpdate); +} + +void CSVSettings::View::setSelectedValues (const QStringList &list, + bool doViewUpdate, bool signalUpdate) +{ + QItemSelection selection; + + if (stringListsMatch (list, selectedValues())) + return; + + if (!mHasFixedValues) + { + QStandardItemModel *model = + static_cast (mDataModel); + + model->clear(); + model->appendColumn (toStandardItemList (list)); + + for (int i = 0; i < model->rowCount(); i++) + { + QModelIndex idx = model->index(i, 0); + selection.append (QItemSelectionRange (idx, idx)); + } + } + else + { + for (int i = 0; i < mDataModel->rowCount(); i++) + { + if (list.contains(value(i))) + { + QModelIndex idx = mDataModel->index(i, 0); + selection.append(QItemSelectionRange (idx, idx)); + } + } + } + select (selection); + + if (doViewUpdate) + updateView (signalUpdate); +} + +void CSVSettings::View::showEvent ( QShowEvent * event ) +{ + refresh(); +} + +bool CSVSettings::View::stringListsMatch ( + const QStringList &list1, + const QStringList &list2) const +{ + //returns a "sloppy" match, verifying that each list contains all the same + //items, though not necessarily in the same order. + + if (list1.size() != list2.size()) + return false; + + QStringList tempList(list2); + + //iterate each value in the list, removing one occurrence of the value in + //the other list. If no corresponding value is found, test fails + foreach (const QString &value, list1) + { + if (!tempList.contains(value)) + return false; + + tempList.removeOne(value); + } + return true; +} + +QList CSVSettings::View::toStandardItemList + (const QStringList &list) const +{ + QList itemList; + + foreach (const QString &value, list) + itemList.append (new QStandardItem (value)); + + return itemList; +} + +void CSVSettings::View::updateView (bool signalUpdate) const +{ + if (signalUpdate) + emit viewUpdated(objectName(), selectedValues()); +} + +QString CSVSettings::View::value (int row) const +{ + if (row > -1 && row < mDataModel->rowCount()) + return mDataModel->data (mDataModel->index(row, 0)).toString(); + + return ""; +} + +int CSVSettings::View::widgetWidth(int characterCount) const +{ + QString widthToken = QString().fill ('P', characterCount); + QFontMetrics fm (QApplication::font()); + + return (fm.width (widthToken)); +} diff --git a/apps/opencs/view/settings/view.hpp b/apps/opencs/view/settings/view.hpp new file mode 100644 index 000000000..c99879762 --- /dev/null +++ b/apps/opencs/view/settings/view.hpp @@ -0,0 +1,163 @@ +#ifndef CSVSETTINGS_VIEW_HPP +#define CSVSETTINGS_VIEW_HPP + +#include +#include + +#include "frame.hpp" +#include "../../model/settings/support.hpp" + +class QGroupBox; +class QStringList; +class QStandardItem; +class QItemSelection; +class QStringListModel; +class QStandardItemModel; +class QAbstractItemModel; +class QItemSelectionModel; + +namespace CSMSettings { class Setting; } + +namespace CSVSettings +{ + class Page; + + class View : public Frame + { + Q_OBJECT + + ///Pointer to the owning Page instance + Page *mParentPage; + + ///Pointer to the selection model for the view + QItemSelectionModel *mSelectionModel; + + ///Pointer to the data model for the view's selection model + QAbstractItemModel *mDataModel; + + ///State indicating whether or not the setting has a pre-defined list + ///of values, limiting possible definitions + bool mHasFixedValues; + + ///State indicating whether the view will allow multiple values + bool mIsMultiValue; + + QString mViewKey; + + bool mSerializable; + + public: + + explicit View (CSMSettings::Setting *setting, Page *parent); + + ///Physical frame in which the view UI is contained + void addViewWidget (QWidget *widget, int row = -1, int col = -1) const; + + ///Returns the index / row of the passed value, -1 if not found. + int currentIndex () const; + + ///Returns the number of rows in the view's data model + int rowCount() const; + + ///Returns bool indicating the data in this view should / should not + ///be serialized to a config file + bool serializable() const { return mSerializable; } + + ///Returns a pointer to the view's owning parent page + const Page *parentPage() const { return mParentPage; } + + ///Returns the selected items in the selection model as a QStringList + QStringList selectedValues() const; + + ///Sets the selected items in the selection model based on passed list. + ///Bools allow opt-out of updating the view + ///or signaling the view was updatedto avoid viscious cylcing. + void setSelectedValues (const QStringList &values, + bool updateView = true, + bool signalUpdate = true); + + void setSelectedValue (const QString &value, + bool updateView = true, + bool signalUpdate = true); + + + ///Returns the value of the data model at the specified row + QString value (int row) const; + + QString viewKey() const { return mViewKey; } + + protected: + + /// Returns the model which provides data for the selection model + QAbstractItemModel *dataModel() { return mDataModel; } + + ///Accessor function for subclasses + bool isMultiValue() { return mIsMultiValue; } + + ///Returns the view selection model + QItemSelectionModel *selectionModel() { return mSelectionModel;} + + ///Global callback for basic view initialization + void showEvent ( QShowEvent * event ); + + ///Virtual for updating a specific View subclass + ///bool indicates whether a signal is emitted that the view was updated + virtual void updateView (bool signalUpdate = true) const; + + ///Returns the pixel width corresponding to the specified number of + ///characters. + int widgetWidth(int characterCount) const; + + private: + + ///Constructs the view layout + void buildView(); + + ///Constructs the data and selection models + void buildModel (const CSMSettings::Setting *setting); + + ///In cases where the view has a pre-defined list of possible values, + ///a QStringListModel is created using those values. + ///View changes operate on the selection model only. + void buildFixedValueModel (const QStringList &definitions); + + ///In cases where the view does not have a pre-defined list of possible + ///values, a QStandardItemModel is created, containing the actual + ///setting definitions. View changes first update the data in the + ///model to match the data in the view. The selection model always + ///selects all values. + void buildUpdatableValueModel (const QStringList &definitions); + + ///Refreshes the view + void refresh() const; + + ///Convenince function for selection model's select() method. Also + ///clears out the model beforehand to ensure complete selection. + void select (const QItemSelection &selection) const; + + ///Compares two string lists "loosely", ensuring that all values in + ///one list are contained entirely in the other, and that neither list + ///has more values than the other. List order is not considered. + bool stringListsMatch (const QStringList &list1, + const QStringList &list2) const; + + ///Converts a string list to a list of QStandardItem pointers. + QList toStandardItemList(const QStringList &) const; + + signals: + + ///Signals that the view has been changed. + void viewUpdated(const QString &, const QStringList &) const; + + }; + + class IViewFactory + { + public: + + ///Creation interface for view factories + virtual View *createView (CSMSettings::Setting *setting, + Page *parent) = 0; + }; +} +#endif // CSVSETTINGS_VIEW_HPP From e3384e399913e2dc4a56f599fea0f1e8b4ab65b9 Mon Sep 17 00:00:00 2001 From: graffy76 Date: Tue, 22 Apr 2014 22:17:52 -0500 Subject: [PATCH 012/118] relocate support.hpp / remove support.cpp --- apps/opencs/CMakeLists.txt | 31 ++-- apps/opencs/model/settings/support.cpp | 1 - apps/opencs/model/settings/support.hpp | 139 +++++++++++++---- apps/opencs/view/settings/support.cpp | 1 - apps/opencs/view/settings/support.hpp | 206 ------------------------- 5 files changed, 126 insertions(+), 252 deletions(-) delete mode 100644 apps/opencs/model/settings/support.cpp delete mode 100644 apps/opencs/view/settings/support.cpp delete mode 100644 apps/opencs/view/settings/support.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index cbe90b1d3..8ab44243d 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -88,34 +88,29 @@ opencs_units_noqt (view/tools ) opencs_units (view/settings - abstractblock - proxyblock - abstractwidget - usersettingsdialog - datadisplayformatpage - windowpage + settingwindow + dialog + page + view + booleanview + textview + listview + resizeablestackedwidget ) opencs_units_noqt (view/settings - abstractpage - blankpage - groupblock - customblock - groupbox - itemblock - settingwidget - toggleblock - support + frame ) opencs_units (model/settings usersettings - settingcontainer + settingmanager + setting + connector ) -opencs_units_noqt (model/settings +opencs_hdrs_noqt (model/settings support - settingsitem ) opencs_units_noqt (model/filter diff --git a/apps/opencs/model/settings/support.cpp b/apps/opencs/model/settings/support.cpp deleted file mode 100644 index d79edfdb3..000000000 --- a/apps/opencs/model/settings/support.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "support.hpp" diff --git a/apps/opencs/model/settings/support.hpp b/apps/opencs/model/settings/support.hpp index 4ffd01b73..abc86a0cb 100644 --- a/apps/opencs/model/settings/support.hpp +++ b/apps/opencs/model/settings/support.hpp @@ -1,39 +1,126 @@ -#ifndef MODEL_SUPPORT_HPP -#define MODEL_SUPPORT_HPP +#ifndef SETTING_SUPPORT_HPP +#define SETTING_SUPPORT_HPP -#include +#include +#include +#include +#include #include -class QLayout; -class QWidget; -class QListWidgetItem; - +//Typedefs namespace CSMSettings { - class SettingContainer; + // Definition / Declaration model typedefs + // "Pair" = Setting name and specific data + // "ListItem" = Page name and associated setting pair - typedef QList SettingList; - typedef QMap SettingMap; - typedef QMap SectionMap; + typedef QPair StringPair; + typedef QPair StringListPair; + typedef QList StringListPairs; - struct QStringPair +} + +//Enums +namespace CSMSettings +{ + enum SettingProperty { - QStringPair(): left (""), right ("") - {} + Property_Name = 0, + Property_Page = 1, + Property_ViewType = 2, + Property_IsMultiValue = 3, + Property_IsMultiLine = 4, + Property_WidgetWidth = 5, + Property_ViewRow = 6, + Property_ViewColumn = 7, + Property_Delimiter = 8, + Property_Serializable = 9, + Property_ColumnSpan = 10, + Property_RowSpan = 11, - QStringPair (const QString &leftValue, const QString &rightValue) - : left (leftValue), right(rightValue) - {} + //Stringlists should always be the last items + Property_DefaultValues = 12, + Property_DeclaredValues = 13, + Property_DefinedValues = 14, + Property_Proxies = 15 + }; - QStringPair (const QStringPair &pair) - : left (pair.left), right (pair.right) - {} + enum SettingType + { + Type_MultiBool = 0, + Type_SingleBool = 1, + Type_MultiList = 2, + Type_SingleList = 3, + Type_MultiRange = 4, + Type_SingleRange = 5, + Type_MultiText = 6, + Type_SingleText = 7 + }; - QString left; - QString right; - - bool isEmpty() const - { return (left.isEmpty() && right.isEmpty()); } + enum MergeMethod + { + Merge_Accept, + Merge_Ignore, + Merge_Overwrite }; } -#endif // MODEL_SUPPORT_HPP + +namespace CSVSettings +{ + enum ViewType + { + ViewType_Boolean = 0, + ViewType_List = 1, + ViewType_Range = 2, + ViewType_Text = 3, + ViewType_Undefined = 4 + }; + + enum Alignment + { + Align_Left = Qt::AlignLeft, + Align_Center = Qt::AlignHCenter, + Align_Right = Qt::AlignRight + }; +} + +// +namespace CSMSettings +{ + struct PropertyDefaultValues + { + int id; + QString name; + QVariant value; + }; + + const QString sPropertyNames[] = + { + "name", "page", "view_type", "is_multi_value", + "is_multi_line", "widget_width", "view_row", "view_column", "delimiter", + "is_serializable","column_span", "row_span", + "defaults", "declarations", "definitions", "proxies" + }; + + const QString sPropertyDefaults[] = + { + "", //name + "", //page + "0", //view type + "false", //multivalue + "false", //multiline + "0", //widget width + "-1", //view row + "-1", //view column + ",", //delimiter + "true", //serialized + "1", //column span + "1", //row span + "", //default values + "", //declared values + "", //defined values + "" //proxy values + }; +} + +#endif // VIEW_SUPPORT_HPP diff --git a/apps/opencs/view/settings/support.cpp b/apps/opencs/view/settings/support.cpp deleted file mode 100644 index d79edfdb3..000000000 --- a/apps/opencs/view/settings/support.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "support.hpp" diff --git a/apps/opencs/view/settings/support.hpp b/apps/opencs/view/settings/support.hpp deleted file mode 100644 index 5d954505c..000000000 --- a/apps/opencs/view/settings/support.hpp +++ /dev/null @@ -1,206 +0,0 @@ -#ifndef VIEW_SUPPORT_HPP -#define VIEW_SUPPORT_HPP - -#include -#include - -#include "../../model/settings/support.hpp" - -namespace CSVSettings -{ - struct WidgetDef; - class ItemBlock; - class GroupBlock; - struct GroupBlockDef; - - typedef QList GroupBlockDefList; - typedef QList GroupBlockList; - typedef QList ItemBlockList; - typedef QList ProxyList; - typedef QList WidgetList; - typedef QMap ItemBlockMap; - - enum Orientation - { - Orient_Horizontal, - Orient_Vertical - }; - - enum WidgetType - { - Widget_CheckBox, - Widget_ComboBox, - Widget_LineEdit, - Widget_ListBox, - Widget_RadioButton, - Widget_SpinBox, - Widget_Undefined - }; - - enum Alignment - { - Align_Left = Qt::AlignLeft, - Align_Center = Qt::AlignHCenter, - Align_Right = Qt::AlignRight - }; - - /// definition struct for widgets - struct WidgetDef - { - /// type of widget providing input - WidgetType type; - - /// width of caption label - int labelWidth; - - /// width of input widget - int widgetWidth; - - /// label / widget orientation (horizontal / vertical) - Orientation orientation; - - /// input mask (line edit only) - QString inputMask; - - /// label caption. Leave empty for multiple items. See BlockDef::captionList - QString caption; - - /// widget value. Leave empty for multiple items. See BlockDef::valueList - QString value; - - /// Min/Max QString value pair. If empty, assigned to property item value pair. - CSMSettings::QStringPair *minMax; - - /// value list for list widgets. If left empty, is assigned to property item value list during block build(). - QStringList *valueList; - - /// determined at runtime - bool isDefault; - - /// left / center / right-justify text in widget - Alignment valueAlignment; - - /// left / center / right-justify widget in group box - Alignment widgetAlignment; - - - WidgetDef() : labelWidth (-1), widgetWidth (-1), - orientation (Orient_Horizontal), - isDefault (true), valueAlignment (Align_Center), - widgetAlignment (Align_Right), - inputMask (""), value (""), - caption (""), valueList (0) - {} - - WidgetDef (WidgetType widgType) - : type (widgType), orientation (Orient_Horizontal), - caption (""), value (""), valueAlignment (Align_Center), - widgetAlignment (Align_Right), - labelWidth (-1), widgetWidth (-1), - valueList (0), isDefault (true) - {} - - }; - - /// Defines the attributes of the setting as it is represented in the config file - /// as well as the UI elements (group box and widget) that serve it. - /// Only one widget may serve as the input widget for the setting. - struct SettingsItemDef - { - /// setting name - QString name; - - /// list of valid values for the setting - QStringList *valueList; - - /// Used to populate option widget captions or list widget item lists (see WidgetDef::caption / value) - QString defaultValue; - - /// flag indicating multi-valued setting - bool hasMultipleValues; - - /// minimum / maximum value pair - CSMSettings::QStringPair minMax; - - /// definition of the input widget for this setting - WidgetDef widget; - - /// general orientation of the widget / label for this setting - Orientation orientation; - - /// list of settings and corresponding default values for proxy widget - ProxyList *proxyList; - - SettingsItemDef() : name (""), defaultValue (""), orientation (Orient_Vertical), hasMultipleValues (false) - {} - - SettingsItemDef (QString propName, QString propDefault, Orientation propOrient = Orient_Vertical) - : name (propName), defaultValue (propDefault), orientation (propOrient), - hasMultipleValues(false), valueList (new QStringList), proxyList ( new ProxyList) - {} - }; - - - /// Generic container block - struct GroupBlockDef - { - /// block title - QString title; - - /// list of captions for widgets at the block level (not associated with any particular setting) - QStringList captions; - - /// list of widgets at the block level (not associated with any particular setting) - WidgetList widgets; - - /// list of the settings which are subordinate to the setting block. - QList settingItems; - - /// general orientation of widgets in group block - Orientation widgetOrientation; - - /// determines whether or not box border/title are visible - bool isVisible; - - /// indicates whether or not this block defines a proxy block - bool isProxy; - - /// generic default value attribute - QString defaultValue; - - /// shows / hides margins - bool isZeroMargin; - - GroupBlockDef (): title(""), widgetOrientation (Orient_Vertical), isVisible (true), isProxy (false), defaultValue (""), isZeroMargin (true) - {} - - GroupBlockDef (QString blockTitle) - : title (blockTitle), widgetOrientation (Orient_Vertical), isProxy (false), isVisible (true), defaultValue (""), isZeroMargin (true) - {} - }; - - /// used to create unique, complex blocks - struct CustomBlockDef - { - /// block title - QString title; - - /// default value for widgets unique to the custom block - QString defaultValue; - - /// list of settings groups that comprise the settings within the custom block - GroupBlockDefList blockDefList; - - /// orientation of the widgets within the block - Orientation blockOrientation; - - CustomBlockDef (): title (""), defaultValue (""), blockOrientation (Orient_Horizontal) - {} - - CustomBlockDef (const QString &blockTitle) - : title (blockTitle), defaultValue (""), blockOrientation (Orient_Horizontal) - {} - }; -} - -#endif // VIEW_SUPPORT_HPP From 4b607d658f5e8f2008d06395f270b2f902ef4d3f Mon Sep 17 00:00:00 2001 From: graffy76 Date: Tue, 22 Apr 2014 22:19:53 -0500 Subject: [PATCH 013/118] Re-link user settings to editor main application --- apps/opencs/editor.cpp | 13 + apps/opencs/editor.hpp | 4 +- apps/opencs/model/settings/usersettings.cpp | 477 +++++++++----------- apps/opencs/model/settings/usersettings.hpp | 45 +- apps/opencs/view/doc/subview.cpp | 9 +- apps/opencs/view/doc/subview.hpp | 4 +- apps/opencs/view/doc/view.cpp | 39 +- apps/opencs/view/doc/view.hpp | 2 + apps/opencs/view/doc/viewmanager.cpp | 17 +- apps/opencs/view/doc/viewmanager.hpp | 3 - apps/opencs/view/tools/reportsubview.cpp | 7 +- apps/opencs/view/tools/reportsubview.hpp | 5 +- apps/opencs/view/world/table.cpp | 14 +- apps/opencs/view/world/table.hpp | 2 +- apps/opencs/view/world/tablesubview.cpp | 7 +- apps/opencs/view/world/tablesubview.hpp | 3 +- apps/opencs/view/world/util.cpp | 6 +- apps/opencs/view/world/util.hpp | 4 +- 18 files changed, 290 insertions(+), 371 deletions(-) diff --git a/apps/opencs/editor.cpp b/apps/opencs/editor.cpp index 87660a60b..2dfdb1de6 100644 --- a/apps/opencs/editor.cpp +++ b/apps/opencs/editor.cpp @@ -28,6 +28,7 @@ CS::Editor::Editor (OgreInit::OgreInit& ogreInit) setupDataFiles (config.first); CSMSettings::UserSettings::instance().loadSettings ("opencs.cfg"); + mSettings.setModel (CSMSettings::UserSettings::instance()); ogreInit.init ((mCfgMgr.getUserConfigPath() / "opencsOgre.log").string()); @@ -117,6 +118,18 @@ std::pair > CS::Editor::readConfi dataDirs.insert (dataDirs.end(), dataLocal.begin(), dataLocal.end()); + //iterate the data directories and add them to the file dialog for loading + for (Files::PathContainer::const_iterator iter = dataDirs.begin(); iter != dataDirs.end(); ++iter) + { + QString path = QString::fromStdString(iter->string()); + mFileDialog.addFiles(path); + } +/* + //load the settings into the userSettings instance. + const QString settingFileName = "opencs.cfg"; + CSMSettings::UserSettings::instance().loadSettings(settingFileName); +*/ + return std::make_pair (dataDirs, variables["fallback-archive"].as >()); } diff --git a/apps/opencs/editor.hpp b/apps/opencs/editor.hpp index 164398fb7..4c02b462e 100644 --- a/apps/opencs/editor.hpp +++ b/apps/opencs/editor.hpp @@ -24,7 +24,7 @@ #include "view/doc/filedialog.hpp" #include "view/doc/newgame.hpp" -#include "view/settings/usersettingsdialog.hpp" +#include "view/settings/dialog.hpp" namespace OgreInit { @@ -43,7 +43,7 @@ namespace CS CSVDoc::ViewManager mViewManager; CSVDoc::StartupDialogue mStartup; CSVDoc::NewGameDialogue mNewGame; - CSVSettings::UserSettingsDialog mSettings; + CSVSettings::Dialog mSettings; CSVDoc::FileDialog mFileDialog; boost::filesystem::path mLocal; boost::filesystem::path mResources; diff --git a/apps/opencs/model/settings/usersettings.cpp b/apps/opencs/model/settings/usersettings.cpp index 94cee8a43..db31f4255 100644 --- a/apps/opencs/model/settings/usersettings.cpp +++ b/apps/opencs/model/settings/usersettings.cpp @@ -9,11 +9,16 @@ #include #include +#include + +#include #include -#include "settingcontainer.hpp" #include +#include "setting.hpp" +#include "support.hpp" + /** * Workaround for problems with whitespaces in paths in older versions of Boost library */ @@ -37,38 +42,151 @@ CSMSettings::UserSettings::UserSettings() assert(!mUserSettingsInstance); mUserSettingsInstance = this; - mReadWriteMessage = QObject::tr("
Could not open or create file for writing

\ - Please make sure you have the right permissions and try again.
"); - - mReadOnlyMessage = QObject::tr("
Could not open file for reading

\ - Please make sure you have the right permissions and try again.
"); - - buildEditorSettingDefaults(); + buildSettingModelDefaults(); } -void CSMSettings::UserSettings::buildEditorSettingDefaults() +void CSMSettings::UserSettings::buildSettingModelDefaults() { - SettingContainer *windowHeight = new SettingContainer("768", this); - SettingContainer *windowWidth = new SettingContainer("1024", this); - SettingContainer *rsDelegate = new SettingContainer("Icon and Text", this); - SettingContainer *refIdTypeDelegate = new SettingContainer("Icon and Text", this); + QString section = "Window Size"; + { + Setting *width = createSetting (Type_SingleText, section, "Width"); + Setting *height = createSetting (Type_SingleText, section, "Height"); - windowHeight->setObjectName ("Height"); - windowWidth->setObjectName ("Width"); - rsDelegate->setObjectName ("Record Status Display"); - refIdTypeDelegate->setObjectName ("Referenceable ID Type Display"); + width->setWidgetWidth (5); + height->setWidgetWidth (5); - SettingMap *displayFormatMap = new SettingMap; - SettingMap *windowSizeMap = new SettingMap; + width->setDefaultValues (QStringList() << "1024"); + height->setDefaultValues (QStringList() << "768"); - displayFormatMap->insert (rsDelegate->objectName(), rsDelegate ); - displayFormatMap->insert (refIdTypeDelegate->objectName(), refIdTypeDelegate); + width->setEditorSetting (true); + height->setEditorSetting (true); - windowSizeMap->insert (windowWidth->objectName(), windowWidth ); - windowSizeMap->insert (windowHeight->objectName(), windowHeight ); + height->setViewLocation (2,2); + width->setViewLocation (2,1); - mEditorSettingDefaults.insert ("Display Format", displayFormatMap); - mEditorSettingDefaults.insert ("Window Size", windowSizeMap); + /* + *Create the proxy setting for predefined values + */ + Setting *preDefined = createSetting (Type_SingleList, section, + "Pre-Defined", + QStringList() + << "640 x 480" + << "800 x 600" + << "1024 x 768" + << "1440 x 900" + ); + + preDefined->setViewLocation (1, 1); + preDefined->setWidgetWidth (10); + preDefined->setColumnSpan (2); + + preDefined->addProxy (width, + QStringList() << "640" << "800" << "1024" << "1440" + ); + + preDefined->addProxy (height, + QStringList() << "480" << "600" << "768" << "900" + ); + } + + section = "Display Format"; + { + QString defaultValue = "Icon and Text"; + + QStringList values = QStringList() + << defaultValue << "Icon Only" << "Text Only"; + + Setting *rsd = createSetting (Type_SingleBool, + section, "Record Status Display", + values); + + Setting *ritd = createSetting (Type_SingleBool, + section, "Referenceable ID Type Display", + values); + + rsd->setEditorSetting (true); + ritd->setEditorSetting (true); + } + + section = "Proxy Selection Test"; + { + //create three setting objects, specifying the basic widget type, + //the setting view name, the page name, and the default value + Setting *masterBoolean = createSetting (Type_SingleBool, section, + "Master Proxy", + QStringList() + << "Profile One" << "Profile Two" + << "Profile Three" << "Profile Four" + ); + + Setting *slaveBoolean = createSetting (Type_MultiBool, section, + "Proxy Checkboxes", + QStringList() << "One" << "Two" + << "Three" << "Four" << "Five" + ); + + Setting *slaveSingleText = createSetting (Type_SingleText, section, + "Proxy TextBox 1" + ); + + Setting *slaveMultiText = createSetting (Type_SingleText, section, + "ProxyTextBox 2" + ); + + // There are three types of values: + // + // Declared values - Pre-determined values, typically for + // combobox drop downs and boolean (radiobutton / checkbox) labels. + // These values represent the total possible list of values that may + // define a setting. No other values are allowed. + // + // Defined values - Values which represent the atual, current value of + // a setting. For settings with declared values, this must be one or + // several declared values, as appropriate. + // + // Proxy values - values the proxy master updates the proxy slave when + // it's own definition is set / changed. These are definitions for + // proxy slave settings, but must match any declared values the proxy + // slave has, if any. + + masterBoolean->addProxy (slaveBoolean, QList () + << (QStringList() << "One" << "Three") + << (QStringList() << "One" << "Three") + << (QStringList() << "One" << "Three" << "Five") + << (QStringList() << "Two" << "Four") + ); + + masterBoolean->addProxy (slaveSingleText, QList () + << (QStringList() << "Text A") + << (QStringList() << "Text B") + << (QStringList() << "Text A") + << (QStringList() << "Text C") + ); + + masterBoolean->addProxy (slaveMultiText, QList () + << (QStringList() << "One" << "Three") + << (QStringList() << "One" << "Three") + << (QStringList() << "One" << "Three" << "Five") + << (QStringList() << "Two" << "Four") + ); + + //settings with proxies are not serialized by default + //other settings non-serialized for demo purposes + slaveBoolean->setSerializable (false); + slaveSingleText->setSerializable (false); + slaveMultiText->setSerializable (false); + + slaveBoolean->setDefaultValues (QStringList() + << "One" << "Three" << "Five"); + + slaveSingleText->setDefaultValue ("Text A"); + + slaveMultiText->setDefaultValues (QStringList() + << "One" << "Three" << "Five"); + + slaveSingleText->setWidgetWidth (24); + slaveMultiText->setWidgetWidth (24); + } } CSMSettings::UserSettings::~UserSettings() @@ -76,230 +194,83 @@ CSMSettings::UserSettings::~UserSettings() mUserSettingsInstance = 0; } -QTextStream *CSMSettings::UserSettings::openFileStream (const QString &filePath, bool isReadOnly) const -{ - QIODevice::OpenMode openFlags = QIODevice::Text; - - if (isReadOnly) - openFlags = QIODevice::ReadOnly | openFlags; - else - openFlags = QIODevice::ReadWrite | QIODevice::Truncate | openFlags; - - QFile *file = new QFile(filePath); - QTextStream *stream = 0; - - if (file->open(openFlags)) - { - stream = new QTextStream(file); - stream->setCodec(QTextCodec::codecForName("UTF-8")); - } - - return stream; - -} - -bool CSMSettings::UserSettings::writeSettings(QMap &settings) -{ - QTextStream *stream = openFileStream(mUserFilePath); - - bool success = (stream); - - if (success) - { - QList keyList = settings.keys(); - - foreach (QString key, keyList) - { - SettingList *sectionSettings = settings[key]; - - *stream << "[" << key << "]" << '\n'; - - foreach (SettingContainer *item, *sectionSettings) - *stream << item->objectName() << " = " << item->getValue() << '\n'; - } - - stream->device()->close(); - delete stream; - stream = 0; - } - else - { - displayFileErrorMessage(mReadWriteMessage, false); - } - - return (success); -} - - -const CSMSettings::SectionMap &CSMSettings::UserSettings::getSectionMap() const -{ - return mSectionSettings; -} - -const CSMSettings::SettingMap *CSMSettings::UserSettings::getSettings(const QString §ionName) const -{ - return getValidSettings(sectionName); -} - -bool CSMSettings::UserSettings::loadFromFile(const QString &filePath) -{ - if (filePath.isEmpty()) - return false; - - SectionMap loadedSettings; - - QTextStream *stream = openFileStream (filePath, true); - - bool success = (stream); - - if (success) - { - //looks for a square bracket, "'\\[" - //that has one or more "not nothing" in it, "([^]]+)" - //and is closed with a square bracket, "\\]" - - QRegExp sectionRe("^\\[([^]]+)\\]"); - - //Find any character(s) that is/are not equal sign(s), "[^=]+" - //followed by an optional whitespace, an equal sign, and another optional whitespace, "\\s*=\\s*" - //and one or more periods, "(.+)" - - QRegExp keyRe("^([^=]+)\\s*=\\s*(.+)$"); - - CSMSettings::SettingMap *settings = 0; - QString section = "none"; - - while (!stream->atEnd()) - { - QString line = stream->readLine().simplified(); - - if (line.isEmpty() || line.startsWith("#")) - continue; - - //if a section is found, push it onto a new QStringList - //and push the QStringList onto - if (sectionRe.exactMatch(line)) - { - //add the previous section's settings to the member map - if (settings) - loadedSettings.insert(section, settings); - - //save new section and create a new list - section = sectionRe.cap(1); - settings = new SettingMap; - continue; - } - - if (keyRe.indexIn(line) != -1) - { - SettingContainer *sc = new SettingContainer (keyRe.cap(2).simplified()); - sc->setObjectName(keyRe.cap(1).simplified()); - (*settings)[keyRe.cap(1).simplified()] = sc; - } - - } - - loadedSettings.insert(section, settings); - - stream->device()->close(); - delete stream; - stream = 0; - } - - mergeMap (loadedSettings); - - return success; -} - -void CSMSettings::UserSettings::mergeMap (const CSMSettings::SectionMap §ionSettings) -{ - foreach (QString key, sectionSettings.uniqueKeys()) - { - // insert entire section if it does not already exist in the loaded files - if (mSectionSettings.find(key) == mSectionSettings.end()) - mSectionSettings.insert(key, sectionSettings.value(key)); - else - { - SettingMap *passedSettings = sectionSettings.value(key); - SettingMap *settings = mSectionSettings.value(key); - - foreach (QString key2, passedSettings->uniqueKeys()) - { - //insert section settings individially if they do not already exist - if (settings->find(key2) == settings->end()) - settings->insert(key2, passedSettings->value(key2)); - else - { - settings->value(key2)->update(passedSettings->value(key2)->getValue()); - } - } - } - } -} - void CSMSettings::UserSettings::loadSettings (const QString &fileName) { - mSectionSettings.clear(); + mUserFilePath = QString::fromUtf8 + (mCfgMgr.getUserConfigPath().c_str()) + fileName.toUtf8(); - //global - QString globalFilePath = QString::fromStdString(mCfgMgr.getGlobalPath().string()) + fileName; - bool globalOk = loadFromFile(globalFilePath); + QString global = QString::fromUtf8 + (mCfgMgr.getGlobalPath().c_str()) + fileName.toUtf8(); + QString local = QString::fromUtf8 + (mCfgMgr.getLocalPath().c_str()) + fileName.toUtf8(); - //local - QString localFilePath = QString::fromStdString(mCfgMgr.getLocalPath().string()) + fileName; - bool localOk = loadFromFile(localFilePath); + //open user and global streams + QTextStream *userStream = openFilestream (mUserFilePath, true); + QTextStream *otherStream = openFilestream (global, true); - //user - mUserFilePath = QString::fromStdString(mCfgMgr.getUserConfigPath().string()) + fileName; - loadFromFile(mUserFilePath); + //failed stream, try for local + if (!otherStream) + otherStream = openFilestream (local, true); - if (!(localOk || globalOk)) + //error condition - notify and return + if (!otherStream || !userStream) { - QString message = QObject::tr("
Could not open user settings files for reading

\ - Global and local settings files could not be read.\ - You may have incorrect file permissions or the OpenCS installation may be corrupted.
"); + QString message = QObject::tr("
An error was encountered loading \ + user settings files.

One or several files could not \ + be read. This may be caused by a missing configuration file, \ + incorrect file permissions or a corrupted installation of \ + OpenCS.
"); - message += QObject::tr("
Global filepath: ") + globalFilePath; - message += QObject::tr("
Local filepath: ") + localFilePath; + message += QObject::tr("
Global filepath: ") + global; + message += QObject::tr("
Local filepath: ") + local; + message += QObject::tr("
User filepath: ") + mUserFilePath; displayFileErrorMessage ( message, true); - } -} - -void CSMSettings::UserSettings::updateSettings (const QString §ionName, const QString &settingName) -{ - - SettingMap *settings = getValidSettings(sectionName); - - if (!settings) return; + } - if (settingName.isEmpty()) - { - foreach (const SettingContainer *setting, *settings) - emit signalUpdateEditorSetting (setting->objectName(), setting->getValue()); - } - else - { - if (settings->find(settingName) != settings->end()) - { - const SettingContainer *setting = settings->value(settingName); - emit signalUpdateEditorSetting (setting->objectName(), setting->getValue()); - } - } + //success condition - merge the two streams into a single map and save + DefinitionPageMap totalMap = readFilestream (userStream); + DefinitionPageMap otherMap = readFilestream(otherStream); + + //merging other settings file in and ignore duplicate settings to + //avoid overwriting user-level settings + mergeSettings (totalMap, otherMap); + + if (!totalMap.isEmpty()) + addDefinitions (totalMap); } -QString CSMSettings::UserSettings::getSetting (const QString §ion, const QString &setting) const +void CSMSettings::UserSettings::saveSettings + (const QMap &settingMap) { - SettingMap *settings = getValidSettings(section); + for (int i = 0; i < settings().size(); i++) + { + Setting* setting = settings().at(i); - QString retVal = ""; + QString key = setting->page() + '.' + setting->name(); - if (settings->find(setting) != settings->end()) - retVal = settings->value(setting)->getValue(); + if (!settingMap.keys().contains(key)) + continue; - return retVal; + setting->setDefinedValues (settingMap.value(key)); + } + + writeFilestream (openFilestream (mUserFilePath, false), settingMap); +} + +QString CSMSettings::UserSettings::settingValue (const QString §ion, + const QString &name) +{ + Setting *setting = findSetting(section, name); + + if (setting) + { + if (!setting->definedValues().isEmpty()) + return setting->definedValues().at(0); + } + return ""; } CSMSettings::UserSettings& CSMSettings::UserSettings::instance() @@ -307,49 +278,3 @@ CSMSettings::UserSettings& CSMSettings::UserSettings::instance() assert(mUserSettingsInstance); return *mUserSettingsInstance; } - -void CSMSettings::UserSettings::displayFileErrorMessage(const QString &message, bool isReadOnly) -{ - // File cannot be opened or created - QMessageBox msgBox; - msgBox.setWindowTitle(QObject::tr("OpenCS configuration file I/O error")); - msgBox.setIcon(QMessageBox::Critical); - msgBox.setStandardButtons(QMessageBox::Ok); - - if (!isReadOnly) - msgBox.setText (mReadWriteMessage + message); - else - msgBox.setText (message); - - msgBox.exec(); -} - -CSMSettings::SettingMap * -CSMSettings::UserSettings::getValidSettings (const QString §ionName) const -{ - SettingMap *settings = 0; - - //copy the default values for the entire section if it's not found - if (mSectionSettings.find(sectionName) == mSectionSettings.end()) - { - if (mEditorSettingDefaults.find(sectionName) != mEditorSettingDefaults.end()) - settings = mEditorSettingDefaults.value (sectionName); - } - //otherwise, iterate the section's settings, looking for missing values and replacing them with defaults. - else - { - SettingMap *loadedSettings = mSectionSettings[sectionName]; - SettingMap *defaultSettings = mEditorSettingDefaults[sectionName]; - - foreach (QString key, defaultSettings->uniqueKeys()) - { - //write the default value to the loaded settings - if (loadedSettings->find((key))==loadedSettings->end()) - loadedSettings->insert(key, defaultSettings->value(key)); - } - - settings = mSectionSettings.value (sectionName); - } - - return settings; -} diff --git a/apps/opencs/model/settings/usersettings.hpp b/apps/opencs/model/settings/usersettings.hpp index 63e78bd61..75a3a0797 100644 --- a/apps/opencs/model/settings/usersettings.hpp +++ b/apps/opencs/model/settings/usersettings.hpp @@ -8,7 +8,7 @@ #include -#include "support.hpp" +#include "settingmanager.hpp" #ifndef Q_MOC_RUN #include @@ -21,17 +21,15 @@ class QFile; namespace CSMSettings { - struct UserSettings: public QObject + class UserSettings: public SettingManager { Q_OBJECT - SectionMap mSectionSettings; - SectionMap mEditorSettingDefaults; - static UserSettings *mUserSettingsInstance; QString mUserFilePath; Files::ConfigurationManager mCfgMgr; + QString mReadOnlyMessage; QString mReadWriteMessage; @@ -47,48 +45,23 @@ namespace CSMSettings { void operator= (UserSettings const &); //not implemented /// Writes settings to the last loaded settings file - bool writeSettings(QMap §ions); - - /// Called from editor to trigger signal to update the specified setting. - /// If no setting name is specified, all settings found in the specified section are updated. - void updateSettings (const QString §ionName, const QString &settingName = ""); + bool writeSettings(); /// Retrieves the settings file at all three levels (global, local and user). - - /// \todo Multi-valued settings are not fully implemented. Setting values - /// \todo loaded in later files will always overwrite previously loaded values. void loadSettings (const QString &fileName); - /// Returns the entire map of settings across all sections - const SectionMap &getSectionMap () const; + /// Writes settings to the user's config file path + void saveSettings (const QMap &settingMap); - const SettingMap *getSettings (const QString §ionName) const; - - /// Retrieves the value as a QString of the specified setting in the specified section - QString getSetting(const QString §ion, const QString &setting) const; + QString settingValue (const QString §ion, const QString &name); private: - - /// Opens a QTextStream from the provided path as read-only or read-write. - QTextStream *openFileStream (const QString &filePath, bool isReadOnly = false) const; - - /// Parses a setting file specified in filePath from the provided text stream. - bool loadFromFile (const QString &filePath = ""); - - /// merge the passed map into mSectionSettings - void mergeMap (const SectionMap &); - - void displayFileErrorMessage(const QString &message, bool isReadOnly); - - void buildEditorSettingDefaults(); - - SettingMap *getValidSettings (const QString §ionName) const; + void buildSettingModelDefaults(); signals: - void signalUpdateEditorSetting (const QString &settingName, const QString &settingValue); - + void userSettingUpdated(const QString &, const QStringList &); }; } #endif // USERSETTINGS_HPP diff --git a/apps/opencs/view/doc/subview.cpp b/apps/opencs/view/doc/subview.cpp index 7fd005717..a80d21cb2 100644 --- a/apps/opencs/view/doc/subview.cpp +++ b/apps/opencs/view/doc/subview.cpp @@ -12,16 +12,15 @@ CSMWorld::UniversalId CSVDoc::SubView::getUniversalId() const return mUniversalId; } -void CSVDoc::SubView::updateEditorSetting (const QString &settingName, const QString &settingValue) -{ -} - void CSVDoc::SubView::setStatusBar (bool show) {} void CSVDoc::SubView::useHint (const std::string& hint) {} +void CSVDoc::SubView::updateUserSetting (const QString &, const QStringList &) +{} + void CSVDoc::SubView::setUniversalId (const CSMWorld::UniversalId& id) { mUniversalId = id; setWindowTitle (mUniversalId.toString().c_str()); -} \ No newline at end of file +} diff --git a/apps/opencs/view/doc/subview.hpp b/apps/opencs/view/doc/subview.hpp index 85274a18d..52e42cc0e 100644 --- a/apps/opencs/view/doc/subview.hpp +++ b/apps/opencs/view/doc/subview.hpp @@ -37,7 +37,9 @@ namespace CSVDoc CSMWorld::UniversalId getUniversalId() const; virtual void setEditLock (bool locked) = 0; - virtual void updateEditorSetting (const QString &, const QString &); + + virtual void updateUserSetting + (const QString &, const QStringList &); virtual void setStatusBar (bool show); ///< Default implementation: ignored diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index bc34c6118..47e1a80de 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -12,7 +12,7 @@ #include "../../model/doc/document.hpp" #include "../world/subviews.hpp" #include "../tools/subviews.hpp" -#include "../settings/usersettingsdialog.hpp" +#include "../../model/settings/usersettings.hpp" #include "viewmanager.hpp" #include "operations.hpp" #include "subview.hpp" @@ -235,8 +235,11 @@ CSVDoc::View::View (ViewManager& viewManager, CSMDoc::Document *document, int to : mViewManager (viewManager), mDocument (document), mViewIndex (totalViews-1), mViewTotal (totalViews) { - QString width = CSMSettings::UserSettings::instance().getSetting(QString("Window Size"), QString("Width")); - QString height = CSMSettings::UserSettings::instance().getSetting(QString("Window Size"), QString("Height")); + QString width = CSMSettings::UserSettings::instance().settingValue + (QString("Window Size"), QString("Width")); + + QString height = CSMSettings::UserSettings::instance().settingValue + (QString("Window Size"), QString("Height")); resize (width.toInt(), height.toInt()); @@ -336,7 +339,10 @@ void CSVDoc::View::addSubView (const CSMWorld::UniversalId& id, const std::strin connect (view, SIGNAL (focusId (const CSMWorld::UniversalId&, const std::string&)), this, SLOT (addSubView (const CSMWorld::UniversalId&, const std::string&))); - CSMSettings::UserSettings::instance().updateSettings("Display Format"); + connect (&CSMSettings::UserSettings::instance(), + SIGNAL (userSettingUpdated (const QString &, const QStringList &)), + view, + SLOT (updateUserSetting (const QString &, const QStringList &))); view->show(); } @@ -484,24 +490,19 @@ void CSVDoc::View::resizeViewHeight (int height) resize (geometry().width(), height); } -void CSVDoc::View::updateEditorSetting (const QString &settingName, const QString &settingValue) +void CSVDoc::View::updateUserSetting + (const QString &name, const QStringList &list) { - if ( (settingName == "Record Status Display") || (settingName == "Referenceable ID Type Display") ) - { - foreach (QObject *view, mSubViewWindow.children()) - { - // not all mSubviewWindow children are CSVDoc::Subview objects - CSVDoc::SubView *subview = dynamic_cast(view); + if (list.isEmpty()) + return; - if (subview) - subview->updateEditorSetting (settingName, settingValue); - } - } - else if (settingName == "Width") - resizeViewWidth (settingValue.toInt()); + int value = list.at(0).toInt(); - else if (settingName == "Height") - resizeViewHeight (settingValue.toInt()); + if (name == "Width") + resizeViewWidth (value); + + else if (name == "Height") + resizeViewHeight (value); } void CSVDoc::View::toggleShowStatusBar (bool show) diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp index ee7380e2b..5e6c9abc4 100644 --- a/apps/opencs/view/doc/view.hpp +++ b/apps/opencs/view/doc/view.hpp @@ -126,6 +126,8 @@ namespace CSVDoc void abortOperation (int type); + void updateUserSetting (const QString &, const QStringList &); + private slots: void newView(); diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index 4a4dbc124..2297af0ba 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -15,7 +15,8 @@ #include "../world/vartypedelegate.hpp" #include "../world/recordstatusdelegate.hpp" #include "../world/idtypedelegate.hpp" -#include "../settings/usersettingsdialog.hpp" + +#include "../../model/settings/usersettings.hpp" #include "view.hpp" @@ -83,9 +84,6 @@ CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager) for (std::size_t i=0; iadd (sMapping[i].mDisplay, new CSVWorld::EnumDelegateFactory ( CSMWorld::Columns::getEnums (sMapping[i].mColumnId), sMapping[i].mAllowNone)); - - connect (&CSMSettings::UserSettings::instance(), SIGNAL (signalUpdateEditorSetting (const QString &, const QString &)), - this, SLOT (slotUpdateEditorSetting (const QString &, const QString &))); } CSVDoc::ViewManager::~ViewManager() @@ -119,6 +117,11 @@ CSVDoc::View *CSVDoc::ViewManager::addView (CSMDoc::Document *document) connect (view, SIGNAL (loadDocumentRequest ()), this, SIGNAL (loadDocumentRequest())); connect (view, SIGNAL (editSettingsRequest()), this, SIGNAL (editSettingsRequest())); + connect (&CSMSettings::UserSettings::instance(), + SIGNAL (userSettingUpdated(const QString &, const QStringList &)), + view, + SLOT (updateUserSetting (const QString &, const QStringList &))); + updateIndices(); return view; @@ -313,9 +316,3 @@ void CSVDoc::ViewManager::exitApplication (CSVDoc::View *view) if (notifySaveOnClose (view)) QApplication::instance()->exit(); } - -void CSVDoc::ViewManager::slotUpdateEditorSetting (const QString &settingName, const QString &settingValue) -{ - foreach (CSVDoc::View *view, mViews) - view->updateEditorSetting (settingName, settingValue); -} diff --git a/apps/opencs/view/doc/viewmanager.hpp b/apps/opencs/view/doc/viewmanager.hpp index 01f495186..00e33916d 100644 --- a/apps/opencs/view/doc/viewmanager.hpp +++ b/apps/opencs/view/doc/viewmanager.hpp @@ -76,9 +76,6 @@ namespace CSVDoc void progress (int current, int max, int type, int threads, CSMDoc::Document *document); void onExitWarningHandler(int state, CSMDoc::Document* document); - - /// connected to update signal in UserSettings - void slotUpdateEditorSetting (const QString &, const QString &); }; } diff --git a/apps/opencs/view/tools/reportsubview.cpp b/apps/opencs/view/tools/reportsubview.cpp index d59f0c234..e84f5cf4b 100644 --- a/apps/opencs/view/tools/reportsubview.cpp +++ b/apps/opencs/view/tools/reportsubview.cpp @@ -33,12 +33,13 @@ void CSVTools::ReportSubView::setEditLock (bool locked) // ignored. We don't change document state anyway. } -void CSVTools::ReportSubView::updateEditorSetting (const QString& key, const QString& value) +void CSVTools::ReportSubView::updateUserSetting + (const QString &name, const QStringList &list) { - mIdTypeDelegate->updateEditorSetting (key, value); + mIdTypeDelegate->updateUserSetting (name, list); } void CSVTools::ReportSubView::show (const QModelIndex& index) { focusId (mModel->getUniversalId (index.row()), ""); -} \ No newline at end of file +} diff --git a/apps/opencs/view/tools/reportsubview.hpp b/apps/opencs/view/tools/reportsubview.hpp index 6503ebd27..9f6a4c1da 100644 --- a/apps/opencs/view/tools/reportsubview.hpp +++ b/apps/opencs/view/tools/reportsubview.hpp @@ -39,7 +39,8 @@ namespace CSVTools virtual void setEditLock (bool locked); - virtual void updateEditorSetting (const QString&, const QString&); + virtual void updateUserSetting + (const QString &, const QStringList &); private slots: @@ -47,4 +48,4 @@ namespace CSVTools }; } -#endif \ No newline at end of file +#endif diff --git a/apps/opencs/view/world/table.cpp b/apps/opencs/view/world/table.cpp index 712b8f556..995de21fc 100644 --- a/apps/opencs/view/world/table.cpp +++ b/apps/opencs/view/world/table.cpp @@ -449,15 +449,19 @@ void CSVWorld::Table::previewRecord() } } -void CSVWorld::Table::updateEditorSetting (const QString &settingName, const QString &settingValue) +void CSVWorld::Table::updateUserSetting + (const QString &name, const QStringList &list) { int columns = mModel->columnCount(); for (int i=0; i (*delegate). - updateEditorSetting (settingName, settingValue)) - emit dataChanged (mModel->index (0, i), mModel->index (mModel->rowCount()-1, i)); + if (dynamic_cast + (*delegate).updateUserSetting (name, list)) + { + emit dataChanged (mModel->index (0, i), + mModel->index (mModel->rowCount()-1, i)); + } } void CSVWorld::Table::tableSizeUpdate() @@ -598,4 +602,4 @@ std::vector CSVWorld::Table::getColumnsWithDisplay(CSMWorld::Column } } return titles; -} \ No newline at end of file +} diff --git a/apps/opencs/view/world/table.hpp b/apps/opencs/view/world/table.hpp index 4231a4a43..dfc74b3eb 100644 --- a/apps/opencs/view/world/table.hpp +++ b/apps/opencs/view/world/table.hpp @@ -78,7 +78,7 @@ namespace CSVWorld CSMWorld::UniversalId getUniversalId (int row) const; - void updateEditorSetting (const QString &settingName, const QString &settingValue); + void updateUserSetting (const QString &name, const QStringList &list); std::vector getColumnsWithDisplay(CSMWorld::ColumnBase::Display display) const; diff --git a/apps/opencs/view/world/tablesubview.cpp b/apps/opencs/view/world/tablesubview.cpp index a5a7e8252..c193ed32b 100644 --- a/apps/opencs/view/world/tablesubview.cpp +++ b/apps/opencs/view/world/tablesubview.cpp @@ -82,9 +82,10 @@ void CSVWorld::TableSubView::editRequest (const CSMWorld::UniversalId& id, const focusId (id, hint); } -void CSVWorld::TableSubView::updateEditorSetting(const QString &settingName, const QString &settingValue) +void CSVWorld::TableSubView::updateUserSetting + (const QString &name, const QStringList &list) { - mTable->updateEditorSetting(settingName, settingValue); + mTable->updateUserSetting(name, list); } void CSVWorld::TableSubView::setStatusBar (bool show) @@ -134,4 +135,4 @@ bool CSVWorld::TableSubView::eventFilter (QObject* object, QEvent* event) return handled; } return false; -} \ No newline at end of file +} diff --git a/apps/opencs/view/world/tablesubview.hpp b/apps/opencs/view/world/tablesubview.hpp index b344ba1ad..9d86c32e4 100644 --- a/apps/opencs/view/world/tablesubview.hpp +++ b/apps/opencs/view/world/tablesubview.hpp @@ -43,7 +43,8 @@ namespace CSVWorld virtual void setEditLock (bool locked); - virtual void updateEditorSetting (const QString& key, const QString& value); + virtual void updateUserSetting + (const QString& name, const QStringList &list); virtual void setStatusBar (bool show); diff --git a/apps/opencs/view/world/util.cpp b/apps/opencs/view/world/util.cpp index b2a32b551..16310c8a9 100644 --- a/apps/opencs/view/world/util.cpp +++ b/apps/opencs/view/world/util.cpp @@ -196,8 +196,8 @@ bool CSVWorld::CommandDelegate::isEditLocked() const return mEditLock; } -bool CSVWorld::CommandDelegate::updateEditorSetting (const QString &settingName, - const QString &settingValue) +bool CSVWorld::CommandDelegate::updateUserSetting (const QString &name, + const QStringList &list) { return false; } @@ -263,4 +263,4 @@ void CSVWorld::DropLineEdit::dropEvent(QDropEvent *event) const CSMWorld::TableMimeData* data(dynamic_cast(event->mimeData())); emit tableMimeDataDropped(data->getData(), data->getDocumentPtr()); //WIP -} \ No newline at end of file +} diff --git a/apps/opencs/view/world/util.hpp b/apps/opencs/view/world/util.hpp index 7664f3eae..50e2cf858 100644 --- a/apps/opencs/view/world/util.hpp +++ b/apps/opencs/view/world/util.hpp @@ -136,7 +136,9 @@ namespace CSVWorld bool isEditLocked() const; - virtual bool updateEditorSetting (const QString &settingName, const QString &settingValue); + virtual bool updateUserSetting + (const QString &name, const QStringList &list); + ///< \return Does column require update? virtual void setEditorData (QWidget *editor, const QModelIndex& index, bool tryDisplay = false) const; From e71a119c23ac5992ed016f0d3a2e4298494b309c Mon Sep 17 00:00:00 2001 From: Thomas Date: Wed, 23 Apr 2014 02:57:48 -0400 Subject: [PATCH 014/118] Made aifollowers run when long distances (800 or 10000, depending) from what they're following. --- apps/openmw/mwmechanics/aifollow.cpp | 60 ++++++++++++++++++---------- 1 file changed, 40 insertions(+), 20 deletions(-) diff --git a/apps/openmw/mwmechanics/aifollow.cpp b/apps/openmw/mwmechanics/aifollow.cpp index c3b36516c..161c9700f 100644 --- a/apps/openmw/mwmechanics/aifollow.cpp +++ b/apps/openmw/mwmechanics/aifollow.cpp @@ -4,6 +4,7 @@ #include "../mwbase/environment.hpp" #include "../mwworld/class.hpp" #include "../mwworld/cellstore.hpp" +#include "creaturestats.hpp" #include "movement.hpp" #include @@ -26,69 +27,77 @@ MWMechanics::AiFollow::AiFollow(const std::string &actorId) bool MWMechanics::AiFollow::execute (const MWWorld::Ptr& actor,float duration) { - const MWWorld::Ptr target = MWBase::Environment::get().getWorld()->searchPtr(mActorId, false); - - if(target == MWWorld::Ptr()) return true; + const MWWorld::Ptr target = MWBase::Environment::get().getWorld()->searchPtr(mActorId, false); //The target to follow - mTimer = mTimer + duration; - mStuckTimer = mStuckTimer + duration; - mTotalTime = mTotalTime + duration; + if(target == MWWorld::Ptr()) return true; //Target doesn't exist - ESM::Position pos = actor.getRefData().getPosition(); + mTimer = mTimer + duration; //Update timer + mStuckTimer = mStuckTimer + duration; //Update stuck timer + mTotalTime = mTotalTime + duration; //Update total time following - if(!mAlwaysFollow) + ESM::Position pos = actor.getRefData().getPosition(); //position of the actor + + if(!mAlwaysFollow) //Update if you only follow for a bit { - if(mTotalTime > mDuration && mDuration != 0) + if(mTotalTime > mDuration && mDuration != 0) //Check if we've run out of time return true; if((pos.pos[0]-mX)*(pos.pos[0]-mX) + (pos.pos[1]-mY)*(pos.pos[1]-mY) + - (pos.pos[2]-mZ)*(pos.pos[2]-mZ) < 100*100) + (pos.pos[2]-mZ)*(pos.pos[2]-mZ) < 100*100) //Close-ish to final position { - if(actor.getCell()->isExterior()) + if(actor.getCell()->isExterior()) //Outside? { - if(mCellId == "") + if(mCellId == "") //No cell to travel to return true; } else { - if(mCellId == actor.getCell()->getCell()->mName) + if(mCellId == actor.getCell()->getCell()->mName) //Cell to travel to return true; } } } + //Set the target desition from the actor ESM::Pathgrid::Point dest; dest.mX = target.getRefData().getPosition().pos[0]; dest.mY = target.getRefData().getPosition().pos[1]; dest.mZ = target.getRefData().getPosition().pos[2]; + //Current position, for pathfilding stuff ESM::Pathgrid::Point start; start.mX = pos.pos[0]; start.mY = pos.pos[1]; start.mZ = pos.pos[2]; + //Build the path to get to the destination if(mPathFinder.getPath().empty()) mPathFinder.buildPath(start, dest, actor.getCell(), true); - + //*********************** + // Checks if you can't get to the end position at all + //*********************** if(mTimer > 0.25) { - if(!mPathFinder.getPath().empty()) + if(!mPathFinder.getPath().empty()) //Path has points in it { - ESM::Pathgrid::Point lastPos = mPathFinder.getPath().back(); + ESM::Pathgrid::Point lastPos = mPathFinder.getPath().back(); //Get the end of the proposed path - if((dest.mX - lastPos.mX)*(dest.mX - lastPos.mX) + if((dest.mX - lastPos.mX)*(dest.mX - lastPos.mX) +(dest.mY - lastPos.mY)*(dest.mY - lastPos.mY) +(dest.mZ - lastPos.mZ)*(dest.mZ - lastPos.mZ) - > 100*100) - mPathFinder.addPointToPath(dest); + > 100*100) //End of the path is far from the destination + mPathFinder.addPointToPath(dest); //Adds the final destination to the path, to try to get to where you want to go } mTimer = 0; } - if(mStuckTimer>0.5) + //************************ + // Checks if you aren't moving; you're stuck + //************************ + if(mStuckTimer>0.5) //Checks every half of a second { if((mStuckPos.pos[0] - pos.pos[0])*(mStuckPos.pos[0] - pos.pos[0]) +(mStuckPos.pos[1] - pos.pos[1])*(mStuckPos.pos[1] - pos.pos[1]) @@ -99,6 +108,7 @@ bool MWMechanics::AiFollow::execute (const MWWorld::Ptr& actor,float duration) mStuckPos = pos; } + //Checks if the path isn't over, turn tomards the direction that you're going if(!mPathFinder.checkPathCompleted(pos.pos[0],pos.pos[1],pos.pos[2])) { zTurn(actor, Ogre::Degree(mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]))); @@ -110,6 +120,16 @@ bool MWMechanics::AiFollow::execute (const MWWorld::Ptr& actor,float duration) else actor.getClass().getMovementSettings(actor).mPosition[1] = 1; + //Check if you're far away + if((dest.mX - start.mX)*(dest.mX - start.mX) + +(dest.mY - start.mY)*(dest.mY - start.mY) + +(dest.mZ - start.mZ)*(dest.mZ - start.mZ) > 1000*1000) + actor.getClass().getCreatureStats(actor).setMovementFlag(MWMechanics::CreatureStats::Flag_Run, true); //Make NPC run + else if((dest.mX - start.mX)*(dest.mX - start.mX) //Have a bit of a dead zone, otherwise npc will constantly flip between running and not when right on the edge of the running threshhold + +(dest.mY - start.mY)*(dest.mY - start.mY) + +(dest.mZ - start.mZ)*(dest.mZ - start.mZ) < 800*800) + actor.getClass().getCreatureStats(actor).setMovementFlag(MWMechanics::CreatureStats::Flag_Run, false); //make NPC walk + return false; } From cac8e52154a99b310368ceabe3b61dcf2f63d44c Mon Sep 17 00:00:00 2001 From: Thomas Date: Wed, 23 Apr 2014 05:12:07 -0400 Subject: [PATCH 015/118] Seperated locked and lock level, to allow for relocking doors to previous lock level. The data is stored in the esm as -lockLevel if unlocked; lockLevel if locked. While not tested, it should not present any problems. --- apps/openmw/mwclass/container.cpp | 23 +++++++++++++++-------- apps/openmw/mwclass/container.hpp | 5 ++++- apps/openmw/mwclass/door.cpp | 15 +++++++++++---- apps/openmw/mwclass/door.hpp | 6 +++++- apps/openmw/mwmechanics/security.cpp | 2 +- apps/openmw/mwmechanics/spellcasting.cpp | 5 +++-- apps/openmw/mwscript/miscextensions.cpp | 6 +++--- apps/openmw/mwworld/class.cpp | 7 ++++++- apps/openmw/mwworld/class.hpp | 2 ++ apps/openmw/mwworld/manualref.hpp | 1 + 10 files changed, 51 insertions(+), 21 deletions(-) diff --git a/apps/openmw/mwclass/container.cpp b/apps/openmw/mwclass/container.cpp index 604b51990..ee6dba982 100644 --- a/apps/openmw/mwclass/container.cpp +++ b/apps/openmw/mwclass/container.cpp @@ -111,7 +111,7 @@ namespace MWClass MWWorld::Ptr player = MWBase::Environment::get().getWorld ()->getPlayerPtr(); MWWorld::InventoryStore& invStore = MWWorld::Class::get(player).getInventoryStore(player); - bool needKey = ptr.getCellRef().mLockLevel>0; + bool needKey = ptr.getCellRef().mLocked; bool hasKey = false; std::string keyName; @@ -132,7 +132,7 @@ namespace MWClass if (needKey && hasKey) { MWBase::Environment::get().getWindowManager ()->messageBox (keyName + " #{sKeyUsed}"); - ptr.getCellRef().mLockLevel = 0; + unlock(ptr); // using a key disarms the trap ptr.getCellRef().mTrap = ""; } @@ -209,7 +209,7 @@ namespace MWClass info.caption = ref->mBase->mName; std::string text; - if (ref->mRef.mLockLevel > 0) + if (ref->mRef.mLocked) text += "\n#{sLockLevel}: " + MWGui::ToolTips::toString(ref->mRef.mLockLevel); if (ref->mRef.mTrap != "") text += "\n#{sTrapped}"; @@ -240,15 +240,22 @@ namespace MWClass void Container::lock (const MWWorld::Ptr& ptr, int lockLevel) const { - if (lockLevel<0) - lockLevel = 0; - - ptr.getCellRef().mLockLevel = lockLevel; + ptr.getCellRef().mLocked = true; + if(lockLevel>=0) //Lock level setting left as most of the code relies on this + ptr.getCellRef().mLockLevel = lockLevel; } void Container::unlock (const MWWorld::Ptr& ptr) const { - ptr.getCellRef().mLockLevel = 0; + ptr.getCellRef().mLocked= false; + } + + void Container::changeLockLevel(const MWWorld::Ptr& ptr, int lockLevel, bool doLock) { + if (lockLevel<0) + lockLevel = 0; + + ptr.getCellRef().mLockLevel = lockLevel; + if(doLock) lock(ptr); } MWWorld::Ptr diff --git a/apps/openmw/mwclass/container.hpp b/apps/openmw/mwclass/container.hpp index c97867d35..6945ae441 100644 --- a/apps/openmw/mwclass/container.hpp +++ b/apps/openmw/mwclass/container.hpp @@ -48,12 +48,15 @@ namespace MWClass ///< Returns total weight of objects inside this object (including modifications from magic /// effects). Throws an exception, if the object can't hold other objects. - virtual void lock (const MWWorld::Ptr& ptr, int lockLevel) const; + virtual void lock (const MWWorld::Ptr& ptr, int lockLevel = -999) const; ///< Lock object virtual void unlock (const MWWorld::Ptr& ptr) const; ///< Unlock object + ///Changes the lock level of the object + virtual void changeLockLevel(const MWWorld::Ptr& ptr, int lockLevel, bool lock=true); + virtual void readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state) const; ///< Read additional state from \a state into \a ptr. diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index 3cd8237e7..2662e1c53 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -76,7 +76,7 @@ namespace MWClass MWWorld::ContainerStore &invStore = get(actor).getContainerStore(actor); - bool needKey = ptr.getCellRef().mLockLevel>0; + bool needKey = ptr.getCellRef().mLocked; bool hasKey = false; std::string keyName; @@ -98,7 +98,7 @@ namespace MWClass { if(actor == MWBase::Environment::get().getWorld()->getPlayerPtr()) MWBase::Environment::get().getWindowManager()->messageBox(keyName + " #{sKeyUsed}"); - ptr.getCellRef().mLockLevel = 0; + unlock(ptr); //Call the function here. because that makes sense. // using a key disarms the trap ptr.getCellRef().mTrap = ""; } @@ -158,15 +158,22 @@ namespace MWClass void Door::lock (const MWWorld::Ptr& ptr, int lockLevel) const { + ptr.getCellRef().mLocked = true; + if(lockLevel>=0) //Lock level setting left as most of the code relies on this + ptr.getCellRef().mLockLevel = lockLevel; + } + + void Door::changeLockLevel(const MWWorld::Ptr& ptr, int lockLevel, bool doLock) const{ if (lockLevel<0) lockLevel = 0; ptr.getCellRef().mLockLevel = lockLevel; + if(doLock) lock(ptr); //A change in lock level almost always nesesitates a lock } void Door::unlock (const MWWorld::Ptr& ptr) const { - ptr.getCellRef().mLockLevel = 0; + ptr.getCellRef().mLocked = false; } std::string Door::getScript (const MWWorld::Ptr& ptr) const @@ -208,7 +215,7 @@ namespace MWClass text += "\n" + getDestination(*ref); } - if (ref->mRef.mLockLevel > 0) + if (ref->mRef.mLocked == true) text += "\n#{sLockLevel}: " + MWGui::ToolTips::toString(ref->mRef.mLockLevel); if (ref->mRef.mTrap != "") text += "\n#{sTrapped}"; diff --git a/apps/openmw/mwclass/door.hpp b/apps/openmw/mwclass/door.hpp index 2ac342a61..e053136d5 100644 --- a/apps/openmw/mwclass/door.hpp +++ b/apps/openmw/mwclass/door.hpp @@ -36,18 +36,22 @@ namespace MWClass static std::string getDestination (const MWWorld::LiveCellRef& door); ///< @return destination cell name or token - virtual void lock (const MWWorld::Ptr& ptr, int lockLevel) const; + virtual void lock (const MWWorld::Ptr& ptr, int lockLevel = -999) const; ///< Lock object virtual void unlock (const MWWorld::Ptr& ptr) const; ///< Unlock object + ///Change the lock level + virtual void changeLockLevel(const MWWorld::Ptr& ptr, int lockLevel, bool lock=true) const; + virtual std::string getScript (const MWWorld::Ptr& ptr) const; ///< Return name of the script attached to ptr static void registerSelf(); virtual std::string getModel(const MWWorld::Ptr &ptr) const; + private: }; } diff --git a/apps/openmw/mwmechanics/security.cpp b/apps/openmw/mwmechanics/security.cpp index edec45e15..ba2a32727 100644 --- a/apps/openmw/mwmechanics/security.cpp +++ b/apps/openmw/mwmechanics/security.cpp @@ -29,7 +29,7 @@ namespace MWMechanics void Security::pickLock(const MWWorld::Ptr &lock, const MWWorld::Ptr &lockpick, std::string& resultMessage, std::string& resultSound) { - if (lock.getCellRef().mLockLevel <= 0) + if (!lock.getCellRef().mLocked) return; int lockStrength = lock.getCellRef().mLockLevel; diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 6ea3f5472..d861e2032 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -420,6 +420,7 @@ namespace MWMechanics { if (effectId == ESM::MagicEffect::Lock) { + target.getCellRef().mLocked = true; if (target.getCellRef().mLockLevel < magnitude) target.getCellRef().mLockLevel = magnitude; } @@ -427,12 +428,12 @@ namespace MWMechanics { if (target.getCellRef().mLockLevel <= magnitude) { - if (target.getCellRef().mLockLevel > 0) + if (target.getCellRef().mLocked) { MWBase::Environment::get().getSoundManager()->playSound3D(target, "Open Lock", 1.f, 1.f); MWBase::Environment::get().getMechanicsManager()->objectOpened(caster, target); } - target.getCellRef().mLockLevel = 0; + target.getCellRef().mLocked=false; } else MWBase::Environment::get().getSoundManager()->playSound3D(target, "Open Lock Fail", 1.f, 1.f); diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index 968d3bbd7..f10d1df96 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -131,7 +131,7 @@ namespace MWScript { MWWorld::Ptr ptr = R()(runtime); - Interpreter::Type_Integer lockLevel = 100; + Interpreter::Type_Integer lockLevel = ptr.getCellRef().mLockLevel; if (arg0==1) { @@ -283,7 +283,7 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime) { // We are ignoring the DontSaveObject statement for now. Probably not worth - /// bothering with. The incompatibility we are creating should be marginal at most. + // bothering with. The incompatibility we are creating should be marginal at most. } }; @@ -320,7 +320,7 @@ namespace MWScript { MWWorld::Ptr ptr = R()(runtime); - runtime.push (ptr.getCellRef ().mLockLevel > 0); + runtime.push (ptr.getCellRef().mLocked); } }; diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 99dbcc66c..4b3d40ab7 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -137,6 +137,11 @@ namespace MWWorld throw std::runtime_error ("class does not support locking"); } + void Class::setLockLevel (const Ptr& ptr, int lockLevel) const + { + throw std::runtime_error ("class does not support setting lock level"); + } + void Class::unlock (const Ptr& ptr) const { throw std::runtime_error ("class does not support unlocking"); @@ -397,7 +402,7 @@ namespace MWWorld void Class::writeAdditionalState (const MWWorld::Ptr& ptr, ESM::ObjectState& state) const {} - int Class::getBaseGold(const MWWorld::Ptr& ptr) const + int Class::getBaseGold(const MWWorld::Ptr& ptr) const { throw std::runtime_error("class does not support base gold"); } diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 27b842348..dc06bf6c9 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -165,6 +165,8 @@ namespace MWWorld virtual void lock (const Ptr& ptr, int lockLevel) const; ///< Lock object (default implementation: throw an exception) + virtual void setLockLevel(const Ptr& ptr, int lockLevel) const; + virtual void unlock (const Ptr& ptr) const; ///< Unlock object (default implementation: throw an exception) diff --git a/apps/openmw/mwworld/manualref.hpp b/apps/openmw/mwworld/manualref.hpp index 0e21c55ac..174e34423 100644 --- a/apps/openmw/mwworld/manualref.hpp +++ b/apps/openmw/mwworld/manualref.hpp @@ -76,6 +76,7 @@ namespace MWWorld cellRef.mEnchantmentCharge = -1; cellRef.mTeleport = false; cellRef.mLockLevel = 0; + cellRef.mLocked = false; cellRef.mReferenceBlocked = 0; mPtr.getRefData().setCount(count); } From 420163d35f6aac7a233bc57fb5bee334b4fd6fbd Mon Sep 17 00:00:00 2001 From: Thomas Date: Wed, 23 Apr 2014 05:19:34 -0400 Subject: [PATCH 016/118] Small changes to lock command (If no valid lockLevel exists, defaults to 100) --- apps/openmw/mwscript/miscextensions.cpp | 4 ++++ components/esm/cellref.cpp | 18 +++++++++++++++--- components/esm/cellref.hpp | 1 + 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index f10d1df96..686fa94a7 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -132,6 +132,10 @@ namespace MWScript MWWorld::Ptr ptr = R()(runtime); Interpreter::Type_Integer lockLevel = ptr.getCellRef().mLockLevel; + if(lockLevel<0) { //no lock level was ever set, set to 100 as default + ptr.getCellRef().mLockLevel = 100; + lockLevel = 100; + } if (arg0==1) { diff --git a/components/esm/cellref.cpp b/components/esm/cellref.cpp index 00b15f4a3..c46d83c1b 100644 --- a/components/esm/cellref.cpp +++ b/components/esm/cellref.cpp @@ -54,8 +54,15 @@ void ESM::CellRef::load (ESMReader& esm, bool wideRefNum) else mTeleport = false; - mLockLevel = -1; + mLockLevel = -999; //Set to impossible value to indicate no lock + mLocked = false; esm.getHNOT (mLockLevel, "FLTV"); + if(mLockLevel < 0 && mLockLevel != -999) //Unlocked lock, save lock level properly + mLockLevel*=-1; + else if(mLockLevel != -999){ + mLocked = true; + } + mKey = esm.getHNOString ("KNAM"); mTrap = esm.getHNOString ("TNAM"); @@ -113,8 +120,12 @@ void ESM::CellRef::save (ESMWriter &esm, bool wideRefNum, bool inInventory) cons esm.writeHNOCString("DNAM", mDestCell); } - if (mLockLevel != -1 && !inInventory) - esm.writeHNT("FLTV", mLockLevel); + if (mLockLevel != -999 && !inInventory) { + if(mLocked) + esm.writeHNT("FLTV", mLockLevel); + else //If it's not locked we simply flip the locklevel to indicate it's locked + esm.writeHNT("FLTV", -mLockLevel); + } if (!inInventory) esm.writeHNOCString ("KNAM", mKey); @@ -151,6 +162,7 @@ void ESM::CellRef::blank() mGoldValue = 0; mDestCell.clear(); mLockLevel = 0; + mLocked = false; mKey.clear(); mTrap.clear(); mReferenceBlocked = 0; diff --git a/components/esm/cellref.hpp b/components/esm/cellref.hpp index 16f6603a2..75122eacb 100644 --- a/components/esm/cellref.hpp +++ b/components/esm/cellref.hpp @@ -71,6 +71,7 @@ namespace ESM // Lock level for doors and containers int mLockLevel; + bool mLocked; //Door locked/unlocked std::string mKey, mTrap; // Key and trap ID names, if any // This corresponds to the "Reference Blocked" checkbox in the construction set, From 6022ffbd1ff25d56934760fd330e1c6de797bee8 Mon Sep 17 00:00:00 2001 From: Thomas Date: Wed, 23 Apr 2014 05:54:18 -0400 Subject: [PATCH 017/118] Evidence chest now locks when new evidence is added to it --- apps/openmw/mwworld/worldimp.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index e3c632512..5b4c2570a 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2724,6 +2724,7 @@ namespace MWWorld } } } + closestChest.getCellRef().mLocked = true; } void World::goToJail() @@ -2791,7 +2792,7 @@ namespace MWWorld message += "\n" + skillMsg; } - // TODO: Sleep the player + // TODO: Sleep the player std::vector buttons; buttons.push_back("#{sOk}"); From 61341d420678e6e5e9cae019d342d0dde2f531ad Mon Sep 17 00:00:00 2001 From: Thomas Date: Wed, 23 Apr 2014 10:00:18 -0400 Subject: [PATCH 018/118] Removed mLocked, kept it as "Negative lock level means unlocked" --- apps/openmw/mwclass/container.cpp | 8 ++++---- apps/openmw/mwclass/door.cpp | 10 +++++----- apps/openmw/mwmechanics/security.cpp | 2 +- apps/openmw/mwmechanics/spellcasting.cpp | 6 +++--- apps/openmw/mwscript/miscextensions.cpp | 5 ++--- apps/openmw/mwworld/manualref.hpp | 1 - apps/openmw/mwworld/worldimp.cpp | 2 +- components/esm/cellref.cpp | 10 ---------- components/esm/cellref.hpp | 1 - 9 files changed, 16 insertions(+), 29 deletions(-) diff --git a/apps/openmw/mwclass/container.cpp b/apps/openmw/mwclass/container.cpp index ee6dba982..1847fbd44 100644 --- a/apps/openmw/mwclass/container.cpp +++ b/apps/openmw/mwclass/container.cpp @@ -111,7 +111,7 @@ namespace MWClass MWWorld::Ptr player = MWBase::Environment::get().getWorld ()->getPlayerPtr(); MWWorld::InventoryStore& invStore = MWWorld::Class::get(player).getInventoryStore(player); - bool needKey = ptr.getCellRef().mLocked; + bool needKey = ptr.getCellRef().mLockLevel > 0; bool hasKey = false; std::string keyName; @@ -209,7 +209,7 @@ namespace MWClass info.caption = ref->mBase->mName; std::string text; - if (ref->mRef.mLocked) + if (ref->mRef.mLockLevel > 0) text += "\n#{sLockLevel}: " + MWGui::ToolTips::toString(ref->mRef.mLockLevel); if (ref->mRef.mTrap != "") text += "\n#{sTrapped}"; @@ -240,14 +240,14 @@ namespace MWClass void Container::lock (const MWWorld::Ptr& ptr, int lockLevel) const { - ptr.getCellRef().mLocked = true; + ptr.getCellRef().mLockLevel = abs(ptr.getCellRef().mLockLevel); //Makes lockLevel positive if(lockLevel>=0) //Lock level setting left as most of the code relies on this ptr.getCellRef().mLockLevel = lockLevel; } void Container::unlock (const MWWorld::Ptr& ptr) const { - ptr.getCellRef().mLocked= false; + ptr.getCellRef().mLockLevel = -abs(ptr.getCellRef().mLockLevel); //Makes lockLevel negative } void Container::changeLockLevel(const MWWorld::Ptr& ptr, int lockLevel, bool doLock) { diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index 2662e1c53..e9f384572 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -76,7 +76,7 @@ namespace MWClass MWWorld::ContainerStore &invStore = get(actor).getContainerStore(actor); - bool needKey = ptr.getCellRef().mLocked; + bool needKey = ptr.getCellRef().mLockLevel > 0; bool hasKey = false; std::string keyName; @@ -158,9 +158,9 @@ namespace MWClass void Door::lock (const MWWorld::Ptr& ptr, int lockLevel) const { - ptr.getCellRef().mLocked = true; + ptr.getCellRef().mLockLevel = abs(ptr.getCellRef().mLockLevel); //Makes lockLevel positive; if(lockLevel>=0) //Lock level setting left as most of the code relies on this - ptr.getCellRef().mLockLevel = lockLevel; + ptr.getCellRef().mLockLevel = abs(lockLevel); } void Door::changeLockLevel(const MWWorld::Ptr& ptr, int lockLevel, bool doLock) const{ @@ -173,7 +173,7 @@ namespace MWClass void Door::unlock (const MWWorld::Ptr& ptr) const { - ptr.getCellRef().mLocked = false; + ptr.getCellRef().mLockLevel = -abs(ptr.getCellRef().mLockLevel); //Makes lockLevel positive } std::string Door::getScript (const MWWorld::Ptr& ptr) const @@ -215,7 +215,7 @@ namespace MWClass text += "\n" + getDestination(*ref); } - if (ref->mRef.mLocked == true) + if (ref->mRef.mLockLevel > 0) text += "\n#{sLockLevel}: " + MWGui::ToolTips::toString(ref->mRef.mLockLevel); if (ref->mRef.mTrap != "") text += "\n#{sTrapped}"; diff --git a/apps/openmw/mwmechanics/security.cpp b/apps/openmw/mwmechanics/security.cpp index ba2a32727..3751e5828 100644 --- a/apps/openmw/mwmechanics/security.cpp +++ b/apps/openmw/mwmechanics/security.cpp @@ -29,7 +29,7 @@ namespace MWMechanics void Security::pickLock(const MWWorld::Ptr &lock, const MWWorld::Ptr &lockpick, std::string& resultMessage, std::string& resultSound) { - if (!lock.getCellRef().mLocked) + if (!(lock.getCellRef().mLockLevel > 0)) //If it's unlocked back out immediately return; int lockStrength = lock.getCellRef().mLockLevel; diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index d861e2032..db8daff15 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -420,7 +420,7 @@ namespace MWMechanics { if (effectId == ESM::MagicEffect::Lock) { - target.getCellRef().mLocked = true; + target.getCellRef().mLockLevel = abs(target.getCellRef().mLockLevel); //Makes lockLevel positive if (target.getCellRef().mLockLevel < magnitude) target.getCellRef().mLockLevel = magnitude; } @@ -428,12 +428,12 @@ namespace MWMechanics { if (target.getCellRef().mLockLevel <= magnitude) { - if (target.getCellRef().mLocked) + if (target.getCellRef().mLockLevel > 0) { MWBase::Environment::get().getSoundManager()->playSound3D(target, "Open Lock", 1.f, 1.f); MWBase::Environment::get().getMechanicsManager()->objectOpened(caster, target); } - target.getCellRef().mLocked=false; + target.getCellRef().mLockLevel = -abs(target.getCellRef().mLockLevel); } else MWBase::Environment::get().getSoundManager()->playSound3D(target, "Open Lock Fail", 1.f, 1.f); diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index 686fa94a7..bc71cc494 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -132,8 +132,7 @@ namespace MWScript MWWorld::Ptr ptr = R()(runtime); Interpreter::Type_Integer lockLevel = ptr.getCellRef().mLockLevel; - if(lockLevel<0) { //no lock level was ever set, set to 100 as default - ptr.getCellRef().mLockLevel = 100; + if(lockLevel==-999) { //no lock level was ever set, set to 100 as default lockLevel = 100; } @@ -324,7 +323,7 @@ namespace MWScript { MWWorld::Ptr ptr = R()(runtime); - runtime.push (ptr.getCellRef().mLocked); + runtime.push (ptr.getCellRef().mLockLevel > 0); } }; diff --git a/apps/openmw/mwworld/manualref.hpp b/apps/openmw/mwworld/manualref.hpp index 174e34423..0e21c55ac 100644 --- a/apps/openmw/mwworld/manualref.hpp +++ b/apps/openmw/mwworld/manualref.hpp @@ -76,7 +76,6 @@ namespace MWWorld cellRef.mEnchantmentCharge = -1; cellRef.mTeleport = false; cellRef.mLockLevel = 0; - cellRef.mLocked = false; cellRef.mReferenceBlocked = 0; mPtr.getRefData().setCount(count); } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 5b4c2570a..5c9b25d28 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2724,7 +2724,7 @@ namespace MWWorld } } } - closestChest.getCellRef().mLocked = true; + closestChest.getCellRef().mLockLevel = abs(closestChest.getCellRef().mLockLevel); } void World::goToJail() diff --git a/components/esm/cellref.cpp b/components/esm/cellref.cpp index c46d83c1b..699d326ee 100644 --- a/components/esm/cellref.cpp +++ b/components/esm/cellref.cpp @@ -55,13 +55,7 @@ void ESM::CellRef::load (ESMReader& esm, bool wideRefNum) mTeleport = false; mLockLevel = -999; //Set to impossible value to indicate no lock - mLocked = false; esm.getHNOT (mLockLevel, "FLTV"); - if(mLockLevel < 0 && mLockLevel != -999) //Unlocked lock, save lock level properly - mLockLevel*=-1; - else if(mLockLevel != -999){ - mLocked = true; - } mKey = esm.getHNOString ("KNAM"); mTrap = esm.getHNOString ("TNAM"); @@ -121,10 +115,7 @@ void ESM::CellRef::save (ESMWriter &esm, bool wideRefNum, bool inInventory) cons } if (mLockLevel != -999 && !inInventory) { - if(mLocked) esm.writeHNT("FLTV", mLockLevel); - else //If it's not locked we simply flip the locklevel to indicate it's locked - esm.writeHNT("FLTV", -mLockLevel); } if (!inInventory) @@ -162,7 +153,6 @@ void ESM::CellRef::blank() mGoldValue = 0; mDestCell.clear(); mLockLevel = 0; - mLocked = false; mKey.clear(); mTrap.clear(); mReferenceBlocked = 0; diff --git a/components/esm/cellref.hpp b/components/esm/cellref.hpp index 75122eacb..16f6603a2 100644 --- a/components/esm/cellref.hpp +++ b/components/esm/cellref.hpp @@ -71,7 +71,6 @@ namespace ESM // Lock level for doors and containers int mLockLevel; - bool mLocked; //Door locked/unlocked std::string mKey, mTrap; // Key and trap ID names, if any // This corresponds to the "Reference Blocked" checkbox in the construction set, From f6deca7c80c489488412cd85959c09e8ee68f5b9 Mon Sep 17 00:00:00 2001 From: Thomas Date: Wed, 23 Apr 2014 13:02:51 -0400 Subject: [PATCH 019/118] Fixed various issues caused by late-night coding. Also added "unlock" message to unlocked doors --- apps/openmw/mwclass/container.cpp | 16 ++++++---------- apps/openmw/mwclass/container.hpp | 5 +---- apps/openmw/mwclass/door.cpp | 19 +++++++------------ apps/openmw/mwclass/door.hpp | 5 +---- apps/openmw/mwmechanics/spellcasting.cpp | 6 +++--- apps/openmw/mwscript/miscextensions.cpp | 2 +- apps/openmw/mwworld/class.cpp | 5 ----- apps/openmw/mwworld/class.hpp | 2 -- components/esm/cellref.cpp | 4 ++-- 9 files changed, 21 insertions(+), 43 deletions(-) diff --git a/apps/openmw/mwclass/container.cpp b/apps/openmw/mwclass/container.cpp index 1847fbd44..be76bd0b4 100644 --- a/apps/openmw/mwclass/container.cpp +++ b/apps/openmw/mwclass/container.cpp @@ -211,6 +211,8 @@ namespace MWClass std::string text; if (ref->mRef.mLockLevel > 0) text += "\n#{sLockLevel}: " + MWGui::ToolTips::toString(ref->mRef.mLockLevel); + else if (ref->mRef.mLockLevel < 0) + text += "\n#{sUnlocked}"; if (ref->mRef.mTrap != "") text += "\n#{sTrapped}"; @@ -240,9 +242,10 @@ namespace MWClass void Container::lock (const MWWorld::Ptr& ptr, int lockLevel) const { - ptr.getCellRef().mLockLevel = abs(ptr.getCellRef().mLockLevel); //Makes lockLevel positive - if(lockLevel>=0) //Lock level setting left as most of the code relies on this - ptr.getCellRef().mLockLevel = lockLevel; + if(lockLevel!=0) + ptr.getCellRef().mLockLevel = abs(lockLevel); //Changes lock to locklevel, in positive + else + ptr.getCellRef().mLockLevel = abs(ptr.getCellRef().mLockLevel); //No locklevel given, just flip the oriional one } void Container::unlock (const MWWorld::Ptr& ptr) const @@ -250,13 +253,6 @@ namespace MWClass ptr.getCellRef().mLockLevel = -abs(ptr.getCellRef().mLockLevel); //Makes lockLevel negative } - void Container::changeLockLevel(const MWWorld::Ptr& ptr, int lockLevel, bool doLock) { - if (lockLevel<0) - lockLevel = 0; - - ptr.getCellRef().mLockLevel = lockLevel; - if(doLock) lock(ptr); - } MWWorld::Ptr Container::copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const diff --git a/apps/openmw/mwclass/container.hpp b/apps/openmw/mwclass/container.hpp index 6945ae441..f012d675c 100644 --- a/apps/openmw/mwclass/container.hpp +++ b/apps/openmw/mwclass/container.hpp @@ -48,15 +48,12 @@ namespace MWClass ///< Returns total weight of objects inside this object (including modifications from magic /// effects). Throws an exception, if the object can't hold other objects. - virtual void lock (const MWWorld::Ptr& ptr, int lockLevel = -999) const; + virtual void lock (const MWWorld::Ptr& ptr, int lockLevel = 0) const; ///< Lock object virtual void unlock (const MWWorld::Ptr& ptr) const; ///< Unlock object - ///Changes the lock level of the object - virtual void changeLockLevel(const MWWorld::Ptr& ptr, int lockLevel, bool lock=true); - virtual void readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state) const; ///< Read additional state from \a state into \a ptr. diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index e9f384572..984e21e72 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -158,22 +158,15 @@ namespace MWClass void Door::lock (const MWWorld::Ptr& ptr, int lockLevel) const { - ptr.getCellRef().mLockLevel = abs(ptr.getCellRef().mLockLevel); //Makes lockLevel positive; - if(lockLevel>=0) //Lock level setting left as most of the code relies on this - ptr.getCellRef().mLockLevel = abs(lockLevel); - } - - void Door::changeLockLevel(const MWWorld::Ptr& ptr, int lockLevel, bool doLock) const{ - if (lockLevel<0) - lockLevel = 0; - - ptr.getCellRef().mLockLevel = lockLevel; - if(doLock) lock(ptr); //A change in lock level almost always nesesitates a lock + if(lockLevel!=0) + ptr.getCellRef().mLockLevel = abs(lockLevel); //Changes lock to locklevel, in positive + else + ptr.getCellRef().mLockLevel = abs(ptr.getCellRef().mLockLevel); //No locklevel given, just flip the origional one } void Door::unlock (const MWWorld::Ptr& ptr) const { - ptr.getCellRef().mLockLevel = -abs(ptr.getCellRef().mLockLevel); //Makes lockLevel positive + ptr.getCellRef().mLockLevel = -abs(ptr.getCellRef().mLockLevel); //Makes lockLevel negative } std::string Door::getScript (const MWWorld::Ptr& ptr) const @@ -217,6 +210,8 @@ namespace MWClass if (ref->mRef.mLockLevel > 0) text += "\n#{sLockLevel}: " + MWGui::ToolTips::toString(ref->mRef.mLockLevel); + else if (ref->mRef.mLockLevel < 0) + text += "\n#{sUnlocked}"; if (ref->mRef.mTrap != "") text += "\n#{sTrapped}"; diff --git a/apps/openmw/mwclass/door.hpp b/apps/openmw/mwclass/door.hpp index e053136d5..bddc46728 100644 --- a/apps/openmw/mwclass/door.hpp +++ b/apps/openmw/mwclass/door.hpp @@ -36,15 +36,12 @@ namespace MWClass static std::string getDestination (const MWWorld::LiveCellRef& door); ///< @return destination cell name or token - virtual void lock (const MWWorld::Ptr& ptr, int lockLevel = -999) const; + virtual void lock (const MWWorld::Ptr& ptr, int lockLevel = 0) const; ///< Lock object virtual void unlock (const MWWorld::Ptr& ptr) const; ///< Unlock object - ///Change the lock level - virtual void changeLockLevel(const MWWorld::Ptr& ptr, int lockLevel, bool lock=true) const; - virtual std::string getScript (const MWWorld::Ptr& ptr) const; ///< Return name of the script attached to ptr diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index db8daff15..9a6cd6b89 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -420,20 +420,20 @@ namespace MWMechanics { if (effectId == ESM::MagicEffect::Lock) { - target.getCellRef().mLockLevel = abs(target.getCellRef().mLockLevel); //Makes lockLevel positive - if (target.getCellRef().mLockLevel < magnitude) + if (target.getCellRef().mLockLevel < magnitude) //If the door is not already locked to a higher value, lock it to spell magnitude target.getCellRef().mLockLevel = magnitude; } else if (effectId == ESM::MagicEffect::Open) { if (target.getCellRef().mLockLevel <= magnitude) { + //Door not already unlocked if (target.getCellRef().mLockLevel > 0) { MWBase::Environment::get().getSoundManager()->playSound3D(target, "Open Lock", 1.f, 1.f); MWBase::Environment::get().getMechanicsManager()->objectOpened(caster, target); } - target.getCellRef().mLockLevel = -abs(target.getCellRef().mLockLevel); + target.getCellRef().mLockLevel = -abs(target.getCellRef().mLockLevel); //unlocks the door } else MWBase::Environment::get().getSoundManager()->playSound3D(target, "Open Lock Fail", 1.f, 1.f); diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index bc71cc494..20013493f 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -132,7 +132,7 @@ namespace MWScript MWWorld::Ptr ptr = R()(runtime); Interpreter::Type_Integer lockLevel = ptr.getCellRef().mLockLevel; - if(lockLevel==-999) { //no lock level was ever set, set to 100 as default + if(lockLevel==0) { //no lock level was ever set, set to 100 as default lockLevel = 100; } diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 4b3d40ab7..f20c5f6d2 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -137,11 +137,6 @@ namespace MWWorld throw std::runtime_error ("class does not support locking"); } - void Class::setLockLevel (const Ptr& ptr, int lockLevel) const - { - throw std::runtime_error ("class does not support setting lock level"); - } - void Class::unlock (const Ptr& ptr) const { throw std::runtime_error ("class does not support unlocking"); diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index dc06bf6c9..27b842348 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -165,8 +165,6 @@ namespace MWWorld virtual void lock (const Ptr& ptr, int lockLevel) const; ///< Lock object (default implementation: throw an exception) - virtual void setLockLevel(const Ptr& ptr, int lockLevel) const; - virtual void unlock (const Ptr& ptr) const; ///< Unlock object (default implementation: throw an exception) diff --git a/components/esm/cellref.cpp b/components/esm/cellref.cpp index 699d326ee..f04e819c8 100644 --- a/components/esm/cellref.cpp +++ b/components/esm/cellref.cpp @@ -54,7 +54,7 @@ void ESM::CellRef::load (ESMReader& esm, bool wideRefNum) else mTeleport = false; - mLockLevel = -999; //Set to impossible value to indicate no lock + mLockLevel = 0; //Set to 0 to indicate no lock esm.getHNOT (mLockLevel, "FLTV"); mKey = esm.getHNOString ("KNAM"); @@ -114,7 +114,7 @@ void ESM::CellRef::save (ESMWriter &esm, bool wideRefNum, bool inInventory) cons esm.writeHNOCString("DNAM", mDestCell); } - if (mLockLevel != -999 && !inInventory) { + if (mLockLevel != 0 && !inInventory) { esm.writeHNT("FLTV", mLockLevel); } From ee581f593b29f2656160b04cd1f5ea1a32b7f776 Mon Sep 17 00:00:00 2001 From: Thomas Date: Wed, 23 Apr 2014 13:20:43 -0400 Subject: [PATCH 020/118] Fixed issue which may occur if there's no evidence chest nearby --- apps/openmw/mwworld/worldimp.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 5c9b25d28..87bdd2f9d 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2695,6 +2695,7 @@ namespace MWWorld MWWorld::Ptr closestChest; float closestDistance = FLT_MAX; + //Find closest stolen_goods chest std::vector chests; mCells.getInteriorPtrs("stolen_goods", chests); @@ -2712,19 +2713,19 @@ namespace MWWorld } } - if (!closestChest.isEmpty()) + if (!closestChest.isEmpty()) //Found a close chest { ContainerStore& store = ptr.getClass().getContainerStore(ptr); - for (ContainerStoreIterator it = store.begin(); it != store.end(); ++it) + for (ContainerStoreIterator it = store.begin(); it != store.end(); ++it) //Move all stolen stuff into chest { - if (!it->getCellRef().mOwner.empty() && it->getCellRef().mOwner != "player") + if (!it->getCellRef().mOwner.empty() && it->getCellRef().mOwner != "player") //Not owned by no one/player? { closestChest.getClass().getContainerStore(closestChest).add(*it, it->getRefData().getCount(), closestChest); store.remove(*it, it->getRefData().getCount(), ptr); } } + closestChest.getCellRef().mLockLevel = abs(closestChest.getCellRef().mLockLevel); } - closestChest.getCellRef().mLockLevel = abs(closestChest.getCellRef().mLockLevel); } void World::goToJail() From ce566693397b6fd23f71221abf07181325678e2e Mon Sep 17 00:00:00 2001 From: graffy76 Date: Wed, 23 Apr 2014 17:02:37 -0500 Subject: [PATCH 021/118] Fixed failed signal/slot connection between UserSettings and CSVWorld::SubView --- apps/opencs/view/doc/subview.hpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/apps/opencs/view/doc/subview.hpp b/apps/opencs/view/doc/subview.hpp index 52e42cc0e..733a75bb0 100644 --- a/apps/opencs/view/doc/subview.hpp +++ b/apps/opencs/view/doc/subview.hpp @@ -38,9 +38,6 @@ namespace CSVDoc virtual void setEditLock (bool locked) = 0; - virtual void updateUserSetting - (const QString &, const QStringList &); - virtual void setStatusBar (bool show); ///< Default implementation: ignored @@ -50,6 +47,10 @@ namespace CSVDoc signals: void focusId (const CSMWorld::UniversalId& universalId, const std::string& hint); + + public slots: + virtual void updateUserSetting + (const QString &, const QStringList &); }; } From f90810223abeac58b05c807476a77d9cf338a7ab Mon Sep 17 00:00:00 2001 From: Thomas Date: Wed, 23 Apr 2014 21:02:09 -0400 Subject: [PATCH 022/118] Added quicksave and quickload --- apps/openmw/mwinput/inputmanagerimp.cpp | 43 +++++++++++++++++++++++++ apps/openmw/mwinput/inputmanagerimp.hpp | 2 ++ 2 files changed, 45 insertions(+) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 1346b9e95..4bd2a1e65 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -26,6 +26,7 @@ #include "../mwworld/esmstore.hpp" #include "../mwmechanics/creaturestats.hpp" +#include "../mwstate/character.hpp" using namespace ICS; @@ -252,6 +253,12 @@ namespace MWInput case A_ToggleHUD: MWBase::Environment::get().getWindowManager()->toggleHud(); break; + case A_QuickSave: + quickSave(); + break; + case A_QuickLoad: + quickLoad(); + break; } } } @@ -638,6 +645,36 @@ namespace MWInput } } + void InputManager::quickLoad() { + MWState::Character* mCurrentCharacter = MWBase::Environment::get().getStateManager()->getCurrentCharacter(false); //Get current character + if(mCurrentCharacter) { //Ensure a current character exists + const MWState::Slot* slot = &*mCurrentCharacter->begin(); //Get newest save + if(slot) //Don't even try loading it if there's no prior save. + MWBase::Environment::get().getStateManager()->loadGame (mCurrentCharacter, slot); //load newest save. That was easy! + } + } + + void InputManager::quickSave() { + const MWState::Slot* slot = NULL; + MWState::Character* mCurrentCharacter = MWBase::Environment::get().getStateManager()->getCurrentCharacter(false); //Get current character + if (mCurrentCharacter) //Ensure one exists, otherwise do nothing + { + //Find quicksave slot + for (MWState::Character::SlotIterator it = mCurrentCharacter->begin(); it != mCurrentCharacter->end(); ++it) + { + if (it->mProfile.mDescription == "Quicksave") + slot = &*it; + } + //If no quicksave works create a new slot with Signature + if(slot == NULL) { + slot = mCurrentCharacter->createSlot(mCurrentCharacter->getSignature()); + if(slot==NULL) + std::cout << "Couldn't work out" << std::endl; + } + //MWBase::Environment::get().getWindowManager()->messageBox("#{sQuick_save}"); //No message on quicksave? + MWBase::Environment::get().getStateManager()->saveGame("Quicksave", slot); + } + } void InputManager::toggleSpell() { if (MWBase::Environment::get().getWindowManager()->isGuiMode()) return; @@ -842,6 +879,8 @@ namespace MWInput defaultKeyBindings[A_Screenshot] = SDL_GetKeyFromScancode(SDL_SCANCODE_F12); defaultKeyBindings[A_ToggleHUD] = SDL_GetKeyFromScancode(SDL_SCANCODE_F11); defaultKeyBindings[A_AlwaysRun] = SDL_GetKeyFromScancode(SDL_SCANCODE_Y); + defaultKeyBindings[A_QuickSave] = SDL_GetKeyFromScancode(SDL_SCANCODE_F5); + defaultKeyBindings[A_QuickLoad] = SDL_GetKeyFromScancode(SDL_SCANCODE_F9); std::map defaultMouseButtonBindings; defaultMouseButtonBindings[A_Inventory] = SDL_BUTTON_RIGHT; @@ -918,6 +957,8 @@ namespace MWInput descriptions[A_QuickKey9] = "sQuick9Cmd"; descriptions[A_QuickKey10] = "sQuick10Cmd"; descriptions[A_AlwaysRun] = "sAlways_Run"; + descriptions[A_QuickSave] = "sQuickSaveCmd"; + descriptions[A_QuickLoad] = "sQuickLoadCmd"; if (descriptions[action] == "") return ""; // not configurable @@ -961,6 +1002,8 @@ namespace MWInput ret.push_back(A_Journal); ret.push_back(A_Rest); ret.push_back(A_Console); + ret.push_back(A_QuickSave); + ret.push_back(A_QuickLoad); ret.push_back(A_Screenshot); ret.push_back(A_QuickKeysMenu); ret.push_back(A_QuickKey1); diff --git a/apps/openmw/mwinput/inputmanagerimp.hpp b/apps/openmw/mwinput/inputmanagerimp.hpp index 87fbda25c..5eb355566 100644 --- a/apps/openmw/mwinput/inputmanagerimp.hpp +++ b/apps/openmw/mwinput/inputmanagerimp.hpp @@ -183,6 +183,8 @@ namespace MWInput void toggleWalking(); void toggleAutoMove(); void rest(); + void quickLoad(); + void quickSave(); void quickKey (int index); void showQuickKeysMenu(); From e873135da7f1065c1168cff1ab6f18b8d5c04b8f Mon Sep 17 00:00:00 2001 From: Thomas Date: Wed, 23 Apr 2014 21:04:52 -0400 Subject: [PATCH 023/118] Missed a debug message --- apps/openmw/mwinput/inputmanagerimp.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 4bd2a1e65..7fc867186 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -668,8 +668,6 @@ namespace MWInput //If no quicksave works create a new slot with Signature if(slot == NULL) { slot = mCurrentCharacter->createSlot(mCurrentCharacter->getSignature()); - if(slot==NULL) - std::cout << "Couldn't work out" << std::endl; } //MWBase::Environment::get().getWindowManager()->messageBox("#{sQuick_save}"); //No message on quicksave? MWBase::Environment::get().getStateManager()->saveGame("Quicksave", slot); From 49620968b93caf88d4b49f94d0da7649aaf90a24 Mon Sep 17 00:00:00 2001 From: Thomas Date: Wed, 23 Apr 2014 21:21:11 -0400 Subject: [PATCH 024/118] Disallowed quicksave/load in character creation --- apps/openmw/mwinput/inputmanagerimp.cpp | 42 ++++++++++++++----------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 7fc867186..3d5d2f4a8 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -646,31 +646,35 @@ namespace MWInput } void InputManager::quickLoad() { - MWState::Character* mCurrentCharacter = MWBase::Environment::get().getStateManager()->getCurrentCharacter(false); //Get current character - if(mCurrentCharacter) { //Ensure a current character exists - const MWState::Slot* slot = &*mCurrentCharacter->begin(); //Get newest save - if(slot) //Don't even try loading it if there's no prior save. - MWBase::Environment::get().getStateManager()->loadGame (mCurrentCharacter, slot); //load newest save. That was easy! + if(MWBase::Environment::get().getWorld()->getGlobalInt ("chargenstate")==-1) { + MWState::Character* mCurrentCharacter = MWBase::Environment::get().getStateManager()->getCurrentCharacter(false); //Get current character + if(mCurrentCharacter) { //Ensure a current character exists + const MWState::Slot* slot = &*mCurrentCharacter->begin(); //Get newest save + if(slot) //Don't even try loading it if there's no prior save. + MWBase::Environment::get().getStateManager()->loadGame (mCurrentCharacter, slot); //load newest save. That was easy! + } } } void InputManager::quickSave() { - const MWState::Slot* slot = NULL; - MWState::Character* mCurrentCharacter = MWBase::Environment::get().getStateManager()->getCurrentCharacter(false); //Get current character - if (mCurrentCharacter) //Ensure one exists, otherwise do nothing - { - //Find quicksave slot - for (MWState::Character::SlotIterator it = mCurrentCharacter->begin(); it != mCurrentCharacter->end(); ++it) + if(MWBase::Environment::get().getWorld()->getGlobalInt ("chargenstate")==-1) { //ensure you're not in character creation + const MWState::Slot* slot = NULL; + MWState::Character* mCurrentCharacter = MWBase::Environment::get().getStateManager()->getCurrentCharacter(true); //Get current character + if (mCurrentCharacter) //Ensure one exists { - if (it->mProfile.mDescription == "Quicksave") - slot = &*it; + //Find quicksave slot + for (MWState::Character::SlotIterator it = mCurrentCharacter->begin(); it != mCurrentCharacter->end(); ++it) + { + if (it->mProfile.mDescription == "Quicksave") + slot = &*it; + } + //If no quicksave works create a new slot with Signature + if(slot == NULL) { + slot = mCurrentCharacter->createSlot(mCurrentCharacter->getSignature()); + } + //MWBase::Environment::get().getWindowManager()->messageBox("#{sQuick_save}"); //No message on quicksave? + MWBase::Environment::get().getStateManager()->saveGame("Quicksave", slot); } - //If no quicksave works create a new slot with Signature - if(slot == NULL) { - slot = mCurrentCharacter->createSlot(mCurrentCharacter->getSignature()); - } - //MWBase::Environment::get().getWindowManager()->messageBox("#{sQuick_save}"); //No message on quicksave? - MWBase::Environment::get().getStateManager()->saveGame("Quicksave", slot); } } void InputManager::toggleSpell() From 682c39548869593b02873a11f819a019056145fc Mon Sep 17 00:00:00 2001 From: Thomas Date: Wed, 23 Apr 2014 21:39:25 -0400 Subject: [PATCH 025/118] Apparently a normal save must exist for some reason, calling for a character to be made doesn't cause the signature to be created, and I don't know how to force create the signature (It's kinda driving me nuts) --- apps/openmw/mwinput/inputmanagerimp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 3d5d2f4a8..db030c940 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -659,7 +659,7 @@ namespace MWInput void InputManager::quickSave() { if(MWBase::Environment::get().getWorld()->getGlobalInt ("chargenstate")==-1) { //ensure you're not in character creation const MWState::Slot* slot = NULL; - MWState::Character* mCurrentCharacter = MWBase::Environment::get().getStateManager()->getCurrentCharacter(true); //Get current character + MWState::Character* mCurrentCharacter = MWBase::Environment::get().getStateManager()->getCurrentCharacter(false); //Get current character if (mCurrentCharacter) //Ensure one exists { //Find quicksave slot From a598060071bd6c3224f5f8c959ed1ab38fd16beb Mon Sep 17 00:00:00 2001 From: Thomas Date: Wed, 23 Apr 2014 23:12:30 -0400 Subject: [PATCH 026/118] Added autosave on rest, as well as an option in the settings menu --- apps/openmw/mwgui/waitdialog.cpp | 21 +++++++++++++++++++++ apps/openmw/mwgui/waitdialog.hpp | 1 + apps/openmw/mwinput/inputmanagerimp.cpp | 6 +----- files/mygui/openmw_settings_window.layout | 18 +++++++++++++++--- files/settings-default.cfg | 2 ++ 5 files changed, 40 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index 9417d2a4b..7e4522de6 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -8,6 +8,7 @@ #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/mechanicsmanager.hpp" +#include "../mwbase/statemanager.hpp" #include "../mwworld/class.hpp" #include "../mwworld/cellstore.hpp" @@ -15,6 +16,7 @@ #include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/npcstats.hpp" +#include "../mwstate/charactermanager.hpp" namespace MWGui { @@ -236,6 +238,25 @@ namespace MWGui { MWBase::Environment::get().getWindowManager()->pushGuiMode (GM_Levelup); } + if(Settings::Manager::getBool("autosave","Saves")) + autosave(); + } + + void WaitDialog::autosave() { + if(MWBase::Environment::get().getWorld()->getGlobalInt ("chargenstate")==-1) { //ensure you're not in character creation + const MWState::Slot* slot = NULL; + MWState::Character* mCurrentCharacter = MWBase::Environment::get().getStateManager()->getCurrentCharacter(true); //Get current character + if (mCurrentCharacter) //Ensure one exists + { + //Find quicksave slot + for (MWState::Character::SlotIterator it = mCurrentCharacter->begin(); it != mCurrentCharacter->end(); ++it) + { + if (it->mProfile.mDescription == "Autosave") + slot = &*it; + } + MWBase::Environment::get().getStateManager()->saveGame("Autosave", slot); + } + } } void WaitDialog::wakeUp () diff --git a/apps/openmw/mwgui/waitdialog.hpp b/apps/openmw/mwgui/waitdialog.hpp index d96649af6..5a66c3370 100644 --- a/apps/openmw/mwgui/waitdialog.hpp +++ b/apps/openmw/mwgui/waitdialog.hpp @@ -34,6 +34,7 @@ namespace MWGui bool getSleeping() { return mWaiting && mSleeping; } void wakeUp(); + void autosave(); protected: MyGUI::TextBox* mDateTimeText; diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index db030c940..c3f5ff7aa 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -659,7 +659,7 @@ namespace MWInput void InputManager::quickSave() { if(MWBase::Environment::get().getWorld()->getGlobalInt ("chargenstate")==-1) { //ensure you're not in character creation const MWState::Slot* slot = NULL; - MWState::Character* mCurrentCharacter = MWBase::Environment::get().getStateManager()->getCurrentCharacter(false); //Get current character + MWState::Character* mCurrentCharacter = MWBase::Environment::get().getStateManager()->getCurrentCharacter(true); //Get current character if (mCurrentCharacter) //Ensure one exists { //Find quicksave slot @@ -668,10 +668,6 @@ namespace MWInput if (it->mProfile.mDescription == "Quicksave") slot = &*it; } - //If no quicksave works create a new slot with Signature - if(slot == NULL) { - slot = mCurrentCharacter->createSlot(mCurrentCharacter->getSignature()); - } //MWBase::Environment::get().getWindowManager()->messageBox("#{sQuick_save}"); //No message on quicksave? MWBase::Environment::get().getStateManager()->saveGame("Quicksave", slot); } diff --git a/files/mygui/openmw_settings_window.layout b/files/mygui/openmw_settings_window.layout index adf9f1557..e348323be 100644 --- a/files/mygui/openmw_settings_window.layout +++ b/files/mygui/openmw_settings_window.layout @@ -3,10 +3,10 @@ - - + + - + @@ -95,6 +95,18 @@ + + + + + + + + + + + + diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 6361476e3..f24636d15 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -174,6 +174,8 @@ best attack = false [Saves] character = +# Save when resting +autosave = true [Windows] inventory x = 0 From 6a8bf71c4c173f4c05489eb028b4c679859de476 Mon Sep 17 00:00:00 2001 From: Thomas Date: Wed, 23 Apr 2014 23:33:57 -0400 Subject: [PATCH 027/118] Moved autosave to before you rest, not after it. --- apps/openmw/mwgui/waitdialog.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index 7e4522de6..b4dae090f 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -121,6 +121,8 @@ namespace MWGui MWBase::World* world = MWBase::Environment::get().getWorld(); world->getFader ()->fadeOut(0.2); setVisible(false); + if(Settings::Manager::getBool("autosave","Saves")) //autosaves + autosave(); mProgressBar.setVisible (true); mWaiting = true; @@ -238,8 +240,6 @@ namespace MWGui { MWBase::Environment::get().getWindowManager()->pushGuiMode (GM_Levelup); } - if(Settings::Manager::getBool("autosave","Saves")) - autosave(); } void WaitDialog::autosave() { From 05b21c92afde503ec2c524e66c1233f5772d1b21 Mon Sep 17 00:00:00 2001 From: Thomas Date: Thu, 24 Apr 2014 03:06:36 -0400 Subject: [PATCH 028/118] Moved quick save into statemanager class. Kept loader as is as it's rather specalized. --- apps/openmw/mwbase/statemanager.hpp | 4 ++++ apps/openmw/mwgui/waitdialog.cpp | 18 +----------------- apps/openmw/mwinput/inputmanagerimp.cpp | 16 +--------------- apps/openmw/mwstate/statemanagerimp.cpp | 21 +++++++++++++++++++-- apps/openmw/mwstate/statemanagerimp.hpp | 4 ++++ 5 files changed, 29 insertions(+), 34 deletions(-) diff --git a/apps/openmw/mwbase/statemanager.hpp b/apps/openmw/mwbase/statemanager.hpp index cd907408a..b9cf6aa7f 100644 --- a/apps/openmw/mwbase/statemanager.hpp +++ b/apps/openmw/mwbase/statemanager.hpp @@ -65,6 +65,10 @@ namespace MWBase /// /// \note \a slot must belong to \a character. + ///Simple saver, writes over the file if already existing + /** Used for quick save and autosave **/ + virtual void quickSave(std::string = "Quicksave")=0; + virtual MWState::Character *getCurrentCharacter (bool create = true) = 0; ///< \param create Create a new character, if there is no current character. diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index b4dae090f..023e01b06 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -122,7 +122,7 @@ namespace MWGui world->getFader ()->fadeOut(0.2); setVisible(false); if(Settings::Manager::getBool("autosave","Saves")) //autosaves - autosave(); + MWBase::Environment::get().getStateManager()->quickSave("Autosave"); mProgressBar.setVisible (true); mWaiting = true; @@ -242,22 +242,6 @@ namespace MWGui } } - void WaitDialog::autosave() { - if(MWBase::Environment::get().getWorld()->getGlobalInt ("chargenstate")==-1) { //ensure you're not in character creation - const MWState::Slot* slot = NULL; - MWState::Character* mCurrentCharacter = MWBase::Environment::get().getStateManager()->getCurrentCharacter(true); //Get current character - if (mCurrentCharacter) //Ensure one exists - { - //Find quicksave slot - for (MWState::Character::SlotIterator it = mCurrentCharacter->begin(); it != mCurrentCharacter->end(); ++it) - { - if (it->mProfile.mDescription == "Autosave") - slot = &*it; - } - MWBase::Environment::get().getStateManager()->saveGame("Autosave", slot); - } - } - } void WaitDialog::wakeUp () { diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index c3f5ff7aa..bc1aaf8f6 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -657,21 +657,7 @@ namespace MWInput } void InputManager::quickSave() { - if(MWBase::Environment::get().getWorld()->getGlobalInt ("chargenstate")==-1) { //ensure you're not in character creation - const MWState::Slot* slot = NULL; - MWState::Character* mCurrentCharacter = MWBase::Environment::get().getStateManager()->getCurrentCharacter(true); //Get current character - if (mCurrentCharacter) //Ensure one exists - { - //Find quicksave slot - for (MWState::Character::SlotIterator it = mCurrentCharacter->begin(); it != mCurrentCharacter->end(); ++it) - { - if (it->mProfile.mDescription == "Quicksave") - slot = &*it; - } - //MWBase::Environment::get().getWindowManager()->messageBox("#{sQuick_save}"); //No message on quicksave? - MWBase::Environment::get().getStateManager()->saveGame("Quicksave", slot); - } - } + MWBase::Environment::get().getStateManager()->quickSave(); } void InputManager::toggleSpell() { diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index 6b0871012..19b6ca1f3 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -223,6 +223,23 @@ void MWState::StateManager::saveGame (const std::string& description, const Slot slot->mPath.parent_path().filename().string()); } +void MWState::StateManager::quickSave(std::string name) { + if(MWBase::Environment::get().getWorld()->getGlobalInt ("chargenstate")==-1) { //ensure you're not in character creation + const MWState::Slot* slot = NULL; + MWState::Character* mCurrentCharacter = MWBase::Environment::get().getStateManager()->getCurrentCharacter(true); //Get current character + if (mCurrentCharacter) //Ensure one exists + { + //Find quicksave slot + for (MWState::Character::SlotIterator it = mCurrentCharacter->begin(); it != mCurrentCharacter->end(); ++it) + { + if (it->mProfile.mDescription == name) + slot = &*it; + } + MWBase::Environment::get().getStateManager()->saveGame(name, slot); + } + } +} + void MWState::StateManager::loadGame (const Character *character, const Slot *slot) { try @@ -309,11 +326,11 @@ void MWState::StateManager::loadGame (const Character *character, const Slot *sl MWBase::Environment::get().getMechanicsManager()->playerLoaded(); MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getPlayerPtr(); - + //Update the weapon icon in the hud with whatever the player is currently holding. MWWorld::InventoryStore& invStore = ptr.getClass().getInventoryStore(ptr); MWWorld::ContainerStoreIterator item = invStore.getSlot(MWWorld::InventoryStore::Slot_CarriedRight); - + if (item != invStore.end()) MWBase::Environment::get().getWindowManager()->setSelectedWeapon(*item); diff --git a/apps/openmw/mwstate/statemanagerimp.hpp b/apps/openmw/mwstate/statemanagerimp.hpp index 46ade236b..8082a2c78 100644 --- a/apps/openmw/mwstate/statemanagerimp.hpp +++ b/apps/openmw/mwstate/statemanagerimp.hpp @@ -49,6 +49,10 @@ namespace MWState /// /// \note Slot must belong to the current character. + ///Saves a file, using supplied filename, overwritting if needed + /** This is mostly used for quicksaving and autosaving, for they use the same name over and over again **/ + virtual void quickSave(std::string name = "Quicksave"); + virtual void loadGame (const Character *character, const Slot *slot); ///< Load a saved game file from \a slot. /// From 5b681e2199689120274e52e86585d803320552c4 Mon Sep 17 00:00:00 2001 From: Thomas Date: Thu, 24 Apr 2014 03:14:47 -0400 Subject: [PATCH 029/118] Moved quickload to statemanager for consistency's sake, as well as make autosave only occur on sleep, not wait. --- apps/openmw/mwbase/statemanager.hpp | 4 ++++ apps/openmw/mwgui/waitdialog.cpp | 2 +- apps/openmw/mwinput/inputmanagerimp.cpp | 9 +-------- apps/openmw/mwstate/statemanagerimp.cpp | 11 +++++++++++ apps/openmw/mwstate/statemanagerimp.hpp | 7 ++++++- 5 files changed, 23 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwbase/statemanager.hpp b/apps/openmw/mwbase/statemanager.hpp index b9cf6aa7f..fc4a2d806 100644 --- a/apps/openmw/mwbase/statemanager.hpp +++ b/apps/openmw/mwbase/statemanager.hpp @@ -69,6 +69,10 @@ namespace MWBase /** Used for quick save and autosave **/ virtual void quickSave(std::string = "Quicksave")=0; + ///Simple loader, loads the last saved file + /** Used for quickload **/ + virtual void quickLoad()=0; + virtual MWState::Character *getCurrentCharacter (bool create = true) = 0; ///< \param create Create a new character, if there is no current character. diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index 023e01b06..ed1b9e0a9 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -121,7 +121,7 @@ namespace MWGui MWBase::World* world = MWBase::Environment::get().getWorld(); world->getFader ()->fadeOut(0.2); setVisible(false); - if(Settings::Manager::getBool("autosave","Saves")) //autosaves + if(Settings::Manager::getBool("autosave","Saves") && mSleeping) //autosaves when enabled and sleeping (Not resting, apparently) MWBase::Environment::get().getStateManager()->quickSave("Autosave"); mProgressBar.setVisible (true); diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index bc1aaf8f6..51c0a1621 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -646,14 +646,7 @@ namespace MWInput } void InputManager::quickLoad() { - if(MWBase::Environment::get().getWorld()->getGlobalInt ("chargenstate")==-1) { - MWState::Character* mCurrentCharacter = MWBase::Environment::get().getStateManager()->getCurrentCharacter(false); //Get current character - if(mCurrentCharacter) { //Ensure a current character exists - const MWState::Slot* slot = &*mCurrentCharacter->begin(); //Get newest save - if(slot) //Don't even try loading it if there's no prior save. - MWBase::Environment::get().getStateManager()->loadGame (mCurrentCharacter, slot); //load newest save. That was easy! - } - } + MWBase::Environment::get().getStateManager()->quickLoad(); } void InputManager::quickSave() { diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index 19b6ca1f3..a0971b942 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -345,6 +345,17 @@ void MWState::StateManager::loadGame (const Character *character, const Slot *sl } } +void MWState::StateManager::quickLoad() { + if(MWBase::Environment::get().getWorld()->getGlobalInt ("chargenstate")==-1) { + MWState::Character* mCurrentCharacter = MWBase::Environment::get().getStateManager()->getCurrentCharacter(false); //Get current character + if(mCurrentCharacter) { //Ensure a current character exists + const MWState::Slot* slot = &*mCurrentCharacter->begin(); //Get newest save + if(slot) //Don't even try loading it if there's no prior save. + MWBase::Environment::get().getStateManager()->loadGame (mCurrentCharacter, slot); //load newest save. That was easy! + } + } +} + MWState::Character *MWState::StateManager::getCurrentCharacter (bool create) { return mCharacterManager.getCurrentCharacter (create); diff --git a/apps/openmw/mwstate/statemanagerimp.hpp b/apps/openmw/mwstate/statemanagerimp.hpp index 8082a2c78..2d3ca21fb 100644 --- a/apps/openmw/mwstate/statemanagerimp.hpp +++ b/apps/openmw/mwstate/statemanagerimp.hpp @@ -50,9 +50,14 @@ namespace MWState /// \note Slot must belong to the current character. ///Saves a file, using supplied filename, overwritting if needed - /** This is mostly used for quicksaving and autosaving, for they use the same name over and over again **/ + /** This is mostly used for quicksaving and autosaving, for they use the same name over and over again + \param name Name of save, defaults to "Quicksave"**/ virtual void quickSave(std::string name = "Quicksave"); + ///Loads the last saved file + /** Used for quickload **/ + virtual void quickLoad(); + virtual void loadGame (const Character *character, const Slot *slot); ///< Load a saved game file from \a slot. /// From 42b3233bdad827479a75a070b9edfa18a888d643 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 24 Apr 2014 09:54:47 +0200 Subject: [PATCH 030/118] removed a redundant check --- apps/openmw/mwstate/statemanagerimp.cpp | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index a0971b942..56f562e04 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -227,16 +227,14 @@ void MWState::StateManager::quickSave(std::string name) { if(MWBase::Environment::get().getWorld()->getGlobalInt ("chargenstate")==-1) { //ensure you're not in character creation const MWState::Slot* slot = NULL; MWState::Character* mCurrentCharacter = MWBase::Environment::get().getStateManager()->getCurrentCharacter(true); //Get current character - if (mCurrentCharacter) //Ensure one exists + + //Find quicksave slot + for (MWState::Character::SlotIterator it = mCurrentCharacter->begin(); it != mCurrentCharacter->end(); ++it) { - //Find quicksave slot - for (MWState::Character::SlotIterator it = mCurrentCharacter->begin(); it != mCurrentCharacter->end(); ++it) - { - if (it->mProfile.mDescription == name) - slot = &*it; - } - MWBase::Environment::get().getStateManager()->saveGame(name, slot); + if (it->mProfile.mDescription == name) + slot = &*it; } + MWBase::Environment::get().getStateManager()->saveGame(name, slot); } } From 760c8c721426f4a02711faad9ef94211f6254581 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 24 Apr 2014 09:56:51 +0200 Subject: [PATCH 031/118] removed a redundant include --- apps/openmw/mwinput/inputmanagerimp.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 51c0a1621..b37813915 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -26,7 +26,6 @@ #include "../mwworld/esmstore.hpp" #include "../mwmechanics/creaturestats.hpp" -#include "../mwstate/character.hpp" using namespace ICS; From 9db9ad410d52387a5cd4c96660fda44206eef5e3 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 24 Apr 2014 10:14:17 +0200 Subject: [PATCH 032/118] fixed checks for allowing load/save and some general cleanup --- apps/openmw/mwstate/statemanagerimp.cpp | 40 ++++++++++++------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index 56f562e04..e32aad505 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -223,19 +223,23 @@ void MWState::StateManager::saveGame (const std::string& description, const Slot slot->mPath.parent_path().filename().string()); } -void MWState::StateManager::quickSave(std::string name) { - if(MWBase::Environment::get().getWorld()->getGlobalInt ("chargenstate")==-1) { //ensure you're not in character creation - const MWState::Slot* slot = NULL; - MWState::Character* mCurrentCharacter = MWBase::Environment::get().getStateManager()->getCurrentCharacter(true); //Get current character +void MWState::StateManager::quickSave (std::string name) +{ + if (mState!=State_Running || + MWBase::Environment::get().getWorld()->getGlobalInt ("chargenstate")!=-1) // char gen + return; - //Find quicksave slot - for (MWState::Character::SlotIterator it = mCurrentCharacter->begin(); it != mCurrentCharacter->end(); ++it) - { - if (it->mProfile.mDescription == name) - slot = &*it; - } - MWBase::Environment::get().getStateManager()->saveGame(name, slot); + const Slot* slot = NULL; + Character* mCurrentCharacter = getCurrentCharacter(true); //Get current character + + //Find quicksave slot + for (Character::SlotIterator it = mCurrentCharacter->begin(); it != mCurrentCharacter->end(); ++it) + { + if (it->mProfile.mDescription == name) + slot = &*it; } + + saveGame(name, slot); } void MWState::StateManager::loadGame (const Character *character, const Slot *slot) @@ -343,15 +347,11 @@ void MWState::StateManager::loadGame (const Character *character, const Slot *sl } } -void MWState::StateManager::quickLoad() { - if(MWBase::Environment::get().getWorld()->getGlobalInt ("chargenstate")==-1) { - MWState::Character* mCurrentCharacter = MWBase::Environment::get().getStateManager()->getCurrentCharacter(false); //Get current character - if(mCurrentCharacter) { //Ensure a current character exists - const MWState::Slot* slot = &*mCurrentCharacter->begin(); //Get newest save - if(slot) //Don't even try loading it if there's no prior save. - MWBase::Environment::get().getStateManager()->loadGame (mCurrentCharacter, slot); //load newest save. That was easy! - } - } +void MWState::StateManager::quickLoad() +{ + if (Character* mCurrentCharacter = getCurrentCharacter (false)) + if (const MWState::Slot* slot = &*mCurrentCharacter->begin()) //Get newest save + loadGame (mCurrentCharacter, slot); } MWState::Character *MWState::StateManager::getCurrentCharacter (bool create) From 3f2ae950f5b51aa3c6a86d92b9756c3b7827e866 Mon Sep 17 00:00:00 2001 From: graffy76 Date: Thu, 24 Apr 2014 12:50:10 -0500 Subject: [PATCH 033/118] Disabled view resize for open views when user setting changes. Fixed new view size issue to match existing user settings. --- apps/opencs/model/settings/settingmanager.cpp | 12 ++++++++++++ apps/opencs/model/settings/settingmanager.hpp | 3 +++ apps/opencs/model/settings/usersettings.hpp | 4 ---- apps/opencs/view/doc/view.cpp | 13 +------------ apps/opencs/view/settings/listview.cpp | 2 +- apps/opencs/view/settings/page.cpp | 2 +- apps/opencs/view/settings/view.cpp | 7 ++++++- apps/opencs/view/world/table.cpp | 6 ++++-- apps/opencs/view/world/table.hpp | 4 ++-- apps/opencs/view/world/util.cpp | 6 ------ apps/opencs/view/world/util.hpp | 8 +++----- 11 files changed, 33 insertions(+), 34 deletions(-) diff --git a/apps/opencs/model/settings/settingmanager.cpp b/apps/opencs/model/settings/settingmanager.cpp index 70b91ee40..450252cd9 100644 --- a/apps/opencs/model/settings/settingmanager.cpp +++ b/apps/opencs/model/settings/settingmanager.cpp @@ -328,3 +328,15 @@ CSMSettings::SettingPageMap CSMSettings::SettingManager::settingPageMap() const return pageMap; } + +void CSMSettings::SettingManager::updateUserSetting(const QString &settingKey, + const QStringList &list) +{ + QStringList names = settingKey.split('.'); + + Setting *setting = findSetting (names.at(0), names.at(1)); + + setting->setDefinedValues (list); + + emit userSettingUpdated (names.at(1), list); +} diff --git a/apps/opencs/model/settings/settingmanager.hpp b/apps/opencs/model/settings/settingmanager.hpp index 8819096ad..ca8a2cc7b 100644 --- a/apps/opencs/model/settings/settingmanager.hpp +++ b/apps/opencs/model/settings/settingmanager.hpp @@ -75,8 +75,11 @@ namespace CSMSettings signals: + void userSettingUpdated (const QString &, const QStringList &); + public slots: + void updateUserSetting (const QString &, const QStringList &); }; } #endif // CSMSETTINGS_SETTINGMANAGER_HPP diff --git a/apps/opencs/model/settings/usersettings.hpp b/apps/opencs/model/settings/usersettings.hpp index 75a3a0797..63caed923 100644 --- a/apps/opencs/model/settings/usersettings.hpp +++ b/apps/opencs/model/settings/usersettings.hpp @@ -58,10 +58,6 @@ namespace CSMSettings { private: void buildSettingModelDefaults(); - - signals: - - void userSettingUpdated(const QString &, const QStringList &); }; } #endif // USERSETTINGS_HPP diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 47e1a80de..397567f99 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -492,18 +492,7 @@ void CSVDoc::View::resizeViewHeight (int height) void CSVDoc::View::updateUserSetting (const QString &name, const QStringList &list) -{ - if (list.isEmpty()) - return; - - int value = list.at(0).toInt(); - - if (name == "Width") - resizeViewWidth (value); - - else if (name == "Height") - resizeViewHeight (value); -} +{} void CSVDoc::View::toggleShowStatusBar (bool show) { diff --git a/apps/opencs/view/settings/listview.cpp b/apps/opencs/view/settings/listview.cpp index b2a47903f..36cdbb0ae 100644 --- a/apps/opencs/view/settings/listview.cpp +++ b/apps/opencs/view/settings/listview.cpp @@ -49,7 +49,7 @@ void CSVSettings::ListView::buildAbstractItemViewModel() void CSVSettings::ListView::emitItemViewUpdate (int idx) { - emit viewUpdated (objectName(), selectedValues()); + updateView(); } QWidget *CSVSettings::ListView::buildWidget(bool isMultiLine, int width) diff --git a/apps/opencs/view/settings/page.cpp b/apps/opencs/view/settings/page.cpp index 665326c2c..a5711c8f8 100644 --- a/apps/opencs/view/settings/page.cpp +++ b/apps/opencs/view/settings/page.cpp @@ -52,7 +52,7 @@ void CSVSettings::Page::addView (CSMSettings::Setting *setting) if (setting->isEditorSetting()) { connect (view, SIGNAL (viewUpdated(const QString&, const QStringList&)), &CSMSettings::UserSettings::instance(), - SIGNAL (userSettingUpdated (const QString &, const QStringList &))); + SLOT (updateUserSetting (const QString &, const QStringList &))); } } diff --git a/apps/opencs/view/settings/view.cpp b/apps/opencs/view/settings/view.cpp index 259dd518b..4f93b1c0f 100644 --- a/apps/opencs/view/settings/view.cpp +++ b/apps/opencs/view/settings/view.cpp @@ -151,6 +151,11 @@ void CSVSettings::View::setSelectedValues (const QStringList &list, } select (selection); + //push changes to model side + + + //update the view if the selection was set from the model side, not by the + //user if (doViewUpdate) updateView (signalUpdate); } @@ -198,7 +203,7 @@ QList CSVSettings::View::toStandardItemList void CSVSettings::View::updateView (bool signalUpdate) const { if (signalUpdate) - emit viewUpdated(objectName(), selectedValues()); + emit viewUpdated(viewKey(), selectedValues()); } QString CSVSettings::View::value (int row) const diff --git a/apps/opencs/view/world/table.cpp b/apps/opencs/view/world/table.cpp index 995de21fc..902ab268a 100644 --- a/apps/opencs/view/world/table.cpp +++ b/apps/opencs/view/world/table.cpp @@ -456,12 +456,14 @@ void CSVWorld::Table::updateUserSetting for (int i=0; i - (*delegate).updateUserSetting (name, list)) + { + dynamic_cast + (*delegate).updateUserSetting (name, list); { emit dataChanged (mModel->index (0, i), mModel->index (mModel->rowCount()-1, i)); } + } } void CSVWorld::Table::tableSizeUpdate() diff --git a/apps/opencs/view/world/table.hpp b/apps/opencs/view/world/table.hpp index dfc74b3eb..c2811b893 100644 --- a/apps/opencs/view/world/table.hpp +++ b/apps/opencs/view/world/table.hpp @@ -78,8 +78,6 @@ namespace CSVWorld CSMWorld::UniversalId getUniversalId (int row) const; - void updateUserSetting (const QString &name, const QStringList &list); - std::vector getColumnsWithDisplay(CSMWorld::ColumnBase::Display display) const; signals: @@ -123,6 +121,8 @@ namespace CSVWorld void requestFocus (const std::string& id); void recordFilterChanged (boost::shared_ptr filter); + + void updateUserSetting (const QString &name, const QStringList &list); }; } diff --git a/apps/opencs/view/world/util.cpp b/apps/opencs/view/world/util.cpp index 16310c8a9..ea8a7c541 100644 --- a/apps/opencs/view/world/util.cpp +++ b/apps/opencs/view/world/util.cpp @@ -196,12 +196,6 @@ bool CSVWorld::CommandDelegate::isEditLocked() const return mEditLock; } -bool CSVWorld::CommandDelegate::updateUserSetting (const QString &name, - const QStringList &list) -{ - return false; -} - void CSVWorld::CommandDelegate::setEditorData (QWidget *editor, const QModelIndex& index, bool tryDisplay) const { QVariant v = index.data(Qt::EditRole); diff --git a/apps/opencs/view/world/util.hpp b/apps/opencs/view/world/util.hpp index 50e2cf858..1c7e37818 100644 --- a/apps/opencs/view/world/util.hpp +++ b/apps/opencs/view/world/util.hpp @@ -136,17 +136,15 @@ namespace CSVWorld bool isEditLocked() const; - virtual bool updateUserSetting - (const QString &name, const QStringList &list); - ///< \return Does column require update? virtual void setEditorData (QWidget *editor, const QModelIndex& index, bool tryDisplay = false) const; - private slots: + public slots: - virtual void slotUpdateEditorSetting (const QString &settingName, const QString &settingValue) {} + virtual void updateUserSetting + (const QString &name, const QStringList &list) {} }; } From c3e08916dadd70ac926cb6f3d92ee8c4b4efa50f Mon Sep 17 00:00:00 2001 From: Jeffrey Haines Date: Thu, 24 Apr 2014 20:40:17 -0400 Subject: [PATCH 034/118] Sneak: Added support for state checking I need advice one what I should do in order to pass mActors over to the player. Particularly line 139 in player.cpp --- apps/openmw/mwbase/mechanicsmanager.hpp | 3 +++ apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 5 +++++ apps/openmw/mwmechanics/mechanicsmanagerimp.hpp | 2 ++ apps/openmw/mwworld/player.cpp | 15 +++++++++++++-- 4 files changed, 23 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index 22dda0ce0..7d27e73bd 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -164,6 +164,9 @@ namespace MWBase ///return the list of actors which are following the given actor (ie AiFollow is active and the target is the actor) virtual std::list getActorsFollowing(const MWWorld::Ptr& actor) = 0; + ///return the list of actors + virtual MWMechanics::Actors& getActors() = 0; + virtual void playerLoaded() = 0; }; } diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 84dc337c9..868a09e2e 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -989,4 +989,9 @@ namespace MWMechanics { return mActors.getActorsFollowing(actor); } + + MWMechanics::Actors& MechanicsManager::getActors() + { + return *mActors; + } } diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index 761caf586..a00c79525 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -137,6 +137,8 @@ namespace MWMechanics virtual std::list getActorsFollowing(const MWWorld::Ptr& actor); + virtual MWMechanics::Actors& getActors(); + virtual void toggleAI(); virtual bool isAIActive(); diff --git a/apps/openmw/mwworld/player.cpp b/apps/openmw/mwworld/player.cpp index a4a4e9568..9cc873c0f 100644 --- a/apps/openmw/mwworld/player.cpp +++ b/apps/openmw/mwworld/player.cpp @@ -9,6 +9,8 @@ #include #include +#include "../mwworld/esmstore.hpp" + #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" @@ -16,6 +18,8 @@ #include "../mwmechanics/movement.hpp" #include "../mwmechanics/npcstats.hpp" +#include "../mwmechanics/actors.hpp" +#include "../mwmechanics/mechanicsmanagerimp.hpp" #include "class.hpp" #include "ptr.hpp" @@ -130,8 +134,15 @@ namespace MWWorld ptr.getClass().getCreatureStats(ptr).setMovementFlag(MWMechanics::CreatureStats::Flag_Sneak, sneak); - // TODO show sneak indicator only when the player is not detected by any actor - MWBase::Environment::get().getWindowManager()->setSneakVisibility(sneak); + // Find all the actors who might be able to see the player + std::vector neighbors; + MWBase::Environment::get().getMechanicsManager()->getActors().getObjectsInRange( Ogre::Vector3(ptr.getRefData().getPosition().pos), + esmStore.get().find("fSneakUseDist")->getInt(), neighbors); + for (std::vector::iterator it = neighbors.begin(); it != neighbors.end(); ++it) + if ( MechanicsManager::awarenessCheck(ptr, *it) ) + MWBase::Environment::get().getWindowManager()->setSneakVisibility(sneak); + if (!neighbors) + MWBase::Environment::get().getWindowManager()->setSneakVisibility(sneak); } void Player::yaw(float yaw) From 42b879a9a542a9392352be885b0b8c206f8dfe4e Mon Sep 17 00:00:00 2001 From: Jeffrey Haines Date: Thu, 24 Apr 2014 22:41:05 -0400 Subject: [PATCH 035/118] Reworked the accusation of actors --- apps/openmw/mwbase/mechanicsmanager.hpp | 6 ++---- apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 10 +++++----- apps/openmw/mwmechanics/mechanicsmanagerimp.hpp | 3 +-- apps/openmw/mwworld/player.cpp | 8 +++++--- 4 files changed, 13 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index 7d27e73bd..d0a0783d3 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -160,13 +160,11 @@ namespace MWBase virtual bool isAIActive() = 0; virtual void getObjectsInRange (const Ogre::Vector3& position, float radius, std::vector& objects) = 0; + virtual void getActorsInRange(const Ogre::Vector3 &position, float radius, std::vector &objects) = 0; ///return the list of actors which are following the given actor (ie AiFollow is active and the target is the actor) virtual std::list getActorsFollowing(const MWWorld::Ptr& actor) = 0; - - ///return the list of actors - virtual MWMechanics::Actors& getActors() = 0; - + virtual void playerLoaded() = 0; }; } diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 868a09e2e..0ef94c13c 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -985,13 +985,13 @@ namespace MWMechanics mObjects.getObjectsInRange(position, radius, objects); } + void MechanicsManager::getActorsInRange(const Ogre::Vector3 &position, float radius, std::vector &objects) + { + mActors.getObjectsInRange(position, radius, objects); + } + std::list MechanicsManager::getActorsFollowing(const MWWorld::Ptr& actor) { return mActors.getActorsFollowing(actor); } - - MWMechanics::Actors& MechanicsManager::getActors() - { - return *mActors; - } } diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index a00c79525..603815744 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -134,11 +134,10 @@ namespace MWMechanics virtual void updateMagicEffects (const MWWorld::Ptr& ptr); virtual void getObjectsInRange (const Ogre::Vector3& position, float radius, std::vector& objects); + virtual void getActorsInRange(const Ogre::Vector3 &position, float radius, std::vector &objects); virtual std::list getActorsFollowing(const MWWorld::Ptr& actor); - virtual MWMechanics::Actors& getActors(); - virtual void toggleAI(); virtual bool isAIActive(); diff --git a/apps/openmw/mwworld/player.cpp b/apps/openmw/mwworld/player.cpp index 9cc873c0f..f4ca5ee27 100644 --- a/apps/openmw/mwworld/player.cpp +++ b/apps/openmw/mwworld/player.cpp @@ -134,14 +134,16 @@ namespace MWWorld ptr.getClass().getCreatureStats(ptr).setMovementFlag(MWMechanics::CreatureStats::Flag_Sneak, sneak); + const MWWorld::ESMStore& esmStore = MWBase::Environment::get().getWorld()->getStore(); + // Find all the actors who might be able to see the player std::vector neighbors; - MWBase::Environment::get().getMechanicsManager()->getActors().getObjectsInRange( Ogre::Vector3(ptr.getRefData().getPosition().pos), + MWBase::Environment::get().getMechanicsManager()->getActorsInRange( Ogre::Vector3(ptr.getRefData().getPosition().pos), esmStore.get().find("fSneakUseDist")->getInt(), neighbors); for (std::vector::iterator it = neighbors.begin(); it != neighbors.end(); ++it) - if ( MechanicsManager::awarenessCheck(ptr, *it) ) + if ( MWBase::Environment::get().getMechanicsManager()->awarenessCheck(ptr, *it) ) MWBase::Environment::get().getWindowManager()->setSneakVisibility(sneak); - if (!neighbors) + if (!neighbors.size()) MWBase::Environment::get().getWindowManager()->setSneakVisibility(sneak); } From f3272c941f0caca478418e0b32cd651db33dd526 Mon Sep 17 00:00:00 2001 From: Thomas Date: Thu, 24 Apr 2014 22:47:45 -0400 Subject: [PATCH 036/118] Fix for bug #1080, can't read/repair/make potions/use soul gems/rest/sleep while in combat. The radius for being in combat with the player is fAlarmDistance, which looked like the only pertinent thing. --- apps/openmw/mwbase/mechanicsmanager.hpp | 7 ++++- apps/openmw/mwinput/inputmanagerimp.cpp | 9 +++++-- apps/openmw/mwmechanics/actors.cpp | 26 +++++++++++++++++-- apps/openmw/mwmechanics/actors.hpp | 7 ++++- .../mwmechanics/mechanicsmanagerimp.cpp | 23 +++++++++++----- .../mwmechanics/mechanicsmanagerimp.hpp | 4 ++- apps/openmw/mwstate/statemanagerimp.cpp | 4 +++ apps/openmw/mwworld/actionalchemy.cpp | 8 ++++++ apps/openmw/mwworld/actionread.cpp | 12 +++++++-- apps/openmw/mwworld/actionrepair.cpp | 7 +++++ apps/openmw/mwworld/actionsoulgem.cpp | 22 ++++++++++------ apps/openmw/mwworld/player.cpp | 5 ++++ apps/openmw/mwworld/player.hpp | 5 +++- 13 files changed, 114 insertions(+), 25 deletions(-) diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index e4c480a8c..44b3d0229 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -161,9 +161,14 @@ namespace MWBase virtual void getObjectsInRange (const Ogre::Vector3& position, float radius, std::vector& objects) = 0; - ///return the list of actors which are following the given actor (ie AiFollow is active and the target is the actor) + ///return the list of actors which are following the given actor + /**ie AiFollow is active and the target is the actor**/ virtual std::list getActorsFollowing(const MWWorld::Ptr& actor) = 0; + ///Returns a list of actors who are fighting the given actor within the fAlarmDistance + /** ie AiCombat is active and the target is the actor **/ + virtual std::list getActorsFighting(const MWWorld::Ptr& actor) = 0; + virtual void playerLoaded() = 0; }; } diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 51c0a1621..75c9015a0 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -19,6 +19,7 @@ #include "../mwbase/windowmanager.hpp" #include "../mwbase/soundmanager.hpp" #include "../mwbase/statemanager.hpp" +#include "../mwbase/mechanicsmanager.hpp" #include "../mwworld/player.hpp" #include "../mwworld/class.hpp" @@ -693,8 +694,12 @@ namespace MWInput if (!MWBase::Environment::get().getWindowManager()->getRestEnabled () || MWBase::Environment::get().getWindowManager()->isGuiMode ()) return; - /// \todo check if resting is currently allowed (enemies nearby?) - MWBase::Environment::get().getWindowManager()->pushGuiMode (MWGui::GM_Rest); + if(mPlayer->isInCombat()) {//Check if in combat + MWBase::Environment::get().getWindowManager()->messageBox("#{sNotifyMessage2}"); //Nope, + return; + } + MWBase::Environment::get().getWindowManager()->pushGuiMode (MWGui::GM_Rest); //Open rest GUI + } void InputManager::screenshot() diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 7b83ff1f1..804ec7a41 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -176,7 +176,7 @@ namespace MWMechanics adjustMagicEffects (ptr); if (ptr.getClass().getCreatureStats(ptr).needToRecalcDynamicStats()) calculateDynamicStats (ptr); - + calculateCreatureStatModifiers (ptr, duration); // AI @@ -764,7 +764,7 @@ namespace MWMechanics creatureStats.setHostile(false); creatureStats.setAttacked(false); creatureStats.setAlarmed(false); - + // Update witness crime id npcStats.setCrimeId(-1); } @@ -1038,4 +1038,26 @@ namespace MWMechanics } return list; } + + std::list Actors::getActorsFighting(const MWWorld::Ptr& actor) { + std::list list; + std::vector neighbors; + Ogre::Vector3 position = Ogre::Vector3(actor.getRefData().getPosition().pos); + getObjectsInRange(position, + MWBase::Environment::get().getWorld()->getStore().get().find("fAlarmRadius")->getFloat(), + neighbors); //only care about those within the alarm disance + for(std::vector::iterator iter(neighbors.begin());iter != neighbors.end();iter++) + { + const MWWorld::Class &cls = MWWorld::Class::get(*iter); + CreatureStats &stats = cls.getCreatureStats(*iter); + + if(stats.getAiSequence().getTypeId() == AiPackage::TypeIdCombat) + { + MWMechanics::AiCombat* package = static_cast(stats.getAiSequence().getActivePackage()); + if(package->getTargetId() == actor.getCellRef().mRefID) + list.push_front(*iter); + } + } + return list; + } } diff --git a/apps/openmw/mwmechanics/actors.hpp b/apps/openmw/mwmechanics/actors.hpp index d61d74258..f7dff1058 100644 --- a/apps/openmw/mwmechanics/actors.hpp +++ b/apps/openmw/mwmechanics/actors.hpp @@ -98,8 +98,13 @@ namespace MWMechanics void getObjectsInRange(const Ogre::Vector3& position, float radius, std::vector& out); + ///Returns the list of actors which are following the given actor + /**ie AiFollow is active and the target is the actor **/ std::list getActorsFollowing(const MWWorld::Ptr& actor); - /// getActorsFighting(const MWWorld::Ptr& actor); private: PtrControllerMap mActors; diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index d24191d88..90c00a36e 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -772,6 +772,11 @@ namespace MWMechanics bool MechanicsManager::sleepInBed(const MWWorld::Ptr &ptr, const MWWorld::Ptr &bed) { + if(MWBase::Environment::get().getWorld()->getPlayer().isInCombat()) { + MWBase::Environment::get().getWindowManager()->messageBox("#{sNotifyMessage2}"); + return true; + } + MWWorld::Ptr victim; if (isAllowedToUse(ptr, bed, victim)) return false; @@ -832,17 +837,17 @@ namespace MWMechanics // Find all the NPCs within the alarm radius std::vector neighbors; - mActors.getObjectsInRange(Ogre::Vector3(ptr.getRefData().getPosition().pos), + mActors.getObjectsInRange(Ogre::Vector3(ptr.getRefData().getPosition().pos), esmStore.get().find("fAlarmRadius")->getInt(), neighbors); // Find an actor who witnessed the crime for (std::vector::iterator it = neighbors.begin(); it != neighbors.end(); ++it) - { + { if (*it == ptr) continue; // not the player // Was the crime seen? if ( ( MWBase::Environment::get().getWorld()->getLOS(ptr, *it) && awarenessCheck(ptr, *it) ) || - type == OT_Assault ) + type == OT_Assault ) { // Will the witness report the crime? @@ -853,7 +858,7 @@ namespace MWMechanics // Tell everyone, including yourself for (std::vector::iterator it1 = neighbors.begin(); it1 != neighbors.end(); ++it1) - { + { if (*it1 == ptr) continue; // not the player // TODO: Add more messages @@ -861,9 +866,9 @@ namespace MWMechanics MWBase::Environment::get().getDialogueManager()->say(*it1, "thief"); else if (type == OT_Assault) MWBase::Environment::get().getDialogueManager()->say(*it1, "attack"); - + // Will other witnesses paticipate in crime - if ( it1->getClass().getCreatureStats(*it1).getAiSetting(CreatureStats::AI_Alarm).getBase() >= alarm + if ( it1->getClass().getCreatureStats(*it1).getAiSetting(CreatureStats::AI_Alarm).getBase() >= alarm || type == OT_Assault ) { it1->getClass().getNpcStats(*it1).setCrimeId(id); @@ -884,7 +889,7 @@ namespace MWMechanics void MechanicsManager::reportCrime(const MWWorld::Ptr &ptr, const MWWorld::Ptr &victim, OffenseType type, int arg) { const MWWorld::Store& store = MWBase::Environment::get().getWorld()->getStore().get(); - + // Bounty for each type of crime if (type == OT_Trespassing || type == OT_SleepingInOwnedBed) arg = store.find("iCrimeTresspass")->getInt(); @@ -993,4 +998,8 @@ namespace MWMechanics { return mActors.getActorsFollowing(actor); } + + std::list MechanicsManager::getActorsFighting(const MWWorld::Ptr& actor) { + return mActors.getActorsFighting(actor); + } } diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index 5dd758377..4d59379d6 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -120,7 +120,7 @@ namespace MWMechanics /// Utility to check if opening (i.e. unlocking) this object is illegal and calling commitCrime if so virtual void objectOpened (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item); /// Attempt sleeping in a bed. If this is illegal, call commitCrime. - /// @return was it illegal, and someone saw you doing it? + /// @return was it illegal, and someone saw you doing it? Also returns fail when enemies are nearby virtual bool sleepInBed (const MWWorld::Ptr& ptr, const MWWorld::Ptr& bed); virtual void forceStateUpdate(const MWWorld::Ptr &ptr); @@ -137,6 +137,8 @@ namespace MWMechanics virtual std::list getActorsFollowing(const MWWorld::Ptr& actor); + virtual std::list getActorsFighting(const MWWorld::Ptr& actor); + virtual bool toggleAI(); virtual bool isAIActive(); diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index a0971b942..6c834a2be 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -235,9 +235,12 @@ void MWState::StateManager::quickSave(std::string name) { if (it->mProfile.mDescription == name) slot = &*it; } + MWBase::Environment::get().getWindowManager()->messageBox("#{sNotifyMessage4}"); //Saving... MWBase::Environment::get().getStateManager()->saveGame(name, slot); } } + else + MWBase::Environment::get().getWindowManager()->messageBox("#{sSaveGameDenied}"); //You can not save your game right now } void MWState::StateManager::loadGame (const Character *character, const Slot *slot) @@ -351,6 +354,7 @@ void MWState::StateManager::quickLoad() { if(mCurrentCharacter) { //Ensure a current character exists const MWState::Slot* slot = &*mCurrentCharacter->begin(); //Get newest save if(slot) //Don't even try loading it if there's no prior save. + //MWBase::Environment::get().getWindowManager()->messageBox("#{sLoadingMessage14}"); //it overlaps MWBase::Environment::get().getStateManager()->loadGame (mCurrentCharacter, slot); //load newest save. That was easy! } } diff --git a/apps/openmw/mwworld/actionalchemy.cpp b/apps/openmw/mwworld/actionalchemy.cpp index bba75bc49..bbba1081c 100644 --- a/apps/openmw/mwworld/actionalchemy.cpp +++ b/apps/openmw/mwworld/actionalchemy.cpp @@ -2,11 +2,19 @@ #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" +#include "../mwbase/world.hpp" + +#include "../mwworld/player.hpp" namespace MWWorld { void ActionAlchemy::executeImp (const Ptr& actor) { + if(MWBase::Environment::get().getWorld()->getPlayer().isInCombat()) { //Ensure we're not in combat + MWBase::Environment::get().getWindowManager()->messageBox("#{sInventoryMessage3}"); + return; + } + MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Alchemy); } } diff --git a/apps/openmw/mwworld/actionread.cpp b/apps/openmw/mwworld/actionread.cpp index 67755259e..433237e26 100644 --- a/apps/openmw/mwworld/actionread.cpp +++ b/apps/openmw/mwworld/actionread.cpp @@ -3,6 +3,9 @@ #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" #include "../mwbase/world.hpp" +#include "../mwbase/world.hpp" + +#include "../mwworld/player.hpp" #include "../mwmechanics/npcstats.hpp" @@ -19,8 +22,13 @@ namespace MWWorld { } - void ActionRead::executeImp (const MWWorld::Ptr& actor) - { + void ActionRead::executeImp (const MWWorld::Ptr& actor) { + + if(MWBase::Environment::get().getWorld()->getPlayer().isInCombat()) { //Ensure we're not in combat + MWBase::Environment::get().getWindowManager()->messageBox("#{sInventoryMessage4}"); + return; + } + LiveCellRef *ref = getTarget().get(); if (ref->mBase->mData.mIsScroll) diff --git a/apps/openmw/mwworld/actionrepair.cpp b/apps/openmw/mwworld/actionrepair.cpp index bd5642116..a86dc38b1 100644 --- a/apps/openmw/mwworld/actionrepair.cpp +++ b/apps/openmw/mwworld/actionrepair.cpp @@ -2,6 +2,8 @@ #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" +#include "../mwbase/world.hpp" +#include "../mwworld/player.hpp" namespace MWWorld { @@ -12,6 +14,11 @@ namespace MWWorld void ActionRepair::executeImp (const Ptr& actor) { + if(MWBase::Environment::get().getWorld()->getPlayer().isInCombat()) { + MWBase::Environment::get().getWindowManager()->messageBox("#{sInventoryMessage2}"); + return; + } + MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Repair); MWBase::Environment::get().getWindowManager()->startRepairItem(getTarget()); } diff --git a/apps/openmw/mwworld/actionsoulgem.cpp b/apps/openmw/mwworld/actionsoulgem.cpp index 6746f692f..7237fd334 100644 --- a/apps/openmw/mwworld/actionsoulgem.cpp +++ b/apps/openmw/mwworld/actionsoulgem.cpp @@ -2,20 +2,26 @@ #include "../mwbase/windowmanager.hpp" #include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" +#include "../mwworld/player.hpp" namespace MWWorld { -ActionSoulgem::ActionSoulgem(const Ptr &object) - : Action(false, object) -{ + ActionSoulgem::ActionSoulgem(const Ptr &object) + : Action(false, object) + { -} + } -void ActionSoulgem::executeImp(const Ptr &actor) -{ - MWBase::Environment::get().getWindowManager()->showSoulgemDialog(getTarget()); -} + void ActionSoulgem::executeImp(const Ptr &actor) + { + if(MWBase::Environment::get().getWorld()->getPlayer().isInCombat()) { //Ensure we're not in combat + MWBase::Environment::get().getWindowManager()->messageBox("#{sInventoryMessage5}"); + return; + } + MWBase::Environment::get().getWindowManager()->showSoulgemDialog(getTarget()); + } } diff --git a/apps/openmw/mwworld/player.cpp b/apps/openmw/mwworld/player.cpp index a4a4e9568..9202118a4 100644 --- a/apps/openmw/mwworld/player.cpp +++ b/apps/openmw/mwworld/player.cpp @@ -13,6 +13,7 @@ #include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" #include "../mwbase/soundmanager.hpp" +#include "../mwbase/mechanicsmanager.hpp" #include "../mwmechanics/movement.hpp" #include "../mwmechanics/npcstats.hpp" @@ -166,6 +167,10 @@ namespace MWWorld mTeleported = teleported; } + bool Player::isInCombat() { + return MWBase::Environment::get().getMechanicsManager()->getActorsFighting(getPlayer()).size() != 0; + } + void Player::markPosition(CellStore *markedCell, ESM::Position markedPosition) { mMarkedCell = markedCell; diff --git a/apps/openmw/mwworld/player.hpp b/apps/openmw/mwworld/player.hpp index 7dbaaddb4..7e3f7a3cf 100644 --- a/apps/openmw/mwworld/player.hpp +++ b/apps/openmw/mwworld/player.hpp @@ -44,7 +44,7 @@ namespace MWWorld int mCurrentCrimeId; // the id assigned witnesses int mPayedCrimeId; // the last id payed off (0 bounty) - + public: Player(const ESM::NPC *player, const MWBase::World& world); @@ -90,6 +90,9 @@ namespace MWWorld bool wasTeleported() const; void setTeleported(bool teleported); + ///Checks all actors to see if anyone has an aipackage against you + bool isInCombat(); + void clear(); void write (ESM::ESMWriter& writer) const; From 4a4c08946c5b75701a5eb9b3e878c0727380909d Mon Sep 17 00:00:00 2001 From: Jeffrey Haines Date: Thu, 24 Apr 2014 23:02:11 -0400 Subject: [PATCH 037/118] Checks the state of the passed sneak variable --- apps/openmw/mwworld/player.cpp | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwworld/player.cpp b/apps/openmw/mwworld/player.cpp index f4ca5ee27..8588547d2 100644 --- a/apps/openmw/mwworld/player.cpp +++ b/apps/openmw/mwworld/player.cpp @@ -134,17 +134,25 @@ namespace MWWorld ptr.getClass().getCreatureStats(ptr).setMovementFlag(MWMechanics::CreatureStats::Flag_Sneak, sneak); - const MWWorld::ESMStore& esmStore = MWBase::Environment::get().getWorld()->getStore(); + if (sneak == true) + { + const MWWorld::ESMStore& esmStore = MWBase::Environment::get().getWorld()->getStore(); - // Find all the actors who might be able to see the player - std::vector neighbors; - MWBase::Environment::get().getMechanicsManager()->getActorsInRange( Ogre::Vector3(ptr.getRefData().getPosition().pos), - esmStore.get().find("fSneakUseDist")->getInt(), neighbors); - for (std::vector::iterator it = neighbors.begin(); it != neighbors.end(); ++it) - if ( MWBase::Environment::get().getMechanicsManager()->awarenessCheck(ptr, *it) ) - MWBase::Environment::get().getWindowManager()->setSneakVisibility(sneak); - if (!neighbors.size()) - MWBase::Environment::get().getWindowManager()->setSneakVisibility(sneak); + // Find all the actors who might be able to see the player + std::vector neighbors; + MWBase::Environment::get().getMechanicsManager()->getActorsInRange( Ogre::Vector3(ptr.getRefData().getPosition().pos), + esmStore.get().find("fSneakUseDist")->getInt(), neighbors); + for (std::vector::iterator it = neighbors.begin(); it != neighbors.end(); ++it) + { + if ( MWBase::Environment::get().getMechanicsManager()->awarenessCheck(ptr, *it) ) + { + MWBase::Environment::get().getWindowManager()->setSneakVisibility(false); + break; + } + } + if (neighbors.size() == 0) + MWBase::Environment::get().getWindowManager()->setSneakVisibility(true); + } } void Player::yaw(float yaw) From 2e06414b43663684df1ec2b8e2b59391b2f32f17 Mon Sep 17 00:00:00 2001 From: graffy76 Date: Fri, 25 Apr 2014 07:16:40 -0500 Subject: [PATCH 038/118] Fixed broken delegate display modes (Display Format settings). Moved UserSetting update functions to DataDisplayDelegate. --- apps/opencs/model/settings/settingmanager.cpp | 2 +- apps/opencs/model/settings/usersettings.cpp | 9 ++-- apps/opencs/model/settings/usersettings.hpp | 2 +- apps/opencs/view/doc/view.cpp | 4 +- .../opencs/view/world/datadisplaydelegate.cpp | 44 +++++++++++++++++-- .../opencs/view/world/datadisplaydelegate.hpp | 12 ++++- apps/opencs/view/world/idtypedelegate.cpp | 25 ++--------- apps/opencs/view/world/idtypedelegate.hpp | 3 -- .../view/world/recordstatusdelegate.cpp | 23 ++-------- .../view/world/recordstatusdelegate.hpp | 3 -- 10 files changed, 67 insertions(+), 60 deletions(-) diff --git a/apps/opencs/model/settings/settingmanager.cpp b/apps/opencs/model/settings/settingmanager.cpp index 450252cd9..eec4c54cf 100644 --- a/apps/opencs/model/settings/settingmanager.cpp +++ b/apps/opencs/model/settings/settingmanager.cpp @@ -338,5 +338,5 @@ void CSMSettings::SettingManager::updateUserSetting(const QString &settingKey, setting->setDefinedValues (list); - emit userSettingUpdated (names.at(1), list); + emit userSettingUpdated (settingKey, list); } diff --git a/apps/opencs/model/settings/usersettings.cpp b/apps/opencs/model/settings/usersettings.cpp index db31f4255..badb73ece 100644 --- a/apps/opencs/model/settings/usersettings.cpp +++ b/apps/opencs/model/settings/usersettings.cpp @@ -260,13 +260,16 @@ void CSMSettings::UserSettings::saveSettings writeFilestream (openFilestream (mUserFilePath, false), settingMap); } -QString CSMSettings::UserSettings::settingValue (const QString §ion, - const QString &name) +QString CSMSettings::UserSettings::settingValue (const QString &settingKey) { - Setting *setting = findSetting(section, name); + QStringList names = settingKey.split('.'); + qDebug () << "looking for " << names.at(0) << ',' << names.at(1); + + Setting *setting = findSetting(names.at(0), names.at(1)); if (setting) { + qDebug() << "setting found"; if (!setting->definedValues().isEmpty()) return setting->definedValues().at(0); } diff --git a/apps/opencs/model/settings/usersettings.hpp b/apps/opencs/model/settings/usersettings.hpp index 63caed923..f0ed7af41 100644 --- a/apps/opencs/model/settings/usersettings.hpp +++ b/apps/opencs/model/settings/usersettings.hpp @@ -53,7 +53,7 @@ namespace CSMSettings { /// Writes settings to the user's config file path void saveSettings (const QMap &settingMap); - QString settingValue (const QString §ion, const QString &name); + QString settingValue (const QString &settingKey); private: diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 397567f99..acb272553 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -236,10 +236,10 @@ CSVDoc::View::View (ViewManager& viewManager, CSMDoc::Document *document, int to mViewTotal (totalViews) { QString width = CSMSettings::UserSettings::instance().settingValue - (QString("Window Size"), QString("Width")); + ("Window Size.Width"); QString height = CSMSettings::UserSettings::instance().settingValue - (QString("Window Size"), QString("Height")); + ("Window Size.Height"); resize (width.toInt(), height.toInt()); diff --git a/apps/opencs/view/world/datadisplaydelegate.cpp b/apps/opencs/view/world/datadisplaydelegate.cpp index d838395f6..ef0da56ac 100755 --- a/apps/opencs/view/world/datadisplaydelegate.cpp +++ b/apps/opencs/view/world/datadisplaydelegate.cpp @@ -1,16 +1,26 @@ #include "datadisplaydelegate.hpp" +#include "../../model/settings/usersettings.hpp" + #include #include CSVWorld::DataDisplayDelegate::DataDisplayDelegate(const ValueList &values, const IconList &icons, - QUndoStack &undoStack, QObject *parent) - : EnumDelegate (values, undoStack, parent), mDisplayMode (Mode_TextOnly), mIcons (icons) - , mIconSize (QSize(16, 16)), mIconLeftOffset(3), mTextLeftOffset(8) + QUndoStack &undoStack, + const QString &settingKey, + QObject *parent) + : EnumDelegate (values, undoStack, parent), mDisplayMode (Mode_TextOnly), + mIcons (icons), mIconSize (QSize(16, 16)), mIconLeftOffset(3), + mTextLeftOffset(8), mSettingKey (settingKey) { mTextAlignment.setAlignment (Qt::AlignLeft | Qt::AlignVCenter ); buildPixmaps(); + + QString value = + CSMSettings::UserSettings::instance().settingValue (settingKey); + + updateDisplayMode(value); } void CSVWorld::DataDisplayDelegate::buildPixmaps () @@ -89,6 +99,30 @@ void CSVWorld::DataDisplayDelegate::paintIcon (QPainter *painter, const QStyleOp painter->drawPixmap (iconRect, mPixmaps.at(index).second); } +void CSVWorld::DataDisplayDelegate::updateUserSetting (const QString &name, + const QStringList &list) +{ + if (list.isEmpty()) + return; + + QString value = list.at(0); + + if (name == mSettingKey) + updateDisplayMode (value); +} + +void CSVWorld::DataDisplayDelegate::updateDisplayMode (const QString &mode) +{ + if (mode == "Icon and Text") + mDisplayMode = Mode_IconAndText; + + else if (mode == "Icon Only") + mDisplayMode = Mode_IconOnly; + + else if (mode == "Text Only") + mDisplayMode = Mode_TextOnly; +} + CSVWorld::DataDisplayDelegate::~DataDisplayDelegate() { mIcons.clear(); @@ -106,5 +140,7 @@ CSVWorld::CommandDelegate *CSVWorld::DataDisplayDelegateFactory::makeDelegate (Q QObject *parent) const { - return new DataDisplayDelegate (mValues, mIcons, undoStack, parent); + return new DataDisplayDelegate (mValues, mIcons, undoStack, "", parent); } + + diff --git a/apps/opencs/view/world/datadisplaydelegate.hpp b/apps/opencs/view/world/datadisplaydelegate.hpp index d23b86631..f11c4a2b9 100755 --- a/apps/opencs/view/world/datadisplaydelegate.hpp +++ b/apps/opencs/view/world/datadisplaydelegate.hpp @@ -35,10 +35,14 @@ namespace CSVWorld int mIconLeftOffset; int mTextLeftOffset; + QString mSettingKey; + public: explicit DataDisplayDelegate (const ValueList & values, const IconList & icons, - QUndoStack& undoStack, QObject *parent); + QUndoStack& undoStack, + const QString &settingKey, + QObject *parent); ~DataDisplayDelegate(); @@ -53,8 +57,14 @@ namespace CSVWorld /// offset the horizontal position of the text from the right edge of the icon. Default is 8 pixels. void setTextLeftOffset (int offset); + ///update the display mode for the delegate + void updateUserSetting (const QString &name, const QStringList &list); + private: + /// update the display mode based on a passed string + void updateDisplayMode (const QString &); + /// custom paint function for painting the icon. Mode_IconAndText and Mode_Icon only. void paintIcon (QPainter *painter, const QStyleOptionViewItem &option, int i) const; diff --git a/apps/opencs/view/world/idtypedelegate.cpp b/apps/opencs/view/world/idtypedelegate.cpp index ce4e8f014..485ca57ac 100755 --- a/apps/opencs/view/world/idtypedelegate.cpp +++ b/apps/opencs/view/world/idtypedelegate.cpp @@ -4,30 +4,11 @@ CSVWorld::IdTypeDelegate::IdTypeDelegate (const ValueList &values, const IconList &icons, QUndoStack& undoStack, QObject *parent) - : DataDisplayDelegate (values, icons, undoStack, parent) + : DataDisplayDelegate (values, icons, undoStack, + "Display Format.Referenceable ID Type Display", + parent) {} -bool CSVWorld::IdTypeDelegate::updateEditorSetting (const QString &settingName, const QString &settingValue) -{ - /// \todo make the setting key a member variable, that is initialised from a constructor argument - if (settingName == "Referenceable ID Type Display") - { - if (settingValue == "Icon and Text") - mDisplayMode = Mode_IconAndText; - - else if (settingValue == "Icon Only") - mDisplayMode = Mode_IconOnly; - - else if (settingValue == "Text Only") - mDisplayMode = Mode_TextOnly; - - return true; - } - - return false; -} - - CSVWorld::IdTypeDelegateFactory::IdTypeDelegateFactory() { for (int i=0; i enums = diff --git a/apps/opencs/view/world/recordstatusdelegate.hpp b/apps/opencs/view/world/recordstatusdelegate.hpp index d9126fee0..1b42223af 100644 --- a/apps/opencs/view/world/recordstatusdelegate.hpp +++ b/apps/opencs/view/world/recordstatusdelegate.hpp @@ -20,9 +20,6 @@ namespace CSVWorld explicit RecordStatusDelegate(const ValueList& values, const IconList& icons, QUndoStack& undoStack, QObject *parent = 0); - - virtual bool updateEditorSetting (const QString &settingName, const QString &settingValue); - }; class RecordStatusDelegateFactory : public DataDisplayDelegateFactory From 42b332775a4b6623f4cacd3c7de25f18ead56b40 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 25 Apr 2014 15:30:46 +0200 Subject: [PATCH 039/118] removed some debug statements --- apps/opencs/model/settings/usersettings.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/apps/opencs/model/settings/usersettings.cpp b/apps/opencs/model/settings/usersettings.cpp index badb73ece..808fbfc70 100644 --- a/apps/opencs/model/settings/usersettings.cpp +++ b/apps/opencs/model/settings/usersettings.cpp @@ -11,8 +11,6 @@ #include #include -#include - #include #include @@ -263,13 +261,11 @@ void CSMSettings::UserSettings::saveSettings QString CSMSettings::UserSettings::settingValue (const QString &settingKey) { QStringList names = settingKey.split('.'); - qDebug () << "looking for " << names.at(0) << ',' << names.at(1); Setting *setting = findSetting(names.at(0), names.at(1)); if (setting) { - qDebug() << "setting found"; if (!setting->definedValues().isEmpty()) return setting->definedValues().at(0); } From f3626adc868c7e3a9080e63dd102219c294c20f0 Mon Sep 17 00:00:00 2001 From: mrcheko Date: Sat, 26 Apr 2014 00:20:55 +0400 Subject: [PATCH 040/118] remake of z-moving in combat for flying/swimming enemies --- apps/openmw/mwmechanics/aicombat.cpp | 52 ++++++++++++++----------- apps/openmw/mwmechanics/aicombat.hpp | 4 -- apps/openmw/mwmechanics/character.cpp | 9 ++--- apps/openmw/mwmechanics/pathfinding.hpp | 2 +- apps/openmw/mwmechanics/steering.cpp | 29 ++++++++++++++ apps/openmw/mwmechanics/steering.hpp | 2 + 6 files changed, 65 insertions(+), 33 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index 807e08c1d..8a3c23aef 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -38,6 +38,13 @@ namespace return Ogre::Radian( Ogre::Math::ACos(dir.y / len) * sgn(Ogre::Math::ASin(dir.x / len)) ).valueDegrees(); } + float getXAngleToDir(const Ogre::Vector3& dir, float dirLen = 0.0f) + { + float len = (dirLen >= 0.0f)? dirLen : dir.length(); + return Ogre::Radian(-Ogre::Math::ASin(dir.z / len)).valueDegrees(); + } + + const float PATHFIND_Z_REACH = 50.0f; // distance at which actor pays more attention to decide whether to shortcut or stick to pathgrid const float PATHFIND_CAUTION_DIST = 500.0f; @@ -79,7 +86,6 @@ namespace MWMechanics mStrike(false), mCombatMove(false), mMovement(), - mTargetAngle(0), mForceNoShortcut(false), mShortcutFailPos() { @@ -108,13 +114,18 @@ namespace MWMechanics } actor.getClass().getMovementSettings(actor) = mMovement; + actor.getClass().getMovementSettings(actor).mRotation[0] = 0; + actor.getClass().getMovementSettings(actor).mRotation[2] = 0; - if(actor.getRefData().getPosition().rot[2] != mTargetAngle) + if(mMovement.mRotation[2] != 0) { - zTurn(actor, Ogre::Degree(mTargetAngle)); + if(zTurn(actor, Ogre::Degree(mMovement.mRotation[2]))) mMovement.mRotation[2] = 0; + } + + if(mMovement.mRotation[0] != 0) + { + if(smoothTurn(actor, Ogre::Degree(mMovement.mRotation[0]), 0)) mMovement.mRotation[0] = 0; } - - mTimerAttack -= duration; actor.getClass().getCreatureStats(actor).setAttackingOrSpell(mStrike); @@ -225,7 +236,7 @@ namespace MWMechanics bool isStuck = false; float speed = 0.0f; - if(mMovement.mPosition[1] && (Ogre::Vector3(mLastPos.pos) - vActorPos).length() < (speed = cls.getSpeed(actor)) / 10.0f) + if(mMovement.mPosition[1] && (Ogre::Vector3(mLastPos.pos) - vActorPos).length() < (speed = cls.getSpeed(actor)) / 10.0f) isStuck = true; mLastPos = pos; @@ -235,31 +246,28 @@ namespace MWMechanics if(canMoveByZ = ((actor.getClass().isNpc() || actor.getClass().canSwim(actor)) && MWBase::Environment::get().getWorld()->isSwimming(actor)) || (actor.getClass().canFly(actor) && MWBase::Environment::get().getWorld()->isFlying(actor))) { - float zToTarget = vTargetPos.z - pos.pos[2]; - - mMovement.mPosition[1] = sqrt(distToTarget*distToTarget - zToTarget*zToTarget); // XY-plane vec length - mMovement.mPosition[2] = zToTarget; + // determine vertical angle to target + mMovement.mRotation[0] = getXAngleToDir(vDirToTarget, distToTarget); } if(distToTarget < rangeMelee || (distToTarget <= rangeCloseUp && mFollowTarget && !isStuck) ) { //Melee and Close-up combat vDirToTarget.z = 0; - mTargetAngle = getZAngleToDir(vDirToTarget, distToTarget); + mMovement.mRotation[2] = getZAngleToDir(vDirToTarget, distToTarget); if (mFollowTarget && distToTarget > rangeMelee) { //Close-up combat: just run up on target - if(!canMoveByZ) mMovement.mPosition[1] = 1; + mMovement.mPosition[1] = 1; } else { //Melee: stop running and attack mMovement.mPosition[1] = 0; - if(canMoveByZ) mMovement.mPosition[2] = 0; // When attacking with a weapon, choose between slash, thrust or chop - if (actor.getClass().hasInventoryStore(actor)) + if (mStrike && actor.getClass().hasInventoryStore(actor)) chooseBestAttack(weapon, mMovement); if(mMovement.mPosition[0] || mMovement.mPosition[1]) @@ -304,15 +312,15 @@ namespace MWMechanics if(speed == 0.0f) speed = cls.getSpeed(actor); // maximum dist before pit/obstacle for actor to avoid them depending on his speed float maxAvoidDist = tReaction * speed + speed / MAX_VEL_ANGULAR.valueRadians() * 2; - //if(actor.getRefData().getPosition().rot[2] != mTargetAngle) preferShortcut = checkWayIsClear(vActorPos, vTargetPos, distToTarget > maxAvoidDist*1.5? maxAvoidDist : maxAvoidDist/2); } + // don't use pathgrid when actor can move in 3 dimensions if(canMoveByZ) preferShortcut = true; if(preferShortcut) { - mTargetAngle = getZAngleToDir(vDirToTarget, distToTarget); + mMovement.mRotation[2] = getZAngleToDir(vDirToTarget, distToTarget); mForceNoShortcut = false; mShortcutFailPos.pos[0] = mShortcutFailPos.pos[1] = mShortcutFailPos.pos[2] = 0; mPathFinder.clearPath(); @@ -338,12 +346,12 @@ namespace MWMechanics // get point just before target std::list::iterator pntIter = --mPathFinder.getPath().end(); --pntIter; - Ogre::Vector3 vBeforeTarget = Ogre::Vector3(pntIter->mX, pntIter->mY, pntIter->mZ); + Ogre::Vector3 vBeforeTarget = Ogre::Vector3(pntIter->mX, pntIter->mY, pntIter->mZ); // if current actor pos is closer to target then last point of path (excluding target itself) then go straight on target if(distToTarget <= (vTargetPos - vBeforeTarget).length()) { - mTargetAngle = getZAngleToDir(vDirToTarget, distToTarget); + mMovement.mRotation[2] = getZAngleToDir(vDirToTarget, distToTarget); preferShortcut = true; } } @@ -352,13 +360,13 @@ namespace MWMechanics if(!preferShortcut) { if(!mPathFinder.getPath().empty()) - mTargetAngle = mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]); + mMovement.mRotation[2] = mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]); else - mTargetAngle = getZAngleToDir(vDirToTarget, distToTarget); + mMovement.mRotation[2] = getZAngleToDir(vDirToTarget, distToTarget); } } - if(!canMoveByZ) mMovement.mPosition[1] = 1; + mMovement.mPosition[1] = 1; mReadyToAttack = false; } @@ -392,8 +400,6 @@ namespace MWMechanics } } - actor.getClass().getMovementSettings(actor) = mMovement; - return false; } diff --git a/apps/openmw/mwmechanics/aicombat.hpp b/apps/openmw/mwmechanics/aicombat.hpp index b71dd9cf0..8130df0e8 100644 --- a/apps/openmw/mwmechanics/aicombat.hpp +++ b/apps/openmw/mwmechanics/aicombat.hpp @@ -36,10 +36,6 @@ namespace MWMechanics // when mCombatMove is true float mTimerCombatMove; - // the z rotation angle (degrees) we want to reach - // used every frame when mRotate is true - float mTargetAngle; - bool mReadyToAttack, mStrike; bool mFollowTarget; bool mCombatMove; diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 2c63d5a14..21f2ed883 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1014,11 +1014,11 @@ void CharacterController::update(float duration) if(mHitState != CharState_None && mJumpState == JumpState_None) vec = Ogre::Vector3(0.0f); Ogre::Vector3 rot = cls.getRotationVector(mPtr); + mMovementSpeed = cls.getSpeed(mPtr); vec.x *= mMovementSpeed; vec.y *= mMovementSpeed; - if(inwater || flying) vec.z *= mMovementSpeed; CharacterState movestate = CharState_None; CharacterState idlestate = CharState_SpecialIdle; @@ -1085,8 +1085,7 @@ void CharacterController::update(float duration) fatigue.setCurrent(fatigue.getCurrent() - fatigueLoss, fatigue.getCurrent() < 0); cls.getCreatureStats(mPtr).setFatigue(fatigue); - // kind of hack, reason - creatures can move along z when in water/flying - if(sneak || ((inwater || flying) && mPtr.getRefData().getHandle() == "player")) + if(sneak || inwater || flying) vec.z = 0.0f; if (inwater || flying) @@ -1121,7 +1120,7 @@ void CharacterController::update(float duration) vec.y *= mult; vec.z = 0.0f; } - else if(!inwater && !flying && vec.z > 0.0f && mJumpState == JumpState_None) + else if(vec.z > 0.0f && mJumpState == JumpState_None) { // Started a jump. float z = cls.getJump(mPtr); @@ -1183,7 +1182,7 @@ void CharacterController::update(float duration) { if(!(vec.z > 0.0f)) mJumpState = JumpState_None; - if(!inwater && !flying) vec.z = 0.0f; + vec.z = 0.0f; if(std::abs(vec.x/2.0f) > std::abs(vec.y)) { diff --git a/apps/openmw/mwmechanics/pathfinding.hpp b/apps/openmw/mwmechanics/pathfinding.hpp index 86fa3b6bc..ff3bf06fa 100644 --- a/apps/openmw/mwmechanics/pathfinding.hpp +++ b/apps/openmw/mwmechanics/pathfinding.hpp @@ -67,7 +67,7 @@ namespace MWMechanics /** Synchronize new path with old one to avoid visiting 1 waypoint 2 times @note If the first point is chosen as the nearest one - the cituation can occure when the 1st point of the new path is undesirable + the situation can occur when the 1st point of the new path is undesirable (i.e. the 2nd point of new path == the 1st point of old path). @param path - old path @return true if such point was found and deleted diff --git a/apps/openmw/mwmechanics/steering.cpp b/apps/openmw/mwmechanics/steering.cpp index 7646e832d..d10733b36 100644 --- a/apps/openmw/mwmechanics/steering.cpp +++ b/apps/openmw/mwmechanics/steering.cpp @@ -10,6 +10,35 @@ namespace MWMechanics { +bool smoothTurn(const MWWorld::Ptr& actor, Ogre::Radian targetAngle, int axis) +{ + Ogre::Radian currentAngle (actor.getRefData().getPosition().rot[axis]); + Ogre::Radian diff (targetAngle - currentAngle); + if (diff >= Ogre::Degree(180)) + { + // Turning the other way would be a better idea + diff = diff-Ogre::Degree(360); + } + else if (diff <= Ogre::Degree(-180)) + { + diff = Ogre::Degree(360)-diff; + } + Ogre::Radian absDiff = Ogre::Math::Abs(diff); + + // The turning animation actually moves you slightly, so the angle will be wrong again. + // Use epsilon to prevent jerkiness. + const Ogre::Degree epsilon (0.5); + if (absDiff < epsilon) + return true; + + Ogre::Radian limit = MAX_VEL_ANGULAR * MWBase::Environment::get().getFrameDuration(); + if (absDiff > limit) + diff = Ogre::Math::Sign(diff) * limit; + + actor.getClass().getMovementSettings(actor).mRotation[axis] = diff.valueRadians(); + return false; +} + bool zTurn(const MWWorld::Ptr& actor, Ogre::Radian targetAngle) { Ogre::Radian currentAngle (actor.getRefData().getPosition().rot[2]); diff --git a/apps/openmw/mwmechanics/steering.hpp b/apps/openmw/mwmechanics/steering.hpp index 9bdf7d4a3..1c00b508d 100644 --- a/apps/openmw/mwmechanics/steering.hpp +++ b/apps/openmw/mwmechanics/steering.hpp @@ -17,6 +17,8 @@ const Ogre::Radian MAX_VEL_ANGULAR(10); /// @return have we reached the target angle? bool zTurn(const MWWorld::Ptr& actor, Ogre::Radian targetAngle); +bool smoothTurn(const MWWorld::Ptr& actor, Ogre::Radian targetAngle, int axis); + } #endif From 5b011e43a7a30f6d428f095031f4593e968b1f8b Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 23 Apr 2014 19:49:09 +0200 Subject: [PATCH 041/118] Fix a crash after loading game --- apps/openmw/mwgui/hud.cpp | 8 +++++++- apps/openmw/mwgui/hud.hpp | 1 + apps/openmw/mwgui/windowmanagerimp.cpp | 4 ++++ 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index 06a228a1f..02cc5c6a9 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -52,7 +52,7 @@ namespace MWGui , mWeaponVisible(true) , mSpellVisible(true) , mWorldMouseOver(false) - , mEnemyHealthTimer(0) + , mEnemyHealthTimer(-1) , mIsDrowning(false) , mWeaponSpellTimer(0.f) , mDrowningFlashTheta(0.f) @@ -639,4 +639,10 @@ namespace MWGui updateEnemyHealthBar(); } + void HUD::resetEnemy() + { + mEnemy = MWWorld::Ptr(); + mEnemyHealthTimer = -1; + } + } diff --git a/apps/openmw/mwgui/hud.hpp b/apps/openmw/mwgui/hud.hpp index 1645d8db0..38535630f 100644 --- a/apps/openmw/mwgui/hud.hpp +++ b/apps/openmw/mwgui/hud.hpp @@ -56,6 +56,7 @@ namespace MWGui void update(); void setEnemy(const MWWorld::Ptr& enemy); + void resetEnemy(); private: MyGUI::ProgressBar *mHealth, *mMagicka, *mStamina, *mEnemyHealth, *mDrowning; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index db19070a6..2b9840876 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -289,6 +289,10 @@ namespace MWGui void WindowManager::setNewGame(bool newgame) { + // This method will always be called after loading a savegame or starting a new game + // Reset enemy, it could be a dangling pointer from a previous game + mHud->resetEnemy(); + if (newgame) { disallowAll(); From 91e50585ff1984f0f44a9983d38c16552f144cc7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 24 Apr 2014 05:17:01 +0200 Subject: [PATCH 042/118] AiWander: make sure to walk, not run --- apps/openmw/mwmechanics/aitravel.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwmechanics/aitravel.cpp b/apps/openmw/mwmechanics/aitravel.cpp index c62c4e970..024656b38 100644 --- a/apps/openmw/mwmechanics/aitravel.cpp +++ b/apps/openmw/mwmechanics/aitravel.cpp @@ -8,6 +8,7 @@ #include "steering.hpp" #include "movement.hpp" +#include "creaturestats.hpp" namespace MWMechanics { @@ -30,6 +31,8 @@ namespace MWMechanics Movement &movement = actor.getClass().getMovementSettings(actor); const ESM::Cell *cell = actor.getCell()->getCell(); + actor.getClass().getCreatureStats(actor).setMovementFlag(CreatureStats::Flag_Run, false); + MWWorld::Ptr player = world->getPlayerPtr(); if(cell->mData.mX != player.getCell()->getCell()->mData.mX) { From f05606657cbfabbdc03fdff822149a2b83bc41c0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 25 Apr 2014 10:01:03 +0200 Subject: [PATCH 043/118] Correctly insert pasted text at cursor position --- apps/openmw/mwinput/inputmanagerimp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index deeb93440..42362fde7 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -484,7 +484,7 @@ namespace MWInput if (text) { - edit->addText(MyGUI::UString(text)); + edit->insertText(MyGUI::UString(text), edit->getTextCursor()); SDL_free(text); } } From cd1b4218e79f7c7cad2d7ff32962eb281deb01d4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 26 Apr 2014 03:15:50 +0200 Subject: [PATCH 044/118] Fix dynamically placed objects being discarded when loading game --- apps/openmw/mwworld/cellstore.cpp | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index 6bc7657e4..bbd968a7b 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -52,7 +52,7 @@ namespace iter!=collection.mList.end(); ++iter) { if (iter->mData.getCount()==0 && iter->mRef.mRefNum.mContentFile==-1) - continue; // deleted file that did not came from a content file -> ignore + continue; // deleted reference that did not come from a content file -> ignore RecordType state; iter->save (state); @@ -72,13 +72,17 @@ namespace RecordType state; state.load (reader); - std::map::const_iterator iter = - contentFileMap.find (state.mRef.mRefNum.mContentFile); + // If the reference came from a content file, make sure this content file is loaded + if (state.mRef.mRefNum.mContentFile != -1) + { + std::map::const_iterator iter = + contentFileMap.find (state.mRef.mRefNum.mContentFile); - if (iter==contentFileMap.end()) - return; // content file has been removed -> skip + if (iter==contentFileMap.end()) + return; // content file has been removed -> skip - state.mRef.mRefNum.mContentFile = iter->second; + state.mRef.mRefNum.mContentFile = iter->second; + } if (!MWWorld::LiveCellRef::checkState (state)) return; // not valid anymore with current content files -> skip From 6eca5ac4bbab19dcf2a2a751431a655108718d45 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 26 Apr 2014 07:46:19 +0200 Subject: [PATCH 045/118] Fixes #1296: Streamlined cellChanged detection --- apps/openmw/engine.cpp | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 508b195e9..03361408c 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -59,9 +59,6 @@ void OMW::Engine::executeLocalScripts() MWScript::InterpreterContext interpreterContext ( &script.second.getRefData().getLocals(), script.second); MWBase::Environment::get().getScriptManager()->run (script.first, interpreterContext); - - if (MWBase::Environment::get().getWorld()->hasCellChanged()) - break; } localScripts.setIgnore (MWWorld::Ptr()); @@ -101,15 +98,10 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt) // global scripts MWBase::Environment::get().getScriptManager()->getGlobalScripts().run(); - bool changed = MWBase::Environment::get().getWorld()->hasCellChanged(); - // local scripts - executeLocalScripts(); // This does not handle the case where a global script causes a - // cell change, followed by a cell change in a local script during - // the same frame. + executeLocalScripts(); - if (changed) // keep change flag for another frame, if cell changed happened in local script - MWBase::Environment::get().getWorld()->markCellAsUnchanged(); + MWBase::Environment::get().getWorld()->markCellAsUnchanged(); if (!paused) MWBase::Environment::get().getWorld()->advanceTime( From b13b25dd1b1a94c13b61f569051382f7218304a6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 26 Apr 2014 11:03:17 +0200 Subject: [PATCH 046/118] Fixes #1295: Support partial matches in Cell filter --- apps/openmw/mwdialogue/filter.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwdialogue/filter.cpp b/apps/openmw/mwdialogue/filter.cpp index 18ae7dd1b..b1c700e31 100644 --- a/apps/openmw/mwdialogue/filter.cpp +++ b/apps/openmw/mwdialogue/filter.cpp @@ -111,8 +111,14 @@ bool MWDialogue::Filter::testPlayer (const ESM::DialInfo& info) const // check cell if (!info.mCell.empty()) - if (!Misc::StringUtils::ciEqual(player.getCell()->getCell()->mName, info.mCell)) + { + // supports partial matches, just like getPcCell + const std::string& playerCell = player.getCell()->getCell()->mName; + bool match = playerCell.length()>=info.mCell.length() && + Misc::StringUtils::ciEqual(playerCell.substr (0, info.mCell.length()), info.mCell); + if (!match) return false; + } return true; } From 45d2a00717a504d65679978954876120f9ec00ca Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 26 Apr 2014 11:36:27 +0200 Subject: [PATCH 047/118] Fixes #1293: Allow interpolation type 0 in case of 0 keys --- apps/openmw/mwrender/npcanimation.cpp | 3 ++- components/nif/niffile.hpp | 5 +++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index a09a58191..14f5cc4e7 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -68,7 +68,8 @@ namespace MWRender float HeadAnimationTime::getValue() const { - // TODO: Handle eye blinking (time is in the text keys) + // TODO use time from text keys (Talk Start/Stop, Blink Start/Stop) + // TODO: Handle eye blinking if (MWBase::Environment::get().getSoundManager()->sayDone(mReference)) return 0; else diff --git a/components/nif/niffile.hpp b/components/nif/niffile.hpp index 79e1cc2a5..d4b042726 100644 --- a/components/nif/niffile.hpp +++ b/components/nif/niffile.hpp @@ -199,6 +199,11 @@ struct KeyListT { key.mContinuity = nif->getFloat(); } } + else if (mInterpolationType == 0) + { + if (count != 0) + nif->file->fail("Interpolation type 0 doesn't work with keys"); + } else nif->file->fail("Unhandled interpolation type: "+Ogre::StringConverter::toString(mInterpolationType)); } From ef39b0f6abb7fb6de34fa0934398798a09a0f9fe Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 26 Apr 2014 11:41:44 +0200 Subject: [PATCH 048/118] Fixes #1291: Faction rank saving issue A value of 0 is the first rank, -1 means not a member --- apps/openmw/mwmechanics/npcstats.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/npcstats.cpp b/apps/openmw/mwmechanics/npcstats.cpp index e11e3b0c4..819c2701c 100644 --- a/apps/openmw/mwmechanics/npcstats.cpp +++ b/apps/openmw/mwmechanics/npcstats.cpp @@ -491,7 +491,7 @@ void MWMechanics::NpcStats::readState (const ESM::NpcStats& state) if (iter->second.mExpelled) mExpelled.insert (iter->first); - if (iter->second.mRank) + if (iter->second.mRank >= 0) mFactionRank.insert (std::make_pair (iter->first, iter->second.mRank)); if (iter->second.mReputation) From f921f2e7db8e62cb1f1588b26b2969a4286855a6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 26 Apr 2014 12:04:37 +0200 Subject: [PATCH 049/118] Make PcRaiseRank, PcLowerRank and PcJoinFaction properly accept references instead of using the actor that the player talked to last. This also solves a potential crash when no actor has been talked to yet, e.g. immediately after loading a savegame. --- apps/openmw/mwbase/dialoguemanager.hpp | 3 --- apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 5 ---- apps/openmw/mwdialogue/dialoguemanagerimp.hpp | 3 --- apps/openmw/mwscript/docs/vmformat.txt | 5 +++- apps/openmw/mwscript/statsextensions.cpp | 25 ++++++++++++------- components/compiler/extensions0.cpp | 6 ++--- components/compiler/opcodes.hpp | 4 +++ 7 files changed, 27 insertions(+), 24 deletions(-) diff --git a/apps/openmw/mwbase/dialoguemanager.hpp b/apps/openmw/mwbase/dialoguemanager.hpp index 3d70fdc6a..e1d1246c8 100644 --- a/apps/openmw/mwbase/dialoguemanager.hpp +++ b/apps/openmw/mwbase/dialoguemanager.hpp @@ -45,9 +45,6 @@ namespace MWBase virtual void goodbye() = 0; - virtual MWWorld::Ptr getActor() const = 0; - ///< Return the actor the player is currently talking to. - virtual void say(const MWWorld::Ptr &actor, const std::string &topic) const = 0; //calbacks for the GUI diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index 88f1302bb..32535f33e 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -468,11 +468,6 @@ namespace MWDialogue mIsInChoice = true; } - MWWorld::Ptr DialogueManager::getActor() const - { - return mActor; - } - void DialogueManager::goodbye() { mIsInChoice = true; diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.hpp b/apps/openmw/mwdialogue/dialoguemanagerimp.hpp index b9284dc1a..a2e31e791 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.hpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.hpp @@ -68,9 +68,6 @@ namespace MWDialogue virtual void goodbye(); - virtual MWWorld::Ptr getActor() const; - ///< Return the actor the player is currently talking to. - virtual bool checkServiceRefused (); virtual void say(const MWWorld::Ptr &actor, const std::string &topic) const; diff --git a/apps/openmw/mwscript/docs/vmformat.txt b/apps/openmw/mwscript/docs/vmformat.txt index 70186a089..ceea34466 100644 --- a/apps/openmw/mwscript/docs/vmformat.txt +++ b/apps/openmw/mwscript/docs/vmformat.txt @@ -54,7 +54,10 @@ op 0x20025: AiFollowCell, explicit reference op 0x20026: ModRegion op 0x20027: RemoveSoulGem op 0x20028: RemoveSoulGem, explicit reference -opcodes 0x20029-0x3ffff unused +op 0x20029: PCRaiseRank, explicit reference +op 0x2002a: PCLowerRank, explicit reference +op 0x2002b: PCJoinFaction, explicit reference +opcodes 0x2002c-0x3ffff unused Segment 4: (not implemented yet) diff --git a/apps/openmw/mwscript/statsextensions.cpp b/apps/openmw/mwscript/statsextensions.cpp index 80467f58a..36083e4b0 100644 --- a/apps/openmw/mwscript/statsextensions.cpp +++ b/apps/openmw/mwscript/statsextensions.cpp @@ -29,10 +29,8 @@ namespace { - std::string getDialogueActorFaction() + std::string getDialogueActorFaction(MWWorld::Ptr actor) { - MWWorld::Ptr actor = MWBase::Environment::get().getDialogueManager()->getActor(); - const MWMechanics::NpcStats &stats = MWWorld::Class::get (actor).getNpcStats (actor); if (stats.getFactionRanks().empty()) @@ -523,6 +521,7 @@ namespace MWScript } }; + template class OpPCJoinFaction : public Interpreter::Opcode1 { public: @@ -533,7 +532,8 @@ namespace MWScript if(arg0==0) { - factionID = getDialogueActorFaction(); + MWWorld::Ptr actor = R()(runtime); + factionID = getDialogueActorFaction(actor); } else { @@ -552,6 +552,7 @@ namespace MWScript } }; + template class OpPCRaiseRank : public Interpreter::Opcode1 { public: @@ -562,7 +563,8 @@ namespace MWScript if(arg0==0) { - factionID = getDialogueActorFaction(); + MWWorld::Ptr actor = R()(runtime); + factionID = getDialogueActorFaction(actor); } else { @@ -585,6 +587,7 @@ namespace MWScript } }; + template class OpPCLowerRank : public Interpreter::Opcode1 { public: @@ -595,7 +598,8 @@ namespace MWScript if(arg0==0) { - factionID = getDialogueActorFaction(); + MWWorld::Ptr actor = R()(runtime); + factionID = getDialogueActorFaction(actor); } else { @@ -1180,9 +1184,12 @@ namespace MWScript interpreter.installSegment5 (Compiler::Stats::opcodeGetSpell, new OpGetSpell); interpreter.installSegment5 (Compiler::Stats::opcodeGetSpellExplicit, new OpGetSpell); - interpreter.installSegment3(Compiler::Stats::opcodePCRaiseRank,new OpPCRaiseRank); - interpreter.installSegment3(Compiler::Stats::opcodePCLowerRank,new OpPCLowerRank); - interpreter.installSegment3(Compiler::Stats::opcodePCJoinFaction,new OpPCJoinFaction); + interpreter.installSegment3(Compiler::Stats::opcodePCRaiseRank,new OpPCRaiseRank); + interpreter.installSegment3(Compiler::Stats::opcodePCLowerRank,new OpPCLowerRank); + interpreter.installSegment3(Compiler::Stats::opcodePCJoinFaction,new OpPCJoinFaction); + interpreter.installSegment3(Compiler::Stats::opcodePCRaiseRankExplicit,new OpPCRaiseRank); + interpreter.installSegment3(Compiler::Stats::opcodePCLowerRankExplicit,new OpPCLowerRank); + interpreter.installSegment3(Compiler::Stats::opcodePCJoinFactionExplicit,new OpPCJoinFaction); interpreter.installSegment3(Compiler::Stats::opcodeGetPCRank,new OpGetPCRank); interpreter.installSegment3(Compiler::Stats::opcodeGetPCRankExplicit,new OpGetPCRank); diff --git a/components/compiler/extensions0.cpp b/components/compiler/extensions0.cpp index 78b6409f2..531fe2959 100644 --- a/components/compiler/extensions0.cpp +++ b/components/compiler/extensions0.cpp @@ -409,9 +409,9 @@ namespace Compiler opcodeResurrectExplicit); extensions.registerFunction ("getspell", 'l', "c", opcodeGetSpell, opcodeGetSpellExplicit); - extensions.registerInstruction("pcraiserank","/S",opcodePCRaiseRank); - extensions.registerInstruction("pclowerrank","/S",opcodePCLowerRank); - extensions.registerInstruction("pcjoinfaction","/S",opcodePCJoinFaction); + extensions.registerInstruction("pcraiserank","/S",opcodePCRaiseRank, opcodePCRaiseRankExplicit); + extensions.registerInstruction("pclowerrank","/S",opcodePCLowerRank, opcodePCLowerRankExplicit); + extensions.registerInstruction("pcjoinfaction","/S",opcodePCJoinFaction, opcodePCJoinFactionExplicit); extensions.registerInstruction ("moddisposition","l",opcodeModDisposition, opcodeModDispositionExplicit); extensions.registerInstruction ("setdisposition","l",opcodeSetDisposition, diff --git a/components/compiler/opcodes.hpp b/components/compiler/opcodes.hpp index 1dbdbf7e7..27ee182cf 100644 --- a/components/compiler/opcodes.hpp +++ b/components/compiler/opcodes.hpp @@ -330,6 +330,10 @@ namespace Compiler const int opcodePCRaiseRank = 0x2000b; const int opcodePCLowerRank = 0x2000c; const int opcodePCJoinFaction = 0x2000d; + const int opcodePCRaiseRankExplicit = 0x20029; + const int opcodePCLowerRankExplicit = 0x2002a; + const int opcodePCJoinFactionExplicit = 0x2002b; + const int opcodeGetPCRank = 0x2000e; const int opcodeGetPCRankExplicit = 0x2000f; const int opcodeModDisposition = 0x200014d; From 30666f2cce17357336b70507ef9428dd4e433f77 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 26 Apr 2014 13:42:32 +0200 Subject: [PATCH 050/118] Fixes #1297: Store global map markers in savegame --- apps/openmw/mwgui/mapwindow.cpp | 37 ++++++-- apps/openmw/mwgui/mapwindow.hpp | 3 + apps/openmw/mwgui/windowmanagerimp.cpp | 2 +- apps/openmw/mwrender/globalmap.cpp | 126 ++++++++++--------------- apps/openmw/mwrender/globalmap.hpp | 7 +- components/esm/globalmap.cpp | 17 ++++ components/esm/globalmap.hpp | 3 + 7 files changed, 104 insertions(+), 91 deletions(-) diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index 1cc9610df..aa48631e4 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -14,6 +14,8 @@ #include "../mwrender/globalmap.hpp" +#include "../components/esm/globalmap.hpp" + #include "widgets.hpp" namespace MWGui @@ -436,7 +438,6 @@ namespace MWGui worldY * mGlobalMapRender->getHeight()+6, 12, 12); - static int _counter=0; MyGUI::Button* markerWidget = mGlobalMapOverlay->createWidget("ButtonImage", widgetCoord, MyGUI::Align::Default, "Door" + boost::lexical_cast(_counter)); @@ -452,6 +453,11 @@ namespace MWGui markerWidget->setUserString("ToolTipType", "Layout"); markerWidget->setUserString("ToolTipLayout", "TextToolTipOneLine"); markerWidget->setUserString("Caption_TextOneLine", name); + + CellId cell; + cell.first = x; + cell.second = y; + mMarkers.push_back(cell); } void MapWindow::cellExplored(int x, int y) @@ -580,6 +586,7 @@ namespace MWGui void MapWindow::clear() { + mMarkers.clear(); mGlobalMapRender->clear(); while (mEventBoxGlobal->getChildCount()) @@ -590,19 +597,31 @@ namespace MWGui void MapWindow::write(ESM::ESMWriter &writer) { - mGlobalMapRender->write(writer); + ESM::GlobalMap map; + mGlobalMapRender->write(map); + + map.mMarkers = mMarkers; + + writer.startRecord(ESM::REC_GMAP); + map.save(writer); + writer.endRecord(ESM::REC_GMAP); } void MapWindow::readRecord(ESM::ESMReader &reader, int32_t type) { - std::vector > exploredCells; - mGlobalMapRender->readRecord(reader, type, exploredCells); - - for (std::vector >::iterator it = exploredCells.begin(); it != exploredCells.end(); ++it) + if (type == ESM::REC_GMAP) { - const ESM::Cell* cell = MWBase::Environment::get().getWorld()->getStore().get().search(it->first, it->second); - if (cell && !cell->mName.empty()) - addVisitedLocation(cell->mName, it->first, it->second); + ESM::GlobalMap map; + map.load(reader); + + mGlobalMapRender->read(map); + + for (std::vector::iterator it = map.mMarkers.begin(); it != map.mMarkers.end(); ++it) + { + const ESM::Cell* cell = MWBase::Environment::get().getWorld()->getStore().get().search(it->first, it->second); + if (cell && !cell->mName.empty()) + addVisitedLocation(cell->mName, it->first, it->second); + } } } } diff --git a/apps/openmw/mwgui/mapwindow.hpp b/apps/openmw/mwgui/mapwindow.hpp index 249477551..0b549147c 100644 --- a/apps/openmw/mwgui/mapwindow.hpp +++ b/apps/openmw/mwgui/mapwindow.hpp @@ -55,6 +55,9 @@ namespace MWGui bool mChanged; bool mFogOfWar; + typedef std::pair CellId; + std::vector mMarkers; + std::vector mMapWidgets; std::vector mFogWidgets; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 2b9840876..0457fcb59 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -187,7 +187,7 @@ namespace MWGui MyGUI::InputManager::getInstance().eventChangeKeyFocus += MyGUI::newDelegate(this, &WindowManager::onKeyFocusChanged); onCursorChange(MyGUI::PointerManager::getInstance().getDefaultPointer()); - SDL_ShowCursor(false); + //SDL_ShowCursor(false); mCursorManager->setEnabled(true); diff --git a/apps/openmw/mwrender/globalmap.cpp b/apps/openmw/mwrender/globalmap.cpp index 76ad1890f..0537ed516 100644 --- a/apps/openmw/mwrender/globalmap.cpp +++ b/apps/openmw/mwrender/globalmap.cpp @@ -231,9 +231,8 @@ namespace MWRender mOverlayTexture->getBuffer()->blitFromMemory(pb); } - void GlobalMap::write(ESM::ESMWriter &writer) + void GlobalMap::write(ESM::GlobalMap& map) { - ESM::GlobalMap map; map.mBounds.mMinX = mMinX; map.mBounds.mMaxX = mMaxX; map.mBounds.mMinY = mMinY; @@ -244,95 +243,68 @@ namespace MWRender Ogre::DataStreamPtr encoded = image.encode("png"); map.mImageData.resize(encoded->size()); encoded->read(&map.mImageData[0], encoded->size()); - - writer.startRecord(ESM::REC_GMAP); - map.save(writer); - writer.endRecord(ESM::REC_GMAP); } - void GlobalMap::readRecord(ESM::ESMReader &reader, int32_t type, std::vector >& exploredCells) + void GlobalMap::read(ESM::GlobalMap& map) { - if (type == ESM::REC_GMAP) - { - ESM::GlobalMap map; - map.load(reader); + const ESM::GlobalMap::Bounds& bounds = map.mBounds; - const ESM::GlobalMap::Bounds& bounds = map.mBounds; + if (bounds.mMaxX-bounds.mMinX <= 0) + return; + if (bounds.mMaxY-bounds.mMinY <= 0) + return; - if (bounds.mMaxX-bounds.mMinX <= 0) - return; - if (bounds.mMaxY-bounds.mMinY <= 0) - return; + if (bounds.mMinX > bounds.mMaxX + || bounds.mMinY > bounds.mMaxY) + throw std::runtime_error("invalid map bounds"); - if (bounds.mMinX > bounds.mMaxX - || bounds.mMinY > bounds.mMaxY) - throw std::runtime_error("invalid map bounds"); + Ogre::Image image; + Ogre::DataStreamPtr stream(new Ogre::MemoryDataStream(&map.mImageData[0], map.mImageData.size())); + image.load(stream, "png"); - Ogre::Image image; - Ogre::DataStreamPtr stream(new Ogre::MemoryDataStream(&map.mImageData[0], map.mImageData.size())); - image.load(stream, "png"); + int xLength = (bounds.mMaxX-bounds.mMinX+1); + int yLength = (bounds.mMaxY-bounds.mMinY+1); - int xLength = (bounds.mMaxX-bounds.mMinX+1); - int yLength = (bounds.mMaxY-bounds.mMinY+1); + // Size of one cell in image space + int cellImageSizeSrc = image.getWidth() / xLength; + if (int(image.getHeight() / yLength) != cellImageSizeSrc) + throw std::runtime_error("cell size must be quadratic"); - // Size of one cell in image space - int cellImageSizeSrc = image.getWidth() / xLength; - if (int(image.getHeight() / yLength) != cellImageSizeSrc) - throw std::runtime_error("cell size must be quadratic"); + // If cell bounds of the currently loaded content and the loaded savegame do not match, + // we need to resize source/dest boxes to accommodate + // This means nonexisting cells will be dropped silently + int cellImageSizeDst = 24; - // Determine which cells were explored by reading the image data - for (int x=0; x < xLength; ++x) - { - for (int y=0; y < yLength; ++y) - { - unsigned int imageX = (x) * cellImageSizeSrc; - // NB y + 1, because we want the top left corner, not bottom left where the origin of the cell is - unsigned int imageY = (yLength - (y + 1)) * cellImageSizeSrc; + // Completely off-screen? -> no need to blit anything + if (bounds.mMaxX < mMinX + || bounds.mMaxY < mMinY + || bounds.mMinX > mMaxX + || bounds.mMinY > mMaxY) + return; - assert(imageX < image.getWidth()); - assert(imageY < image.getHeight()); + int leftDiff = (mMinX - bounds.mMinX); + int topDiff = (bounds.mMaxY - mMaxY); + int rightDiff = (bounds.mMaxX - mMaxX); + int bottomDiff = (mMinY - bounds.mMinY); + Ogre::Image::Box srcBox ( std::max(0, leftDiff * cellImageSizeSrc), + std::max(0, topDiff * cellImageSizeSrc), + std::min(image.getWidth(), image.getWidth() - rightDiff * cellImageSizeSrc), + std::min(image.getHeight(), image.getHeight() - bottomDiff * cellImageSizeSrc)); - if (image.getColourAt(imageX, imageY, 0).a > 0) - exploredCells.push_back(std::make_pair(x+bounds.mMinX,y+bounds.mMinY)); - } - } + Ogre::Image::Box destBox ( std::max(0, -leftDiff * cellImageSizeDst), + std::max(0, -topDiff * cellImageSizeDst), + std::min(mOverlayTexture->getWidth(), mOverlayTexture->getWidth() + rightDiff * cellImageSizeDst), + std::min(mOverlayTexture->getHeight(), mOverlayTexture->getHeight() + bottomDiff * cellImageSizeDst)); - // If cell bounds of the currently loaded content and the loaded savegame do not match, - // we need to resize source/dest boxes to accommodate - // This means nonexisting cells will be dropped silently - int cellImageSizeDst = 24; + // Looks like there is no interface for blitting from memory with src/dst boxes. + // So we create a temporary texture for blitting. + Ogre::TexturePtr tex = Ogre::TextureManager::getSingleton().createManual("@temp", + Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, Ogre::TEX_TYPE_2D, image.getWidth(), + image.getHeight(), 0, Ogre::PF_A8B8G8R8); + tex->loadImage(image); - // Completely off-screen? -> no need to blit anything - if (bounds.mMaxX < mMinX - || bounds.mMaxY < mMinY - || bounds.mMinX > mMaxX - || bounds.mMinY > mMaxY) - return; + mOverlayTexture->getBuffer()->blit(tex->getBuffer(), srcBox, destBox); - int leftDiff = (mMinX - bounds.mMinX); - int topDiff = (bounds.mMaxY - mMaxY); - int rightDiff = (bounds.mMaxX - mMaxX); - int bottomDiff = (mMinY - bounds.mMinY); - Ogre::Image::Box srcBox ( std::max(0, leftDiff * cellImageSizeSrc), - std::max(0, topDiff * cellImageSizeSrc), - std::min(image.getWidth(), image.getWidth() - rightDiff * cellImageSizeSrc), - std::min(image.getHeight(), image.getHeight() - bottomDiff * cellImageSizeSrc)); - - Ogre::Image::Box destBox ( std::max(0, -leftDiff * cellImageSizeDst), - std::max(0, -topDiff * cellImageSizeDst), - std::min(mOverlayTexture->getWidth(), mOverlayTexture->getWidth() + rightDiff * cellImageSizeDst), - std::min(mOverlayTexture->getHeight(), mOverlayTexture->getHeight() + bottomDiff * cellImageSizeDst)); - - // Looks like there is no interface for blitting from memory with src/dst boxes. - // So we create a temporary texture for blitting. - Ogre::TexturePtr tex = Ogre::TextureManager::getSingleton().createManual("@temp", - Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, Ogre::TEX_TYPE_2D, image.getWidth(), - image.getHeight(), 0, Ogre::PF_A8B8G8R8); - tex->loadImage(image); - - mOverlayTexture->getBuffer()->blit(tex->getBuffer(), srcBox, destBox); - - Ogre::TextureManager::getSingleton().remove("@temp"); - } + Ogre::TextureManager::getSingleton().remove("@temp"); } } diff --git a/apps/openmw/mwrender/globalmap.hpp b/apps/openmw/mwrender/globalmap.hpp index 5fe878cd4..6075d042e 100644 --- a/apps/openmw/mwrender/globalmap.hpp +++ b/apps/openmw/mwrender/globalmap.hpp @@ -12,8 +12,7 @@ namespace Loading namespace ESM { - class ESMWriter; - class ESMReader; + class GlobalMap; } namespace MWRender @@ -40,8 +39,8 @@ namespace MWRender /// Clears the overlay void clear(); - void write (ESM::ESMWriter& writer); - void readRecord (ESM::ESMReader& reader, int32_t type, std::vector >& exploredCells); + void write (ESM::GlobalMap& map); + void read (ESM::GlobalMap& map); private: std::string mCacheDir; diff --git a/components/esm/globalmap.cpp b/components/esm/globalmap.cpp index 1fa5f907e..f17c071ff 100644 --- a/components/esm/globalmap.cpp +++ b/components/esm/globalmap.cpp @@ -14,6 +14,15 @@ void ESM::GlobalMap::load (ESMReader &esm) esm.getSubHeader(); mImageData.resize(esm.getSubSize()); esm.getExact(&mImageData[0], mImageData.size()); + + while (esm.isNextSub("MRK_")) + { + esm.getSubHeader(); + CellId cell; + esm.getT(cell.first); + esm.getT(cell.second); + mMarkers.push_back(cell); + } } void ESM::GlobalMap::save (ESMWriter &esm) const @@ -23,4 +32,12 @@ void ESM::GlobalMap::save (ESMWriter &esm) const esm.startSubRecord("DATA"); esm.write(&mImageData[0], mImageData.size()); esm.endRecord("DATA"); + + for (std::vector::const_iterator it = mMarkers.begin(); it != mMarkers.end(); ++it) + { + esm.startSubRecord("MRK_"); + esm.writeT(it->first); + esm.writeT(it->second); + esm.endRecord("MRK_"); + } } diff --git a/components/esm/globalmap.hpp b/components/esm/globalmap.hpp index 5d036c736..158f70a6e 100644 --- a/components/esm/globalmap.hpp +++ b/components/esm/globalmap.hpp @@ -25,6 +25,9 @@ namespace ESM std::vector mImageData; + typedef std::pair CellId; + std::vector mMarkers; + void load (ESMReader &esm); void save (ESMWriter &esm) const; }; From afe624bd07822ca9ee9fd6ba120c9036b4ffe743 Mon Sep 17 00:00:00 2001 From: Jeffrey Haines Date: Sat, 26 Apr 2014 08:12:57 -0400 Subject: [PATCH 051/118] Cleaned up update in Actors.cpp Removed unnecessary for loops --- apps/openmw/mwmechanics/actors.cpp | 35 +++++++++--------------------- 1 file changed, 10 insertions(+), 25 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index ca37b152c..267170214 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -852,39 +852,29 @@ namespace MWMechanics // Note, the new hit object for this frame may be set by CharacterController::update -> Animation::runAnimation // (below) iter->first.getClass().getCreatureStats(iter->first).setLastHitObject(std::string()); - } - // AI and magic effects update - for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter) - { + // AI and magic effects update if (!iter->first.getClass().getCreatureStats(iter->first).isDead()) { updateActor(iter->first, duration); if(iter->first.getTypeName() == typeid(ESM::NPC).name()) updateNpc(iter->first, duration, paused); } - } - // Looping magic VFX update - // Note: we need to do this before any of the animations are updated. - // Reaching the text keys may trigger Hit / Spellcast (and as such, particles), - // so updating VFX immediately after that would just remove the particle effects instantly. - // There needs to be a magic effect update in between. - for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter) + // Looping magic VFX update + // Note: we need to do this before any of the animations are updated. + // Reaching the text keys may trigger Hit / Spellcast (and as such, particles), + // so updating VFX immediately after that would just remove the particle effects instantly. + // There needs to be a magic effect update in between. iter->second->updateContinuousVfx(); - // Animation/movement update - for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter) - { + // Animation/movement update if (iter->first.getClass().getCreatureStats(iter->first).getMagicEffects().get( ESM::MagicEffect::Paralyze).mMagnitude > 0) iter->second->skipAnim(); iter->second->update(duration); - } - // Kill dead actors - for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();iter++) - { + // Kill dead actors const MWWorld::Class &cls = MWWorld::Class::get(iter->first); CreatureStats &stats = cls.getCreatureStats(iter->first); @@ -912,13 +902,8 @@ namespace MWMechanics continue; } - // Make sure spell effects with CasterLinked flag are removed - // TODO: would be nice not to do this all the time... - for(PtrControllerMap::iterator iter2(mActors.begin());iter2 != mActors.end();++iter2) - { - MWMechanics::ActiveSpells& spells = iter2->first.getClass().getCreatureStats(iter2->first).getActiveSpells(); - spells.purge(iter->first.getRefData().getHandle()); - } + MWMechanics::ActiveSpells& spells = iter2->first.getClass().getCreatureStats(iter2->first).getActiveSpells(); + spells.purge(iter->first.getRefData().getHandle()); // FIXME: see http://bugs.openmw.org/issues/869 MWBase::Environment::get().getWorld()->enableActorCollision(iter->first, false); From 48b2c0073b1dceecb940eed8e54ff061833bc773 Mon Sep 17 00:00:00 2001 From: Jeffrey Haines Date: Sat, 26 Apr 2014 08:29:28 -0400 Subject: [PATCH 052/118] fix, sorry for being sloppy.. --- apps/openmw/mwmechanics/actors.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 267170214..a08cd9c33 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -845,7 +845,7 @@ namespace MWMechanics { if(!paused) { - // Reset data from previous frame + // Update actors from previous frame for (PtrControllerMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter) { // Reset last hit object, which is only valid for one frame @@ -902,7 +902,7 @@ namespace MWMechanics continue; } - MWMechanics::ActiveSpells& spells = iter2->first.getClass().getCreatureStats(iter2->first).getActiveSpells(); + MWMechanics::ActiveSpells& spells = iter->first.getClass().getCreatureStats(iter->first).getActiveSpells(); spells.purge(iter->first.getRefData().getHandle()); // FIXME: see http://bugs.openmw.org/issues/869 From d5dd864404c783464cb089ba9eeca8d1b48eb6ea Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 26 Apr 2014 14:33:45 +0200 Subject: [PATCH 053/118] Fixes #1236: Disable all controls while playing movie --- apps/openmw/mwinput/inputmanagerimp.cpp | 15 +++++++++------ apps/openmw/mwinput/inputmanagerimp.hpp | 4 +++- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 42362fde7..8095b0d05 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -114,6 +114,7 @@ namespace MWInput , mTimeIdle(0.f) , mOverencumberedMessageDelay(0.f) , mAlwaysRunActive(false) + , mControlsDisabled(false) { Ogre::RenderWindow* window = ogre.getWindow (); @@ -265,19 +266,20 @@ namespace MWInput void InputManager::update(float dt, bool disableControls, bool disableEvents) { + mControlsDisabled = disableControls; + mInputManager->setMouseVisible(MWBase::Environment::get().getWindowManager()->getCursorVisible()); mInputManager->capture(disableEvents); // inject some fake mouse movement to force updating MyGUI's widget states MyGUI::InputManager::getInstance().injectMouseMove( int(mMouseX), int(mMouseY), mMouseWheel); - // update values of channels (as a result of pressed keys) - if (!disableControls) - mInputBinder->update(dt); - - if (disableControls) + if (mControlsDisabled) return; + // update values of channels (as a result of pressed keys) + mInputBinder->update(dt); + bool grab = !MWBase::Environment::get().getWindowManager()->containsMode(MWGui::GM_MainMenu) && MWBase::Environment::get().getWindowManager()->getMode() != MWGui::GM_Console; @@ -509,7 +511,8 @@ namespace MWInput } } - mInputBinder->keyPressed (arg); + if (!mControlsDisabled) + mInputBinder->keyPressed (arg); OIS::KeyCode kc = mInputManager->sdl2OISKeyCode(arg.keysym.sym); diff --git a/apps/openmw/mwinput/inputmanagerimp.hpp b/apps/openmw/mwinput/inputmanagerimp.hpp index 5eb355566..3787a9c07 100644 --- a/apps/openmw/mwinput/inputmanagerimp.hpp +++ b/apps/openmw/mwinput/inputmanagerimp.hpp @@ -68,7 +68,7 @@ namespace MWInput /// Clear all savegame-specific data virtual void clear(); - virtual void update(float dt, bool disableControls, bool disableEvents=false); + virtual void update(float dt, bool disableControls=false, bool disableEvents=false); void setPlayer (MWWorld::Player* player) { mPlayer = player; } @@ -145,6 +145,8 @@ namespace MWInput bool mInvertY; + bool mControlsDisabled; + float mCameraSensitivity; float mUISensitivity; float mCameraYMultiplier; From f0c5d1a7e1eba636e3b0baa9ead6d00e70b059b3 Mon Sep 17 00:00:00 2001 From: Jeffrey Haines Date: Sat, 26 Apr 2014 10:03:56 -0400 Subject: [PATCH 054/118] Revert "Checks the state of the passed sneak variable" This reverts commit 4a4c08946c5b75701a5eb9b3e878c0727380909d. --- apps/openmw/mwworld/player.cpp | 28 ++++++++++------------------ 1 file changed, 10 insertions(+), 18 deletions(-) diff --git a/apps/openmw/mwworld/player.cpp b/apps/openmw/mwworld/player.cpp index 8588547d2..f4ca5ee27 100644 --- a/apps/openmw/mwworld/player.cpp +++ b/apps/openmw/mwworld/player.cpp @@ -134,25 +134,17 @@ namespace MWWorld ptr.getClass().getCreatureStats(ptr).setMovementFlag(MWMechanics::CreatureStats::Flag_Sneak, sneak); - if (sneak == true) - { - const MWWorld::ESMStore& esmStore = MWBase::Environment::get().getWorld()->getStore(); + const MWWorld::ESMStore& esmStore = MWBase::Environment::get().getWorld()->getStore(); - // Find all the actors who might be able to see the player - std::vector neighbors; - MWBase::Environment::get().getMechanicsManager()->getActorsInRange( Ogre::Vector3(ptr.getRefData().getPosition().pos), - esmStore.get().find("fSneakUseDist")->getInt(), neighbors); - for (std::vector::iterator it = neighbors.begin(); it != neighbors.end(); ++it) - { - if ( MWBase::Environment::get().getMechanicsManager()->awarenessCheck(ptr, *it) ) - { - MWBase::Environment::get().getWindowManager()->setSneakVisibility(false); - break; - } - } - if (neighbors.size() == 0) - MWBase::Environment::get().getWindowManager()->setSneakVisibility(true); - } + // Find all the actors who might be able to see the player + std::vector neighbors; + MWBase::Environment::get().getMechanicsManager()->getActorsInRange( Ogre::Vector3(ptr.getRefData().getPosition().pos), + esmStore.get().find("fSneakUseDist")->getInt(), neighbors); + for (std::vector::iterator it = neighbors.begin(); it != neighbors.end(); ++it) + if ( MWBase::Environment::get().getMechanicsManager()->awarenessCheck(ptr, *it) ) + MWBase::Environment::get().getWindowManager()->setSneakVisibility(sneak); + if (!neighbors.size()) + MWBase::Environment::get().getWindowManager()->setSneakVisibility(sneak); } void Player::yaw(float yaw) From b28dfa94cd5b92f47d9adef8ee06d7a1908cc7a1 Mon Sep 17 00:00:00 2001 From: Jeffrey Haines Date: Sat, 26 Apr 2014 10:07:56 -0400 Subject: [PATCH 055/118] Revert 4a4c089..f0c5d1a This rolls back to commit 4a4c08946c5b75701a5eb9b3e878c0727380909d. --- apps/openmw/mwmechanics/actors.cpp | 37 +++++++++++++++++++++--------- apps/openmw/mwworld/player.cpp | 28 ++++++++++++++-------- 2 files changed, 44 insertions(+), 21 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index a08cd9c33..ca37b152c 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -845,36 +845,46 @@ namespace MWMechanics { if(!paused) { - // Update actors from previous frame + // Reset data from previous frame for (PtrControllerMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter) { // Reset last hit object, which is only valid for one frame // Note, the new hit object for this frame may be set by CharacterController::update -> Animation::runAnimation // (below) iter->first.getClass().getCreatureStats(iter->first).setLastHitObject(std::string()); + } - // AI and magic effects update + // AI and magic effects update + for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter) + { if (!iter->first.getClass().getCreatureStats(iter->first).isDead()) { updateActor(iter->first, duration); if(iter->first.getTypeName() == typeid(ESM::NPC).name()) updateNpc(iter->first, duration, paused); } + } - // Looping magic VFX update - // Note: we need to do this before any of the animations are updated. - // Reaching the text keys may trigger Hit / Spellcast (and as such, particles), - // so updating VFX immediately after that would just remove the particle effects instantly. - // There needs to be a magic effect update in between. + // Looping magic VFX update + // Note: we need to do this before any of the animations are updated. + // Reaching the text keys may trigger Hit / Spellcast (and as such, particles), + // so updating VFX immediately after that would just remove the particle effects instantly. + // There needs to be a magic effect update in between. + for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter) iter->second->updateContinuousVfx(); - // Animation/movement update + // Animation/movement update + for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter) + { if (iter->first.getClass().getCreatureStats(iter->first).getMagicEffects().get( ESM::MagicEffect::Paralyze).mMagnitude > 0) iter->second->skipAnim(); iter->second->update(duration); + } - // Kill dead actors + // Kill dead actors + for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();iter++) + { const MWWorld::Class &cls = MWWorld::Class::get(iter->first); CreatureStats &stats = cls.getCreatureStats(iter->first); @@ -902,8 +912,13 @@ namespace MWMechanics continue; } - MWMechanics::ActiveSpells& spells = iter->first.getClass().getCreatureStats(iter->first).getActiveSpells(); - spells.purge(iter->first.getRefData().getHandle()); + // Make sure spell effects with CasterLinked flag are removed + // TODO: would be nice not to do this all the time... + for(PtrControllerMap::iterator iter2(mActors.begin());iter2 != mActors.end();++iter2) + { + MWMechanics::ActiveSpells& spells = iter2->first.getClass().getCreatureStats(iter2->first).getActiveSpells(); + spells.purge(iter->first.getRefData().getHandle()); + } // FIXME: see http://bugs.openmw.org/issues/869 MWBase::Environment::get().getWorld()->enableActorCollision(iter->first, false); diff --git a/apps/openmw/mwworld/player.cpp b/apps/openmw/mwworld/player.cpp index f4ca5ee27..8588547d2 100644 --- a/apps/openmw/mwworld/player.cpp +++ b/apps/openmw/mwworld/player.cpp @@ -134,17 +134,25 @@ namespace MWWorld ptr.getClass().getCreatureStats(ptr).setMovementFlag(MWMechanics::CreatureStats::Flag_Sneak, sneak); - const MWWorld::ESMStore& esmStore = MWBase::Environment::get().getWorld()->getStore(); + if (sneak == true) + { + const MWWorld::ESMStore& esmStore = MWBase::Environment::get().getWorld()->getStore(); - // Find all the actors who might be able to see the player - std::vector neighbors; - MWBase::Environment::get().getMechanicsManager()->getActorsInRange( Ogre::Vector3(ptr.getRefData().getPosition().pos), - esmStore.get().find("fSneakUseDist")->getInt(), neighbors); - for (std::vector::iterator it = neighbors.begin(); it != neighbors.end(); ++it) - if ( MWBase::Environment::get().getMechanicsManager()->awarenessCheck(ptr, *it) ) - MWBase::Environment::get().getWindowManager()->setSneakVisibility(sneak); - if (!neighbors.size()) - MWBase::Environment::get().getWindowManager()->setSneakVisibility(sneak); + // Find all the actors who might be able to see the player + std::vector neighbors; + MWBase::Environment::get().getMechanicsManager()->getActorsInRange( Ogre::Vector3(ptr.getRefData().getPosition().pos), + esmStore.get().find("fSneakUseDist")->getInt(), neighbors); + for (std::vector::iterator it = neighbors.begin(); it != neighbors.end(); ++it) + { + if ( MWBase::Environment::get().getMechanicsManager()->awarenessCheck(ptr, *it) ) + { + MWBase::Environment::get().getWindowManager()->setSneakVisibility(false); + break; + } + } + if (neighbors.size() == 0) + MWBase::Environment::get().getWindowManager()->setSneakVisibility(true); + } } void Player::yaw(float yaw) From ab33e78b6799c8875d262048651787ee83a8f044 Mon Sep 17 00:00:00 2001 From: graffy76 Date: Sat, 26 Apr 2014 09:40:58 -0500 Subject: [PATCH 056/118] Added RangeView class files --- apps/opencs/CMakeLists.txt | 1 + apps/opencs/view/settings/booleanview.hpp | 2 +- apps/opencs/view/settings/rangeview.cpp | 91 +++++++++++++++++++++++ apps/opencs/view/settings/rangeview.hpp | 44 +++++++++++ 4 files changed, 137 insertions(+), 1 deletion(-) create mode 100644 apps/opencs/view/settings/rangeview.cpp create mode 100644 apps/opencs/view/settings/rangeview.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 8ab44243d..680c8f8b7 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -95,6 +95,7 @@ opencs_units (view/settings booleanview textview listview + rangeview resizeablestackedwidget ) diff --git a/apps/opencs/view/settings/booleanview.hpp b/apps/opencs/view/settings/booleanview.hpp index 52f9e05f1..55ef0bb08 100644 --- a/apps/opencs/view/settings/booleanview.hpp +++ b/apps/opencs/view/settings/booleanview.hpp @@ -1,5 +1,5 @@ #ifndef CSVSETTINGS_BOOLEANVIEW_HPP -#define CSVSETTINGS_BOOELANVIEW_HPP +#define CSVSETTINGS_BOOLEANVIEW_HPP #include #include diff --git a/apps/opencs/view/settings/rangeview.cpp b/apps/opencs/view/settings/rangeview.cpp new file mode 100644 index 000000000..411e12775 --- /dev/null +++ b/apps/opencs/view/settings/rangeview.cpp @@ -0,0 +1,91 @@ +#include +#include + +#include +#include +#include + +#include + +#include "rangeview.hpp" +#include "../../model/settings/setting.hpp" + +CSVSettings::RangeView::RangeView (CSMSettings::Setting *setting, + Page *parent) + : View (setting, parent) +{ + foreach (const QString &value, setting->declaredValues()) + { + QAbstractButton *button = 0; + + if (isMultiValue()) + button = new QCheckBox (value, this); + else + button = new QRadioButton (value, this); + + connect (button, SIGNAL (clicked (bool)), + this, SLOT (slotToggled (bool))); + + button->setObjectName (value); + + addWidget (button); + + mButtons[value] = button; + } +} + +void CSVSettings::RangeView::slotToggled (bool state) +{ + //test only for true to avoid multiple selection updates with radiobuttons + if (!isMultiValue() && !state) + return; + + QStringList values; + + foreach (QString key, mButtons.keys()) + { + if (mButtons.value(key)->isChecked()) + values.append (key); + } + setSelectedValues (values, false); + + View::updateView(); +} + +void CSVSettings::RangeView::updateView (bool signalUpdate) const +{ + + QStringList values = selectedValues(); + + foreach (const QString &buttonName, mButtons.keys()) + { + QAbstractButton *button = mButtons[buttonName]; + + //if the value is not found in the list, the widget is checked false + bool buttonValue = values.contains(buttonName); + + //skip if the butotn value will not change + if (button->isChecked() == buttonValue) + continue; + + //disable autoexclusive if it's enabled and we're setting + //the button value to false + bool switchExclusive = (!buttonValue && button->autoExclusive()); + + if (switchExclusive) + button->setAutoExclusive (false); + + button->setChecked (buttonValue); + + if (switchExclusive) + button->setAutoExclusive(true); + } + View::updateView (signalUpdate); +} + +CSVSettings::RangeView *CSVSettings::RangeViewFactory::createView + (CSMSettings::Setting *setting, + Page *parent) +{ + return new RangeView (setting, parent); +} diff --git a/apps/opencs/view/settings/rangeview.hpp b/apps/opencs/view/settings/rangeview.hpp new file mode 100644 index 000000000..1df0c7bd6 --- /dev/null +++ b/apps/opencs/view/settings/rangeview.hpp @@ -0,0 +1,44 @@ +#ifndef CSVSETTINGS_RANGEVIEW_HPP +#define CSVSETTINGS_RANGEVIEW_HPP + +#include +#include + +#include "view.hpp" +#include "../../model/settings/support.hpp" + +class QStringListModel; + +namespace CSVSettings +{ + class RangeView : public View + { + Q_OBJECT + + QMap mButtons; + + public: + explicit RangeView (CSMSettings::Setting *setting, + Page *parent); + + protected: + void updateView (bool signalUpdate = true) const; + + private slots: + void slotToggled (bool state); + }; + + class RangeViewFactory : public QObject, public IViewFactory + { + Q_OBJECT + + public: + explicit RangeViewFactory (QWidget *parent = 0) + : QObject (parent) + {} + + RangeView *createView (CSMSettings::Setting *setting, + Page *parent); + }; +} +#endif // CSVSETTINGS_RANGEVIEW_HPP From 04964595efb1d1ab55a68f49c43172aae54de16b Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 26 Apr 2014 16:44:20 +0200 Subject: [PATCH 057/118] Fixes #1270, Fixes #1201: Update active weapon/spell icons every frame --- apps/openmw/mwgui/quickkeysmenu.cpp | 1 - apps/openmw/mwgui/spellwindow.cpp | 1 - apps/openmw/mwmechanics/character.cpp | 4 ---- apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 13 +++++++++++++ apps/openmw/mwmechanics/spellcasting.cpp | 1 - apps/openmw/mwstate/statemanagerimp.cpp | 7 ------- apps/openmw/mwworld/inventorystore.cpp | 15 --------------- apps/openmw/mwworld/worldimp.cpp | 1 - 8 files changed, 13 insertions(+), 30 deletions(-) diff --git a/apps/openmw/mwgui/quickkeysmenu.cpp b/apps/openmw/mwgui/quickkeysmenu.cpp index 4c0faeac1..dc7226909 100644 --- a/apps/openmw/mwgui/quickkeysmenu.cpp +++ b/apps/openmw/mwgui/quickkeysmenu.cpp @@ -325,7 +325,6 @@ namespace MWGui } store.setSelectedEnchantItem(it); - MWBase::Environment::get().getWindowManager()->setSelectedEnchantItem(item); } } diff --git a/apps/openmw/mwgui/spellwindow.cpp b/apps/openmw/mwgui/spellwindow.cpp index b052739bd..a00c2480e 100644 --- a/apps/openmw/mwgui/spellwindow.cpp +++ b/apps/openmw/mwgui/spellwindow.cpp @@ -322,7 +322,6 @@ namespace MWGui } store.setSelectedEnchantItem(it); - MWBase::Environment::get().getWindowManager()->setSelectedEnchantItem(item); updateSpells(); } diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 93c789af1..4cabaee09 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -740,10 +740,6 @@ bool CharacterController::updateWeaponState() MWBase::Environment::get().getWindowManager()->messageBox(resultMessage); if(!resultSound.empty()) MWBase::Environment::get().getSoundManager()->playSound(resultSound, 1.0f, 1.0f); - - // Set again, just to update the charge bar - if(item.getRefData().getCount()) - MWBase::Environment::get().getWindowManager()->setSelectedWeapon(item); } else if (ammunition) { diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 2b1fdd365..ff9bacf7b 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -325,6 +325,19 @@ namespace MWMechanics winMgr->updateSkillArea(); winMgr->setValue("level", stats.getLevel()); + + // Update the equipped weapon icon + MWWorld::InventoryStore& inv = mWatched.getClass().getInventoryStore(mWatched); + MWWorld::ContainerStoreIterator weapon = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight); + if (weapon == inv.end()) + winMgr->unsetSelectedWeapon(); + else + winMgr->setSelectedWeapon(*weapon); + + // Update the selected spell icon + MWWorld::ContainerStoreIterator enchantItem = inv.getSelectedEnchantItem(); + if (enchantItem != inv.end()) + winMgr->setSelectedEnchantItem(*enchantItem); } if (mUpdatePlayer) diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 9a6cd6b89..21aee5b98 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -575,7 +575,6 @@ namespace MWMechanics { if (mCaster.getRefData().getHandle() == "player") { - MWBase::Environment::get().getWindowManager()->setSelectedEnchantItem(item); // Set again to show the modified charge mCaster.getClass().skillUsageSucceeded (mCaster, ESM::Skill::Enchant, 3); } } diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index 0b3f3438d..acf1cf3f2 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -335,13 +335,6 @@ void MWState::StateManager::loadGame (const Character *character, const Slot *sl MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getPlayerPtr(); - //Update the weapon icon in the hud with whatever the player is currently holding. - MWWorld::InventoryStore& invStore = ptr.getClass().getInventoryStore(ptr); - MWWorld::ContainerStoreIterator item = invStore.getSlot(MWWorld::InventoryStore::Slot_CarriedRight); - - if (item != invStore.end()) - MWBase::Environment::get().getWindowManager()->setSelectedWeapon(*item); - ESM::CellId cellId = ptr.getCell()->getCell()->getCellId(); MWBase::Environment::get().getWorld()->changeToCell (cellId, ptr.getRefData().getPosition()); diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index e00276293..9610171b2 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -8,7 +8,6 @@ #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" -#include "../mwbase/windowmanager.hpp" #include "../mwbase/mechanicsmanager.hpp" #include "../mwmechanics/npcstats.hpp" @@ -150,10 +149,6 @@ void MWWorld::InventoryStore::equip (int slot, const ContainerStoreIterator& ite fireEquipmentChangedEvent(); updateMagicEffects(actor); - - // Update HUD icon for player weapon - if (slot == MWWorld::InventoryStore::Slot_CarriedRight) - MWBase::Environment::get().getWindowManager()->setSelectedWeapon(*getSlot(slot)); } void MWWorld::InventoryStore::unequipAll(const MWWorld::Ptr& actor) @@ -494,7 +489,6 @@ int MWWorld::InventoryStore::remove(const Ptr& item, int count, const Ptr& actor && *mSelectedEnchantItem == item && actor.getRefData().getHandle() == "player") { mSelectedEnchantItem = end(); - MWBase::Environment::get().getWindowManager()->unsetSelectedSpell(); } updateRechargingItems(); @@ -532,18 +526,9 @@ MWWorld::ContainerStoreIterator MWWorld::InventoryStore::unequipSlot(int slot, c if (script != "") (*it).getRefData().getLocals().setVarByInt(script, "onpcequip", 0); - // Update HUD icon when removing player weapon or selected enchanted item. - // We have to check for both as the weapon could also be the enchanted item. - if (slot == MWWorld::InventoryStore::Slot_CarriedRight) - { - // weapon - MWBase::Environment::get().getWindowManager()->unsetSelectedWeapon(); - } if ((mSelectedEnchantItem != end()) && (mSelectedEnchantItem == it)) { - // enchanted item mSelectedEnchantItem = end(); - MWBase::Environment::get().getWindowManager()->unsetSelectedSpell(); } } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 87bdd2f9d..46bb4db58 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2056,7 +2056,6 @@ namespace MWWorld { // Update the GUI only when called on the player MWBase::WindowManager* windowManager = MWBase::Environment::get().getWindowManager(); - windowManager->unsetSelectedWeapon(); if (werewolf) { From dbe1307de0914d3eb6ecda03b59bf624366dca85 Mon Sep 17 00:00:00 2001 From: mrcheko Date: Sat, 26 Apr 2014 22:21:20 +0400 Subject: [PATCH 058/118] code refining + minor fixes --- apps/openmw/mwmechanics/aicombat.cpp | 35 ++++++++++++++-------------- apps/openmw/mwmechanics/steering.cpp | 26 +-------------------- 2 files changed, 18 insertions(+), 43 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index 8a3c23aef..fa7ef28a3 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -175,23 +175,23 @@ namespace MWMechanics mStrike = false; } - const MWWorld::Class &cls = actor.getClass(); + const MWWorld::Class &actorCls = actor.getClass(); const ESM::Weapon *weapon = NULL; MWMechanics::WeaponType weaptype; float weapRange, weapSpeed = 1.0f; - actor.getClass().getCreatureStats(actor).setMovementFlag(CreatureStats::Flag_Run, true); + actorCls.getCreatureStats(actor).setMovementFlag(CreatureStats::Flag_Run, true); // Get weapon characteristics - if (actor.getClass().hasInventoryStore(actor)) + if (actorCls.hasInventoryStore(actor)) { - MWMechanics::DrawState_ state = actor.getClass().getCreatureStats(actor).getDrawState(); + MWMechanics::DrawState_ state = actorCls.getCreatureStats(actor).getDrawState(); if (state == MWMechanics::DrawState_Spell || state == MWMechanics::DrawState_Nothing) - actor.getClass().getCreatureStats(actor).setDrawState(MWMechanics::DrawState_Weapon); + actorCls.getCreatureStats(actor).setDrawState(MWMechanics::DrawState_Weapon); //Get weapon speed and range MWWorld::ContainerStoreIterator weaponSlot = - MWMechanics::getActiveWeapon(cls.getCreatureStats(actor), cls.getInventoryStore(actor), &weaptype); + MWMechanics::getActiveWeapon(actorCls.getCreatureStats(actor), actorCls.getInventoryStore(actor), &weaptype); if (weaptype == WeapType_HandToHand) { @@ -216,7 +216,7 @@ namespace MWMechanics float rangeMelee; float rangeCloseUp; bool distantCombat = false; - if (weaptype==WeapType_BowAndArrow || weaptype==WeapType_Crossbow || weaptype==WeapType_Thrown) + if (weaptype == WeapType_BowAndArrow || weaptype == WeapType_Crossbow || weaptype == WeapType_Thrown) { rangeMelee = 1000; // TODO: should depend on archer skill rangeCloseUp = 0; // not needed in ranged combat @@ -236,15 +236,15 @@ namespace MWMechanics bool isStuck = false; float speed = 0.0f; - if(mMovement.mPosition[1] && (Ogre::Vector3(mLastPos.pos) - vActorPos).length() < (speed = cls.getSpeed(actor)) / 10.0f) + if(mMovement.mPosition[1] && (Ogre::Vector3(mLastPos.pos) - vActorPos).length() < (speed = actorCls.getSpeed(actor)) / 10.0f) isStuck = true; mLastPos = pos; // check if can move along z-axis bool canMoveByZ; - if(canMoveByZ = ((actor.getClass().isNpc() || actor.getClass().canSwim(actor)) && MWBase::Environment::get().getWorld()->isSwimming(actor)) - || (actor.getClass().canFly(actor) && MWBase::Environment::get().getWorld()->isFlying(actor))) + if(canMoveByZ = ((actorCls.isNpc() || actorCls.canSwim(actor)) && MWBase::Environment::get().getWorld()->isSwimming(actor)) + || (actorCls.canFly(actor) && MWBase::Environment::get().getWorld()->isFlying(actor))) { // determine vertical angle to target mMovement.mRotation[0] = getXAngleToDir(vDirToTarget, distToTarget); @@ -266,16 +266,15 @@ namespace MWMechanics //Melee: stop running and attack mMovement.mPosition[1] = 0; - // When attacking with a weapon, choose between slash, thrust or chop - if (mStrike && actor.getClass().hasInventoryStore(actor)) - chooseBestAttack(weapon, mMovement); + // set slash/thrust/chop attack + if (mStrike) chooseBestAttack(weapon, mMovement); if(mMovement.mPosition[0] || mMovement.mPosition[1]) { mTimerCombatMove = 0.1f + 0.1f * static_cast(rand())/RAND_MAX; mCombatMove = true; } - else if(actor.getClass().isNpc() && (!distantCombat || (distantCombat && rangeMelee/5))) + else if(actorCls.isNpc() && (!distantCombat || (distantCombat && distToTarget < rangeMelee/2))) { //apply sideway movement (kind of dodging) with some probability if(static_cast(rand())/RAND_MAX < 0.25) @@ -309,7 +308,7 @@ namespace MWMechanics || (Ogre::Vector3(mShortcutFailPos.pos) - vActorPos).length() >= PATHFIND_SHORTCUT_RETRY_DIST) && (inLOS = MWBase::Environment::get().getWorld()->getLOS(actor, mTarget))) { - if(speed == 0.0f) speed = cls.getSpeed(actor); + if(speed == 0.0f) speed = actorCls.getSpeed(actor); // maximum dist before pit/obstacle for actor to avoid them depending on his speed float maxAvoidDist = tReaction * speed + speed / MAX_VEL_ANGULAR.valueRadians() * 2; preferShortcut = checkWayIsClear(vActorPos, vTargetPos, distToTarget > maxAvoidDist*1.5? maxAvoidDist : maxAvoidDist/2); @@ -370,15 +369,15 @@ namespace MWMechanics mReadyToAttack = false; } - if(distToTarget > rangeMelee) + if(distToTarget > rangeMelee && !distantCombat) { //special run attack; it shouldn't affect melee combat tactics - if(actor.getClass().getMovementSettings(actor).mPosition[1] == 1) + if(actorCls.getMovementSettings(actor).mPosition[1] == 1) { //check if actor can overcome the distance = distToTarget - attackerWeapRange //less than in time of playing weapon anim from 'start' to 'hit' tags (t_swing) //then start attacking - float speed1 = cls.getSpeed(actor); + float speed1 = actorCls.getSpeed(actor); float speed2 = mTarget.getClass().getSpeed(mTarget); if(mTarget.getClass().getMovementSettings(mTarget).mPosition[0] == 0 && mTarget.getClass().getMovementSettings(mTarget).mPosition[1] == 0) diff --git a/apps/openmw/mwmechanics/steering.cpp b/apps/openmw/mwmechanics/steering.cpp index d10733b36..0a8a37ecb 100644 --- a/apps/openmw/mwmechanics/steering.cpp +++ b/apps/openmw/mwmechanics/steering.cpp @@ -41,31 +41,7 @@ bool smoothTurn(const MWWorld::Ptr& actor, Ogre::Radian targetAngle, int axis) bool zTurn(const MWWorld::Ptr& actor, Ogre::Radian targetAngle) { - Ogre::Radian currentAngle (actor.getRefData().getPosition().rot[2]); - Ogre::Radian diff (targetAngle - currentAngle); - if (diff >= Ogre::Degree(180)) - { - // Turning the other way would be a better idea - diff = diff-Ogre::Degree(360); - } - else if (diff <= Ogre::Degree(-180)) - { - diff = Ogre::Degree(360)-diff; - } - Ogre::Radian absDiff = Ogre::Math::Abs(diff); - - // The turning animation actually moves you slightly, so the angle will be wrong again. - // Use epsilon to prevent jerkiness. - const Ogre::Degree epsilon (0.5); - if (absDiff < epsilon) - return true; - - Ogre::Radian limit = MAX_VEL_ANGULAR * MWBase::Environment::get().getFrameDuration(); - if (absDiff > limit) - diff = Ogre::Math::Sign(diff) * limit; - - actor.getClass().getMovementSettings(actor).mRotation[2] = diff.valueRadians(); - return false; + return smoothTurn(actor, targetAngle, 2); } } From c2b692e124f0eb3079499d393cfc2a86bfa134ec Mon Sep 17 00:00:00 2001 From: Thomas Date: Sat, 26 Apr 2014 17:21:53 -0400 Subject: [PATCH 059/118] getActorsFollowing/Fighting no longer returns dead actors --- apps/openmw/mwmechanics/actors.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 804ec7a41..d51b02a15 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -1029,7 +1029,7 @@ namespace MWMechanics const MWWorld::Class &cls = MWWorld::Class::get(iter->first); CreatureStats &stats = cls.getCreatureStats(iter->first); - if(stats.getAiSequence().getTypeId() == AiPackage::TypeIdFollow) + if(stats.getAiSequence().getTypeId() == AiPackage::TypeIdFollow && !stats.isDead()) { MWMechanics::AiFollow* package = static_cast(stats.getAiSequence().getActivePackage()); if(package->getFollowedActor() == actor.getCellRef().mRefID) @@ -1051,7 +1051,7 @@ namespace MWMechanics const MWWorld::Class &cls = MWWorld::Class::get(*iter); CreatureStats &stats = cls.getCreatureStats(*iter); - if(stats.getAiSequence().getTypeId() == AiPackage::TypeIdCombat) + if(stats.getAiSequence().getTypeId() == AiPackage::TypeIdCombat && !stats.isDead()) { MWMechanics::AiCombat* package = static_cast(stats.getAiSequence().getActivePackage()); if(package->getTargetId() == actor.getCellRef().mRefID) From 1fb2c8d87bf505ccf003415e2fafcefb218e4688 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sat, 26 Apr 2014 19:47:47 +1000 Subject: [PATCH 060/118] NPC turning is less hacky but still not perfect. NPC's should walk away after a period of non-action by the player (vanilla behaviour) - not yet implemented. --- apps/openmw/mwmechanics/aiwander.cpp | 41 +++++++++++++++++----------- apps/openmw/mwmechanics/aiwander.hpp | 1 + 2 files changed, 26 insertions(+), 16 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index ad94be0eb..2d1fbdd78 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -1,6 +1,7 @@ #include "aiwander.hpp" #include +#include #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" @@ -211,7 +212,7 @@ namespace MWMechanics // Reduce the turning animation glitch by using a *HUGE* value of // epsilon... TODO: a proper fix might be in either the physics or the // animation subsystem - if (zTurn(actor, Ogre::Degree(mTargetAngle), Ogre::Degree(12))) + if (zTurn(actor, Ogre::Degree(mTargetAngle), Ogre::Degree(5))) mRotate = false; } @@ -333,18 +334,7 @@ namespace MWMechanics if(mChooseAction) { mPlayedIdle = 0; - unsigned short idleRoll = 0; - - for(unsigned int counter = 0; counter < mIdle.size(); counter++) - { - 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+2; - idleRoll = randSelect; - } - } + getRandomIdle(); // NOTE: sets mPlayedIdle with a random selection if(!mPlayedIdle && mDistance) { @@ -395,6 +385,8 @@ namespace MWMechanics mMoveNow = false; mWalking = false; mObstacleCheck.clear(); + mIdleNow = true; + getRandomIdle(); } if(!mRotate) @@ -402,11 +394,11 @@ namespace MWMechanics Ogre::Vector3 dir = playerPos - actorPos; float length = dir.length(); - // FIXME: horrible hack float faceAngle = Ogre::Radian(Ogre::Math::ACos(dir.y / length) * ((Ogre::Math::ASin(dir.x / length).valueRadians()>0)?1.0:-1.0)).valueDegrees(); + float actorAngle = actor.getRefData().getBaseNode()->getOrientation().getRoll().valueDegrees(); // an attempt at reducing the turning animation glitch - if(abs(faceAngle) > 10) + if(abs(abs(faceAngle) - abs(actorAngle)) >= 5) // TODO: is there a better way? { mTargetAngle = faceAngle; mRotate = true; @@ -432,7 +424,8 @@ namespace MWMechanics } // Check if idle animation finished - if(!checkIdle(actor, mPlayedIdle)) + // FIXME: don't stay forever + if(!checkIdle(actor, mPlayedIdle) && playerDistSqr > helloDistance*helloDistance) { mPlayedIdle = 0; mIdleNow = false; @@ -586,5 +579,21 @@ namespace MWMechanics else return false; } + + void AiWander::getRandomIdle() + { + unsigned short idleRoll = 0; + + for(unsigned int counter = 0; counter < mIdle.size(); counter++) + { + 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+2; + idleRoll = randSelect; + } + } + } } diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index fe14abeb6..35ecc83e0 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -26,6 +26,7 @@ namespace MWMechanics void stopWalking(const MWWorld::Ptr& actor); void playIdle(const MWWorld::Ptr& actor, unsigned short idleSelect); bool checkIdle(const MWWorld::Ptr& actor, unsigned short idleSelect); + void getRandomIdle(); int mDistance; // how far the actor can wander from the spawn point int mDuration; From e8210c92c688d527db9a24df475161fef259ac47 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 27 Apr 2014 04:27:26 +0200 Subject: [PATCH 061/118] Fixes #1240: Don't hardcode drowning time --- apps/openmw/mwbase/windowmanager.hpp | 5 +++-- apps/openmw/mwgui/hud.cpp | 4 ++-- apps/openmw/mwgui/hud.hpp | 5 +++-- apps/openmw/mwgui/windowmanagerimp.cpp | 4 ++-- apps/openmw/mwgui/windowmanagerimp.hpp | 5 +++-- apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 6 ++++-- 6 files changed, 17 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index e3bd428e2..eb84741c4 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -156,8 +156,9 @@ namespace MWBase virtual void setValue (const std::string& id, int value) = 0; /// Set time left for the player to start drowning (update the drowning bar) - /// @param time value from [0,20] - virtual void setDrowningTimeLeft (float time) =0; + /// @param time time left to start drowning + /// @param maxTime how long we can be underwater (in total) until drowning starts + virtual void setDrowningTimeLeft (float time, float maxTime) = 0; virtual void setPlayerClass (const ESM::Class &class_) = 0; ///< set current class of player diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index 02cc5c6a9..946259e10 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -203,9 +203,9 @@ namespace MWGui } } - void HUD::setDrowningTimeLeft(float time) + void HUD::setDrowningTimeLeft(float time, float maxTime) { - size_t progress = time/20.0*200.0; + size_t progress = time/maxTime*200.0; mDrowning->setProgressPosition(progress); bool isDrowning = (progress == 0); diff --git a/apps/openmw/mwgui/hud.hpp b/apps/openmw/mwgui/hud.hpp index 38535630f..973ac0745 100644 --- a/apps/openmw/mwgui/hud.hpp +++ b/apps/openmw/mwgui/hud.hpp @@ -22,8 +22,9 @@ namespace MWGui void setBatchCount(unsigned int count); /// Set time left for the player to start drowning - /// @param time value from [0,20] - void setDrowningTimeLeft(float time); + /// @param time time left to start drowning + /// @param maxTime how long we can be underwater (in total) until drowning starts + void setDrowningTimeLeft(float time, float maxTime); void setDrowningBarVisible(bool visible); void setHmsVisible(bool visible); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 0457fcb59..2ed113126 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -625,9 +625,9 @@ namespace MWGui mStatsWindow->setValue (id, value); } - void WindowManager::setDrowningTimeLeft (float time) + void WindowManager::setDrowningTimeLeft (float time, float maxTime) { - mHud->setDrowningTimeLeft(time); + mHud->setDrowningTimeLeft(time, maxTime); } void WindowManager::setPlayerClass (const ESM::Class &class_) diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index ab9770a41..074cb3208 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -166,8 +166,9 @@ namespace MWGui virtual void setValue (const std::string& id, int value); /// Set time left for the player to start drowning (update the drowning bar) - /// @param time value from [0,20] - virtual void setDrowningTimeLeft (float time); + /// @param time time left to start drowning + /// @param maxTime how long we can be underwater (in total) until drowning starts + virtual void setDrowningTimeLeft (float time, float maxTime); virtual void setPlayerClass (const ESM::Class &class_); ///< set current class of player virtual void configureSkills (const SkillList& major, const SkillList& minor); ///< configure skill groups, each set contains the skill ID for that group. diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index ff9bacf7b..34402977c 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -298,13 +298,15 @@ namespace MWMechanics if(stats.getTimeToStartDrowning() != mWatchedStats.getTimeToStartDrowning()) { + const float fHoldBreathTime = MWBase::Environment::get().getWorld()->getStore().get() + .find("fHoldBreathTime")->getFloat(); mWatchedStats.setTimeToStartDrowning(stats.getTimeToStartDrowning()); - if(stats.getTimeToStartDrowning() >= 20.0f) + if(stats.getTimeToStartDrowning() >= fHoldBreathTime) winMgr->setDrowningBarVisibility(false); else { winMgr->setDrowningBarVisibility(true); - winMgr->setDrowningTimeLeft(stats.getTimeToStartDrowning()); + winMgr->setDrowningTimeLeft(stats.getTimeToStartDrowning(), fHoldBreathTime); } } From 0d711e51b00463308d455510d8668322fec81099 Mon Sep 17 00:00:00 2001 From: graffy76 Date: Sat, 26 Apr 2014 21:32:36 -0500 Subject: [PATCH 062/118] Converted SettingType enums to indicate widget type. --- apps/opencs/model/settings/setting.cpp | 17 ++++++------ apps/opencs/model/settings/support.hpp | 29 +++++++++++++++------ apps/opencs/model/settings/usersettings.cpp | 18 ++++++------- apps/opencs/view/settings/page.cpp | 2 ++ apps/opencs/view/settings/rangeview.cpp | 4 +++ apps/opencs/view/settings/settingwindow.cpp | 12 +++++---- 6 files changed, 51 insertions(+), 31 deletions(-) diff --git a/apps/opencs/model/settings/setting.cpp b/apps/opencs/model/settings/setting.cpp index 6c7e78087..ca682b454 100644 --- a/apps/opencs/model/settings/setting.cpp +++ b/apps/opencs/model/settings/setting.cpp @@ -12,15 +12,14 @@ CSMSettings::Setting::Setting(SettingType typ, const QString &settingName, { buildDefaultSetting(); - int vType = static_cast (typ); + int settingType = static_cast (typ); - if ((vType % 2) == 0) - setProperty (Property_IsMultiValue, - QVariant(true).toString()); - else - vType--; + //even-numbered setting types are multi-valued + if ((settingType % 2) == 0) + setProperty (Property_IsMultiValue, QVariant(true).toString()); - setProperty (Property_ViewType, QVariant (vType / 2).toString()); + //view type is related to setting type by an order of magnitude + setProperty (Property_ViewType, QVariant (settingType / 10).toString()); setProperty (Property_Page, pageName); setProperty (Property_Name, settingName); setProperty (Property_DeclaredValues, values); @@ -267,9 +266,9 @@ void CSMSettings::Setting::setProperty (SettingProperty prop, QDataStream &operator <<(QDataStream &stream, const CSMSettings::Setting& setting) { - stream << setting.properties(); + // stream << setting.properties(); - stream << setting.proxies(); + // stream << setting.proxies(); return stream; } diff --git a/apps/opencs/model/settings/support.hpp b/apps/opencs/model/settings/support.hpp index abc86a0cb..ce808587f 100644 --- a/apps/opencs/model/settings/support.hpp +++ b/apps/opencs/model/settings/support.hpp @@ -47,14 +47,27 @@ namespace CSMSettings enum SettingType { - Type_MultiBool = 0, - Type_SingleBool = 1, - Type_MultiList = 2, - Type_SingleList = 3, - Type_MultiRange = 4, - Type_SingleRange = 5, - Type_MultiText = 6, - Type_SingleText = 7 + /* + * 0 - 9 - Boolean widgets + * 10-19 - List widgets + * 21-29 - Range widgets + * 31-39 - Text widgets + * + * Each range corresponds to a View_Type enum by a factor of 10. + * + * Even-numbered values are single-value widgets + * Odd-numbered values are multi-valued widgets + */ + + Type_CheckBox = 0, + Type_RadioButton = 1, + Type_ListView = 10, + Type_ComboBox = 11, + Type_SpinBox = 21, + Type_Slider = 23, + Type_Dial = 24, + Type_TextArea = 30, + Type_LineEdit = 31 }; enum MergeMethod diff --git a/apps/opencs/model/settings/usersettings.cpp b/apps/opencs/model/settings/usersettings.cpp index 808fbfc70..2f8e8098d 100644 --- a/apps/opencs/model/settings/usersettings.cpp +++ b/apps/opencs/model/settings/usersettings.cpp @@ -47,8 +47,8 @@ void CSMSettings::UserSettings::buildSettingModelDefaults() { QString section = "Window Size"; { - Setting *width = createSetting (Type_SingleText, section, "Width"); - Setting *height = createSetting (Type_SingleText, section, "Height"); + Setting *width = createSetting (Type_LineEdit, section, "Width"); + Setting *height = createSetting (Type_LineEdit, section, "Height"); width->setWidgetWidth (5); height->setWidgetWidth (5); @@ -65,7 +65,7 @@ void CSMSettings::UserSettings::buildSettingModelDefaults() /* *Create the proxy setting for predefined values */ - Setting *preDefined = createSetting (Type_SingleList, section, + Setting *preDefined = createSetting (Type_ComboBox, section, "Pre-Defined", QStringList() << "640 x 480" @@ -94,11 +94,11 @@ void CSMSettings::UserSettings::buildSettingModelDefaults() QStringList values = QStringList() << defaultValue << "Icon Only" << "Text Only"; - Setting *rsd = createSetting (Type_SingleBool, + Setting *rsd = createSetting (Type_RadioButton, section, "Record Status Display", values); - Setting *ritd = createSetting (Type_SingleBool, + Setting *ritd = createSetting (Type_RadioButton, section, "Referenceable ID Type Display", values); @@ -110,24 +110,24 @@ void CSMSettings::UserSettings::buildSettingModelDefaults() { //create three setting objects, specifying the basic widget type, //the setting view name, the page name, and the default value - Setting *masterBoolean = createSetting (Type_SingleBool, section, + Setting *masterBoolean = createSetting (Type_RadioButton, section, "Master Proxy", QStringList() << "Profile One" << "Profile Two" << "Profile Three" << "Profile Four" ); - Setting *slaveBoolean = createSetting (Type_MultiBool, section, + Setting *slaveBoolean = createSetting (Type_CheckBox, section, "Proxy Checkboxes", QStringList() << "One" << "Two" << "Three" << "Four" << "Five" ); - Setting *slaveSingleText = createSetting (Type_SingleText, section, + Setting *slaveSingleText = createSetting (Type_LineEdit, section, "Proxy TextBox 1" ); - Setting *slaveMultiText = createSetting (Type_SingleText, section, + Setting *slaveMultiText = createSetting (Type_LineEdit, section, "ProxyTextBox 2" ); diff --git a/apps/opencs/view/settings/page.cpp b/apps/opencs/view/settings/page.cpp index a5711c8f8..e67445873 100644 --- a/apps/opencs/view/settings/page.cpp +++ b/apps/opencs/view/settings/page.cpp @@ -3,6 +3,7 @@ #include "booleanview.hpp" #include "textview.hpp" #include "listview.hpp" +#include "rangeview.hpp" #include "../../model/settings/usersettings.hpp" #include "../../model/settings/connector.hpp" @@ -85,4 +86,5 @@ void CSVSettings::Page::buildFactories() mViewFactories[ViewType_Boolean] = new BooleanViewFactory (this); mViewFactories[ViewType_Text] = new TextViewFactory (this); mViewFactories[ViewType_List] = new ListViewFactory (this); + mViewFactories[ViewType_Range] = new RangeViewFactory (this); } diff --git a/apps/opencs/view/settings/rangeview.cpp b/apps/opencs/view/settings/rangeview.cpp index 411e12775..12b71d28f 100644 --- a/apps/opencs/view/settings/rangeview.cpp +++ b/apps/opencs/view/settings/rangeview.cpp @@ -10,6 +10,9 @@ #include "rangeview.hpp" #include "../../model/settings/setting.hpp" + +#include + CSVSettings::RangeView::RangeView (CSMSettings::Setting *setting, Page *parent) : View (setting, parent) @@ -87,5 +90,6 @@ CSVSettings::RangeView *CSVSettings::RangeViewFactory::createView (CSMSettings::Setting *setting, Page *parent) { + qDebug() << "adding a new range view"; return new RangeView (setting, parent); } diff --git a/apps/opencs/view/settings/settingwindow.cpp b/apps/opencs/view/settings/settingwindow.cpp index 9283bbf51..8eccee646 100644 --- a/apps/opencs/view/settings/settingwindow.cpp +++ b/apps/opencs/view/settings/settingwindow.cpp @@ -14,16 +14,18 @@ CSVSettings::SettingWindow::SettingWindow(QWidget *parent) void CSVSettings::SettingWindow::createPages() { + qDebug () << "getting page map"; CSMSettings::SettingPageMap pageMap = mModel->settingPageMap(); QList connectedSettings; - + qDebug () << "iterating map"; foreach (const QString &pageName, pageMap.keys()) - { + { + qDebug() << "iterating page: " << pageName; QList pageSettings = pageMap.value (pageName); - + qDebug () << "appending page: " << pageName << "; settings = " << pageSettings.size(); mPages.append (new Page (pageName, pageSettings, this)); - + qDebug() << "iterating page " << pageName << " settings"; for (int i = 0; i < pageSettings.size(); i++) { CSMSettings::Setting *setting = pageSettings.at(i); @@ -32,7 +34,7 @@ void CSVSettings::SettingWindow::createPages() connectedSettings.append (setting); } } - + qDebug() << "making connections"; if (!connectedSettings.isEmpty()) createConnections(connectedSettings); } From 985af15a12f2645c1fe47f25c67e460d2f4d39da Mon Sep 17 00:00:00 2001 From: graffy76 Date: Sat, 26 Apr 2014 21:43:42 -0500 Subject: [PATCH 063/118] removed qdebug references --- apps/opencs/view/settings/rangeview.cpp | 1 - apps/opencs/view/settings/settingwindow.cpp | 10 ++++------ 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/apps/opencs/view/settings/rangeview.cpp b/apps/opencs/view/settings/rangeview.cpp index 12b71d28f..2bb5863bc 100644 --- a/apps/opencs/view/settings/rangeview.cpp +++ b/apps/opencs/view/settings/rangeview.cpp @@ -90,6 +90,5 @@ CSVSettings::RangeView *CSVSettings::RangeViewFactory::createView (CSMSettings::Setting *setting, Page *parent) { - qDebug() << "adding a new range view"; return new RangeView (setting, parent); } diff --git a/apps/opencs/view/settings/settingwindow.cpp b/apps/opencs/view/settings/settingwindow.cpp index 8eccee646..7bd0b228e 100644 --- a/apps/opencs/view/settings/settingwindow.cpp +++ b/apps/opencs/view/settings/settingwindow.cpp @@ -14,18 +14,16 @@ CSVSettings::SettingWindow::SettingWindow(QWidget *parent) void CSVSettings::SettingWindow::createPages() { - qDebug () << "getting page map"; CSMSettings::SettingPageMap pageMap = mModel->settingPageMap(); QList connectedSettings; - qDebug () << "iterating map"; + foreach (const QString &pageName, pageMap.keys()) { - qDebug() << "iterating page: " << pageName; QList pageSettings = pageMap.value (pageName); - qDebug () << "appending page: " << pageName << "; settings = " << pageSettings.size(); + mPages.append (new Page (pageName, pageSettings, this)); - qDebug() << "iterating page " << pageName << " settings"; + for (int i = 0; i < pageSettings.size(); i++) { CSMSettings::Setting *setting = pageSettings.at(i); @@ -34,7 +32,7 @@ void CSVSettings::SettingWindow::createPages() connectedSettings.append (setting); } } - qDebug() << "making connections"; + if (!connectedSettings.isEmpty()) createConnections(connectedSettings); } From 93b76a603b5128ebd4da0787f6ea77bad2ccb0c9 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 27 Apr 2014 05:40:07 +0200 Subject: [PATCH 064/118] Fixes #1100: Looting a corpse is no longer considered stealing --- apps/openmw/mwgui/companionitemmodel.cpp | 4 ++-- apps/openmw/mwgui/companionitemmodel.hpp | 2 +- apps/openmw/mwgui/container.cpp | 13 ++++++++----- apps/openmw/mwgui/containeritemmodel.cpp | 2 +- apps/openmw/mwgui/containeritemmodel.hpp | 2 +- apps/openmw/mwgui/inventoryitemmodel.cpp | 18 ++++++++++++++++-- apps/openmw/mwgui/inventoryitemmodel.hpp | 5 ++++- apps/openmw/mwgui/itemmodel.cpp | 10 ++++++++-- apps/openmw/mwgui/itemmodel.hpp | 8 ++++++-- apps/openmw/mwgui/tradeitemmodel.cpp | 9 +++------ apps/openmw/mwworld/containerstore.cpp | 15 ++++++++++++--- 11 files changed, 62 insertions(+), 26 deletions(-) diff --git a/apps/openmw/mwgui/companionitemmodel.cpp b/apps/openmw/mwgui/companionitemmodel.cpp index bb6cf2800..9c4ea2d29 100644 --- a/apps/openmw/mwgui/companionitemmodel.cpp +++ b/apps/openmw/mwgui/companionitemmodel.cpp @@ -10,7 +10,7 @@ namespace MWGui { } - void CompanionItemModel::copyItem (const ItemStack& item, size_t count) + void CompanionItemModel::copyItem (const ItemStack& item, size_t count, bool setNewOwner=false) { if (mActor.getClass().isNpc()) { @@ -18,7 +18,7 @@ namespace MWGui stats.modifyProfit(MWWorld::Class::get(item.mBase).getValue(item.mBase) * count); } - InventoryItemModel::copyItem(item, count); + InventoryItemModel::copyItem(item, count, setNewOwner); } void CompanionItemModel::removeItem (const ItemStack& item, size_t count) diff --git a/apps/openmw/mwgui/companionitemmodel.hpp b/apps/openmw/mwgui/companionitemmodel.hpp index c11e11c32..49c58c896 100644 --- a/apps/openmw/mwgui/companionitemmodel.hpp +++ b/apps/openmw/mwgui/companionitemmodel.hpp @@ -13,7 +13,7 @@ namespace MWGui public: CompanionItemModel (const MWWorld::Ptr& actor); - virtual void copyItem (const ItemStack& item, size_t count); + virtual void copyItem (const ItemStack& item, size_t count, bool setNewOwner); virtual void removeItem (const ItemStack& item, size_t count); }; diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 34ac8d9f4..585647338 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -13,6 +13,7 @@ #include "../mwworld/containerstore.hpp" #include "../mwmechanics/pickpocket.hpp" +#include "../mwmechanics/creaturestats.hpp" #include "countdialog.hpp" #include "tradewindow.hpp" @@ -84,8 +85,7 @@ namespace MWGui // otherwise, do the transfer if (targetModel != mSourceModel) { - targetModel->copyItem(mItem, mDraggedCount); - mSourceModel->removeItem(mItem, mDraggedCount); + mSourceModel->moveItem(mItem, mDraggedCount, targetModel); } mSourceModel->update(); @@ -292,8 +292,7 @@ namespace MWGui if (!onTakeItem(item, item.mCount)) break; - playerModel->copyItem(item, item.mCount); - mModel->removeItem(item, item.mCount); + mModel->moveItem(item, item.mCount, playerModel); } MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Container); @@ -341,7 +340,11 @@ namespace MWGui } else { - MWBase::Environment::get().getMechanicsManager()->itemTaken(player, item.mBase, count); + // Looting a dead corpse is considered OK + if (mPtr.getClass().isActor() && mPtr.getClass().getCreatureStats(mPtr).isDead()) + return true; + else + MWBase::Environment::get().getMechanicsManager()->itemTaken(player, item.mBase, count); } return true; } diff --git a/apps/openmw/mwgui/containeritemmodel.cpp b/apps/openmw/mwgui/containeritemmodel.cpp index bcb8440bf..e702c073d 100644 --- a/apps/openmw/mwgui/containeritemmodel.cpp +++ b/apps/openmw/mwgui/containeritemmodel.cpp @@ -71,7 +71,7 @@ ItemModel::ModelIndex ContainerItemModel::getIndex (ItemStack item) return -1; } -void ContainerItemModel::copyItem (const ItemStack& item, size_t count) +void ContainerItemModel::copyItem (const ItemStack& item, size_t count, bool setNewOwner) { const MWWorld::Ptr& source = mItemSources[mItemSources.size()-1]; if (item.mBase.getContainerStore() == &source.getClass().getContainerStore(source)) diff --git a/apps/openmw/mwgui/containeritemmodel.hpp b/apps/openmw/mwgui/containeritemmodel.hpp index 22595582e..4b9b4ff99 100644 --- a/apps/openmw/mwgui/containeritemmodel.hpp +++ b/apps/openmw/mwgui/containeritemmodel.hpp @@ -21,7 +21,7 @@ namespace MWGui virtual ModelIndex getIndex (ItemStack item); virtual size_t getItemCount(); - virtual void copyItem (const ItemStack& item, size_t count); + virtual void copyItem (const ItemStack& item, size_t count, bool setNewOwner=false); virtual void removeItem (const ItemStack& item, size_t count); virtual void update(); diff --git a/apps/openmw/mwgui/inventoryitemmodel.cpp b/apps/openmw/mwgui/inventoryitemmodel.cpp index 97e1e9a2b..c0847929b 100644 --- a/apps/openmw/mwgui/inventoryitemmodel.cpp +++ b/apps/openmw/mwgui/inventoryitemmodel.cpp @@ -4,6 +4,8 @@ #include "../mwworld/class.hpp" #include "../mwworld/inventorystore.hpp" +#include "../mwmechanics/creaturestats.hpp" + namespace MWGui { @@ -38,11 +40,11 @@ ItemModel::ModelIndex InventoryItemModel::getIndex (ItemStack item) return -1; } -void InventoryItemModel::copyItem (const ItemStack& item, size_t count) +void InventoryItemModel::copyItem (const ItemStack& item, size_t count, bool setNewOwner) { if (item.mBase.getContainerStore() == &mActor.getClass().getContainerStore(mActor)) throw std::runtime_error("Item to copy needs to be from a different container!"); - mActor.getClass().getContainerStore(mActor).add(item.mBase, count, mActor); + mActor.getClass().getContainerStore(mActor).add(item.mBase, count, mActor, setNewOwner); } @@ -57,6 +59,18 @@ void InventoryItemModel::removeItem (const ItemStack& item, size_t count) throw std::runtime_error("Not enough items in the stack to remove"); } +void InventoryItemModel::moveItem(const ItemStack &item, size_t count, ItemModel *otherModel) +{ + bool setNewOwner = false; + + // Are you dead? Then you wont need that anymore + if (mActor.getClass().isActor() && mActor.getClass().getCreatureStats(mActor).isDead()) + setNewOwner = true; + + otherModel->copyItem(item, count, setNewOwner); + removeItem(item, count); +} + void InventoryItemModel::update() { MWWorld::ContainerStore& store = MWWorld::Class::get(mActor).getContainerStore(mActor); diff --git a/apps/openmw/mwgui/inventoryitemmodel.hpp b/apps/openmw/mwgui/inventoryitemmodel.hpp index 23856395e..78dcc9497 100644 --- a/apps/openmw/mwgui/inventoryitemmodel.hpp +++ b/apps/openmw/mwgui/inventoryitemmodel.hpp @@ -15,9 +15,12 @@ namespace MWGui virtual ModelIndex getIndex (ItemStack item); virtual size_t getItemCount(); - virtual void copyItem (const ItemStack& item, size_t count); + virtual void copyItem (const ItemStack& item, size_t count, bool setNewOwner=false); virtual void removeItem (const ItemStack& item, size_t count); + /// Move items from this model to \a otherModel. + virtual void moveItem (const ItemStack& item, size_t count, ItemModel* otherModel); + virtual void update(); protected: diff --git a/apps/openmw/mwgui/itemmodel.cpp b/apps/openmw/mwgui/itemmodel.cpp index 58e89c4fc..7b2ea4d4a 100644 --- a/apps/openmw/mwgui/itemmodel.cpp +++ b/apps/openmw/mwgui/itemmodel.cpp @@ -71,16 +71,22 @@ namespace MWGui { } + void ItemModel::moveItem(const ItemStack &item, size_t count, ItemModel *otherModel) + { + otherModel->copyItem(item, count); + removeItem(item, count); + } + ProxyItemModel::~ProxyItemModel() { delete mSourceModel; } - void ProxyItemModel::copyItem (const ItemStack& item, size_t count) + void ProxyItemModel::copyItem (const ItemStack& item, size_t count, bool setNewOwner) { // no need to use mapToSource since itemIndex refers to an index in the sourceModel - mSourceModel->copyItem (item, count); + mSourceModel->copyItem (item, count, setNewOwner); } void ProxyItemModel::removeItem (const ItemStack& item, size_t count) diff --git a/apps/openmw/mwgui/itemmodel.hpp b/apps/openmw/mwgui/itemmodel.hpp index 47aaf79e8..684771b86 100644 --- a/apps/openmw/mwgui/itemmodel.hpp +++ b/apps/openmw/mwgui/itemmodel.hpp @@ -55,7 +55,11 @@ namespace MWGui virtual void update() = 0; - virtual void copyItem (const ItemStack& item, size_t count) = 0; + /// Move items from this model to \a otherModel. + virtual void moveItem (const ItemStack& item, size_t count, ItemModel* otherModel); + + /// @param setNewOwner Set the copied item's owner to the actor we are copying to, or keep the original owner? + virtual void copyItem (const ItemStack& item, size_t count, bool setNewOwner=false) = 0; virtual void removeItem (const ItemStack& item, size_t count) = 0; private: @@ -69,7 +73,7 @@ namespace MWGui { public: virtual ~ProxyItemModel(); - virtual void copyItem (const ItemStack& item, size_t count); + virtual void copyItem (const ItemStack& item, size_t count, bool setNewOwner=false); virtual void removeItem (const ItemStack& item, size_t count); virtual ModelIndex getIndex (ItemStack item); diff --git a/apps/openmw/mwgui/tradeitemmodel.cpp b/apps/openmw/mwgui/tradeitemmodel.cpp index c9c65a152..ad18a13e8 100644 --- a/apps/openmw/mwgui/tradeitemmodel.cpp +++ b/apps/openmw/mwgui/tradeitemmodel.cpp @@ -120,14 +120,11 @@ namespace MWGui if (i == sourceModel->getItemCount()) throw std::runtime_error("The borrowed item disappeared"); - // reset owner before copying + // reset owner while copying, but only for items bought by the player + bool setNewOwner = (mMerchant.isEmpty()); const ItemStack& item = sourceModel->getItem(i); - std::string owner = item.mBase.getCellRef().mOwner; - if (mMerchant.isEmpty()) // only for items bought by player - item.mBase.getCellRef().mOwner = ""; // copy the borrowed items to our model - copyItem(item, it->mCount); - item.mBase.getCellRef().mOwner = owner; + copyItem(item, it->mCount, setNewOwner); // then remove them from the source model sourceModel->removeItem(item, it->mCount); } diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index bd0704724..dd2f2f3c1 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -199,16 +199,25 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::add (const Ptr& itemPtr item.getCellRef().mPos.pos[1] = 0; item.getCellRef().mPos.pos[2] = 0; + Ptr player = MWBase::Environment::get().getWorld ()->getPlayerPtr(); + if (setOwner && actorPtr.getClass().isActor()) - item.getCellRef().mOwner = actorPtr.getCellRef().mRefID; + { + if (actorPtr == player) + { + // No point in setting owner to the player - NPCs will not respect this anyway + // Additionally, setting it to "player" would make those items not stack with items that don't have an owner + item.getCellRef().mOwner = ""; + } + else + item.getCellRef().mOwner = actorPtr.getCellRef().mRefID; + } std::string script = MWWorld::Class::get(item).getScript(item); if(script != "") { CellStore *cell; - Ptr player = MWBase::Environment::get().getWorld ()->getPlayerPtr(); - if(&(MWWorld::Class::get (player).getContainerStore (player)) == this) { cell = 0; // Items in player's inventory have cell set to 0, so their scripts will never be removed From d92f95f5bf6f524bafb29a0435c658e4ac4c6c86 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 27 Apr 2014 05:54:19 +0200 Subject: [PATCH 065/118] Fix a stacking issue --- apps/openmw/mwworld/containerstore.cpp | 45 +++++++++++++++++--------- 1 file changed, 29 insertions(+), 16 deletions(-) diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index dd2f2f3c1..b1cbcc9c2 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -187,11 +187,38 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::add(const std::string & MWWorld::ContainerStoreIterator MWWorld::ContainerStore::add (const Ptr& itemPtr, int count, const Ptr& actorPtr, bool setOwner) { - MWWorld::ContainerStoreIterator it = addImp(itemPtr, count); + Ptr player = MWBase::Environment::get().getWorld ()->getPlayerPtr(); + + MWWorld::ContainerStoreIterator it = end(); + + if (setOwner && actorPtr.getClass().isActor()) + { + // HACK: Set owner on the original item, then reset it after we have copied it + // If we set the owner on the copied item, it would not stack correctly... + std::string oldOwner = itemPtr.getCellRef().mOwner; + if (actorPtr == player) + { + // No point in setting owner to the player - NPCs will not respect this anyway + // Additionally, setting it to "player" would make those items not stack with items that don't have an owner + itemPtr.getCellRef().mOwner = ""; + } + else + itemPtr.getCellRef().mOwner = actorPtr.getCellRef().mRefID; + + it = addImp(itemPtr, count); + + itemPtr.getCellRef().mOwner = oldOwner; + } + else + { + it = addImp(itemPtr, count); + } + + // The copy of the original item we just made MWWorld::Ptr item = *it; // we may have copied an item from the world, so reset a few things first - item.getRefData().setBaseNode(NULL); + item.getRefData().setBaseNode(NULL); // Especially important, otherwise scripts on the item could think that it's actually in a cell item.getCellRef().mPos.rot[0] = 0; item.getCellRef().mPos.rot[1] = 0; item.getCellRef().mPos.rot[2] = 0; @@ -199,20 +226,6 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::add (const Ptr& itemPtr item.getCellRef().mPos.pos[1] = 0; item.getCellRef().mPos.pos[2] = 0; - Ptr player = MWBase::Environment::get().getWorld ()->getPlayerPtr(); - - if (setOwner && actorPtr.getClass().isActor()) - { - if (actorPtr == player) - { - // No point in setting owner to the player - NPCs will not respect this anyway - // Additionally, setting it to "player" would make those items not stack with items that don't have an owner - item.getCellRef().mOwner = ""; - } - else - item.getCellRef().mOwner = actorPtr.getCellRef().mRefID; - } - std::string script = MWWorld::Class::get(item).getScript(item); if(script != "") { From dd14dec8dc3b82a89322cc46027d910c3916ff41 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 27 Apr 2014 08:16:35 +0200 Subject: [PATCH 066/118] Tweak loading screen progress bar positioning to match vanilla --- files/mygui/openmw_loading_screen.layout | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/files/mygui/openmw_loading_screen.layout b/files/mygui/openmw_loading_screen.layout index 19649cfd2..faa0d8637 100644 --- a/files/mygui/openmw_loading_screen.layout +++ b/files/mygui/openmw_loading_screen.layout @@ -4,13 +4,13 @@ - + - + - + From 14757a856b6077ab2f00f3fa2b94974efb776a9a Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 27 Apr 2014 08:17:14 +0200 Subject: [PATCH 067/118] Tweak settings window size and encumbrance bar text align --- files/mygui/openmw_settings_window.layout | 6 +++--- files/mygui/openmw_text.skin.xml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/files/mygui/openmw_settings_window.layout b/files/mygui/openmw_settings_window.layout index e348323be..bcf4374a4 100644 --- a/files/mygui/openmw_settings_window.layout +++ b/files/mygui/openmw_settings_window.layout @@ -3,10 +3,10 @@ - - + + - + diff --git a/files/mygui/openmw_text.skin.xml b/files/mygui/openmw_text.skin.xml index 15287bc74..d75abc873 100644 --- a/files/mygui/openmw_text.skin.xml +++ b/files/mygui/openmw_text.skin.xml @@ -152,7 +152,7 @@ - + From 3161647809b31c8e97802d6fe7a058084a4acd4b Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 27 Apr 2014 09:12:49 +0200 Subject: [PATCH 068/118] Fix for not being able to pick up scrolls during combat This is the behaviour I observed in vanilla morrowind. --- apps/openmw/mwworld/actionread.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/actionread.cpp b/apps/openmw/mwworld/actionread.cpp index 433237e26..60af3d9b9 100644 --- a/apps/openmw/mwworld/actionread.cpp +++ b/apps/openmw/mwworld/actionread.cpp @@ -3,7 +3,6 @@ #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" #include "../mwbase/world.hpp" -#include "../mwbase/world.hpp" #include "../mwworld/player.hpp" @@ -24,7 +23,12 @@ namespace MWWorld void ActionRead::executeImp (const MWWorld::Ptr& actor) { - if(MWBase::Environment::get().getWorld()->getPlayer().isInCombat()) { //Ensure we're not in combat + //Ensure we're not in combat + if(MWBase::Environment::get().getWorld()->getPlayer().isInCombat() + // Reading in combat is still allowed if the scroll/book is not in the player inventory yet + // (since otherwise, there would be no way to pick it up) + && getTarget().getContainerStore() == &actor.getClass().getContainerStore(actor) + ) { MWBase::Environment::get().getWindowManager()->messageBox("#{sInventoryMessage4}"); return; } From dac0b7090abc046a938f38de5597987455c8bdec Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 27 Apr 2014 09:14:14 +0200 Subject: [PATCH 069/118] Get rid of bigbars.png and smallbars.png Changed loading bar colour to match vanilla --- apps/openmw/mwgui/hud.cpp | 2 +- files/mygui/CMakeLists.txt | 2 - files/mygui/bigbars.png | Bin 387 -> 0 bytes files/mygui/openmw_hud.layout | 2 +- files/mygui/openmw_hud_energybar.skin.xml | 28 ++++++----- files/mygui/openmw_progress.skin.xml | 57 +++++++++++++--------- files/mygui/smallbars.png | Bin 2985 -> 0 bytes 7 files changed, 53 insertions(+), 38 deletions(-) delete mode 100644 files/mygui/bigbars.png delete mode 100644 files/mygui/smallbars.png diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index 946259e10..be4a9a14e 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -625,7 +625,7 @@ namespace MWGui if (mIsDrowning) { float intensity = (cos(mDrowningFlashTheta) + 1.0f) / 2.0f; - mDrowningFlash->setColour(MyGUI::Colour(intensity, intensity, intensity)); + mDrowningFlash->setColour(MyGUI::Colour(intensity, 0, 0)); } } diff --git a/files/mygui/CMakeLists.txt b/files/mygui/CMakeLists.txt index ef223a617..2135f4dde 100644 --- a/files/mygui/CMakeLists.txt +++ b/files/mygui/CMakeLists.txt @@ -4,7 +4,6 @@ set(SDIR ${CMAKE_CURRENT_SOURCE_DIR}) set(DDIR ${OpenMW_BINARY_DIR}/resources/mygui) set(MYGUI_FILES - bigbars.png black.png core.skin core.xml @@ -81,7 +80,6 @@ set(MYGUI_FILES openmw_companion_window.layout openmw_savegame_dialog.layout openmw_recharge_dialog.layout - smallbars.png DejaVuLGCSansMono.ttf markers.png ../launcher/images/openmw.png diff --git a/files/mygui/bigbars.png b/files/mygui/bigbars.png deleted file mode 100644 index ee91da19e3bc85b5601375d9e84fb45384da5ced..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 387 zcmV-}0et?6P)Px#32;bRa{vGf6951U69E94oEQKA00(qQO+^RU0tXKrA*QRh;Q#;u6-h)vR4C7N zl1)wnF${%2XN-{8vEl|uY&aALV8>}VBdAn`cJkxLqBD~e)GQ)>vg15I+uolaSdS;O z4xR{+j1Vb@0?xPZO7ygk(gv6Z_#7j-sl)L<7zq3n0&bJdA+IK&N*D&Xp!xQ zm%Cm72Q7U&ZUiI|`A|`Xb>+oiu2iT2p7=&^h=0hH)z$sw+v@{GnQNl3+)V8T! z-#p#FUf7FtZaXao0A?Qbv`*13P5fi;V0_I#qrLf>*DV8Plhih^C#ktCkfeaK>Mj&x h-3y1lAs1=a;TPg - + diff --git a/files/mygui/openmw_hud_energybar.skin.xml b/files/mygui/openmw_hud_energybar.skin.xml index f10908d7b..d5078e994 100644 --- a/files/mygui/openmw_hud_energybar.skin.xml +++ b/files/mygui/openmw_hud_energybar.skin.xml @@ -19,24 +19,28 @@ - - - + + + + - - - + + + + - - - + + + + - - - + + + + diff --git a/files/mygui/openmw_progress.skin.xml b/files/mygui/openmw_progress.skin.xml index f5418e3f8..a09011e10 100644 --- a/files/mygui/openmw_progress.skin.xml +++ b/files/mygui/openmw_progress.skin.xml @@ -2,35 +2,48 @@ - - - + + + + - - - + + + + - - - + + + + - - - + + + + + - - - + + + + + + + + + + + - + @@ -39,7 +52,7 @@ - + @@ -47,7 +60,7 @@ - + @@ -55,15 +68,15 @@ - + - - + + @@ -82,7 +95,7 @@ - + diff --git a/files/mygui/smallbars.png b/files/mygui/smallbars.png deleted file mode 100644 index 3c007a55cea32c99bbb4acb41e27419cc0290d49..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2985 zcmV;a3s&@rP)Oz@Z0f2-7z;ux~O9+4z06=<WDR*FRcSTFz- zW=q650N5=6FiBTtNC2?60Km==3$g$R3;-}uh=nNt1bYBr$Ri_o0EC$U6h`t_Jn<{8 z5a%iY0C<_QJh>z}MS)ugEpZ1|S1ukX&Pf+56gFW3VVXcL!g-k)GJ!M?;PcD?0HBc- z5#WRK{dmp}uFlRjj{U%*%WZ25jX z{P*?XzTzZ-GF^d31o+^>%=Ap99M6&ogks$0k4OBs3;+Bb(;~!4V!2o<6ys46agIcq zjPo+3B8fthDa9qy|77CdEc*jK-!%ZRYCZvbku9iQV*~a}ClFY4z~c7+0P?$U!PF=S z1Au6Q;m>#f??3%Vpd|o+W=WE9003S@Bra6Svp>fO002awfhw>;8}z{#EWidF!3EsG z3;bXU&9EIRU@z1_9W=mEXoiz;4lcq~xDGvV5BgyU zp1~-*fe8db$Osc*A=-!mVv1NJjtCc-h4>-CNCXm#Bp}I%6j35eku^v$Qi@a{RY)E3 zJ#qp$hg?Rwkvqr$GJ^buyhkyVfwECO)C{#lxu`c9ghrwZ&}4KmnvWKso6vH!8a<3Q zq36)6Xb;+tK10Vaz~~qUGsJ8#F2=(`u{bOVlVi)VBCHIn#u~6ztOL7=^<&SmcLWlF zMZgI*1b0FpVIDz9SWH+>*hr`#93(Um+6gxa1B6k+CnA%mOSC4s5&6UzVlpv@SV$}* z))J2sFA#f(L&P^E5{W}HC%KRUNwK6<(h|}}(r!{C=`5+6G)NjFlgZj-YqAG9lq?`C z$c5yc>d>VnA`E_*3F2Qp##d8RZb=H01_mm@+|Cqnc9PsG(F5HIG_C zt)aG3uTh7n6Et<2In9F>NlT@zqLtGcXcuVrX|L#Xx)I%#9!{6gSJKPrN9dR61N3(c z4Tcqi$B1Vr8Jidf7-t!G7_XR2rWwr)$3XQ?}=hpK0&Z&W{| zep&sA23f;Q!%st`QJ}G3cbou<7-yIK2z4nfCCCtN2-XOGSWo##{8Q{ATurxr~;I`ytDs%xbip}RzP zziy}Qn4Z2~fSycmr`~zJ=lUFdFa1>gZThG6M+{g7vkW8#+YHVaJjFF}Z#*3@$J_By zLtVo_L#1JrVVB{Ak-5=4qt!-@Mh}c>#$4kh<88)m#-k<%CLtzEP3leVno>={htGUuD;o7bD)w_sX$S}eAxwzy?UvgBH(S?;#HZiQMoS*2K2 zT3xe7t(~nU*1N5{rxB;QPLocnp4Ml>u<^FZwyC!nu;thW+pe~4wtZn|Vi#w(#jeBd zlf9FDx_yoPJqHbk*$%56S{;6Kv~mM9!g3B(KJ}#RZ#@)!hR|78Dq|Iq-afF%KE1Brn_fm;Im z_u$xr8UFki1L{Ox>G0o)(&RAZ;=|I=wN2l97;cLaHH6leTB-XXa*h%dBOEvi`+x zi?=Txl?TadvyiL>SuF~-LZ;|cS}4~l2eM~nS7yJ>iOM;atDY;(?aZ^v+mJV$@1Ote z62cPUlD4IWOIIx&SmwQ~YB{nzae3Pc;}r!fhE@iwJh+OsDs9zItL;~pu715HdQEGA zUct(O!LkCy1<%NCg+}G`0PgpNm-?d@-hMgNe6^V+j6x$b<6@S<$+<4_1hi}Ti zncS4LsjI}fWY1>OX6feMEuLErma3QLmkw?X+1j)X-&VBk_4Y;EFPF_I+q;9dL%E~B zJh;4Nr^(LEJ3myURP{Rblsw%57T)g973R8o)DE9*xN#~;4_o$q%o z4K@u`jhx2fBXC4{U8Qn{*%*B$Ge=nny$HAYq{=vy|sI0 z_vss+H_qMky?OB#|JK!>IX&II^LlUh#rO5!7TtbwC;iULyV-Xq?ybB}ykGP{?LpZ? z-G|jbTmIbG@7#ZCz;~eY(cDM(28Dyq{*m>M4?_iynUBkc4TkHUI6gT!;y-fz>HMcd z&t%Ugo)`Y2{>!cx7B7DI)$7;J(U{Spm-3gBzioV_{p!H$8L!*M!p0uH$#^p{Ui4P` z?ZJ24cOCDe-w#jZd?0@)|7iKK^;6KN`;!@ylm7$*nDhK&GcDTy000JJOGiWi{{a60 z|De66lK=n!32;bRa{vGf6951U69E94oEQKA00(qQO+^RY2Oa|$Dm!$xI{*Lx+et)0 zR4C6~(mhTCF%X8~cLqx-K%%6er{p$VgA1jn<21CnKtxu_CQE|6YY)ZlO89d#(&HKb zjBVT3r{Ld6ZZsn$H)?r$FgMJch>Drx08!?3 zq7>4Uhqh$Qy}++RKDDra`<8RK^n;B-0UW5{ Date: Sun, 27 Apr 2014 09:28:17 +0200 Subject: [PATCH 070/118] Fixes #1241: Removed disposition-based combat conditions The information for this code came from UESP, which in turn cites a (extremely vague) section from the TES-CS help text, so no surprise that it wasn't accurate. The guard on the boat has a fight rating of 70, so with the old code it would attack on sight if the disposition is low enough. BTB-Character.esp includes something (not sure what) that drops his disposition to 35 when playing as a Khajiit, making him attack. Testing in Vanilla it appears that disposition has no effect on combat engagement at all. Even with disposition 0 and fight 70 the NPCs don't attack. Setting an NPCs fight rating to 70 or less still has a meaning, because the higher it is, the easier it becomes to raise the fight rating to 80 (by taunting, for example). --- apps/openmw/mwmechanics/actors.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 804ec7a41..96194d292 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -204,11 +204,6 @@ namespace MWMechanics || (fight >= 95 && d <= 3000) || (fight >= 90 && d <= 2000) || (fight >= 80 && d <= 1000) - || (fight >= 80 && disp <= 40) - || (fight >= 70 && disp <= 35 && d <= 1000) - || (fight >= 60 && disp <= 30 && d <= 1000) - || (fight >= 50 && disp == 0) - || (fight >= 40 && disp <= 10 && d <= 500) ) { bool LOS = MWBase::Environment::get().getWorld()->getLOS(ptr,player) From e42855d522101adc45cbc733dbe8bb96c28b652b Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 27 Apr 2014 12:54:18 +0200 Subject: [PATCH 071/118] Minor fix for spell icon --- apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 34402977c..841f617b7 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -340,6 +340,8 @@ namespace MWMechanics MWWorld::ContainerStoreIterator enchantItem = inv.getSelectedEnchantItem(); if (enchantItem != inv.end()) winMgr->setSelectedEnchantItem(*enchantItem); + else if (winMgr->getSelectedSpell() == "") + winMgr->unsetSelectedSpell(); } if (mUpdatePlayer) From 82121e040172b4d586363e427c09f2df795e443a Mon Sep 17 00:00:00 2001 From: mrcheko Date: Sun, 27 Apr 2014 16:59:21 +0400 Subject: [PATCH 072/118] some checks reworked --- apps/openmw/mwclass/npc.hpp | 8 ++++++++ apps/openmw/mwmechanics/aicombat.cpp | 4 ++-- apps/openmw/mwworld/physicssystem.cpp | 5 +++-- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index 596bf0e56..4b9c8988e 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -170,6 +170,14 @@ namespace MWClass virtual int getBaseGold(const MWWorld::Ptr& ptr) const; virtual bool isClass(const MWWorld::Ptr& ptr, const std::string &className) const; + + virtual bool canSwim (const MWWorld::Ptr &ptr) const { + return true; + } + + virtual bool canWalk (const MWWorld::Ptr &ptr) const { + return true; + } }; } diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index 2b612d734..42d963117 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -341,8 +341,8 @@ namespace MWMechanics // check if can move along z-axis bool canMoveByZ; - if(canMoveByZ = ((actorCls.isNpc() || actorCls.canSwim(actor)) && MWBase::Environment::get().getWorld()->isSwimming(actor)) - || (actorCls.canFly(actor) && MWBase::Environment::get().getWorld()->isFlying(actor))) + if(canMoveByZ = (actorCls.canSwim(actor) && MWBase::Environment::get().getWorld()->isSwimming(actor)) + || MWBase::Environment::get().getWorld()->isFlying(actor)) { // determine vertical angle to target mMovement.mRotation[0] = getXAngleToDir(vDirToTarget, distToTarget); diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 7d531d6d3..5bf8305ba 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -313,8 +313,9 @@ namespace MWWorld // NOTE: stepMove modifies newPosition if successful if(stepMove(colobj, newPosition, velocity, remainingTime, engine)) { - // don't let slaughterfish move out of water after stepMove - if(ptr.getClass().canSwim(ptr) && newPosition.z > (waterlevel - halfExtents.z * 0.5)) + // don't let pure water creatures move out of water after stepMove + if((ptr.getClass().canSwim(ptr) && !ptr.getClass().canWalk(ptr)) + && newPosition.z > (waterlevel - halfExtents.z * 0.5)) newPosition = oldPosition; else // Only on the ground if there's gravity isOnGround = !(newPosition.z < waterlevel || isFlying); From ce106d3becb8b1b7739f21011578d86a76f61c7b Mon Sep 17 00:00:00 2001 From: Jeffrey Haines Date: Sun, 27 Apr 2014 09:34:33 -0400 Subject: [PATCH 073/118] Revert "NPCs detect crime exclusively" This reverts commit 54d9615d85ae856ad4fdd2c130ac9cb0cd847c72. Conflicts: apps/openmw/mwmechanics/mechanicsmanagerimp.cpp --- apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 2b1fdd365..26c629fb8 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -843,7 +843,10 @@ namespace MWMechanics // Find an actor who witnessed the crime for (std::vector::iterator it = neighbors.begin(); it != neighbors.end(); ++it) { +<<<<<<< HEAD +======= if (*it == ptr) continue; // not the player +>>>>>>> parent of 54d9615... NPCs detect crime exclusively // Was the crime seen? if ( ( MWBase::Environment::get().getWorld()->getLOS(ptr, *it) && awarenessCheck(ptr, *it) ) || From b9bd4bc1265a4f4c531b1456f9a4fcf21076cd55 Mon Sep 17 00:00:00 2001 From: Jeffrey Haines Date: Sun, 27 Apr 2014 09:34:59 -0400 Subject: [PATCH 074/118] broken --- apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 26c629fb8..88d07cfa6 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -844,6 +844,8 @@ namespace MWMechanics for (std::vector::iterator it = neighbors.begin(); it != neighbors.end(); ++it) { <<<<<<< HEAD + if ( *it == ptr + && it->getClass().isNpc()) continue; // not the player and is an NPC ======= if (*it == ptr) continue; // not the player >>>>>>> parent of 54d9615... NPCs detect crime exclusively @@ -862,7 +864,8 @@ namespace MWMechanics // Tell everyone, including yourself for (std::vector::iterator it1 = neighbors.begin(); it1 != neighbors.end(); ++it1) { - if (*it1 == ptr) continue; // not the player + if ( *it == ptr + && it->getClass().isNpc()) continue; // not the player and is an NPC // TODO: Add more messages if (type == OT_Theft) From 0409e18a0e7a903a00bc4c4b0951ee7532ec0317 Mon Sep 17 00:00:00 2001 From: Jeffrey Haines Date: Sun, 27 Apr 2014 09:35:49 -0400 Subject: [PATCH 075/118] revert --- apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 88d07cfa6..2b1fdd365 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -843,12 +843,7 @@ namespace MWMechanics // Find an actor who witnessed the crime for (std::vector::iterator it = neighbors.begin(); it != neighbors.end(); ++it) { -<<<<<<< HEAD - if ( *it == ptr - && it->getClass().isNpc()) continue; // not the player and is an NPC -======= if (*it == ptr) continue; // not the player ->>>>>>> parent of 54d9615... NPCs detect crime exclusively // Was the crime seen? if ( ( MWBase::Environment::get().getWorld()->getLOS(ptr, *it) && awarenessCheck(ptr, *it) ) || @@ -864,8 +859,7 @@ namespace MWMechanics // Tell everyone, including yourself for (std::vector::iterator it1 = neighbors.begin(); it1 != neighbors.end(); ++it1) { - if ( *it == ptr - && it->getClass().isNpc()) continue; // not the player and is an NPC + if (*it1 == ptr) continue; // not the player // TODO: Add more messages if (type == OT_Theft) From 7599b26d309bba10a22adab0abd051674a31eb5a Mon Sep 17 00:00:00 2001 From: Jeffrey Haines Date: Sun, 27 Apr 2014 09:37:43 -0400 Subject: [PATCH 076/118] Fixed: creatures won't witness crimes and potential crash. --- apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 2b1fdd365..03beed5a5 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -843,7 +843,8 @@ namespace MWMechanics // Find an actor who witnessed the crime for (std::vector::iterator it = neighbors.begin(); it != neighbors.end(); ++it) { - if (*it == ptr) continue; // not the player + if ( *it == ptr + && it->getClass().isNpc()) continue; // not the player and is an NPC // Was the crime seen? if ( ( MWBase::Environment::get().getWorld()->getLOS(ptr, *it) && awarenessCheck(ptr, *it) ) || @@ -859,7 +860,8 @@ namespace MWMechanics // Tell everyone, including yourself for (std::vector::iterator it1 = neighbors.begin(); it1 != neighbors.end(); ++it1) { - if (*it1 == ptr) continue; // not the player + if ( *it == ptr + && it->getClass().isNpc()) continue; // not the player and is an NPC // TODO: Add more messages if (type == OT_Theft) From 52bb7c3f69914084eacd1affa8470017286a4b1d Mon Sep 17 00:00:00 2001 From: Jeffrey Haines Date: Sun, 27 Apr 2014 09:55:38 -0400 Subject: [PATCH 077/118] fixed logic. ! --- apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 03beed5a5..8b8788741 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -844,7 +844,7 @@ namespace MWMechanics for (std::vector::iterator it = neighbors.begin(); it != neighbors.end(); ++it) { if ( *it == ptr - && it->getClass().isNpc()) continue; // not the player and is an NPC + && !it->getClass().isNpc()) continue; // not the player and is an NPC // Was the crime seen? if ( ( MWBase::Environment::get().getWorld()->getLOS(ptr, *it) && awarenessCheck(ptr, *it) ) || @@ -861,7 +861,7 @@ namespace MWMechanics for (std::vector::iterator it1 = neighbors.begin(); it1 != neighbors.end(); ++it1) { if ( *it == ptr - && it->getClass().isNpc()) continue; // not the player and is an NPC + && !it->getClass().isNpc()) continue; // not the player and is an NPC // TODO: Add more messages if (type == OT_Theft) From edbc319c424d6fd29b00338608f6e52fc2f7b644 Mon Sep 17 00:00:00 2001 From: Jeffrey Haines Date: Sun, 27 Apr 2014 10:05:34 -0400 Subject: [PATCH 078/118] fixed logic. || --- apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 8b8788741..eca0c2289 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -844,7 +844,7 @@ namespace MWMechanics for (std::vector::iterator it = neighbors.begin(); it != neighbors.end(); ++it) { if ( *it == ptr - && !it->getClass().isNpc()) continue; // not the player and is an NPC + || !it->getClass().isNpc()) continue; // not the player and is an NPC // Was the crime seen? if ( ( MWBase::Environment::get().getWorld()->getLOS(ptr, *it) && awarenessCheck(ptr, *it) ) || @@ -861,7 +861,7 @@ namespace MWMechanics for (std::vector::iterator it1 = neighbors.begin(); it1 != neighbors.end(); ++it1) { if ( *it == ptr - && !it->getClass().isNpc()) continue; // not the player and is an NPC + || !it->getClass().isNpc()) continue; // not the player and is an NPC // TODO: Add more messages if (type == OT_Theft) From 1b8c975d5ba62a501ff160a69ef1af7051acf816 Mon Sep 17 00:00:00 2001 From: Thoronador Date: Sun, 27 Apr 2014 19:03:33 +0200 Subject: [PATCH 079/118] minor performance improvements in apps/openmw Checking for emptiness using size() might be inefficient, because it can take linear time, while empty() is guaranteed to take only constant time. For non-primitive types, postfix ++ operators are inefficient compared to prefix ++ operators, because post-increment usually involves keeping a copy of the previous value around. --- apps/openmw/mwgui/tradewindow.cpp | 12 ++++++------ apps/openmw/mwmechanics/activespells.cpp | 4 ++-- apps/openmw/mwmechanics/aisequence.cpp | 8 ++++---- apps/openmw/mwmechanics/pathgrid.cpp | 2 +- apps/openmw/mwmechanics/spellcasting.cpp | 4 ++-- apps/openmw/mwmechanics/spells.cpp | 8 ++++---- apps/openmw/mwrender/animation.cpp | 24 ++++++++++++------------ apps/openmw/mwrender/debugging.cpp | 2 +- apps/openmw/mwrender/objects.cpp | 8 ++++---- apps/openmw/mwsound/soundmanagerimp.cpp | 2 +- apps/openmw/mwworld/actionteleport.cpp | 2 +- apps/openmw/mwworld/cellstore.cpp | 1 - apps/openmw/mwworld/physicssystem.cpp | 4 ++-- apps/openmw/mwworld/player.cpp | 6 +++--- 14 files changed, 43 insertions(+), 44 deletions(-) diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index 3e15bcd78..9cabab3e8 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -78,13 +78,13 @@ namespace MWGui } void TradeWindow::startTrade(const MWWorld::Ptr& actor) - { + { mPtr = actor; mCurrentBalance = 0; mCurrentMerchantOffer = 0; - checkTradeTime(); + checkTradeTime(); std::vector itemSources; MWBase::Environment::get().getWorld()->getContainersOwnedBy(actor, itemSources); @@ -245,7 +245,7 @@ namespace MWGui // were there any items traded at all? std::vector playerBought = playerItemModel->getItemsBorrowedToUs(); std::vector merchantBought = mTradeModel->getItemsBorrowedToUs(); - if (!playerBought.size() && !merchantBought.size()) + if (playerBought.empty() && merchantBought.empty()) { // user notification MWBase::Environment::get().getWindowManager()-> @@ -476,7 +476,7 @@ namespace MWGui } // Relates to NPC gold reset delay - void TradeWindow::checkTradeTime() + void TradeWindow::checkTradeTime() { MWMechanics::CreatureStats &sellerStats = mPtr.getClass().getCreatureStats(mPtr); double delay = boost::lexical_cast(MWBase::Environment::get().getWorld()->getStore().get().find("fBarterGoldResetDelay")->getInt()); @@ -488,14 +488,14 @@ namespace MWGui } } - void TradeWindow::updateTradeTime() + void TradeWindow::updateTradeTime() { MWWorld::ContainerStore store = mPtr.getClass().getContainerStore(mPtr); MWMechanics::CreatureStats &sellerStats = mPtr.getClass().getCreatureStats(mPtr); double delay = boost::lexical_cast(MWBase::Environment::get().getWorld()->getStore().get().find("fBarterGoldResetDelay")->getInt()); // If trade timestamp is within reset delay don't set - if ( ! (MWBase::Environment::get().getWorld()->getTimeStamp() >= sellerStats.getTradeTime() && + if ( ! (MWBase::Environment::get().getWorld()->getTimeStamp() >= sellerStats.getTradeTime() && MWBase::Environment::get().getWorld()->getTimeStamp() < sellerStats.getTradeTime() + delay) ) { sellerStats.setTradeTime(MWBase::Environment::get().getWorld()->getTimeStamp()); diff --git a/apps/openmw/mwmechanics/activespells.cpp b/apps/openmw/mwmechanics/activespells.cpp index 0c5bd9afa..86db207a4 100644 --- a/apps/openmw/mwmechanics/activespells.cpp +++ b/apps/openmw/mwmechanics/activespells.cpp @@ -206,7 +206,7 @@ namespace MWMechanics if (effectIt->mKey.mId == effectId) effectIt = it->second.mEffects.erase(effectIt); else - effectIt++; + ++effectIt; } } mSpellsChanged = true; @@ -224,7 +224,7 @@ namespace MWMechanics && it->second.mCasterHandle == actorHandle) effectIt = it->second.mEffects.erase(effectIt); else - effectIt++; + ++effectIt; } } mSpellsChanged = true; diff --git a/apps/openmw/mwmechanics/aisequence.cpp b/apps/openmw/mwmechanics/aisequence.cpp index c67367a6c..294c9b6a1 100644 --- a/apps/openmw/mwmechanics/aisequence.cpp +++ b/apps/openmw/mwmechanics/aisequence.cpp @@ -38,7 +38,7 @@ MWMechanics::AiSequence& MWMechanics::AiSequence::operator= (const AiSequence& s copy (sequence); mDone = sequence.mDone; } - + return *this; } @@ -51,7 +51,7 @@ int MWMechanics::AiSequence::getTypeId() const { if (mPackages.empty()) return -1; - + return mPackages.front()->getTypeId(); } @@ -102,7 +102,7 @@ void MWMechanics::AiSequence::execute (const MWWorld::Ptr& actor,float duration) } else { - mDone = false; + mDone = false; } } } @@ -118,7 +118,7 @@ void MWMechanics::AiSequence::clear() void MWMechanics::AiSequence::stack (const AiPackage& package) { - for(std::list::iterator it = mPackages.begin(); it != mPackages.end(); it++) + for(std::list::iterator it = mPackages.begin(); it != mPackages.end(); ++it) { if(mPackages.front()->getPriority() <= package.getPriority()) { diff --git a/apps/openmw/mwmechanics/pathgrid.cpp b/apps/openmw/mwmechanics/pathgrid.cpp index cb9f051e3..82d815d68 100644 --- a/apps/openmw/mwmechanics/pathgrid.cpp +++ b/apps/openmw/mwmechanics/pathgrid.cpp @@ -296,7 +296,7 @@ namespace MWMechanics // add this edge to openset, lowest cost goes to the front // TODO: if this causes performance problems a hash table may help std::list::iterator it = openset.begin(); - for(it = openset.begin(); it!= openset.end(); it++) + for(it = openset.begin(); it!= openset.end(); ++it) { if(fScore[*it] > fScore[dest]) break; diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 21aee5b98..e6342e661 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -401,10 +401,10 @@ namespace MWMechanics if (!exploded) MWBase::Environment::get().getWorld()->explodeSpell(mHitPosition, mTarget, effects, caster, mId, mSourceName); - if (reflectedEffects.mList.size()) + if (!reflectedEffects.mList.empty()) inflict(caster, target, reflectedEffects, range, true); - if (appliedLastingEffects.size()) + if (!appliedLastingEffects.empty()) target.getClass().getCreatureStats(target).getActiveSpells().addSpell(mId, mStack, appliedLastingEffects, mSourceName, caster.getRefData().getHandle()); diff --git a/apps/openmw/mwmechanics/spells.cpp b/apps/openmw/mwmechanics/spells.cpp index 21781c530..c2bf794f1 100644 --- a/apps/openmw/mwmechanics/spells.cpp +++ b/apps/openmw/mwmechanics/spells.cpp @@ -129,7 +129,7 @@ namespace MWMechanics if (spell->mData.mType == ESM::Spell::ST_Disease) mSpells.erase(iter++); else - iter++; + ++iter; } } @@ -143,7 +143,7 @@ namespace MWMechanics if (spell->mData.mType == ESM::Spell::ST_Blight) mSpells.erase(iter++); else - iter++; + ++iter; } } @@ -157,7 +157,7 @@ namespace MWMechanics if (Misc::StringUtils::ciEqual(spell->mId, "corprus")) mSpells.erase(iter++); else - iter++; + ++iter; } } @@ -171,7 +171,7 @@ namespace MWMechanics if (spell->mData.mType == ESM::Spell::ST_Curse) mSpells.erase(iter++); else - iter++; + ++iter; } } diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index e62fee6e2..3b8b91b0e 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -411,7 +411,7 @@ Ogre::Node *Animation::getNode(const std::string &name) NifOgre::TextKeyMap::const_iterator Animation::findGroupStart(const NifOgre::TextKeyMap &keys, const std::string &groupname) { NifOgre::TextKeyMap::const_iterator iter(keys.begin()); - for(;iter != keys.end();iter++) + for(;iter != keys.end();++iter) { if(iter->second.compare(0, groupname.size(), groupname) == 0 && iter->second.compare(groupname.size(), 2, ": ") == 0) @@ -424,7 +424,7 @@ NifOgre::TextKeyMap::const_iterator Animation::findGroupStart(const NifOgre::Tex bool Animation::hasAnimation(const std::string &anim) { AnimSourceList::const_iterator iter(mAnimSources.begin()); - for(;iter != mAnimSources.end();iter++) + for(;iter != mAnimSources.end();++iter) { const NifOgre::TextKeyMap &keys = (*iter)->mTextKeys; if(findGroupStart(keys, anim) != keys.end()) @@ -465,7 +465,7 @@ float Animation::calcAnimVelocity(const NifOgre::TextKeyMap &keys, NifOgre::Node stoptime = keyiter->first; break; } - keyiter++; + ++keyiter; } if(stoptime > starttime) @@ -585,13 +585,13 @@ bool Animation::reset(AnimState &state, const NifOgre::TextKeyMap &keys, const s std::string starttag = groupname+": "+start; NifOgre::TextKeyMap::const_iterator startkey(groupstart); while(startkey != keys.end() && startkey->second != starttag) - startkey++; + ++startkey; if(startkey == keys.end() && start == "loop start") { starttag = groupname+": start"; startkey = groupstart; while(startkey != keys.end() && startkey->second != starttag) - startkey++; + ++startkey; } if(startkey == keys.end()) return false; @@ -603,7 +603,7 @@ bool Animation::reset(AnimState &state, const NifOgre::TextKeyMap &keys, const s // The Scrib's idle3 animation has "Idle3: Stop." instead of "Idle3: Stop". // Why, just why? :( && (stopkey->second.size() < stoptag.size() || stopkey->second.substr(0,stoptag.size()) != stoptag)) - stopkey++; + ++stopkey; if(stopkey == keys.end()) return false; @@ -627,7 +627,7 @@ bool Animation::reset(AnimState &state, const NifOgre::TextKeyMap &keys, const s state.mLoopStartTime = key->first; else if(key->second == loopstoptag) state.mLoopStopTime = key->first; - key++; + ++key; } } @@ -776,7 +776,7 @@ void Animation::play(const std::string &groupname, int priority, int groups, boo /* Look in reverse; last-inserted source has priority. */ AnimSourceList::reverse_iterator iter(mAnimSources.rbegin()); - for(;iter != mAnimSources.rend();iter++) + for(;iter != mAnimSources.rend();++iter) { const NifOgre::TextKeyMap &textkeys = (*iter)->mTextKeys; AnimState state; @@ -795,7 +795,7 @@ void Animation::play(const std::string &groupname, int priority, int groups, boo while(textkey != textkeys.end() && textkey->first <= state.mTime) { handleTextKey(state, groupname, textkey); - textkey++; + ++textkey; } if(state.mTime >= state.mLoopStopTime && state.mLoopCount > 0) @@ -810,7 +810,7 @@ void Animation::play(const std::string &groupname, int priority, int groups, boo while(textkey != textkeys.end() && textkey->first <= state.mTime) { handleTextKey(state, groupname, textkey); - textkey++; + ++textkey; } } @@ -965,7 +965,7 @@ Ogre::Vector3 Animation::runAnimation(float duration) while(textkey != textkeys.end() && textkey->first <= state.mTime) { handleTextKey(state, stateiter->first, textkey); - textkey++; + ++textkey; } if(state.mTime >= state.mLoopStopTime && state.mLoopCount > 0) @@ -979,7 +979,7 @@ Ogre::Vector3 Animation::runAnimation(float duration) while(textkey != textkeys.end() && textkey->first <= state.mTime) { handleTextKey(state, stateiter->first, textkey); - textkey++; + ++textkey; } if(state.mTime >= state.mLoopStopTime) diff --git a/apps/openmw/mwrender/debugging.cpp b/apps/openmw/mwrender/debugging.cpp index ba39d10d5..4f5536ca3 100644 --- a/apps/openmw/mwrender/debugging.cpp +++ b/apps/openmw/mwrender/debugging.cpp @@ -106,7 +106,7 @@ ManualObject *Debugging::createPathgridPoints(const ESM::Pathgrid *pathgrid) uint32 startIndex = 0; for(ESM::Pathgrid::PointList::const_iterator it = pathgrid->mPoints.begin(); it != pathgrid->mPoints.end(); - it++, startIndex += 6) + ++it, startIndex += 6) { Vector3 pointPos(it->mX, it->mY, it->mZ); diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index 9c10ca84b..f1b1325f7 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -240,25 +240,25 @@ Ogre::AxisAlignedBox Objects::getDimensions(MWWorld::CellStore* cell) void Objects::enableLights() { PtrAnimationMap::const_iterator it = mObjects.begin(); - for(;it != mObjects.end();it++) + for(;it != mObjects.end();++it) it->second->enableLights(true); } void Objects::disableLights() { PtrAnimationMap::const_iterator it = mObjects.begin(); - for(;it != mObjects.end();it++) + for(;it != mObjects.end();++it) it->second->enableLights(false); } void Objects::update(float dt, Ogre::Camera* camera) { PtrAnimationMap::const_iterator it = mObjects.begin(); - for(;it != mObjects.end();it++) + for(;it != mObjects.end();++it) it->second->runAnimation(dt); it = mObjects.begin(); - for(;it != mObjects.end();it++) + for(;it != mObjects.end();++it) it->second->preRender(camera); } diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 0720e798a..33032477f 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -442,7 +442,7 @@ namespace MWSound { snditer->first->setFadeout(duration); } - snditer++; + ++snditer; } } diff --git a/apps/openmw/mwworld/actionteleport.cpp b/apps/openmw/mwworld/actionteleport.cpp index 150f0bed2..627c05251 100644 --- a/apps/openmw/mwworld/actionteleport.cpp +++ b/apps/openmw/mwworld/actionteleport.cpp @@ -20,7 +20,7 @@ namespace MWWorld //find any NPC that is following the actor and teleport him too std::list followers = MWBase::Environment::get().getMechanicsManager()->getActorsFollowing(actor); - for(std::list::iterator it = followers.begin();it != followers.end();it++) + for(std::list::iterator it = followers.begin();it != followers.end();++it) { std::cout << "teleporting someone!" << (*it).getCellRef().mRefID; executeImp(*it); diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index bbd968a7b..e5f0c4b88 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -433,7 +433,6 @@ namespace MWWorld while(mCell->getNextRef(esm[index], ref, deleted)) { // Don't load reference if it was moved to a different cell. - std::string lowerCase = Misc::StringUtils::lowerCase(ref.mRefID); ESM::MovedCellRefTracker::const_iterator iter = std::find(mCell->mMovedRefs.begin(), mCell->mMovedRefs.end(), ref.mRefNum); if (iter != mCell->mMovedRefs.end()) { diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 7d531d6d3..d1f328f06 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -671,7 +671,7 @@ namespace MWWorld void PhysicsSystem::queueObjectMovement(const Ptr &ptr, const Ogre::Vector3 &movement) { PtrVelocityList::iterator iter = mMovementQueue.begin(); - for(;iter != mMovementQueue.end();iter++) + for(;iter != mMovementQueue.end();++iter) { if(iter->first == ptr) { @@ -692,7 +692,7 @@ namespace MWWorld { const MWBase::World *world = MWBase::Environment::get().getWorld(); PtrVelocityList::iterator iter = mMovementQueue.begin(); - for(;iter != mMovementQueue.end();iter++) + for(;iter != mMovementQueue.end();++iter) { float waterlevel = -std::numeric_limits::max(); const ESM::Cell *cell = iter->first.getCell()->getCell(); diff --git a/apps/openmw/mwworld/player.cpp b/apps/openmw/mwworld/player.cpp index 5e4211faa..b93632d19 100644 --- a/apps/openmw/mwworld/player.cpp +++ b/apps/openmw/mwworld/player.cpp @@ -141,17 +141,17 @@ namespace MWWorld // Find all the actors who might be able to see the player std::vector neighbors; - MWBase::Environment::get().getMechanicsManager()->getActorsInRange( Ogre::Vector3(ptr.getRefData().getPosition().pos), + MWBase::Environment::get().getMechanicsManager()->getActorsInRange( Ogre::Vector3(ptr.getRefData().getPosition().pos), esmStore.get().find("fSneakUseDist")->getInt(), neighbors); for (std::vector::iterator it = neighbors.begin(); it != neighbors.end(); ++it) { if ( MWBase::Environment::get().getMechanicsManager()->awarenessCheck(ptr, *it) ) - { + { MWBase::Environment::get().getWindowManager()->setSneakVisibility(false); break; } } - if (neighbors.size() == 0) + if (neighbors.empty()) MWBase::Environment::get().getWindowManager()->setSneakVisibility(true); } } From 22cdb166f2227ff6f6653027ed56485dd22d47ad Mon Sep 17 00:00:00 2001 From: mrcheko Date: Sun, 27 Apr 2014 22:38:04 +0400 Subject: [PATCH 080/118] warning fix, vars renaming --- apps/openmw/mwmechanics/aicombat.cpp | 89 +++++++++++++--------------- apps/openmw/mwmechanics/aicombat.hpp | 2 +- 2 files changed, 42 insertions(+), 49 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index 42d963117..e64639c34 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -76,6 +76,7 @@ namespace namespace MWMechanics { + static const float MAX_ATTACK_DURATION = 0.35f; static const float DOOR_CHECK_INTERVAL = 1.5f; // same as AiWander // NOTE: MIN_DIST_TO_DOOR_SQUARED is defined in obstacle.hpp @@ -86,7 +87,7 @@ namespace MWMechanics mTimerCombatMove(0), mFollowTarget(false), mReadyToAttack(false), - mStrike(false), + mAttack(false), mCombatMove(false), mMovement(), mForceNoShortcut(false), @@ -182,7 +183,7 @@ namespace MWMechanics } mTimerAttack -= duration; - actor.getClass().getCreatureStats(actor).setAttackingOrSpell(mStrike); + actor.getClass().getCreatureStats(actor).setAttackingOrSpell(mAttack); float tReaction = 0.25f; if(mTimerReact < tReaction) @@ -203,16 +204,16 @@ namespace MWMechanics //actual attacking logic //TODO: Some skills affect period of strikes.For berserk-like style period ~ 0.25f - float attackPeriod = 1.0f; + float attacksPeriod = 1.0f; if(mReadyToAttack) { - if(mTimerAttack <= -attackPeriod) + if(mTimerAttack <= -attacksPeriod) { //TODO: should depend on time between 'start' to 'min attack' //for better controlling of NPCs' attack strength. //Also it seems that this time is different for slash/thrust/chop - mTimerAttack = 0.35f * static_cast(rand())/RAND_MAX; - mStrike = true; + mTimerAttack = MAX_ATTACK_DURATION * static_cast(rand())/RAND_MAX; + mAttack = true; //say a provoking combat phrase if (actor.getClass().isNpc()) @@ -227,12 +228,12 @@ namespace MWMechanics } } else if (mTimerAttack <= 0) - mStrike = false; + mAttack = false; } else { - mTimerAttack = -attackPeriod; - mStrike = false; + mTimerAttack = -attacksPeriod; + mAttack = false; } const MWWorld::Class &actorCls = actor.getClass(); @@ -277,31 +278,23 @@ namespace MWMechanics /* * Some notes on meanings of variables: * - * rangeMelee: + * rangeAttack: * - * - Distance where attack using the actor's weapon is possible - * - longer for ranged weapons (obviously?) vs. melee weapons + * - Distance where attack using the actor's weapon is possible: + * longer for ranged weapons (obviously?) vs. melee weapons + * - Determined by weapon's reach parameter; hardcoded value + * for ranged weapon and for creatures * - Once within this distance mFollowTarget is triggered - * (TODO: check whether the follow logic still works for ranged - * weapons, since rangeCloseup is set to zero) - * - TODO: The variable name is confusing. It was ok when AiCombat only - * had melee weapons but now that ranged weapons are supported that is - * no longer the case. It should really be renamed to something - * like rangeStrike - alternatively, keep this name for melee - * weapons and use a different variable for tracking ranged weapon - * distance (rangeRanged maybe?) * - * rangeCloseup: + * rangeFollow: * * - Applies to melee weapons or hand to hand only (or creatures without * weapons) - * - Distance a little further away from the actor's weapon strike - * i.e. rangeCloseup > rangeMelee for melee weapons - * (the variable names make this simple concept counter-intuitive, - * something like rangeMelee > rangeStrike may be better) + * - Distance a little further away than the actor's weapon reach + * i.e. rangeFollow > rangeAttack for melee weapons + * - Hardcoded value (0 for ranged weapons) * - Once the target gets beyond this distance mFollowTarget is cleared * and a path to the target needs to be found - * - TODO: Possibly rename this variable to rangeMelee or even rangeFollow * * mFollowTarget: * @@ -311,19 +304,19 @@ namespace MWMechanics * target even if LOS is not achieved) */ - float rangeMelee; - float rangeCloseUp; + float rangeAttack; + float rangeFollow; bool distantCombat = false; if (weaptype == WeapType_BowAndArrow || weaptype == WeapType_Crossbow || weaptype == WeapType_Thrown) { - rangeMelee = 1000; // TODO: should depend on archer skill - rangeCloseUp = 0; // not needed in ranged combat + rangeAttack = 1000; // TODO: should depend on archer skill + rangeFollow = 0; // not needed in ranged combat distantCombat = true; } else { - rangeMelee = weapRange; - rangeCloseUp = 300; + rangeAttack = weapRange; + rangeFollow = 300; } ESM::Position pos = actor.getRefData().getPosition(); @@ -339,42 +332,42 @@ namespace MWMechanics mLastPos = pos; - // check if can move along z-axis - bool canMoveByZ; - if(canMoveByZ = (actorCls.canSwim(actor) && MWBase::Environment::get().getWorld()->isSwimming(actor)) - || MWBase::Environment::get().getWorld()->isFlying(actor)) + // check if actor can move along z-axis + bool canMoveByZ = (actorCls.canSwim(actor) && MWBase::Environment::get().getWorld()->isSwimming(actor)) + || MWBase::Environment::get().getWorld()->isFlying(actor); + if(canMoveByZ) { // determine vertical angle to target mMovement.mRotation[0] = getXAngleToDir(vDirToTarget, distToTarget); } // (within strike dist) || (not quite strike dist while following) - if(distToTarget < rangeMelee || (distToTarget <= rangeCloseUp && mFollowTarget && !isStuck) ) + if(distToTarget < rangeAttack || (distToTarget <= rangeFollow && mFollowTarget && !isStuck) ) { //Melee and Close-up combat vDirToTarget.z = 0; mMovement.mRotation[2] = getZAngleToDir(vDirToTarget, distToTarget); // (not quite strike dist while following) - if (mFollowTarget && distToTarget > rangeMelee) + if (mFollowTarget && distToTarget > rangeAttack) { //Close-up combat: just run up on target mMovement.mPosition[1] = 1; } else // (within strike dist) { - //Melee: stop running and attack mMovement.mPosition[1] = 0; // set slash/thrust/chop attack - if (mStrike && !distantCombat) chooseBestAttack(weapon, mMovement); + if (mAttack && !distantCombat) chooseBestAttack(weapon, mMovement); if(mMovement.mPosition[0] || mMovement.mPosition[1]) { mTimerCombatMove = 0.1f + 0.1f * static_cast(rand())/RAND_MAX; mCombatMove = true; } - else if(actorCls.isNpc() && (!distantCombat || (distantCombat && distToTarget < rangeMelee/2))) + // only NPCs are smart enough to use dodge movements + else if(actorCls.isNpc() && (!distantCombat || (distantCombat && distToTarget < rangeAttack/2))) { //apply sideway movement (kind of dodging) with some probability if(static_cast(rand())/RAND_MAX < 0.25) @@ -385,7 +378,7 @@ namespace MWMechanics } } - if(distantCombat && distToTarget < rangeMelee/4) + if(distantCombat && distToTarget < rangeAttack/4) { mMovement.mPosition[1] = -1; } @@ -469,7 +462,7 @@ namespace MWMechanics mReadyToAttack = false; } - if(distToTarget > rangeMelee && !distantCombat) + if(distToTarget > rangeAttack && !distantCombat) { //special run attack; it shouldn't affect melee combat tactics if(actorCls.getMovementSettings(actor).mPosition[1] == 1) @@ -486,14 +479,14 @@ namespace MWMechanics float s1 = distToTarget - weapRange; float t = s1/speed1; float s2 = speed2 * t; - float t_swing = 0.17f/weapSpeed;//instead of 0.17 should be the time of playing weapon anim from 'start' to 'hit' tags + float t_swing = (MAX_ATTACK_DURATION/2) / weapSpeed;//instead of 0.17 should be the time of playing weapon anim from 'start' to 'hit' tags if (t + s2/speed1 <= t_swing) { mReadyToAttack = true; - if(mTimerAttack <= -attackPeriod) + if(mTimerAttack <= -attacksPeriod) { - mTimerAttack = 0.3f*static_cast(rand())/RAND_MAX; - mStrike = true; + mTimerAttack = MAX_ATTACK_DURATION * static_cast(rand())/RAND_MAX; + mAttack = true; } } } @@ -503,7 +496,7 @@ namespace MWMechanics // coded at 250ms or 1/4 second // // TODO: Add a parameter to vary DURATION_SAME_SPOT? - if((distToTarget > rangeMelee || mFollowTarget) && + if((distToTarget > rangeAttack || mFollowTarget) && mObstacleCheck.check(actor, tReaction)) // check if evasive action needed { // first check if we're walking into a door diff --git a/apps/openmw/mwmechanics/aicombat.hpp b/apps/openmw/mwmechanics/aicombat.hpp index 716101637..30b72acd9 100644 --- a/apps/openmw/mwmechanics/aicombat.hpp +++ b/apps/openmw/mwmechanics/aicombat.hpp @@ -40,7 +40,7 @@ namespace MWMechanics float mTimerCombatMove; // AiCombat states - bool mReadyToAttack, mStrike; + bool mReadyToAttack, mAttack; bool mFollowTarget; bool mCombatMove; bool mBackOffDoor; From f69d61976eff72c00434027fe36db5a3c2d8135a Mon Sep 17 00:00:00 2001 From: Thoronador Date: Sun, 27 Apr 2014 23:24:25 +0200 Subject: [PATCH 081/118] minor performance improvements in other apps subdirectories --- apps/esmtool/esmtool.cpp | 2 +- apps/esmtool/record.cpp | 2 +- apps/launcher/graphicspage.cpp | 4 ++-- apps/opencs/view/world/datadisplaydelegate.cpp | 4 ++-- apps/opencs/view/world/table.cpp | 4 ++-- 5 files changed, 8 insertions(+), 8 deletions(-) mode change 100755 => 100644 apps/opencs/view/world/datadisplaydelegate.cpp diff --git a/apps/esmtool/esmtool.cpp b/apps/esmtool/esmtool.cpp index e9731d626..eef96c8c9 100644 --- a/apps/esmtool/esmtool.cpp +++ b/apps/esmtool/esmtool.cpp @@ -333,7 +333,7 @@ int load(Arguments& info) // Is the user interested in this record type? bool interested = true; - if (info.types.size() > 0) + if (!info.types.empty()) { std::vector::iterator match; match = std::find(info.types.begin(), info.types.end(), diff --git a/apps/esmtool/record.cpp b/apps/esmtool/record.cpp index 184d11bb4..25b2a4505 100644 --- a/apps/esmtool/record.cpp +++ b/apps/esmtool/record.cpp @@ -124,7 +124,7 @@ void printEffectList(ESM::EffectList effects) { int i = 0; std::vector::iterator eit; - for (eit = effects.mList.begin(); eit != effects.mList.end(); eit++) + for (eit = effects.mList.begin(); eit != effects.mList.end(); ++eit) { std::cout << " Effect[" << i << "]: " << magicEffectLabel(eit->mEffectID) << " (" << eit->mEffectID << ")" << std::endl; diff --git a/apps/launcher/graphicspage.cpp b/apps/launcher/graphicspage.cpp index 8abdf0019..638237f34 100644 --- a/apps/launcher/graphicspage.cpp +++ b/apps/launcher/graphicspage.cpp @@ -214,13 +214,13 @@ QStringList Launcher::GraphicsPage::getAvailableOptions(const QString &key, Ogre uint row = 0; Ogre::ConfigOptionMap options = renderer->getConfigOptions(); - for (Ogre::ConfigOptionMap::iterator i = options.begin (); i != options.end (); i++, row++) + for (Ogre::ConfigOptionMap::iterator i = options.begin (); i != options.end (); ++i, ++row) { Ogre::StringVector::iterator opt_it; uint idx = 0; for (opt_it = i->second.possibleValues.begin(); - opt_it != i->second.possibleValues.end(); opt_it++, idx++) + opt_it != i->second.possibleValues.end(); ++opt_it, ++idx) { if (strcmp (key.toStdString().c_str(), i->first.c_str()) == 0) { result << ((key == "FSAA") ? QString("MSAA ") : QString("")) + QString::fromStdString((*opt_it).c_str()).simplified(); diff --git a/apps/opencs/view/world/datadisplaydelegate.cpp b/apps/opencs/view/world/datadisplaydelegate.cpp old mode 100755 new mode 100644 index ef0da56ac..c3ec68b52 --- a/apps/opencs/view/world/datadisplaydelegate.cpp +++ b/apps/opencs/view/world/datadisplaydelegate.cpp @@ -25,7 +25,7 @@ CSVWorld::DataDisplayDelegate::DataDisplayDelegate(const ValueList &values, void CSVWorld::DataDisplayDelegate::buildPixmaps () { - if (mPixmaps.size() > 0) + if (!mPixmaps.empty()) mPixmaps.clear(); IconList::iterator it = mIcons.begin(); @@ -33,7 +33,7 @@ void CSVWorld::DataDisplayDelegate::buildPixmaps () while (it != mIcons.end()) { mPixmaps.push_back (std::make_pair (it->first, it->second.pixmap (mIconSize) ) ); - it++; + ++it; } } diff --git a/apps/opencs/view/world/table.cpp b/apps/opencs/view/world/table.cpp index 902ab268a..a5a98aac7 100644 --- a/apps/opencs/view/world/table.cpp +++ b/apps/opencs/view/world/table.cpp @@ -298,7 +298,7 @@ void CSVWorld::Table::revertRecord() { std::vector revertableIds = listRevertableSelectedIds(); - if (revertableIds.size()>0) + if (!revertableIds.empty()) { if (revertableIds.size()>1) mDocument.getUndoStack().beginMacro (tr ("Revert multiple records")); @@ -318,7 +318,7 @@ void CSVWorld::Table::deleteRecord() { std::vector deletableIds = listDeletableSelectedIds(); - if (deletableIds.size()>0) + if (!deletableIds.empty()) { if (deletableIds.size()>1) mDocument.getUndoStack().beginMacro (tr ("Delete multiple records")); From c2127845af27a724d0cf55adb614fbfe0c0c5bbb Mon Sep 17 00:00:00 2001 From: Thomas Date: Sun, 27 Apr 2014 20:54:22 -0400 Subject: [PATCH 082/118] Added onKnockdown command --- apps/openmw/mwmechanics/actors.cpp | 13 ++++++++++- apps/openmw/mwmechanics/creaturestats.cpp | 27 +++++++++++++++++++---- apps/openmw/mwmechanics/creaturestats.hpp | 9 ++++++++ apps/openmw/mwscript/docs/vmformat.txt | 4 +++- apps/openmw/mwscript/statsextensions.cpp | 20 ++++++++++++++++- apps/openmw/mwworld/player.hpp | 2 +- components/compiler/extensions0.cpp | 1 + components/compiler/opcodes.hpp | 2 ++ 8 files changed, 70 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index d51b02a15..0b0569376 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -889,12 +889,23 @@ namespace MWMechanics iter->second->update(duration); } - // Kill dead actors + // Kill dead actors, update some variables for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();iter++) { const MWWorld::Class &cls = MWWorld::Class::get(iter->first); CreatureStats &stats = cls.getCreatureStats(iter->first); + //KnockedOutOneFrameLogic + //Used for "OnKnockedOut" command + //Put here to ensure that it's run for PRECISELY one frame. + if(stats.getKnockedDown() && !stats.getKnockedDownOneFrame() && !stats.getKnockedDownOverOneFrame()) { //Start it for one frame if nessesary + stats.setKnockedDownOneFrame(true); + } + else if (stats.getKnockedDownOneFrame() && !stats.getKnockedDownOverOneFrame()) { //Turn off KnockedOutOneframe + stats.setKnockedDownOneFrame(false); + stats.setKnockedDownOverOneFrame(true); + } + if(!stats.isDead()) { if(iter->second->isDead()) diff --git a/apps/openmw/mwmechanics/creaturestats.cpp b/apps/openmw/mwmechanics/creaturestats.cpp index f81613ed1..40ac92251 100644 --- a/apps/openmw/mwmechanics/creaturestats.cpp +++ b/apps/openmw/mwmechanics/creaturestats.cpp @@ -17,7 +17,7 @@ namespace MWMechanics mAttacked (false), mHostile (false), mAttackingOrSpell(false), mIsWerewolf(false), - mFallHeight(0), mRecalcDynamicStats(false), mKnockdown(false), mHitRecovery(false), mBlock(false), + mFallHeight(0), mRecalcDynamicStats(false), mKnockdown(false), mKnockdownOneFrame(false), mKnockdownOverOneFrame(false), mHitRecovery(false), mBlock(false), mMovementFlags(0), mDrawState (DrawState_Nothing), mAttackStrength(0.f) { for (int i=0; i<4; ++i) @@ -387,6 +387,8 @@ namespace MWMechanics void CreatureStats::setKnockedDown(bool value) { mKnockdown = value; + if(!value) //Resets the "OverOneFrame" flag + setKnockedDownOverOneFrame(false); } bool CreatureStats::getKnockedDown() const @@ -394,6 +396,23 @@ namespace MWMechanics return mKnockdown; } + void CreatureStats::setKnockedDownOneFrame(bool value) + { + mKnockdownOneFrame = value; + } + + bool CreatureStats::getKnockedDownOneFrame() const + { + return mKnockdownOneFrame; + } + + void CreatureStats::setKnockedDownOverOneFrame(bool value) { + mKnockdownOverOneFrame = value; + } + bool CreatureStats::getKnockedDownOverOneFrame() const { + return mKnockdownOverOneFrame; + } + void CreatureStats::setHitRecovery(bool value) { mHitRecovery = value; @@ -479,7 +498,7 @@ namespace MWMechanics } // Relates to NPC gold reset delay - void CreatureStats::setTradeTime(MWWorld::TimeStamp tradeTime) + void CreatureStats::setTradeTime(MWWorld::TimeStamp tradeTime) { mTradeTime = tradeTime; } @@ -489,11 +508,11 @@ namespace MWMechanics return mTradeTime; } - void CreatureStats::setGoldPool(int pool) + void CreatureStats::setGoldPool(int pool) { mGoldPool = pool; } - int CreatureStats::getGoldPool() const + int CreatureStats::getGoldPool() const { return mGoldPool; } diff --git a/apps/openmw/mwmechanics/creaturestats.hpp b/apps/openmw/mwmechanics/creaturestats.hpp index 5dc59e5ab..633dc285c 100644 --- a/apps/openmw/mwmechanics/creaturestats.hpp +++ b/apps/openmw/mwmechanics/creaturestats.hpp @@ -41,6 +41,8 @@ namespace MWMechanics bool mHostile; bool mAttackingOrSpell; bool mKnockdown; + bool mKnockdownOneFrame; + bool mKnockdownOverOneFrame; bool mHitRecovery; bool mBlock; unsigned int mMovementFlags; @@ -188,7 +190,14 @@ namespace MWMechanics float getEvasion() const; void setKnockedDown(bool value); + ///Returns true for the entire duration of the actor being knocked down bool getKnockedDown() const; + void setKnockedDownOneFrame(bool value); + ///Returns true only for the first frame of the actor being knocked out; used for "onKnockedOut" command + bool getKnockedDownOneFrame() const; + void setKnockedDownOverOneFrame(bool value); + ///Returns true for all but the first frame of being knocked out; used to know to not reset mKnockedDownOneFrame + bool getKnockedDownOverOneFrame() const; void setHitRecovery(bool value); bool getHitRecovery() const; void setBlock(bool value); diff --git a/apps/openmw/mwscript/docs/vmformat.txt b/apps/openmw/mwscript/docs/vmformat.txt index ceea34466..bf2273b17 100644 --- a/apps/openmw/mwscript/docs/vmformat.txt +++ b/apps/openmw/mwscript/docs/vmformat.txt @@ -388,5 +388,7 @@ op 0x200023c: StopCombat op 0x200023d: StopCombatExplicit op 0x200023e: GetPcInJail op 0x200023f: GetPcTraveling +op 0x2000240: onKnockout +op 0x2000241: onKnockoutExplicit -opcodes 0x2000240-0x3ffffff unused +opcodes 0x2000242-0x3ffffff unused diff --git a/apps/openmw/mwscript/statsextensions.cpp b/apps/openmw/mwscript/statsextensions.cpp index 36083e4b0..2f584e7ed 100644 --- a/apps/openmw/mwscript/statsextensions.cpp +++ b/apps/openmw/mwscript/statsextensions.cpp @@ -1060,6 +1060,22 @@ namespace MWScript } }; + template + class OpOnKnockout : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWWorld::Ptr ptr = R()(runtime); + + Interpreter::Type_Integer value = + MWWorld::Class::get (ptr).getCreatureStats (ptr).getKnockedDownOneFrame(); + + runtime.push (value); + } + }; + template class OpIsWerewolf : public Interpreter::Opcode0 { @@ -1236,6 +1252,8 @@ namespace MWScript interpreter.installSegment5 (Compiler::Stats::opcodeOnDeath, new OpOnDeath); interpreter.installSegment5 (Compiler::Stats::opcodeOnDeathExplicit, new OpOnDeath); + interpreter.installSegment5 (Compiler::Stats::opcodeOnKnockout, new OpOnKnockout); + interpreter.installSegment5 (Compiler::Stats::opcodeOnKnockoutExplicit, new OpOnKnockout); interpreter.installSegment5 (Compiler::Stats::opcodeIsWerewolf, new OpIsWerewolf); interpreter.installSegment5 (Compiler::Stats::opcodeIsWerewolfExplicit, new OpIsWerewolf); @@ -1245,7 +1263,7 @@ namespace MWScript interpreter.installSegment5 (Compiler::Stats::opcodeUndoWerewolf, new OpSetWerewolf); interpreter.installSegment5 (Compiler::Stats::opcodeUndoWerewolfExplicit, new OpSetWerewolf); interpreter.installSegment5 (Compiler::Stats::opcodeSetWerewolfAcrobatics, new OpSetWerewolfAcrobatics); - interpreter.installSegment5 (Compiler::Stats::opcodeSetWerewolfAcrobaticsExplicit, new OpSetWerewolfAcrobatics); + interpreter.installSegment5 (Compiler::Stats::opcodeSetWerewolfAcrobaticsExplicit, new OpSetWerewolfAcrobatics); } } } diff --git a/apps/openmw/mwworld/player.hpp b/apps/openmw/mwworld/player.hpp index 7e3f7a3cf..638c738bd 100644 --- a/apps/openmw/mwworld/player.hpp +++ b/apps/openmw/mwworld/player.hpp @@ -90,7 +90,7 @@ namespace MWWorld bool wasTeleported() const; void setTeleported(bool teleported); - ///Checks all actors to see if anyone has an aipackage against you + ///Checks all nearby actors to see if anyone has an aipackage against you bool isInCombat(); void clear(); diff --git a/components/compiler/extensions0.cpp b/components/compiler/extensions0.cpp index 531fe2959..db1ac1609 100644 --- a/components/compiler/extensions0.cpp +++ b/components/compiler/extensions0.cpp @@ -444,6 +444,7 @@ namespace Compiler extensions.registerInstruction ("lowerrank", "", opcodeLowerRank, opcodeLowerRankExplicit); extensions.registerFunction ("ondeath", 'l', "", opcodeOnDeath, opcodeOnDeathExplicit); + extensions.registerFunction ("onknockout", 'l', "", opcodeOnKnockout, opcodeOnKnockoutExplicit); extensions.registerFunction ("iswerewolf", 'l', "", opcodeIsWerewolf, opcodeIsWerewolfExplicit); diff --git a/components/compiler/opcodes.hpp b/components/compiler/opcodes.hpp index 27ee182cf..9e36cb68d 100644 --- a/components/compiler/opcodes.hpp +++ b/components/compiler/opcodes.hpp @@ -377,6 +377,8 @@ namespace Compiler const int opcodeLowerRankExplicit = 0x20001eb; const int opcodeOnDeath = 0x20001fc; const int opcodeOnDeathExplicit = 0x2000205; + const int opcodeOnKnockout = 0x2000240; + const int opcodeOnKnockoutExplicit = 0x2000241; const int opcodeBecomeWerewolf = 0x2000217; const int opcodeBecomeWerewolfExplicit = 0x2000218; From 1da19585dc2f279417ad1660d3842bded75f112d Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 28 Apr 2014 07:49:08 +0200 Subject: [PATCH 083/118] Remove some unneeded includes --- apps/openmw/mwrender/videoplayer.cpp | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index 80704ca7c..82400aac4 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -6,14 +6,9 @@ #include #include -#include #include -#include #include -#include -#include -#include -#include +#include #include @@ -21,9 +16,6 @@ #include "../mwbase/soundmanager.hpp" #include "../mwsound/sound_decoder.hpp" #include "../mwsound/sound.hpp" -#include "../mwbase/inputmanager.hpp" - -#include "renderconst.hpp" #ifdef _WIN32 #include From b89463db091936aa5017cadaae99883efafbc375 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 28 Apr 2014 09:12:03 +0200 Subject: [PATCH 084/118] Fix #1207: Remember previous choice in class creation dialog --- apps/openmw/mwgui/charactercreation.cpp | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwgui/charactercreation.cpp b/apps/openmw/mwgui/charactercreation.cpp index 5526bd26d..fa1bd28be 100644 --- a/apps/openmw/mwgui/charactercreation.cpp +++ b/apps/openmw/mwgui/charactercreation.cpp @@ -188,12 +188,13 @@ namespace MWGui break; case GM_ClassCreate: - MWBase::Environment::get().getWindowManager()->removeDialog(mCreateClassDialog); - mCreateClassDialog = 0; - mCreateClassDialog = new CreateClassDialog(); + if (!mCreateClassDialog) + { + mCreateClassDialog = new CreateClassDialog(); + mCreateClassDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onCreateClassDialogDone); + mCreateClassDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onCreateClassDialogBack); + } mCreateClassDialog->setNextButtonShow(mCreationStage >= CSE_ClassChosen); - mCreateClassDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onCreateClassDialogDone); - mCreateClassDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onCreateClassDialogBack); mCreateClassDialog->setVisible(true); if (mCreationStage < CSE_RaceChosen) mCreationStage = CSE_RaceChosen; @@ -531,8 +532,8 @@ namespace MWGui mPlayerClass = klass; MWBase::Environment::get().getWindowManager()->setPlayerClass(klass); - MWBase::Environment::get().getWindowManager()->removeDialog(mCreateClassDialog); - mCreateClassDialog = 0; + // Do not delete dialog, so that choices are rembered in case we want to go back and adjust them later + mCreateClassDialog->setVisible(false); } updatePlayerHealth(); @@ -554,8 +555,8 @@ namespace MWGui void CharacterCreation::onCreateClassDialogBack() { - MWBase::Environment::get().getWindowManager()->removeDialog(mCreateClassDialog); - mCreateClassDialog = 0; + // Do not delete dialog, so that choices are rembered in case we want to go back and adjust them later + mCreateClassDialog->setVisible(false); MWBase::Environment::get().getWindowManager()->popGuiMode(); MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Class); From 1da99d9fc76cc52856d6ceda9a6f8a888f5e66f2 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 28 Apr 2014 10:26:24 +0200 Subject: [PATCH 085/118] Remove unused variable --- apps/openmw/mwmechanics/actors.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 96194d292..a0680c037 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -194,11 +194,6 @@ namespace MWMechanics +(actorpos.pos[1] - playerpos.pos[1])*(actorpos.pos[1] - playerpos.pos[1]) +(actorpos.pos[2] - playerpos.pos[2])*(actorpos.pos[2] - playerpos.pos[2])); float fight = ptr.getClass().getCreatureStats(ptr).getAiSetting(CreatureStats::AI_Fight).getModified(); - float disp = 100; //creatures don't have disposition, so set it to 100 by default - if(ptr.getTypeName() == typeid(ESM::NPC).name()) - { - disp = MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(ptr); - } if( (fight == 100 ) || (fight >= 95 && d <= 3000) From 4555f6ddf6d017156081e484b8f7ceacd527e709 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 28 Apr 2014 11:19:12 +0200 Subject: [PATCH 086/118] Add text shadow to progress bar labels --- files/mygui/openmw_progress.skin.xml | 1 + files/mygui/openmw_text.skin.xml | 10 +++++----- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/files/mygui/openmw_progress.skin.xml b/files/mygui/openmw_progress.skin.xml index a09011e10..5ef3d7304 100644 --- a/files/mygui/openmw_progress.skin.xml +++ b/files/mygui/openmw_progress.skin.xml @@ -45,6 +45,7 @@ + diff --git a/files/mygui/openmw_text.skin.xml b/files/mygui/openmw_text.skin.xml index d75abc873..b80859ea1 100644 --- a/files/mygui/openmw_text.skin.xml +++ b/files/mygui/openmw_text.skin.xml @@ -147,29 +147,29 @@ - + - + - + - + - + From 27a05027f42e524ca2d1125b0501226a5aabe310 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 28 Apr 2014 11:29:57 +0200 Subject: [PATCH 087/118] Fixes #1172: Added basic loading/saving progress bar The progress is not particularly accurate. It simply uses the current / total number of records written/read as indication. Cell records are currently the largest by far, but there is a good chance that could be optimized using a change tracking system. --- apps/openmw/mwbase/dialoguemanager.hpp | 7 ++- apps/openmw/mwbase/journal.hpp | 7 ++- apps/openmw/mwbase/windowmanager.hpp | 2 +- apps/openmw/mwbase/world.hpp | 2 +- apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 3 +- apps/openmw/mwdialogue/dialoguemanagerimp.hpp | 2 +- apps/openmw/mwdialogue/journalimp.cpp | 6 ++- apps/openmw/mwdialogue/journalimp.hpp | 2 +- apps/openmw/mwgui/loadingscreen.hpp | 2 +- apps/openmw/mwgui/mapwindow.cpp | 3 +- apps/openmw/mwgui/mapwindow.hpp | 2 +- apps/openmw/mwgui/windowmanagerimp.cpp | 4 +- apps/openmw/mwgui/windowmanagerimp.hpp | 2 +- apps/openmw/mwscript/globalscripts.cpp | 3 +- apps/openmw/mwscript/globalscripts.hpp | 7 ++- apps/openmw/mwstate/statemanagerimp.cpp | 45 +++++++++++++------ apps/openmw/mwworld/cells.cpp | 8 +++- apps/openmw/mwworld/cells.hpp | 7 ++- apps/openmw/mwworld/esmstore.cpp | 20 ++++----- apps/openmw/mwworld/esmstore.hpp | 2 +- apps/openmw/mwworld/globals.cpp | 3 +- apps/openmw/mwworld/globals.hpp | 7 ++- apps/openmw/mwworld/player.cpp | 4 +- apps/openmw/mwworld/player.hpp | 7 ++- apps/openmw/mwworld/store.hpp | 5 ++- apps/openmw/mwworld/weather.cpp | 3 +- apps/openmw/mwworld/weather.hpp | 7 ++- apps/openmw/mwworld/worldimp.cpp | 17 +++---- apps/openmw/mwworld/worldimp.hpp | 2 +- components/esm/esmreader.hpp | 1 + components/esm/esmwriter.hpp | 5 +++ components/esm/loadtes3.hpp | 4 +- .../loadinglistener/loadinglistener.hpp | 2 +- 33 files changed, 142 insertions(+), 61 deletions(-) diff --git a/apps/openmw/mwbase/dialoguemanager.hpp b/apps/openmw/mwbase/dialoguemanager.hpp index e1d1246c8..f51fba07b 100644 --- a/apps/openmw/mwbase/dialoguemanager.hpp +++ b/apps/openmw/mwbase/dialoguemanager.hpp @@ -5,6 +5,11 @@ #include +namespace Loading +{ + class Listener; +} + namespace ESM { class ESMReader; @@ -60,7 +65,7 @@ namespace MWBase virtual int countSavedGameRecords() const = 0; - virtual void write (ESM::ESMWriter& writer) const = 0; + virtual void write (ESM::ESMWriter& writer, Loading::Listener& progress) const = 0; virtual void readRecord (ESM::ESMReader& reader, int32_t type) = 0; }; diff --git a/apps/openmw/mwbase/journal.hpp b/apps/openmw/mwbase/journal.hpp index 8e4e9703f..7f06320aa 100644 --- a/apps/openmw/mwbase/journal.hpp +++ b/apps/openmw/mwbase/journal.hpp @@ -11,6 +11,11 @@ #include "../mwdialogue/topic.hpp" #include "../mwdialogue/quest.hpp" +namespace Loading +{ + class Listener; +} + namespace ESM { class ESMReader; @@ -80,7 +85,7 @@ namespace MWBase virtual int countSavedGameRecords() const = 0; - virtual void write (ESM::ESMWriter& writer) const = 0; + virtual void write (ESM::ESMWriter& writer, Loading::Listener& progress) const = 0; virtual void readRecord (ESM::ESMReader& reader, int32_t type) = 0; }; diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index eb84741c4..4287e466b 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -303,7 +303,7 @@ namespace MWBase /// Clear all savegame-specific data virtual void clear() = 0; - virtual void write (ESM::ESMWriter& writer) = 0; + virtual void write (ESM::ESMWriter& writer, Loading::Listener& progress) = 0; virtual void readRecord (ESM::ESMReader& reader, int32_t type) = 0; }; } diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index f03a9197d..d68228904 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -108,7 +108,7 @@ namespace MWBase virtual int countSavedGameRecords() const = 0; - virtual void write (ESM::ESMWriter& writer) const = 0; + virtual void write (ESM::ESMWriter& writer, Loading::Listener& listener) const = 0; virtual void readRecord (ESM::ESMReader& reader, int32_t type, const std::map& contentFileMap) = 0; diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index 32535f33e..caaf7c91f 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -609,7 +609,7 @@ namespace MWDialogue return 1; // known topics } - void DialogueManager::write (ESM::ESMWriter& writer) const + void DialogueManager::write (ESM::ESMWriter& writer, Loading::Listener& progress) const { ESM::DialogueState state; @@ -621,6 +621,7 @@ namespace MWDialogue writer.startRecord (ESM::REC_DIAS); state.save (writer); writer.endRecord (ESM::REC_DIAS); + progress.increaseProgress(); } void DialogueManager::readRecord (ESM::ESMReader& reader, int32_t type) diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.hpp b/apps/openmw/mwdialogue/dialoguemanagerimp.hpp index a2e31e791..6cd2c75af 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.hpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.hpp @@ -83,7 +83,7 @@ namespace MWDialogue virtual int countSavedGameRecords() const; - virtual void write (ESM::ESMWriter& writer) const; + virtual void write (ESM::ESMWriter& writer, Loading::Listener& progress) const; virtual void readRecord (ESM::ESMReader& reader, int32_t type); }; diff --git a/apps/openmw/mwdialogue/journalimp.cpp b/apps/openmw/mwdialogue/journalimp.cpp index 26383b3a7..724d531cf 100644 --- a/apps/openmw/mwdialogue/journalimp.cpp +++ b/apps/openmw/mwdialogue/journalimp.cpp @@ -167,7 +167,7 @@ namespace MWDialogue return count; } - void Journal::write (ESM::ESMWriter& writer) const + void Journal::write (ESM::ESMWriter& writer, Loading::Listener& progress) const { for (TQuestIter iter (mQuests.begin()); iter!=mQuests.end(); ++iter) { @@ -178,6 +178,7 @@ namespace MWDialogue writer.startRecord (ESM::REC_QUES); state.save (writer); writer.endRecord (ESM::REC_QUES); + progress.increaseProgress(); for (Topic::TEntryIter iter (quest.begin()); iter!=quest.end(); ++iter) { @@ -188,6 +189,7 @@ namespace MWDialogue writer.startRecord (ESM::REC_JOUR); entry.save (writer); writer.endRecord (ESM::REC_JOUR); + progress.increaseProgress(); } } @@ -199,6 +201,7 @@ namespace MWDialogue writer.startRecord (ESM::REC_JOUR); entry.save (writer); writer.endRecord (ESM::REC_JOUR); + progress.increaseProgress(); } for (TTopicIter iter (mTopics.begin()); iter!=mTopics.end(); ++iter) @@ -214,6 +217,7 @@ namespace MWDialogue writer.startRecord (ESM::REC_JOUR); entry.save (writer); writer.endRecord (ESM::REC_JOUR); + progress.increaseProgress(); } } } diff --git a/apps/openmw/mwdialogue/journalimp.hpp b/apps/openmw/mwdialogue/journalimp.hpp index 1b4803ba2..00511f47c 100644 --- a/apps/openmw/mwdialogue/journalimp.hpp +++ b/apps/openmw/mwdialogue/journalimp.hpp @@ -64,7 +64,7 @@ namespace MWDialogue virtual int countSavedGameRecords() const; - virtual void write (ESM::ESMWriter& writer) const; + virtual void write (ESM::ESMWriter& writer, Loading::Listener& progress) const; virtual void readRecord (ESM::ESMReader& reader, int32_t type); }; diff --git a/apps/openmw/mwgui/loadingscreen.hpp b/apps/openmw/mwgui/loadingscreen.hpp index 55235173f..96e0e1ed4 100644 --- a/apps/openmw/mwgui/loadingscreen.hpp +++ b/apps/openmw/mwgui/loadingscreen.hpp @@ -25,7 +25,7 @@ namespace MWGui virtual void setProgressRange (size_t range); virtual void setProgress (size_t value); - virtual void increaseProgress (size_t increase); + virtual void increaseProgress (size_t increase=1); virtual void setVisible(bool visible); diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index aa48631e4..284e5c4e2 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -595,7 +595,7 @@ namespace MWGui MyGUI::Gui::getInstance().destroyWidget(mGlobalMapOverlay->getChildAt(0)); } - void MapWindow::write(ESM::ESMWriter &writer) + void MapWindow::write(ESM::ESMWriter &writer, Loading::Listener& progress) { ESM::GlobalMap map; mGlobalMapRender->write(map); @@ -605,6 +605,7 @@ namespace MWGui writer.startRecord(ESM::REC_GMAP); map.save(writer); writer.endRecord(ESM::REC_GMAP); + progress.increaseProgress(); } void MapWindow::readRecord(ESM::ESMReader &reader, int32_t type) diff --git a/apps/openmw/mwgui/mapwindow.hpp b/apps/openmw/mwgui/mapwindow.hpp index 0b549147c..7f4f18893 100644 --- a/apps/openmw/mwgui/mapwindow.hpp +++ b/apps/openmw/mwgui/mapwindow.hpp @@ -108,7 +108,7 @@ namespace MWGui /// Clear all savegame-specific data void clear(); - void write (ESM::ESMWriter& writer); + void write (ESM::ESMWriter& writer, Loading::Listener& progress); void readRecord (ESM::ESMReader& reader, int32_t type); private: diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 2ed113126..e2e4e157c 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1407,9 +1407,9 @@ namespace MWGui mMap->clear(); } - void WindowManager::write(ESM::ESMWriter &writer) + void WindowManager::write(ESM::ESMWriter &writer, Loading::Listener& progress) { - mMap->write(writer); + mMap->write(writer, progress); } void WindowManager::readRecord(ESM::ESMReader &reader, int32_t type) diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 074cb3208..064ca89ba 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -291,7 +291,7 @@ namespace MWGui /// Clear all savegame-specific data virtual void clear(); - virtual void write (ESM::ESMWriter& writer); + virtual void write (ESM::ESMWriter& writer, Loading::Listener& progress); virtual void readRecord (ESM::ESMReader& reader, int32_t type); private: diff --git a/apps/openmw/mwscript/globalscripts.cpp b/apps/openmw/mwscript/globalscripts.cpp index 527c576cc..8e118e2f8 100644 --- a/apps/openmw/mwscript/globalscripts.cpp +++ b/apps/openmw/mwscript/globalscripts.cpp @@ -97,7 +97,7 @@ namespace MWScript return mScripts.size(); } - void GlobalScripts::write (ESM::ESMWriter& writer) const + void GlobalScripts::write (ESM::ESMWriter& writer, Loading::Listener& progress) const { for (std::map >::const_iterator iter (mScripts.begin()); iter!=mScripts.end(); ++iter) @@ -113,6 +113,7 @@ namespace MWScript writer.startRecord (ESM::REC_GSCR); script.save (writer); writer.endRecord (ESM::REC_GSCR); + progress.increaseProgress(); } } diff --git a/apps/openmw/mwscript/globalscripts.hpp b/apps/openmw/mwscript/globalscripts.hpp index de63b9906..97584a5b8 100644 --- a/apps/openmw/mwscript/globalscripts.hpp +++ b/apps/openmw/mwscript/globalscripts.hpp @@ -14,6 +14,11 @@ namespace ESM class ESMReader; } +namespace Loading +{ + class Listener; +} + namespace MWWorld { struct ESMStore; @@ -46,7 +51,7 @@ namespace MWScript int countSavedGameRecords() const; - void write (ESM::ESMWriter& writer) const; + void write (ESM::ESMWriter& writer, Loading::Listener& progress) const; bool readRecord (ESM::ESMReader& reader, int32_t type); ///< Records for variables that do not exist are dropped silently. diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index acf1cf3f2..33a78330d 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -196,26 +196,35 @@ void MWState::StateManager::saveGame (const std::string& description, const Slot writer.addMaster (*iter, 0); // not using the size information anyway -> use value of 0 writer.setFormat (ESM::Header::CurrentFormat); - writer.setRecordCount ( - 1 // saved game header - +MWBase::Environment::get().getJournal()->countSavedGameRecords() - +MWBase::Environment::get().getWorld()->countSavedGameRecords() - +MWBase::Environment::get().getScriptManager()->getGlobalScripts().countSavedGameRecords() - +MWBase::Environment::get().getDialogueManager()->countSavedGameRecords() - +1 // global map - ); + int recordCount = 1 // saved game header + +MWBase::Environment::get().getJournal()->countSavedGameRecords() + +MWBase::Environment::get().getWorld()->countSavedGameRecords() + +MWBase::Environment::get().getScriptManager()->getGlobalScripts().countSavedGameRecords() + +MWBase::Environment::get().getDialogueManager()->countSavedGameRecords() + +1; // global map + writer.setRecordCount (recordCount); writer.save (stream); + Loading::Listener& listener = *MWBase::Environment::get().getWindowManager()->getLoadingScreen(); + listener.setProgressRange(recordCount); + listener.setLabel("#{sNotifyMessage4}"); + + Loading::ScopedLoad load(&listener); + writer.startRecord (ESM::REC_SAVE); slot->mProfile.save (writer); writer.endRecord (ESM::REC_SAVE); + listener.increaseProgress(); - MWBase::Environment::get().getJournal()->write (writer); - MWBase::Environment::get().getDialogueManager()->write (writer); - MWBase::Environment::get().getWorld()->write (writer); - MWBase::Environment::get().getScriptManager()->getGlobalScripts().write (writer); - MWBase::Environment::get().getWindowManager()->write(writer); + MWBase::Environment::get().getJournal()->write (writer, listener); + MWBase::Environment::get().getDialogueManager()->write (writer, listener); + MWBase::Environment::get().getWorld()->write (writer, listener); + MWBase::Environment::get().getScriptManager()->getGlobalScripts().write (writer, listener); + MWBase::Environment::get().getWindowManager()->write(writer, listener); + + // Ensure we have written the number of records that was estimated + assert (writer.getRecordCount() == recordCount+1); // 1 extra for TES3 record writer.close(); @@ -261,6 +270,15 @@ void MWState::StateManager::loadGame (const Character *character, const Slot *sl std::map contentFileMap = buildContentFileIndexMap (reader); + Loading::Listener& listener = *MWBase::Environment::get().getWindowManager()->getLoadingScreen(); + + // FIXME: +1 is actually not needed, but older savegames had an off-by-one error with the record count + // So we leave this in for now so that these old savegames still work + listener.setProgressRange(reader.getRecordCount()+1); + listener.setLabel("#{sLoadingMessage14}"); + + Loading::ScopedLoad load(&listener); + while (reader.hasMoreRecs()) { ESM::NAME n = reader.getRecName(); @@ -318,6 +336,7 @@ void MWState::StateManager::loadGame (const Character *character, const Slot *sl /// \todo log error reader.skipRecord(); } + listener.increaseProgress(); } mCharacterManager.setCurrentCharacter(character); diff --git a/apps/openmw/mwworld/cells.cpp b/apps/openmw/mwworld/cells.cpp index acffe20f3..7f2a87eec 100644 --- a/apps/openmw/mwworld/cells.cpp +++ b/apps/openmw/mwworld/cells.cpp @@ -277,17 +277,23 @@ int MWWorld::Cells::countSavedGameRecords() const return count; } -void MWWorld::Cells::write (ESM::ESMWriter& writer) const +void MWWorld::Cells::write (ESM::ESMWriter& writer, Loading::Listener& progress) const { for (std::map, CellStore>::iterator iter (mExteriors.begin()); iter!=mExteriors.end(); ++iter) if (iter->second.hasState()) + { writeCell (writer, iter->second); + progress.increaseProgress(); // Assumes that each cell writes one record + } for (std::map::iterator iter (mInteriors.begin()); iter!=mInteriors.end(); ++iter) if (iter->second.hasState()) + { writeCell (writer, iter->second); + progress.increaseProgress(); // Assumes that each cell writes one record + } } bool MWWorld::Cells::readRecord (ESM::ESMReader& reader, int32_t type, diff --git a/apps/openmw/mwworld/cells.hpp b/apps/openmw/mwworld/cells.hpp index 5209aa51a..a9c17fa93 100644 --- a/apps/openmw/mwworld/cells.hpp +++ b/apps/openmw/mwworld/cells.hpp @@ -15,6 +15,11 @@ namespace ESM struct Cell; } +namespace Loading +{ + class Listener; +} + namespace MWWorld { class ESMStore; @@ -69,7 +74,7 @@ namespace MWWorld int countSavedGameRecords() const; - void write (ESM::ESMWriter& writer) const; + void write (ESM::ESMWriter& writer, Loading::Listener& progress) const; bool readRecord (ESM::ESMReader& reader, int32_t type, const std::map& contentFileMap); diff --git a/apps/openmw/mwworld/esmstore.cpp b/apps/openmw/mwworld/esmstore.cpp index c5c826d47..ebe0aa08a 100644 --- a/apps/openmw/mwworld/esmstore.cpp +++ b/apps/openmw/mwworld/esmstore.cpp @@ -153,17 +153,17 @@ void ESMStore::setUp() +mWeapons.getDynamicSize(); } - void ESMStore::write (ESM::ESMWriter& writer) const + void ESMStore::write (ESM::ESMWriter& writer, Loading::Listener& progress) const { - mPotions.write (writer); - mArmors.write (writer); - mBooks.write (writer); - mClasses.write (writer); - mClothes.write (writer); - mEnchants.write (writer); - mSpells.write (writer); - mWeapons.write (writer); - mNpcs.write (writer); + mPotions.write (writer, progress); + mArmors.write (writer, progress); + mBooks.write (writer, progress); + mClasses.write (writer, progress); + mClothes.write (writer, progress); + mEnchants.write (writer, progress); + mSpells.write (writer, progress); + mWeapons.write (writer, progress); + mNpcs.write (writer, progress); } bool ESMStore::readRecord (ESM::ESMReader& reader, int32_t type) diff --git a/apps/openmw/mwworld/esmstore.hpp b/apps/openmw/mwworld/esmstore.hpp index e6730c307..ea6d3d006 100644 --- a/apps/openmw/mwworld/esmstore.hpp +++ b/apps/openmw/mwworld/esmstore.hpp @@ -212,7 +212,7 @@ namespace MWWorld int countSavedGameRecords() const; - void write (ESM::ESMWriter& writer) const; + void write (ESM::ESMWriter& writer, Loading::Listener& progress) const; bool readRecord (ESM::ESMReader& reader, int32_t type); ///< \return Known type? diff --git a/apps/openmw/mwworld/globals.cpp b/apps/openmw/mwworld/globals.cpp index 879ffa8e3..663af640b 100644 --- a/apps/openmw/mwworld/globals.cpp +++ b/apps/openmw/mwworld/globals.cpp @@ -77,7 +77,7 @@ namespace MWWorld return mVariables.size(); } - void Globals::write (ESM::ESMWriter& writer) const + void Globals::write (ESM::ESMWriter& writer, Loading::Listener& progress) const { for (Collection::const_iterator iter (mVariables.begin()); iter!=mVariables.end(); ++iter) { @@ -85,6 +85,7 @@ namespace MWWorld writer.writeHNString ("NAME", iter->first); iter->second.write (writer, ESM::Variant::Format_Global); writer.endRecord (ESM::REC_GLOB); + progress.increaseProgress(); } } diff --git a/apps/openmw/mwworld/globals.hpp b/apps/openmw/mwworld/globals.hpp index d8d2cefbf..3ff4a5d6e 100644 --- a/apps/openmw/mwworld/globals.hpp +++ b/apps/openmw/mwworld/globals.hpp @@ -16,6 +16,11 @@ namespace ESM class ESMReader; } +namespace Loading +{ + class Listener; +} + namespace MWWorld { class ESMStore; @@ -46,7 +51,7 @@ namespace MWWorld int countSavedGameRecords() const; - void write (ESM::ESMWriter& writer) const; + void write (ESM::ESMWriter& writer, Loading::Listener& progress) const; bool readRecord (ESM::ESMReader& reader, int32_t type); ///< Records for variables that do not exist are dropped silently. diff --git a/apps/openmw/mwworld/player.cpp b/apps/openmw/mwworld/player.cpp index 5e4211faa..0aeb0ae5c 100644 --- a/apps/openmw/mwworld/player.cpp +++ b/apps/openmw/mwworld/player.cpp @@ -215,7 +215,7 @@ namespace MWWorld mTeleported = false; } - void Player::write (ESM::ESMWriter& writer) const + void Player::write (ESM::ESMWriter& writer, Loading::Listener& progress) const { ESM::Player player; @@ -245,6 +245,8 @@ namespace MWWorld writer.startRecord (ESM::REC_PLAY); player.save (writer); writer.endRecord (ESM::REC_PLAY); + + progress.increaseProgress(); } bool Player::readRecord (ESM::ESMReader& reader, int32_t type) diff --git a/apps/openmw/mwworld/player.hpp b/apps/openmw/mwworld/player.hpp index 7e3f7a3cf..8d27b2712 100644 --- a/apps/openmw/mwworld/player.hpp +++ b/apps/openmw/mwworld/player.hpp @@ -21,6 +21,11 @@ namespace MWBase class Ptr; } +namespace Loading +{ + class Listener; +} + namespace MWWorld { class CellStore; @@ -95,7 +100,7 @@ namespace MWWorld void clear(); - void write (ESM::ESMWriter& writer) const; + void write (ESM::ESMWriter& writer, Loading::Listener& progress) const; bool readRecord (ESM::ESMReader& reader, int32_t type); diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index 0fc2d547c..0f8ab8682 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -8,6 +8,8 @@ #include +#include + #include "recordcmp.hpp" namespace MWWorld @@ -313,7 +315,7 @@ namespace MWWorld return erase(item.mId); } - void write (ESM::ESMWriter& writer) const + void write (ESM::ESMWriter& writer, Loading::Listener& progress) const { for (typename Dynamic::const_iterator iter (mDynamic.begin()); iter!=mDynamic.end(); ++iter) @@ -322,6 +324,7 @@ namespace MWWorld writer.writeHNString ("NAME", iter->second.mId); iter->second.save (writer); writer.endRecord (T::sRecordId); + progress.increaseProgress(); } } diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 335702c66..3611114a9 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -686,7 +686,7 @@ bool WeatherManager::isDark() const return exterior && (mHour < mSunriseTime || mHour > mNightStart - 1); } -void WeatherManager::write(ESM::ESMWriter& writer) +void WeatherManager::write(ESM::ESMWriter& writer, Loading::Listener& progress) { ESM::WeatherState state; state.mHour = mHour; @@ -701,6 +701,7 @@ void WeatherManager::write(ESM::ESMWriter& writer) writer.startRecord(ESM::REC_WTHR); state.save(writer); writer.endRecord(ESM::REC_WTHR); + progress.increaseProgress(); } bool WeatherManager::readRecord(ESM::ESMReader& reader, int32_t type) diff --git a/apps/openmw/mwworld/weather.hpp b/apps/openmw/mwworld/weather.hpp index cad3a4492..3e9df504b 100644 --- a/apps/openmw/mwworld/weather.hpp +++ b/apps/openmw/mwworld/weather.hpp @@ -18,6 +18,11 @@ namespace MWRender class RenderingManager; } +namespace Loading +{ + class Listener; +} + namespace MWWorld { class Fallback; @@ -158,7 +163,7 @@ namespace MWWorld /// @see World::isDark bool isDark() const; - void write(ESM::ESMWriter& writer); + void write(ESM::ESMWriter& writer, Loading::Listener& progress); bool readRecord(ESM::ESMReader& reader, int32_t type); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 46bb4db58..0e825e263 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -268,19 +268,20 @@ namespace MWWorld int World::countSavedGameRecords() const { return - mStore.countSavedGameRecords() + mCells.countSavedGameRecords() + +mStore.countSavedGameRecords() +mGlobalVariables.countSavedGameRecords() +1 // player record - +mCells.countSavedGameRecords(); + +1; // weather record } - void World::write (ESM::ESMWriter& writer) const + void World::write (ESM::ESMWriter& writer, Loading::Listener& progress) const { - mStore.write (writer); - mGlobalVariables.write (writer); - mCells.write (writer); - mPlayer->write (writer); - mWeatherManager->write (writer); + mCells.write (writer, progress); + mStore.write (writer, progress); + mGlobalVariables.write (writer, progress); + mPlayer->write (writer, progress); + mWeatherManager->write (writer, progress); } void World::readRecord (ESM::ESMReader& reader, int32_t type, diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index f1e89bf6b..40ba8fa82 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -194,7 +194,7 @@ namespace MWWorld virtual int countSavedGameRecords() const; - virtual void write (ESM::ESMWriter& writer) const; + virtual void write (ESM::ESMWriter& writer, Loading::Listener& progress) const; virtual void readRecord (ESM::ESMReader& reader, int32_t type, const std::map& contentFileMap); diff --git a/components/esm/esmreader.hpp b/components/esm/esmreader.hpp index b6c0ebc70..6b0bb9a27 100644 --- a/components/esm/esmreader.hpp +++ b/components/esm/esmreader.hpp @@ -31,6 +31,7 @@ public: *************************************************************************/ int getVer() const { return mHeader.mData.version; } + int getRecordCount() const { return mHeader.mData.records; } float getFVer() const { if(mHeader.mData.version == VER_12) return 1.2; else return 1.3; } const std::string getAuthor() const { return mHeader.mData.author.toString(); } const std::string getDesc() const { return mHeader.mData.desc.toString(); } diff --git a/components/esm/esmwriter.hpp b/components/esm/esmwriter.hpp index 33650e678..b385ac067 100644 --- a/components/esm/esmwriter.hpp +++ b/components/esm/esmwriter.hpp @@ -29,7 +29,12 @@ class ESMWriter void setEncoder(ToUTF8::Utf8Encoder *encoding); void setAuthor(const std::string& author); void setDescription(const std::string& desc); + // Set the record count for writing it in the file header void setRecordCount (int count); + // Counts how many records we have actually written. + // It is a good idea to compare this with the value you wrote into the header (setRecordCount) + // It should be the record count you set + 1 (1 additional record for the TES3 header) + int getRecordCount() { return mRecordCount; } void setFormat (int format); void clearMaster(); diff --git a/components/esm/loadtes3.hpp b/components/esm/loadtes3.hpp index 5614d295f..eb5e14daf 100644 --- a/components/esm/loadtes3.hpp +++ b/components/esm/loadtes3.hpp @@ -28,7 +28,7 @@ namespace ESM int type; // 0=esp, 1=esm, 32=ess (unused) NAME32 author; // Author's name NAME256 desc; // File description - int records; // Number of records? Not used. + int records; // Number of records }; // Defines another files (esm or esp) that this file depends upon. @@ -52,4 +52,4 @@ namespace ESM } -#endif \ No newline at end of file +#endif diff --git a/components/loadinglistener/loadinglistener.hpp b/components/loadinglistener/loadinglistener.hpp index 483d52491..f6a7b71e9 100644 --- a/components/loadinglistener/loadinglistener.hpp +++ b/components/loadinglistener/loadinglistener.hpp @@ -17,7 +17,7 @@ namespace Loading virtual void setProgressRange (size_t range) = 0; virtual void setProgress (size_t value) = 0; - virtual void increaseProgress (size_t increase) = 0; + virtual void increaseProgress (size_t increase = 1) = 0; /// Indicate the scene is now ready to be shown virtual void removeWallpaper() = 0; From 0796815da0a7f903566f827bf370a325023dd286 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 28 Apr 2014 11:44:56 +0200 Subject: [PATCH 088/118] Ignore dead actors in getActorsFollowing/Fighting Prevents dead enemies from disallowing resting near them --- apps/openmw/mwmechanics/actors.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index a0680c037..2de5e268f 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -1019,7 +1019,7 @@ namespace MWMechanics const MWWorld::Class &cls = MWWorld::Class::get(iter->first); CreatureStats &stats = cls.getCreatureStats(iter->first); - if(stats.getAiSequence().getTypeId() == AiPackage::TypeIdFollow) + if(!stats.isDead() && stats.getAiSequence().getTypeId() == AiPackage::TypeIdFollow) { MWMechanics::AiFollow* package = static_cast(stats.getAiSequence().getActivePackage()); if(package->getFollowedActor() == actor.getCellRef().mRefID) @@ -1041,7 +1041,7 @@ namespace MWMechanics const MWWorld::Class &cls = MWWorld::Class::get(*iter); CreatureStats &stats = cls.getCreatureStats(*iter); - if(stats.getAiSequence().getTypeId() == AiPackage::TypeIdCombat) + if(!stats.isDead() && stats.getAiSequence().getTypeId() == AiPackage::TypeIdCombat) { MWMechanics::AiCombat* package = static_cast(stats.getAiSequence().getActivePackage()); if(package->getTargetId() == actor.getCellRef().mRefID) From 138fb4e29a91dfbf56612c09573223d5ec5826b2 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 28 Apr 2014 12:51:46 +0200 Subject: [PATCH 089/118] Bug #1265: Fixed confirmation buttons align --- files/mygui/openmw_confirmation_dialog.layout | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/mygui/openmw_confirmation_dialog.layout b/files/mygui/openmw_confirmation_dialog.layout index 47e1fd2b8..2bd9d8997 100644 --- a/files/mygui/openmw_confirmation_dialog.layout +++ b/files/mygui/openmw_confirmation_dialog.layout @@ -13,7 +13,7 @@ - + From 35c1724d39d5ca8d9a36107ac3514fd2bf78e765 Mon Sep 17 00:00:00 2001 From: mrcheko Date: Mon, 28 Apr 2014 16:34:49 +0400 Subject: [PATCH 090/118] unblock vertical aiming for combatants --- apps/openmw/mwmechanics/aicombat.cpp | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index e64639c34..d0555cdc3 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -34,13 +34,13 @@ namespace float getZAngleToDir(const Ogre::Vector3& dir, float dirLen = 0.0f) { - float len = (dirLen >= 0.0f)? dirLen : dir.length(); + float len = (dirLen > 0.0f)? dirLen : dir.length(); return Ogre::Radian( Ogre::Math::ACos(dir.y / len) * sgn(Ogre::Math::ASin(dir.x / len)) ).valueDegrees(); } float getXAngleToDir(const Ogre::Vector3& dir, float dirLen = 0.0f) { - float len = (dirLen >= 0.0f)? dirLen : dir.length(); + float len = (dirLen > 0.0f)? dirLen : dir.length(); return Ogre::Radian(-Ogre::Math::ASin(dir.z / len)).valueDegrees(); } @@ -323,7 +323,6 @@ namespace MWMechanics Ogre::Vector3 vActorPos(pos.pos); Ogre::Vector3 vTargetPos(mTarget.getRefData().getPosition().pos); Ogre::Vector3 vDirToTarget = vTargetPos - vActorPos; - float distToTarget = vDirToTarget.length(); bool isStuck = false; float speed = 0.0f; @@ -335,17 +334,19 @@ namespace MWMechanics // check if actor can move along z-axis bool canMoveByZ = (actorCls.canSwim(actor) && MWBase::Environment::get().getWorld()->isSwimming(actor)) || MWBase::Environment::get().getWorld()->isFlying(actor); - if(canMoveByZ) - { - // determine vertical angle to target - mMovement.mRotation[0] = getXAngleToDir(vDirToTarget, distToTarget); - } + + // determine vertical angle to target + // if actor can move along z-axis it will control movement dir + // if can't - it will control correct aiming + mMovement.mRotation[0] = getXAngleToDir(vDirToTarget); + + vDirToTarget.z = 0; + float distToTarget = vDirToTarget.length(); // (within strike dist) || (not quite strike dist while following) if(distToTarget < rangeAttack || (distToTarget <= rangeFollow && mFollowTarget && !isStuck) ) { //Melee and Close-up combat - vDirToTarget.z = 0; mMovement.mRotation[2] = getZAngleToDir(vDirToTarget, distToTarget); // (not quite strike dist while following) From 7e4a0c24780a38e741a054ed64bcf5397ccaf819 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 28 Apr 2014 15:00:52 +0200 Subject: [PATCH 091/118] Removed asserts --- apps/openmw/mwgui/loadingscreen.cpp | 2 -- apps/openmw/mwstate/statemanagerimp.cpp | 7 +++---- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwgui/loadingscreen.cpp b/apps/openmw/mwgui/loadingscreen.cpp index 7917c75f3..7c915ebeb 100644 --- a/apps/openmw/mwgui/loadingscreen.cpp +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -160,7 +160,6 @@ namespace MWGui void LoadingScreen::setProgress (size_t value) { - assert(value < mProgressBar->getScrollRange()); if (value - mProgress < mProgressBar->getScrollRange()/100.f) return; mProgress = value; @@ -174,7 +173,6 @@ namespace MWGui mProgressBar->setScrollPosition(0); size_t value = mProgress + increase; mProgress = value; - assert(mProgress < mProgressBar->getScrollRange()); mProgressBar->setTrackSize(value / (float)(mProgressBar->getScrollRange()) * mProgressBar->getLineSize()); draw(); } diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index 33a78330d..6fbd4bb23 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -224,7 +224,8 @@ void MWState::StateManager::saveGame (const std::string& description, const Slot MWBase::Environment::get().getWindowManager()->write(writer, listener); // Ensure we have written the number of records that was estimated - assert (writer.getRecordCount() == recordCount+1); // 1 extra for TES3 record + if (writer.getRecordCount() != recordCount+1) // 1 extra for TES3 record + std::cerr << "Warning: number of written savegame records does not match. Estimated: " << recordCount+1 << ", written: " << writer.getRecordCount() << std::endl; writer.close(); @@ -272,9 +273,7 @@ void MWState::StateManager::loadGame (const Character *character, const Slot *sl Loading::Listener& listener = *MWBase::Environment::get().getWindowManager()->getLoadingScreen(); - // FIXME: +1 is actually not needed, but older savegames had an off-by-one error with the record count - // So we leave this in for now so that these old savegames still work - listener.setProgressRange(reader.getRecordCount()+1); + listener.setProgressRange(reader.getRecordCount()); listener.setLabel("#{sLoadingMessage14}"); Loading::ScopedLoad load(&listener); From b2119441b9bed515eb8eddd64b6fac528ca9cc2b Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 28 Apr 2014 15:26:40 +0200 Subject: [PATCH 092/118] Fix bug in PcRank / PcNextRank It was using the first faction instead of the actor's faction. --- apps/openmw/mwscript/interpretercontext.cpp | 39 +++++++++++---------- 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/apps/openmw/mwscript/interpretercontext.cpp b/apps/openmw/mwscript/interpretercontext.cpp index b79808d08..9a55b3dcf 100644 --- a/apps/openmw/mwscript/interpretercontext.cpp +++ b/apps/openmw/mwscript/interpretercontext.cpp @@ -302,15 +302,18 @@ namespace MWScript std::string factionId = MWWorld::Class::get (mReference).getNpcStats (mReference).getFactionRanks().begin()->first; std::map ranks = MWWorld::Class::get (player).getNpcStats (player).getFactionRanks(); - std::map::const_iterator it = ranks.begin(); + std::map::const_iterator it = ranks.find(factionId); + int rank = -1; + if (it != ranks.end()) + rank = it->second; const MWWorld::ESMStore &store = world->getStore(); const ESM::Faction *faction = store.get().find(factionId); - if(it->second < 0 || it->second > 9) // there are only 10 ranks + if(rank < 0 || rank > 9) // there are only 10 ranks return ""; - return faction->mRanks[it->second]; + return faction->mRanks[rank]; } std::string InterpreterContext::getPCNextRank() const @@ -320,25 +323,25 @@ namespace MWScript std::string factionId = MWWorld::Class::get (mReference).getNpcStats (mReference).getFactionRanks().begin()->first; + std::map ranks = MWWorld::Class::get (player).getNpcStats (player).getFactionRanks(); + std::map::const_iterator it = ranks.find(factionId); + int rank = -1; + if (it != ranks.end()) + rank = it->second; + + ++rank; // Next rank + + // if we are already at max rank, there is no next rank + if (rank > 9) + rank = 9; + const MWWorld::ESMStore &store = world->getStore(); const ESM::Faction *faction = store.get().find(factionId); - std::map ranks = MWWorld::Class::get (player).getNpcStats (player).getFactionRanks(); + if(rank < 0 || rank > 9) + return ""; - if (!ranks.empty()) - { - std::map::const_iterator it = ranks.begin(); - - if(it->second < -1 || it->second > 9) - return ""; - - if(it->second <= 8) // If player is at max rank, there is no next rank - return faction->mRanks[it->second + 1]; - else - return faction->mRanks[it->second]; - } - else - return faction->mRanks[0]; + return faction->mRanks[rank]; } int InterpreterContext::getPCBounty() const From 84961d78434ca5a6651eb4d7565ed7ec1d8b6140 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 28 Apr 2014 15:30:57 +0200 Subject: [PATCH 093/118] Fixes #1254: PcRank should return first rank if not in the faction --- apps/openmw/mwscript/interpretercontext.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/apps/openmw/mwscript/interpretercontext.cpp b/apps/openmw/mwscript/interpretercontext.cpp index 9a55b3dcf..b97be61e1 100644 --- a/apps/openmw/mwscript/interpretercontext.cpp +++ b/apps/openmw/mwscript/interpretercontext.cpp @@ -307,6 +307,11 @@ namespace MWScript if (it != ranks.end()) rank = it->second; + // If you are not in the faction, PcRank returns the first rank, for whatever reason. + // This is used by the dialogue when joining the Thieves Guild in Balmora. + if (rank == -1) + rank = 0; + const MWWorld::ESMStore &store = world->getStore(); const ESM::Faction *faction = store.get().find(factionId); From b0bdd233eea81bdf3c42346cc1a75767c7179fd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20S=C3=B6derberg?= Date: Mon, 28 Apr 2014 16:05:27 +0200 Subject: [PATCH 094/118] Center, switch and change text for confirmation buttons The confirmation buttons for quitting or starting a new game were driving me crazy by not being ok left and cancel right, as e.g. vanilla is. Then I noticed the text isn't the same as in vanilla either. It should be yes/no, not ok/cancel. To make it even more authentic I also centered the buttons. Had to remove autosized buttons for this. I think it looks fine still. Comments? --- files/mygui/openmw_confirmation_dialog.layout | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/files/mygui/openmw_confirmation_dialog.layout b/files/mygui/openmw_confirmation_dialog.layout index 2bd9d8997..b5bf6405d 100644 --- a/files/mygui/openmw_confirmation_dialog.layout +++ b/files/mygui/openmw_confirmation_dialog.layout @@ -4,7 +4,7 @@ - + @@ -13,18 +13,13 @@ - - - + + + - - - - - + + - - - + \ No newline at end of file From 04e5b9c72c86d04118f6a3e7e22939bd3c9f9963 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20S=C3=B6derberg?= Date: Mon, 28 Apr 2014 16:23:07 +0200 Subject: [PATCH 095/118] Right aligned version/revision I've always felt that having the version/revision text at the bottom center in the main menu was a bit out of place. A more common place for this kind of thing is in one of the corners. I chose bottom right. Aditionally I right aligned it and changed the v and r in version and revision to capital letters. Comments? --- apps/openmw/mwgui/mainmenu.cpp | 4 ++-- files/mygui/openmw_mainmenu.layout | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwgui/mainmenu.cpp b/apps/openmw/mwgui/mainmenu.cpp index b6e3915bb..df9c53ea8 100644 --- a/apps/openmw/mwgui/mainmenu.cpp +++ b/apps/openmw/mwgui/mainmenu.cpp @@ -28,7 +28,7 @@ namespace MWGui { getWidget(mVersionText, "VersionText"); std::stringstream sstream; - sstream << "OpenMW version: " << OPENMW_VERSION; + sstream << "OpenMW Version: " << OPENMW_VERSION; // adding info about git hash if available std::string rev = OPENMW_VERSION_COMMITHASH; @@ -36,7 +36,7 @@ namespace MWGui if (!rev.empty() && !tag.empty()) { rev = rev.substr(0,10); - sstream << "\nrevision: " << rev; + sstream << "\nRevision: " << rev; } std::string output = sstream.str(); diff --git a/files/mygui/openmw_mainmenu.layout b/files/mygui/openmw_mainmenu.layout index e8cb23b77..f4c7142ce 100644 --- a/files/mygui/openmw_mainmenu.layout +++ b/files/mygui/openmw_mainmenu.layout @@ -2,11 +2,11 @@ - - - + + + - + From 0513d0837c32dace48eee31ff373886745ca356f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20S=C3=B6derberg?= Date: Mon, 28 Apr 2014 17:54:55 +0200 Subject: [PATCH 096/118] Alignment tweaks and autosized buttons workaround --- files/mygui/openmw_confirmation_dialog.layout | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/files/mygui/openmw_confirmation_dialog.layout b/files/mygui/openmw_confirmation_dialog.layout index b5bf6405d..e299c7b0b 100644 --- a/files/mygui/openmw_confirmation_dialog.layout +++ b/files/mygui/openmw_confirmation_dialog.layout @@ -4,7 +4,7 @@ - + @@ -13,13 +13,25 @@ - - + + + + + + - + + + + + + + + + \ No newline at end of file From 518a32c19d93599af37b691b685eef8857103e75 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 28 Apr 2014 18:33:42 +0200 Subject: [PATCH 097/118] Fixes #1195: Make NPCs equip torches in interiors under certain conditions --- apps/openmw/mwworld/worldimp.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 0e825e263..4c1a8b1c0 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2506,7 +2506,17 @@ namespace MWWorld bool World::isDark() const { - return mWeatherManager->isDark(); + MWWorld::CellStore* cell = mPlayer->getPlayer().getCell(); + if (cell->isExterior()) + return mWeatherManager->isDark(); + else + { + uint32_t ambient = cell->getCell()->mAmbi.mAmbient; + int ambientTotal = (ambient & 0xff) + + ((ambient>>8) & 0xff) + + ((ambient>>16) & 0xff); + return !(cell->getCell()->mData.mFlags & ESM::Cell::NoSleep) && ambientTotal <= 201; + } } bool World::findInteriorPositionInWorldSpace(MWWorld::CellStore* cell, Ogre::Vector3& result) From a35f7c73ae0679acea383eab14628b4713453d18 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 28 Apr 2014 18:40:29 +0200 Subject: [PATCH 098/118] Fixes #1286 (Dialogue topic list clips with window frame) The first problem was with the ScrollView skin, which had a full-sized client area. Since the scrollbar starts out visible, MyGUI expects the client area to be smaller to accomodate for the scrollbar width. As a result, the starting canvas size becomes bigger than the view size. Another bug was with the MWList code: reducing the canvas size for the scrollbar is not needed, since MyGUI is already doing that, and attempting to do it manually interferes with the view offset. --- apps/openmw/mwgui/list.cpp | 6 +++--- files/mygui/openmw_scroll_skin.xml | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwgui/list.cpp b/apps/openmw/mwgui/list.cpp index 8dda041ca..eff7aea24 100644 --- a/apps/openmw/mwgui/list.cpp +++ b/apps/openmw/mwgui/list.cpp @@ -48,7 +48,7 @@ namespace MWGui void MWList::redraw(bool scrollbarShown) { - const int _scrollBarWidth = 24; // fetch this from skin? + const int _scrollBarWidth = 20; // fetch this from skin? const int scrollBarWidth = scrollbarShown ? _scrollBarWidth : 0; const int spacing = 3; size_t scrollbarPosition = mScrollView->getScrollPosition(); @@ -83,7 +83,7 @@ namespace MWGui else { MyGUI::ImageBox* separator = mScrollView->createWidget("MW_HLine", - MyGUI::IntCoord(2, mItemHeight, mScrollView->getWidth()-4, 18), + MyGUI::IntCoord(2, mItemHeight, mScrollView->getWidth() - scrollBarWidth - 4, 18), MyGUI::Align::Left | MyGUI::Align::Top | MyGUI::Align::HStretch); separator->setNeedMouseFocus(false); @@ -91,7 +91,7 @@ namespace MWGui } ++i; } - mScrollView->setCanvasSize(mClient->getSize().width + (_scrollBarWidth-scrollBarWidth), std::max(mItemHeight, mClient->getSize().height)); + mScrollView->setCanvasSize(mClient->getSize().width, std::max(mItemHeight, mClient->getSize().height)); if (!scrollbarShown && mItemHeight > mClient->getSize().height) redraw(true); diff --git a/files/mygui/openmw_scroll_skin.xml b/files/mygui/openmw_scroll_skin.xml index b6ed9155f..b5dfd333d 100644 --- a/files/mygui/openmw_scroll_skin.xml +++ b/files/mygui/openmw_scroll_skin.xml @@ -3,12 +3,12 @@ - + - + From d530bbe5cddd96b0483f2c35573901d22de4cf73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20S=C3=B6derberg?= Date: Mon, 28 Apr 2014 18:52:53 +0200 Subject: [PATCH 099/118] Implemented Scrawls alternative workaround. --- files/mygui/openmw_confirmation_dialog.layout | 28 ++++++++----------- 1 file changed, 11 insertions(+), 17 deletions(-) diff --git a/files/mygui/openmw_confirmation_dialog.layout b/files/mygui/openmw_confirmation_dialog.layout index e299c7b0b..edeed539c 100644 --- a/files/mygui/openmw_confirmation_dialog.layout +++ b/files/mygui/openmw_confirmation_dialog.layout @@ -13,25 +13,19 @@ - - - + + + + + + + + + + - - - + - - - - - - - - - - - \ No newline at end of file From 7f37f2c2be7d598af1cd3cd621e03dac658ac2b8 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 28 Apr 2014 19:23:25 +0200 Subject: [PATCH 100/118] Fixes #1187: Make GetDistance handle actors in remote cells gracefully --- apps/openmw/mwscript/interpretercontext.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwscript/interpretercontext.cpp b/apps/openmw/mwscript/interpretercontext.cpp index b97be61e1..1f5ad5b07 100644 --- a/apps/openmw/mwscript/interpretercontext.cpp +++ b/apps/openmw/mwscript/interpretercontext.cpp @@ -378,10 +378,14 @@ namespace MWScript float InterpreterContext::getDistance (const std::string& name, const std::string& id) const { - // TODO handle exterior cells (when ref and ref2 are located in different cells) - const MWWorld::Ptr ref2 = getReference (id, false); + const MWWorld::Ptr ref2 = getReference (id, false, false); + // If either actor is in a non-active cell, return a large value (just like vanilla) + if (ref2.isEmpty()) + return std::numeric_limits().max(); - const MWWorld::Ptr ref = MWBase::Environment::get().getWorld()->getPtr (name, true); + const MWWorld::Ptr ref = getReference (name, false, false); + if (ref.isEmpty()) + return std::numeric_limits().max(); double diff[3]; From 7a0aeeaa38498be4805dc4eb5a0864b526522580 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 28 Apr 2014 20:57:45 +0200 Subject: [PATCH 101/118] Allow to delete savegames (shift + click) --- apps/openmw/mwbase/statemanager.hpp | 2 + apps/openmw/mwgui/savegamedialog.cpp | 84 ++++++++++++++++-------- apps/openmw/mwgui/savegamedialog.hpp | 9 +++ apps/openmw/mwstate/character.cpp | 32 ++++++++- apps/openmw/mwstate/character.hpp | 8 +++ apps/openmw/mwstate/charactermanager.cpp | 19 ++++++ apps/openmw/mwstate/charactermanager.hpp | 2 + apps/openmw/mwstate/statemanagerimp.cpp | 5 ++ apps/openmw/mwstate/statemanagerimp.hpp | 3 + 9 files changed, 134 insertions(+), 30 deletions(-) diff --git a/apps/openmw/mwbase/statemanager.hpp b/apps/openmw/mwbase/statemanager.hpp index fc4a2d806..121a73a48 100644 --- a/apps/openmw/mwbase/statemanager.hpp +++ b/apps/openmw/mwbase/statemanager.hpp @@ -55,6 +55,8 @@ namespace MWBase virtual void endGame() = 0; + virtual void deleteGame (const MWState::Character *character, const MWState::Slot *slot) = 0; + virtual void saveGame (const std::string& description, const MWState::Slot *slot = 0) = 0; ///< Write a saved game to \a slot or create a new slot if \a slot == 0. /// diff --git a/apps/openmw/mwgui/savegamedialog.cpp b/apps/openmw/mwgui/savegamedialog.cpp index bb4373cba..74ccc82f4 100644 --- a/apps/openmw/mwgui/savegamedialog.cpp +++ b/apps/openmw/mwgui/savegamedialog.cpp @@ -23,6 +23,7 @@ namespace MWGui : WindowModal("openmw_savegame_dialog.layout") , mSaving(true) , mCurrentCharacter(NULL) + , mCurrentSlot(NULL) { getWidget(mScreenshot, "Screenshot"); getWidget(mCharacterSelection, "SelectCharacter"); @@ -36,6 +37,7 @@ namespace MWGui mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SaveGameDialog::onCancelButtonClicked); mCharacterSelection->eventComboChangePosition += MyGUI::newDelegate(this, &SaveGameDialog::onCharacterSelected); mSaveList->eventListChangePosition += MyGUI::newDelegate(this, &SaveGameDialog::onSlotSelected); + mSaveList->eventListMouseItemActivate += MyGUI::newDelegate(this, &SaveGameDialog::onSlotMouseClick); mSaveList->eventListSelectAccept += MyGUI::newDelegate(this, &SaveGameDialog::onSlotActivated); mSaveNameEdit->eventEditSelectAccept += MyGUI::newDelegate(this, &SaveGameDialog::onEditSelectAccept); mSaveNameEdit->eventEditTextChange += MyGUI::newDelegate(this, &SaveGameDialog::onSaveNameChanged); @@ -47,6 +49,37 @@ namespace MWGui accept(); } + void SaveGameDialog::onSlotMouseClick(MyGUI::ListBox* sender, size_t pos) + { + onSlotSelected(sender, pos); + + if (MyGUI::InputManager::getInstance().isShiftPressed()) + { + ConfirmationDialog* dialog = MWBase::Environment::get().getWindowManager()->getConfirmationDialog(); + dialog->open("#{sMessage3}"); + dialog->eventOkClicked.clear(); + dialog->eventOkClicked += MyGUI::newDelegate(this, &SaveGameDialog::onDeleteSlotConfirmed); + dialog->eventCancelClicked.clear(); + } + } + + void SaveGameDialog::onDeleteSlotConfirmed() + { + MWBase::Environment::get().getStateManager()->deleteGame (mCurrentCharacter, mCurrentSlot); + mSaveList->removeItemAt(mSaveList->getIndexSelected()); + onSlotSelected(mSaveList, MyGUI::ITEM_NONE); + + // The character might be deleted now + size_t previousIndex = mCharacterSelection->getIndexSelected(); + open(); + if (mCharacterSelection->getItemCount()) + { + size_t nextCharacter = std::min(previousIndex, mCharacterSelection->getItemCount()-1); + mCharacterSelection->setIndexSelected(nextCharacter); + onCharacterSelected(mCharacterSelection, nextCharacter); + } + } + void SaveGameDialog::onSaveNameChanged(MyGUI::EditBox *sender) { // This might have previously been a save slot from the list. If so, that is no longer the case @@ -69,6 +102,12 @@ namespace MWGui center(); + mCharacterSelection->setCaption(""); + mCharacterSelection->removeAllItems(); + mCurrentCharacter = NULL; + mCurrentSlot = NULL; + mSaveList->removeAllItems(); + MWBase::StateManager* mgr = MWBase::Environment::get().getStateManager(); if (mgr->characterBegin() == mgr->characterEnd()) return; @@ -78,8 +117,6 @@ namespace MWGui std::string directory = Misc::StringUtils::lowerCase (Settings::Manager::getString ("character", "Saves")); - mCharacterSelection->removeAllItems(); - int selectedIndex = MyGUI::ITEM_NONE; for (MWBase::StateManager::CharacterIterator it = mgr->characterBegin(); it != mgr->characterEnd(); ++it) @@ -152,23 +189,10 @@ namespace MWGui { MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(NULL); - // Get the selected slot, if any - unsigned int i=0; - const MWState::Slot* slot = NULL; - - if (mCurrentCharacter) - { - for (MWState::Character::SlotIterator it = mCurrentCharacter->begin(); it != mCurrentCharacter->end(); ++it,++i) - { - if (i == mSaveList->getIndexSelected()) - slot = &*it; - } - } - if (mSaving) { // If overwriting an existing slot, ask for confirmation first - if (slot != NULL && !reallySure) + if (mCurrentSlot != NULL && !reallySure) { ConfirmationDialog* dialog = MWBase::Environment::get().getWindowManager()->getConfirmationDialog(); dialog->open("#{sMessage4}"); @@ -182,13 +206,13 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->messageBox("#{sNotifyMessage65}"); return; } - MWBase::Environment::get().getStateManager()->saveGame (mSaveNameEdit->getCaption(), slot); + MWBase::Environment::get().getStateManager()->saveGame (mSaveNameEdit->getCaption(), mCurrentSlot); } else { - if (mCurrentCharacter && slot) + if (mCurrentCharacter && mCurrentSlot) { - MWBase::Environment::get().getStateManager()->loadGame (mCurrentCharacter, slot); + MWBase::Environment::get().getStateManager()->loadGame (mCurrentCharacter, mCurrentSlot); MWBase::Environment::get().getWindowManager()->removeGuiMode (MWGui::GM_MainMenu); } } @@ -221,6 +245,7 @@ namespace MWGui assert(character && "Can't find selected character"); mCurrentCharacter = character; + mCurrentSlot = NULL; fillSaveList(); } @@ -240,6 +265,7 @@ namespace MWGui { if (pos == MyGUI::ITEM_NONE) { + mCurrentSlot = NULL; mInfoText->setCaption(""); mScreenshot->setImageTexture(""); return; @@ -248,17 +274,17 @@ namespace MWGui if (mSaving) mSaveNameEdit->setCaption(sender->getItemNameAt(pos)); - const MWState::Slot* slot = NULL; + mCurrentSlot = NULL; unsigned int i=0; for (MWState::Character::SlotIterator it = mCurrentCharacter->begin(); it != mCurrentCharacter->end(); ++it, ++i) { if (i == pos) - slot = &*it; + mCurrentSlot = &*it; } - assert(slot && "Can't find selected slot"); + assert(mCurrentSlot && "Can't find selected slot"); std::stringstream text; - time_t time = slot->mTimeStamp; + time_t time = mCurrentSlot->mTimeStamp; struct tm* timeinfo; timeinfo = localtime(&time); @@ -269,24 +295,24 @@ namespace MWGui char buffer[size]; if (std::strftime(buffer, size, "%x %X", timeinfo) > 0) text << buffer << "\n"; - text << "Level " << slot->mProfile.mPlayerLevel << "\n"; - text << slot->mProfile.mPlayerCell << "\n"; + text << "Level " << mCurrentSlot->mProfile.mPlayerLevel << "\n"; + text << mCurrentSlot->mProfile.mPlayerCell << "\n"; // text << "Time played: " << slot->mProfile.mTimePlayed << "\n"; - int hour = int(slot->mProfile.mInGameTime.mGameHour); + int hour = int(mCurrentSlot->mProfile.mInGameTime.mGameHour); bool pm = hour >= 12; if (hour >= 13) hour -= 12; if (hour == 0) hour = 12; text - << slot->mProfile.mInGameTime.mDay << " " - << MWBase::Environment::get().getWorld()->getMonthName(slot->mProfile.mInGameTime.mMonth) + << mCurrentSlot->mProfile.mInGameTime.mDay << " " + << MWBase::Environment::get().getWorld()->getMonthName(mCurrentSlot->mProfile.mInGameTime.mMonth) << " " << hour << " " << (pm ? "#{sSaveMenuHelp05}" : "#{sSaveMenuHelp04}"); mInfoText->setCaptionWithReplacing(text.str()); // Decode screenshot - std::vector data = slot->mProfile.mScreenshot; // MemoryDataStream doesn't work with const data :( + std::vector data = mCurrentSlot->mProfile.mScreenshot; // MemoryDataStream doesn't work with const data :( Ogre::DataStreamPtr stream(new Ogre::MemoryDataStream(&data[0], data.size())); Ogre::Image image; image.load(stream, "jpg"); diff --git a/apps/openmw/mwgui/savegamedialog.hpp b/apps/openmw/mwgui/savegamedialog.hpp index 8d09a1cbc..42c29f4bc 100644 --- a/apps/openmw/mwgui/savegamedialog.hpp +++ b/apps/openmw/mwgui/savegamedialog.hpp @@ -6,6 +6,7 @@ namespace MWState { class Character; + class Slot; } namespace MWGui @@ -24,8 +25,15 @@ namespace MWGui void onCancelButtonClicked (MyGUI::Widget* sender); void onOkButtonClicked (MyGUI::Widget* sender); void onCharacterSelected (MyGUI::ComboBox* sender, size_t pos); + // Slot selected (mouse click or arrow keys) void onSlotSelected (MyGUI::ListBox* sender, size_t pos); + // Slot activated (double click or enter key) void onSlotActivated (MyGUI::ListBox* sender, size_t pos); + // Slot clicked with mouse + void onSlotMouseClick(MyGUI::ListBox* sender, size_t pos); + + void onDeleteSlotConfirmed(); + void onEditSelectAccept (MyGUI::EditBox* sender); void onSaveNameChanged (MyGUI::EditBox* sender); void onConfirmationGiven(); @@ -46,6 +54,7 @@ namespace MWGui MyGUI::Widget* mSpacer; const MWState::Character* mCurrentCharacter; + const MWState::Slot* mCurrentSlot; }; diff --git a/apps/openmw/mwstate/character.cpp b/apps/openmw/mwstate/character.cpp index 304eaddd3..5fe80ce0c 100644 --- a/apps/openmw/mwstate/character.cpp +++ b/apps/openmw/mwstate/character.cpp @@ -95,6 +95,21 @@ MWState::Character::Character (const boost::filesystem::path& saves, const std:: } } +void MWState::Character::cleanup() +{ + if (mSlots.size() == 0) + { + // All slots are gone, no need to keep the empty directory + if (boost::filesystem::is_directory (mPath)) + { + // Extra safety check to make sure the directory is empty (e.g. slots failed to parse header) + boost::filesystem::directory_iterator it(mPath); + if (it == boost::filesystem::directory_iterator()) + boost::filesystem::remove_all(mPath); + } + } +} + const MWState::Slot *MWState::Character::createSlot (const ESM::SavedGame& profile) { addSlot (profile); @@ -102,6 +117,21 @@ const MWState::Slot *MWState::Character::createSlot (const ESM::SavedGame& profi return &mSlots.back(); } +void MWState::Character::deleteSlot (const Slot *slot) +{ + int index = slot - &mSlots[0]; + + if (index<0 || index>=static_cast (mSlots.size())) + { + // sanity check; not entirely reliable + throw std::logic_error ("slot not found"); + } + + boost::filesystem::remove(slot->mPath); + + mSlots.erase (mSlots.begin()+index); +} + const MWState::Slot *MWState::Character::updateSlot (const Slot *slot, const ESM::SavedGame& profile) { int index = slot - &mSlots[0]; @@ -150,4 +180,4 @@ ESM::SavedGame MWState::Character::getSignature() const slot = *iter; return slot.mProfile; -} \ No newline at end of file +} diff --git a/apps/openmw/mwstate/character.hpp b/apps/openmw/mwstate/character.hpp index 61e4e5b25..874533289 100644 --- a/apps/openmw/mwstate/character.hpp +++ b/apps/openmw/mwstate/character.hpp @@ -36,11 +36,19 @@ namespace MWState Character (const boost::filesystem::path& saves, const std::string& game); + void cleanup(); + ///< Delete the directory we used, if it is empty + const Slot *createSlot (const ESM::SavedGame& profile); ///< Create new slot. /// /// \attention The ownership of the slot is not transferred. + /// \note Slot must belong to this character. + /// + /// \attention The \a slot pointer will be invalidated by this call. + void deleteSlot (const Slot *slot); + const Slot *updateSlot (const Slot *slot, const ESM::SavedGame& profile); /// \note Slot must belong to this character. /// diff --git a/apps/openmw/mwstate/charactermanager.cpp b/apps/openmw/mwstate/charactermanager.cpp index 2a40fb1cc..822e2d88e 100644 --- a/apps/openmw/mwstate/charactermanager.cpp +++ b/apps/openmw/mwstate/charactermanager.cpp @@ -47,6 +47,25 @@ MWState::Character *MWState::CharacterManager::getCurrentCharacter (bool create) return mCurrent; } +void MWState::CharacterManager::deleteSlot(const MWState::Character *character, const MWState::Slot *slot) +{ + int index = character - &mCharacters[0]; + + if (index<0 || index>=static_cast (mCharacters.size())) + throw std::logic_error ("invalid character"); + + mCharacters[index].deleteSlot(slot); + + if (mCharacters[index].begin() == mCharacters[index].end()) + { + // All slots deleted, cleanup and remove this character + mCharacters[index].cleanup(); + if (character == mCurrent) + mCurrent = NULL; + mCharacters.erase(mCharacters.begin() + index); + } +} + void MWState::CharacterManager::createCharacter() { std::ostringstream stream; diff --git a/apps/openmw/mwstate/charactermanager.hpp b/apps/openmw/mwstate/charactermanager.hpp index bc2e23f89..869d34f21 100644 --- a/apps/openmw/mwstate/charactermanager.hpp +++ b/apps/openmw/mwstate/charactermanager.hpp @@ -30,6 +30,8 @@ namespace MWState Character *getCurrentCharacter (bool create = true); ///< \param create Create a new character, if there is no current character. + void deleteSlot(const MWState::Character *character, const MWState::Slot *slot); + void createCharacter(); ///< Create new character within saved game management diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index 6fbd4bb23..635ad1ff4 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -374,6 +374,11 @@ void MWState::StateManager::quickLoad() } } +void MWState::StateManager::deleteGame(const MWState::Character *character, const MWState::Slot *slot) +{ + mCharacterManager.deleteSlot(character, slot); +} + MWState::Character *MWState::StateManager::getCurrentCharacter (bool create) { return mCharacterManager.getCurrentCharacter (create); diff --git a/apps/openmw/mwstate/statemanagerimp.hpp b/apps/openmw/mwstate/statemanagerimp.hpp index 2d3ca21fb..40c36deb5 100644 --- a/apps/openmw/mwstate/statemanagerimp.hpp +++ b/apps/openmw/mwstate/statemanagerimp.hpp @@ -44,6 +44,9 @@ namespace MWState virtual void endGame(); + virtual void deleteGame (const MWState::Character *character, const MWState::Slot *slot); + ///< Delete a saved game slot from this character. If all save slots are deleted, the character will be deleted too. + virtual void saveGame (const std::string& description, const Slot *slot = 0); ///< Write a saved game to \a slot or create a new slot if \a slot == 0. /// From 3780503275d2e3380ff10c2e91231e25402db4a0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 29 Apr 2014 07:07:03 +0200 Subject: [PATCH 102/118] Removed quicksave/quickload message boxes, now that the same text is shown in the progress bar --- apps/openmw/mwstate/statemanagerimp.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index 635ad1ff4..33f2dce7c 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -253,8 +253,6 @@ void MWState::StateManager::quickSave (std::string name) slot = &*it; } - MWBase::Environment::get().getWindowManager()->messageBox("#{sNotifyMessage4}"); - saveGame(name, slot); } @@ -368,10 +366,7 @@ void MWState::StateManager::quickLoad() { if (Character* mCurrentCharacter = getCurrentCharacter (false)) if (const MWState::Slot* slot = &*mCurrentCharacter->begin()) //Get newest save - { - //MWBase::Environment::get().getWindowManager()->messageBox("#{sLoadingMessage14}"); //it overlaps loadGame (mCurrentCharacter, slot); - } } void MWState::StateManager::deleteGame(const MWState::Character *character, const MWState::Slot *slot) From 9b36a138217389315f8be4c7b85878f1a4998c68 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 29 Apr 2014 09:09:51 +0200 Subject: [PATCH 103/118] Feature #1289: NPCs return to default position Make stationary NPCs return to their previous position once combat/crime AI finishes. --- apps/openmw/mwmechanics/actors.cpp | 12 ++++---- apps/openmw/mwmechanics/aisequence.cpp | 12 +++++++- apps/openmw/mwmechanics/aisequence.hpp | 2 +- apps/openmw/mwmechanics/aiwander.cpp | 40 +++++++++++++++++++++++++- apps/openmw/mwmechanics/aiwander.hpp | 11 +++++++ apps/openmw/mwscript/aiextensions.cpp | 16 +++++------ 6 files changed, 76 insertions(+), 17 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 2de5e268f..b87bc453c 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -206,7 +206,7 @@ namespace MWMechanics if (LOS) { - creatureStats.getAiSequence().stack(AiCombat(MWBase::Environment::get().getWorld()->getPlayerPtr())); + creatureStats.getAiSequence().stack(AiCombat(MWBase::Environment::get().getWorld()->getPlayerPtr()), ptr); creatureStats.setHostile(true); } } @@ -537,7 +537,7 @@ namespace MWMechanics // TODO: Add AI to follow player and fight for him AiFollow package(ptr.getRefData().getHandle()); - MWWorld::Class::get (ref.getPtr()).getCreatureStats (ref.getPtr()).getAiSequence().stack(package); + MWWorld::Class::get (ref.getPtr()).getCreatureStats (ref.getPtr()).getAiSequence().stack(package, ptr); // TODO: VFX_SummonStart, VFX_SummonEnd creatureStats.mSummonedCreatures.insert(std::make_pair(it->first, MWBase::Environment::get().getWorld()->safePlaceObject(ref.getPtr(),store,ipos).getRefData().getHandle())); @@ -732,7 +732,7 @@ namespace MWMechanics && MWBase::Environment::get().getWorld()->getLOS(ptr, player) && MWBase::Environment::get().getMechanicsManager()->awarenessCheck(player, ptr)) { - creatureStats.getAiSequence().stack(AiCombat(player)); + creatureStats.getAiSequence().stack(AiCombat(player), ptr); creatureStats.setHostile(true); npcStats.setCrimeId( MWBase::Environment::get().getWorld()->getPlayer().getCrimeId() ); } @@ -761,9 +761,9 @@ namespace MWMechanics else if (!creatureStats.isHostile()) { if (ptr.getClass().isClass(ptr, "Guard")) - creatureStats.getAiSequence().stack(AiPersue(player.getClass().getId(player))); + creatureStats.getAiSequence().stack(AiPersue(player.getClass().getId(player)), ptr); else - creatureStats.getAiSequence().stack(AiCombat(player)); + creatureStats.getAiSequence().stack(AiCombat(player), ptr); creatureStats.setHostile(true); } } @@ -771,7 +771,7 @@ namespace MWMechanics // if I didn't report a crime was I attacked? else if (creatureStats.getAttacked() && !creatureStats.isHostile()) { - creatureStats.getAiSequence().stack(AiCombat(player)); + creatureStats.getAiSequence().stack(AiCombat(player), ptr); creatureStats.setHostile(true); } } diff --git a/apps/openmw/mwmechanics/aisequence.cpp b/apps/openmw/mwmechanics/aisequence.cpp index c67367a6c..2581d52c9 100644 --- a/apps/openmw/mwmechanics/aisequence.cpp +++ b/apps/openmw/mwmechanics/aisequence.cpp @@ -116,8 +116,18 @@ void MWMechanics::AiSequence::clear() mPackages.clear(); } -void MWMechanics::AiSequence::stack (const AiPackage& package) +void MWMechanics::AiSequence::stack (const AiPackage& package, const MWWorld::Ptr& actor) { + if (package.getTypeId() == AiPackage::TypeIdCombat || package.getTypeId() == AiPackage::TypeIdPersue) + { + // Notify AiWander of our current position so we can return to it after combat finished + for (std::list::const_iterator iter (mPackages.begin()); iter!=mPackages.end(); ++iter) + { + if ((*iter)->getTypeId() == AiPackage::TypeIdWander) + static_cast(*iter)->setReturnPosition(Ogre::Vector3(actor.getRefData().getPosition().pos)); + } + } + for(std::list::iterator it = mPackages.begin(); it != mPackages.end(); it++) { if(mPackages.front()->getPriority() <= package.getPriority()) diff --git a/apps/openmw/mwmechanics/aisequence.hpp b/apps/openmw/mwmechanics/aisequence.hpp index 07b7c898c..cb1b0de02 100644 --- a/apps/openmw/mwmechanics/aisequence.hpp +++ b/apps/openmw/mwmechanics/aisequence.hpp @@ -62,7 +62,7 @@ namespace MWMechanics void clear(); ///< Remove all packages. - void stack (const AiPackage& package); + void stack (const AiPackage& package, const MWWorld::Ptr& actor); ///< Add \a package to the front of the sequence (suspends current package) void queue (const AiPackage& package); diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index ad94be0eb..972c4553d 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -37,6 +37,8 @@ namespace MWMechanics , mRotate(false) , mTargetAngle(0) , mSaidGreeting(false) + , mHasReturnPosition(false) + , mReturnPosition(0,0,0) { for(unsigned short counter = 0; counter < mIdle.size(); counter++) { @@ -330,6 +332,37 @@ namespace MWMechanics if(mDistance && cellChange) mDistance = 0; + // For stationary NPCs, move back to the starting location if another AiPackage moved us elsewhere + if (cellChange) + mHasReturnPosition = false; + if (mDistance == 0 && mHasReturnPosition && Ogre::Vector3(pos.pos).squaredDistance(mReturnPosition) > 20*20) + { + mChooseAction = false; + mIdleNow = false; + + Ogre::Vector3 destNodePos = mReturnPosition; + + ESM::Pathgrid::Point dest; + dest.mX = destNodePos[0]; + dest.mY = destNodePos[1]; + dest.mZ = destNodePos[2]; + + // actor position is already in world co-ordinates + ESM::Pathgrid::Point start; + start.mX = pos.pos[0]; + start.mY = pos.pos[1]; + start.mZ = pos.pos[2]; + + // don't take shortcuts for wandering + mPathFinder.buildPath(start, dest, actor.getCell(), false); + + if(mPathFinder.isPathConstructed()) + { + mMoveNow = false; + mWalking = true; + } + } + if(mChooseAction) { mPlayedIdle = 0; @@ -375,7 +408,7 @@ namespace MWMechanics } // Allow interrupting a walking actor to trigger a greeting - if(mIdleNow || (mWalking && !mObstacleCheck.isNormalState())) + if(mIdleNow || (mWalking && !mObstacleCheck.isNormalState() && mDistance)) { // Play a random voice greeting if the player gets too close int hello = cStats.getAiSetting(CreatureStats::AI_Hello).getModified(); @@ -586,5 +619,10 @@ namespace MWMechanics else return false; } + + void AiWander::setReturnPosition(const Ogre::Vector3& position) + { + mHasReturnPosition = true; mReturnPosition = position; + } } diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index fe14abeb6..a789a372e 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -2,8 +2,11 @@ #define GAME_MWMECHANICS_AIWANDER_H #include "aipackage.hpp" + #include +#include + #include "pathfinding.hpp" #include "obstacle.hpp" @@ -22,6 +25,10 @@ namespace MWMechanics virtual int getTypeId() const; ///< 0: Wander + void setReturnPosition (const Ogre::Vector3& position); + ///< Set the position to return to for a stationary (non-wandering) actor, in case + /// another AI package moved the actor elsewhere + private: void stopWalking(const MWWorld::Ptr& actor); void playIdle(const MWWorld::Ptr& actor, unsigned short idleSelect); @@ -38,6 +45,10 @@ namespace MWMechanics float mGreetDistanceReset; float mChance; + bool mHasReturnPosition; // NOTE: Could be removed if mReturnPosition was initialized to actor position, + // if we had the actor in the AiWander constructor... + Ogre::Vector3 mReturnPosition; + // Cached current cell location int mCellX; int mCellY; diff --git a/apps/openmw/mwscript/aiextensions.cpp b/apps/openmw/mwscript/aiextensions.cpp index a34c5476c..43da111bf 100644 --- a/apps/openmw/mwscript/aiextensions.cpp +++ b/apps/openmw/mwscript/aiextensions.cpp @@ -48,7 +48,7 @@ namespace MWScript for (unsigned int i=0; igetPtr(targetID, true) )); + MWMechanics::AiCombat(MWBase::Environment::get().getWorld()->getPtr(targetID, true) ), actor); } }; From 28ef236f0e878523f0c36544136d2516d14764ee Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 29 Apr 2014 11:17:07 +0200 Subject: [PATCH 104/118] Don't allow setting a new return position if there already is one and we haven't reached it yet --- apps/openmw/mwmechanics/aiwander.cpp | 48 ++++++++++++++++------------ 1 file changed, 28 insertions(+), 20 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 722010686..7120ff5af 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -341,26 +341,29 @@ namespace MWMechanics mChooseAction = false; mIdleNow = false; - Ogre::Vector3 destNodePos = mReturnPosition; - - ESM::Pathgrid::Point dest; - dest.mX = destNodePos[0]; - dest.mY = destNodePos[1]; - dest.mZ = destNodePos[2]; - - // actor position is already in world co-ordinates - ESM::Pathgrid::Point start; - start.mX = pos.pos[0]; - start.mY = pos.pos[1]; - start.mZ = pos.pos[2]; - - // don't take shortcuts for wandering - mPathFinder.buildPath(start, dest, actor.getCell(), false); - - if(mPathFinder.isPathConstructed()) + if (!mPathFinder.isPathConstructed()) { - mMoveNow = false; - mWalking = true; + Ogre::Vector3 destNodePos = mReturnPosition; + + ESM::Pathgrid::Point dest; + dest.mX = destNodePos[0]; + dest.mY = destNodePos[1]; + dest.mZ = destNodePos[2]; + + // actor position is already in world co-ordinates + ESM::Pathgrid::Point start; + start.mX = pos.pos[0]; + start.mY = pos.pos[1]; + start.mZ = pos.pos[2]; + + // don't take shortcuts for wandering + mPathFinder.buildPath(start, dest, actor.getCell(), false); + + if(mPathFinder.isPathConstructed()) + { + mMoveNow = false; + mWalking = true; + } } } @@ -529,6 +532,7 @@ namespace MWMechanics mMoveNow = false; mWalking = false; mChooseAction = true; + mHasReturnPosition = false; } return false; // AiWander package not yet completed @@ -615,7 +619,11 @@ namespace MWMechanics void AiWander::setReturnPosition(const Ogre::Vector3& position) { - mHasReturnPosition = true; mReturnPosition = position; + if (!mHasReturnPosition) + { + mHasReturnPosition = true; + mReturnPosition = position; + } } void AiWander::getRandomIdle() From 2906ade5316099ed899906d26eb66391a72aed45 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 29 Apr 2014 13:16:58 +0200 Subject: [PATCH 105/118] string fix --- apps/opencs/editor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/editor.cpp b/apps/opencs/editor.cpp index 2dfdb1de6..f6370ac51 100644 --- a/apps/opencs/editor.cpp +++ b/apps/opencs/editor.cpp @@ -121,7 +121,7 @@ std::pair > CS::Editor::readConfi //iterate the data directories and add them to the file dialog for loading for (Files::PathContainer::const_iterator iter = dataDirs.begin(); iter != dataDirs.end(); ++iter) { - QString path = QString::fromStdString(iter->string()); + QString path = QString::fromUtf8 (iter->string().c_str()); mFileDialog.addFiles(path); } /* From 7d990abd376891c91c233410c4e06e66ae926eff Mon Sep 17 00:00:00 2001 From: cc9cii Date: Tue, 29 Apr 2014 22:46:55 +1000 Subject: [PATCH 106/118] OpenCS changes to allow compilation with MSVC 11.0. --- apps/opencs/model/settings/usersettings.cpp | 6 +++--- apps/opencs/view/world/dialoguesubview.cpp | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/opencs/model/settings/usersettings.cpp b/apps/opencs/model/settings/usersettings.cpp index 2f8e8098d..fa89fceee 100644 --- a/apps/opencs/model/settings/usersettings.cpp +++ b/apps/opencs/model/settings/usersettings.cpp @@ -195,13 +195,13 @@ CSMSettings::UserSettings::~UserSettings() void CSMSettings::UserSettings::loadSettings (const QString &fileName) { mUserFilePath = QString::fromUtf8 - (mCfgMgr.getUserConfigPath().c_str()) + fileName.toUtf8(); + (mCfgMgr.getUserConfigPath().string().c_str()) + fileName.toUtf8(); QString global = QString::fromUtf8 - (mCfgMgr.getGlobalPath().c_str()) + fileName.toUtf8(); + (mCfgMgr.getGlobalPath().string().c_str()) + fileName.toUtf8(); QString local = QString::fromUtf8 - (mCfgMgr.getLocalPath().c_str()) + fileName.toUtf8(); + (mCfgMgr.getLocalPath().string().c_str()) + fileName.toUtf8(); //open user and global streams QTextStream *userStream = openFilestream (mUserFilePath, true); diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index abdc33103..d03bf3f80 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -183,7 +183,7 @@ CSVWorld::CommandDelegate* CSVWorld::DialogueDelegateDispatcher::makeDelegate(CS { delegate = CommandDelegateFactoryCollection::get().makeDelegate ( display, mUndoStack, mParent); - mDelegates.insert(std::make_pair(display, delegate)); + mDelegates.insert(std::make_pair(display, delegate)); } else { delegate = delegateIt->second; From e8f7d12c01300fe703c6439db05ebca9cabfc580 Mon Sep 17 00:00:00 2001 From: mrcheko Date: Wed, 30 Apr 2014 23:57:19 +0400 Subject: [PATCH 107/118] uninit bool and invalid iterator bugs fixes --- apps/openmw/mwmechanics/aicombat.cpp | 6 +++--- apps/openmw/mwmechanics/aiwander.cpp | 4 ++-- apps/openmw/mwmechanics/aiwander.hpp | 2 +- apps/openmw/mwmechanics/pathfinding.hpp | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index d0555cdc3..fdaec28b4 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -392,7 +392,7 @@ namespace MWMechanics else // remote pathfinding { bool preferShortcut = false; - bool inLOS; + bool inLOS = MWBase::Environment::get().getWorld()->getLOS(actor, mTarget); if(mReadyToAttack) isStuck = false; @@ -400,7 +400,7 @@ namespace MWMechanics if(!isStuck && (!mForceNoShortcut || (Ogre::Vector3(mShortcutFailPos.pos) - vActorPos).length() >= PATHFIND_SHORTCUT_RETRY_DIST) - && (inLOS = MWBase::Environment::get().getWorld()->getLOS(actor, mTarget))) + && inLOS) { if(speed == 0.0f) speed = actorCls.getSpeed(actor); // maximum dist before pit/obstacle for actor to avoid them depending on his speed @@ -437,7 +437,7 @@ namespace MWMechanics if(inLOS && mPathFinder.getPath().size() > 1) { // get point just before target - std::list::iterator pntIter = --mPathFinder.getPath().end(); + std::list::const_iterator pntIter = --mPathFinder.getPath().end(); --pntIter; Ogre::Vector3 vBeforeTarget = Ogre::Vector3(pntIter->mX, pntIter->mY, pntIter->mZ); diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 7120ff5af..f95c858c9 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -539,14 +539,14 @@ namespace MWMechanics } void AiWander::trimAllowedNodes(std::vector& nodes, - const PathFinder& pathfinder) + PathFinder& pathfinder) { // TODO: how to add these back in once the door opens? // Idea: keep a list of detected closed doors (see aicombat.cpp) // Every now and then check whether one of the doors is opened. (maybe // at the end of playing idle?) If the door is opened then re-calculate // allowed nodes starting from the spawn point. - std::list paths = pathfinder.getPath(); + std::list& paths = pathfinder.getPath(); while(paths.size() >= 2) { ESM::Pathgrid::Point pt = paths.back(); diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index 2975c8315..3be74010d 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -77,7 +77,7 @@ namespace MWMechanics ESM::Pathgrid::Point mCurrentNode; bool mTrimCurrentNode; void trimAllowedNodes(std::vector& nodes, - const PathFinder& pathfinder); + PathFinder& pathfinder); PathFinder mPathFinder; diff --git a/apps/openmw/mwmechanics/pathfinding.hpp b/apps/openmw/mwmechanics/pathfinding.hpp index 97bb88c52..ec9c86754 100644 --- a/apps/openmw/mwmechanics/pathfinding.hpp +++ b/apps/openmw/mwmechanics/pathfinding.hpp @@ -57,7 +57,7 @@ namespace MWMechanics return mPath.size(); } - std::list getPath() const + std::list& getPath() { return mPath; } From 9e79fb5b87c8513792212f398ad6068e717823b5 Mon Sep 17 00:00:00 2001 From: mrcheko Date: Thu, 1 May 2014 11:41:25 +0400 Subject: [PATCH 108/118] fix to broken aiwander logic --- apps/openmw/mwmechanics/aiwander.cpp | 4 ++-- apps/openmw/mwmechanics/aiwander.hpp | 2 +- apps/openmw/mwmechanics/pathfinding.hpp | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index f95c858c9..7120ff5af 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -539,14 +539,14 @@ namespace MWMechanics } void AiWander::trimAllowedNodes(std::vector& nodes, - PathFinder& pathfinder) + const PathFinder& pathfinder) { // TODO: how to add these back in once the door opens? // Idea: keep a list of detected closed doors (see aicombat.cpp) // Every now and then check whether one of the doors is opened. (maybe // at the end of playing idle?) If the door is opened then re-calculate // allowed nodes starting from the spawn point. - std::list& paths = pathfinder.getPath(); + std::list paths = pathfinder.getPath(); while(paths.size() >= 2) { ESM::Pathgrid::Point pt = paths.back(); diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index 3be74010d..2975c8315 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -77,7 +77,7 @@ namespace MWMechanics ESM::Pathgrid::Point mCurrentNode; bool mTrimCurrentNode; void trimAllowedNodes(std::vector& nodes, - PathFinder& pathfinder); + const PathFinder& pathfinder); PathFinder mPathFinder; diff --git a/apps/openmw/mwmechanics/pathfinding.hpp b/apps/openmw/mwmechanics/pathfinding.hpp index ec9c86754..29577542e 100644 --- a/apps/openmw/mwmechanics/pathfinding.hpp +++ b/apps/openmw/mwmechanics/pathfinding.hpp @@ -57,7 +57,7 @@ namespace MWMechanics return mPath.size(); } - std::list& getPath() + const std::list& getPath() const { return mPath; } From 36914b43d776ce0dde24df6c5acf0972d8f19289 Mon Sep 17 00:00:00 2001 From: Sandy Date: Thu, 1 May 2014 08:19:05 -0400 Subject: [PATCH 109/118] Remove install of License of no longer used font --- CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 392fdfc66..bd45a207c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -434,7 +434,6 @@ IF(NOT WIN32 AND NOT APPLE) # Install licenses INSTALL(FILES "DejaVu Font License.txt" DESTINATION "${LICDIR}" ) - INSTALL(FILES "OFL.txt" DESTINATION "${LICDIR}" ) INSTALL(FILES "extern/shiny/License.txt" DESTINATION "${LICDIR}" RENAME "Shiny License.txt" ) ENDIF (DPKG_PROGRAM) From 5415ca6a6311215b5b3aab84526d7044f7c6280f Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 29 Apr 2014 13:04:09 +0200 Subject: [PATCH 110/118] Fix exception when shift+click on empty space in save dialog --- apps/openmw/mwgui/savegamedialog.cpp | 2 +- apps/openmw/mwgui/statswindow.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/savegamedialog.cpp b/apps/openmw/mwgui/savegamedialog.cpp index 74ccc82f4..a77c625f9 100644 --- a/apps/openmw/mwgui/savegamedialog.cpp +++ b/apps/openmw/mwgui/savegamedialog.cpp @@ -53,7 +53,7 @@ namespace MWGui { onSlotSelected(sender, pos); - if (MyGUI::InputManager::getInstance().isShiftPressed()) + if (pos != MyGUI::ITEM_NONE && MyGUI::InputManager::getInstance().isShiftPressed()) { ConfirmationDialog* dialog = MWBase::Environment::get().getWindowManager()->getConfirmationDialog(); dialog->open("#{sMessage3}"); diff --git a/apps/openmw/mwgui/statswindow.cpp b/apps/openmw/mwgui/statswindow.cpp index 3d4c741a3..31a3b6fdd 100644 --- a/apps/openmw/mwgui/statswindow.cpp +++ b/apps/openmw/mwgui/statswindow.cpp @@ -475,7 +475,7 @@ namespace MWGui text += std::string("#DDC79E") + faction->mName; if (expelled.find(it->first) != expelled.end()) - text += "\n#{sExpelled}"; + text += "\n#BF9959#{sExpelled}"; else { text += std::string("\n#BF9959") + faction->mRanks[it->second]; From f99eda1a543c79bad59e23e9ed5a0fcd9215644d Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 30 Apr 2014 13:34:06 +0200 Subject: [PATCH 111/118] Fixes #1302: Do not attempt to set OnPcAdd before the script has been added --- apps/openmw/mwworld/containerstore.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index b1cbcc9c2..eb6760d14 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -231,6 +231,8 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::add (const Ptr& itemPtr { CellStore *cell; + MWBase::Environment::get().getWorld()->getLocalScripts().add(script, item); + if(&(MWWorld::Class::get (player).getContainerStore (player)) == this) { cell = 0; // Items in player's inventory have cell set to 0, so their scripts will never be removed @@ -243,7 +245,6 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::add (const Ptr& itemPtr item.mCell = cell; item.mContainerStore = 0; - MWBase::Environment::get().getWorld()->getLocalScripts().add(script, item); } return it; From 6f7fbc867f6e4ba8acb9fe03d7169c819cfecf91 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 30 Apr 2014 21:15:14 +0200 Subject: [PATCH 112/118] Fix several leaks --- apps/openmw/mwgui/inventorywindow.cpp | 10 +++++----- apps/openmw/mwgui/inventorywindow.hpp | 4 ++-- apps/openmw/mwrender/characterpreview.hpp | 4 ++++ apps/openmw/mwrender/ripplesimulation.cpp | 5 ++++- components/ogreinit/ogreinit.cpp | 1 + components/terrain/world.cpp | 2 ++ files/mygui/openmw_text.skin.xml | 16 ---------------- 7 files changed, 18 insertions(+), 24 deletions(-) diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index e9efe75e7..2bea088e3 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -35,7 +35,7 @@ namespace MWGui , mTrading(false) , mLastXSize(0) , mLastYSize(0) - , mPreview(MWBase::Environment::get().getWorld ()->getPlayerPtr()) + , mPreview(new MWRender::InventoryPreview(MWBase::Environment::get().getWorld ()->getPlayerPtr())) , mPreviewDirty(true) , mDragAndDrop(dragAndDrop) , mSelectedItem(-1) @@ -91,8 +91,8 @@ namespace MWGui mTradeModel = new TradeItemModel(new InventoryItemModel(mPtr), MWWorld::Ptr()); mSortModel = new SortFilterItemModel(mTradeModel); mItemView->setModel(mSortModel); - mPreview = MWRender::InventoryPreview(mPtr); - mPreview.setup(); + mPreview.reset(new MWRender::InventoryPreview(mPtr)); + mPreview->setup(); } void InventoryWindow::setGuiMode(GuiMode mode) @@ -444,7 +444,7 @@ namespace MWGui MWWorld::Ptr InventoryWindow::getAvatarSelectedItem(int x, int y) { - int slot = mPreview.getSlotSelected (x, y); + int slot = mPreview->getSlotSelected (x, y); if (slot == -1) return MWWorld::Ptr(); @@ -493,7 +493,7 @@ namespace MWGui mPreviewDirty = false; MyGUI::IntSize size = mAvatarImage->getSize(); - mPreview.update (size.width, size.height); + mPreview->update (size.width, size.height); mAvatarImage->setImageTexture("CharacterPreview"); mAvatarImage->setImageCoord(MyGUI::IntCoord(0, 0, std::min(512, size.width), std::min(1024, size.height))); diff --git a/apps/openmw/mwgui/inventorywindow.hpp b/apps/openmw/mwgui/inventorywindow.hpp index 7ef168e98..c23a74efa 100644 --- a/apps/openmw/mwgui/inventorywindow.hpp +++ b/apps/openmw/mwgui/inventorywindow.hpp @@ -34,7 +34,7 @@ namespace MWGui MWWorld::Ptr getAvatarSelectedItem(int x, int y); void rebuildAvatar() { - mPreview.rebuild(); + mPreview->rebuild(); } TradeItemModel* getTradeModel(); @@ -81,7 +81,7 @@ namespace MWGui int mLastXSize; int mLastYSize; - MWRender::InventoryPreview mPreview; + std::auto_ptr mPreview; bool mTrading; diff --git a/apps/openmw/mwrender/characterpreview.hpp b/apps/openmw/mwrender/characterpreview.hpp index 16e6ab017..60312455f 100644 --- a/apps/openmw/mwrender/characterpreview.hpp +++ b/apps/openmw/mwrender/characterpreview.hpp @@ -34,6 +34,10 @@ namespace MWRender virtual void rebuild(); + private: + CharacterPreview(const CharacterPreview&); + CharacterPreview& operator=(const CharacterPreview&); + protected: virtual bool renderHeadOnly() { return false; } diff --git a/apps/openmw/mwrender/ripplesimulation.cpp b/apps/openmw/mwrender/ripplesimulation.cpp index f52deedcc..74216c1de 100644 --- a/apps/openmw/mwrender/ripplesimulation.cpp +++ b/apps/openmw/mwrender/ripplesimulation.cpp @@ -28,7 +28,9 @@ RippleSimulation::RippleSimulation(Ogre::SceneManager* mainSceneManager) mRippleAreaLength(1000), mImpulseSize(20), mTexelOffset(0,0), - mFirstUpdate(true) + mFirstUpdate(true), + mRectangle(NULL), + mImpulse(NULL) { Ogre::AxisAlignedBox aabInf; aabInf.setInfinite(); @@ -105,6 +107,7 @@ RippleSimulation::RippleSimulation(Ogre::SceneManager* mainSceneManager) RippleSimulation::~RippleSimulation() { delete mRectangle; + delete mImpulse; Ogre::Root::getSingleton().destroySceneManager(mSceneMgr); } diff --git a/components/ogreinit/ogreinit.cpp b/components/ogreinit/ogreinit.cpp index 1b9a899a0..01b8764c2 100644 --- a/components/ogreinit/ogreinit.cpp +++ b/components/ogreinit/ogreinit.cpp @@ -62,6 +62,7 @@ namespace OgreInit OgreInit::~OgreInit() { delete mRoot; + delete Ogre::LogManager::getSingletonPtr(); std::vector::iterator ei; for(ei = mEmitterFactories.begin();ei != mEmitterFactories.end();++ei) diff --git a/components/terrain/world.cpp b/components/terrain/world.cpp index 844144d7c..3d968470f 100644 --- a/components/terrain/world.cpp +++ b/components/terrain/world.cpp @@ -337,6 +337,8 @@ namespace Terrain it->mTarget->loadLayers(*it); } + delete data; + mRootNode->loadMaterials(); mLayerLoadPending = false; diff --git a/files/mygui/openmw_text.skin.xml b/files/mygui/openmw_text.skin.xml index b80859ea1..d4c72c75b 100644 --- a/files/mygui/openmw_text.skin.xml +++ b/files/mygui/openmw_text.skin.xml @@ -49,22 +49,6 @@ - - - - - - - - - - - - - - - - From 64a30ad182bdb4caec160b6fd1d53b0caab9e8b5 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 1 May 2014 12:44:31 +0200 Subject: [PATCH 113/118] Fix another leak --- apps/openmw/mwgui/fontloader.cpp | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwgui/fontloader.cpp b/apps/openmw/mwgui/fontloader.cpp index 7a6317c16..59c2e7ca6 100644 --- a/apps/openmw/mwgui/fontloader.cpp +++ b/apps/openmw/mwgui/fontloader.cpp @@ -196,6 +196,16 @@ namespace MWGui bitmapFile->read(&textureData[0], width*height*4); bitmapFile->close(); + std::string resourceName; + if (name.size() >= 5 && Misc::StringUtils::ciEqual(name.substr(0, 5), "magic")) + resourceName = "Magic Cards"; + else if (name.size() >= 7 && Misc::StringUtils::ciEqual(name.substr(0, 7), "century")) + resourceName = "Century Gothic"; + else if (name.size() >= 7 && Misc::StringUtils::ciEqual(name.substr(0, 7), "daedric")) + resourceName = "Daedric"; + else + return; // no point in loading it, since there is no way of using additional fonts + std::string textureName = name; Ogre::Image image; image.loadDynamicImage(&textureData[0], width, height, Ogre::PF_BYTE_RGBA); @@ -208,18 +218,11 @@ namespace MWGui // Register the font with MyGUI MyGUI::ResourceManualFont* font = static_cast( MyGUI::FactoryManager::getInstance().createObject("Resource", "ResourceManualFont")); + // We need to emulate loading from XML because the data members are private as of mygui 3.2.0 MyGUI::xml::Document xmlDocument; MyGUI::xml::ElementPtr root = xmlDocument.createRoot("ResourceManualFont"); - - if (name.size() >= 5 && Misc::StringUtils::ciEqual(name.substr(0, 5), "magic")) - root->addAttribute("name", "Magic Cards"); - else if (name.size() >= 7 && Misc::StringUtils::ciEqual(name.substr(0, 7), "century")) - root->addAttribute("name", "Century Gothic"); - else if (name.size() >= 7 && Misc::StringUtils::ciEqual(name.substr(0, 7), "daedric")) - root->addAttribute("name", "Daedric"); - else - return; // no point in loading it, since there is no way of using additional fonts + root->addAttribute("name", resourceName); MyGUI::xml::ElementPtr defaultHeight = root->createChild("Property"); defaultHeight->addAttribute("key", "DefaultHeight"); @@ -285,6 +288,7 @@ namespace MWGui font->deserialization(root, MyGUI::Version(3,2,0)); + MyGUI::ResourceManager::getInstance().removeByName(font->getResourceName()); MyGUI::ResourceManager::getInstance().addResource(font); } From fc7e79027af9df32276211b9f8306c73cb51f1e4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 1 May 2014 16:44:39 +0200 Subject: [PATCH 114/118] Fixes #1144: Don't refreshCurrentAnims when adding already dead actors --- apps/openmw/mwmechanics/character.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 8ad2b4a67..280639f71 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -489,12 +489,13 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim mIdleState = CharState_Idle; } - refreshCurrentAnims(mIdleState, mMovementState, true); if(mDeathState != CharState_None) { playRandomDeath(1.0f); } + else + refreshCurrentAnims(mIdleState, mMovementState, true); } CharacterController::~CharacterController() From 17bb8d7f9a84fbe5106ab97fbe4407f327b34097 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 1 May 2014 21:16:32 +0200 Subject: [PATCH 115/118] Fixes #1252: Add item/magic keybindings to savegame --- apps/openmw/mwbase/windowmanager.hpp | 1 + apps/openmw/mwgui/quickkeysmenu.cpp | 119 +++++++++++++++++++++++- apps/openmw/mwgui/quickkeysmenu.hpp | 5 + apps/openmw/mwgui/windowmanagerimp.cpp | 15 ++- apps/openmw/mwgui/windowmanagerimp.hpp | 1 + apps/openmw/mwstate/statemanagerimp.cpp | 4 +- components/esm/defs.hpp | 7 ++ 7 files changed, 144 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 4287e466b..c78902a60 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -305,6 +305,7 @@ namespace MWBase virtual void write (ESM::ESMWriter& writer, Loading::Listener& progress) = 0; virtual void readRecord (ESM::ESMReader& reader, int32_t type) = 0; + virtual int countSavedGameRecords() const = 0; }; } diff --git a/apps/openmw/mwgui/quickkeysmenu.cpp b/apps/openmw/mwgui/quickkeysmenu.cpp index dc7226909..fb41b3b67 100644 --- a/apps/openmw/mwgui/quickkeysmenu.cpp +++ b/apps/openmw/mwgui/quickkeysmenu.cpp @@ -55,6 +55,14 @@ namespace MWGui } } + void QuickKeysMenu::clear() + { + for (int i=0; i<10; ++i) + { + unassign(mQuickKeyButtons[i], i); + } + } + QuickKeysMenu::~QuickKeysMenu() { delete mAssignDialog; @@ -154,8 +162,6 @@ namespace MWGui frame->setUserString ("ToolTipType", "ItemPtr"); frame->setUserData(item); frame->eventMouseButtonClick += MyGUI::newDelegate(this, &QuickKeysMenu::onQuickKeyButtonClicked); - - MyGUI::ImageBox* image = frame->createWidget("ImageBox", MyGUI::IntCoord(5, 5, 32, 32), MyGUI::Align::Default); std::string path = std::string("icons\\"); path += MWWorld::Class::get(item).getInventoryIcon(item); @@ -165,7 +171,8 @@ namespace MWGui image->setImageTexture (path); image->setNeedMouseFocus (false); - mItemSelectionDialog->setVisible(false); + if (mItemSelectionDialog) + mItemSelectionDialog->setVisible(false); } void QuickKeysMenu::onAssignItemCancel() @@ -198,7 +205,8 @@ namespace MWGui image->setImageTexture (path); image->setNeedMouseFocus (false); - mMagicSelectionDialog->setVisible(false); + if (mMagicSelectionDialog) + mMagicSelectionDialog->setVisible(false); } void QuickKeysMenu::onAssignMagic (const std::string& spellId) @@ -239,7 +247,8 @@ namespace MWGui image->setImageTexture (path); image->setNeedMouseFocus (false); - mMagicSelectionDialog->setVisible(false); + if (mMagicSelectionDialog) + mMagicSelectionDialog->setVisible(false); } void QuickKeysMenu::onAssignMagicCancel () @@ -374,6 +383,106 @@ namespace MWGui center(); } + void QuickKeysMenu::write(ESM::ESMWriter &writer) + { + const std::string recKey = "KEY_"; + writer.startRecord(ESM::REC_KEYS); + + for (int i=0; i<10; ++i) + { + writer.startSubRecord(recKey); + + MyGUI::Button* button = mQuickKeyButtons[i]; + + int type = *button->getUserData(); + writer.writeHNT("TYPE", type); + + switch (type) + { + case Type_Unassigned: + writer.writeHNString("ID__", ""); + break; + case Type_Item: + case Type_MagicItem: + { + MWWorld::Ptr item = *button->getChildAt(0)->getUserData(); + writer.writeHNString("ID__", item.getCellRef().mRefID); + break; + } + case Type_Magic: + std::string spellId = button->getChildAt(0)->getUserString("Spell"); + writer.writeHNString("ID__", spellId); + break; + } + + writer.endRecord(recKey); + } + + writer.endRecord(ESM::REC_KEYS); + } + + void QuickKeysMenu::readRecord(ESM::ESMReader &reader, int32_t type) + { + if (type != ESM::REC_KEYS) + return; + + int i=0; + while (reader.isNextSub("KEY_")) + { + reader.getSubHeader(); + int keyType; + reader.getHNT(keyType, "TYPE"); + std::string id; + id = reader.getHNString("ID__"); + + mSelectedIndex = i; + + MyGUI::Button* button = mQuickKeyButtons[i]; + + switch (keyType) + { + case Type_Magic: + onAssignMagic(id); + break; + case Type_Item: + case Type_MagicItem: + { + // Find the item by id + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::InventoryStore& store = player.getClass().getInventoryStore(player); + MWWorld::Ptr item; + for (MWWorld::ContainerStoreIterator it = store.begin(); it != store.end(); ++it) + { + if (Misc::StringUtils::ciEqual(it->getCellRef().mRefID, id)) + { + if (item.isEmpty() || + // Prefer the stack with the lowest remaining uses + (it->getCellRef().mCharge != -1 && (item.getCellRef().mCharge == -1 || it->getCellRef().mCharge < item.getCellRef().mCharge) )) + { + item = *it; + } + } + } + + if (item.isEmpty()) + unassign(button, i); + else + { + if (keyType == Type_Item) + onAssignItem(item); + else if (keyType == Type_MagicItem) + onAssignMagicItem(item); + } + + break; + } + case Type_Unassigned: + unassign(button, i); + break; + } + ++i; + } + } // --------------------------------------------------------------------------------------------------------- diff --git a/apps/openmw/mwgui/quickkeysmenu.hpp b/apps/openmw/mwgui/quickkeysmenu.hpp index 058519ece..c0e25a517 100644 --- a/apps/openmw/mwgui/quickkeysmenu.hpp +++ b/apps/openmw/mwgui/quickkeysmenu.hpp @@ -41,6 +41,11 @@ namespace MWGui }; + void write (ESM::ESMWriter& writer); + void readRecord (ESM::ESMReader& reader, int32_t type); + void clear(); + + private: MyGUI::EditBox* mInstructionLabel; MyGUI::Button* mOkButton; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index e2e4e157c..1b4145e5c 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1405,16 +1405,29 @@ namespace MWGui void WindowManager::clear() { mMap->clear(); + mQuickKeysMenu->clear(); } void WindowManager::write(ESM::ESMWriter &writer, Loading::Listener& progress) { mMap->write(writer, progress); + + mQuickKeysMenu->write(writer); + progress.increaseProgress(); } void WindowManager::readRecord(ESM::ESMReader &reader, int32_t type) { - mMap->readRecord(reader, type); + if (type == ESM::REC_GMAP) + mMap->readRecord(reader, type); + else if (type == ESM::REC_KEYS) + mQuickKeysMenu->readRecord(reader, type); + } + + int WindowManager::countSavedGameRecords() const + { + return 1 // Global map + + 1; // QuickKeysMenu } void WindowManager::playVideo(const std::string &name, bool allowSkipping) diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 064ca89ba..44bc56654 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -293,6 +293,7 @@ namespace MWGui virtual void write (ESM::ESMWriter& writer, Loading::Listener& progress); virtual void readRecord (ESM::ESMReader& reader, int32_t type); + virtual int countSavedGameRecords() const; private: bool mConsoleOnlyScripts; diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index 33f2dce7c..48d12f0a6 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -201,7 +201,7 @@ void MWState::StateManager::saveGame (const std::string& description, const Slot +MWBase::Environment::get().getWorld()->countSavedGameRecords() +MWBase::Environment::get().getScriptManager()->getGlobalScripts().countSavedGameRecords() +MWBase::Environment::get().getDialogueManager()->countSavedGameRecords() - +1; // global map + +MWBase::Environment::get().getWindowManager()->countSavedGameRecords(); writer.setRecordCount (recordCount); writer.save (stream); @@ -323,7 +323,7 @@ void MWState::StateManager::loadGame (const Character *character, const Slot *sl break; case ESM::REC_GMAP: - + case ESM::REC_KEYS: MWBase::Environment::get().getWindowManager()->readRecord(reader, n.val); break; diff --git a/components/esm/defs.hpp b/components/esm/defs.hpp index 4d5b36c74..b2a1637f1 100644 --- a/components/esm/defs.hpp +++ b/components/esm/defs.hpp @@ -34,6 +34,12 @@ struct Position }; #pragma pack(pop) +template +struct FourCC +{ + static const unsigned int value = (((((d << 8) | c) << 8) | b) << 8) | a; +}; + enum RecNameInts { // format 0 / legacy @@ -93,6 +99,7 @@ enum RecNameInts REC_GMAP = 0x50414d47, REC_DIAS = 0x53414944, REC_WTHR = 0x52485457, + REC_KEYS = FourCC<'K','E','Y','S'>::value, // format 1 REC_FILT = 0x544C4946 From 6381b1e9381436a22c8a3af212bd4b4145607529 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 2 May 2014 11:20:43 +0200 Subject: [PATCH 116/118] Fixes #1309: Do not allow saving while dialogs are opened, just like vanilla This limitation could be removed post-1.0 by serializing the state of open windows. --- apps/openmw/mwbase/windowmanager.hpp | 3 +++ apps/openmw/mwgui/mainmenu.cpp | 3 ++- apps/openmw/mwgui/referenceinterface.hpp | 2 ++ apps/openmw/mwgui/windowmanagerimp.cpp | 20 ++++++++++++++++++++ apps/openmw/mwgui/windowmanagerimp.hpp | 3 +++ apps/openmw/mwstate/statemanagerimp.cpp | 5 +++-- 6 files changed, 33 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index c78902a60..9e5230af6 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -306,6 +306,9 @@ namespace MWBase virtual void write (ESM::ESMWriter& writer, Loading::Listener& progress) = 0; virtual void readRecord (ESM::ESMReader& reader, int32_t type) = 0; virtual int countSavedGameRecords() const = 0; + + /// Does the current stack of GUI-windows permit saving? + virtual bool isSavingAllowed() const = 0; }; } diff --git a/apps/openmw/mwgui/mainmenu.cpp b/apps/openmw/mwgui/mainmenu.cpp index df9c53ea8..8b44af2ef 100644 --- a/apps/openmw/mwgui/mainmenu.cpp +++ b/apps/openmw/mwgui/mainmenu.cpp @@ -170,7 +170,8 @@ namespace MWGui buttons.push_back("loadgame"); if (state==MWBase::StateManager::State_Running && - MWBase::Environment::get().getWorld()->getGlobalInt ("chargenstate")==-1) + MWBase::Environment::get().getWorld()->getGlobalInt ("chargenstate")==-1 && + MWBase::Environment::get().getWindowManager()->isSavingAllowed()) buttons.push_back("savegame"); buttons.push_back("options"); diff --git a/apps/openmw/mwgui/referenceinterface.hpp b/apps/openmw/mwgui/referenceinterface.hpp index 39574d0f7..df53a42b7 100644 --- a/apps/openmw/mwgui/referenceinterface.hpp +++ b/apps/openmw/mwgui/referenceinterface.hpp @@ -17,6 +17,8 @@ namespace MWGui void checkReferenceAvailable(); ///< closes the window, if the MW-reference has become unavailable + void resetReference() { mPtr = MWWorld::Ptr(); mCurrentPlayerCell = NULL; } + protected: virtual void onReferenceUnavailable() = 0; ///< called when reference has become unavailable diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 1b4145e5c..d2a31e8d1 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1406,6 +1406,19 @@ namespace MWGui { mMap->clear(); mQuickKeysMenu->clear(); + + mTrainingWindow->resetReference(); + mDialogueWindow->resetReference(); + mTradeWindow->resetReference(); + mSpellBuyingWindow->resetReference(); + mSpellCreationDialog->resetReference(); + mEnchantingDialog->resetReference(); + mContainerWindow->resetReference(); + mCompanionWindow->resetReference(); + mConsole->resetReference(); + + mGuiModes.clear(); + updateVisible(); } void WindowManager::write(ESM::ESMWriter &writer, Loading::Listener& progress) @@ -1430,6 +1443,13 @@ namespace MWGui + 1; // QuickKeysMenu } + bool WindowManager::isSavingAllowed() const + { + return !MyGUI::InputManager::getInstance().isModalAny() + // TODO: remove this, once we have properly serialized the state of open windows + && (!isGuiMode() || (mGuiModes.size() == 1 && getMode() == GM_MainMenu)); + } + void WindowManager::playVideo(const std::string &name, bool allowSkipping) { mVideoWidget->playVideo("video\\" + name, allowSkipping); diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 44bc56654..e31013b45 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -295,6 +295,9 @@ namespace MWGui virtual void readRecord (ESM::ESMReader& reader, int32_t type); virtual int countSavedGameRecords() const; + /// Does the current stack of GUI-windows permit saving? + virtual bool isSavingAllowed() const; + private: bool mConsoleOnlyScripts; diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index 48d12f0a6..c718eeced 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -235,8 +235,9 @@ void MWState::StateManager::saveGame (const std::string& description, const Slot void MWState::StateManager::quickSave (std::string name) { - if (mState!=State_Running || - MWBase::Environment::get().getWorld()->getGlobalInt ("chargenstate")!=-1) // char gen + if (!(mState==State_Running && + MWBase::Environment::get().getWorld()->getGlobalInt ("chargenstate")==-1 // char gen + && MWBase::Environment::get().getWindowManager()->isSavingAllowed())) { //You can not save your game right now MWBase::Environment::get().getWindowManager()->messageBox("#{sSaveGameDenied}"); From f8cc328b5e63e2eed325cde7b97bc7ee1d8bacb7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 2 May 2014 11:26:05 +0200 Subject: [PATCH 117/118] Slightly prettier backdrop when loading game from main menu. --- apps/openmw/mwgui/savegamedialog.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwgui/savegamedialog.cpp b/apps/openmw/mwgui/savegamedialog.cpp index a77c625f9..c0daa2c0e 100644 --- a/apps/openmw/mwgui/savegamedialog.cpp +++ b/apps/openmw/mwgui/savegamedialog.cpp @@ -206,6 +206,13 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->messageBox("#{sNotifyMessage65}"); return; } + } + + setVisible(false); + MWBase::Environment::get().getWindowManager()->removeGuiMode (MWGui::GM_MainMenu); + + if (mSaving) + { MWBase::Environment::get().getStateManager()->saveGame (mSaveNameEdit->getCaption(), mCurrentSlot); } else @@ -213,12 +220,9 @@ namespace MWGui if (mCurrentCharacter && mCurrentSlot) { MWBase::Environment::get().getStateManager()->loadGame (mCurrentCharacter, mCurrentSlot); - MWBase::Environment::get().getWindowManager()->removeGuiMode (MWGui::GM_MainMenu); } } - setVisible(false); - if (MWBase::Environment::get().getStateManager()->getState()== MWBase::StateManager::State_NoGame) { From 8560b43464a9af526e34ce23b17423ed9a577fe1 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 2 May 2014 12:47:28 +0200 Subject: [PATCH 118/118] Move to esm component --- apps/openmw/mwgui/quickkeysmenu.cpp | 36 ++++++++++++++---------- components/CMakeLists.txt | 2 +- components/esm/quickkeys.cpp | 43 +++++++++++++++++++++++++++++ components/esm/quickkeys.hpp | 28 +++++++++++++++++++ 4 files changed, 93 insertions(+), 16 deletions(-) create mode 100644 components/esm/quickkeys.cpp create mode 100644 components/esm/quickkeys.hpp diff --git a/apps/openmw/mwgui/quickkeysmenu.cpp b/apps/openmw/mwgui/quickkeysmenu.cpp index fb41b3b67..51e24e29c 100644 --- a/apps/openmw/mwgui/quickkeysmenu.cpp +++ b/apps/openmw/mwgui/quickkeysmenu.cpp @@ -2,6 +2,8 @@ #include +#include + #include "../mwworld/inventorystore.hpp" #include "../mwworld/class.hpp" @@ -385,39 +387,41 @@ namespace MWGui void QuickKeysMenu::write(ESM::ESMWriter &writer) { - const std::string recKey = "KEY_"; writer.startRecord(ESM::REC_KEYS); + ESM::QuickKeys keys; + for (int i=0; i<10; ++i) { - writer.startSubRecord(recKey); - MyGUI::Button* button = mQuickKeyButtons[i]; int type = *button->getUserData(); - writer.writeHNT("TYPE", type); + + ESM::QuickKeys::QuickKey key; + key.mType = type; switch (type) { case Type_Unassigned: - writer.writeHNString("ID__", ""); break; case Type_Item: case Type_MagicItem: { MWWorld::Ptr item = *button->getChildAt(0)->getUserData(); - writer.writeHNString("ID__", item.getCellRef().mRefID); + key.mId = item.getCellRef().mRefID; break; } case Type_Magic: std::string spellId = button->getChildAt(0)->getUserString("Spell"); - writer.writeHNString("ID__", spellId); + key.mId = spellId; break; } - writer.endRecord(recKey); + keys.mKeys.push_back(key); } + keys.save(writer); + writer.endRecord(ESM::REC_KEYS); } @@ -426,17 +430,18 @@ namespace MWGui if (type != ESM::REC_KEYS) return; + ESM::QuickKeys keys; + keys.load(reader); + int i=0; - while (reader.isNextSub("KEY_")) + for (std::vector::const_iterator it = keys.mKeys.begin(); it != keys.mKeys.end(); ++it) { - reader.getSubHeader(); - int keyType; - reader.getHNT(keyType, "TYPE"); - std::string id; - id = reader.getHNString("ID__"); + if (i >= 10) + return; mSelectedIndex = i; - + int keyType = it->mType; + std::string id = it->mId; MyGUI::Button* button = mQuickKeyButtons[i]; switch (keyType) @@ -480,6 +485,7 @@ namespace MWGui unassign(button, i); break; } + ++i; } } diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 38be5b11a..1c60dfb83 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -45,7 +45,7 @@ add_component_dir (esm loadnpc loadpgrd loadrace loadregn loadscpt loadskil loadsndg loadsoun loadspel loadsscr loadstat loadweap records aipackage effectlist spelllist variant variantimp loadtes3 cellref filter savedgame journalentry queststate locals globalscript player objectstate cellid cellstate globalmap lightstate inventorystate containerstate npcstate creaturestate dialoguestate statstate - npcstats creaturestats weatherstate + npcstats creaturestats weatherstate quickkeys ) add_component_dir (misc diff --git a/components/esm/quickkeys.cpp b/components/esm/quickkeys.cpp new file mode 100644 index 000000000..ad2b671aa --- /dev/null +++ b/components/esm/quickkeys.cpp @@ -0,0 +1,43 @@ +#include "quickkeys.hpp" + +#include "esmwriter.hpp" +#include "esmreader.hpp" + +namespace ESM +{ + + void QuickKeys::load(ESMReader &esm) + { + while (esm.isNextSub("KEY_")) + { + esm.getSubHeader(); + int keyType; + esm.getHNT(keyType, "TYPE"); + std::string id; + id = esm.getHNString("ID__"); + + QuickKey key; + key.mType = keyType; + key.mId = id; + + mKeys.push_back(key); + } + } + + void QuickKeys::save(ESMWriter &esm) const + { + const std::string recKey = "KEY_"; + + for (std::vector::const_iterator it = mKeys.begin(); it != mKeys.end(); ++it) + { + esm.startSubRecord(recKey); + + esm.writeHNT("TYPE", it->mType); + esm.writeHNString("ID__", it->mId); + + esm.endRecord(recKey); + } + } + + +} diff --git a/components/esm/quickkeys.hpp b/components/esm/quickkeys.hpp new file mode 100644 index 000000000..c52466b13 --- /dev/null +++ b/components/esm/quickkeys.hpp @@ -0,0 +1,28 @@ +#ifndef OPENMW_COMPONENTS_ESM_QUICKKEYS_H +#define OPENMW_COMPONENTS_ESM_QUICKKEYS_H + +#include +#include + +namespace ESM +{ + class ESMReader; + class ESMWriter; + + struct QuickKeys + { + struct QuickKey + { + int mType; + std::string mId; // Spell or Item ID + }; + + std::vector mKeys; + + void load (ESMReader &esm); + void save (ESMWriter &esm) const; + }; + +} + +#endif