From 18a139cd66dada5a42b93a7f26bb46c7929fa744 Mon Sep 17 00:00:00 2001 From: Jason Hooks Date: Sat, 24 Mar 2012 22:03:08 -0400 Subject: [PATCH 001/325] adding up and down move buttons --- apps/openmw/mwclass/npc.cpp | 5 +- apps/openmw/mwinput/inputmanager.cpp | 16 + apps/openmw/mwmechanics/movement.hpp | 3 +- apps/openmw/mwrender/objects.cpp | 2 + apps/openmw/mwworld/physicssystem.cpp | 15 +- apps/openmw/mwworld/player.cpp | 9 + apps/openmw/mwworld/player.hpp | 1 + apps/openmw/physicssystem.cpp | 225 +++++++ libs/openengine/bullet/physic.cpp | 4 +- libs/openengine/bullet/pmove.cpp | 27 +- libs/openengine/bullet/pmove.h | 4 +- libs/openengine/bullet/trace.cpp | 4 +- libs/openengine/bullet/weather.cpp | 811 ++++++++++++++++++++++++++ libs/openengine/bullet/weather.hpp | 272 +++++++++ 14 files changed, 1374 insertions(+), 24 deletions(-) create mode 100644 apps/openmw/physicssystem.cpp create mode 100644 libs/openengine/bullet/weather.cpp create mode 100644 libs/openengine/bullet/weather.hpp diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 83a94d27d1..522fce3a3c 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -269,8 +269,9 @@ namespace MWClass { Ogre::Vector3 vector (0, 0, 0); - vector.x = - getMovementSettings (ptr).mLeftRight * 200; - vector.y = getMovementSettings (ptr).mForwardBackward * 200; + vector.x = - getMovementSettings (ptr).mLeftRight * 127; + vector.y = getMovementSettings (ptr).mForwardBackward * 127; + vector.z = getMovementSettings(ptr).mUpDown * 127; if (getStance (ptr, Run, false)) vector *= 2; diff --git a/apps/openmw/mwinput/inputmanager.cpp b/apps/openmw/mwinput/inputmanager.cpp index 88534dddae..074f8a906a 100644 --- a/apps/openmw/mwinput/inputmanager.cpp +++ b/apps/openmw/mwinput/inputmanager.cpp @@ -60,6 +60,7 @@ namespace MWInput A_CycleWeaponRight, A_ToggleSneak, //Toggles Sneak, add Push-Sneak later A_ToggleWalk, //Toggle Walking/Running + A_Crouch, A_QuickSave, A_QuickLoad, @@ -259,6 +260,9 @@ namespace MWInput poller.bind(A_MoveRight, KC_D); poller.bind(A_MoveForward, KC_W); poller.bind(A_MoveBackward, KC_S); + + poller.bind(A_Jump, KC_E); + poller.bind(A_Crouch, KC_LCONTROL); } //NOTE: Used to check for movement keys @@ -306,6 +310,18 @@ namespace MWInput else player.setForwardBackward (0); + if (poller.isDown(A_Jump)) + { + + player.setUpDown (1); + } + else if (poller.isDown(A_Crouch)) + { + player.setUpDown (-1); + } + else + player.setUpDown (0); + return true; } diff --git a/apps/openmw/mwmechanics/movement.hpp b/apps/openmw/mwmechanics/movement.hpp index a555ac010a..11eb83151e 100644 --- a/apps/openmw/mwmechanics/movement.hpp +++ b/apps/openmw/mwmechanics/movement.hpp @@ -8,8 +8,9 @@ namespace MWMechanics { signed char mLeftRight; // 1: wants to move left, -1: wants to move right signed char mForwardBackward; // 1:wants to move forward, -1: wants to move backward + signed char mUpDown; - Movement() : mLeftRight (0), mForwardBackward (0) {} + Movement() : mLeftRight (0), mForwardBackward (0), mUpDown(0) {} }; } diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index 717064ada5..0d19a30130 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -56,8 +56,10 @@ void Objects::insertBegin (const MWWorld::Ptr& ptr, bool enabled, bool static_) Ogre::SceneNode* insert = cellnode->createChildSceneNode(); const float *f = ptr.getRefData().getPosition().pos; + insert->setPosition(f[0], f[1], f[2]); insert->setScale(ptr.getCellRef().scale, ptr.getCellRef().scale, ptr.getCellRef().scale); + // Convert MW rotation to a quaternion: f = ptr.getCellRef().pos.rot; diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 11a43c7d30..d54f4696a2 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -103,7 +103,7 @@ namespace MWWorld playerphysics->ps.viewangles.x = 0; playerphysics->ps.viewangles.z = 0; - playerphysics->ps.viewangles.y = both.getYaw().valueDegrees() *-1 + 90; + playerphysics->ps.viewangles.y = both.getYaw().valueDegrees() *-1 + 90; //playerphysics->ps.viewangles.z = both.getPitch().valueDegrees(); @@ -113,6 +113,7 @@ namespace MWWorld Ogre::Vector3 dir1(iter->second.x,iter->second.z,-iter->second.y); pm_ref.rightmove = -dir1.x; pm_ref.forwardmove = dir1.z; + pm_ref.upmove = dir1.y; @@ -127,6 +128,7 @@ namespace MWWorld Ogre::Vector3 dir1(iter->second.x,iter->second.z,-iter->second.y); pm_ref.rightmove = -dir1.x; pm_ref.forwardmove = dir1.z; + pm_ref.upmove = dir.y; dir = 0.025*(quat*dir1); } @@ -135,7 +137,7 @@ namespace MWWorld //set the walk direction act->setWalkDirection(btVector3(dir.x,-dir.z,dir.y)); } - //mEngine->stepSimulation(duration); + mEngine->stepSimulation(duration); Pmove(playerphysics); std::vector< std::pair > response; for(std::map::iterator it = mEngine->PhysicActorMap.begin(); it != mEngine->PhysicActorMap.end();it++) @@ -147,7 +149,7 @@ namespace MWWorld coord = playerphysics->ps.origin; //std::cout << "Coord" << coord << "\n"; - coord = Ogre::Vector3(coord.x, coord.z, coord.y); //x, z, -y + //coord = Ogre::Vector3(coord.x, coord.z, coord.y); //x, z, -y } response.push_back(std::pair(it->first, coord)); @@ -218,6 +220,10 @@ namespace MWWorld bool PhysicsSystem::toggleCollisionMode() { + if(playerphysics->ps.move_type==PM_NOCLIP) + playerphysics->ps.move_type=PM_NORMAL; + else + playerphysics->ps.move_type=PM_NOCLIP; for(std::map::iterator it = mEngine->PhysicActorMap.begin(); it != mEngine->PhysicActorMap.end();it++) { if (it->first=="player") @@ -248,7 +254,10 @@ namespace MWWorld } void PhysicsSystem::insertObjectPhysics(const MWWorld::Ptr& ptr, const std::string model){ + Ogre::SceneNode* node = ptr.getRefData().getBaseNode(); + Ogre::Vector3 objPos = node->getPosition(); + addObject (node->getName(), model, node->getOrientation(), node->getScale().x, node->getPosition()); } diff --git a/apps/openmw/mwworld/player.cpp b/apps/openmw/mwworld/player.cpp index 5bfb82138c..884a72c3a6 100644 --- a/apps/openmw/mwworld/player.cpp +++ b/apps/openmw/mwworld/player.cpp @@ -80,6 +80,14 @@ namespace MWWorld MWWorld::Class::get (ptr).getMovementSettings (ptr).mForwardBackward = value; } + void Player::setUpDown(int value) + { + MWWorld::Ptr ptr = getPlayer(); + + + + MWWorld::Class::get (ptr).getMovementSettings (ptr).mUpDown = value; + } void Player::toggleRunning() { @@ -89,4 +97,5 @@ namespace MWWorld MWWorld::Class::get (ptr).setStance (ptr, MWWorld::Class::Run, !running); } + } diff --git a/apps/openmw/mwworld/player.hpp b/apps/openmw/mwworld/player.hpp index 01c71da437..da74fe6ded 100644 --- a/apps/openmw/mwworld/player.hpp +++ b/apps/openmw/mwworld/player.hpp @@ -111,6 +111,7 @@ namespace MWWorld void setLeftRight (int value); void setForwardBackward (int value); + void setUpDown(int value); void toggleRunning(); }; diff --git a/apps/openmw/physicssystem.cpp b/apps/openmw/physicssystem.cpp new file mode 100644 index 0000000000..a07358f8ee --- /dev/null +++ b/apps/openmw/physicssystem.cpp @@ -0,0 +1,225 @@ +#include + +#include "physicssystem.hpp" +#include "../mwworld/ptr.hpp" +#include "../mwworld/world.hpp" // FIXME +#include + +#include "OgreRoot.h" +#include "OgreRenderWindow.h" +#include "OgreSceneManager.h" +#include "OgreViewport.h" +#include "OgreCamera.h" +#include "OgreTextureManager.h" + + +using namespace Ogre; +namespace MWWorld +{ + + PhysicsSystem::PhysicsSystem(OEngine::Render::OgreRenderer &_rend) : + mRender(_rend), mEngine(0), mFreeFly (true) + { + // Create physics. shapeLoader is deleted by the physic engine + NifBullet::ManualBulletShapeLoader* shapeLoader = new NifBullet::ManualBulletShapeLoader(); + mEngine = new OEngine::Physic::PhysicEngine(shapeLoader); + } + + PhysicsSystem::~PhysicsSystem() + { + delete mEngine; + + } + OEngine::Physic::PhysicEngine* PhysicsSystem::getEngine() + { + return mEngine; + } + + std::pair PhysicsSystem::getFacedHandle (MWWorld::World& world) + { + std::string handle = ""; + + //get a ray pointing to the center of the viewport + Ray centerRay = mRender.getCamera()->getCameraToViewportRay( + mRender.getViewport()->getWidth()/2, + mRender.getViewport()->getHeight()/2); + //let's avoid the capsule shape of the player. + centerRay.setOrigin(centerRay.getOrigin() + 20*centerRay.getDirection()); + btVector3 from(centerRay.getOrigin().x,-centerRay.getOrigin().z,centerRay.getOrigin().y); + btVector3 to(centerRay.getPoint(500).x,-centerRay.getPoint(500).z,centerRay.getPoint(500).y); + + return mEngine->rayTest(from,to); + } + + bool PhysicsSystem::castRay(const Vector3& from, const Vector3& to) + { + btVector3 _from, _to; + _from = btVector3(from.x, from.y, from.z); + _to = btVector3(to.x, to.y, to.z); + + std::pair result = mEngine->rayTest(_from, _to); + + return !(result.first == ""); + } + + + std::vector< std::pair > PhysicsSystem::doPhysics (float duration, + const std::vector >& actors) + { + //set the DebugRenderingMode. To disable it,set it to 0 + //eng->setDebugRenderingMode(1); + + //set the walkdirection to 0 (no movement) for every actor) + for(std::map::iterator it = mEngine->PhysicActorMap.begin(); it != mEngine->PhysicActorMap.end();it++) + { + OEngine::Physic::PhysicActor* act = it->second; + act->setWalkDirection(btVector3(0,0,0)); + } + + for (std::vector >::const_iterator iter (actors.begin()); + iter!=actors.end(); ++iter) + { + OEngine::Physic::PhysicActor* act = mEngine->getCharacter(iter->first); + + //dirty stuff to get the camera orientation. Must be changed! + + Ogre::SceneNode *sceneNode = mRender.getScene()->getSceneNode (iter->first); + Ogre::Vector3 dir; + Ogre::Node* yawNode = sceneNode->getChildIterator().getNext(); + Ogre::Node* pitchNode = yawNode->getChildIterator().getNext(); + if(mFreeFly) + { + Ogre::Quaternion yawQuat = yawNode->getOrientation(); + Ogre::Quaternion pitchQuat = pitchNode->getOrientation(); + Ogre::Vector3 dir1(iter->second.x,iter->second.z,-iter->second.y); + dir = 0.07*(yawQuat*pitchQuat*dir1); + } + else + { + Ogre::Quaternion quat = yawNode->getOrientation(); + Ogre::Vector3 dir1(iter->second.x,iter->second.z,-iter->second.y); + dir = 0.025*(quat*dir1); + } + + //set the walk direction + act->setWalkDirection(btVector3(dir.x,-dir.z,dir.y)); + } + mEngine->stepSimulation(duration); + + std::vector< std::pair > response; + for(std::map::iterator it = mEngine->PhysicActorMap.begin(); it != mEngine->PhysicActorMap.end();it++) + { + btVector3 newPos = it->second->getPosition(); + Ogre::Vector3 coord(newPos.x(), newPos.y(), newPos.z()); + + response.push_back(std::pair(it->first, coord)); + } + return response; + } + + void PhysicsSystem::addObject (const std::string& handle, const std::string& mesh, + const Ogre::Quaternion& rotation, float scale, const Ogre::Vector3& position) + { + OEngine::Physic::RigidBody* body = mEngine->createRigidBody(mesh,handle,scale); + mEngine->addRigidBody(body); + btTransform tr; + tr.setOrigin(btVector3(position.x,position.y,position.z)); + std::cout << "Position object:" << position << "\n"; + tr.setRotation(btQuaternion(rotation.x,rotation.y,rotation.z,rotation.w)); + body->setWorldTransform(tr); + } + + void PhysicsSystem::addActor (const std::string& handle, const std::string& mesh, + const Ogre::Vector3& position) + { + //TODO:optimize this. Searching the std::map isn't very efficient i think. + mEngine->addCharacter(handle); + OEngine::Physic::PhysicActor* act = mEngine->getCharacter(handle); + act->setPosition(btVector3(position.x,position.y,position.z)); + } + + void PhysicsSystem::removeObject (const std::string& handle) + { + //TODO:check if actor??? + mEngine->removeCharacter(handle); + mEngine->removeRigidBody(handle); + mEngine->deleteRigidBody(handle); + } + + void PhysicsSystem::moveObject (const std::string& handle, const Ogre::Vector3& position) + { + if (OEngine::Physic::RigidBody* body = mEngine->getRigidBody(handle)) + { + // TODO very dirty hack to avoid crash during setup -> needs cleaning up to allow + // start positions others than 0, 0, 0 + btTransform tr = body->getWorldTransform(); + tr.setOrigin(btVector3(position.x,position.y,position.z)); + body->setWorldTransform(tr); + } + if (OEngine::Physic::PhysicActor* act = mEngine->getCharacter(handle)) + { + // TODO very dirty hack to avoid crash during setup -> needs cleaning up to allow + // start positions others than 0, 0, 0 + act->setPosition(btVector3(position.x,position.y,position.z)); + } + } + + void PhysicsSystem::rotateObject (const std::string& handle, const Ogre::Quaternion& rotation) + { + if (OEngine::Physic::PhysicActor* act = mEngine->getCharacter(handle)) + { + // TODO very dirty hack to avoid crash during setup -> needs cleaning up to allow + // start positions others than 0, 0, 0 + act->setRotation(btQuaternion(rotation.x, rotation.y, rotation.z, rotation.w)); + } + } + + void PhysicsSystem::scaleObject (const std::string& handle, float scale) + { + + } + + bool PhysicsSystem::toggleCollisionMode() + { + for(std::map::iterator it = mEngine->PhysicActorMap.begin(); it != mEngine->PhysicActorMap.end();it++) + { + if (it->first=="player") + { + OEngine::Physic::PhysicActor* act = it->second; + + bool cmode = act->getCollisionMode(); + if(cmode) + { + act->enableCollisions(false); + act->setGravity(0.); + act->setVerticalVelocity(0); + mFreeFly = true; + return false; + } + else + { + mFreeFly = false; + act->enableCollisions(true); + act->setGravity(4.); + act->setVerticalVelocity(0); + return true; + } + } + } + + throw std::logic_error ("can't find player"); + } + + void PhysicsSystem::insertObjectPhysics(const MWWorld::Ptr& ptr, const std::string model){ + Ogre::SceneNode* node = ptr.getRefData().getBaseNode(); + addObject (node->getName(), model, node->getOrientation(), + node->getScale().x, node->getPosition()); + } + + void PhysicsSystem::insertActorPhysics(const MWWorld::Ptr& ptr, const std::string model){ + Ogre::SceneNode* node = ptr.getRefData().getBaseNode(); + // std::cout << "Adding node with name" << node->getName(); + addActor (node->getName(), model, node->getPosition()); + } + +} diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index 07bad30535..911f6279bd 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -156,10 +156,10 @@ namespace Physic solver = new btSequentialImpulseConstraintSolver; //TODO: memory leak? - btOverlappingPairCache* pairCache = new btSortedOverlappingPairCache(); + //btOverlappingPairCache* pairCache = new btSortedOverlappingPairCache(); //pairCache->setInternalGhostPairCallback( new btGhostPairCallback() ); - broadphase = new btDbvtBroadphase(pairCache); + broadphase = new btDbvtBroadphase(); // The world. dynamicsWorld = new btDiscreteDynamicsWorld(dispatcher,broadphase,solver,collisionConfiguration); diff --git a/libs/openengine/bullet/pmove.cpp b/libs/openengine/bullet/pmove.cpp index 45fe84f4fc..71c15fe45f 100644 --- a/libs/openengine/bullet/pmove.cpp +++ b/libs/openengine/bullet/pmove.cpp @@ -786,7 +786,7 @@ static void PM_WaterMove( playerMove* const pm ) wishvel = pml.forward * scale * pm->cmd.forwardmove + pml.right * scale * pm->cmd.rightmove; //wishvel[2] += scale * pm->cmd.upmove; - wishvel.y += pm->cmd.upmove * scale; + wishvel.z += pm->cmd.upmove * scale; } //VectorCopy (wishvel, wishdir); @@ -1094,21 +1094,22 @@ void AngleVectors( const Ogre::Vector3& angles, Ogre::Vector3* const forward, Og if (forward) { forward->x = cp * cy; - forward->z = cp * sy; - forward->y = -sp; + forward->y = cp * sy; + forward->z = -sp; } if (right) { right->x = (-1 * sr * sp * cy + -1 * cr * -sy); - right->z = (-1 * sr * sp * sy + -1 * cr * cy); - right->y = 0.0f;//-1 * sp * cp; + right->y = (-1 * sr * sp * sy + -1 * cr * cy); + right->z = 0.0f;//-1 * sp * cp; } if (up) { - up->x = (cr * sp * cy + -sr * -sy); - up->z = (cr * sp * sy + -sr * cy); - up->y = cr * cp; + up->x =(cr * sp * cy + -sr * -sy); + up->y=(cr * sp * sy + -sr * cy); + up->z = cr * cp; } + } void PM_GroundTraceMissed() @@ -1356,7 +1357,7 @@ static void PM_CrashLand( void ) static void PM_GroundTrace( void ) { - std::cout << "Ground trace\n"; + //std::cout << "Ground trace\n"; Ogre::Vector3 point; traceResults trace; @@ -1578,9 +1579,12 @@ static void PM_NoclipMove( void ) //for (i=0 ; i<3 ; i++) //wishvel[i] = pml.forward[i] * fmove + pml.right[i] * smove; + std::cout << "Forward" << pml.forward << "\n"; + std::cout << "Right" << pml.right << "\n"; + std::cout << "Up" << pml.up << "\n"; wishvel = pml.forward * fmove + pml.right * smove; //wishvel[2] += pm->cmd.upmove; - wishvel.y += pm->cmd.upmove; + wishvel.z += pm->cmd.upmove; //VectorCopy (wishvel, wishdir); wishdir = wishvel; @@ -1720,7 +1724,6 @@ void PM_SetWaterLevel( playerMove* const pm ) void PmoveSingle (playerMove* const pmove) { - std::cout << "Pmove single\n"; //pm = pmove; // Aedra doesn't support Q3-style VM traps D: //while(1); @@ -1944,7 +1947,7 @@ void PmoveSingle (playerMove* const pmove) else { // airborne - std::cout << "AIRMOVE\n"; + //std::cout << "AIRMOVE\n"; PM_AirMove(); //bprintf("AirMove\n"); } diff --git a/libs/openengine/bullet/pmove.h b/libs/openengine/bullet/pmove.h index e90cc3b35d..5dfd18f6dc 100644 --- a/libs/openengine/bullet/pmove.h +++ b/libs/openengine/bullet/pmove.h @@ -90,9 +90,9 @@ struct playerMove { struct playerStruct { - playerStruct() : gravity(50.0f), speed(320.0f), pmove_framecount(20), groundEntityNum(ENTITYNUM_NONE), commandTime(40), move_type(PM_NORMAL), pm_time(0) + playerStruct() : gravity(50.0f), speed(320.0f), pmove_framecount(20), groundEntityNum(ENTITYNUM_NONE), commandTime(40), move_type(PM_NOCLIP), pm_time(0) { - origin = Ogre::Vector3(733.164f,1000.0f, 839.432f); + origin = Ogre::Vector3(733.164f,900.0f, 839.432f); velocity = Ogre::Vector3(0.0f, 0.0f, 0.0f); viewangles = Ogre::Vector3(0.0f, 0.0f, 0.0f); diff --git a/libs/openengine/bullet/trace.cpp b/libs/openengine/bullet/trace.cpp index 49e12064ee..57d071f170 100644 --- a/libs/openengine/bullet/trace.cpp +++ b/libs/openengine/bullet/trace.cpp @@ -112,8 +112,8 @@ const bool NewPhysicsTrace(NewPhysTraceResults* const out, const Ogre::Vector3& float y2 = to.getOrigin().getY(); float z2 = to.getOrigin().getZ(); - std::cout << "BtFrom: " << x << "," << y << "," << z << "\n"; - std::cout << "BtTo: " << x2 << "," << y2 << "," << z2 << "\n"; + //std::cout << "BtFrom: " << x << "," << y << "," << z << "\n"; + //std::cout << "BtTo: " << x2 << "," << y2 << "," << z2 << "\n"; //std::cout << "BtTo: " << to.getOrigin().getX() << "," << to.getOrigin().getY() << "," << to.getOrigin().getZ() << "\n"; diff --git a/libs/openengine/bullet/weather.cpp b/libs/openengine/bullet/weather.cpp new file mode 100644 index 0000000000..90afc4e78b --- /dev/null +++ b/libs/openengine/bullet/weather.cpp @@ -0,0 +1,811 @@ +#include "weather.hpp" +#include "world.hpp" +#include "player.hpp" + +#include "../mwrender/renderingmanager.hpp" +#include "../mwsound/soundmanager.hpp" + +#include +#include +#include + +#include + +using namespace Ogre; +using namespace MWWorld; +using namespace MWSound; + +#define lerp(x, y) (x * (1-factor) + y * factor) + +const std::string WeatherGlobals::mThunderSoundID0 = "Thunder0"; +const std::string WeatherGlobals::mThunderSoundID1 = "Thunder1"; +const std::string WeatherGlobals::mThunderSoundID2 = "Thunder2"; +const std::string WeatherGlobals::mThunderSoundID3 = "Thunder3"; +const float WeatherGlobals::mSunriseTime = 8; +const float WeatherGlobals::mSunsetTime = 18; +const float WeatherGlobals::mSunriseDuration = 2; +const float WeatherGlobals::mSunsetDuration = 2; +const float WeatherGlobals::mWeatherUpdateTime = 20.f; +const float WeatherGlobals::mThunderFrequency = .4; +const float WeatherGlobals::mThunderThreshold = 0.6; +const float WeatherGlobals::mThunderSoundDelay = 0.25; + +WeatherManager::WeatherManager(MWRender::RenderingManager* rendering, Environment* env) : + mHour(14), mCurrentWeather("clear"), mFirstUpdate(true), mWeatherUpdateTime(0), + mThunderFlash(0), mThunderChance(0), mThunderChanceNeeded(50), mThunderSoundDelay(0) +{ + mRendering = rendering; + mEnvironment = env; + + #define clr(r,g,b) ColourValue(r/255.f, g/255.f, b/255.f) + + /// \todo read these from Morrowind.ini + Weather clear; + clear.mCloudTexture = "tx_sky_clear.dds"; + clear.mCloudsMaximumPercent = 1.0; + clear.mTransitionDelta = 0.015; + clear.mSkySunriseColor = clr(118, 141, 164); + clear.mSkyDayColor = clr(95, 135, 203); + clear.mSkySunsetColor = clr(56, 89, 129); + clear.mSkyNightColor = clr(9, 10, 11); + clear.mFogSunriseColor = clr(255, 189, 157); + clear.mFogDayColor = clr(206, 227, 255); + clear.mFogSunsetColor = clr(255, 189, 157); + clear.mFogNightColor = clr(9, 10, 11); + clear.mAmbientSunriseColor = clr(47, 66, 96); + clear.mAmbientDayColor = clr(137, 140, 160); + clear.mAmbientSunsetColor = clr(68, 75, 96); + clear.mAmbientNightColor = clr(32, 35, 42); + clear.mSunSunriseColor = clr(242, 159, 99); + clear.mSunDayColor = clr(255, 252, 238); + clear.mSunSunsetColor = clr(255, 115, 79); + clear.mSunNightColor = clr(59, 97, 176); + clear.mSunDiscSunsetColor = clr(255, 189, 157); + clear.mLandFogDayDepth = 0.69; + clear.mLandFogNightDepth = 0.69; + clear.mWindSpeed = 0.1; + clear.mCloudSpeed = 1.25; + clear.mGlareView = 1.0; + mWeatherSettings["clear"] = clear; + + Weather cloudy; + cloudy.mCloudTexture = "tx_sky_cloudy.dds"; + cloudy.mCloudsMaximumPercent = 1.0; + cloudy.mTransitionDelta = 0.015; + cloudy.mSkySunriseColor = clr(126, 158, 173); + cloudy.mSkyDayColor = clr(117, 160, 215); + cloudy.mSkySunsetColor = clr(111, 114, 159); + cloudy.mSkyNightColor = clr(9, 10, 11); + cloudy.mFogSunriseColor = clr(255, 207, 149); + cloudy.mFogDayColor = clr(245, 235, 224); + cloudy.mFogSunsetColor = clr(255, 155, 106); + cloudy.mFogNightColor = clr(9, 10, 11); + cloudy.mAmbientSunriseColor = clr(66, 74, 87); + cloudy.mAmbientDayColor = clr(137, 145, 160); + cloudy.mAmbientSunsetColor = clr(71, 80, 92); + cloudy.mAmbientNightColor = clr(32, 39, 54); + cloudy.mSunSunriseColor = clr(241, 177, 99); + cloudy.mSunDayColor = clr(255, 236, 221); + cloudy.mSunSunsetColor = clr(255, 89, 00); + cloudy.mSunNightColor = clr(77, 91, 124); + cloudy.mSunDiscSunsetColor = clr(255, 202, 179); + cloudy.mLandFogDayDepth = 0.72; + cloudy.mLandFogNightDepth = 0.72; + cloudy.mWindSpeed = 0.2; + cloudy.mCloudSpeed = 2; + cloudy.mGlareView = 1.0; + mWeatherSettings["cloudy"] = cloudy; + + Weather foggy; + foggy.mCloudTexture = "tx_sky_foggy.dds"; + foggy.mCloudsMaximumPercent = 1.0; + foggy.mTransitionDelta = 0.015; + foggy.mSkySunriseColor = clr(197, 190, 180); + foggy.mSkyDayColor = clr(184, 211, 228); + foggy.mSkySunsetColor = clr(142, 159, 176); + foggy.mSkyNightColor = clr(18, 23, 28); + foggy.mFogSunriseColor = clr(173, 164, 148); + foggy.mFogDayColor = clr(150, 187, 209); + foggy.mFogSunsetColor = clr(113, 135, 157); + foggy.mFogNightColor = clr(19, 24, 29); + foggy.mAmbientSunriseColor = clr(48, 43, 37); + foggy.mAmbientDayColor = clr(92, 109, 120); + foggy.mAmbientSunsetColor = clr(28, 33, 39); + foggy.mAmbientNightColor = clr(28, 33, 39); + foggy.mSunSunriseColor = clr(177, 162, 137); + foggy.mSunDayColor = clr(111, 131, 151); + foggy.mSunSunsetColor = clr(125, 157, 189); + foggy.mSunNightColor = clr(81, 100, 119); + foggy.mSunDiscSunsetColor = clr(223, 223, 223); + foggy.mLandFogDayDepth = 1.0; + foggy.mLandFogNightDepth = 1.9; + foggy.mWindSpeed = 0; + foggy.mCloudSpeed = 1.25; + foggy.mGlareView = 0.25; + mWeatherSettings["foggy"] = foggy; + + Weather thunderstorm; + thunderstorm.mCloudTexture = "tx_sky_thunder.dds"; + thunderstorm.mCloudsMaximumPercent = 0.66; + thunderstorm.mTransitionDelta = 0.03; + thunderstorm.mSkySunriseColor = clr(35, 36, 39); + thunderstorm.mSkyDayColor = clr(97, 104, 115); + thunderstorm.mSkySunsetColor = clr(35, 36, 39); + thunderstorm.mSkyNightColor = clr(19, 20, 22); + thunderstorm.mFogSunriseColor = clr(70, 74, 85); + thunderstorm.mFogDayColor = clr(97, 104, 115); + thunderstorm.mFogSunsetColor = clr(70, 74, 85); + thunderstorm.mFogNightColor = clr(19, 20, 22); + thunderstorm.mAmbientSunriseColor = clr(54, 54, 54); + thunderstorm.mAmbientDayColor = clr(90, 90, 90); + thunderstorm.mAmbientSunsetColor = clr(54, 54, 54); + thunderstorm.mAmbientNightColor = clr(49, 51, 54); + thunderstorm.mSunSunriseColor = clr(91, 99, 122); + thunderstorm.mSunDayColor = clr(138, 144, 155); + thunderstorm.mSunSunsetColor = clr(96, 101, 117); + thunderstorm.mSunNightColor = clr(55, 76, 110); + thunderstorm.mSunDiscSunsetColor = clr(128, 128, 128); + thunderstorm.mLandFogDayDepth = 1; + thunderstorm.mLandFogNightDepth = 1.15; + thunderstorm.mWindSpeed = 0.5; + thunderstorm.mCloudSpeed = 3; + thunderstorm.mGlareView = 0; + thunderstorm.mRainLoopSoundID = "rain heavy"; + mWeatherSettings["thunderstorm"] = thunderstorm; + + Weather rain; + rain.mCloudTexture = "tx_sky_rainy.dds"; + rain.mCloudsMaximumPercent = 0.66; + rain.mTransitionDelta = 0.015; + rain.mSkySunriseColor = clr(71, 74, 75); + rain.mSkyDayColor = clr(116, 120, 122); + rain.mSkySunsetColor = clr(73, 73, 73); + rain.mSkyNightColor = clr(24, 25, 26); + rain.mFogSunriseColor = clr(71, 74, 75); + rain.mFogDayColor = clr(116, 120, 122); + rain.mFogSunsetColor = clr(73, 73, 73); + rain.mFogNightColor = clr(24, 25, 26); + rain.mAmbientSunriseColor = clr(97, 90, 88); + rain.mAmbientDayColor = clr(105, 110, 113); + rain.mAmbientSunsetColor = clr(88, 97, 97); + rain.mAmbientNightColor = clr(50, 55, 67); + rain.mSunSunriseColor = clr(131, 122, 120); + rain.mSunDayColor = clr(149, 157, 170); + rain.mSunSunsetColor = clr(120, 126, 131); + rain.mSunNightColor = clr(50, 62, 101); + rain.mSunDiscSunsetColor = clr(128, 128, 128); + rain.mLandFogDayDepth = 0.8; + rain.mLandFogNightDepth = 0.8; + rain.mWindSpeed = 0.3; + rain.mCloudSpeed = 2; + rain.mGlareView = 0; + rain.mRainLoopSoundID = "rain"; + mWeatherSettings["rain"] = rain; + + Weather overcast; + overcast.mCloudTexture = "tx_sky_overcast.dds"; + overcast.mCloudsMaximumPercent = 1.0; + overcast.mTransitionDelta = 0.015; + overcast.mSkySunriseColor = clr(91, 99, 106); + overcast.mSkyDayColor = clr(143, 146, 149); + overcast.mSkySunsetColor = clr(108, 115, 121); + overcast.mSkyNightColor = clr(19, 22, 25); + overcast.mFogSunriseColor = clr(91, 99, 106); + overcast.mFogDayColor = clr(143, 146, 149); + overcast.mFogSunsetColor = clr(108, 115, 121); + overcast.mFogNightColor = clr(19, 22, 25); + overcast.mAmbientSunriseColor = clr(84, 88, 92); + overcast.mAmbientDayColor = clr(93, 96, 105); + overcast.mAmbientSunsetColor = clr(83, 77, 75); + overcast.mAmbientNightColor = clr(57, 60, 66); + overcast.mSunSunriseColor = clr(87, 125, 163); + overcast.mSunDayColor = clr(163, 169, 183); + overcast.mSunSunsetColor = clr(85, 103, 157); + overcast.mSunNightColor = clr(32, 54, 100); + overcast.mSunDiscSunsetColor = clr(128, 128, 128); + overcast.mLandFogDayDepth = 0.7; + overcast.mLandFogNightDepth = 0.7; + overcast.mWindSpeed = 0.2; + overcast.mCloudSpeed = 1.5; + overcast.mGlareView = 0; + mWeatherSettings["overcast"] = overcast; + + Weather ashstorm; + ashstorm.mCloudTexture = "tx_sky_ashstorm.dds"; + ashstorm.mCloudsMaximumPercent = 1.0; + ashstorm.mTransitionDelta = 0.035; + ashstorm.mSkySunriseColor = clr(91, 56, 51); + ashstorm.mSkyDayColor = clr(124, 73, 58); + ashstorm.mSkySunsetColor = clr(106, 55, 40); + ashstorm.mSkyNightColor = clr(20, 21, 22); + ashstorm.mFogSunriseColor = clr(91, 56, 51); + ashstorm.mFogDayColor = clr(124, 73, 58); + ashstorm.mFogSunsetColor = clr(106, 55, 40); + ashstorm.mFogNightColor = clr(20, 21, 22); + ashstorm.mAmbientSunriseColor = clr(52, 42, 37); + ashstorm.mAmbientDayColor = clr(75, 49, 41); + ashstorm.mAmbientSunsetColor = clr(48, 39, 35); + ashstorm.mAmbientNightColor = clr(36, 42, 49); + ashstorm.mSunSunriseColor = clr(184, 91, 71); + ashstorm.mSunDayColor = clr(228, 139, 114); + ashstorm.mSunSunsetColor = clr(185, 86, 57); + ashstorm.mSunNightColor = clr(54, 66, 74); + ashstorm.mSunDiscSunsetColor = clr(128, 128, 128); + ashstorm.mLandFogDayDepth = 1.1; + ashstorm.mLandFogNightDepth = 1.2; + ashstorm.mWindSpeed = 0.8; + ashstorm.mCloudSpeed = 7; + ashstorm.mGlareView = 0; + ashstorm.mAmbientLoopSoundID = "ashstorm"; + mWeatherSettings["ashstorm"] = ashstorm; + + Weather blight; + blight.mCloudTexture = "tx_sky_blight.dds"; + blight.mCloudsMaximumPercent = 1.0; + blight.mTransitionDelta = 0.04; + blight.mSkySunriseColor = clr(90, 35, 35); + blight.mSkyDayColor = clr(90, 35, 35); + blight.mSkySunsetColor = clr(92, 33, 33); + blight.mSkyNightColor = clr(44, 14, 14); + blight.mFogSunriseColor = clr(90, 35, 35); + blight.mFogDayColor = clr(128, 19, 19); + blight.mFogSunsetColor = clr(92, 33, 33); + blight.mFogNightColor = clr(44, 14, 14); + blight.mAmbientSunriseColor = clr(61, 40, 40); + blight.mAmbientDayColor = clr(79, 54, 54); + blight.mAmbientSunsetColor = clr(61, 40, 40); + blight.mAmbientNightColor = clr(56, 58, 62); + blight.mSunSunriseColor = clr(180, 78, 78); + blight.mSunDayColor = clr(224, 84, 84); + blight.mSunSunsetColor = clr(180, 78, 78); + blight.mSunNightColor = clr(61, 91, 143); + blight.mSunDiscSunsetColor = clr(128, 128, 128); + blight.mLandFogDayDepth = 1.1; + blight.mLandFogNightDepth = 1.2; + blight.mWindSpeed = 0.9; + blight.mCloudSpeed = 9; + blight.mGlareView = 0; + blight.mAmbientLoopSoundID = "blight"; + mWeatherSettings["blight"] = blight; + + Weather snow; + snow.mCloudTexture = "tx_bm_sky_snow.dds"; + snow.mCloudsMaximumPercent = 1.0; + snow.mTransitionDelta = 0.014; + snow.mSkySunriseColor = clr(196, 91, 91); + snow.mSkyDayColor = clr(153, 158, 166); + snow.mSkySunsetColor = clr(96, 115, 134); + snow.mSkyNightColor = clr(31, 35, 39); + snow.mFogSunriseColor = clr(106, 91, 91); + snow.mFogDayColor = clr(153, 158, 166); + snow.mFogSunsetColor = clr(96, 115, 134); + snow.mFogNightColor = clr(31, 35, 39); + snow.mAmbientSunriseColor = clr(92, 84, 84); + snow.mAmbientDayColor = clr(93, 96, 105); + snow.mAmbientSunsetColor = clr(70, 79, 87); + snow.mAmbientNightColor = clr(49, 58, 68); + snow.mSunSunriseColor = clr(141, 109, 109); + snow.mSunDayColor = clr(163, 169, 183); + snow.mSunSunsetColor = clr(101, 121, 141); + snow.mSunNightColor = clr(55, 66, 77); + snow.mSunDiscSunsetColor = clr(128, 128, 128); + snow.mLandFogDayDepth = 1.0; + snow.mLandFogNightDepth = 1.2; + snow.mWindSpeed = 0; + snow.mCloudSpeed = 1.5; + snow.mGlareView = 0; + mWeatherSettings["snow"] = snow; + + Weather blizzard; + blizzard.mCloudTexture = "tx_bm_sky_blizzard.dds"; + blizzard.mCloudsMaximumPercent = 1.0; + blizzard.mTransitionDelta = 0.030; + blizzard.mSkySunriseColor = clr(91, 99, 106); + blizzard.mSkyDayColor = clr(121, 133, 145); + blizzard.mSkySunsetColor = clr(108, 115, 121); + blizzard.mSkyNightColor = clr(27, 29, 31); + blizzard.mFogSunriseColor = clr(91, 99, 106); + blizzard.mFogDayColor = clr(121, 133, 145); + blizzard.mFogSunsetColor = clr(108, 115, 121); + blizzard.mFogNightColor = clr(21, 24, 28); + blizzard.mAmbientSunriseColor = clr(84, 88, 92); + blizzard.mAmbientDayColor = clr(93, 96, 105); + blizzard.mAmbientSunsetColor = clr(83, 77, 75); + blizzard.mAmbientNightColor = clr(53, 62, 70); + blizzard.mSunSunriseColor = clr(114, 128, 146); + blizzard.mSunDayColor = clr(163, 169, 183); + blizzard.mSunSunsetColor = clr(106, 114, 136); + blizzard.mSunNightColor = clr(57, 66, 74); + blizzard.mSunDiscSunsetColor = clr(128, 128, 128); + blizzard.mLandFogDayDepth = 2.8; + blizzard.mLandFogNightDepth = 3.0; + blizzard.mWindSpeed = 0.9; + blizzard.mCloudSpeed = 7.5; + blizzard.mGlareView = 0; + blizzard.mAmbientLoopSoundID = "BM Blizzard"; + mWeatherSettings["blizzard"] = blizzard; +} + +void WeatherManager::setWeather(const String& weather, bool instant) +{ + if (instant || mFirstUpdate) + { + mNextWeather = ""; + mCurrentWeather = weather; + mFirstUpdate = false; + } + else + { + if (mNextWeather != "") + { + // transition more than 50% finished? + if (mRemainingTransitionTime/(mWeatherSettings[mCurrentWeather].mTransitionDelta*24.f*60) <= 0.5) + mCurrentWeather = mNextWeather; + } + + mNextWeather = weather; + mRemainingTransitionTime = mWeatherSettings[mCurrentWeather].mTransitionDelta*24.f*60; + } +} + +WeatherResult WeatherManager::getResult(const String& weather) +{ + const Weather& current = mWeatherSettings[weather]; + WeatherResult result; + + result.mCloudTexture = current.mCloudTexture; + result.mCloudBlendFactor = 0; + result.mCloudOpacity = current.mCloudsMaximumPercent; + result.mWindSpeed = current.mWindSpeed; + result.mCloudSpeed = current.mCloudSpeed; + result.mGlareView = current.mGlareView; + result.mAmbientLoopSoundID = current.mAmbientLoopSoundID; + result.mSunColor = current.mSunDiscSunsetColor; + + const float fade_duration = current.mTransitionDelta * 24.f; + + result.mNight = (mHour < 6.f+fade_duration || mHour > 20.f-fade_duration); + + result.mFogDepth = result.mNight ? current.mLandFogNightDepth : current.mLandFogDayDepth; + + // night + if (mHour <= (WeatherGlobals::mSunriseTime-WeatherGlobals::mSunriseDuration) + || mHour >= (WeatherGlobals::mSunsetTime+WeatherGlobals::mSunsetDuration)) + { + result.mFogColor = current.mFogNightColor; + result.mAmbientColor = current.mAmbientNightColor; + result.mSunColor = current.mSunNightColor; + result.mSkyColor = current.mSkyNightColor; + result.mNightFade = 1.f; + } + + // sunrise + else if (mHour >= (WeatherGlobals::mSunriseTime-WeatherGlobals::mSunriseDuration) && mHour <= WeatherGlobals::mSunriseTime) + { + if (mHour <= (WeatherGlobals::mSunriseTime-WeatherGlobals::mSunriseDuration+fade_duration)) + { + // fade in + float advance = (WeatherGlobals::mSunriseTime-WeatherGlobals::mSunriseDuration+fade_duration)-mHour; + float factor = (advance / fade_duration); + result.mFogColor = lerp(current.mFogSunriseColor, current.mFogNightColor); + result.mAmbientColor = lerp(current.mAmbientSunriseColor, current.mAmbientNightColor); + result.mSunColor = lerp(current.mSunSunriseColor, current.mSunNightColor); + result.mSkyColor = lerp(current.mSkySunriseColor, current.mSkyNightColor); + result.mNightFade = factor; + } + else if (mHour >= (WeatherGlobals::mSunriseTime-fade_duration)) + { + // fade out + float advance = mHour-(WeatherGlobals::mSunriseTime-fade_duration); + float factor = advance / fade_duration; + result.mFogColor = lerp(current.mFogSunriseColor, current.mFogDayColor); + result.mAmbientColor = lerp(current.mAmbientSunriseColor, current.mAmbientDayColor); + result.mSunColor = lerp(current.mSunSunriseColor, current.mSunDayColor); + result.mSkyColor = lerp(current.mSkySunriseColor, current.mSkyDayColor); + } + else + { + result.mFogColor = current.mFogSunriseColor; + result.mAmbientColor = current.mAmbientSunriseColor; + result.mSunColor = current.mSunSunriseColor; + result.mSkyColor = current.mSkySunriseColor; + } + } + + // day + else if (mHour >= (WeatherGlobals::mSunriseTime) && mHour <= (WeatherGlobals::mSunsetTime)) + { + result.mFogColor = current.mFogDayColor; + result.mAmbientColor = current.mAmbientDayColor; + result.mSunColor = current.mSunDayColor; + result.mSkyColor = current.mSkyDayColor; + } + + // sunset + else if (mHour >= (WeatherGlobals::mSunsetTime) && mHour <= (WeatherGlobals::mSunsetTime+WeatherGlobals::mSunsetDuration)) + { + if (mHour <= (WeatherGlobals::mSunsetTime+fade_duration)) + { + // fade in + float advance = (WeatherGlobals::mSunsetTime+fade_duration)-mHour; + float factor = (advance / fade_duration); + result.mFogColor = lerp(current.mFogSunsetColor, current.mFogDayColor); + result.mAmbientColor = lerp(current.mAmbientSunsetColor, current.mAmbientDayColor); + result.mSunColor = lerp(current.mSunSunsetColor, current.mSunDayColor); + result.mSkyColor = lerp(current.mSkySunsetColor, current.mSkyDayColor); + } + else if (mHour >= (WeatherGlobals::mSunsetTime+WeatherGlobals::mSunsetDuration-fade_duration)) + { + // fade out + float advance = mHour-(WeatherGlobals::mSunsetTime+WeatherGlobals::mSunsetDuration-fade_duration); + float factor = advance / fade_duration; + result.mFogColor = lerp(current.mFogSunsetColor, current.mFogNightColor); + result.mAmbientColor = lerp(current.mAmbientSunsetColor, current.mAmbientNightColor); + result.mSunColor = lerp(current.mSunSunsetColor, current.mSunNightColor); + result.mSkyColor = lerp(current.mSkySunsetColor, current.mSkyNightColor); + result.mNightFade = factor; + } + else + { + result.mFogColor = current.mFogSunsetColor; + result.mAmbientColor = current.mAmbientSunsetColor; + result.mSunColor = current.mSunSunsetColor; + result.mSkyColor = current.mSkySunsetColor; + } + } + + return result; +} + +WeatherResult WeatherManager::transition(float factor) +{ + const WeatherResult& current = getResult(mCurrentWeather); + const WeatherResult& other = getResult(mNextWeather); + WeatherResult result; + + result.mCloudTexture = current.mCloudTexture; + result.mNextCloudTexture = other.mCloudTexture; + result.mCloudBlendFactor = factor; + + result.mCloudOpacity = lerp(current.mCloudOpacity, other.mCloudOpacity); + result.mFogColor = lerp(current.mFogColor, other.mFogColor); + result.mSunColor = lerp(current.mSunColor, other.mSunColor); + result.mSkyColor = lerp(current.mSkyColor, other.mSkyColor); + + result.mAmbientColor = lerp(current.mAmbientColor, other.mAmbientColor); + result.mSunDiscColor = lerp(current.mSunDiscColor, other.mSunDiscColor); + result.mFogDepth = lerp(current.mFogDepth, other.mFogDepth); + result.mWindSpeed = lerp(current.mWindSpeed, other.mWindSpeed); + result.mCloudSpeed = lerp(current.mCloudSpeed, other.mCloudSpeed); + result.mCloudOpacity = lerp(current.mCloudOpacity, other.mCloudOpacity); + result.mGlareView = lerp(current.mGlareView, other.mGlareView); + + result.mNight = current.mNight; + + // sound change behaviour: + // if 'other' has a new sound, switch to it after 1/2 of the transition length + if (other.mAmbientLoopSoundID != "") + result.mAmbientLoopSoundID = factor>0.5 ? other.mAmbientLoopSoundID : current.mAmbientLoopSoundID; + // if 'current' has a sound and 'other' does not have a sound, turn off the sound immediately + else if (current.mAmbientLoopSoundID != "") + result.mAmbientLoopSoundID = ""; + + return result; +} + +void WeatherManager::update(float duration) +{ + mWeatherUpdateTime -= duration; + if (mEnvironment->mWorld->isCellExterior() || mEnvironment->mWorld->isCellQuasiExterior()) + { + std::string regionstr = mEnvironment->mWorld->getPlayer().getPlayer().getCell()->cell->region; + boost::algorithm::to_lower(regionstr); + + if (mWeatherUpdateTime <= 0 || regionstr != mCurrentRegion) + { + mCurrentRegion = regionstr; + mWeatherUpdateTime = WeatherGlobals::mWeatherUpdateTime*60.f; + + std::string weather; + + if (mRegionOverrides.find(regionstr) != mRegionOverrides.end()) + weather = mRegionOverrides[regionstr]; + else + { + // get weather probabilities for the current region + const ESM::Region *region = mEnvironment->mWorld->getStore().regions.find (regionstr); + + float clear = region->data.clear/255.f; + float cloudy = region->data.cloudy/255.f; + float foggy = region->data.foggy/255.f; + float overcast = region->data.overcast/255.f; + float rain = region->data.rain/255.f; + float thunder = region->data.thunder/255.f; + float ash = region->data.ash/255.f; + float blight = region->data.blight/255.f; + float snow = region->data.a/255.f; + float blizzard = region->data.b/255.f; + + // re-scale to 100 percent + const float total = clear+cloudy+foggy+overcast+rain+thunder+ash+blight+snow+blizzard; + + srand(time(NULL)); + float random = ((rand()%100)/100.f) * total; + + if (random >= snow+blight+ash+thunder+rain+overcast+foggy+cloudy+clear) + weather = "blizzard"; + else if (random >= blight+ash+thunder+rain+overcast+foggy+cloudy+clear) + weather = "snow"; + else if (random >= ash+thunder+rain+overcast+foggy+cloudy+clear) + weather = "blight"; + else if (random >= thunder+rain+overcast+foggy+cloudy+clear) + weather = "ashstorm"; + else if (random >= rain+overcast+foggy+cloudy+clear) + weather = "thunderstorm"; + else if (random >= overcast+foggy+cloudy+clear) + weather = "rain"; + else if (random >= foggy+cloudy+clear) + weather = "overcast"; + else if (random >= cloudy+clear) + weather = "foggy"; + else if (random >= clear) + weather = "cloudy"; + else + weather = "clear"; + } + + setWeather(weather, false); + /* + std::cout << "roll result: " << random << std::endl; + + std::cout << regionstr << " weather probabilities: " << clear << " " << cloudy << " " << foggy << " " + << overcast << " " << rain << " " << thunder << " " << ash << " " << blight << " " << snow << " " + << blizzard << std::endl; + + std::cout << "New weather : " << weather << std::endl; + */ + } + + WeatherResult result; + + if (mNextWeather != "") + { + mRemainingTransitionTime -= duration; + if (mRemainingTransitionTime < 0) + { + mCurrentWeather = mNextWeather; + mNextWeather = ""; + } + } + + if (mNextWeather != "") + result = transition(1-(mRemainingTransitionTime/(mWeatherSettings[mCurrentWeather].mTransitionDelta*24.f*60))); + else + result = getResult(mCurrentWeather); + + mRendering->configureFog(result.mFogDepth, result.mFogColor); + + // disable sun during night + if (mHour >= WeatherGlobals::mSunsetTime+WeatherGlobals::mSunsetDuration + || mHour <= WeatherGlobals::mSunriseTime-WeatherGlobals::mSunriseDuration) + mRendering->getSkyManager()->sunDisable(); + else + { + // during day, calculate sun angle + float height = 1-std::abs(((mHour-13)/7.f)); + int facing = mHour > 13.f ? 1 : -1; + Vector3 final( + (1-height)*facing, + (1-height)*facing, + height); + mRendering->setSunDirection(final); + + mRendering->getSkyManager()->sunEnable(); + } + + // moon calculations + float night; + if (mHour >= 14) + night = mHour-14; + else if (mHour <= 10) + night = mHour+10; + else + night = 0; + + night /= 20.f; + + if (night != 0) + { + float moonHeight = 1-std::abs((night-0.5)*2); + int facing = (mHour > 0.f && mHour<12.f) ? 1 : -1; + Vector3 masser( + (1-moonHeight)*facing, + (1-moonHeight)*facing, + moonHeight); + + Vector3 secunda( + (1-moonHeight)*facing*0.8, + (1-moonHeight)*facing*1.25, + moonHeight); + + mRendering->getSkyManager()->setMasserDirection(masser); + mRendering->getSkyManager()->setSecundaDirection(secunda); + mRendering->getSkyManager()->masserEnable(); + mRendering->getSkyManager()->secundaEnable(); + + float hour_fade; + if (mHour >= 7.f && mHour <= 14.f) + hour_fade = 1-(mHour-7)/3.f; + else if (mHour >= 14 && mHour <= 15.f) + hour_fade = mHour-14; + else + hour_fade = 1; + + float secunda_angle_fade; + float masser_angle_fade; + float angle = moonHeight*90.f; + + if (angle >= 30 && angle <= 50) + secunda_angle_fade = (angle-30)/20.f; + else if (angle <30) + secunda_angle_fade = 0.f; + else + secunda_angle_fade = 1.f; + + if (angle >= 40 && angle <= 50) + masser_angle_fade = (angle-40)/10.f; + else if (angle <40) + masser_angle_fade = 0.f; + else + masser_angle_fade = 1.f; + + masser_angle_fade *= hour_fade; + secunda_angle_fade *= hour_fade; + + mRendering->getSkyManager()->setMasserFade(masser_angle_fade); + mRendering->getSkyManager()->setSecundaFade(secunda_angle_fade); + } + else + { + mRendering->getSkyManager()->masserDisable(); + mRendering->getSkyManager()->secundaDisable(); + } + + if (mCurrentWeather == "thunderstorm" && mNextWeather == "") + { + if (mThunderFlash > 0) + { + // play the sound after a delay + mThunderSoundDelay -= duration; + if (mThunderSoundDelay <= 0) + { + // pick a random sound + int sound = rand() % 4; + std::string soundname; + if (sound == 0) soundname = WeatherGlobals::mThunderSoundID0; + else if (sound == 1) soundname = WeatherGlobals::mThunderSoundID1; + else if (sound == 2) soundname = WeatherGlobals::mThunderSoundID2; + else if (sound == 3) soundname = WeatherGlobals::mThunderSoundID3; + mEnvironment->mSoundManager->playSound(soundname, 1.0, 1.0); + mThunderSoundDelay = 1000; + } + + mThunderFlash -= duration; + if (mThunderFlash > 0) + mRendering->getSkyManager()->setThunder( mThunderFlash / WeatherGlobals::mThunderThreshold ); + else + { + srand(time(NULL)); + mThunderChanceNeeded = rand() % 100; + mThunderChance = 0; + mRendering->getSkyManager()->setThunder( 0.f ); + } + } + else + { + // no thunder active + mThunderChance += duration*4; // chance increases by 4 percent every second + if (mThunderChance >= mThunderChanceNeeded) + { + mThunderFlash = WeatherGlobals::mThunderThreshold; + + mRendering->getSkyManager()->setThunder( mThunderFlash / WeatherGlobals::mThunderThreshold ); + + mThunderSoundDelay = WeatherGlobals::mThunderSoundDelay; + } + } + } + else + mRendering->getSkyManager()->setThunder(0.f); + + mRendering->setAmbientColour(result.mAmbientColor); + mRendering->sunEnable(); + mRendering->setSunColour(result.mSunColor); + + mRendering->getSkyManager()->setWeather(result); + } + else + { + mRendering->sunDisable(); + mRendering->skyDisable(); + mRendering->getSkyManager()->setThunder(0.f); + } +} + +void WeatherManager::setHour(const float hour) +{ + // accelerate a bit for testing + /* + mHour += 0.005; + + if (mHour >= 24.f) mHour = 0.f; + + std::cout << "hour " << mHour << std::endl; + */ + + mHour = hour; +} + +void WeatherManager::setDate(const int day, const int month) +{ + mDay = day; + mMonth = month; +} + +unsigned int WeatherManager::getWeatherID() const +{ + // Source: http://www.uesp.net/wiki/Tes3Mod:GetCurrentWeather + + if (mCurrentWeather == "clear") + return 0; + else if (mCurrentWeather == "cloudy") + return 1; + else if (mCurrentWeather == "foggy") + return 2; + else if (mCurrentWeather == "overcast") + return 3; + else if (mCurrentWeather == "rain") + return 4; + else if (mCurrentWeather == "thunderstorm") + return 5; + else if (mCurrentWeather == "ashstorm") + return 6; + else if (mCurrentWeather == "blight") + return 7; + else if (mCurrentWeather == "snow") + return 8; + else if (mCurrentWeather == "blizzard") + return 9; + + else + return 0; +} + +void WeatherManager::changeWeather(const std::string& region, const unsigned int id) +{ + std::string weather; + if (id==0) + weather = "clear"; + else if (id==1) + weather = "cloudy"; + else if (id==2) + weather = "foggy"; + else if (id==3) + weather = "overcast"; + else if (id==4) + weather = "rain"; + else if (id==5) + weather = "thunderstorm"; + else if (id==6) + weather = "ashstorm"; + else if (id==7) + weather = "blight"; + else if (id==8) + weather = "snow"; + else if (id==9) + weather = "blizzard"; + else + weather = "clear"; + + mRegionOverrides[region] = weather; +} diff --git a/libs/openengine/bullet/weather.hpp b/libs/openengine/bullet/weather.hpp new file mode 100644 index 0000000000..9353f7cd1d --- /dev/null +++ b/libs/openengine/bullet/weather.hpp @@ -0,0 +1,272 @@ +#ifndef GAME_MWWORLD_WEATHER_H +#define GAME_MWWORLD_WEATHER_H + +#include +#include + +namespace MWRender +{ + class RenderingManager; +} + +namespace MWWorld +{ + class Environment; + + /// Global weather manager properties (according to INI) + struct WeatherGlobals + { + /* + [Weather] + EnvReduceColor=255,255,255,255 + LerpCloseColor=037,046,048,255 + BumpFadeColor=230,239,255,255 + AlphaReduce=0.35 + Minimum Time Between Environmental Sounds=1.0 + Maximum Time Between Environmental Sounds=5.0 + Sun Glare Fader Max=0.5 + Sun Glare Fader Angle Max=30.0 + Sun Glare Fader Color=222,095,039 + Timescale Clouds=0 + Precip Gravity=575 + Hours Between Weather Changes=20 + Rain Ripples=1 + Rain Ripple Radius=1024 + Rain Ripples Per Drop=1 + Rain Ripple Scale=0.3 + Rain Ripple Speed=1.0 + Fog Depth Change Speed=3 + Sunrise Time=6 + Sunset Time=18 + Sunrise Duration=2 + Sunset Duration=2 + Sky Pre-Sunrise Time=.5 + Sky Post-Sunrise Time=1 + Sky Pre-Sunset Time=1.5 + Sky Post-Sunset Time=.5 + Ambient Pre-Sunrise Time=.5 + Ambient Post-Sunrise Time=2 + Ambient Pre-Sunset Time=1 + Ambient Post-Sunset Time=1.25 + Fog Pre-Sunrise Time=.5 + Fog Post-Sunrise Time=1 + Fog Pre-Sunset Time=2 + Fog Post-Sunset Time=1 + Sun Pre-Sunrise Time=0 + Sun Post-Sunrise Time=0 + Sun Pre-Sunset Time=1 + Sun Post-Sunset Time=1.25 + Stars Post-Sunset Start=1 + Stars Pre-Sunrise Finish=2 + Stars Fading Duration=2 + Snow Ripples=0 + Snow Ripple Radius=1024 + Snow Ripples Per Flake=1 + Snow Ripple Scale=0.3 + Snow Ripple Speed=1.0 + Snow Gravity Scale=0.1 + Snow High Kill=700 + Snow Low Kill=150 + + + [Moons] + Masser Size=94 + Masser Fade In Start=14 + Masser Fade In Finish=15 + Masser Fade Out Start=7 + Masser Fade Out Finish=10 + Masser Axis Offset=35 + Masser Speed=.5 + Masser Daily Increment=1 + Masser Fade Start Angle=50 + Masser Fade End Angle=40 + Masser Moon Shadow Early Fade Angle=0.5 + Secunda Size=40 + Secunda Fade In Start=14 + Secunda Fade In Finish=15 + Secunda Fade Out Start=7 + Secunda Fade Out Finish=10 + Secunda Axis Offset=50 + Secunda Speed=.6 + Secunda Daily Increment=1.2 + Secunda Fade Start Angle=50 + Secunda Fade End Angle=30 + Secunda Moon Shadow Early Fade Angle=0.5 + Script Color=255,20,20 + */ + + static const float mSunriseTime; + static const float mSunsetTime; + static const float mSunriseDuration; + static const float mSunsetDuration; + + static const float mWeatherUpdateTime; + + // morrowind sets these per-weather, but since they are only used by 'thunderstorm' + // weather setting anyway, we can just as well set them globally + static const float mThunderFrequency; + static const float mThunderThreshold; + static const float mThunderSoundDelay; + static const std::string mThunderSoundID0; + static const std::string mThunderSoundID1; + static const std::string mThunderSoundID2; + static const std::string mThunderSoundID3; + }; + + /// Defines the actual weather that results from weather setting (see below), time of day and weather transition + struct WeatherResult + { + Ogre::String mCloudTexture; + Ogre::String mNextCloudTexture; + float mCloudBlendFactor; + + Ogre::ColourValue mFogColor; + + Ogre::ColourValue mAmbientColor; + + Ogre::ColourValue mSkyColor; + + Ogre::ColourValue mSunColor; + + Ogre::ColourValue mSunDiscColor; + + float mFogDepth; + + float mWindSpeed; + + float mCloudSpeed; + + float mCloudOpacity; + + float mGlareView; + + bool mNight; // use night skybox + float mNightFade; // fading factor for night skybox + + Ogre::String mAmbientLoopSoundID; + }; + + + /// Defines a single weather setting (according to INI) + struct Weather + { + Ogre::String mCloudTexture; + + // Sky (atmosphere) colors + Ogre::ColourValue mSkySunriseColor, + mSkyDayColor, + mSkySunsetColor, + mSkyNightColor; + + // Fog colors + Ogre::ColourValue mFogSunriseColor, + mFogDayColor, + mFogSunsetColor, + mFogNightColor; + + // Ambient lighting colors + Ogre::ColourValue mAmbientSunriseColor, + mAmbientDayColor, + mAmbientSunsetColor, + mAmbientNightColor; + + // Sun (directional) lighting colors + Ogre::ColourValue mSunSunriseColor, + mSunDayColor, + mSunSunsetColor, + mSunNightColor; + + // Fog depth/density + float mLandFogDayDepth, + mLandFogNightDepth; + + // Color modulation for the sun itself during sunset (not completely sure) + Ogre::ColourValue mSunDiscSunsetColor; + + // Duration of weather transition (in days) + float mTransitionDelta; + + // No idea what this one is used for? + float mWindSpeed; + + // Cloud animation speed multiplier + float mCloudSpeed; + + // Multiplier for clouds transparency + float mCloudsMaximumPercent; + + // Value between 0 and 1, defines the strength of the sun glare effect + float mGlareView; + + // Sound effect + // This is used for Blight, Ashstorm and Blizzard (Bloodmoon) + Ogre::String mAmbientLoopSoundID; + + // Rain sound effect + Ogre::String mRainLoopSoundID; + + /// \todo disease chance + }; + + /// + /// Interface for weather settings + /// + class WeatherManager + { + public: + WeatherManager(MWRender::RenderingManager*, MWWorld::Environment*); + + /** + * Change the weather in the specified region + * @param region that should be changed + * @param ID of the weather setting to shift to + */ + void changeWeather(const std::string& region, const unsigned int id); + + /** + * Per-frame update + * @param duration + */ + void update(float duration); + + void setHour(const float hour); + + void setDate(const int day, const int month); + + unsigned int getWeatherID() const; + + private: + float mHour; + int mDay, mMonth; + + MWRender::RenderingManager* mRendering; + MWWorld::Environment* mEnvironment; + + std::map mWeatherSettings; + + std::map mRegionOverrides; + + Ogre::String mCurrentWeather; + Ogre::String mNextWeather; + + std::string mCurrentRegion; + + bool mFirstUpdate; + + float mWeatherUpdateTime; + + float mRemainingTransitionTime; + + float mThunderFlash; + float mThunderChance; + float mThunderChanceNeeded; + float mThunderSoundDelay; + + WeatherResult transition(const float factor); + WeatherResult getResult(const Ogre::String& weather); + + void setWeather(const Ogre::String& weather, bool instant=false); + }; +} + +#endif // GAME_MWWORLD_WEATHER_H From e4251be5299c7114a9b3f9053b5bb35706062453 Mon Sep 17 00:00:00 2001 From: Jason Hooks Date: Sun, 25 Mar 2012 15:16:02 -0400 Subject: [PATCH 002/325] Down gravity --- apps/openmw/mwworld/physicssystem.cpp | 1 + libs/openengine/bullet/pmove.cpp | 75 +-- libs/openengine/bullet/trace.cpp | 10 +- libs/openengine/bullet/weather.cpp | 811 -------------------------- libs/openengine/bullet/weather.hpp | 272 --------- 5 files changed, 46 insertions(+), 1123 deletions(-) delete mode 100644 libs/openengine/bullet/weather.cpp delete mode 100644 libs/openengine/bullet/weather.hpp diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index d54f4696a2..15d2d3f9f6 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -148,6 +148,7 @@ namespace MWWorld if(it->first == "player"){ coord = playerphysics->ps.origin; + //std::cout << "ZCoord: " << coord.z << "\n"; //std::cout << "Coord" << coord << "\n"; //coord = Ogre::Vector3(coord.x, coord.z, coord.y); //x, z, -y diff --git a/libs/openengine/bullet/pmove.cpp b/libs/openengine/bullet/pmove.cpp index 71c15fe45f..8dd01ef190 100644 --- a/libs/openengine/bullet/pmove.cpp +++ b/libs/openengine/bullet/pmove.cpp @@ -178,7 +178,7 @@ bool PM_SlideMove( bool gravity ) float into; Ogre::Vector3 endVelocity; Ogre::Vector3 endClipVelocity; - + std::cout << "Slide move\n"; numbumps = 4; // primal_velocity = pm->ps->velocity @@ -191,14 +191,14 @@ bool PM_SlideMove( bool gravity ) //VectorCopy( pm->ps->velocity, endVelocity ); endVelocity = pm->ps.velocity; //endVelocity[2] -= pm->ps->gravity * pml.frametime; - endVelocity.y -= pm->ps.gravity * pml.frametime; + endVelocity.z -= pm->ps.gravity * pml.frametime; // pm->ps->velocity = avg(pm->ps->velocity.z, endVelocity.z) //pm->ps->velocity[2] = ( pm->ps->velocity[2] + endVelocity[2] ) * 0.5; - pm->ps.velocity.y= (pm->ps.velocity.y + endVelocity.y) * 0.5f; + pm->ps.velocity.z= (pm->ps.velocity.z + endVelocity.z) * 0.5f; //primal_velocity[2] = endVelocity[2]; - primal_velocity.y = endVelocity.y; + primal_velocity.z = endVelocity.z; if ( pml.groundPlane ) // slide along the ground plane @@ -239,7 +239,7 @@ bool PM_SlideMove( bool gravity ) { // entity is completely trapped in another solid //pm->ps->velocity[2] = 0; // don't build up falling damage, but allow sideways acceleration - pm->ps.velocity.y = 0; + pm->ps.velocity.z = 0; return true; } @@ -427,10 +427,11 @@ int PM_StepSlideMove( bool gravity ) if ( PM_SlideMove( gravity ) == false ) return 1; // we got exactly where we wanted to go first try + std::cout << "Step Slide move\n"; // down = start_o - vec3(0, 0, STEPSIZE) //VectorCopy(start_o, down); down = start_o; - down.y -= STEPSIZE; + down.z -= STEPSIZE; //pm->trace (&trace, start_o, pm->mins, pm->maxs, down, pm->ps->clientNum, pm->tracemask); //tracefunc(&trace, start_o, down, , 0, pml.scene); @@ -439,11 +440,11 @@ int PM_StepSlideMove( bool gravity ) // up = vec3(0, 0, 1) //VectorSet(up, 0, 0, 1); - up = Ogre::Vector3(0.0f, 1.0f, 0.0f); + up = Ogre::Vector3(0.0f, 0.0f, 1.0f); // never step up when you still have up velocity //if ( pm->ps->velocity[2] > 0 && (trace.fraction == 1.0 || DotProduct(trace.plane.normal, up) < 0.7)) - if (pm->ps.velocity.y > 0 && ( + if (pm->ps.velocity.z > 0 && ( trace.fraction == 1.0 || trace.planenormal.dotProduct(up) < 0.7 ) ) return 2; @@ -460,7 +461,7 @@ int PM_StepSlideMove( bool gravity ) //VectorCopy (start_o, up); up = start_o; //up[2] += STEPSIZE; - up.y += STEPSIZE; + up.z += STEPSIZE; // test the player position if they were a stepheight higher //pm->trace (&trace, start_o, pm->mins, pm->maxs, up, pm->ps->clientNum, pm->tracemask); @@ -475,7 +476,7 @@ int PM_StepSlideMove( bool gravity ) } //stepSize = trace.endpos[2] - start_o[2]; - stepSize = trace.endpos.y - start_o.y; + stepSize = trace.endpos.z - start_o.z; // try slidemove from this position //VectorCopy (trace.endpos, pm->ps->origin); // pm->ps->origin = trace.endpos @@ -491,7 +492,7 @@ int PM_StepSlideMove( bool gravity ) //VectorCopy (pm->ps->origin, down); down = pm->ps.origin; //down[2] -= stepSize; - down.y -= stepSize; + down.z -= stepSize; //pm->trace (&trace, pm->ps->origin, pm->mins, pm->maxs, down, pm->ps->clientNum, pm->tracemask); @@ -510,7 +511,7 @@ int PM_StepSlideMove( bool gravity ) float delta; //delta = pm->ps->origin[2] - start_o[2]; - delta = pm->ps.origin.y - start_o.y; + delta = pm->ps.origin.z - start_o.z; if ( delta > 2 ) { if (gravity) @@ -541,6 +542,7 @@ int PM_StepSlideMove( bool gravity ) void PM_Friction(void) { + std::cout << "Friction\n"; Ogre::Vector3 vec; float* vel; float speed, newspeed, control; @@ -554,14 +556,14 @@ void PM_Friction(void) if ( pml.walking ) //vec[2] = 0; // ignore slope movement - vec.y = 0; + vec.z = 0; //speed = VectorLength(vec); speed = vec.length(); if (speed < 1) { vel[0] = 0; - vel[2] = 0; // allow sinking underwater + vel[1] = 0; // allow sinking underwater // FIXME: still have z friction underwater? //bprintf("Static friction (vec = [%f, %f, %f]) (vec.length = %f)\n", vec.x, vec.y, vec.z, speed); return; @@ -636,6 +638,7 @@ static void PM_Accelerate( Ogre::Vector3& wishdir, float wishspeed, float accel { // int i; float addspeed, accelspeed, currentspeed; + std::cout << "Accelerate\n"; // currentspeed = pm->ps->velocity dot wishdir //currentspeed = DotProduct (pm->ps->velocity, wishdir); @@ -681,7 +684,7 @@ static bool PM_CheckJump(void) //pm->ps->pm_flags |= PMF_JUMP_HELD; pm->ps.groundEntityNum = ENTITYNUM_NONE; - pm->ps.velocity.y = JUMP_VELOCITY; + pm->ps.velocity.z = JUMP_VELOCITY; //PM_AddEvent( EV_JUMP ); /*if ( pm->cmd.forwardmove >= 0 ) @@ -776,8 +779,8 @@ static void PM_WaterMove( playerMove* const pm ) wishvel[2] = -60; // sink towards bottom */ wishvel.x = 0; - wishvel.y = -60; - wishvel.z = 0; + wishvel.z = -60; + wishvel.y = 0; } else { @@ -834,6 +837,7 @@ static void PM_WalkMove( playerMove* const pmove ) playerMove::playercmd cmd; float accelerate; float vel; + std::cout << "Walking\n"; if ( pm->ps.waterlevel > 2 && //DotProduct( pml.forward, pml.groundTrace.plane.normal ) > 0 ) pml.forward.dotProduct(pml.groundTrace.planenormal) > 0.0f) @@ -937,10 +941,10 @@ static void PM_WalkMove( playerMove* const pmove ) // project moves down to flat plane //pml.forward[2] = 0; - pml.forward.y = 0; + pml.forward.z = 0; //pml.right[2] = 0; - pml.right.y = 0; + pml.right.z = 0; // project the forward and right directions onto the ground plane PM_ClipVelocity (pml.forward, pml.groundTrace.planenormal, pml.forward, OVERCLIP ); @@ -1035,7 +1039,7 @@ void PM_UpdateViewAngles( playerMove::playerStruct* const ps, playerMove::player { short temp; int i; - + std::cout << "Updating viewangles\n"; //while(1); //if ( ps->pm_type == PM_INTERMISSION || ps->pm_type == PM_SPINTERMISSION) @@ -1128,7 +1132,7 @@ void PM_GroundTraceMissed() //VectorCopy( pm->ps->origin, point ); point = pm->ps.origin; //point[2] -= 64; - point.y -= 64; + point.z -= 64; //pm->trace (&trace, pm->ps->origin, pm->mins, pm->maxs, point, pm->ps->clientNum, pm->tracemask); //tracefunc(&trace, *(const D3DXVECTOR3* const)&(pm->ps.origin), *(const D3DXVECTOR3* const)&point, D3DXVECTOR3(0.0f, -64.0f, 0.0f), 0, pml.traceObj); @@ -1188,7 +1192,7 @@ static bool PM_CorrectAllSolid(traceResults* const trace) point[1] = pm->ps->origin[1]; point[2] = pm->ps->origin[2] - 0.25;*/ point = pm->ps.origin; - point.y -= 0.25f; + point.z -= 0.25f; //pm->trace (trace, pm->ps->origin, pm->mins, pm->maxs, point, pm->ps->clientNum, pm->tracemask); //tracefunc(trace, *(const D3DXVECTOR3* const)&(pm->ps.origin), *(const D3DXVECTOR3* const)&point, D3DXVECTOR3(0.0f, -0.25f, 0.0f), 0, pml.traceObj); @@ -1215,7 +1219,7 @@ static void PM_CrashLand( void ) float vel, acc; float t; float a, b, c, den; - + std::cout << "Crash land\n"; // decide which landing animation to use /*if ( pm->ps->pm_flags & PMF_BACKWARDS_JUMP ) PM_ForceLegsAnim( LEGS_LANDB ); @@ -1227,10 +1231,10 @@ static void PM_CrashLand( void ) // calculate the exact velocity on landing //dist = pm->ps->origin[2] - pml.previous_origin[2]; - dist = pm->ps.origin.y - pml.previous_origin.y; + dist = pm->ps.origin.z - pml.previous_origin.z; //vel = pml.previous_velocity[2]; - vel = pml.previous_velocity.y; + vel = pml.previous_velocity.z; //acc = -pm->ps->gravity; acc = -pm->ps.gravity; @@ -1294,7 +1298,7 @@ static void PM_CrashLand( void ) const float waterHeight = pm->waterHeight; const float waterHeightSplash = waterHeight + halfExtents.y; - if (pm->ps.origin.y < waterHeightSplash) + if (pm->ps.origin.z < waterHeightSplash) { splashSound = true; } @@ -1357,7 +1361,7 @@ static void PM_CrashLand( void ) static void PM_GroundTrace( void ) { - //std::cout << "Ground trace\n"; + std::cout << "Ground trace\n"; Ogre::Vector3 point; traceResults trace; @@ -1365,7 +1369,7 @@ static void PM_GroundTrace( void ) point[1] = pm->ps->origin[1]; point[2] = pm->ps->origin[2] - 0.25;*/ point = pm->ps.origin; - point.y -= 0.25f; + point.z -= 0.25f; //pm->trace (&trace, pm->ps->origin, pm->mins, pm->maxs, point, pm->ps->clientNum, pm->tracemask); //tracefunc(&trace, *(const D3DXVECTOR3* const)&(pm->ps.origin), *(const D3DXVECTOR3* const)&point, D3DXVECTOR3(0.0f, -0.25f, 0.0f), 0, pml.traceObj); @@ -1392,7 +1396,7 @@ static void PM_GroundTrace( void ) // check if getting thrown off the ground //if ( pm->ps->velocity[2] > 0 && DotProduct( pm->ps->velocity, trace.plane.normal ) > 10 ) - if (pm->ps.velocity.y > 0 && pm->ps.velocity.dotProduct(trace.planenormal) > 10.0f) + if (pm->ps.velocity.z > 0 && pm->ps.velocity.dotProduct(trace.planenormal) > 10.0f) { //if ( pm->debugLevel ) //Com_Printf("%i:kickoff\n", c_pmove); @@ -1417,7 +1421,7 @@ static void PM_GroundTrace( void ) // slopes that are too steep will not be considered onground //if ( trace.plane.normal[2] < MIN_WALK_NORMAL ) - if (trace.planenormal.y < MIN_WALK_NORMAL) + if (trace.planenormal.z < MIN_WALK_NORMAL) { //if ( pm->debugLevel ) //Com_Printf("%i:steep\n", c_pmove); @@ -1451,7 +1455,7 @@ static void PM_GroundTrace( void ) // don't do landing time if we were just going down a slope //if ( pml.previous_velocity[2] < -200 ) - if (pml.previous_velocity.y < -200) + if (pml.previous_velocity.z < -200) { // don't allow another jump for a little while //pm->ps->pm_flags |= PMF_TIME_LAND; @@ -1469,6 +1473,7 @@ static void PM_GroundTrace( void ) static void PM_AirMove() { + std::cout << "Air move\n"; //int i; Ogre::Vector3 wishvel; float fmove, smove; @@ -1490,7 +1495,7 @@ static void PM_AirMove() // project moves down to flat plane //pml.forward[2] = 0; - pml.forward.y = 0; + pml.forward.y = 0; //Z or Y? //pml.right[2] = 0; pml.right.y = 0; //VectorNormalize (pml.forward); @@ -1503,7 +1508,7 @@ static void PM_AirMove() wishvel = pml.forward * fmove + pml.right * smove; //wishvel[2] = 0; - wishvel.y = 0; + wishvel.z = 0; //VectorCopy (wishvel, wishdir); wishdir = wishvel; @@ -1659,7 +1664,7 @@ static void PM_FlyMove( void ) wishvel = pml.forward * scale * pm->cmd.forwardmove + pml.right * scale * pm->cmd.rightmove; //wishvel[2] += scale * pm->cmd.upmove; - wishvel.y += /*6.35f * */pm->cmd.upmove * scale; + wishvel.z += /*6.35f * */pm->cmd.upmove * scale; } //VectorCopy (wishvel, wishdir); @@ -1939,7 +1944,7 @@ void PmoveSingle (playerMove* const pmove) PM_WaterMove(pmove); else if ( pml.walking ) { - std::cout << "WALKING\n"; + // walking on ground PM_WalkMove(pmove); //bprintf("WalkMove\n"); diff --git a/libs/openengine/bullet/trace.cpp b/libs/openengine/bullet/trace.cpp index 57d071f170..8f2423c242 100644 --- a/libs/openengine/bullet/trace.cpp +++ b/libs/openengine/bullet/trace.cpp @@ -28,11 +28,11 @@ void newtrace(traceResults* const results, const Ogre::Vector3& start, const Ogr NewPhysTraceResults out; //std::cout << "Starting trace\n"; - Ogre::Vector3 startReplace = Ogre::Vector3(650,950, 45); - Ogre::Vector3 endReplace = startReplace; - endReplace.y -= .25; + //Ogre::Vector3 startReplace = Ogre::Vector3(650,950, 45); + //Ogre::Vector3 endReplace = startReplace; + //endReplace.z -= .25; - const bool hasHit = NewPhysicsTrace(&out, start, end, BBHalfExtents, Ogre::Vector3(0.0f, rotation, 0.0f), isInterior, enginePass); + const bool hasHit = NewPhysicsTrace(&out, start, end, BBHalfExtents, Ogre::Vector3(0.0f, 0.0f, rotation), isInterior, enginePass); if(hasHit) std::cout << "Has hit\n"; if (out.fraction < 0.001f) @@ -65,7 +65,7 @@ void newtrace(traceResults* const results, const Ogre::Vector3& start, const Ogr if (!hasHit) { results->endpos = end; - results->planenormal = Ogre::Vector3(0.0f, 1.0f, 0.0f); + results->planenormal = Ogre::Vector3(0.0f, 0.0f, 1.0f); results->entityNum = ENTITYNUM_NONE; results->fraction = 1.0f; } diff --git a/libs/openengine/bullet/weather.cpp b/libs/openengine/bullet/weather.cpp deleted file mode 100644 index 90afc4e78b..0000000000 --- a/libs/openengine/bullet/weather.cpp +++ /dev/null @@ -1,811 +0,0 @@ -#include "weather.hpp" -#include "world.hpp" -#include "player.hpp" - -#include "../mwrender/renderingmanager.hpp" -#include "../mwsound/soundmanager.hpp" - -#include -#include -#include - -#include - -using namespace Ogre; -using namespace MWWorld; -using namespace MWSound; - -#define lerp(x, y) (x * (1-factor) + y * factor) - -const std::string WeatherGlobals::mThunderSoundID0 = "Thunder0"; -const std::string WeatherGlobals::mThunderSoundID1 = "Thunder1"; -const std::string WeatherGlobals::mThunderSoundID2 = "Thunder2"; -const std::string WeatherGlobals::mThunderSoundID3 = "Thunder3"; -const float WeatherGlobals::mSunriseTime = 8; -const float WeatherGlobals::mSunsetTime = 18; -const float WeatherGlobals::mSunriseDuration = 2; -const float WeatherGlobals::mSunsetDuration = 2; -const float WeatherGlobals::mWeatherUpdateTime = 20.f; -const float WeatherGlobals::mThunderFrequency = .4; -const float WeatherGlobals::mThunderThreshold = 0.6; -const float WeatherGlobals::mThunderSoundDelay = 0.25; - -WeatherManager::WeatherManager(MWRender::RenderingManager* rendering, Environment* env) : - mHour(14), mCurrentWeather("clear"), mFirstUpdate(true), mWeatherUpdateTime(0), - mThunderFlash(0), mThunderChance(0), mThunderChanceNeeded(50), mThunderSoundDelay(0) -{ - mRendering = rendering; - mEnvironment = env; - - #define clr(r,g,b) ColourValue(r/255.f, g/255.f, b/255.f) - - /// \todo read these from Morrowind.ini - Weather clear; - clear.mCloudTexture = "tx_sky_clear.dds"; - clear.mCloudsMaximumPercent = 1.0; - clear.mTransitionDelta = 0.015; - clear.mSkySunriseColor = clr(118, 141, 164); - clear.mSkyDayColor = clr(95, 135, 203); - clear.mSkySunsetColor = clr(56, 89, 129); - clear.mSkyNightColor = clr(9, 10, 11); - clear.mFogSunriseColor = clr(255, 189, 157); - clear.mFogDayColor = clr(206, 227, 255); - clear.mFogSunsetColor = clr(255, 189, 157); - clear.mFogNightColor = clr(9, 10, 11); - clear.mAmbientSunriseColor = clr(47, 66, 96); - clear.mAmbientDayColor = clr(137, 140, 160); - clear.mAmbientSunsetColor = clr(68, 75, 96); - clear.mAmbientNightColor = clr(32, 35, 42); - clear.mSunSunriseColor = clr(242, 159, 99); - clear.mSunDayColor = clr(255, 252, 238); - clear.mSunSunsetColor = clr(255, 115, 79); - clear.mSunNightColor = clr(59, 97, 176); - clear.mSunDiscSunsetColor = clr(255, 189, 157); - clear.mLandFogDayDepth = 0.69; - clear.mLandFogNightDepth = 0.69; - clear.mWindSpeed = 0.1; - clear.mCloudSpeed = 1.25; - clear.mGlareView = 1.0; - mWeatherSettings["clear"] = clear; - - Weather cloudy; - cloudy.mCloudTexture = "tx_sky_cloudy.dds"; - cloudy.mCloudsMaximumPercent = 1.0; - cloudy.mTransitionDelta = 0.015; - cloudy.mSkySunriseColor = clr(126, 158, 173); - cloudy.mSkyDayColor = clr(117, 160, 215); - cloudy.mSkySunsetColor = clr(111, 114, 159); - cloudy.mSkyNightColor = clr(9, 10, 11); - cloudy.mFogSunriseColor = clr(255, 207, 149); - cloudy.mFogDayColor = clr(245, 235, 224); - cloudy.mFogSunsetColor = clr(255, 155, 106); - cloudy.mFogNightColor = clr(9, 10, 11); - cloudy.mAmbientSunriseColor = clr(66, 74, 87); - cloudy.mAmbientDayColor = clr(137, 145, 160); - cloudy.mAmbientSunsetColor = clr(71, 80, 92); - cloudy.mAmbientNightColor = clr(32, 39, 54); - cloudy.mSunSunriseColor = clr(241, 177, 99); - cloudy.mSunDayColor = clr(255, 236, 221); - cloudy.mSunSunsetColor = clr(255, 89, 00); - cloudy.mSunNightColor = clr(77, 91, 124); - cloudy.mSunDiscSunsetColor = clr(255, 202, 179); - cloudy.mLandFogDayDepth = 0.72; - cloudy.mLandFogNightDepth = 0.72; - cloudy.mWindSpeed = 0.2; - cloudy.mCloudSpeed = 2; - cloudy.mGlareView = 1.0; - mWeatherSettings["cloudy"] = cloudy; - - Weather foggy; - foggy.mCloudTexture = "tx_sky_foggy.dds"; - foggy.mCloudsMaximumPercent = 1.0; - foggy.mTransitionDelta = 0.015; - foggy.mSkySunriseColor = clr(197, 190, 180); - foggy.mSkyDayColor = clr(184, 211, 228); - foggy.mSkySunsetColor = clr(142, 159, 176); - foggy.mSkyNightColor = clr(18, 23, 28); - foggy.mFogSunriseColor = clr(173, 164, 148); - foggy.mFogDayColor = clr(150, 187, 209); - foggy.mFogSunsetColor = clr(113, 135, 157); - foggy.mFogNightColor = clr(19, 24, 29); - foggy.mAmbientSunriseColor = clr(48, 43, 37); - foggy.mAmbientDayColor = clr(92, 109, 120); - foggy.mAmbientSunsetColor = clr(28, 33, 39); - foggy.mAmbientNightColor = clr(28, 33, 39); - foggy.mSunSunriseColor = clr(177, 162, 137); - foggy.mSunDayColor = clr(111, 131, 151); - foggy.mSunSunsetColor = clr(125, 157, 189); - foggy.mSunNightColor = clr(81, 100, 119); - foggy.mSunDiscSunsetColor = clr(223, 223, 223); - foggy.mLandFogDayDepth = 1.0; - foggy.mLandFogNightDepth = 1.9; - foggy.mWindSpeed = 0; - foggy.mCloudSpeed = 1.25; - foggy.mGlareView = 0.25; - mWeatherSettings["foggy"] = foggy; - - Weather thunderstorm; - thunderstorm.mCloudTexture = "tx_sky_thunder.dds"; - thunderstorm.mCloudsMaximumPercent = 0.66; - thunderstorm.mTransitionDelta = 0.03; - thunderstorm.mSkySunriseColor = clr(35, 36, 39); - thunderstorm.mSkyDayColor = clr(97, 104, 115); - thunderstorm.mSkySunsetColor = clr(35, 36, 39); - thunderstorm.mSkyNightColor = clr(19, 20, 22); - thunderstorm.mFogSunriseColor = clr(70, 74, 85); - thunderstorm.mFogDayColor = clr(97, 104, 115); - thunderstorm.mFogSunsetColor = clr(70, 74, 85); - thunderstorm.mFogNightColor = clr(19, 20, 22); - thunderstorm.mAmbientSunriseColor = clr(54, 54, 54); - thunderstorm.mAmbientDayColor = clr(90, 90, 90); - thunderstorm.mAmbientSunsetColor = clr(54, 54, 54); - thunderstorm.mAmbientNightColor = clr(49, 51, 54); - thunderstorm.mSunSunriseColor = clr(91, 99, 122); - thunderstorm.mSunDayColor = clr(138, 144, 155); - thunderstorm.mSunSunsetColor = clr(96, 101, 117); - thunderstorm.mSunNightColor = clr(55, 76, 110); - thunderstorm.mSunDiscSunsetColor = clr(128, 128, 128); - thunderstorm.mLandFogDayDepth = 1; - thunderstorm.mLandFogNightDepth = 1.15; - thunderstorm.mWindSpeed = 0.5; - thunderstorm.mCloudSpeed = 3; - thunderstorm.mGlareView = 0; - thunderstorm.mRainLoopSoundID = "rain heavy"; - mWeatherSettings["thunderstorm"] = thunderstorm; - - Weather rain; - rain.mCloudTexture = "tx_sky_rainy.dds"; - rain.mCloudsMaximumPercent = 0.66; - rain.mTransitionDelta = 0.015; - rain.mSkySunriseColor = clr(71, 74, 75); - rain.mSkyDayColor = clr(116, 120, 122); - rain.mSkySunsetColor = clr(73, 73, 73); - rain.mSkyNightColor = clr(24, 25, 26); - rain.mFogSunriseColor = clr(71, 74, 75); - rain.mFogDayColor = clr(116, 120, 122); - rain.mFogSunsetColor = clr(73, 73, 73); - rain.mFogNightColor = clr(24, 25, 26); - rain.mAmbientSunriseColor = clr(97, 90, 88); - rain.mAmbientDayColor = clr(105, 110, 113); - rain.mAmbientSunsetColor = clr(88, 97, 97); - rain.mAmbientNightColor = clr(50, 55, 67); - rain.mSunSunriseColor = clr(131, 122, 120); - rain.mSunDayColor = clr(149, 157, 170); - rain.mSunSunsetColor = clr(120, 126, 131); - rain.mSunNightColor = clr(50, 62, 101); - rain.mSunDiscSunsetColor = clr(128, 128, 128); - rain.mLandFogDayDepth = 0.8; - rain.mLandFogNightDepth = 0.8; - rain.mWindSpeed = 0.3; - rain.mCloudSpeed = 2; - rain.mGlareView = 0; - rain.mRainLoopSoundID = "rain"; - mWeatherSettings["rain"] = rain; - - Weather overcast; - overcast.mCloudTexture = "tx_sky_overcast.dds"; - overcast.mCloudsMaximumPercent = 1.0; - overcast.mTransitionDelta = 0.015; - overcast.mSkySunriseColor = clr(91, 99, 106); - overcast.mSkyDayColor = clr(143, 146, 149); - overcast.mSkySunsetColor = clr(108, 115, 121); - overcast.mSkyNightColor = clr(19, 22, 25); - overcast.mFogSunriseColor = clr(91, 99, 106); - overcast.mFogDayColor = clr(143, 146, 149); - overcast.mFogSunsetColor = clr(108, 115, 121); - overcast.mFogNightColor = clr(19, 22, 25); - overcast.mAmbientSunriseColor = clr(84, 88, 92); - overcast.mAmbientDayColor = clr(93, 96, 105); - overcast.mAmbientSunsetColor = clr(83, 77, 75); - overcast.mAmbientNightColor = clr(57, 60, 66); - overcast.mSunSunriseColor = clr(87, 125, 163); - overcast.mSunDayColor = clr(163, 169, 183); - overcast.mSunSunsetColor = clr(85, 103, 157); - overcast.mSunNightColor = clr(32, 54, 100); - overcast.mSunDiscSunsetColor = clr(128, 128, 128); - overcast.mLandFogDayDepth = 0.7; - overcast.mLandFogNightDepth = 0.7; - overcast.mWindSpeed = 0.2; - overcast.mCloudSpeed = 1.5; - overcast.mGlareView = 0; - mWeatherSettings["overcast"] = overcast; - - Weather ashstorm; - ashstorm.mCloudTexture = "tx_sky_ashstorm.dds"; - ashstorm.mCloudsMaximumPercent = 1.0; - ashstorm.mTransitionDelta = 0.035; - ashstorm.mSkySunriseColor = clr(91, 56, 51); - ashstorm.mSkyDayColor = clr(124, 73, 58); - ashstorm.mSkySunsetColor = clr(106, 55, 40); - ashstorm.mSkyNightColor = clr(20, 21, 22); - ashstorm.mFogSunriseColor = clr(91, 56, 51); - ashstorm.mFogDayColor = clr(124, 73, 58); - ashstorm.mFogSunsetColor = clr(106, 55, 40); - ashstorm.mFogNightColor = clr(20, 21, 22); - ashstorm.mAmbientSunriseColor = clr(52, 42, 37); - ashstorm.mAmbientDayColor = clr(75, 49, 41); - ashstorm.mAmbientSunsetColor = clr(48, 39, 35); - ashstorm.mAmbientNightColor = clr(36, 42, 49); - ashstorm.mSunSunriseColor = clr(184, 91, 71); - ashstorm.mSunDayColor = clr(228, 139, 114); - ashstorm.mSunSunsetColor = clr(185, 86, 57); - ashstorm.mSunNightColor = clr(54, 66, 74); - ashstorm.mSunDiscSunsetColor = clr(128, 128, 128); - ashstorm.mLandFogDayDepth = 1.1; - ashstorm.mLandFogNightDepth = 1.2; - ashstorm.mWindSpeed = 0.8; - ashstorm.mCloudSpeed = 7; - ashstorm.mGlareView = 0; - ashstorm.mAmbientLoopSoundID = "ashstorm"; - mWeatherSettings["ashstorm"] = ashstorm; - - Weather blight; - blight.mCloudTexture = "tx_sky_blight.dds"; - blight.mCloudsMaximumPercent = 1.0; - blight.mTransitionDelta = 0.04; - blight.mSkySunriseColor = clr(90, 35, 35); - blight.mSkyDayColor = clr(90, 35, 35); - blight.mSkySunsetColor = clr(92, 33, 33); - blight.mSkyNightColor = clr(44, 14, 14); - blight.mFogSunriseColor = clr(90, 35, 35); - blight.mFogDayColor = clr(128, 19, 19); - blight.mFogSunsetColor = clr(92, 33, 33); - blight.mFogNightColor = clr(44, 14, 14); - blight.mAmbientSunriseColor = clr(61, 40, 40); - blight.mAmbientDayColor = clr(79, 54, 54); - blight.mAmbientSunsetColor = clr(61, 40, 40); - blight.mAmbientNightColor = clr(56, 58, 62); - blight.mSunSunriseColor = clr(180, 78, 78); - blight.mSunDayColor = clr(224, 84, 84); - blight.mSunSunsetColor = clr(180, 78, 78); - blight.mSunNightColor = clr(61, 91, 143); - blight.mSunDiscSunsetColor = clr(128, 128, 128); - blight.mLandFogDayDepth = 1.1; - blight.mLandFogNightDepth = 1.2; - blight.mWindSpeed = 0.9; - blight.mCloudSpeed = 9; - blight.mGlareView = 0; - blight.mAmbientLoopSoundID = "blight"; - mWeatherSettings["blight"] = blight; - - Weather snow; - snow.mCloudTexture = "tx_bm_sky_snow.dds"; - snow.mCloudsMaximumPercent = 1.0; - snow.mTransitionDelta = 0.014; - snow.mSkySunriseColor = clr(196, 91, 91); - snow.mSkyDayColor = clr(153, 158, 166); - snow.mSkySunsetColor = clr(96, 115, 134); - snow.mSkyNightColor = clr(31, 35, 39); - snow.mFogSunriseColor = clr(106, 91, 91); - snow.mFogDayColor = clr(153, 158, 166); - snow.mFogSunsetColor = clr(96, 115, 134); - snow.mFogNightColor = clr(31, 35, 39); - snow.mAmbientSunriseColor = clr(92, 84, 84); - snow.mAmbientDayColor = clr(93, 96, 105); - snow.mAmbientSunsetColor = clr(70, 79, 87); - snow.mAmbientNightColor = clr(49, 58, 68); - snow.mSunSunriseColor = clr(141, 109, 109); - snow.mSunDayColor = clr(163, 169, 183); - snow.mSunSunsetColor = clr(101, 121, 141); - snow.mSunNightColor = clr(55, 66, 77); - snow.mSunDiscSunsetColor = clr(128, 128, 128); - snow.mLandFogDayDepth = 1.0; - snow.mLandFogNightDepth = 1.2; - snow.mWindSpeed = 0; - snow.mCloudSpeed = 1.5; - snow.mGlareView = 0; - mWeatherSettings["snow"] = snow; - - Weather blizzard; - blizzard.mCloudTexture = "tx_bm_sky_blizzard.dds"; - blizzard.mCloudsMaximumPercent = 1.0; - blizzard.mTransitionDelta = 0.030; - blizzard.mSkySunriseColor = clr(91, 99, 106); - blizzard.mSkyDayColor = clr(121, 133, 145); - blizzard.mSkySunsetColor = clr(108, 115, 121); - blizzard.mSkyNightColor = clr(27, 29, 31); - blizzard.mFogSunriseColor = clr(91, 99, 106); - blizzard.mFogDayColor = clr(121, 133, 145); - blizzard.mFogSunsetColor = clr(108, 115, 121); - blizzard.mFogNightColor = clr(21, 24, 28); - blizzard.mAmbientSunriseColor = clr(84, 88, 92); - blizzard.mAmbientDayColor = clr(93, 96, 105); - blizzard.mAmbientSunsetColor = clr(83, 77, 75); - blizzard.mAmbientNightColor = clr(53, 62, 70); - blizzard.mSunSunriseColor = clr(114, 128, 146); - blizzard.mSunDayColor = clr(163, 169, 183); - blizzard.mSunSunsetColor = clr(106, 114, 136); - blizzard.mSunNightColor = clr(57, 66, 74); - blizzard.mSunDiscSunsetColor = clr(128, 128, 128); - blizzard.mLandFogDayDepth = 2.8; - blizzard.mLandFogNightDepth = 3.0; - blizzard.mWindSpeed = 0.9; - blizzard.mCloudSpeed = 7.5; - blizzard.mGlareView = 0; - blizzard.mAmbientLoopSoundID = "BM Blizzard"; - mWeatherSettings["blizzard"] = blizzard; -} - -void WeatherManager::setWeather(const String& weather, bool instant) -{ - if (instant || mFirstUpdate) - { - mNextWeather = ""; - mCurrentWeather = weather; - mFirstUpdate = false; - } - else - { - if (mNextWeather != "") - { - // transition more than 50% finished? - if (mRemainingTransitionTime/(mWeatherSettings[mCurrentWeather].mTransitionDelta*24.f*60) <= 0.5) - mCurrentWeather = mNextWeather; - } - - mNextWeather = weather; - mRemainingTransitionTime = mWeatherSettings[mCurrentWeather].mTransitionDelta*24.f*60; - } -} - -WeatherResult WeatherManager::getResult(const String& weather) -{ - const Weather& current = mWeatherSettings[weather]; - WeatherResult result; - - result.mCloudTexture = current.mCloudTexture; - result.mCloudBlendFactor = 0; - result.mCloudOpacity = current.mCloudsMaximumPercent; - result.mWindSpeed = current.mWindSpeed; - result.mCloudSpeed = current.mCloudSpeed; - result.mGlareView = current.mGlareView; - result.mAmbientLoopSoundID = current.mAmbientLoopSoundID; - result.mSunColor = current.mSunDiscSunsetColor; - - const float fade_duration = current.mTransitionDelta * 24.f; - - result.mNight = (mHour < 6.f+fade_duration || mHour > 20.f-fade_duration); - - result.mFogDepth = result.mNight ? current.mLandFogNightDepth : current.mLandFogDayDepth; - - // night - if (mHour <= (WeatherGlobals::mSunriseTime-WeatherGlobals::mSunriseDuration) - || mHour >= (WeatherGlobals::mSunsetTime+WeatherGlobals::mSunsetDuration)) - { - result.mFogColor = current.mFogNightColor; - result.mAmbientColor = current.mAmbientNightColor; - result.mSunColor = current.mSunNightColor; - result.mSkyColor = current.mSkyNightColor; - result.mNightFade = 1.f; - } - - // sunrise - else if (mHour >= (WeatherGlobals::mSunriseTime-WeatherGlobals::mSunriseDuration) && mHour <= WeatherGlobals::mSunriseTime) - { - if (mHour <= (WeatherGlobals::mSunriseTime-WeatherGlobals::mSunriseDuration+fade_duration)) - { - // fade in - float advance = (WeatherGlobals::mSunriseTime-WeatherGlobals::mSunriseDuration+fade_duration)-mHour; - float factor = (advance / fade_duration); - result.mFogColor = lerp(current.mFogSunriseColor, current.mFogNightColor); - result.mAmbientColor = lerp(current.mAmbientSunriseColor, current.mAmbientNightColor); - result.mSunColor = lerp(current.mSunSunriseColor, current.mSunNightColor); - result.mSkyColor = lerp(current.mSkySunriseColor, current.mSkyNightColor); - result.mNightFade = factor; - } - else if (mHour >= (WeatherGlobals::mSunriseTime-fade_duration)) - { - // fade out - float advance = mHour-(WeatherGlobals::mSunriseTime-fade_duration); - float factor = advance / fade_duration; - result.mFogColor = lerp(current.mFogSunriseColor, current.mFogDayColor); - result.mAmbientColor = lerp(current.mAmbientSunriseColor, current.mAmbientDayColor); - result.mSunColor = lerp(current.mSunSunriseColor, current.mSunDayColor); - result.mSkyColor = lerp(current.mSkySunriseColor, current.mSkyDayColor); - } - else - { - result.mFogColor = current.mFogSunriseColor; - result.mAmbientColor = current.mAmbientSunriseColor; - result.mSunColor = current.mSunSunriseColor; - result.mSkyColor = current.mSkySunriseColor; - } - } - - // day - else if (mHour >= (WeatherGlobals::mSunriseTime) && mHour <= (WeatherGlobals::mSunsetTime)) - { - result.mFogColor = current.mFogDayColor; - result.mAmbientColor = current.mAmbientDayColor; - result.mSunColor = current.mSunDayColor; - result.mSkyColor = current.mSkyDayColor; - } - - // sunset - else if (mHour >= (WeatherGlobals::mSunsetTime) && mHour <= (WeatherGlobals::mSunsetTime+WeatherGlobals::mSunsetDuration)) - { - if (mHour <= (WeatherGlobals::mSunsetTime+fade_duration)) - { - // fade in - float advance = (WeatherGlobals::mSunsetTime+fade_duration)-mHour; - float factor = (advance / fade_duration); - result.mFogColor = lerp(current.mFogSunsetColor, current.mFogDayColor); - result.mAmbientColor = lerp(current.mAmbientSunsetColor, current.mAmbientDayColor); - result.mSunColor = lerp(current.mSunSunsetColor, current.mSunDayColor); - result.mSkyColor = lerp(current.mSkySunsetColor, current.mSkyDayColor); - } - else if (mHour >= (WeatherGlobals::mSunsetTime+WeatherGlobals::mSunsetDuration-fade_duration)) - { - // fade out - float advance = mHour-(WeatherGlobals::mSunsetTime+WeatherGlobals::mSunsetDuration-fade_duration); - float factor = advance / fade_duration; - result.mFogColor = lerp(current.mFogSunsetColor, current.mFogNightColor); - result.mAmbientColor = lerp(current.mAmbientSunsetColor, current.mAmbientNightColor); - result.mSunColor = lerp(current.mSunSunsetColor, current.mSunNightColor); - result.mSkyColor = lerp(current.mSkySunsetColor, current.mSkyNightColor); - result.mNightFade = factor; - } - else - { - result.mFogColor = current.mFogSunsetColor; - result.mAmbientColor = current.mAmbientSunsetColor; - result.mSunColor = current.mSunSunsetColor; - result.mSkyColor = current.mSkySunsetColor; - } - } - - return result; -} - -WeatherResult WeatherManager::transition(float factor) -{ - const WeatherResult& current = getResult(mCurrentWeather); - const WeatherResult& other = getResult(mNextWeather); - WeatherResult result; - - result.mCloudTexture = current.mCloudTexture; - result.mNextCloudTexture = other.mCloudTexture; - result.mCloudBlendFactor = factor; - - result.mCloudOpacity = lerp(current.mCloudOpacity, other.mCloudOpacity); - result.mFogColor = lerp(current.mFogColor, other.mFogColor); - result.mSunColor = lerp(current.mSunColor, other.mSunColor); - result.mSkyColor = lerp(current.mSkyColor, other.mSkyColor); - - result.mAmbientColor = lerp(current.mAmbientColor, other.mAmbientColor); - result.mSunDiscColor = lerp(current.mSunDiscColor, other.mSunDiscColor); - result.mFogDepth = lerp(current.mFogDepth, other.mFogDepth); - result.mWindSpeed = lerp(current.mWindSpeed, other.mWindSpeed); - result.mCloudSpeed = lerp(current.mCloudSpeed, other.mCloudSpeed); - result.mCloudOpacity = lerp(current.mCloudOpacity, other.mCloudOpacity); - result.mGlareView = lerp(current.mGlareView, other.mGlareView); - - result.mNight = current.mNight; - - // sound change behaviour: - // if 'other' has a new sound, switch to it after 1/2 of the transition length - if (other.mAmbientLoopSoundID != "") - result.mAmbientLoopSoundID = factor>0.5 ? other.mAmbientLoopSoundID : current.mAmbientLoopSoundID; - // if 'current' has a sound and 'other' does not have a sound, turn off the sound immediately - else if (current.mAmbientLoopSoundID != "") - result.mAmbientLoopSoundID = ""; - - return result; -} - -void WeatherManager::update(float duration) -{ - mWeatherUpdateTime -= duration; - if (mEnvironment->mWorld->isCellExterior() || mEnvironment->mWorld->isCellQuasiExterior()) - { - std::string regionstr = mEnvironment->mWorld->getPlayer().getPlayer().getCell()->cell->region; - boost::algorithm::to_lower(regionstr); - - if (mWeatherUpdateTime <= 0 || regionstr != mCurrentRegion) - { - mCurrentRegion = regionstr; - mWeatherUpdateTime = WeatherGlobals::mWeatherUpdateTime*60.f; - - std::string weather; - - if (mRegionOverrides.find(regionstr) != mRegionOverrides.end()) - weather = mRegionOverrides[regionstr]; - else - { - // get weather probabilities for the current region - const ESM::Region *region = mEnvironment->mWorld->getStore().regions.find (regionstr); - - float clear = region->data.clear/255.f; - float cloudy = region->data.cloudy/255.f; - float foggy = region->data.foggy/255.f; - float overcast = region->data.overcast/255.f; - float rain = region->data.rain/255.f; - float thunder = region->data.thunder/255.f; - float ash = region->data.ash/255.f; - float blight = region->data.blight/255.f; - float snow = region->data.a/255.f; - float blizzard = region->data.b/255.f; - - // re-scale to 100 percent - const float total = clear+cloudy+foggy+overcast+rain+thunder+ash+blight+snow+blizzard; - - srand(time(NULL)); - float random = ((rand()%100)/100.f) * total; - - if (random >= snow+blight+ash+thunder+rain+overcast+foggy+cloudy+clear) - weather = "blizzard"; - else if (random >= blight+ash+thunder+rain+overcast+foggy+cloudy+clear) - weather = "snow"; - else if (random >= ash+thunder+rain+overcast+foggy+cloudy+clear) - weather = "blight"; - else if (random >= thunder+rain+overcast+foggy+cloudy+clear) - weather = "ashstorm"; - else if (random >= rain+overcast+foggy+cloudy+clear) - weather = "thunderstorm"; - else if (random >= overcast+foggy+cloudy+clear) - weather = "rain"; - else if (random >= foggy+cloudy+clear) - weather = "overcast"; - else if (random >= cloudy+clear) - weather = "foggy"; - else if (random >= clear) - weather = "cloudy"; - else - weather = "clear"; - } - - setWeather(weather, false); - /* - std::cout << "roll result: " << random << std::endl; - - std::cout << regionstr << " weather probabilities: " << clear << " " << cloudy << " " << foggy << " " - << overcast << " " << rain << " " << thunder << " " << ash << " " << blight << " " << snow << " " - << blizzard << std::endl; - - std::cout << "New weather : " << weather << std::endl; - */ - } - - WeatherResult result; - - if (mNextWeather != "") - { - mRemainingTransitionTime -= duration; - if (mRemainingTransitionTime < 0) - { - mCurrentWeather = mNextWeather; - mNextWeather = ""; - } - } - - if (mNextWeather != "") - result = transition(1-(mRemainingTransitionTime/(mWeatherSettings[mCurrentWeather].mTransitionDelta*24.f*60))); - else - result = getResult(mCurrentWeather); - - mRendering->configureFog(result.mFogDepth, result.mFogColor); - - // disable sun during night - if (mHour >= WeatherGlobals::mSunsetTime+WeatherGlobals::mSunsetDuration - || mHour <= WeatherGlobals::mSunriseTime-WeatherGlobals::mSunriseDuration) - mRendering->getSkyManager()->sunDisable(); - else - { - // during day, calculate sun angle - float height = 1-std::abs(((mHour-13)/7.f)); - int facing = mHour > 13.f ? 1 : -1; - Vector3 final( - (1-height)*facing, - (1-height)*facing, - height); - mRendering->setSunDirection(final); - - mRendering->getSkyManager()->sunEnable(); - } - - // moon calculations - float night; - if (mHour >= 14) - night = mHour-14; - else if (mHour <= 10) - night = mHour+10; - else - night = 0; - - night /= 20.f; - - if (night != 0) - { - float moonHeight = 1-std::abs((night-0.5)*2); - int facing = (mHour > 0.f && mHour<12.f) ? 1 : -1; - Vector3 masser( - (1-moonHeight)*facing, - (1-moonHeight)*facing, - moonHeight); - - Vector3 secunda( - (1-moonHeight)*facing*0.8, - (1-moonHeight)*facing*1.25, - moonHeight); - - mRendering->getSkyManager()->setMasserDirection(masser); - mRendering->getSkyManager()->setSecundaDirection(secunda); - mRendering->getSkyManager()->masserEnable(); - mRendering->getSkyManager()->secundaEnable(); - - float hour_fade; - if (mHour >= 7.f && mHour <= 14.f) - hour_fade = 1-(mHour-7)/3.f; - else if (mHour >= 14 && mHour <= 15.f) - hour_fade = mHour-14; - else - hour_fade = 1; - - float secunda_angle_fade; - float masser_angle_fade; - float angle = moonHeight*90.f; - - if (angle >= 30 && angle <= 50) - secunda_angle_fade = (angle-30)/20.f; - else if (angle <30) - secunda_angle_fade = 0.f; - else - secunda_angle_fade = 1.f; - - if (angle >= 40 && angle <= 50) - masser_angle_fade = (angle-40)/10.f; - else if (angle <40) - masser_angle_fade = 0.f; - else - masser_angle_fade = 1.f; - - masser_angle_fade *= hour_fade; - secunda_angle_fade *= hour_fade; - - mRendering->getSkyManager()->setMasserFade(masser_angle_fade); - mRendering->getSkyManager()->setSecundaFade(secunda_angle_fade); - } - else - { - mRendering->getSkyManager()->masserDisable(); - mRendering->getSkyManager()->secundaDisable(); - } - - if (mCurrentWeather == "thunderstorm" && mNextWeather == "") - { - if (mThunderFlash > 0) - { - // play the sound after a delay - mThunderSoundDelay -= duration; - if (mThunderSoundDelay <= 0) - { - // pick a random sound - int sound = rand() % 4; - std::string soundname; - if (sound == 0) soundname = WeatherGlobals::mThunderSoundID0; - else if (sound == 1) soundname = WeatherGlobals::mThunderSoundID1; - else if (sound == 2) soundname = WeatherGlobals::mThunderSoundID2; - else if (sound == 3) soundname = WeatherGlobals::mThunderSoundID3; - mEnvironment->mSoundManager->playSound(soundname, 1.0, 1.0); - mThunderSoundDelay = 1000; - } - - mThunderFlash -= duration; - if (mThunderFlash > 0) - mRendering->getSkyManager()->setThunder( mThunderFlash / WeatherGlobals::mThunderThreshold ); - else - { - srand(time(NULL)); - mThunderChanceNeeded = rand() % 100; - mThunderChance = 0; - mRendering->getSkyManager()->setThunder( 0.f ); - } - } - else - { - // no thunder active - mThunderChance += duration*4; // chance increases by 4 percent every second - if (mThunderChance >= mThunderChanceNeeded) - { - mThunderFlash = WeatherGlobals::mThunderThreshold; - - mRendering->getSkyManager()->setThunder( mThunderFlash / WeatherGlobals::mThunderThreshold ); - - mThunderSoundDelay = WeatherGlobals::mThunderSoundDelay; - } - } - } - else - mRendering->getSkyManager()->setThunder(0.f); - - mRendering->setAmbientColour(result.mAmbientColor); - mRendering->sunEnable(); - mRendering->setSunColour(result.mSunColor); - - mRendering->getSkyManager()->setWeather(result); - } - else - { - mRendering->sunDisable(); - mRendering->skyDisable(); - mRendering->getSkyManager()->setThunder(0.f); - } -} - -void WeatherManager::setHour(const float hour) -{ - // accelerate a bit for testing - /* - mHour += 0.005; - - if (mHour >= 24.f) mHour = 0.f; - - std::cout << "hour " << mHour << std::endl; - */ - - mHour = hour; -} - -void WeatherManager::setDate(const int day, const int month) -{ - mDay = day; - mMonth = month; -} - -unsigned int WeatherManager::getWeatherID() const -{ - // Source: http://www.uesp.net/wiki/Tes3Mod:GetCurrentWeather - - if (mCurrentWeather == "clear") - return 0; - else if (mCurrentWeather == "cloudy") - return 1; - else if (mCurrentWeather == "foggy") - return 2; - else if (mCurrentWeather == "overcast") - return 3; - else if (mCurrentWeather == "rain") - return 4; - else if (mCurrentWeather == "thunderstorm") - return 5; - else if (mCurrentWeather == "ashstorm") - return 6; - else if (mCurrentWeather == "blight") - return 7; - else if (mCurrentWeather == "snow") - return 8; - else if (mCurrentWeather == "blizzard") - return 9; - - else - return 0; -} - -void WeatherManager::changeWeather(const std::string& region, const unsigned int id) -{ - std::string weather; - if (id==0) - weather = "clear"; - else if (id==1) - weather = "cloudy"; - else if (id==2) - weather = "foggy"; - else if (id==3) - weather = "overcast"; - else if (id==4) - weather = "rain"; - else if (id==5) - weather = "thunderstorm"; - else if (id==6) - weather = "ashstorm"; - else if (id==7) - weather = "blight"; - else if (id==8) - weather = "snow"; - else if (id==9) - weather = "blizzard"; - else - weather = "clear"; - - mRegionOverrides[region] = weather; -} diff --git a/libs/openengine/bullet/weather.hpp b/libs/openengine/bullet/weather.hpp deleted file mode 100644 index 9353f7cd1d..0000000000 --- a/libs/openengine/bullet/weather.hpp +++ /dev/null @@ -1,272 +0,0 @@ -#ifndef GAME_MWWORLD_WEATHER_H -#define GAME_MWWORLD_WEATHER_H - -#include -#include - -namespace MWRender -{ - class RenderingManager; -} - -namespace MWWorld -{ - class Environment; - - /// Global weather manager properties (according to INI) - struct WeatherGlobals - { - /* - [Weather] - EnvReduceColor=255,255,255,255 - LerpCloseColor=037,046,048,255 - BumpFadeColor=230,239,255,255 - AlphaReduce=0.35 - Minimum Time Between Environmental Sounds=1.0 - Maximum Time Between Environmental Sounds=5.0 - Sun Glare Fader Max=0.5 - Sun Glare Fader Angle Max=30.0 - Sun Glare Fader Color=222,095,039 - Timescale Clouds=0 - Precip Gravity=575 - Hours Between Weather Changes=20 - Rain Ripples=1 - Rain Ripple Radius=1024 - Rain Ripples Per Drop=1 - Rain Ripple Scale=0.3 - Rain Ripple Speed=1.0 - Fog Depth Change Speed=3 - Sunrise Time=6 - Sunset Time=18 - Sunrise Duration=2 - Sunset Duration=2 - Sky Pre-Sunrise Time=.5 - Sky Post-Sunrise Time=1 - Sky Pre-Sunset Time=1.5 - Sky Post-Sunset Time=.5 - Ambient Pre-Sunrise Time=.5 - Ambient Post-Sunrise Time=2 - Ambient Pre-Sunset Time=1 - Ambient Post-Sunset Time=1.25 - Fog Pre-Sunrise Time=.5 - Fog Post-Sunrise Time=1 - Fog Pre-Sunset Time=2 - Fog Post-Sunset Time=1 - Sun Pre-Sunrise Time=0 - Sun Post-Sunrise Time=0 - Sun Pre-Sunset Time=1 - Sun Post-Sunset Time=1.25 - Stars Post-Sunset Start=1 - Stars Pre-Sunrise Finish=2 - Stars Fading Duration=2 - Snow Ripples=0 - Snow Ripple Radius=1024 - Snow Ripples Per Flake=1 - Snow Ripple Scale=0.3 - Snow Ripple Speed=1.0 - Snow Gravity Scale=0.1 - Snow High Kill=700 - Snow Low Kill=150 - - - [Moons] - Masser Size=94 - Masser Fade In Start=14 - Masser Fade In Finish=15 - Masser Fade Out Start=7 - Masser Fade Out Finish=10 - Masser Axis Offset=35 - Masser Speed=.5 - Masser Daily Increment=1 - Masser Fade Start Angle=50 - Masser Fade End Angle=40 - Masser Moon Shadow Early Fade Angle=0.5 - Secunda Size=40 - Secunda Fade In Start=14 - Secunda Fade In Finish=15 - Secunda Fade Out Start=7 - Secunda Fade Out Finish=10 - Secunda Axis Offset=50 - Secunda Speed=.6 - Secunda Daily Increment=1.2 - Secunda Fade Start Angle=50 - Secunda Fade End Angle=30 - Secunda Moon Shadow Early Fade Angle=0.5 - Script Color=255,20,20 - */ - - static const float mSunriseTime; - static const float mSunsetTime; - static const float mSunriseDuration; - static const float mSunsetDuration; - - static const float mWeatherUpdateTime; - - // morrowind sets these per-weather, but since they are only used by 'thunderstorm' - // weather setting anyway, we can just as well set them globally - static const float mThunderFrequency; - static const float mThunderThreshold; - static const float mThunderSoundDelay; - static const std::string mThunderSoundID0; - static const std::string mThunderSoundID1; - static const std::string mThunderSoundID2; - static const std::string mThunderSoundID3; - }; - - /// Defines the actual weather that results from weather setting (see below), time of day and weather transition - struct WeatherResult - { - Ogre::String mCloudTexture; - Ogre::String mNextCloudTexture; - float mCloudBlendFactor; - - Ogre::ColourValue mFogColor; - - Ogre::ColourValue mAmbientColor; - - Ogre::ColourValue mSkyColor; - - Ogre::ColourValue mSunColor; - - Ogre::ColourValue mSunDiscColor; - - float mFogDepth; - - float mWindSpeed; - - float mCloudSpeed; - - float mCloudOpacity; - - float mGlareView; - - bool mNight; // use night skybox - float mNightFade; // fading factor for night skybox - - Ogre::String mAmbientLoopSoundID; - }; - - - /// Defines a single weather setting (according to INI) - struct Weather - { - Ogre::String mCloudTexture; - - // Sky (atmosphere) colors - Ogre::ColourValue mSkySunriseColor, - mSkyDayColor, - mSkySunsetColor, - mSkyNightColor; - - // Fog colors - Ogre::ColourValue mFogSunriseColor, - mFogDayColor, - mFogSunsetColor, - mFogNightColor; - - // Ambient lighting colors - Ogre::ColourValue mAmbientSunriseColor, - mAmbientDayColor, - mAmbientSunsetColor, - mAmbientNightColor; - - // Sun (directional) lighting colors - Ogre::ColourValue mSunSunriseColor, - mSunDayColor, - mSunSunsetColor, - mSunNightColor; - - // Fog depth/density - float mLandFogDayDepth, - mLandFogNightDepth; - - // Color modulation for the sun itself during sunset (not completely sure) - Ogre::ColourValue mSunDiscSunsetColor; - - // Duration of weather transition (in days) - float mTransitionDelta; - - // No idea what this one is used for? - float mWindSpeed; - - // Cloud animation speed multiplier - float mCloudSpeed; - - // Multiplier for clouds transparency - float mCloudsMaximumPercent; - - // Value between 0 and 1, defines the strength of the sun glare effect - float mGlareView; - - // Sound effect - // This is used for Blight, Ashstorm and Blizzard (Bloodmoon) - Ogre::String mAmbientLoopSoundID; - - // Rain sound effect - Ogre::String mRainLoopSoundID; - - /// \todo disease chance - }; - - /// - /// Interface for weather settings - /// - class WeatherManager - { - public: - WeatherManager(MWRender::RenderingManager*, MWWorld::Environment*); - - /** - * Change the weather in the specified region - * @param region that should be changed - * @param ID of the weather setting to shift to - */ - void changeWeather(const std::string& region, const unsigned int id); - - /** - * Per-frame update - * @param duration - */ - void update(float duration); - - void setHour(const float hour); - - void setDate(const int day, const int month); - - unsigned int getWeatherID() const; - - private: - float mHour; - int mDay, mMonth; - - MWRender::RenderingManager* mRendering; - MWWorld::Environment* mEnvironment; - - std::map mWeatherSettings; - - std::map mRegionOverrides; - - Ogre::String mCurrentWeather; - Ogre::String mNextWeather; - - std::string mCurrentRegion; - - bool mFirstUpdate; - - float mWeatherUpdateTime; - - float mRemainingTransitionTime; - - float mThunderFlash; - float mThunderChance; - float mThunderChanceNeeded; - float mThunderSoundDelay; - - WeatherResult transition(const float factor); - WeatherResult getResult(const Ogre::String& weather); - - void setWeather(const Ogre::String& weather, bool instant=false); - }; -} - -#endif // GAME_MWWORLD_WEATHER_H From 318355f1be3fa5f14abe34d39a3b76b063b5b9a3 Mon Sep 17 00:00:00 2001 From: Jason Hooks Date: Mon, 26 Mar 2012 21:35:20 -0400 Subject: [PATCH 003/325] Bouncy effect gone --- libs/openengine/bullet/pmove.cpp | 48 ++++++++++++++++++++++---------- libs/openengine/bullet/trace.cpp | 4 +-- 2 files changed, 35 insertions(+), 17 deletions(-) diff --git a/libs/openengine/bullet/pmove.cpp b/libs/openengine/bullet/pmove.cpp index 8dd01ef190..d8880a49f1 100644 --- a/libs/openengine/bullet/pmove.cpp +++ b/libs/openengine/bullet/pmove.cpp @@ -178,7 +178,7 @@ bool PM_SlideMove( bool gravity ) float into; Ogre::Vector3 endVelocity; Ogre::Vector3 endClipVelocity; - std::cout << "Slide move\n"; + std::cout << "Slide move" << pm->ps.velocity << "\n"; numbumps = 4; // primal_velocity = pm->ps->velocity @@ -415,6 +415,7 @@ int PM_StepSlideMove( bool gravity ) // vec3_t delta, delta2; Ogre::Vector3 up, down; float stepSize; + std::cout << "Step Slide move" << pm->ps.velocity << "\n"; // start_o = pm->ps->origin //VectorCopy (pm->ps->origin, start_o); @@ -427,7 +428,7 @@ int PM_StepSlideMove( bool gravity ) if ( PM_SlideMove( gravity ) == false ) return 1; // we got exactly where we wanted to go first try - std::cout << "Step Slide move\n"; + // down = start_o - vec3(0, 0, STEPSIZE) //VectorCopy(start_o, down); down = start_o; @@ -711,7 +712,7 @@ static void PM_WaterMove( playerMove* const pm ) Ogre::Vector3 wishdir; float scale; float vel; - + std::cout << "Water moving"; /*if ( PM_CheckWaterJump() ) { PM_WaterJumpMove(); @@ -837,7 +838,7 @@ static void PM_WalkMove( playerMove* const pmove ) playerMove::playercmd cmd; float accelerate; float vel; - std::cout << "Walking\n"; + std::cout << "Walking" << pm->ps.velocity << "\n"; if ( pm->ps.waterlevel > 2 && //DotProduct( pml.forward, pml.groundTrace.plane.normal ) > 0 ) pml.forward.dotProduct(pml.groundTrace.planenormal) > 0.0f) @@ -927,6 +928,7 @@ static void PM_WalkMove( playerMove* const pmove ) PM_Friction (); + std::cout << "After friction" << pm->ps.velocity << "\n"; //bprintf("vel: (%f, %f, %f)\n", pm->ps.velocity.x, pm->ps.velocity.y, pm->ps.velocity.z); @@ -945,20 +947,28 @@ static void PM_WalkMove( playerMove* const pmove ) //pml.right[2] = 0; pml.right.z = 0; + //std::cout << "Further down" << pm->ps.velocity << "\n"; + // project the forward and right directions onto the ground plane PM_ClipVelocity (pml.forward, pml.groundTrace.planenormal, pml.forward, OVERCLIP ); PM_ClipVelocity (pml.right, pml.groundTrace.planenormal, pml.right, OVERCLIP ); + std::cout << "Clip velocity" << pm->ps.velocity << "\n"; // - //VectorNormalize (pml.forward); - pml.forward = pml.forward.normalise(); - pml.right = pml.right.normalise(); + + VectorNormalize (pml.forward); + VectorNormalize (pml.right); + //pml.forward = pml.forward.normalise(); + //pml.right = pml.right.normalise(); + std::cout << "forward2" << pml.forward << "\n"; + std::cout << "right2" << pml.right << "\n"; // wishvel = (pml.forward * fmove) + (pml.right * smove); //for ( i = 0 ; i < 3 ; i++ ) //wishvel[i] = pml.forward[i] * fmove + pml.right[i] * smove; wishvel = pml.forward * fmove + pml.right * smove; + std::cout << "WishVel" << wishvel << "\n"; //bprintf("f: (%f, %f, %f), s: (%f, %f, %f)\n", fmove, smove); @@ -971,7 +981,9 @@ static void PM_WalkMove( playerMove* const pmove ) wishdir = wishvel; wishspeed = VectorNormalize(wishdir); + std::cout << "Wishspeed: " << wishspeed << "\n"; wishspeed *= scale; + std::cout << "Wishspeed scaled:" << wishspeed << "\n"; // clamp the speed lower if ducking if ( pm->cmd.ducking ) @@ -998,6 +1010,7 @@ static void PM_WalkMove( playerMove* const pmove ) PM_Accelerate (wishdir, wishspeed, accelerate); + std::cout << "Velocityafter: " << pm->ps.velocity << "\n"; //Com_Printf("velocity = %1.1f %1.1f %1.1f\n", pm->ps->velocity[0], pm->ps->velocity[1], pm->ps->velocity[2]); //Com_Printf("velocity1 = %1.1f\n", VectorLength(pm->ps->velocity)); @@ -1012,15 +1025,18 @@ static void PM_WalkMove( playerMove* const pmove ) //vel = VectorLength(pm->ps->velocity); vel = pm->ps.velocity.length(); + std::cout << "The length" << vel << "\n"; // slide along the ground plane PM_ClipVelocity (pm->ps.velocity, pml.groundTrace.planenormal, pm->ps.velocity, OVERCLIP ); + std::cout << "Velocity clipped" << pm->ps.velocity << "\n"; // don't decrease velocity when going up or down a slope - //VectorNormalize(pm->ps->velocity); - pm->ps.velocity = pm->ps.velocity.normalise(); + VectorNormalize(pm->ps.velocity); + //pm->ps.velocity = pm->ps.velocity.normalise(); + std::cout << "Final:" << pm->ps.velocity << "\n"; //VectorScale(pm->ps->velocity, vel, pm->ps->velocity); pm->ps.velocity = pm->ps.velocity * vel; @@ -1032,6 +1048,7 @@ static void PM_WalkMove( playerMove* const pmove ) PM_StepSlideMove( false ); //Com_Printf("velocity2 = %1.1f\n", VectorLength(pm->ps->velocity)); + std::cout << "Walk2" << pm->ps.velocity << "\n"; } @@ -1361,7 +1378,7 @@ static void PM_CrashLand( void ) static void PM_GroundTrace( void ) { - std::cout << "Ground trace\n"; + std::cout << "Ground trace" << pm->ps.velocity << "\n"; Ogre::Vector3 point; traceResults trace; @@ -1467,13 +1484,13 @@ static void PM_GroundTrace( void ) // don't reset the z velocity for slopes // pm->ps->velocity[2] = 0; - + std::cout << "Ground trace2" << pm->ps.velocity << "\n"; //PM_AddTouchEnt( trace.entityNum ); } static void PM_AirMove() { - std::cout << "Air move\n"; + std::cout << "Air move " << pm->ps.velocity << "\n"; //int i; Ogre::Vector3 wishvel; float fmove, smove; @@ -1495,9 +1512,9 @@ static void PM_AirMove() // project moves down to flat plane //pml.forward[2] = 0; - pml.forward.y = 0; //Z or Y? + pml.forward.z = 0; //Z or Y? //pml.right[2] = 0; - pml.right.y = 0; + pml.right.z = 0; //VectorNormalize (pml.forward); pml.forward = Ogre::Vector3(pml.forward.normalise()); pml.right = Ogre::Vector3(pml.right.normalise()); @@ -1535,8 +1552,9 @@ static void PM_AirMove() else PM_SlideMove ( qtrue ); #endif*/ - + /*bprintf("%i ", */PM_StepSlideMove ( true )/* )*/; + std::cout << "Velocity 2 " << pm->ps.velocity << "\n"; } static void PM_NoclipMove( void ) diff --git a/libs/openengine/bullet/trace.cpp b/libs/openengine/bullet/trace.cpp index 8f2423c242..18a668e55b 100644 --- a/libs/openengine/bullet/trace.cpp +++ b/libs/openengine/bullet/trace.cpp @@ -32,7 +32,7 @@ void newtrace(traceResults* const results, const Ogre::Vector3& start, const Ogr //Ogre::Vector3 endReplace = startReplace; //endReplace.z -= .25; - const bool hasHit = NewPhysicsTrace(&out, start, end, BBHalfExtents, Ogre::Vector3(0.0f, 0.0f, rotation), isInterior, enginePass); + const bool hasHit = NewPhysicsTrace(&out, start, end, BBHalfExtents, Ogre::Vector3(0.0f, rotation, 0.0f), isInterior, enginePass); if(hasHit) std::cout << "Has hit\n"; if (out.fraction < 0.001f) @@ -100,7 +100,7 @@ const bool NewPhysicsTrace(NewPhysTraceResults* const out, const Ogre::Vector3& const btVector3 btstart(start.x, start.y, start.z); const btVector3 btend(end.x, end.y, end.z); - const btQuaternion btrot(rotation.y, rotation.x, rotation.z); + const btQuaternion btrot(rotation.y, rotation.x, rotation.z); //y, x, z const btBoxShape newshape(btVector3(BBHalfExtents.x, BBHalfExtents.y, BBHalfExtents.z)); const btTransform from(btrot, btstart); From b9fabce9c4654f99c3b3bc8e296e64e35b13639d Mon Sep 17 00:00:00 2001 From: Jason Hooks Date: Tue, 27 Mar 2012 20:17:54 -0400 Subject: [PATCH 004/325] Awesome, working --- apps/openmw/mwclass/npc.cpp | 4 +- apps/openmw/mwworld/physicssystem.cpp | 7 ++- libs/openengine/bullet/pmove.cpp | 67 +++++++++++++-------------- libs/openengine/bullet/pmove.h | 2 +- libs/openengine/bullet/trace.cpp | 8 ++-- 5 files changed, 44 insertions(+), 44 deletions(-) diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 522fce3a3c..8bb394129f 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -273,8 +273,8 @@ namespace MWClass vector.y = getMovementSettings (ptr).mForwardBackward * 127; vector.z = getMovementSettings(ptr).mUpDown * 127; - if (getStance (ptr, Run, false)) - vector *= 2; + //if (getStance (ptr, Run, false)) + // vector *= 2; return vector; } diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 15d2d3f9f6..fdcee417f4 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -116,7 +116,6 @@ namespace MWWorld pm_ref.upmove = dir1.y; - //std::cout << "Current angle" << yawQuat.getYaw().valueDegrees() - 90<< "\n"; //playerphysics->ps.viewangles.x = pitchQuat.getPitch().valueDegrees(); //std::cout << "Pitch: " << yawQuat.getPitch() << "Yaw:" << yawQuat.getYaw() << "Roll: " << yawQuat.getRoll() << "\n"; @@ -124,11 +123,15 @@ namespace MWWorld } else { + Ogre::Quaternion quat = yawNode->getOrientation(); Ogre::Vector3 dir1(iter->second.x,iter->second.z,-iter->second.y); + pm_ref.rightmove = -dir1.x; pm_ref.forwardmove = dir1.z; - pm_ref.upmove = dir.y; + pm_ref.upmove = dir1.y; + + dir = 0.025*(quat*dir1); } diff --git a/libs/openengine/bullet/pmove.cpp b/libs/openengine/bullet/pmove.cpp index d8880a49f1..8fb72aa1f0 100644 --- a/libs/openengine/bullet/pmove.cpp +++ b/libs/openengine/bullet/pmove.cpp @@ -93,6 +93,7 @@ static inline void PM_ClipVelocity(const Ogre::Vector3& in, const Ogre::Vector3& { change = normal[i]*backoff; out[i] = in[i] - change; + }*/ float changex = normal.x * backoff; out.x = in.x - changex; @@ -178,7 +179,7 @@ bool PM_SlideMove( bool gravity ) float into; Ogre::Vector3 endVelocity; Ogre::Vector3 endClipVelocity; - std::cout << "Slide move" << pm->ps.velocity << "\n"; + numbumps = 4; // primal_velocity = pm->ps->velocity @@ -415,7 +416,7 @@ int PM_StepSlideMove( bool gravity ) // vec3_t delta, delta2; Ogre::Vector3 up, down; float stepSize; - std::cout << "Step Slide move" << pm->ps.velocity << "\n"; + // start_o = pm->ps->origin //VectorCopy (pm->ps->origin, start_o); @@ -543,7 +544,7 @@ int PM_StepSlideMove( bool gravity ) void PM_Friction(void) { - std::cout << "Friction\n"; + Ogre::Vector3 vec; float* vel; float speed, newspeed, control; @@ -639,7 +640,6 @@ static void PM_Accelerate( Ogre::Vector3& wishdir, float wishspeed, float accel { // int i; float addspeed, accelspeed, currentspeed; - std::cout << "Accelerate\n"; // currentspeed = pm->ps->velocity dot wishdir //currentspeed = DotProduct (pm->ps->velocity, wishdir); @@ -712,7 +712,7 @@ static void PM_WaterMove( playerMove* const pm ) Ogre::Vector3 wishdir; float scale; float vel; - std::cout << "Water moving"; + /*if ( PM_CheckWaterJump() ) { PM_WaterJumpMove(); @@ -838,7 +838,7 @@ static void PM_WalkMove( playerMove* const pmove ) playerMove::playercmd cmd; float accelerate; float vel; - std::cout << "Walking" << pm->ps.velocity << "\n"; + if ( pm->ps.waterlevel > 2 && //DotProduct( pml.forward, pml.groundTrace.plane.normal ) > 0 ) pml.forward.dotProduct(pml.groundTrace.planenormal) > 0.0f) @@ -851,6 +851,7 @@ static void PM_WalkMove( playerMove* const pmove ) if ( PM_CheckJump () ) { + // jumped away if ( pm->ps.waterlevel > 1 ) PM_WaterMove(pmove); @@ -928,12 +929,13 @@ static void PM_WalkMove( playerMove* const pmove ) PM_Friction (); - std::cout << "After friction" << pm->ps.velocity << "\n"; + //bprintf("vel: (%f, %f, %f)\n", pm->ps.velocity.x, pm->ps.velocity.y, pm->ps.velocity.z); fmove = pm->cmd.forwardmove; smove = pm->cmd.rightmove; + cmd = pm->cmd; scale = PM_CmdScale( &cmd ); @@ -953,22 +955,23 @@ static void PM_WalkMove( playerMove* const pmove ) // project the forward and right directions onto the ground plane PM_ClipVelocity (pml.forward, pml.groundTrace.planenormal, pml.forward, OVERCLIP ); PM_ClipVelocity (pml.right, pml.groundTrace.planenormal, pml.right, OVERCLIP ); - std::cout << "Clip velocity" << pm->ps.velocity << "\n"; + //std::cout << "Clip velocity" << pm->ps.velocity << "\n"; // VectorNormalize (pml.forward); VectorNormalize (pml.right); //pml.forward = pml.forward.normalise(); //pml.right = pml.right.normalise(); - std::cout << "forward2" << pml.forward << "\n"; - std::cout << "right2" << pml.right << "\n"; + //std::cout << "forward2" << pml.forward << "\n"; + //std::cout << "right2" << pml.right << "\n"; // wishvel = (pml.forward * fmove) + (pml.right * smove); //for ( i = 0 ; i < 3 ; i++ ) //wishvel[i] = pml.forward[i] * fmove + pml.right[i] * smove; wishvel = pml.forward * fmove + pml.right * smove; - std::cout << "WishVel" << wishvel << "\n"; + + //bprintf("f: (%f, %f, %f), s: (%f, %f, %f)\n", fmove, smove); @@ -981,9 +984,9 @@ static void PM_WalkMove( playerMove* const pmove ) wishdir = wishvel; wishspeed = VectorNormalize(wishdir); - std::cout << "Wishspeed: " << wishspeed << "\n"; + //std::cout << "Wishspeed: " << wishspeed << "\n"; wishspeed *= scale; - std::cout << "Wishspeed scaled:" << wishspeed << "\n"; + //std::cout << "Wishspeed scaled:" << wishspeed << "\n"; // clamp the speed lower if ducking if ( pm->cmd.ducking ) @@ -1010,7 +1013,7 @@ static void PM_WalkMove( playerMove* const pmove ) PM_Accelerate (wishdir, wishspeed, accelerate); - std::cout << "Velocityafter: " << pm->ps.velocity << "\n"; + //std::cout << "Velocityafter: " << pm->ps.velocity << "\n"; //Com_Printf("velocity = %1.1f %1.1f %1.1f\n", pm->ps->velocity[0], pm->ps->velocity[1], pm->ps->velocity[2]); //Com_Printf("velocity1 = %1.1f\n", VectorLength(pm->ps->velocity)); @@ -1025,18 +1028,18 @@ static void PM_WalkMove( playerMove* const pmove ) //vel = VectorLength(pm->ps->velocity); vel = pm->ps.velocity.length(); - std::cout << "The length" << vel << "\n"; + //std::cout << "The length" << vel << "\n"; // slide along the ground plane PM_ClipVelocity (pm->ps.velocity, pml.groundTrace.planenormal, pm->ps.velocity, OVERCLIP ); - std::cout << "Velocity clipped" << pm->ps.velocity << "\n"; + //std::cout << "Velocity clipped" << pm->ps.velocity << "\n"; // don't decrease velocity when going up or down a slope VectorNormalize(pm->ps.velocity); //pm->ps.velocity = pm->ps.velocity.normalise(); - std::cout << "Final:" << pm->ps.velocity << "\n"; + //std::cout << "Final:" << pm->ps.velocity << "\n"; //VectorScale(pm->ps->velocity, vel, pm->ps->velocity); pm->ps.velocity = pm->ps.velocity * vel; @@ -1048,7 +1051,7 @@ static void PM_WalkMove( playerMove* const pmove ) PM_StepSlideMove( false ); //Com_Printf("velocity2 = %1.1f\n", VectorLength(pm->ps->velocity)); - std::cout << "Walk2" << pm->ps.velocity << "\n"; + } @@ -1056,7 +1059,7 @@ void PM_UpdateViewAngles( playerMove::playerStruct* const ps, playerMove::player { short temp; int i; - std::cout << "Updating viewangles\n"; + //while(1); //if ( ps->pm_type == PM_INTERMISSION || ps->pm_type == PM_SPINTERMISSION) @@ -1178,7 +1181,6 @@ static bool PM_CorrectAllSolid(traceResults* const trace) { int i, j, k; Ogre::Vector3 point; - std::cout << "Correct all solid\n"; //if ( pm->debugLevel ) //Com_Printf("%i:allsolid\n", c_pmove); @@ -1236,7 +1238,7 @@ static void PM_CrashLand( void ) float vel, acc; float t; float a, b, c, den; - std::cout << "Crash land\n"; + // decide which landing animation to use /*if ( pm->ps->pm_flags & PMF_BACKWARDS_JUMP ) PM_ForceLegsAnim( LEGS_LANDB ); @@ -1378,7 +1380,6 @@ static void PM_CrashLand( void ) static void PM_GroundTrace( void ) { - std::cout << "Ground trace" << pm->ps.velocity << "\n"; Ogre::Vector3 point; traceResults trace; @@ -1484,13 +1485,12 @@ static void PM_GroundTrace( void ) // don't reset the z velocity for slopes // pm->ps->velocity[2] = 0; - std::cout << "Ground trace2" << pm->ps.velocity << "\n"; + //PM_AddTouchEnt( trace.entityNum ); } static void PM_AirMove() { - std::cout << "Air move " << pm->ps.velocity << "\n"; //int i; Ogre::Vector3 wishvel; float fmove, smove; @@ -1516,8 +1516,8 @@ static void PM_AirMove() //pml.right[2] = 0; pml.right.z = 0; //VectorNormalize (pml.forward); - pml.forward = Ogre::Vector3(pml.forward.normalise()); - pml.right = Ogre::Vector3(pml.right.normalise()); + VectorNormalize(pml.forward); + VectorNormalize(pml.right); //VectorNormalize (pml.right); //for ( i = 0 ; i < 2 ; i++ ) @@ -1554,7 +1554,6 @@ static void PM_AirMove() #endif*/ /*bprintf("%i ", */PM_StepSlideMove ( true )/* )*/; - std::cout << "Velocity 2 " << pm->ps.velocity << "\n"; } static void PM_NoclipMove( void ) @@ -1602,9 +1601,7 @@ static void PM_NoclipMove( void ) //for (i=0 ; i<3 ; i++) //wishvel[i] = pml.forward[i] * fmove + pml.right[i] * smove; - std::cout << "Forward" << pml.forward << "\n"; - std::cout << "Right" << pml.right << "\n"; - std::cout << "Up" << pml.up << "\n"; + wishvel = pml.forward * fmove + pml.right * smove; //wishvel[2] += pm->cmd.upmove; wishvel.z += pm->cmd.upmove; @@ -1614,6 +1611,7 @@ static void PM_NoclipMove( void ) wishspeed = VectorNormalize(wishdir); wishspeed *= scale; + PM_Accelerate( wishdir, wishspeed, pm_accelerate ); // move @@ -1747,6 +1745,7 @@ void PM_SetWaterLevel( playerMove* const pm ) void PmoveSingle (playerMove* const pmove) { + //pm = pmove; // Aedra doesn't support Q3-style VM traps D: //while(1); @@ -1898,7 +1897,7 @@ void PmoveSingle (playerMove* const pmove) if ( pm->ps.move_type == PM_SPECTATOR ) { - std::cout << "SPECTATOR\n"; + //PM_CheckDuck (); PM_FlyMove (); PM_DropTimers (); @@ -1907,20 +1906,19 @@ void PmoveSingle (playerMove* const pmove) if ( pm->ps.move_type == PM_NOCLIP ) { - std::cout << "NOCLIP\n"; + PM_NoclipMove (); PM_DropTimers (); return; } if (pm->ps.move_type == PM_FREEZE){ - std::cout << "FREEZE\n"; + return; // no movement at all } if ( pm->ps.move_type == PM_INTERMISSION || pm->ps.move_type == PM_SPINTERMISSION){ - std::cout << "INTERMISSION\n"; return; // no movement at all } @@ -2006,6 +2004,7 @@ void Ext_UpdateViewAngles(playerMove* const pm) void Pmove (playerMove* const pmove) { + int fmove = pmove->cmd.forwardmove; pm = pmove; int finalTime; diff --git a/libs/openengine/bullet/pmove.h b/libs/openengine/bullet/pmove.h index 5dfd18f6dc..30572a92a2 100644 --- a/libs/openengine/bullet/pmove.h +++ b/libs/openengine/bullet/pmove.h @@ -90,7 +90,7 @@ struct playerMove { struct playerStruct { - playerStruct() : gravity(50.0f), speed(320.0f), pmove_framecount(20), groundEntityNum(ENTITYNUM_NONE), commandTime(40), move_type(PM_NOCLIP), pm_time(0) + playerStruct() : gravity(800.0f), speed(320.0f), pmove_framecount(20), groundEntityNum(ENTITYNUM_NONE), commandTime(40), move_type(PM_NOCLIP), pm_time(0) { origin = Ogre::Vector3(733.164f,900.0f, 839.432f); velocity = Ogre::Vector3(0.0f, 0.0f, 0.0f); diff --git a/libs/openengine/bullet/trace.cpp b/libs/openengine/bullet/trace.cpp index 18a668e55b..ca68a5d5c0 100644 --- a/libs/openengine/bullet/trace.cpp +++ b/libs/openengine/bullet/trace.cpp @@ -32,9 +32,8 @@ void newtrace(traceResults* const results, const Ogre::Vector3& start, const Ogr //Ogre::Vector3 endReplace = startReplace; //endReplace.z -= .25; - const bool hasHit = NewPhysicsTrace(&out, start, end, BBHalfExtents, Ogre::Vector3(0.0f, rotation, 0.0f), isInterior, enginePass); - if(hasHit) - std::cout << "Has hit\n"; + const bool hasHit = NewPhysicsTrace(&out, start, end, BBHalfExtents, Ogre::Vector3(0.0f, 0.0, rotation), isInterior, enginePass); + if (out.fraction < 0.001f) results->startsolid = true; else @@ -180,8 +179,7 @@ const bool NewPhysicsTrace(NewPhysTraceResults* const out, const Ogre::Vector3& const bool hasHit = newTraceCallback.hasHit(); - if(hasHit) - std::cout << "HIT\n"; + return hasHit; From c5f044eb0df83cb1b550bf3e3559d2f7621b7637 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 28 Mar 2012 22:46:29 +0200 Subject: [PATCH 005/325] fixed compilation --- apps/openmw/mwworld/scene.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 79e7d565d2..205d66cd7d 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -112,9 +112,12 @@ namespace MWWorld float worldsize = ESM::Land::REAL_SIZE; if (!(cell->cell->data.flags & ESM::Cell::Interior)) - mPhysics->addHeightField (cell->land[1][1]->landData->heights, + { + ESM::Land* land = mWorld->getStore().lands.search(cell->cell->data.gridX,cell->cell->data.gridY); + mPhysics->addHeightField (land->landData->heights, cell->cell->data.gridX, cell->cell->data.gridY, 0, ( worldsize/(verts-1) ), verts); + } mRendering.configureAmbient(*cell); mRendering.requestMap(cell); From bc636f036ce6c10470625e33bc3e2e762989ab96 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 8 Apr 2012 18:25:50 +0200 Subject: [PATCH 006/325] made it compile --- libs/openengine/bullet/pmove.cpp | 2 +- libs/openengine/bullet/trace.h | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/libs/openengine/bullet/pmove.cpp b/libs/openengine/bullet/pmove.cpp index 8fb72aa1f0..dcb2e9f9b0 100644 --- a/libs/openengine/bullet/pmove.cpp +++ b/libs/openengine/bullet/pmove.cpp @@ -1489,7 +1489,7 @@ static void PM_GroundTrace( void ) //PM_AddTouchEnt( trace.entityNum ); } -static void PM_AirMove() +void PM_AirMove() { //int i; Ogre::Vector3 wishvel; diff --git a/libs/openengine/bullet/trace.h b/libs/openengine/bullet/trace.h index 025673ab7a..fb666b6ebd 100644 --- a/libs/openengine/bullet/trace.h +++ b/libs/openengine/bullet/trace.h @@ -53,10 +53,10 @@ struct traceResults template const bool NewPhysicsTrace(NewPhysTraceResults* const out, const Ogre::Vector3& start, const Ogre::Vector3& end, const Ogre::Vector3& BBExtents, const Ogre::Vector3& rotation, bool isInterior, OEngine::Physic::PhysicEngine* enginePass); -template const bool NewPhysicsTrace(NewPhysTraceResults* const out, const Ogre::Vector3& start, const Ogre::Vector3& end, const Ogre::Vector3& BBExtents, const Ogre::Vector3& rotation, bool isInterior, OEngine::Physic::PhysicEngine* enginePass); -template const bool NewPhysicsTrace(NewPhysTraceResults* const out, const Ogre::Vector3& start, const Ogre::Vector3& end, const Ogre::Vector3& BBExtents, const Ogre::Vector3& rotation, bool isInterior, OEngine::Physic::PhysicEngine* enginePass); +//template const bool NewPhysicsTrace(NewPhysTraceResults* const out, const Ogre::Vector3& start, const Ogre::Vector3& end, const Ogre::Vector3& BBExtents, const Ogre::Vector3& rotation, bool isInterior, OEngine::Physic::PhysicEngine* enginePass); +//template const bool NewPhysicsTrace(NewPhysTraceResults* const out, const Ogre::Vector3& start, const Ogre::Vector3& end, const Ogre::Vector3& BBExtents, const Ogre::Vector3& rotation, bool isInterior, OEngine::Physic::PhysicEngine* enginePass); void newtrace(traceResults* const results, const Ogre::Vector3& start, const Ogre::Vector3& end, const Ogre::Vector3& BBExtents, const float rotation, bool isInterior, OEngine::Physic::PhysicEngine* enginePass); -#endif \ No newline at end of file +#endif From cac662ca981dc0cdb19872f4c40e46b97bf7b365 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 14 Apr 2012 17:47:44 +0200 Subject: [PATCH 007/325] basic tooltips --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/engine.cpp | 16 +++---- apps/openmw/mwgui/tooltips.cpp | 63 ++++++++++++++++++++++++++++ apps/openmw/mwgui/tooltips.hpp | 30 +++++++++++++ apps/openmw/mwgui/window_manager.cpp | 10 +++++ apps/openmw/mwgui/window_manager.hpp | 2 + files/mygui/CMakeLists.txt | 1 + files/mygui/openmw_tooltips.xml | 21 ++++++++++ 8 files changed, 136 insertions(+), 9 deletions(-) create mode 100644 apps/openmw/mwgui/tooltips.cpp create mode 100644 apps/openmw/mwgui/tooltips.hpp create mode 100644 files/mygui/openmw_tooltips.xml diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index c4b3776ed6..a37dbf7af2 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -25,7 +25,7 @@ add_openmw_dir (mwinput add_openmw_dir (mwgui layouts text_input widgets race class birth review window_manager console dialogue dialogue_history window_base stats_window messagebox journalwindow charactercreation - map_window window_pinnable_base cursorreplace + map_window window_pinnable_base cursorreplace tooltips ) add_openmw_dir (mwdialogue diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 2d3c872dd7..36a2cb645b 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -133,14 +133,6 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt) if (mUseSound) mEnvironment.mSoundManager->update (evt.timeSinceLastFrame); - // update GUI - Ogre::RenderWindow* window = mOgre->getWindow(); - mEnvironment.mWindowManager->wmUpdateFps(window->getLastFPS(), - window->getTriangleCount(), - window->getBatchCount()); - - mEnvironment.mWindowManager->onFrame(mEnvironment.mFrameDuration); - // global scripts mEnvironment.mGlobalScripts->run (mEnvironment); @@ -171,6 +163,14 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt) // update world mEnvironment.mWorld->update (evt.timeSinceLastFrame); + // update GUI + Ogre::RenderWindow* window = mOgre->getWindow(); + mEnvironment.mWindowManager->wmUpdateFps(window->getLastFPS(), + window->getTriangleCount(), + window->getBatchCount()); + + mEnvironment.mWindowManager->onFrame(mEnvironment.mFrameDuration); + // report focus object (for debugging) if (mReportFocus) updateFocusReport (mEnvironment.mFrameDuration); diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp new file mode 100644 index 0000000000..d7c61c51a6 --- /dev/null +++ b/apps/openmw/mwgui/tooltips.cpp @@ -0,0 +1,63 @@ +#include "tooltips.hpp" + +using namespace MWGui; +using namespace MyGUI; + +ToolTips::ToolTips() : + Layout("openmw_tooltips.xml") + , mGameMode(true) +{ + getWidget(mTextToolTip, "TextToolTip"); + getWidget(mTextToolTipBox, "TextToolTipBox"); + getWidget(mDynamicToolTipBox, "DynamicToolTipBox"); + + mDynamicToolTipBox->setVisible(false); + + // turn off mouse focus so that getMouseFocusWidget returns the correct widget, + // even if the mouse is over the tooltip + mDynamicToolTipBox->setNeedMouseFocus(false); + mTextToolTipBox->setNeedMouseFocus(false); + mTextToolTip->setNeedMouseFocus(false); + mMainWidget->setNeedMouseFocus(false); +} + +void ToolTips::onFrame(float frameDuration) +{ + /// \todo Store a MWWorld::Ptr in the widget user data, retrieve it here and construct a tooltip dynamically + + const IntSize &viewSize = RenderManager::getInstance().getViewSize(); + + Widget* focus = InputManager::getInstance().getMouseFocusWidget(); + if (focus == 0) return; + + // this the maximum width of the tooltip before it starts word-wrapping + setCoord(0, 0, 300, 300); + + mTextToolTip->setCaption("Focused: " + focus->getName() + "\nType: " + focus->getTypeName()); + const IntSize &textSize = mTextToolTip->getTextSize(); + + IntPoint tooltipPosition = InputManager::getInstance().getMousePosition() + IntPoint(0, 24); + + IntSize size = textSize + IntSize(12, 12); + // make the tooltip stay completely in the viewport + if ((tooltipPosition.left + size.width) > viewSize.width) + { + tooltipPosition.left = viewSize.width - size.width; + } + if ((tooltipPosition.top + size.height) > viewSize.height) + { + tooltipPosition.top = viewSize.height - size.height; + } + + setCoord(tooltipPosition.left, tooltipPosition.top, size.width, size.height); +} + +void ToolTips::enterGameMode() +{ + mGameMode = true; +} + +void ToolTips::enterGuiMode() +{ + mGameMode = false; +} diff --git a/apps/openmw/mwgui/tooltips.hpp b/apps/openmw/mwgui/tooltips.hpp new file mode 100644 index 0000000000..aa929ff510 --- /dev/null +++ b/apps/openmw/mwgui/tooltips.hpp @@ -0,0 +1,30 @@ + +#ifndef MWGUI_TOOLTIPS_H +#define MWGUI_TOOLTIPS_H + +#include + +namespace MWGui +{ + class ToolTips : public OEngine::GUI::Layout + { + public: + ToolTips(); + + void onFrame(float frameDuration); + + void enterGameMode(); + void enterGuiMode(); + + void adjustScreen(int screenWidth, int screenHeight); + + private: + MyGUI::EditBox* mTextToolTip; + MyGUI::Widget* mTextToolTipBox; + + MyGUI::Widget* mDynamicToolTipBox; + + bool mGameMode; + }; +} +#endif diff --git a/apps/openmw/mwgui/window_manager.cpp b/apps/openmw/mwgui/window_manager.cpp index 34d62ba080..1ef5cae421 100644 --- a/apps/openmw/mwgui/window_manager.cpp +++ b/apps/openmw/mwgui/window_manager.cpp @@ -7,6 +7,7 @@ #include "map_window.hpp" #include "stats_window.hpp" #include "messagebox.hpp" +#include "tooltips.hpp" #include "../mwmechanics/mechanicsmanager.hpp" #include "../mwinput/inputmanager.hpp" @@ -31,6 +32,7 @@ WindowManager::WindowManager(MWWorld::Environment& environment, , map(NULL) , menu(NULL) , stats(NULL) + , mToolTips(NULL) , mMessageBoxManager(NULL) , console(NULL) , mJournal(NULL) @@ -80,6 +82,7 @@ WindowManager::WindowManager(MWWorld::Environment& environment, mJournal = new JournalWindow(*this); mMessageBoxManager = new MessageBoxManager(this); dialogueWindow = new DialogueWindow(*this,environment); + mToolTips = new ToolTips(); // The HUD is always on hud->setVisible(true); @@ -118,6 +121,7 @@ WindowManager::~WindowManager() delete stats; delete mJournal; delete dialogueWindow; + delete mToolTips; delete mCharGen; @@ -183,6 +187,11 @@ void WindowManager::updateVisible() // Mouse is visible whenever we're not in game mode MyGUI::PointerManager::getInstance().setVisible(isGuiMode()); + if (mode == GM_Game) + mToolTips->enterGameMode(); + else + mToolTips->enterGuiMode(); + switch(mode) { case GM_Game: // If in game mode, don't show anything. @@ -408,6 +417,7 @@ void WindowManager::onDialogueWindowBye() void WindowManager::onFrame (float frameDuration) { mMessageBoxManager->onFrame(frameDuration); + mToolTips->onFrame(frameDuration); } const ESMS::ESMStore& WindowManager::getStore() const diff --git a/apps/openmw/mwgui/window_manager.hpp b/apps/openmw/mwgui/window_manager.hpp index 2b53560baf..1cbd8f6a6f 100644 --- a/apps/openmw/mwgui/window_manager.hpp +++ b/apps/openmw/mwgui/window_manager.hpp @@ -62,6 +62,7 @@ namespace MWGui class Console; class JournalWindow; class CharacterCreation; + class ToolTips; class TextInputDialog; class InfoBoxDialog; @@ -196,6 +197,7 @@ namespace MWGui HUD *hud; MapWindow *map; MainMenu *menu; + ToolTips *mToolTips; StatsWindow *stats; MessageBoxManager *mMessageBoxManager; Console *console; diff --git a/files/mygui/CMakeLists.txt b/files/mygui/CMakeLists.txt index e3a7b9999c..49055d2ede 100644 --- a/files/mygui/CMakeLists.txt +++ b/files/mygui/CMakeLists.txt @@ -50,6 +50,7 @@ configure_file("${SDIR}/openmw_messagebox_layout.xml" "${DDIR}/openmw_messagebox configure_file("${SDIR}/openmw_interactive_messagebox_layout.xml" "${DDIR}/openmw_interactive_messagebox_layout.xml" COPYONLY) configure_file("${SDIR}/openmw_journal_layout.xml" "${DDIR}/openmw_journal_layout.xml" COPYONLY) configure_file("${SDIR}/openmw_journal_skin.xml" "${DDIR}/openmw_journal_skin.xml" COPYONLY) +configure_file("${SDIR}/openmw_tooltips.xml" "${DDIR}/openmw_tooltips.xml" COPYONLY) configure_file("${SDIR}/smallbars.png" "${DDIR}/smallbars.png" COPYONLY) configure_file("${SDIR}/transparent.png" "${DDIR}/transparent.png" COPYONLY) configure_file("${SDIR}/EBGaramond-Regular.ttf" "${DDIR}/EBGaramond-Regular.ttf" COPYONLY) diff --git a/files/mygui/openmw_tooltips.xml b/files/mygui/openmw_tooltips.xml new file mode 100644 index 0000000000..76df7b9a74 --- /dev/null +++ b/files/mygui/openmw_tooltips.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + From d37bc9cba8d6d9bd9afe07dd48c5981171b812fe Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 15 Apr 2012 17:10:08 +0200 Subject: [PATCH 008/325] basic mouse-over info for in-game objects --- apps/openmw/mwgui/tooltips.cpp | 412 +++++++++++++++++++++++++-- apps/openmw/mwgui/tooltips.hpp | 6 + apps/openmw/mwgui/window_manager.cpp | 5 + apps/openmw/mwgui/window_manager.hpp | 2 + apps/openmw/mwrender/shadows.cpp | 5 +- apps/openmw/mwworld/world.cpp | 12 + files/mygui/openmw_tooltips.xml | 10 +- 7 files changed, 426 insertions(+), 26 deletions(-) diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index d7c61c51a6..7f45bdbddc 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -6,6 +6,7 @@ using namespace MyGUI; ToolTips::ToolTips() : Layout("openmw_tooltips.xml") , mGameMode(true) + , mFocusChanged(true) { getWidget(mTextToolTip, "TextToolTip"); getWidget(mTextToolTipBox, "TextToolTipBox"); @@ -27,29 +28,389 @@ void ToolTips::onFrame(float frameDuration) const IntSize &viewSize = RenderManager::getInstance().getViewSize(); - Widget* focus = InputManager::getInstance().getMouseFocusWidget(); - if (focus == 0) return; - - // this the maximum width of the tooltip before it starts word-wrapping - setCoord(0, 0, 300, 300); - - mTextToolTip->setCaption("Focused: " + focus->getName() + "\nType: " + focus->getTypeName()); - const IntSize &textSize = mTextToolTip->getTextSize(); - - IntPoint tooltipPosition = InputManager::getInstance().getMousePosition() + IntPoint(0, 24); - - IntSize size = textSize + IntSize(12, 12); - // make the tooltip stay completely in the viewport - if ((tooltipPosition.left + size.width) > viewSize.width) + if (!mGameMode) { - tooltipPosition.left = viewSize.width - size.width; - } - if ((tooltipPosition.top + size.height) > viewSize.height) - { - tooltipPosition.top = viewSize.height - size.height; - } + mDynamicToolTipBox->setVisible(false); - setCoord(tooltipPosition.left, tooltipPosition.top, size.width, size.height); + Widget* focus = InputManager::getInstance().getMouseFocusWidget(); + if (focus == 0) return; + + // this the maximum width of the tooltip before it starts word-wrapping + setCoord(0, 0, 300, 300); + + mTextToolTip->setCaption("Focused: " + focus->getName() + "\nType: " + focus->getTypeName()); + const IntSize &textSize = mTextToolTip->getTextSize(); + + IntPoint tooltipPosition = InputManager::getInstance().getMousePosition() + IntPoint(0, 24); + + IntSize size = textSize + IntSize(12, 12); + // make the tooltip stay completely in the viewport + if ((tooltipPosition.left + size.width) > viewSize.width) + { + tooltipPosition.left = viewSize.width - size.width; + } + if ((tooltipPosition.top + size.height) > viewSize.height) + { + tooltipPosition.top = viewSize.height - size.height; + } + + setCoord(tooltipPosition.left, tooltipPosition.top, size.width, size.height); + } + else + { + mTextToolTipBox->setVisible(false); + + if (!mFocusObject.isEmpty()) + { + if (mFocusChanged) + { + for (size_t i=0; igetChildCount(); ++i) + { + mDynamicToolTipBox->_destroyChildWidget(mDynamicToolTipBox->getChildAt(i)); + } + + // this the maximum width of the tooltip before it starts word-wrapping + setCoord(0, 0, 300, 300); + + IntSize tooltipSize; + + /// \todo Not sure about levelled lists (ESM::CreateLevList and ESM::ItemLevList). I think + /// they are supposed to spawn a concrete object (Creature or item of any type), so + /// the player wouldn't encounter them and we don't have to handle them here. + + // -------------------- Door ------------------------------- + if (mFocusObject.getTypeName() == typeid(ESM::Door).name()) + { + ESMS::LiveCellRef* ref = mFocusObject.get(); + + EditBox* box = mDynamicToolTipBox->createWidget("MW_TextEdit", IntCoord(0, 0, 300, 300), Align::Stretch, "ToolTip"); + box->setTextAlign(Align::HCenter); + box->setProperty("Static", "true"); + box->setProperty("MultiLine", "true"); + + std::string caption = ref->base->name; + /// \todo If destCell is empty, the teleport target is an exterior cell. In that case we + /// need to fetch that cell (via target position) and retrieve the region name. + if (ref->ref.teleport && (ref->ref.destCell != "")) + { + caption += "\n-"; + caption += "\n"+ref->ref.destCell; + } + box->setCaption(caption); + + /// \todo Lock level, trap (retrieve GMST) + + tooltipSize = box->getTextSize() + IntSize(12,12); + + mDynamicToolTipBox->setVisible(true); + } + + // -------------------- NPC ------------------------------- + else if (mFocusObject.getTypeName() == typeid(ESM::NPC).name()) + { + /// \todo We don't want tooltips for NPCs in combat mode. + ESMS::LiveCellRef* ref = mFocusObject.get(); + + EditBox* box = mDynamicToolTipBox->createWidget("MW_TextEdit", IntCoord(0, 0, 300, 300), Align::Stretch, "ToolTip"); + box->setTextAlign(Align::HCenter); + box->setProperty("Static", "true"); + box->setCaption(ref->base->name); + + tooltipSize = box->getTextSize() + IntSize(12,12); + + mDynamicToolTipBox->setVisible(true); + } + + // -------------------- Creature ------------------------------- + else if (mFocusObject.getTypeName() == typeid(ESM::Creature).name()) + { + ESMS::LiveCellRef* ref = mFocusObject.get(); + + EditBox* box = mDynamicToolTipBox->createWidget("MW_TextEdit", IntCoord(0, 0, 300, 300), Align::Stretch, "ToolTip"); + box->setTextAlign(Align::HCenter); + box->setProperty("Static", "true"); + box->setCaption(ref->base->name); + + /// \todo + + tooltipSize = box->getTextSize() + IntSize(12,12); + + mDynamicToolTipBox->setVisible(true); + } + + // -------------------- CreatureLevList ------------------------------- + else if (mFocusObject.getTypeName() == typeid(ESM::Creature).name()) + { + ESMS::LiveCellRef* ref = mFocusObject.get(); + + EditBox* box = mDynamicToolTipBox->createWidget("MW_TextEdit", IntCoord(0, 0, 300, 300), Align::Stretch, "ToolTip"); + box->setTextAlign(Align::HCenter); + box->setProperty("Static", "true"); + box->setCaption(ref->base->name); + + /// \todo + + tooltipSize = box->getTextSize() + IntSize(12,12); + + mDynamicToolTipBox->setVisible(true); + } + + // -------------------- Container ------------------------------- + else if (mFocusObject.getTypeName() == typeid(ESM::Container).name()) + { + ESMS::LiveCellRef* ref = mFocusObject.get(); + + EditBox* box = mDynamicToolTipBox->createWidget("MW_TextEdit", IntCoord(0, 0, 300, 300), Align::Stretch, "ToolTip"); + box->setTextAlign(Align::HCenter); + box->setProperty("Static", "true"); + box->setCaption(ref->base->name); + + /// \todo Lock level, trap (retrieve GMST) + + tooltipSize = box->getTextSize() + IntSize(12,12); + + mDynamicToolTipBox->setVisible(true); + } + + // -------------------- Potion ------------------------------- + else if (mFocusObject.getTypeName() == typeid(ESM::Potion).name()) + { + ESMS::LiveCellRef* ref = mFocusObject.get(); + + EditBox* box = mDynamicToolTipBox->createWidget("MW_TextEdit", IntCoord(0, 0, 300, 300), Align::Stretch, "ToolTip"); + box->setTextAlign(Align::HCenter); + box->setProperty("Static", "true"); + box->setCaption(ref->base->name); + + /// \todo + + tooltipSize = box->getTextSize() + IntSize(12,12); + + mDynamicToolTipBox->setVisible(true); + } + + // -------------------- Apparatus ------------------------------- + else if (mFocusObject.getTypeName() == typeid(ESM::Apparatus).name()) + { + ESMS::LiveCellRef* ref = mFocusObject.get(); + + EditBox* box = mDynamicToolTipBox->createWidget("MW_TextEdit", IntCoord(0, 0, 300, 300), Align::Stretch, "ToolTip"); + box->setTextAlign(Align::HCenter); + box->setProperty("Static", "true"); + box->setCaption(ref->base->name); + + /// \todo + + tooltipSize = box->getTextSize() + IntSize(12,12); + + mDynamicToolTipBox->setVisible(true); + } + + // -------------------- Armor ------------------------------- + else if (mFocusObject.getTypeName() == typeid(ESM::Armor).name()) + { + ESMS::LiveCellRef* ref = mFocusObject.get(); + + EditBox* box = mDynamicToolTipBox->createWidget("MW_TextEdit", IntCoord(0, 0, 300, 300), Align::Stretch, "ToolTip"); + box->setTextAlign(Align::HCenter); + box->setProperty("Static", "true"); + box->setCaption(ref->base->name); + + /// \todo weight, armor value, value, durability.. + + tooltipSize = box->getTextSize() + IntSize(12,12); + + mDynamicToolTipBox->setVisible(true); + } + + // -------------------- Book ------------------------------- + else if (mFocusObject.getTypeName() == typeid(ESM::Book).name()) + { + ESMS::LiveCellRef* ref = mFocusObject.get(); + + EditBox* box = mDynamicToolTipBox->createWidget("MW_TextEdit", IntCoord(0, 0, 300, 300), Align::Stretch, "ToolTip"); + box->setTextAlign(Align::HCenter); + box->setProperty("Static", "true"); + box->setCaption(ref->base->name); + + /// \todo + + tooltipSize = box->getTextSize() + IntSize(12,12); + + mDynamicToolTipBox->setVisible(true); + } + + // -------------------- Clothing ------------------------------- + else if (mFocusObject.getTypeName() == typeid(ESM::Clothing).name()) + { + ESMS::LiveCellRef* ref = mFocusObject.get(); + + EditBox* box = mDynamicToolTipBox->createWidget("MW_TextEdit", IntCoord(0, 0, 300, 300), Align::Stretch, "ToolTip"); + box->setTextAlign(Align::HCenter); + box->setProperty("Static", "true"); + box->setCaption(ref->base->name); + + /// \todo + + tooltipSize = box->getTextSize() + IntSize(12,12); + + mDynamicToolTipBox->setVisible(true); + } + + // -------------------- Ingredient ------------------------------- + else if (mFocusObject.getTypeName() == typeid(ESM::Ingredient).name()) + { + ESMS::LiveCellRef* ref = mFocusObject.get(); + + EditBox* box = mDynamicToolTipBox->createWidget("MW_TextEdit", IntCoord(0, 0, 300, 300), Align::Stretch, "ToolTip"); + box->setTextAlign(Align::HCenter); + box->setProperty("Static", "true"); + box->setCaption(ref->base->name); + + /// \todo + + tooltipSize = box->getTextSize() + IntSize(12,12); + + mDynamicToolTipBox->setVisible(true); + } + + // -------------------- Light ------------------------------- + else if (mFocusObject.getTypeName() == typeid(ESM::Light).name()) + { + ESMS::LiveCellRef* ref = mFocusObject.get(); + + EditBox* box = mDynamicToolTipBox->createWidget("MW_TextEdit", IntCoord(0, 0, 300, 300), Align::Stretch, "ToolTip"); + box->setTextAlign(Align::HCenter); + box->setProperty("Static", "true"); + box->setCaption(ref->base->name); + + /// \todo + + tooltipSize = box->getTextSize() + IntSize(12,12); + + mDynamicToolTipBox->setVisible(ref->base->name != ""); + } + + // -------------------- Tool ------------------------------- + else if (mFocusObject.getTypeName() == typeid(ESM::Tool).name()) + { + ESMS::LiveCellRef* ref = mFocusObject.get(); + + EditBox* box = mDynamicToolTipBox->createWidget("MW_TextEdit", IntCoord(0, 0, 300, 300), Align::Stretch, "ToolTip"); + box->setTextAlign(Align::HCenter); + box->setProperty("Static", "true"); + box->setCaption(ref->base->name); + + /// \todo + + tooltipSize = box->getTextSize() + IntSize(12,12); + + mDynamicToolTipBox->setVisible(true); + } + + // -------------------- Miscellaneous ------------------------------- + else if (mFocusObject.getTypeName() == typeid(ESM::Miscellaneous).name()) + { + ESMS::LiveCellRef* ref = mFocusObject.get(); + + EditBox* box = mDynamicToolTipBox->createWidget("MW_TextEdit", IntCoord(0, 0, 300, 300), Align::Stretch, "ToolTip"); + box->setTextAlign(Align::HCenter); + box->setProperty("Static", "true"); + box->setCaption(ref->base->name); + + /// \todo + + tooltipSize = box->getTextSize() + IntSize(12,12); + + mDynamicToolTipBox->setVisible(true); + } + + // -------------------- Probe ------------------------------- + else if (mFocusObject.getTypeName() == typeid(ESM::Probe).name()) + { + ESMS::LiveCellRef* ref = mFocusObject.get(); + + EditBox* box = mDynamicToolTipBox->createWidget("MW_TextEdit", IntCoord(0, 0, 300, 300), Align::Stretch, "ToolTip"); + box->setTextAlign(Align::HCenter); + box->setProperty("Static", "true"); + box->setCaption(ref->base->name); + + /// \todo + + tooltipSize = box->getTextSize() + IntSize(12,12); + + mDynamicToolTipBox->setVisible(true); + } + + // -------------------- Repair ------------------------------- + else if (mFocusObject.getTypeName() == typeid(ESM::Repair).name()) + { + ESMS::LiveCellRef* ref = mFocusObject.get(); + + EditBox* box = mDynamicToolTipBox->createWidget("MW_TextEdit", IntCoord(0, 0, 300, 300), Align::Stretch, "ToolTip"); + box->setTextAlign(Align::HCenter); + box->setProperty("Static", "true"); + box->setCaption(ref->base->name); + + /// \todo + + tooltipSize = box->getTextSize() + IntSize(12,12); + + mDynamicToolTipBox->setVisible(true); + } + + // -------------------- Weapon ------------------------------- + else if (mFocusObject.getTypeName() == typeid(ESM::Weapon).name()) + { + ESMS::LiveCellRef* ref = mFocusObject.get(); + + EditBox* box = mDynamicToolTipBox->createWidget("MW_TextEdit", IntCoord(0, 0, 300, 300), Align::Stretch, "ToolTip"); + box->setTextAlign(Align::HCenter); + box->setProperty("Static", "true"); + box->setCaption(ref->base->name); + + /// \todo + + tooltipSize = box->getTextSize() + IntSize(12,12); + + mDynamicToolTipBox->setVisible(true); + } + + // -------------------- Activator ------------------------------- + else if (mFocusObject.getTypeName() == typeid(ESM::Activator).name()) + { + ESMS::LiveCellRef* ref = mFocusObject.get(); + + EditBox* box = mDynamicToolTipBox->createWidget("MW_TextEdit", IntCoord(0, 0, 300, 300), Align::Stretch, "ToolTip"); + box->setTextAlign(Align::HCenter); + box->setProperty("Static", "true"); + box->setCaption(ref->base->name); + + /// \todo + + tooltipSize = box->getTextSize() + IntSize(12,12); + + mDynamicToolTipBox->setVisible(ref->base->name != ""); + } + + else + { + // object without tooltip + mDynamicToolTipBox->setVisible(false); + } + + // adjust tooltip size to fit its content, position it above the crosshair + /// \todo Slide the tooltip along the bounding box of the focused object (like in Morrowind) + setCoord(viewSize.width/2 - (tooltipSize.width)/2.f, + viewSize.height/2 - (tooltipSize.height) - 32, + tooltipSize.width, + tooltipSize.height); + } + mFocusChanged = false; + } + else + mDynamicToolTipBox->setVisible(false); + } } void ToolTips::enterGameMode() @@ -61,3 +422,12 @@ void ToolTips::enterGuiMode() { mGameMode = false; } + +void ToolTips::setFocusObject(const MWWorld::Ptr& focus) +{ + if (focus != mFocusObject) + { + mFocusObject = focus; + mFocusChanged = true; + } +} diff --git a/apps/openmw/mwgui/tooltips.hpp b/apps/openmw/mwgui/tooltips.hpp index aa929ff510..3052abb7a4 100644 --- a/apps/openmw/mwgui/tooltips.hpp +++ b/apps/openmw/mwgui/tooltips.hpp @@ -3,6 +3,7 @@ #define MWGUI_TOOLTIPS_H #include +#include "../mwworld/ptr.hpp" namespace MWGui { @@ -16,6 +17,8 @@ namespace MWGui void enterGameMode(); void enterGuiMode(); + void setFocusObject(const MWWorld::Ptr& focus); + void adjustScreen(int screenWidth, int screenHeight); private: @@ -24,6 +27,9 @@ namespace MWGui MyGUI::Widget* mDynamicToolTipBox; + MWWorld::Ptr mFocusObject; + bool mFocusChanged; + bool mGameMode; }; } diff --git a/apps/openmw/mwgui/window_manager.cpp b/apps/openmw/mwgui/window_manager.cpp index 1ef5cae421..909be0ac2f 100644 --- a/apps/openmw/mwgui/window_manager.cpp +++ b/apps/openmw/mwgui/window_manager.cpp @@ -492,3 +492,8 @@ int WindowManager::toggleFps() Settings::Manager::setInt("fps", "HUD", showFPSLevel); return showFPSLevel; } + +void WindowManager::setFocusObject(const MWWorld::Ptr& focus) +{ + mToolTips->setFocusObject(focus); +} diff --git a/apps/openmw/mwgui/window_manager.hpp b/apps/openmw/mwgui/window_manager.hpp index 1cbd8f6a6f..d5f0683b86 100644 --- a/apps/openmw/mwgui/window_manager.hpp +++ b/apps/openmw/mwgui/window_manager.hpp @@ -158,6 +158,8 @@ namespace MWGui void setPlayerPos(const float x, const float y); ///< set player position in map space void setPlayerDir(const float x, const float y); ///< set player view direction in map space + void setFocusObject(const MWWorld::Ptr& focus); + void toggleFogOfWar(); int toggleFps(); diff --git a/apps/openmw/mwrender/shadows.cpp b/apps/openmw/mwrender/shadows.cpp index bf5602f438..9a4ae7243c 100644 --- a/apps/openmw/mwrender/shadows.cpp +++ b/apps/openmw/mwrender/shadows.cpp @@ -66,7 +66,10 @@ void Shadows::recreate() if (split) { mPSSMSetup = new PSSMShadowCameraSetup(); - mPSSMSetup->setSplitPadding(5); + + // Make sure to keep this in sync with the camera's near clip distance! + mPSSMSetup->setSplitPadding(mRendering->getCamera()->getNearClipDistance()); + mPSSMSetup->calculateSplitPoints(3, mRendering->getCamera()->getNearClipDistance(), mShadowFar); const Real adjustFactors[3] = {64, 64, 64}; diff --git a/apps/openmw/mwworld/world.cpp b/apps/openmw/mwworld/world.cpp index 1c64039d4c..4719a25cf4 100644 --- a/apps/openmw/mwworld/world.cpp +++ b/apps/openmw/mwworld/world.cpp @@ -13,6 +13,7 @@ #include "../mwsound/soundmanager.hpp" +#include "../mwgui/window_manager.hpp" #include "ptr.hpp" #include "environment.hpp" @@ -737,6 +738,17 @@ namespace MWWorld mWeatherManager->update (duration); + // inform the GUI about focused object + try + { + mEnvironment.mWindowManager->setFocusObject(getPtrViaHandle(mFacedHandle)); + } + catch (std::runtime_error&) + { + MWWorld::Ptr null; + mEnvironment.mWindowManager->setFocusObject(null); + } + if (!mRendering->occlusionQuerySupported()) { // cast a ray from player to sun to detect if the sun is visible diff --git a/files/mygui/openmw_tooltips.xml b/files/mygui/openmw_tooltips.xml index 76df7b9a74..26fc1eeab5 100644 --- a/files/mygui/openmw_tooltips.xml +++ b/files/mygui/openmw_tooltips.xml @@ -1,11 +1,12 @@ - + - - + + + @@ -13,7 +14,8 @@ - + + From b309d245c5db4fa12832292572033fc092d98b1c Mon Sep 17 00:00:00 2001 From: gugus Date: Sun, 15 Apr 2012 17:52:39 +0200 Subject: [PATCH 009/325] cleaning up hircine work --- apps/openmw/CMakeLists.txt | 4 +- apps/openmw/mwclass/apparatus.cpp | 10 + apps/openmw/mwclass/apparatus.hpp | 3 + apps/openmw/mwclass/armor.cpp | 8 + apps/openmw/mwclass/armor.hpp | 3 + apps/openmw/mwclass/book.cpp | 8 + apps/openmw/mwclass/book.hpp | 3 + apps/openmw/mwclass/clothing.cpp | 8 + apps/openmw/mwclass/clothing.hpp | 3 + apps/openmw/mwclass/container.cpp | 7 +- apps/openmw/mwclass/ingredient.cpp | 8 + apps/openmw/mwclass/ingredient.hpp | 3 + apps/openmw/mwclass/light.cpp | 8 + apps/openmw/mwclass/light.hpp | 3 + apps/openmw/mwclass/lockpick.cpp | 8 + apps/openmw/mwclass/lockpick.hpp | 3 + apps/openmw/mwclass/misc.cpp | 8 + apps/openmw/mwclass/misc.hpp | 3 + apps/openmw/mwclass/potion.cpp | 9 + apps/openmw/mwclass/potion.hpp | 3 + apps/openmw/mwclass/probe.cpp | 8 + apps/openmw/mwclass/probe.hpp | 3 + apps/openmw/mwclass/repair.cpp | 8 + apps/openmw/mwclass/repair.hpp | 3 + apps/openmw/mwclass/weapon.cpp | 9 + apps/openmw/mwclass/weapon.hpp | 5 + apps/openmw/mwgui/container.cpp | 191 ++++++++++++++++++ apps/openmw/mwgui/container.hpp | 62 ++++++ apps/openmw/mwgui/window_manager.cpp | 4 +- apps/openmw/mwgui/window_manager.hpp | 6 +- apps/openmw/mwworld/actionopen.cpp | 21 ++ apps/openmw/mwworld/actionopen.hpp | 22 ++ apps/openmw/mwworld/containerstore.cpp | 30 +++ apps/openmw/mwworld/containerstore.hpp | 2 + files/mygui/CMakeLists.txt | 1 + .../mygui/openmw_container_window_layout.xml | 24 +++ 36 files changed, 506 insertions(+), 6 deletions(-) create mode 100644 apps/openmw/mwgui/container.cpp create mode 100644 apps/openmw/mwgui/container.hpp create mode 100644 apps/openmw/mwworld/actionopen.cpp create mode 100644 apps/openmw/mwworld/actionopen.hpp create mode 100644 files/mygui/openmw_container_window_layout.xml diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 2630098f5c..6fb8a24c3d 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -24,7 +24,7 @@ add_openmw_dir (mwinput add_openmw_dir (mwgui layouts text_input widgets race class birth review window_manager console dialogue - dialogue_history window_base stats_window messagebox journalwindow charactercreation + dialogue_history window_base stats_window messagebox journalwindow charactercreation container ) add_openmw_dir (mwdialogue @@ -45,7 +45,7 @@ add_openmw_dir (mwsound add_openmw_dir (mwworld refdata world physicssystem scene environment globals class action nullaction actionteleport containerstore actiontalk actiontake manualref player cellfunctors - cells localscripts customdata weather inventorystore ptr + cells localscripts customdata weather inventorystore ptr actionopen ) add_openmw_dir (mwclass diff --git a/apps/openmw/mwclass/apparatus.cpp b/apps/openmw/mwclass/apparatus.cpp index e95fb572f3..8ac589db6f 100644 --- a/apps/openmw/mwclass/apparatus.cpp +++ b/apps/openmw/mwclass/apparatus.cpp @@ -86,4 +86,14 @@ namespace MWClass { return std::string("Item Apparatus Down"); } + + + std::string Apparatus::getInventoryIcon (const MWWorld::Ptr& ptr) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + return ref->base->icon; + } + } diff --git a/apps/openmw/mwclass/apparatus.hpp b/apps/openmw/mwclass/apparatus.hpp index c0849e1fe2..2d1175951b 100644 --- a/apps/openmw/mwclass/apparatus.hpp +++ b/apps/openmw/mwclass/apparatus.hpp @@ -32,6 +32,9 @@ namespace MWClass virtual std::string getDownSoundId (const MWWorld::Ptr& ptr) const; ///< Return the put down sound Id + + virtual std::string getInventoryIcon (const MWWorld::Ptr& ptr) const; + ///< Return name of inventory icon. }; } diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index e1c2734f0e..597094a45e 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -188,4 +188,12 @@ namespace MWClass else return std::string("Item Armor Heavy Down"); } + + std::string Armor::getInventoryIcon (const MWWorld::Ptr& ptr) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + return ref->base->icon; + } } diff --git a/apps/openmw/mwclass/armor.hpp b/apps/openmw/mwclass/armor.hpp index 2b66ff8280..aada97eec6 100644 --- a/apps/openmw/mwclass/armor.hpp +++ b/apps/openmw/mwclass/armor.hpp @@ -47,6 +47,9 @@ namespace MWClass virtual std::string getDownSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const; ///< Return the put down sound Id + + virtual std::string getInventoryIcon (const MWWorld::Ptr& ptr) const; + ///< Return name of inventory icon. }; } diff --git a/apps/openmw/mwclass/book.cpp b/apps/openmw/mwclass/book.cpp index 0a81ebafb7..f22191f265 100644 --- a/apps/openmw/mwclass/book.cpp +++ b/apps/openmw/mwclass/book.cpp @@ -88,4 +88,12 @@ namespace MWClass { return std::string("Item Book Down"); } + std::string Book::getInventoryIcon (const MWWorld::Ptr& ptr) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + return ref->base->icon; + } + } diff --git a/apps/openmw/mwclass/book.hpp b/apps/openmw/mwclass/book.hpp index ccbbfb4b2d..2d37bffead 100644 --- a/apps/openmw/mwclass/book.hpp +++ b/apps/openmw/mwclass/book.hpp @@ -32,6 +32,9 @@ namespace MWClass virtual std::string getDownSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const; ///< Return the put down sound Id + + virtual std::string getInventoryIcon (const MWWorld::Ptr& ptr) const; + ///< Return name of inventory icon. }; } diff --git a/apps/openmw/mwclass/clothing.cpp b/apps/openmw/mwclass/clothing.cpp index 4fe19ada40..176ab26dc5 100644 --- a/apps/openmw/mwclass/clothing.cpp +++ b/apps/openmw/mwclass/clothing.cpp @@ -153,4 +153,12 @@ namespace MWClass } return std::string("Item Clothes Down"); } + + std::string Clothing::getInventoryIcon (const MWWorld::Ptr& ptr) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + return ref->base->icon; + } } diff --git a/apps/openmw/mwclass/clothing.hpp b/apps/openmw/mwclass/clothing.hpp index 171b062461..b7084a4d53 100644 --- a/apps/openmw/mwclass/clothing.hpp +++ b/apps/openmw/mwclass/clothing.hpp @@ -41,6 +41,9 @@ namespace MWClass virtual std::string getDownSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const; ///< Return the put down sound Id + + virtual std::string getInventoryIcon (const MWWorld::Ptr& ptr) const; + ///< Return name of inventory icon. }; } diff --git a/apps/openmw/mwclass/container.cpp b/apps/openmw/mwclass/container.cpp index c58a25c03e..dd5f3add31 100644 --- a/apps/openmw/mwclass/container.cpp +++ b/apps/openmw/mwclass/container.cpp @@ -12,6 +12,7 @@ #include "../mwworld/environment.hpp" #include "../mwrender/objects.hpp" +#include "../mwworld/actionopen.hpp" #include "../mwsound/soundmanager.hpp" @@ -81,6 +82,7 @@ namespace MWClass const std::string lockedSound = "LockedChest"; const std::string trapActivationSound = "Disarm Trap Fail"; + if (ptr.getCellRef().lockLevel>0) { // TODO check for key @@ -94,7 +96,8 @@ namespace MWClass if(ptr.getCellRef().trap.empty()) { // Not trapped, Inventory GUI goes here - return boost::shared_ptr (new MWWorld::NullAction); + //return boost::shared_ptr (new MWWorld::NullAction); + return boost::shared_ptr (new MWWorld::ActionOpen(ptr)); } else { @@ -137,4 +140,6 @@ namespace MWClass registerClass (typeid (ESM::Container).name(), instance); } + + } diff --git a/apps/openmw/mwclass/ingredient.cpp b/apps/openmw/mwclass/ingredient.cpp index 1a7edf6325..7b96817e92 100644 --- a/apps/openmw/mwclass/ingredient.cpp +++ b/apps/openmw/mwclass/ingredient.cpp @@ -84,4 +84,12 @@ namespace MWClass { return std::string("Item Ingredient Down"); } + + std::string Ingredient::getInventoryIcon (const MWWorld::Ptr& ptr) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + return ref->base->icon; + } } diff --git a/apps/openmw/mwclass/ingredient.hpp b/apps/openmw/mwclass/ingredient.hpp index 9463dcf8d7..f79534868f 100644 --- a/apps/openmw/mwclass/ingredient.hpp +++ b/apps/openmw/mwclass/ingredient.hpp @@ -32,6 +32,9 @@ namespace MWClass virtual std::string getDownSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const; ///< Return the put down sound Id + + virtual std::string getInventoryIcon (const MWWorld::Ptr& ptr) const; + ///< Return name of inventory icon. }; } diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index e2e63a89bb..50fc390239 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -126,4 +126,12 @@ namespace MWClass { return std::string("Item Misc Down"); } + + std::string Light::getInventoryIcon (const MWWorld::Ptr& ptr) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + return ref->base->icon; + } } diff --git a/apps/openmw/mwclass/light.hpp b/apps/openmw/mwclass/light.hpp index 46a4d60ba4..bd04401ced 100644 --- a/apps/openmw/mwclass/light.hpp +++ b/apps/openmw/mwclass/light.hpp @@ -41,6 +41,9 @@ namespace MWClass virtual std::string getDownSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const; ///< Return the put down sound Id + + virtual std::string getInventoryIcon (const MWWorld::Ptr& ptr) const; + ///< Return name of inventory icon. }; } diff --git a/apps/openmw/mwclass/lockpick.cpp b/apps/openmw/mwclass/lockpick.cpp index 3dda2f4af0..49300eb09b 100644 --- a/apps/openmw/mwclass/lockpick.cpp +++ b/apps/openmw/mwclass/lockpick.cpp @@ -97,4 +97,12 @@ namespace MWClass { return std::string("Item Lockpick Down"); } + + std::string Lockpick::getInventoryIcon (const MWWorld::Ptr& ptr) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + return ref->base->icon; + } } diff --git a/apps/openmw/mwclass/lockpick.hpp b/apps/openmw/mwclass/lockpick.hpp index 0c9189c548..4d5938a692 100644 --- a/apps/openmw/mwclass/lockpick.hpp +++ b/apps/openmw/mwclass/lockpick.hpp @@ -36,6 +36,9 @@ namespace MWClass virtual std::string getDownSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const; ///< Return the put down sound Id + + virtual std::string getInventoryIcon (const MWWorld::Ptr& ptr) const; + ///< Return name of inventory icon. }; } diff --git a/apps/openmw/mwclass/misc.cpp b/apps/openmw/mwclass/misc.cpp index 864fc1e382..cd06d10736 100644 --- a/apps/openmw/mwclass/misc.cpp +++ b/apps/openmw/mwclass/misc.cpp @@ -100,4 +100,12 @@ namespace MWClass } return std::string("Item Misc Down"); } + + std::string Miscellaneous::getInventoryIcon (const MWWorld::Ptr& ptr) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + return ref->base->icon; + } } diff --git a/apps/openmw/mwclass/misc.hpp b/apps/openmw/mwclass/misc.hpp index b07964f990..39d771dc9f 100644 --- a/apps/openmw/mwclass/misc.hpp +++ b/apps/openmw/mwclass/misc.hpp @@ -32,6 +32,9 @@ namespace MWClass virtual std::string getDownSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const; ///< Return the put down sound Id + + virtual std::string getInventoryIcon (const MWWorld::Ptr& ptr) const; + ///< Return name of inventory icon. }; } diff --git a/apps/openmw/mwclass/potion.cpp b/apps/openmw/mwclass/potion.cpp index 4ab3745900..a50d19736e 100644 --- a/apps/openmw/mwclass/potion.cpp +++ b/apps/openmw/mwclass/potion.cpp @@ -86,4 +86,13 @@ namespace MWClass { return std::string("Item Potion Down"); } + + + std::string Potion::getInventoryIcon (const MWWorld::Ptr& ptr) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + return ref->base->icon; + } } diff --git a/apps/openmw/mwclass/potion.hpp b/apps/openmw/mwclass/potion.hpp index be9e713fba..5eb9a3e460 100644 --- a/apps/openmw/mwclass/potion.hpp +++ b/apps/openmw/mwclass/potion.hpp @@ -32,6 +32,9 @@ namespace MWClass virtual std::string getDownSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const; ///< Return the put down sound Id + + virtual std::string getInventoryIcon (const MWWorld::Ptr& ptr) const; + ///< Return name of inventory icon. }; } diff --git a/apps/openmw/mwclass/probe.cpp b/apps/openmw/mwclass/probe.cpp index 4b4d79a73e..3f8dc2a441 100644 --- a/apps/openmw/mwclass/probe.cpp +++ b/apps/openmw/mwclass/probe.cpp @@ -96,4 +96,12 @@ namespace MWClass { return std::string("Item Probe Down"); } + + std::string Probe::getInventoryIcon (const MWWorld::Ptr& ptr) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + return ref->base->icon; + } } diff --git a/apps/openmw/mwclass/probe.hpp b/apps/openmw/mwclass/probe.hpp index 1507d65aab..1d9ce7d863 100644 --- a/apps/openmw/mwclass/probe.hpp +++ b/apps/openmw/mwclass/probe.hpp @@ -36,6 +36,9 @@ namespace MWClass virtual std::string getDownSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const; ///< Return the put down sound Id + + virtual std::string getInventoryIcon (const MWWorld::Ptr& ptr) const; + ///< Return name of inventory icon. }; } diff --git a/apps/openmw/mwclass/repair.cpp b/apps/openmw/mwclass/repair.cpp index 758bf40797..bafb84bca6 100644 --- a/apps/openmw/mwclass/repair.cpp +++ b/apps/openmw/mwclass/repair.cpp @@ -86,4 +86,12 @@ namespace MWClass { return std::string("Item Repair Down"); } + + std::string Repair::getInventoryIcon (const MWWorld::Ptr& ptr) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + return ref->base->icon; + } } diff --git a/apps/openmw/mwclass/repair.hpp b/apps/openmw/mwclass/repair.hpp index 17b606f4cb..3b8260f9d1 100644 --- a/apps/openmw/mwclass/repair.hpp +++ b/apps/openmw/mwclass/repair.hpp @@ -32,6 +32,9 @@ namespace MWClass virtual std::string getDownSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const; ///< Return the put down sound Id + + virtual std::string getInventoryIcon (const MWWorld::Ptr& ptr) const; + ///< Return name of inventory icon. }; } diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index 20db0cf38f..9d3d406460 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -237,4 +237,13 @@ namespace MWClass return std::string("Item Misc Down"); } + + + std::string Weapon::getInventoryIcon (const MWWorld::Ptr& ptr) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + return ref->base->icon; + } } diff --git a/apps/openmw/mwclass/weapon.hpp b/apps/openmw/mwclass/weapon.hpp index f863c0bfe2..31fee9b4b3 100644 --- a/apps/openmw/mwclass/weapon.hpp +++ b/apps/openmw/mwclass/weapon.hpp @@ -47,6 +47,11 @@ namespace MWClass virtual std::string getDownSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const; ///< Return the put down sound Id + + virtual std::string getInventoryIcon (const MWWorld::Ptr& ptr) const; + ///< Return name of inventory icon. + + }; } diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp new file mode 100644 index 0000000000..c09a1bf58b --- /dev/null +++ b/apps/openmw/mwgui/container.cpp @@ -0,0 +1,191 @@ +#include "container.hpp" + +#include +#include +#include "window_manager.hpp" +#include "widgets.hpp" + +#include "../mwworld/environment.hpp" +#include "../mwworld/manualref.hpp" +#include +#include +#include + +#include +#include +#include "../mwclass/container.hpp" +#include "../mwworld/containerstore.hpp" +#include + + +using namespace MWGui; +using namespace Widgets; + + +ContainerWindow::ContainerWindow(WindowManager& parWindowManager,MWWorld::Environment& environment) + : WindowBase("openmw_container_window_layout.xml", parWindowManager), + mEnvironment(environment) +{ + setText("_Main", "Name of Container"); + setVisible(false); + + getWidget(containerWidget, "Items"); + getWidget(takeButton, "TakeButton"); + getWidget(closeButton, "CloseButton"); + + setText("CloseButton","Close"); + setText("TakeButton","Take All"); + + //ctor +} + +ContainerWindow::~ContainerWindow() +{ + //dtor + + + + +} + +void ContainerWindow::setName(std::string contName) +{ + setText("_Main", contName); +} + + + +void ContainerWindow::open(MWWorld::Ptr& container) +{ + setName(MWWorld::Class::get(container).getName(container)); + //MWWorld::ContainerStore* containerStore = container.getContainerStore(); + + MWWorld::ContainerStore& containerStore = MWWorld::Class::get(container).getContainerStore(container); + + + MWWorld::ManualRef furRef (mWindowManager.getStore(), "fur_cuirass"); + furRef.getPtr().getRefData().setCount (5); + MWWorld::ManualRef bukkitRef (mWindowManager.getStore(), "misc_com_bucket_01"); + MWWorld::ManualRef broomRef (mWindowManager.getStore(), "misc_com_broom_01"); + MWWorld::ManualRef goldRef (mWindowManager.getStore(), "gold_100"); + + containerStore.add(furRef.getPtr()); + containerStore.add(furRef.getPtr()); + containerStore.add(furRef.getPtr()); + containerStore.add(broomRef.getPtr()); + containerStore.add(broomRef.getPtr()); + containerStore.add(broomRef.getPtr()); + containerStore.add(broomRef.getPtr()); + containerStore.add(broomRef.getPtr()); + containerStore.add(broomRef.getPtr()); + containerStore.add(broomRef.getPtr()); + containerStore.add(broomRef.getPtr()); + containerStore.add(broomRef.getPtr()); + containerStore.add(broomRef.getPtr()); + containerStore.add(bukkitRef.getPtr()); + containerStore.add(bukkitRef.getPtr()); + containerStore.add(bukkitRef.getPtr()); + containerStore.add(bukkitRef.getPtr()); + containerStore.add(bukkitRef.getPtr()); + containerStore.add(bukkitRef.getPtr()); + containerStore.add(bukkitRef.getPtr()); + containerStore.add(bukkitRef.getPtr()); + containerStore.add(bukkitRef.getPtr()); + containerStore.add(bukkitRef.getPtr()); + containerStore.add(goldRef.getPtr()); + + + + // ESMS::LiveCellRef *ref = iter->get(); + + + int x = 4; + int y = 4; + int count = 0; + + for (MWWorld::ContainerStoreIterator iter (containerStore.begin()); iter!=containerStore.end(); ++iter) + { + std::string path = std::string("icons\\"); + + + path += iter.getInventoryIcon(); +// switch (iter.getType()) +// { +// +// case MWWorld::ContainerStore::Type_Potion: +// path += iter->get()->base->icon; +// break; +// case MWWorld::ContainerStore::Type_Apparatus: +// path += iter->get()->base->icon; +// break; +// case MWWorld::ContainerStore::Type_Armor: +// path += iter->get()->base->icon; +// break; +// case MWWorld::ContainerStore::Type_Book: +// path += iter->get()->base->icon; +// break; +// case MWWorld::ContainerStore::Type_Clothing: +// path += iter->get()->base->icon; +// break; +// case MWWorld::ContainerStore::Type_Ingredient: +// path += iter->get()->base->icon; +// break; +// case MWWorld::ContainerStore::Type_Light: +// path += iter->get()->base->icon; +// break; +// case MWWorld::ContainerStore::Type_Lockpick: +// path += iter->get()->base->icon; +// break; +// case MWWorld::ContainerStore::Type_Miscellaneous: +// path += iter->get()->base->icon; +// break; +// case MWWorld::ContainerStore::Type_Probe: +// path += iter->get()->base->icon; +// break; +// case MWWorld::ContainerStore::Type_Repair: +// path += iter->get()->base->icon; +// break; +// case MWWorld::ContainerStore::Type_Weapon: +// path += iter->get()->base->icon; +// break; +// +// +// } + count++; + + if(count % 8 == 0) + { + y += 36; + x = 4; + count = 0; + } + x += 36; + + + MyGUI::ImageBox* image = containerWidget->createWidget("ImageBox", MyGUI::IntCoord(x, y, 32, 32), MyGUI::Align::Default); + MyGUI::TextBox* text = containerWidget->createWidget("SandBrightText", MyGUI::IntCoord(x, y, 18, 18), MyGUI::Align::Default, std::string("Label")); + + if(iter->getRefData().getCount() > 1) + text->setCaption(boost::lexical_cast(iter->getRefData().getCount())); + + + containerWidgets.push_back(image); + + + int pos = path.rfind("."); + path.erase(pos); + path.append(".dds"); + + //std::cout << path << std::endl; + image->setImageTexture(path); + } + + + setVisible(true); +} + +void Update() +{ + +} + diff --git a/apps/openmw/mwgui/container.hpp b/apps/openmw/mwgui/container.hpp new file mode 100644 index 0000000000..e027f48fe7 --- /dev/null +++ b/apps/openmw/mwgui/container.hpp @@ -0,0 +1,62 @@ +#ifndef MGUI_CONTAINER_H +#define MGUI_CONTAINER_H + +#include +#include "../mwclass/container.hpp" +#include +#include +#include +#include +#include "window_base.hpp" +#include "../mwworld/ptr.hpp" +#include "../mwworld/containerstore.hpp" + +namespace MWWorld +{ + class Environment; +} + +namespace MyGUI +{ + class Gui; + class Widget; +} + +namespace MWGui +{ + class WindowManager; +} + + +namespace MWGui +{ + + + class ContainerWindow : public WindowBase + { + public: + ContainerWindow(WindowManager& parWindowManager,MWWorld::Environment& environment); + + + void open(MWWorld::Ptr& container); + void setName(std::string contName); + void Update(); + + virtual ~ContainerWindow(); + protected: + private: + MWWorld::Environment& mEnvironment; + std::vector containerWidgets; + MyGUI::WidgetPtr containerWidget; + + MyGUI::ButtonPtr takeButton; + MyGUI::ButtonPtr closeButton; + + + + + + //MWWorld::Ptr& mContainer; + }; +} +#endif // CONTAINER_H diff --git a/apps/openmw/mwgui/window_manager.cpp b/apps/openmw/mwgui/window_manager.cpp index fa6dedc77e..7410668969 100644 --- a/apps/openmw/mwgui/window_manager.cpp +++ b/apps/openmw/mwgui/window_manager.cpp @@ -6,6 +6,7 @@ #include "dialogue_history.hpp" #include "stats_window.hpp" #include "messagebox.hpp" +#include "container.hpp" #include "../mwmechanics/mechanicsmanager.hpp" #include "../mwinput/inputmanager.hpp" @@ -52,6 +53,7 @@ WindowManager::WindowManager(MWWorld::Environment& environment, mJournal = new JournalWindow(*this); mMessageBoxManager = new MessageBoxManager(this); dialogueWindow = new DialogueWindow(*this,environment); + containerWindow = new ContainerWindow(*this,environment); // The HUD is always on hud->setVisible(true); @@ -90,7 +92,7 @@ WindowManager::~WindowManager() delete stats; delete mJournal; delete dialogueWindow; - + delete containerWindow; delete mCharGen; cleanupGarbage(); diff --git a/apps/openmw/mwgui/window_manager.hpp b/apps/openmw/mwgui/window_manager.hpp index 582f438e8f..cbe0edad96 100644 --- a/apps/openmw/mwgui/window_manager.hpp +++ b/apps/openmw/mwgui/window_manager.hpp @@ -62,7 +62,7 @@ namespace MWGui class Console; class JournalWindow; class CharacterCreation; - + class ContainerWindow; class TextInputDialog; class InfoBoxDialog; class DialogueWindow; @@ -127,6 +127,8 @@ namespace MWGui MWGui::DialogueWindow* getDialogueWindow() {return dialogueWindow;} + MWGui::ContainerWindow* getContainerWindow() {return containerWindow;} + MyGUI::Gui* getGui() const { return gui; } void wmUpdateFps(float fps, size_t triangleCount, size_t batchCount) @@ -191,7 +193,7 @@ namespace MWGui Console *console; JournalWindow* mJournal; DialogueWindow *dialogueWindow; - + ContainerWindow *containerWindow; CharacterCreation* mCharGen; // Various stats about player as needed by window manager diff --git a/apps/openmw/mwworld/actionopen.cpp b/apps/openmw/mwworld/actionopen.cpp new file mode 100644 index 0000000000..c7b066d8e6 --- /dev/null +++ b/apps/openmw/mwworld/actionopen.cpp @@ -0,0 +1,21 @@ +#include "actionopen.hpp" + +#include "environment.hpp" +#include "class.hpp" +#include "world.hpp" +#include "containerstore.hpp" +#include "../mwclass/container.hpp" +#include "../mwgui/window_manager.hpp" +#include "../mwgui/container.hpp" + +namespace MWWorld +{ + ActionOpen::ActionOpen (const MWWorld::Ptr& container) : mContainer (container) { + mContainer = container; + } + + void ActionOpen::execute (Environment& environment) + { + environment.mWindowManager->getContainerWindow()->open(mContainer); + } +} diff --git a/apps/openmw/mwworld/actionopen.hpp b/apps/openmw/mwworld/actionopen.hpp new file mode 100644 index 0000000000..7c660e4c94 --- /dev/null +++ b/apps/openmw/mwworld/actionopen.hpp @@ -0,0 +1,22 @@ + +#ifndef GAME_MWWORLD_ACTIONOPEN_H +#define GAME_MWWORLD_ACTIONOPEN_H + +#include "action.hpp" +#include "ptr.hpp" + + +namespace MWWorld +{ + class ActionOpen : public Action + { + Ptr mContainer; + + public: + ActionOpen (const Ptr& container); + ///< \param The Container the Player has activated. + virtual void execute (Environment& environment); + }; +} + +#endif // ACTIONOPEN_H diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index 2800b6f3c1..16de93332e 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -457,3 +457,33 @@ bool MWWorld::operator!= (const ContainerStoreIterator& left, const ContainerSto { return !(left==right); } + + +std::string MWWorld::ContainerStoreIterator::getInventoryIcon() +{ + Ptr ptr; + + switch (mType) + { + case ContainerStore::Type_Potion: ptr = MWWorld::Ptr (&*mPotion, 0); break; + case ContainerStore::Type_Apparatus: ptr = MWWorld::Ptr (&*mApparatus, 0); break; + case ContainerStore::Type_Armor: ptr = MWWorld::Ptr (&*mArmor, 0); break; + case ContainerStore::Type_Book: ptr = MWWorld::Ptr (&*mBook, 0); break; + case ContainerStore::Type_Clothing: ptr = MWWorld::Ptr (&*mClothing, 0); break; + case ContainerStore::Type_Ingredient: ptr = MWWorld::Ptr (&*mIngredient, 0); break; + case ContainerStore::Type_Light: ptr = MWWorld::Ptr (&*mLight, 0); break; + case ContainerStore::Type_Lockpick: ptr = MWWorld::Ptr (&*mLockpick, 0); break; + case ContainerStore::Type_Miscellaneous: ptr = MWWorld::Ptr (&*mMiscellaneous, 0); break; + case ContainerStore::Type_Probe: ptr = MWWorld::Ptr (&*mProbe, 0); break; + case ContainerStore::Type_Repair: ptr = MWWorld::Ptr (&*mRepair, 0); break; + case ContainerStore::Type_Weapon: ptr = MWWorld::Ptr (&*mWeapon, 0); break; + } + + if (ptr.isEmpty()) + throw std::runtime_error ("invalid iterator"); + + + std::string s = ptr.getInventoryIcon(); + + return s; +} diff --git a/apps/openmw/mwworld/containerstore.hpp b/apps/openmw/mwworld/containerstore.hpp index da5424fe08..fc6283442e 100644 --- a/apps/openmw/mwworld/containerstore.hpp +++ b/apps/openmw/mwworld/containerstore.hpp @@ -161,6 +161,8 @@ namespace MWWorld const ContainerStore *getContainerStore() const; + std::string getInventoryIcon(); + friend class ContainerStore; }; diff --git a/files/mygui/CMakeLists.txt b/files/mygui/CMakeLists.txt index 9a6cde7ba1..c24bd59f45 100644 --- a/files/mygui/CMakeLists.txt +++ b/files/mygui/CMakeLists.txt @@ -38,6 +38,7 @@ configure_file("${SDIR}/openmw_chargen_review_layout.xml" "${DDIR}/openmw_charge configure_file("${SDIR}/openmw_dialogue_window_layout.xml" "${DDIR}/openmw_dialogue_window_layout.xml" COPYONLY) configure_file("${SDIR}/openmw_dialogue_window_skin.xml" "${DDIR}/openmw_dialogue_window_skin.xml" COPYONLY) configure_file("${SDIR}/openmw_inventory_window_layout.xml" "${DDIR}/openmw_inventory_window_layout.xml" COPYONLY) +configure_file("${SDIR}/openmw_container_window_layout.xml" "${DDIR}/openmw_container_window_layout.xml" COPYONLY) configure_file("${SDIR}/openmw_layers.xml" "${DDIR}/openmw_layers.xml" COPYONLY) configure_file("${SDIR}/openmw_mainmenu_layout.xml" "${DDIR}/openmw_mainmenu_layout.xml" COPYONLY) configure_file("${SDIR}/openmw_mainmenu_skin.xml" "${DDIR}/openmw_mainmenu_skin.xml" COPYONLY) diff --git a/files/mygui/openmw_container_window_layout.xml b/files/mygui/openmw_container_window_layout.xml new file mode 100644 index 0000000000..a9de148804 --- /dev/null +++ b/files/mygui/openmw_container_window_layout.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + From 78c8a22cd16bef3ca0efc1479b8ceb777aac77af Mon Sep 17 00:00:00 2001 From: gugus Date: Sun, 15 Apr 2012 19:32:41 +0200 Subject: [PATCH 010/325] more clean up. The container GUI shows up now --- apps/openmw/mwgui/container.cpp | 95 ++++++++++++-------------- apps/openmw/mwgui/mode.hpp | 1 + apps/openmw/mwgui/window_manager.cpp | 5 ++ apps/openmw/mwworld/actionopen.cpp | 1 + apps/openmw/mwworld/containerstore.cpp | 2 +- 5 files changed, 52 insertions(+), 52 deletions(-) diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index c09a1bf58b..7a3d5b2406 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -27,7 +27,7 @@ ContainerWindow::ContainerWindow(WindowManager& parWindowManager,MWWorld::Enviro mEnvironment(environment) { setText("_Main", "Name of Container"); - setVisible(false); + center(); getWidget(containerWidget, "Items"); getWidget(takeButton, "TakeButton"); @@ -35,17 +35,10 @@ ContainerWindow::ContainerWindow(WindowManager& parWindowManager,MWWorld::Enviro setText("CloseButton","Close"); setText("TakeButton","Take All"); - - //ctor } ContainerWindow::~ContainerWindow() { - //dtor - - - - } void ContainerWindow::setName(std::string contName) @@ -108,49 +101,49 @@ void ContainerWindow::open(MWWorld::Ptr& container) std::string path = std::string("icons\\"); - path += iter.getInventoryIcon(); -// switch (iter.getType()) -// { -// -// case MWWorld::ContainerStore::Type_Potion: -// path += iter->get()->base->icon; -// break; -// case MWWorld::ContainerStore::Type_Apparatus: -// path += iter->get()->base->icon; -// break; -// case MWWorld::ContainerStore::Type_Armor: -// path += iter->get()->base->icon; -// break; -// case MWWorld::ContainerStore::Type_Book: -// path += iter->get()->base->icon; -// break; -// case MWWorld::ContainerStore::Type_Clothing: -// path += iter->get()->base->icon; -// break; -// case MWWorld::ContainerStore::Type_Ingredient: -// path += iter->get()->base->icon; -// break; -// case MWWorld::ContainerStore::Type_Light: -// path += iter->get()->base->icon; -// break; -// case MWWorld::ContainerStore::Type_Lockpick: -// path += iter->get()->base->icon; -// break; -// case MWWorld::ContainerStore::Type_Miscellaneous: -// path += iter->get()->base->icon; -// break; -// case MWWorld::ContainerStore::Type_Probe: -// path += iter->get()->base->icon; -// break; -// case MWWorld::ContainerStore::Type_Repair: -// path += iter->get()->base->icon; -// break; -// case MWWorld::ContainerStore::Type_Weapon: -// path += iter->get()->base->icon; -// break; -// -// -// } + //path += iter.getInventoryIcon(); + switch (iter.getType()) + { + + case MWWorld::ContainerStore::Type_Potion: + path += iter->get()->base->icon; + break; + case MWWorld::ContainerStore::Type_Apparatus: + path += iter->get()->base->icon; + break; + case MWWorld::ContainerStore::Type_Armor: + path += iter->get()->base->icon; + break; + case MWWorld::ContainerStore::Type_Book: + path += iter->get()->base->icon; + break; + case MWWorld::ContainerStore::Type_Clothing: + path += iter->get()->base->icon; + break; + case MWWorld::ContainerStore::Type_Ingredient: + path += iter->get()->base->icon; + break; + case MWWorld::ContainerStore::Type_Light: + path += iter->get()->base->icon; + break; + case MWWorld::ContainerStore::Type_Lockpick: + path += iter->get()->base->icon; + break; + case MWWorld::ContainerStore::Type_Miscellaneous: + path += iter->get()->base->icon; + break; + case MWWorld::ContainerStore::Type_Probe: + path += iter->get()->base->icon; + break; + case MWWorld::ContainerStore::Type_Repair: + path += iter->get()->base->icon; + break; + case MWWorld::ContainerStore::Type_Weapon: + path += iter->get()->base->icon; + break; + + + } count++; if(count % 8 == 0) diff --git a/apps/openmw/mwgui/mode.hpp b/apps/openmw/mwgui/mode.hpp index 55f0952ce5..48670e9a54 100644 --- a/apps/openmw/mwgui/mode.hpp +++ b/apps/openmw/mwgui/mode.hpp @@ -7,6 +7,7 @@ namespace MWGui { GM_Game, // Game mode, only HUD GM_Inventory, // Inventory mode + GM_Container, GM_MainMenu, // Main menu mode GM_Console, // Console mode diff --git a/apps/openmw/mwgui/window_manager.cpp b/apps/openmw/mwgui/window_manager.cpp index 06bbb3a308..34048c935d 100644 --- a/apps/openmw/mwgui/window_manager.cpp +++ b/apps/openmw/mwgui/window_manager.cpp @@ -181,6 +181,7 @@ void WindowManager::updateVisible() console->disable(); mJournal->setVisible(false); dialogueWindow->setVisible(false); + containerWindow->setVisible(false); // Mouse is visible whenever we're not in game mode MyGUI::PointerManager::getInstance().setVisible(isGuiMode()); @@ -216,8 +217,12 @@ void WindowManager::updateVisible() // Show the windows we want map -> setVisible( (eff & GW_Map) != 0 ); stats -> setVisible( (eff & GW_Stats) != 0 ); + break; } + case GM_Container: + containerWindow->setVisible(true); + break; case GM_Dialogue: dialogueWindow->open(); break; diff --git a/apps/openmw/mwworld/actionopen.cpp b/apps/openmw/mwworld/actionopen.cpp index c7b066d8e6..aa4a67b2b5 100644 --- a/apps/openmw/mwworld/actionopen.cpp +++ b/apps/openmw/mwworld/actionopen.cpp @@ -16,6 +16,7 @@ namespace MWWorld void ActionOpen::execute (Environment& environment) { + environment.mWindowManager->setGuiMode(MWGui::GuiMode::GM_Container); environment.mWindowManager->getContainerWindow()->open(mContainer); } } diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index 16de93332e..3f1b7ea2cf 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -483,7 +483,7 @@ std::string MWWorld::ContainerStoreIterator::getInventoryIcon() throw std::runtime_error ("invalid iterator"); - std::string s = ptr.getInventoryIcon(); + std::string s = "";//ptr.getInventoryIcon(); return s; } From 58d05fa503f9117ae7ddc6288cbeb421c73b83cc Mon Sep 17 00:00:00 2001 From: gugus Date: Sun, 15 Apr 2012 20:56:45 +0200 Subject: [PATCH 011/325] more clean-up. Container window shows up! But there is no working close button. --- apps/openmw/mwgui/container.cpp | 45 ++------------------------ apps/openmw/mwworld/class.cpp | 5 +++ apps/openmw/mwworld/class.hpp | 3 ++ apps/openmw/mwworld/containerstore.cpp | 32 +----------------- apps/openmw/mwworld/containerstore.hpp | 2 -- files/mygui/core.xml | 1 + 6 files changed, 12 insertions(+), 76 deletions(-) diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 7a3d5b2406..2defad2075 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -16,6 +16,7 @@ #include "../mwclass/container.hpp" #include "../mwworld/containerstore.hpp" #include +#include "../mwworld/class.hpp" using namespace MWGui; @@ -101,49 +102,7 @@ void ContainerWindow::open(MWWorld::Ptr& container) std::string path = std::string("icons\\"); - //path += iter.getInventoryIcon(); - switch (iter.getType()) - { - - case MWWorld::ContainerStore::Type_Potion: - path += iter->get()->base->icon; - break; - case MWWorld::ContainerStore::Type_Apparatus: - path += iter->get()->base->icon; - break; - case MWWorld::ContainerStore::Type_Armor: - path += iter->get()->base->icon; - break; - case MWWorld::ContainerStore::Type_Book: - path += iter->get()->base->icon; - break; - case MWWorld::ContainerStore::Type_Clothing: - path += iter->get()->base->icon; - break; - case MWWorld::ContainerStore::Type_Ingredient: - path += iter->get()->base->icon; - break; - case MWWorld::ContainerStore::Type_Light: - path += iter->get()->base->icon; - break; - case MWWorld::ContainerStore::Type_Lockpick: - path += iter->get()->base->icon; - break; - case MWWorld::ContainerStore::Type_Miscellaneous: - path += iter->get()->base->icon; - break; - case MWWorld::ContainerStore::Type_Probe: - path += iter->get()->base->icon; - break; - case MWWorld::ContainerStore::Type_Repair: - path += iter->get()->base->icon; - break; - case MWWorld::ContainerStore::Type_Weapon: - path += iter->get()->base->icon; - break; - - - } + path+=MWWorld::Class::get(*iter).getInventoryIcon(*iter); count++; if(count % 8 == 0) diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index d49b98d0fb..2dd8aee1e0 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -173,4 +173,9 @@ namespace MWWorld { throw std::runtime_error ("class does not have an down sound"); } + + std::string Class::getInventoryIcon (const MWWorld::Ptr& ptr) const + { + throw std::runtime_error ("class does not have any inventory icon"); + } } diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index e474e9b926..eaa0d5f6f1 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -174,6 +174,9 @@ namespace MWWorld virtual std::string getDownSoundId (const Ptr& ptr, const MWWorld::Environment& environment) const; ///< Return the down sound ID of \a ptr or throw an exception, if class does not support ID retrieval /// (default implementation: throw an exception) + + virtual std::string getInventoryIcon (const MWWorld::Ptr& ptr) const; + ///< Return name of inventory icon. }; } diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index 3f1b7ea2cf..86ee15e587 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -456,34 +456,4 @@ bool MWWorld::operator== (const ContainerStoreIterator& left, const ContainerSto bool MWWorld::operator!= (const ContainerStoreIterator& left, const ContainerStoreIterator& right) { return !(left==right); -} - - -std::string MWWorld::ContainerStoreIterator::getInventoryIcon() -{ - Ptr ptr; - - switch (mType) - { - case ContainerStore::Type_Potion: ptr = MWWorld::Ptr (&*mPotion, 0); break; - case ContainerStore::Type_Apparatus: ptr = MWWorld::Ptr (&*mApparatus, 0); break; - case ContainerStore::Type_Armor: ptr = MWWorld::Ptr (&*mArmor, 0); break; - case ContainerStore::Type_Book: ptr = MWWorld::Ptr (&*mBook, 0); break; - case ContainerStore::Type_Clothing: ptr = MWWorld::Ptr (&*mClothing, 0); break; - case ContainerStore::Type_Ingredient: ptr = MWWorld::Ptr (&*mIngredient, 0); break; - case ContainerStore::Type_Light: ptr = MWWorld::Ptr (&*mLight, 0); break; - case ContainerStore::Type_Lockpick: ptr = MWWorld::Ptr (&*mLockpick, 0); break; - case ContainerStore::Type_Miscellaneous: ptr = MWWorld::Ptr (&*mMiscellaneous, 0); break; - case ContainerStore::Type_Probe: ptr = MWWorld::Ptr (&*mProbe, 0); break; - case ContainerStore::Type_Repair: ptr = MWWorld::Ptr (&*mRepair, 0); break; - case ContainerStore::Type_Weapon: ptr = MWWorld::Ptr (&*mWeapon, 0); break; - } - - if (ptr.isEmpty()) - throw std::runtime_error ("invalid iterator"); - - - std::string s = "";//ptr.getInventoryIcon(); - - return s; -} +} \ No newline at end of file diff --git a/apps/openmw/mwworld/containerstore.hpp b/apps/openmw/mwworld/containerstore.hpp index fc6283442e..da5424fe08 100644 --- a/apps/openmw/mwworld/containerstore.hpp +++ b/apps/openmw/mwworld/containerstore.hpp @@ -161,8 +161,6 @@ namespace MWWorld const ContainerStore *getContainerStore() const; - std::string getInventoryIcon(); - friend class ContainerStore; }; diff --git a/files/mygui/core.xml b/files/mygui/core.xml index 7417328cf1..8e256ca9c4 100644 --- a/files/mygui/core.xml +++ b/files/mygui/core.xml @@ -20,6 +20,7 @@ + From 489261a6ae514dafe2aea679bbca17c1c52cf46b Mon Sep 17 00:00:00 2001 From: gugus Date: Sun, 15 Apr 2012 21:02:54 +0200 Subject: [PATCH 012/325] Close button works. --- apps/openmw/mwgui/container.cpp | 10 +++++++++- apps/openmw/mwgui/container.hpp | 2 +- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 2defad2075..3f27351a98 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -29,11 +29,14 @@ ContainerWindow::ContainerWindow(WindowManager& parWindowManager,MWWorld::Enviro { setText("_Main", "Name of Container"); center(); + adjustWindowCaption(); getWidget(containerWidget, "Items"); getWidget(takeButton, "TakeButton"); getWidget(closeButton, "CloseButton"); + closeButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ContainerWindow::onByeClicked); + setText("CloseButton","Close"); setText("TakeButton","Take All"); } @@ -136,8 +139,13 @@ void ContainerWindow::open(MWWorld::Ptr& container) setVisible(true); } -void Update() +void ContainerWindow::Update() { } +void ContainerWindow::onByeClicked(MyGUI::Widget* _sender) +{ + mEnvironment.mWindowManager->setGuiMode(MWGui::GuiMode::GM_Game); +} + diff --git a/apps/openmw/mwgui/container.hpp b/apps/openmw/mwgui/container.hpp index e027f48fe7..76905a6814 100644 --- a/apps/openmw/mwgui/container.hpp +++ b/apps/openmw/mwgui/container.hpp @@ -53,7 +53,7 @@ namespace MWGui MyGUI::ButtonPtr closeButton; - + void onByeClicked(MyGUI::Widget* _sender); //MWWorld::Ptr& mContainer; From 705d4c6d54f94bad23fdf07efedc5842f73322de Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 15 Apr 2012 21:14:14 +0200 Subject: [PATCH 013/325] mostly complete --- apps/openmw/mwgui/stats_window.cpp | 16 +- apps/openmw/mwgui/stats_window.hpp | 2 +- apps/openmw/mwgui/tooltips.cpp | 720 ++++++++++++++------------- apps/openmw/mwgui/tooltips.hpp | 24 +- apps/openmw/mwgui/window_manager.cpp | 2 +- files/mygui/openmw_tooltips.xml | 2 +- 6 files changed, 406 insertions(+), 360 deletions(-) diff --git a/apps/openmw/mwgui/stats_window.cpp b/apps/openmw/mwgui/stats_window.cpp index 675e5141fa..23f93cd1b2 100644 --- a/apps/openmw/mwgui/stats_window.cpp +++ b/apps/openmw/mwgui/stats_window.cpp @@ -251,14 +251,18 @@ void StatsWindow::addGroup(const std::string &label, MyGUI::IntCoord &coord1, My coord2.top += lineHeight; } -MyGUI::TextBox* StatsWindow::addValueItem(const std::string text, const std::string &value, ColorStyle style, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) +MyGUI::TextBox* StatsWindow::addValueItem(const std::string text, const std::string& tooltip, const std::string &value, ColorStyle style, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) { MyGUI::TextBox *skillNameWidget, *skillValueWidget; skillNameWidget = skillClientWidget->createWidget("SandText", coord1, MyGUI::Align::Default); skillNameWidget->setCaption(text); + skillNameWidget->setUserString("ToolTipType", "Text"); + skillNameWidget->setUserString("ToolTipText", tooltip); skillValueWidget = skillClientWidget->createWidget("SandTextRight", coord2, MyGUI::Align::Default); + skillValueWidget->setUserString("ToolTipType", "Text"); + skillValueWidget->setUserString("ToolTipText", tooltip); setStyledText(skillValueWidget, style, value); skillWidgets.push_back(skillNameWidget); @@ -310,7 +314,7 @@ void StatsWindow::addSkills(const SkillList &skills, const std::string &titleId, style = CS_Super; else if (modified < base) style = CS_Sub; - MyGUI::TextBox* widget = addValueItem(mWindowManager.getGameSettingString(skillNameId, skillNameId), boost::lexical_cast(static_cast(modified)), style, coord1, coord2); + MyGUI::TextBox* widget = addValueItem(mWindowManager.getGameSettingString(skillNameId, skillNameId), "", boost::lexical_cast(static_cast(modified)), style, coord1, coord2); skillWidgetMap[skillId] = widget; } } @@ -369,8 +373,12 @@ void StatsWindow::updateSkillArea() if (!skillWidgets.empty()) addSeparator(coord1, coord2); - addValueItem(mWindowManager.getGameSettingString("sReputation", "Reputation"), boost::lexical_cast(static_cast(reputation)), CS_Normal, coord1, coord2); - addValueItem(mWindowManager.getGameSettingString("sBounty", "Bounty"), boost::lexical_cast(static_cast(bounty)), CS_Normal, coord1, coord2); + addValueItem(mWindowManager.getGameSettingString("sReputation", "Reputation"), + mWindowManager.getGameSettingString("sSkillsMenuReputationHelp", ""), + boost::lexical_cast(static_cast(reputation)), CS_Normal, coord1, coord2); + addValueItem(mWindowManager.getGameSettingString("sBounty", "Bounty"), + mWindowManager.getGameSettingString("sCrimeHelp", ""), + boost::lexical_cast(static_cast(bounty)), CS_Normal, coord1, coord2); clientHeight = coord1.top; updateScroller(); diff --git a/apps/openmw/mwgui/stats_window.hpp b/apps/openmw/mwgui/stats_window.hpp index f2731e545c..1ce3db98dc 100644 --- a/apps/openmw/mwgui/stats_window.hpp +++ b/apps/openmw/mwgui/stats_window.hpp @@ -53,7 +53,7 @@ namespace MWGui void addSkills(const SkillList &skills, const std::string &titleId, const std::string &titleDefault, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2); void addSeparator(MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2); void addGroup(const std::string &label, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2); - MyGUI::TextBox* addValueItem(const std::string text, const std::string &value, ColorStyle style, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2); + MyGUI::TextBox* addValueItem(const std::string text, const std::string& tooltip, const std::string &value, ColorStyle style, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2); void addItem(const std::string text, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2); void updateScroller(); diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 7f45bdbddc..4c435e3bf6 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -1,12 +1,15 @@ #include "tooltips.hpp" +#include "window_manager.hpp" + +#include using namespace MWGui; using namespace MyGUI; -ToolTips::ToolTips() : +ToolTips::ToolTips(WindowManager* windowManager) : Layout("openmw_tooltips.xml") , mGameMode(true) - , mFocusChanged(true) + , mWindowManager(windowManager) { getWidget(mTextToolTip, "TextToolTip"); getWidget(mTextToolTipBox, "TextToolTipBox"); @@ -31,19 +34,32 @@ void ToolTips::onFrame(float frameDuration) if (!mGameMode) { mDynamicToolTipBox->setVisible(false); + mTextToolTipBox->setVisible(true); Widget* focus = InputManager::getInstance().getMouseFocusWidget(); - if (focus == 0) return; + if (focus == 0) + { + mTextToolTipBox->setVisible(false); + return; + } + + std::string type = focus->getUserString("ToolTipType"); + std::string text = focus->getUserString("ToolTipText"); + if (type == "" || text == "") + { + mTextToolTipBox->setVisible(false); + return; + } // this the maximum width of the tooltip before it starts word-wrapping setCoord(0, 0, 300, 300); - mTextToolTip->setCaption("Focused: " + focus->getName() + "\nType: " + focus->getTypeName()); + mTextToolTip->setCaption(text); const IntSize &textSize = mTextToolTip->getTextSize(); IntPoint tooltipPosition = InputManager::getInstance().getMousePosition() + IntPoint(0, 24); - IntSize size = textSize + IntSize(12, 12); + IntSize size = textSize + IntSize(6, 6); // make the tooltip stay completely in the viewport if ((tooltipPosition.left + size.width) > viewSize.width) { @@ -62,351 +78,16 @@ void ToolTips::onFrame(float frameDuration) if (!mFocusObject.isEmpty()) { - if (mFocusChanged) - { - for (size_t i=0; igetChildCount(); ++i) - { - mDynamicToolTipBox->_destroyChildWidget(mDynamicToolTipBox->getChildAt(i)); - } + IntSize tooltipSize = getToolTipViaPtr(); - // this the maximum width of the tooltip before it starts word-wrapping - setCoord(0, 0, 300, 300); + tooltipSize += IntSize(6,6); // padding, adjust for skin - IntSize tooltipSize; - - /// \todo Not sure about levelled lists (ESM::CreateLevList and ESM::ItemLevList). I think - /// they are supposed to spawn a concrete object (Creature or item of any type), so - /// the player wouldn't encounter them and we don't have to handle them here. - - // -------------------- Door ------------------------------- - if (mFocusObject.getTypeName() == typeid(ESM::Door).name()) - { - ESMS::LiveCellRef* ref = mFocusObject.get(); - - EditBox* box = mDynamicToolTipBox->createWidget("MW_TextEdit", IntCoord(0, 0, 300, 300), Align::Stretch, "ToolTip"); - box->setTextAlign(Align::HCenter); - box->setProperty("Static", "true"); - box->setProperty("MultiLine", "true"); - - std::string caption = ref->base->name; - /// \todo If destCell is empty, the teleport target is an exterior cell. In that case we - /// need to fetch that cell (via target position) and retrieve the region name. - if (ref->ref.teleport && (ref->ref.destCell != "")) - { - caption += "\n-"; - caption += "\n"+ref->ref.destCell; - } - box->setCaption(caption); - - /// \todo Lock level, trap (retrieve GMST) - - tooltipSize = box->getTextSize() + IntSize(12,12); - - mDynamicToolTipBox->setVisible(true); - } - - // -------------------- NPC ------------------------------- - else if (mFocusObject.getTypeName() == typeid(ESM::NPC).name()) - { - /// \todo We don't want tooltips for NPCs in combat mode. - ESMS::LiveCellRef* ref = mFocusObject.get(); - - EditBox* box = mDynamicToolTipBox->createWidget("MW_TextEdit", IntCoord(0, 0, 300, 300), Align::Stretch, "ToolTip"); - box->setTextAlign(Align::HCenter); - box->setProperty("Static", "true"); - box->setCaption(ref->base->name); - - tooltipSize = box->getTextSize() + IntSize(12,12); - - mDynamicToolTipBox->setVisible(true); - } - - // -------------------- Creature ------------------------------- - else if (mFocusObject.getTypeName() == typeid(ESM::Creature).name()) - { - ESMS::LiveCellRef* ref = mFocusObject.get(); - - EditBox* box = mDynamicToolTipBox->createWidget("MW_TextEdit", IntCoord(0, 0, 300, 300), Align::Stretch, "ToolTip"); - box->setTextAlign(Align::HCenter); - box->setProperty("Static", "true"); - box->setCaption(ref->base->name); - - /// \todo - - tooltipSize = box->getTextSize() + IntSize(12,12); - - mDynamicToolTipBox->setVisible(true); - } - - // -------------------- CreatureLevList ------------------------------- - else if (mFocusObject.getTypeName() == typeid(ESM::Creature).name()) - { - ESMS::LiveCellRef* ref = mFocusObject.get(); - - EditBox* box = mDynamicToolTipBox->createWidget("MW_TextEdit", IntCoord(0, 0, 300, 300), Align::Stretch, "ToolTip"); - box->setTextAlign(Align::HCenter); - box->setProperty("Static", "true"); - box->setCaption(ref->base->name); - - /// \todo - - tooltipSize = box->getTextSize() + IntSize(12,12); - - mDynamicToolTipBox->setVisible(true); - } - - // -------------------- Container ------------------------------- - else if (mFocusObject.getTypeName() == typeid(ESM::Container).name()) - { - ESMS::LiveCellRef* ref = mFocusObject.get(); - - EditBox* box = mDynamicToolTipBox->createWidget("MW_TextEdit", IntCoord(0, 0, 300, 300), Align::Stretch, "ToolTip"); - box->setTextAlign(Align::HCenter); - box->setProperty("Static", "true"); - box->setCaption(ref->base->name); - - /// \todo Lock level, trap (retrieve GMST) - - tooltipSize = box->getTextSize() + IntSize(12,12); - - mDynamicToolTipBox->setVisible(true); - } - - // -------------------- Potion ------------------------------- - else if (mFocusObject.getTypeName() == typeid(ESM::Potion).name()) - { - ESMS::LiveCellRef* ref = mFocusObject.get(); - - EditBox* box = mDynamicToolTipBox->createWidget("MW_TextEdit", IntCoord(0, 0, 300, 300), Align::Stretch, "ToolTip"); - box->setTextAlign(Align::HCenter); - box->setProperty("Static", "true"); - box->setCaption(ref->base->name); - - /// \todo - - tooltipSize = box->getTextSize() + IntSize(12,12); - - mDynamicToolTipBox->setVisible(true); - } - - // -------------------- Apparatus ------------------------------- - else if (mFocusObject.getTypeName() == typeid(ESM::Apparatus).name()) - { - ESMS::LiveCellRef* ref = mFocusObject.get(); - - EditBox* box = mDynamicToolTipBox->createWidget("MW_TextEdit", IntCoord(0, 0, 300, 300), Align::Stretch, "ToolTip"); - box->setTextAlign(Align::HCenter); - box->setProperty("Static", "true"); - box->setCaption(ref->base->name); - - /// \todo - - tooltipSize = box->getTextSize() + IntSize(12,12); - - mDynamicToolTipBox->setVisible(true); - } - - // -------------------- Armor ------------------------------- - else if (mFocusObject.getTypeName() == typeid(ESM::Armor).name()) - { - ESMS::LiveCellRef* ref = mFocusObject.get(); - - EditBox* box = mDynamicToolTipBox->createWidget("MW_TextEdit", IntCoord(0, 0, 300, 300), Align::Stretch, "ToolTip"); - box->setTextAlign(Align::HCenter); - box->setProperty("Static", "true"); - box->setCaption(ref->base->name); - - /// \todo weight, armor value, value, durability.. - - tooltipSize = box->getTextSize() + IntSize(12,12); - - mDynamicToolTipBox->setVisible(true); - } - - // -------------------- Book ------------------------------- - else if (mFocusObject.getTypeName() == typeid(ESM::Book).name()) - { - ESMS::LiveCellRef* ref = mFocusObject.get(); - - EditBox* box = mDynamicToolTipBox->createWidget("MW_TextEdit", IntCoord(0, 0, 300, 300), Align::Stretch, "ToolTip"); - box->setTextAlign(Align::HCenter); - box->setProperty("Static", "true"); - box->setCaption(ref->base->name); - - /// \todo - - tooltipSize = box->getTextSize() + IntSize(12,12); - - mDynamicToolTipBox->setVisible(true); - } - - // -------------------- Clothing ------------------------------- - else if (mFocusObject.getTypeName() == typeid(ESM::Clothing).name()) - { - ESMS::LiveCellRef* ref = mFocusObject.get(); - - EditBox* box = mDynamicToolTipBox->createWidget("MW_TextEdit", IntCoord(0, 0, 300, 300), Align::Stretch, "ToolTip"); - box->setTextAlign(Align::HCenter); - box->setProperty("Static", "true"); - box->setCaption(ref->base->name); - - /// \todo - - tooltipSize = box->getTextSize() + IntSize(12,12); - - mDynamicToolTipBox->setVisible(true); - } - - // -------------------- Ingredient ------------------------------- - else if (mFocusObject.getTypeName() == typeid(ESM::Ingredient).name()) - { - ESMS::LiveCellRef* ref = mFocusObject.get(); - - EditBox* box = mDynamicToolTipBox->createWidget("MW_TextEdit", IntCoord(0, 0, 300, 300), Align::Stretch, "ToolTip"); - box->setTextAlign(Align::HCenter); - box->setProperty("Static", "true"); - box->setCaption(ref->base->name); - - /// \todo - - tooltipSize = box->getTextSize() + IntSize(12,12); - - mDynamicToolTipBox->setVisible(true); - } - - // -------------------- Light ------------------------------- - else if (mFocusObject.getTypeName() == typeid(ESM::Light).name()) - { - ESMS::LiveCellRef* ref = mFocusObject.get(); - - EditBox* box = mDynamicToolTipBox->createWidget("MW_TextEdit", IntCoord(0, 0, 300, 300), Align::Stretch, "ToolTip"); - box->setTextAlign(Align::HCenter); - box->setProperty("Static", "true"); - box->setCaption(ref->base->name); - - /// \todo - - tooltipSize = box->getTextSize() + IntSize(12,12); - - mDynamicToolTipBox->setVisible(ref->base->name != ""); - } - - // -------------------- Tool ------------------------------- - else if (mFocusObject.getTypeName() == typeid(ESM::Tool).name()) - { - ESMS::LiveCellRef* ref = mFocusObject.get(); - - EditBox* box = mDynamicToolTipBox->createWidget("MW_TextEdit", IntCoord(0, 0, 300, 300), Align::Stretch, "ToolTip"); - box->setTextAlign(Align::HCenter); - box->setProperty("Static", "true"); - box->setCaption(ref->base->name); - - /// \todo - - tooltipSize = box->getTextSize() + IntSize(12,12); - - mDynamicToolTipBox->setVisible(true); - } - - // -------------------- Miscellaneous ------------------------------- - else if (mFocusObject.getTypeName() == typeid(ESM::Miscellaneous).name()) - { - ESMS::LiveCellRef* ref = mFocusObject.get(); - - EditBox* box = mDynamicToolTipBox->createWidget("MW_TextEdit", IntCoord(0, 0, 300, 300), Align::Stretch, "ToolTip"); - box->setTextAlign(Align::HCenter); - box->setProperty("Static", "true"); - box->setCaption(ref->base->name); - - /// \todo - - tooltipSize = box->getTextSize() + IntSize(12,12); - - mDynamicToolTipBox->setVisible(true); - } - - // -------------------- Probe ------------------------------- - else if (mFocusObject.getTypeName() == typeid(ESM::Probe).name()) - { - ESMS::LiveCellRef* ref = mFocusObject.get(); - - EditBox* box = mDynamicToolTipBox->createWidget("MW_TextEdit", IntCoord(0, 0, 300, 300), Align::Stretch, "ToolTip"); - box->setTextAlign(Align::HCenter); - box->setProperty("Static", "true"); - box->setCaption(ref->base->name); - - /// \todo - - tooltipSize = box->getTextSize() + IntSize(12,12); - - mDynamicToolTipBox->setVisible(true); - } - - // -------------------- Repair ------------------------------- - else if (mFocusObject.getTypeName() == typeid(ESM::Repair).name()) - { - ESMS::LiveCellRef* ref = mFocusObject.get(); - - EditBox* box = mDynamicToolTipBox->createWidget("MW_TextEdit", IntCoord(0, 0, 300, 300), Align::Stretch, "ToolTip"); - box->setTextAlign(Align::HCenter); - box->setProperty("Static", "true"); - box->setCaption(ref->base->name); - - /// \todo - - tooltipSize = box->getTextSize() + IntSize(12,12); - - mDynamicToolTipBox->setVisible(true); - } - - // -------------------- Weapon ------------------------------- - else if (mFocusObject.getTypeName() == typeid(ESM::Weapon).name()) - { - ESMS::LiveCellRef* ref = mFocusObject.get(); - - EditBox* box = mDynamicToolTipBox->createWidget("MW_TextEdit", IntCoord(0, 0, 300, 300), Align::Stretch, "ToolTip"); - box->setTextAlign(Align::HCenter); - box->setProperty("Static", "true"); - box->setCaption(ref->base->name); - - /// \todo - - tooltipSize = box->getTextSize() + IntSize(12,12); - - mDynamicToolTipBox->setVisible(true); - } - - // -------------------- Activator ------------------------------- - else if (mFocusObject.getTypeName() == typeid(ESM::Activator).name()) - { - ESMS::LiveCellRef* ref = mFocusObject.get(); - - EditBox* box = mDynamicToolTipBox->createWidget("MW_TextEdit", IntCoord(0, 0, 300, 300), Align::Stretch, "ToolTip"); - box->setTextAlign(Align::HCenter); - box->setProperty("Static", "true"); - box->setCaption(ref->base->name); - - /// \todo - - tooltipSize = box->getTextSize() + IntSize(12,12); - - mDynamicToolTipBox->setVisible(ref->base->name != ""); - } - - else - { - // object without tooltip - mDynamicToolTipBox->setVisible(false); - } - - // adjust tooltip size to fit its content, position it above the crosshair - /// \todo Slide the tooltip along the bounding box of the focused object (like in Morrowind) - setCoord(viewSize.width/2 - (tooltipSize.width)/2.f, - viewSize.height/2 - (tooltipSize.height) - 32, - tooltipSize.width, - tooltipSize.height); - } - mFocusChanged = false; + // adjust tooltip size to fit its content, position it above the crosshair + /// \todo Slide the tooltip along the bounding box of the focused object (like in Morrowind) + setCoord(viewSize.width/2 - (tooltipSize.width)/2.f, + viewSize.height/2 - (tooltipSize.height) - 32, + tooltipSize.width, + tooltipSize.height); } else mDynamicToolTipBox->setVisible(false); @@ -425,9 +106,346 @@ void ToolTips::enterGuiMode() void ToolTips::setFocusObject(const MWWorld::Ptr& focus) { - if (focus != mFocusObject) + mFocusObject = focus; +} + +IntSize ToolTips::getToolTipViaPtr () +{ + /// \todo we are destroying/creating the tooltip widgets every frame here, + /// because the tooltip might change (e.g. when trap is activated) + /// is there maybe a better way (listener when the object changes)? + for (size_t i=0; igetChildCount(); ++i) { - mFocusObject = focus; - mFocusChanged = true; + mDynamicToolTipBox->_destroyChildWidget(mDynamicToolTipBox->getChildAt(i)); + } + + // this the maximum width of the tooltip before it starts word-wrapping + setCoord(0, 0, 300, 300); + + IntSize tooltipSize; + + // -------------------- Door ------------------------------- + if (mFocusObject.getTypeName() == typeid(ESM::Door).name()) + { + ESMS::LiveCellRef* ref = mFocusObject.get(); + + std::string text; + /// \todo If destCell is empty, the teleport target is an exterior cell. In that case we + /// need to fetch that cell (via target position) and retrieve the region name. + if (ref->ref.teleport && (ref->ref.destCell != "")) + { + text += "\n" + mWindowManager->getGameSettingString("sTo", "to"); + text += "\n"+ref->ref.destCell; + } + + if (ref->ref.lockLevel > 0) + text += "\n" + mWindowManager->getGameSettingString("sLockLevel", "Lock") + ": " + toString(ref->ref.lockLevel); + if (ref->ref.trap != "") + text += "\n" + mWindowManager->getGameSettingString("sTrapped", "Trapped!"); + + tooltipSize = createToolTip(ref->base->name, text); + } + + // -------------------- NPC ------------------------------- + else if (mFocusObject.getTypeName() == typeid(ESM::NPC).name()) + { + /// \todo We don't want tooltips for NPCs in combat mode. + ESMS::LiveCellRef* ref = mFocusObject.get(); + + tooltipSize = createToolTip(ref->base->name, ""); + } + + // -------------------- Creature ------------------------------- + else if (mFocusObject.getTypeName() == typeid(ESM::Creature).name()) + { + /// \todo We don't want tooltips for Creatures in combat mode. + ESMS::LiveCellRef* ref = mFocusObject.get(); + + tooltipSize = createToolTip(ref->base->name, ""); + } + + // -------------------- Container ------------------------------- + else if (mFocusObject.getTypeName() == typeid(ESM::Container).name()) + { + ESMS::LiveCellRef* ref = mFocusObject.get(); + + std::string text; + + if (ref->ref.lockLevel > 0) + text += "\n" + mWindowManager->getGameSettingString("sLockLevel", "Lock") + ": " + toString(ref->ref.lockLevel); + if (ref->ref.trap != "") + text += "\n" + mWindowManager->getGameSettingString("sTrapped", "Trapped!"); + + tooltipSize = createToolTip(ref->base->name, text); + } + + // -------------------- Potion ------------------------------- + else if (mFocusObject.getTypeName() == typeid(ESM::Potion).name()) + { + ESMS::LiveCellRef* ref = mFocusObject.get(); + + /// \todo magic effects + std::string text; + text += "\n" + mWindowManager->getGameSettingString("sWeight", "Weight") + ": " + toString(ref->base->data.weight); + text += getValueString(ref->base->data.value); + + tooltipSize = createImageToolTip(ref->base->name, ref->base->icon, text); + } + + // -------------------- Apparatus ------------------------------- + else if (mFocusObject.getTypeName() == typeid(ESM::Apparatus).name()) + { + ESMS::LiveCellRef* ref = mFocusObject.get(); + + std::string text; + text += "\n" + mWindowManager->getGameSettingString("sQuality", "Quality") + ": " + toString(ref->base->data.quality); + text += "\n" + mWindowManager->getGameSettingString("sWeight", "Weight") + ": " + toString(ref->base->data.weight); + text += getValueString(ref->base->data.value); + + tooltipSize = createImageToolTip(ref->base->name, ref->base->icon, text); + } + + // -------------------- Armor ------------------------------- + else if (mFocusObject.getTypeName() == typeid(ESM::Armor).name()) + { + ESMS::LiveCellRef* ref = mFocusObject.get(); + + /// \todo magic effects, armor type (medium/light/heavy) + std::string text; + text += "\n" + mWindowManager->getGameSettingString("sArmorRating", "Armor Rating") + ": " + toString(ref->base->data.armor); + + /// \todo where is the current armor health stored? + //text += "\n" + mWindowManager->getGameSettingString("sCondition", "Condition") + ": " + toString(ref->base->data.health); + text += "\n" + mWindowManager->getGameSettingString("sWeight", "Weight") + ": " + toString(ref->base->data.weight); + text += getValueString(ref->base->data.value); + + tooltipSize = createImageToolTip(ref->base->name, ref->base->icon, text); + } + + // -------------------- Book ------------------------------- + else if (mFocusObject.getTypeName() == typeid(ESM::Book).name()) + { + ESMS::LiveCellRef* ref = mFocusObject.get(); + + std::string text; + text += "\n" + mWindowManager->getGameSettingString("sWeight", "Weight") + ": " + toString(ref->base->data.weight); + text += getValueString(ref->base->data.value); + + tooltipSize = createImageToolTip(ref->base->name, ref->base->icon, text); + } + + // -------------------- Clothing ------------------------------- + else if (mFocusObject.getTypeName() == typeid(ESM::Clothing).name()) + { + ESMS::LiveCellRef* ref = mFocusObject.get(); + + /// \todo magic effects + std::string text; + text += "\n" + mWindowManager->getGameSettingString("sWeight", "Weight") + ": " + toString(ref->base->data.weight); + text += getValueString(ref->base->data.value); + + tooltipSize = createImageToolTip(ref->base->name, ref->base->icon, text); + } + + // -------------------- Ingredient ------------------------------- + else if (mFocusObject.getTypeName() == typeid(ESM::Ingredient).name()) + { + ESMS::LiveCellRef* ref = mFocusObject.get(); + + /// \todo magic effects + std::string text; + text += "\n" + mWindowManager->getGameSettingString("sWeight", "Weight") + ": " + toString(ref->base->data.weight); + text += getValueString(ref->base->data.value); + + tooltipSize = createImageToolTip(ref->base->name, ref->base->icon, text); + } + + // -------------------- Light ------------------------------- + else if (mFocusObject.getTypeName() == typeid(ESM::Light).name()) + { + ESMS::LiveCellRef* ref = mFocusObject.get(); + + std::string text; + text += "\n" + mWindowManager->getGameSettingString("sWeight", "Weight") + ": " + toString(ref->base->data.weight); + text += getValueString(ref->base->data.value); + + tooltipSize = createImageToolTip(ref->base->name, ref->base->icon, text); + } + + // -------------------- Tool ------------------------------- + else if (mFocusObject.getTypeName() == typeid(ESM::Tool).name()) + { + ESMS::LiveCellRef* ref = mFocusObject.get(); + + std::string text; + text += "\n" + mWindowManager->getGameSettingString("sUses", "Uses") + ": " + toString(ref->base->data.uses); + text += "\n" + mWindowManager->getGameSettingString("sQuality", "Quality") + ": " + toString(ref->base->data.quality); + text += "\n" + mWindowManager->getGameSettingString("sWeight", "Weight") + ": " + toString(ref->base->data.weight); + text += getValueString(ref->base->data.value); + + tooltipSize = createImageToolTip(ref->base->name, ref->base->icon, text); + } + + // -------------------- Miscellaneous ------------------------------- + else if (mFocusObject.getTypeName() == typeid(ESM::Miscellaneous).name()) + { + ESMS::LiveCellRef* ref = mFocusObject.get(); + + std::string text; + text += "\n" + mWindowManager->getGameSettingString("sWeight", "Weight") + ": " + toString(ref->base->data.weight); + text += getValueString(ref->base->data.value); + + tooltipSize = createImageToolTip(ref->base->name, ref->base->icon, text); + } + + // -------------------- Probe ------------------------------- + else if (mFocusObject.getTypeName() == typeid(ESM::Probe).name()) + { + ESMS::LiveCellRef* ref = mFocusObject.get(); + + std::string text; + text += "\n" + mWindowManager->getGameSettingString("sUses", "Uses") + ": " + toString(ref->base->data.uses); + text += "\n" + mWindowManager->getGameSettingString("sQuality", "Quality") + ": " + toString(ref->base->data.quality); + text += "\n" + mWindowManager->getGameSettingString("sWeight", "Weight") + ": " + toString(ref->base->data.weight); + text += getValueString(ref->base->data.value); + + tooltipSize = createImageToolTip(ref->base->name, ref->base->icon, text); + } + + // -------------------- Repair ------------------------------- + else if (mFocusObject.getTypeName() == typeid(ESM::Repair).name()) + { + ESMS::LiveCellRef* ref = mFocusObject.get(); + + std::string text; + text += "\n" + mWindowManager->getGameSettingString("sUses", "Uses") + ": " + toString(ref->base->data.uses); + text += "\n" + mWindowManager->getGameSettingString("sQuality", "Quality") + ": " + toString(ref->base->data.quality); + text += "\n" + mWindowManager->getGameSettingString("sWeight", "Weight") + ": " + toString(ref->base->data.weight); + text += getValueString(ref->base->data.value); + + tooltipSize = createImageToolTip(ref->base->name, ref->base->icon, text); + } + + // -------------------- Weapon ------------------------------- + else if (mFocusObject.getTypeName() == typeid(ESM::Weapon).name()) + { + ESMS::LiveCellRef* ref = mFocusObject.get(); + + /// \todo weapon damage, magic effects, health (condition) + + std::string text; + text += "\n" + mWindowManager->getGameSettingString("sWeight", "Weight") + ": " + toString(ref->base->data.weight); + text += getValueString(ref->base->data.value); + + tooltipSize = createImageToolTip(ref->base->name, ref->base->icon, ""); + } + + // -------------------- Activator ------------------------------- + else if (mFocusObject.getTypeName() == typeid(ESM::Activator).name()) + { + ESMS::LiveCellRef* ref = mFocusObject.get(); + + tooltipSize = createToolTip(ref->base->name, ""); + } + + else + { + // object without tooltip + mDynamicToolTipBox->setVisible(false); + } + + return tooltipSize; +} + +void ToolTips::findImageExtension(std::string& image) +{ + int len = image.size(); + if (len < 4) return; + + if (!Ogre::ResourceGroupManager::getSingleton().resourceExists(Ogre::ResourceGroupManager::AUTODETECT_RESOURCE_GROUP_NAME, image)) + { + // Change texture extension to .dds + image[len-3] = 'd'; + image[len-2] = 'd'; + image[len-1] = 's'; } } + +IntSize ToolTips::createImageToolTip(const std::string& caption, const std::string& image, const std::string& text) +{ + // remove the first newline (easier this way) + std::string realText = text; + if (realText.size() > 0) + realText.erase(0, 1); + + std::string realImage = "icons\\" + image; + findImageExtension(realImage); + + const int imageSize = 32; + + EditBox* captionWidget = mDynamicToolTipBox->createWidget("NormalText", IntCoord(0, 0, 300, 300), Align::Left | Align::Top, "ToolTipCaption"); + captionWidget->setProperty("Static", "true"); + captionWidget->setCaption(caption); + EditBox* textWidget = mDynamicToolTipBox->createWidget("SandText", IntCoord(0, imageSize, 300, 262), Align::Stretch, "ToolTipText"); + textWidget->setProperty("Static", "true"); + textWidget->setProperty("MultiLine", "true"); + textWidget->setCaption(realText); + textWidget->setTextAlign(Align::HCenter); + + IntSize captionSize = captionWidget->getTextSize(); + IntSize textSize = textWidget->getTextSize(); + + captionSize += IntSize(imageSize, 0); // adjust for image + IntSize totalSize = IntSize( std::max(textSize.width, captionSize.width), ((realText != "") ? textSize.height : 0) + imageSize ); + + ImageBox* imageWidget = mDynamicToolTipBox->createWidget("ImageBox", + IntCoord((totalSize.width - captionSize.width)/2, 0, imageSize, imageSize), + Align::Left | Align::Top, "ToolTipImage"); + imageWidget->setImageTexture(realImage); + + captionWidget->setCoord( (totalSize.width - captionSize.width)/2 + imageSize, (32-captionSize.height)/2, captionSize.width-imageSize, captionSize.height); + + mDynamicToolTipBox->setVisible(caption != ""); + + return totalSize; +} + +IntSize ToolTips::createToolTip(const std::string& caption, const std::string& text) +{ + // remove the first newline (easier this way) + std::string realText = text; + if (realText.size() > 0) + realText.erase(0, 1); + + EditBox* box = mDynamicToolTipBox->createWidget("NormalText", IntCoord(0, 0, 300, 300), Align::Stretch, "ToolTip"); + box->setTextAlign(Align::HCenter); + box->setProperty("Static", "true"); + box->setProperty("MultiLine", "true"); + box->setCaption(caption + (realText != "" ? "\n#BF9959" + realText : "")); + + mDynamicToolTipBox->setVisible(caption != ""); + + return box->getTextSize(); +} + +std::string ToolTips::toString(const float value) +{ + std::ostringstream stream; + stream << std::setprecision(3) << value; + return stream.str(); +} + +std::string ToolTips::toString(const int value) +{ + std::ostringstream stream; + stream << value; + return stream.str(); +} + +std::string ToolTips::getValueString(const int value) +{ + if (value == 0) + return ""; + else + return "\n" + mWindowManager->getGameSettingString("sValue", "Value") + ": " + toString(value); +} diff --git a/apps/openmw/mwgui/tooltips.hpp b/apps/openmw/mwgui/tooltips.hpp index 3052abb7a4..cb1af73499 100644 --- a/apps/openmw/mwgui/tooltips.hpp +++ b/apps/openmw/mwgui/tooltips.hpp @@ -7,10 +7,12 @@ namespace MWGui { + class WindowManager; + class ToolTips : public OEngine::GUI::Layout { public: - ToolTips(); + ToolTips(WindowManager* windowManager); void onFrame(float frameDuration); @@ -27,8 +29,26 @@ namespace MWGui MyGUI::Widget* mDynamicToolTipBox; + WindowManager* mWindowManager; + MWWorld::Ptr mFocusObject; - bool mFocusChanged; + + void findImageExtension(std::string& image); + + MyGUI::IntSize getToolTipViaPtr (); + ///< @return requested tooltip size + + MyGUI::IntSize createImageToolTip(const std::string& caption, const std::string& image, const std::string& text); + ///< @return requested tooltip size + + MyGUI::IntSize createToolTip(const std::string& caption, const std::string& text); + ///< @return requested tooltip size + + std::string getValueString(const int value); + ///< get "Value: X" string or "" if value is 0 + + std::string toString(const float value); + std::string toString(const int value); bool mGameMode; }; diff --git a/apps/openmw/mwgui/window_manager.cpp b/apps/openmw/mwgui/window_manager.cpp index 909be0ac2f..8ed2050cc0 100644 --- a/apps/openmw/mwgui/window_manager.cpp +++ b/apps/openmw/mwgui/window_manager.cpp @@ -82,7 +82,7 @@ WindowManager::WindowManager(MWWorld::Environment& environment, mJournal = new JournalWindow(*this); mMessageBoxManager = new MessageBoxManager(this); dialogueWindow = new DialogueWindow(*this,environment); - mToolTips = new ToolTips(); + mToolTips = new ToolTips(this); // The HUD is always on hud->setVisible(true); diff --git a/files/mygui/openmw_tooltips.xml b/files/mygui/openmw_tooltips.xml index 26fc1eeab5..1d55bd12f1 100644 --- a/files/mygui/openmw_tooltips.xml +++ b/files/mygui/openmw_tooltips.xml @@ -6,7 +6,7 @@ - + From 5d9648d6457b5b3e812fbfadb4c4a24a093a6f9c Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 15 Apr 2012 22:00:28 +0200 Subject: [PATCH 014/325] fix const reference --- apps/openmw/mwgui/stats_window.cpp | 2 +- apps/openmw/mwgui/stats_window.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/stats_window.cpp b/apps/openmw/mwgui/stats_window.cpp index 23f93cd1b2..3746728833 100644 --- a/apps/openmw/mwgui/stats_window.cpp +++ b/apps/openmw/mwgui/stats_window.cpp @@ -251,7 +251,7 @@ void StatsWindow::addGroup(const std::string &label, MyGUI::IntCoord &coord1, My coord2.top += lineHeight; } -MyGUI::TextBox* StatsWindow::addValueItem(const std::string text, const std::string& tooltip, const std::string &value, ColorStyle style, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) +MyGUI::TextBox* StatsWindow::addValueItem(const std::string& text, const std::string& tooltip, const std::string &value, ColorStyle style, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) { MyGUI::TextBox *skillNameWidget, *skillValueWidget; diff --git a/apps/openmw/mwgui/stats_window.hpp b/apps/openmw/mwgui/stats_window.hpp index 1ce3db98dc..66655a055f 100644 --- a/apps/openmw/mwgui/stats_window.hpp +++ b/apps/openmw/mwgui/stats_window.hpp @@ -53,7 +53,7 @@ namespace MWGui void addSkills(const SkillList &skills, const std::string &titleId, const std::string &titleDefault, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2); void addSeparator(MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2); void addGroup(const std::string &label, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2); - MyGUI::TextBox* addValueItem(const std::string text, const std::string& tooltip, const std::string &value, ColorStyle style, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2); + MyGUI::TextBox* addValueItem(const std::string& text, const std::string& tooltip, const std::string &value, ColorStyle style, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2); void addItem(const std::string text, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2); void updateScroller(); From 194ecf274c09140ffd0afa73b9ac359efc0ef15c Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 16 Apr 2012 00:16:35 +0200 Subject: [PATCH 015/325] attribute tooltips --- apps/openmw/mwgui/stats_window.cpp | 97 ++++++++++++++++++++++++++++++ apps/openmw/mwgui/stats_window.hpp | 2 + apps/openmw/mwgui/tooltips.cpp | 83 +++++++++++++++---------- apps/openmw/mwgui/tooltips.hpp | 8 +-- files/mygui/openmw_tooltips.xml | 10 --- 5 files changed, 153 insertions(+), 47 deletions(-) diff --git a/apps/openmw/mwgui/stats_window.cpp b/apps/openmw/mwgui/stats_window.cpp index 3746728833..cf279faf7f 100644 --- a/apps/openmw/mwgui/stats_window.cpp +++ b/apps/openmw/mwgui/stats_window.cpp @@ -72,6 +72,8 @@ StatsWindow::StatsWindow (WindowManager& parWindowManager) MyGUI::WindowPtr t = static_cast(mMainWidget); t->eventWindowChangeCoord += MyGUI::newDelegate(this, &StatsWindow::onWindowResize); + + setupToolTips(); } void StatsWindow::onScrollChangePosition(MyGUI::ScrollBar* scroller, size_t pos) @@ -394,3 +396,98 @@ void StatsWindow::onPinToggled() { mWindowManager.setHMSVisibility(!mPinned); } + +void StatsWindow::setupToolTips() +{ + + const ESMS::ESMStore &store = mWindowManager.getStore(); + MyGUI::Widget* widget; + + getWidget(widget, "Attrib1"); + widget->setUserString("ToolTipType", "ImageCaptionText"); + widget->setUserString("ToolTipCaption", store.gameSettings.find ("sAttributeStrength")->str); + widget->setUserString("ToolTipText", store.gameSettings.find ("sStrDesc")->str); + widget->setUserString("ToolTipImage", "k\\attribute_strength.dds"); + getWidget(widget, "AttribVal1"); + widget->setUserString("ToolTipType", "ImageCaptionText"); + widget->setUserString("ToolTipCaption", store.gameSettings.find ("sAttributeStrength")->str); + widget->setUserString("ToolTipText", store.gameSettings.find ("sStrDesc")->str); + widget->setUserString("ToolTipImage", "k\\attribute_strength.dds"); + + getWidget(widget, "Attrib2"); + widget->setUserString("ToolTipType", "ImageCaptionText"); + widget->setUserString("ToolTipCaption", store.gameSettings.find ("sAttributeIntelligence")->str); + widget->setUserString("ToolTipText", store.gameSettings.find ("sIntDesc")->str); + widget->setUserString("ToolTipImage", "k\\attribute_int.dds"); + getWidget(widget, "AttribVal2"); + widget->setUserString("ToolTipType", "ImageCaptionText"); + widget->setUserString("ToolTipCaption", store.gameSettings.find ("sAttributeIntelligence")->str); + widget->setUserString("ToolTipText", store.gameSettings.find ("sIntDesc")->str); + widget->setUserString("ToolTipImage", "k\\attribute_int.dds"); + + getWidget(widget, "Attrib3"); + widget->setUserString("ToolTipType", "ImageCaptionText"); + widget->setUserString("ToolTipCaption", store.gameSettings.find ("sAttributeWillpower")->str); + widget->setUserString("ToolTipText", store.gameSettings.find ("sWilDesc")->str); + widget->setUserString("ToolTipImage", "k\\attribute_wilpower.dds"); + getWidget(widget, "AttribVal3"); + widget->setUserString("ToolTipType", "ImageCaptionText"); + widget->setUserString("ToolTipCaption", store.gameSettings.find ("sAttributeWillpower")->str); + widget->setUserString("ToolTipText", store.gameSettings.find ("sWilDesc")->str); + widget->setUserString("ToolTipImage", "k\\attribute_wilpower.dds"); + + getWidget(widget, "Attrib4"); + widget->setUserString("ToolTipType", "ImageCaptionText"); + widget->setUserString("ToolTipCaption", store.gameSettings.find ("sAttributeAgility")->str); + widget->setUserString("ToolTipText", store.gameSettings.find ("sAgiDesc")->str); + widget->setUserString("ToolTipImage", "k\\attribute_agility.dds"); + getWidget(widget, "AttribVal4"); + widget->setUserString("ToolTipType", "ImageCaptionText"); + widget->setUserString("ToolTipCaption", store.gameSettings.find ("sAttributeAgility")->str); + widget->setUserString("ToolTipText", store.gameSettings.find ("sAgiDesc")->str); + widget->setUserString("ToolTipImage", "k\\attribute_agility.dds"); + + getWidget(widget, "Attrib5"); + widget->setUserString("ToolTipType", "ImageCaptionText"); + widget->setUserString("ToolTipCaption", store.gameSettings.find ("sAttributeSpeed")->str); + widget->setUserString("ToolTipText", store.gameSettings.find ("sSpdDesc")->str); + widget->setUserString("ToolTipImage", "k\\attribute_speed.dds"); + getWidget(widget, "AttribVal5"); + widget->setUserString("ToolTipType", "ImageCaptionText"); + widget->setUserString("ToolTipCaption", store.gameSettings.find ("sAttributeSpeed")->str); + widget->setUserString("ToolTipText", store.gameSettings.find ("sSpdDesc")->str); + widget->setUserString("ToolTipImage", "k\\attribute_speed.dds"); + + getWidget(widget, "Attrib6"); + widget->setUserString("ToolTipType", "ImageCaptionText"); + widget->setUserString("ToolTipCaption", store.gameSettings.find ("sAttributeEndurance")->str); + widget->setUserString("ToolTipText", store.gameSettings.find ("sEndDesc")->str); + widget->setUserString("ToolTipImage", "k\\attribute_endurance.dds"); + getWidget(widget, "AttribVal6"); + widget->setUserString("ToolTipType", "ImageCaptionText"); + widget->setUserString("ToolTipCaption", store.gameSettings.find ("sAttributeEndurance")->str); + widget->setUserString("ToolTipText", store.gameSettings.find ("sEndDesc")->str); + widget->setUserString("ToolTipImage", "k\\attribute_endurance.dds"); + + getWidget(widget, "Attrib7"); + widget->setUserString("ToolTipType", "ImageCaptionText"); + widget->setUserString("ToolTipCaption", store.gameSettings.find ("sAttributePersonality")->str); + widget->setUserString("ToolTipText", store.gameSettings.find ("sPerDesc")->str); + widget->setUserString("ToolTipImage", "k\\attribute_personality.dds"); + getWidget(widget, "AttribVal7"); + widget->setUserString("ToolTipType", "ImageCaptionText"); + widget->setUserString("ToolTipCaption", store.gameSettings.find ("sAttributePersonality")->str); + widget->setUserString("ToolTipText", store.gameSettings.find ("sPerDesc")->str); + widget->setUserString("ToolTipImage", "k\\attribute_personality.dds"); + + getWidget(widget, "Attrib8"); + widget->setUserString("ToolTipType", "ImageCaptionText"); + widget->setUserString("ToolTipCaption", store.gameSettings.find ("sAttributeLuck")->str); + widget->setUserString("ToolTipText", store.gameSettings.find ("sLucDesc")->str); + widget->setUserString("ToolTipImage", "k\\attribute_luck.dds"); + getWidget(widget, "AttribVal8"); + widget->setUserString("ToolTipType", "ImageCaptionText"); + widget->setUserString("ToolTipCaption", store.gameSettings.find ("sAttributeLuck")->str); + widget->setUserString("ToolTipText", store.gameSettings.find ("sLucDesc")->str); + widget->setUserString("ToolTipImage", "k\\attribute_luck.dds"); +} diff --git a/apps/openmw/mwgui/stats_window.hpp b/apps/openmw/mwgui/stats_window.hpp index 66655a055f..075c08dd32 100644 --- a/apps/openmw/mwgui/stats_window.hpp +++ b/apps/openmw/mwgui/stats_window.hpp @@ -57,6 +57,8 @@ namespace MWGui void addItem(const std::string text, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2); void updateScroller(); + void setupToolTips(); + void onScrollChangePosition(MyGUI::ScrollBar* scroller, size_t pos); void onWindowResize(MyGUI::Window* window); diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 4c435e3bf6..4dcb1cda78 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -11,8 +11,6 @@ ToolTips::ToolTips(WindowManager* windowManager) : , mGameMode(true) , mWindowManager(windowManager) { - getWidget(mTextToolTip, "TextToolTip"); - getWidget(mTextToolTipBox, "TextToolTipBox"); getWidget(mDynamicToolTipBox, "DynamicToolTipBox"); mDynamicToolTipBox->setVisible(false); @@ -20,8 +18,6 @@ ToolTips::ToolTips(WindowManager* windowManager) : // turn off mouse focus so that getMouseFocusWidget returns the correct widget, // even if the mouse is over the tooltip mDynamicToolTipBox->setNeedMouseFocus(false); - mTextToolTipBox->setNeedMouseFocus(false); - mTextToolTip->setNeedMouseFocus(false); mMainWidget->setNeedMouseFocus(false); } @@ -29,37 +25,54 @@ void ToolTips::onFrame(float frameDuration) { /// \todo Store a MWWorld::Ptr in the widget user data, retrieve it here and construct a tooltip dynamically + /// \todo we are destroying/creating the tooltip widgets every frame here, + /// because the tooltip might change (e.g. when trap is activated) + /// is there maybe a better way (listener when the object changes)? + for (size_t i=0; igetChildCount(); ++i) + { + mDynamicToolTipBox->_destroyChildWidget(mDynamicToolTipBox->getChildAt(i)); + } + const IntSize &viewSize = RenderManager::getInstance().getViewSize(); if (!mGameMode) { - mDynamicToolTipBox->setVisible(false); - mTextToolTipBox->setVisible(true); - Widget* focus = InputManager::getInstance().getMouseFocusWidget(); if (focus == 0) { - mTextToolTipBox->setVisible(false); - return; - } - - std::string type = focus->getUserString("ToolTipType"); - std::string text = focus->getUserString("ToolTipText"); - if (type == "" || text == "") - { - mTextToolTipBox->setVisible(false); + mDynamicToolTipBox->setVisible(false); return; } // this the maximum width of the tooltip before it starts word-wrapping setCoord(0, 0, 300, 300); - mTextToolTip->setCaption(text); - const IntSize &textSize = mTextToolTip->getTextSize(); + IntSize tooltipSize; + + std::string type = focus->getUserString("ToolTipType"); + std::string text = focus->getUserString("ToolTipText"); + if (type == "") + { + mDynamicToolTipBox->setVisible(false); + return; + } + else if (type == "Text") + tooltipSize = createToolTip(text); + else if (type == "CaptionText") + { + std::string caption = focus->getUserString("ToolTipCaption"); + tooltipSize = createToolTip(caption, text); + } + else if (type == "ImageCaptionText") + { + std::string caption = focus->getUserString("ToolTipCaption"); + std::string image = focus->getUserString("ToolTipImage"); + tooltipSize = createImageToolTip(caption, image, text); + } IntPoint tooltipPosition = InputManager::getInstance().getMousePosition() + IntPoint(0, 24); - IntSize size = textSize + IntSize(6, 6); + IntSize size = tooltipSize + IntSize(6, 6); // make the tooltip stay completely in the viewport if ((tooltipPosition.left + size.width) > viewSize.width) { @@ -74,8 +87,6 @@ void ToolTips::onFrame(float frameDuration) } else { - mTextToolTipBox->setVisible(false); - if (!mFocusObject.isEmpty()) { IntSize tooltipSize = getToolTipViaPtr(); @@ -111,14 +122,6 @@ void ToolTips::setFocusObject(const MWWorld::Ptr& focus) IntSize ToolTips::getToolTipViaPtr () { - /// \todo we are destroying/creating the tooltip widgets every frame here, - /// because the tooltip might change (e.g. when trap is activated) - /// is there maybe a better way (listener when the object changes)? - for (size_t i=0; igetChildCount(); ++i) - { - mDynamicToolTipBox->_destroyChildWidget(mDynamicToolTipBox->getChildAt(i)); - } - // this the maximum width of the tooltip before it starts word-wrapping setCoord(0, 0, 300, 300); @@ -337,7 +340,7 @@ IntSize ToolTips::getToolTipViaPtr () text += "\n" + mWindowManager->getGameSettingString("sWeight", "Weight") + ": " + toString(ref->base->data.weight); text += getValueString(ref->base->data.value); - tooltipSize = createImageToolTip(ref->base->name, ref->base->icon, ""); + tooltipSize = createImageToolTip(ref->base->name, ref->base->icon, text); } // -------------------- Activator ------------------------------- @@ -375,7 +378,7 @@ IntSize ToolTips::createImageToolTip(const std::string& caption, const std::stri { // remove the first newline (easier this way) std::string realText = text; - if (realText.size() > 0) + if (realText.size() > 0 && realText[0] == '\n') realText.erase(0, 1); std::string realImage = "icons\\" + image; @@ -389,6 +392,7 @@ IntSize ToolTips::createImageToolTip(const std::string& caption, const std::stri EditBox* textWidget = mDynamicToolTipBox->createWidget("SandText", IntCoord(0, imageSize, 300, 262), Align::Stretch, "ToolTipText"); textWidget->setProperty("Static", "true"); textWidget->setProperty("MultiLine", "true"); + textWidget->setProperty("WordWrap", "true"); textWidget->setCaption(realText); textWidget->setTextAlign(Align::HCenter); @@ -414,13 +418,14 @@ IntSize ToolTips::createToolTip(const std::string& caption, const std::string& t { // remove the first newline (easier this way) std::string realText = text; - if (realText.size() > 0) + if (realText.size() > 0 && realText[0] == '\n') realText.erase(0, 1); EditBox* box = mDynamicToolTipBox->createWidget("NormalText", IntCoord(0, 0, 300, 300), Align::Stretch, "ToolTip"); box->setTextAlign(Align::HCenter); box->setProperty("Static", "true"); box->setProperty("MultiLine", "true"); + box->setProperty("WordWrap", "true"); box->setCaption(caption + (realText != "" ? "\n#BF9959" + realText : "")); mDynamicToolTipBox->setVisible(caption != ""); @@ -428,6 +433,20 @@ IntSize ToolTips::createToolTip(const std::string& caption, const std::string& t return box->getTextSize(); } +IntSize ToolTips::createToolTip(const std::string& text) +{ + EditBox* box = mDynamicToolTipBox->createWidget("SandText", IntCoord(0, 0, 300, 300), Align::Stretch, "ToolTip"); + box->setTextAlign(Align::HCenter); + box->setProperty("Static", "true"); + box->setProperty("MultiLine", "true"); + box->setProperty("WordWrap", "true"); + box->setCaption(text); + + mDynamicToolTipBox->setVisible(text != ""); + + return box->getTextSize(); +} + std::string ToolTips::toString(const float value) { std::ostringstream stream; diff --git a/apps/openmw/mwgui/tooltips.hpp b/apps/openmw/mwgui/tooltips.hpp index cb1af73499..7a2dded114 100644 --- a/apps/openmw/mwgui/tooltips.hpp +++ b/apps/openmw/mwgui/tooltips.hpp @@ -21,12 +21,7 @@ namespace MWGui void setFocusObject(const MWWorld::Ptr& focus); - void adjustScreen(int screenWidth, int screenHeight); - private: - MyGUI::EditBox* mTextToolTip; - MyGUI::Widget* mTextToolTipBox; - MyGUI::Widget* mDynamicToolTipBox; WindowManager* mWindowManager; @@ -44,6 +39,9 @@ namespace MWGui MyGUI::IntSize createToolTip(const std::string& caption, const std::string& text); ///< @return requested tooltip size + MyGUI::IntSize createToolTip(const std::string& text); + ///< @return requested tooltip size + std::string getValueString(const int value); ///< get "Value: X" string or "" if value is 0 diff --git a/files/mygui/openmw_tooltips.xml b/files/mygui/openmw_tooltips.xml index 1d55bd12f1..2d5a5da9f2 100644 --- a/files/mygui/openmw_tooltips.xml +++ b/files/mygui/openmw_tooltips.xml @@ -3,16 +3,6 @@ - - - - - - - - - - From f5ab127a39dd06a3b94ae5a9b839f255069f1b0c Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 16 Apr 2012 15:00:44 +0200 Subject: [PATCH 016/325] toggleFullHelp --- apps/openmw/mwgui/tooltips.cpp | 114 ++++++++++++++++++++----- apps/openmw/mwgui/tooltips.hpp | 6 +- apps/openmw/mwgui/window_manager.cpp | 5 ++ apps/openmw/mwgui/window_manager.hpp | 1 + apps/openmw/mwscript/docs/vmformat.txt | 3 +- apps/openmw/mwscript/guiextensions.cpp | 21 ++++- 6 files changed, 128 insertions(+), 22 deletions(-) diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 4dcb1cda78..25361ffcc6 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -10,6 +10,7 @@ ToolTips::ToolTips(WindowManager* windowManager) : Layout("openmw_tooltips.xml") , mGameMode(true) , mWindowManager(windowManager) + , mFullHelp(false) { getWidget(mDynamicToolTipBox, "DynamicToolTipBox"); @@ -67,7 +68,9 @@ void ToolTips::onFrame(float frameDuration) { std::string caption = focus->getUserString("ToolTipCaption"); std::string image = focus->getUserString("ToolTipImage"); - tooltipSize = createImageToolTip(caption, image, text); + std::string sizeString = focus->getUserString("ToolTipImageSize"); + int size = (sizeString != "" ? boost::lexical_cast(sizeString) : 32); + tooltipSize = createImageToolTip(caption, image, size, text); } IntPoint tooltipPosition = InputManager::getInstance().getMousePosition() + IntPoint(0, 24); @@ -179,6 +182,11 @@ IntSize ToolTips::getToolTipViaPtr () if (ref->ref.trap != "") text += "\n" + mWindowManager->getGameSettingString("sTrapped", "Trapped!"); + if (mFullHelp) { + text += "\n Owner: " + ref->ref.owner; + text += "\n Script: " + ref->base->script; + } + tooltipSize = createToolTip(ref->base->name, text); } @@ -192,7 +200,12 @@ IntSize ToolTips::getToolTipViaPtr () text += "\n" + mWindowManager->getGameSettingString("sWeight", "Weight") + ": " + toString(ref->base->data.weight); text += getValueString(ref->base->data.value); - tooltipSize = createImageToolTip(ref->base->name, ref->base->icon, text); + if (mFullHelp) { + text += "\n Owner: " + ref->ref.owner; + text += "\n Script: " + ref->base->script; + } + + tooltipSize = createImageToolTip(ref->base->name, ref->base->icon, 32, text); } // -------------------- Apparatus ------------------------------- @@ -205,7 +218,12 @@ IntSize ToolTips::getToolTipViaPtr () text += "\n" + mWindowManager->getGameSettingString("sWeight", "Weight") + ": " + toString(ref->base->data.weight); text += getValueString(ref->base->data.value); - tooltipSize = createImageToolTip(ref->base->name, ref->base->icon, text); + if (mFullHelp) { + text += "\n Owner: " + ref->ref.owner; + text += "\n Script: " + ref->base->script; + } + + tooltipSize = createImageToolTip(ref->base->name, ref->base->icon, 32, text); } // -------------------- Armor ------------------------------- @@ -222,7 +240,12 @@ IntSize ToolTips::getToolTipViaPtr () text += "\n" + mWindowManager->getGameSettingString("sWeight", "Weight") + ": " + toString(ref->base->data.weight); text += getValueString(ref->base->data.value); - tooltipSize = createImageToolTip(ref->base->name, ref->base->icon, text); + if (mFullHelp) { + text += "\n Owner: " + ref->ref.owner; + text += "\n Script: " + ref->base->script; + } + + tooltipSize = createImageToolTip(ref->base->name, ref->base->icon, 32, text); } // -------------------- Book ------------------------------- @@ -234,7 +257,12 @@ IntSize ToolTips::getToolTipViaPtr () text += "\n" + mWindowManager->getGameSettingString("sWeight", "Weight") + ": " + toString(ref->base->data.weight); text += getValueString(ref->base->data.value); - tooltipSize = createImageToolTip(ref->base->name, ref->base->icon, text); + if (mFullHelp) { + text += "\n Owner: " + ref->ref.owner; + text += "\n Script: " + ref->base->script; + } + + tooltipSize = createImageToolTip(ref->base->name, ref->base->icon, 32, text); } // -------------------- Clothing ------------------------------- @@ -247,7 +275,12 @@ IntSize ToolTips::getToolTipViaPtr () text += "\n" + mWindowManager->getGameSettingString("sWeight", "Weight") + ": " + toString(ref->base->data.weight); text += getValueString(ref->base->data.value); - tooltipSize = createImageToolTip(ref->base->name, ref->base->icon, text); + if (mFullHelp) { + text += "\n Owner: " + ref->ref.owner; + text += "\n Script: " + ref->base->script; + } + + tooltipSize = createImageToolTip(ref->base->name, ref->base->icon, 32, text); } // -------------------- Ingredient ------------------------------- @@ -260,7 +293,12 @@ IntSize ToolTips::getToolTipViaPtr () text += "\n" + mWindowManager->getGameSettingString("sWeight", "Weight") + ": " + toString(ref->base->data.weight); text += getValueString(ref->base->data.value); - tooltipSize = createImageToolTip(ref->base->name, ref->base->icon, text); + if (mFullHelp) { + text += "\n Owner: " + ref->ref.owner; + text += "\n Script: " + ref->base->script; + } + + tooltipSize = createImageToolTip(ref->base->name, ref->base->icon, 32, text); } // -------------------- Light ------------------------------- @@ -272,7 +310,12 @@ IntSize ToolTips::getToolTipViaPtr () text += "\n" + mWindowManager->getGameSettingString("sWeight", "Weight") + ": " + toString(ref->base->data.weight); text += getValueString(ref->base->data.value); - tooltipSize = createImageToolTip(ref->base->name, ref->base->icon, text); + if (mFullHelp) { + text += "\n Owner: " + ref->ref.owner; + text += "\n Script: " + ref->base->script; + } + + tooltipSize = createImageToolTip(ref->base->name, ref->base->icon, 32, text); } // -------------------- Tool ------------------------------- @@ -286,7 +329,12 @@ IntSize ToolTips::getToolTipViaPtr () text += "\n" + mWindowManager->getGameSettingString("sWeight", "Weight") + ": " + toString(ref->base->data.weight); text += getValueString(ref->base->data.value); - tooltipSize = createImageToolTip(ref->base->name, ref->base->icon, text); + if (mFullHelp) { + text += "\n Owner: " + ref->ref.owner; + text += "\n Script: " + ref->base->script; + } + + tooltipSize = createImageToolTip(ref->base->name, ref->base->icon, 32, text); } // -------------------- Miscellaneous ------------------------------- @@ -298,7 +346,12 @@ IntSize ToolTips::getToolTipViaPtr () text += "\n" + mWindowManager->getGameSettingString("sWeight", "Weight") + ": " + toString(ref->base->data.weight); text += getValueString(ref->base->data.value); - tooltipSize = createImageToolTip(ref->base->name, ref->base->icon, text); + if (mFullHelp) { + text += "\n Owner: " + ref->ref.owner; + text += "\n Script: " + ref->base->script; + } + + tooltipSize = createImageToolTip(ref->base->name, ref->base->icon, 32, text); } // -------------------- Probe ------------------------------- @@ -312,7 +365,12 @@ IntSize ToolTips::getToolTipViaPtr () text += "\n" + mWindowManager->getGameSettingString("sWeight", "Weight") + ": " + toString(ref->base->data.weight); text += getValueString(ref->base->data.value); - tooltipSize = createImageToolTip(ref->base->name, ref->base->icon, text); + if (mFullHelp) { + text += "\n Owner: " + ref->ref.owner; + text += "\n Script: " + ref->base->script; + } + + tooltipSize = createImageToolTip(ref->base->name, ref->base->icon, 32, text); } // -------------------- Repair ------------------------------- @@ -326,7 +384,12 @@ IntSize ToolTips::getToolTipViaPtr () text += "\n" + mWindowManager->getGameSettingString("sWeight", "Weight") + ": " + toString(ref->base->data.weight); text += getValueString(ref->base->data.value); - tooltipSize = createImageToolTip(ref->base->name, ref->base->icon, text); + if (mFullHelp) { + text += "\n Owner: " + ref->ref.owner; + text += "\n Script: " + ref->base->script; + } + + tooltipSize = createImageToolTip(ref->base->name, ref->base->icon, 32, text); } // -------------------- Weapon ------------------------------- @@ -340,7 +403,12 @@ IntSize ToolTips::getToolTipViaPtr () text += "\n" + mWindowManager->getGameSettingString("sWeight", "Weight") + ": " + toString(ref->base->data.weight); text += getValueString(ref->base->data.value); - tooltipSize = createImageToolTip(ref->base->name, ref->base->icon, text); + if (mFullHelp) { + text += "\n Owner: " + ref->ref.owner; + text += "\n Script: " + ref->base->script; + } + + tooltipSize = createImageToolTip(ref->base->name, ref->base->icon, 32, text); } // -------------------- Activator ------------------------------- @@ -348,7 +416,12 @@ IntSize ToolTips::getToolTipViaPtr () { ESMS::LiveCellRef* ref = mFocusObject.get(); - tooltipSize = createToolTip(ref->base->name, ""); + std::string text; + if (mFullHelp) { + text += "\n Script: " + ref->base->script; + } + + tooltipSize = createToolTip(ref->base->name, text); } else @@ -374,7 +447,7 @@ void ToolTips::findImageExtension(std::string& image) } } -IntSize ToolTips::createImageToolTip(const std::string& caption, const std::string& image, const std::string& text) +IntSize ToolTips::createImageToolTip(const std::string& caption, const std::string& image, const int imageSize, const std::string& text) { // remove the first newline (easier this way) std::string realText = text; @@ -384,12 +457,10 @@ IntSize ToolTips::createImageToolTip(const std::string& caption, const std::stri std::string realImage = "icons\\" + image; findImageExtension(realImage); - const int imageSize = 32; - EditBox* captionWidget = mDynamicToolTipBox->createWidget("NormalText", IntCoord(0, 0, 300, 300), Align::Left | Align::Top, "ToolTipCaption"); captionWidget->setProperty("Static", "true"); captionWidget->setCaption(caption); - EditBox* textWidget = mDynamicToolTipBox->createWidget("SandText", IntCoord(0, imageSize, 300, 262), Align::Stretch, "ToolTipText"); + EditBox* textWidget = mDynamicToolTipBox->createWidget("SandText", IntCoord(0, imageSize, 300, 300-imageSize), Align::Stretch, "ToolTipText"); textWidget->setProperty("Static", "true"); textWidget->setProperty("MultiLine", "true"); textWidget->setProperty("WordWrap", "true"); @@ -407,7 +478,7 @@ IntSize ToolTips::createImageToolTip(const std::string& caption, const std::stri Align::Left | Align::Top, "ToolTipImage"); imageWidget->setImageTexture(realImage); - captionWidget->setCoord( (totalSize.width - captionSize.width)/2 + imageSize, (32-captionSize.height)/2, captionSize.width-imageSize, captionSize.height); + captionWidget->setCoord( (totalSize.width - captionSize.width)/2 + imageSize, (imageSize-captionSize.height)/2, captionSize.width-imageSize, captionSize.height); mDynamicToolTipBox->setVisible(caption != ""); @@ -468,3 +539,8 @@ std::string ToolTips::getValueString(const int value) else return "\n" + mWindowManager->getGameSettingString("sValue", "Value") + ": " + toString(value); } + +void ToolTips::toggleFullHelp() +{ + mFullHelp = !mFullHelp; +} diff --git a/apps/openmw/mwgui/tooltips.hpp b/apps/openmw/mwgui/tooltips.hpp index 7a2dded114..f546f3976e 100644 --- a/apps/openmw/mwgui/tooltips.hpp +++ b/apps/openmw/mwgui/tooltips.hpp @@ -19,6 +19,8 @@ namespace MWGui void enterGameMode(); void enterGuiMode(); + void toggleFullHelp(); ///< show extra info in item tooltips (owner, script) + void setFocusObject(const MWWorld::Ptr& focus); private: @@ -33,7 +35,7 @@ namespace MWGui MyGUI::IntSize getToolTipViaPtr (); ///< @return requested tooltip size - MyGUI::IntSize createImageToolTip(const std::string& caption, const std::string& image, const std::string& text); + MyGUI::IntSize createImageToolTip(const std::string& caption, const std::string& image, const int imageSize, const std::string& text); ///< @return requested tooltip size MyGUI::IntSize createToolTip(const std::string& caption, const std::string& text); @@ -49,6 +51,8 @@ namespace MWGui std::string toString(const int value); bool mGameMode; + + bool mFullHelp; }; } #endif diff --git a/apps/openmw/mwgui/window_manager.cpp b/apps/openmw/mwgui/window_manager.cpp index 8ed2050cc0..b18ee4e432 100644 --- a/apps/openmw/mwgui/window_manager.cpp +++ b/apps/openmw/mwgui/window_manager.cpp @@ -497,3 +497,8 @@ void WindowManager::setFocusObject(const MWWorld::Ptr& focus) { mToolTips->setFocusObject(focus); } + +void WindowManager::toggleFullHelp() +{ + mToolTips->toggleFullHelp(); +} diff --git a/apps/openmw/mwgui/window_manager.hpp b/apps/openmw/mwgui/window_manager.hpp index d5f0683b86..d76d15dd4c 100644 --- a/apps/openmw/mwgui/window_manager.hpp +++ b/apps/openmw/mwgui/window_manager.hpp @@ -161,6 +161,7 @@ namespace MWGui void setFocusObject(const MWWorld::Ptr& focus); void toggleFogOfWar(); + void toggleFullHelp(); ///< show extra info in item tooltips (owner, script) int toggleFps(); ///< toggle fps display @return resulting fps level diff --git a/apps/openmw/mwscript/docs/vmformat.txt b/apps/openmw/mwscript/docs/vmformat.txt index 58960aac47..378b2412a5 100644 --- a/apps/openmw/mwscript/docs/vmformat.txt +++ b/apps/openmw/mwscript/docs/vmformat.txt @@ -144,4 +144,5 @@ op 0x200014d: ModDisposition op 0x200014e: ModDisposition, explicit reference op 0x200014f: ForceGreeting op 0x2000150: ForceGreeting, explicit reference -opcodes 0x2000151-0x3ffffff unused +op 0x2000151: ToggleFullHelp +opcodes 0x2000152-0x3ffffff unused diff --git a/apps/openmw/mwscript/guiextensions.cpp b/apps/openmw/mwscript/guiextensions.cpp index 426378efca..f7be161d62 100644 --- a/apps/openmw/mwscript/guiextensions.cpp +++ b/apps/openmw/mwscript/guiextensions.cpp @@ -80,6 +80,19 @@ namespace MWScript } }; + class OpToggleFullHelp : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + InterpreterContext& context = + static_cast (runtime.getContext()); + + context.getEnvironment().mWindowManager->toggleFullHelp(); + } + }; + const int opcodeEnableBirthMenu = 0x200000e; const int opcodeEnableClassMenu = 0x200000f; const int opcodeEnableNameMenu = 0x2000010; @@ -93,6 +106,7 @@ namespace MWScript const int opcodeShowRestMenu = 0x2000018; const int opcodeGetButtonPressed = 0x2000137; const int opcodeToggleFogOfWar = 0x2000145; + const int opcodeToggleFullHelp = 0x2000151; void registerExtensions (Compiler::Extensions& extensions) { @@ -101,7 +115,7 @@ namespace MWScript extensions.registerInstruction ("enablenamemenu", "", opcodeEnableNameMenu); extensions.registerInstruction ("enableracemenu", "", opcodeEnableRaceMenu); extensions.registerInstruction ("enablestatsreviewmenu", "", - opcodeEnableStatsReviewMenu); +opcodeEnableStatsReviewMenu); extensions.registerInstruction ("enableinventorymenu", "", opcodeEnableInventoryMenu); extensions.registerInstruction ("enablemagicmenu", "", opcodeEnableMagicMenu); @@ -117,6 +131,9 @@ namespace MWScript extensions.registerInstruction ("togglefogofwar", "", opcodeToggleFogOfWar); extensions.registerInstruction ("tfow", "", opcodeToggleFogOfWar); + + extensions.registerInstruction ("togglefullhelp", "", opcodeToggleFullHelp); + extensions.registerInstruction ("tfh", "", opcodeToggleFullHelp); } void installOpcodes (Interpreter::Interpreter& interpreter) @@ -154,6 +171,8 @@ namespace MWScript interpreter.installSegment5 (opcodeGetButtonPressed, new OpGetButtonPressed); interpreter.installSegment5 (opcodeToggleFogOfWar, new OpToggleFogOfWar); + + interpreter.installSegment5 (opcodeToggleFullHelp, new OpToggleFullHelp); } } } From b3dc1931a947b03a0895bb854eff3fd4d4e5fb25 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 16 Apr 2012 15:48:01 +0200 Subject: [PATCH 017/325] general GUI refactoring, part 1 --- apps/openmw/mwgui/review.cpp | 37 ++++++++++------------- apps/openmw/mwgui/review.hpp | 9 +----- apps/openmw/mwgui/stats_window.cpp | 47 +++++++++++++----------------- apps/openmw/mwgui/stats_window.hpp | 9 +----- files/mygui/openmw_button.skin.xml | 10 +++---- files/mygui/openmw_edit.skin.xml | 4 +-- files/mygui/openmw_list.skin.xml | 10 +++---- libs/openengine/gui/layout.hpp | 14 +++++++++ 8 files changed, 64 insertions(+), 76 deletions(-) diff --git a/apps/openmw/mwgui/review.cpp b/apps/openmw/mwgui/review.cpp index cb0d9969c6..dbd832580e 100644 --- a/apps/openmw/mwgui/review.cpp +++ b/apps/openmw/mwgui/review.cpp @@ -28,21 +28,25 @@ ReviewDialog::ReviewDialog(WindowManager& parWindowManager) getWidget(nameWidget, "NameText"); getWidget(button, "NameButton"); button->setCaption(mWindowManager.getGameSettingString("sName", "")); + adjustButtonSize(button); button->eventMouseButtonClick += MyGUI::newDelegate(this, &ReviewDialog::onNameClicked);; getWidget(raceWidget, "RaceText"); getWidget(button, "RaceButton"); button->setCaption(mWindowManager.getGameSettingString("sRace", "")); + adjustButtonSize(button); button->eventMouseButtonClick += MyGUI::newDelegate(this, &ReviewDialog::onRaceClicked);; getWidget(classWidget, "ClassText"); getWidget(button, "ClassButton"); button->setCaption(mWindowManager.getGameSettingString("sClass", "")); + adjustButtonSize(button); button->eventMouseButtonClick += MyGUI::newDelegate(this, &ReviewDialog::onClassClicked);; getWidget(birthSignWidget, "SignText"); getWidget(button, "SignButton"); button->setCaption(mWindowManager.getGameSettingString("sBirthSign", "")); + adjustButtonSize(button); button->eventMouseButtonClick += MyGUI::newDelegate(this, &ReviewDialog::onBirthSignClicked);; // Setup dynamic stats @@ -181,13 +185,14 @@ void ReviewDialog::setSkillValue(ESM::Skill::SkillEnum skillId, const MWMechanic { float modified = value.getModified(), base = value.getBase(); std::string text = boost::lexical_cast(std::floor(modified)); - ColorStyle style = CS_Normal; + std::string state = "normal"; if (modified > base) - style = CS_Super; + state = "increased"; else if (modified < base) - style = CS_Sub; + state = "decreased"; - setStyledText(widget, style, text); + widget->setCaption(text); + widget->_setWidgetState(state); } } @@ -210,17 +215,6 @@ void ReviewDialog::configureSkills(const std::vector& major, const std::vec } } -void ReviewDialog::setStyledText(MyGUI::TextBox* widget, ColorStyle style, const std::string &value) -{ - widget->setCaption(value); - if (style == CS_Super) - widget->setTextColour(MyGUI::Colour(0, 1, 0)); - else if (style == CS_Sub) - widget->setTextColour(MyGUI::Colour(1, 0, 0)); - else - widget->setTextColour(MyGUI::Colour(1, 1, 1)); -} - void ReviewDialog::addSeparator(MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) { MyGUI::ImageBox* separator = skillClientWidget->createWidget("MW_HLine", MyGUI::IntCoord(10, coord1.top, coord1.width + coord2.width - 4, 18), MyGUI::Align::Default); @@ -240,7 +234,7 @@ void ReviewDialog::addGroup(const std::string &label, MyGUI::IntCoord &coord1, M coord2.top += lineHeight; } -MyGUI::TextBox* ReviewDialog::addValueItem(const std::string text, const std::string &value, ColorStyle style, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) +MyGUI::TextBox* ReviewDialog::addValueItem(const std::string text, const std::string &value, const std::string& state, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) { MyGUI::TextBox* skillNameWidget; MyGUI::TextBox* skillValueWidget; @@ -249,7 +243,8 @@ MyGUI::TextBox* ReviewDialog::addValueItem(const std::string text, const std::st skillNameWidget->setCaption(text); skillValueWidget = skillClientWidget->createWidget("SandTextRight", coord2, MyGUI::Align::Default); - setStyledText(skillValueWidget, style, value); + skillValueWidget->setCaption(value); + skillValueWidget->_setWidgetState(state); skillWidgets.push_back(skillNameWidget); skillWidgets.push_back(skillValueWidget); @@ -295,12 +290,12 @@ void ReviewDialog::addSkills(const SkillList &skills, const std::string &titleId float base = stat.getBase(); float modified = stat.getModified(); - ColorStyle style = CS_Normal; + std::string state = "normal"; if (modified > base) - style = CS_Super; + state = "increased"; else if (modified < base) - style = CS_Sub; - MyGUI::TextBox* widget = addValueItem(mWindowManager.getGameSettingString(skillNameId, skillNameId), boost::lexical_cast(static_cast(modified)), style, coord1, coord2); + state = "decreased"; + MyGUI::TextBox* widget = addValueItem(mWindowManager.getGameSettingString(skillNameId, skillNameId), boost::lexical_cast(static_cast(modified)), state, coord1, coord2); skillWidgetMap[skillId] = widget; } } diff --git a/apps/openmw/mwgui/review.hpp b/apps/openmw/mwgui/review.hpp index 588c1b6b5d..76ca5a2d76 100644 --- a/apps/openmw/mwgui/review.hpp +++ b/apps/openmw/mwgui/review.hpp @@ -69,17 +69,10 @@ namespace MWGui void onBirthSignClicked(MyGUI::Widget* _sender); private: - enum ColorStyle - { - CS_Sub, - CS_Normal, - CS_Super - }; - void setStyledText(MyGUI::TextBox* widget, ColorStyle style, const std::string &value); void addSkills(const SkillList &skills, const std::string &titleId, const std::string &titleDefault, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2); void addSeparator(MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2); void addGroup(const std::string &label, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2); - MyGUI::TextBox* addValueItem(const std::string text, const std::string &value, ColorStyle style, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2); + MyGUI::TextBox* addValueItem(const std::string text, const std::string &value, const std::string& state, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2); void addItem(const std::string text, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2); void updateScroller(); void updateSkillArea(); diff --git a/apps/openmw/mwgui/stats_window.cpp b/apps/openmw/mwgui/stats_window.cpp index cf279faf7f..42194740f1 100644 --- a/apps/openmw/mwgui/stats_window.cpp +++ b/apps/openmw/mwgui/stats_window.cpp @@ -113,17 +113,6 @@ void StatsWindow::setPlayerName(const std::string& playerName) static_cast(mMainWidget)->setCaption(playerName); } -void StatsWindow::setStyledText(MyGUI::TextBox* widget, ColorStyle style, const std::string &value) -{ - widget->setCaption(value); - if (style == CS_Super) - widget->setTextColour(MyGUI::Colour(0, 1, 0)); - else if (style == CS_Sub) - widget->setTextColour(MyGUI::Colour(1, 0, 0)); - else - widget->setTextColour(MyGUI::Colour(1, 1, 1)); -} - void StatsWindow::setValue (const std::string& id, const MWMechanics::Stat& value) { static const char *ids[] = @@ -140,12 +129,15 @@ void StatsWindow::setValue (const std::string& id, const MWMechanics::Stat& valueString << value.getModified(); setText (id, valueString.str()); + MyGUI::TextBox* box; + getWidget(box, id); + if (value.getModified()>value.getBase()) - setTextColor (id, 0, 1, 0); + box->_setWidgetState("increased"); else if (value.getModified()_setWidgetState("decreased"); else - setTextColor (id, 1, 1, 1); + box->_setWidgetState("normal"); break; } @@ -195,13 +187,14 @@ void StatsWindow::setValue(const ESM::Skill::SkillEnum parSkill, const MWMechani { float modified = value.getModified(), base = value.getBase(); std::string text = boost::lexical_cast(std::floor(modified)); - ColorStyle style = CS_Normal; + std::string state = "normal"; if (modified > base) - style = CS_Super; + state = "increased"; else if (modified < base) - style = CS_Sub; + state = "decreased"; - setStyledText(widget, style, text); + widget->setCaption(text); + widget->_setWidgetState(state); } } @@ -253,7 +246,7 @@ void StatsWindow::addGroup(const std::string &label, MyGUI::IntCoord &coord1, My coord2.top += lineHeight; } -MyGUI::TextBox* StatsWindow::addValueItem(const std::string& text, const std::string& tooltip, const std::string &value, ColorStyle style, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) +MyGUI::TextBox* StatsWindow::addValueItem(const std::string& text, const std::string& tooltip, const std::string &value, const std::string& state, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) { MyGUI::TextBox *skillNameWidget, *skillValueWidget; @@ -265,7 +258,8 @@ MyGUI::TextBox* StatsWindow::addValueItem(const std::string& text, const std::st skillValueWidget = skillClientWidget->createWidget("SandTextRight", coord2, MyGUI::Align::Default); skillValueWidget->setUserString("ToolTipType", "Text"); skillValueWidget->setUserString("ToolTipText", tooltip); - setStyledText(skillValueWidget, style, value); + skillValueWidget->setCaption(value); + skillValueWidget->_setWidgetState(state); skillWidgets.push_back(skillNameWidget); skillWidgets.push_back(skillValueWidget); @@ -311,12 +305,13 @@ void StatsWindow::addSkills(const SkillList &skills, const std::string &titleId, float base = stat.getBase(); float modified = stat.getModified(); - ColorStyle style = CS_Normal; + std::string state = "normal"; if (modified > base) - style = CS_Super; + state = "increased"; else if (modified < base) - style = CS_Sub; - MyGUI::TextBox* widget = addValueItem(mWindowManager.getGameSettingString(skillNameId, skillNameId), "", boost::lexical_cast(static_cast(modified)), style, coord1, coord2); + state = "decreased"; + MyGUI::TextBox* widget = addValueItem(mWindowManager.getGameSettingString(skillNameId, skillNameId), "", + boost::lexical_cast(static_cast(modified)), state, coord1, coord2); skillWidgetMap[skillId] = widget; } } @@ -377,10 +372,10 @@ void StatsWindow::updateSkillArea() addValueItem(mWindowManager.getGameSettingString("sReputation", "Reputation"), mWindowManager.getGameSettingString("sSkillsMenuReputationHelp", ""), - boost::lexical_cast(static_cast(reputation)), CS_Normal, coord1, coord2); + boost::lexical_cast(static_cast(reputation)), "normal", coord1, coord2); addValueItem(mWindowManager.getGameSettingString("sBounty", "Bounty"), mWindowManager.getGameSettingString("sCrimeHelp", ""), - boost::lexical_cast(static_cast(bounty)), CS_Normal, coord1, coord2); + boost::lexical_cast(static_cast(bounty)), "normal", coord1, coord2); clientHeight = coord1.top; updateScroller(); diff --git a/apps/openmw/mwgui/stats_window.hpp b/apps/openmw/mwgui/stats_window.hpp index 075c08dd32..ecbc82894e 100644 --- a/apps/openmw/mwgui/stats_window.hpp +++ b/apps/openmw/mwgui/stats_window.hpp @@ -43,17 +43,10 @@ namespace MWGui void updateSkillArea(); private: - enum ColorStyle - { - CS_Sub, - CS_Normal, - CS_Super - }; - void setStyledText(MyGUI::TextBox* widget, ColorStyle style, const std::string &value); void addSkills(const SkillList &skills, const std::string &titleId, const std::string &titleDefault, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2); void addSeparator(MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2); void addGroup(const std::string &label, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2); - MyGUI::TextBox* addValueItem(const std::string& text, const std::string& tooltip, const std::string &value, ColorStyle style, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2); + MyGUI::TextBox* addValueItem(const std::string& text, const std::string& tooltip, const std::string &value, const std::string& state, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2); void addItem(const std::string text, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2); void updateScroller(); diff --git a/files/mygui/openmw_button.skin.xml b/files/mygui/openmw_button.skin.xml index 1c68930264..b88e994066 100644 --- a/files/mygui/openmw_button.skin.xml +++ b/files/mygui/openmw_button.skin.xml @@ -47,7 +47,6 @@ - @@ -59,11 +58,10 @@ - - - - - + + + + diff --git a/files/mygui/openmw_edit.skin.xml b/files/mygui/openmw_edit.skin.xml index a86317d620..02fee4b179 100644 --- a/files/mygui/openmw_edit.skin.xml +++ b/files/mygui/openmw_edit.skin.xml @@ -13,7 +13,7 @@ - + @@ -34,7 +34,7 @@ - + diff --git a/files/mygui/openmw_list.skin.xml b/files/mygui/openmw_list.skin.xml index 0ac8e03ba6..5ec975a1b0 100644 --- a/files/mygui/openmw_list.skin.xml +++ b/files/mygui/openmw_list.skin.xml @@ -180,10 +180,10 @@ - - - - + + + + @@ -219,7 +219,7 @@ - <_BasisSkin type="MainSkin" offset = "0 0 0 0" align = "ALIGN_LEFT ALIGN_TOP"/> + diff --git a/libs/openengine/gui/layout.hpp b/libs/openengine/gui/layout.hpp index 05a23e8aea..b95dcc4a55 100644 --- a/libs/openengine/gui/layout.hpp +++ b/libs/openengine/gui/layout.hpp @@ -115,6 +115,13 @@ namespace GUI static_cast(pt)->setCaption(caption); } + void setState(const std::string& widget, const std::string& state) + { + MyGUI::Widget* pt; + getWidget(pt, widget); + pt->_setWidgetState(state); + } + void setTextColor(const std::string& name, float r, float g, float b) { MyGUI::Widget* pt; @@ -131,6 +138,13 @@ namespace GUI pt->setImageTexture(imgName); } + void adjustButtonSize(MyGUI::Button* button) + { + // adjust size of button to fit its text + MyGUI::IntSize size = button->getTextSize(); + button->setSize(size.width + 24, button->getSize().height); + } + protected: MyGUI::Widget* mMainWidget; From 14377ba789ee001503a6441cd713d08b55db0d76 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 16 Apr 2012 17:30:57 +0200 Subject: [PATCH 018/325] window caption fix --- apps/openmw/mwgui/stats_window.cpp | 1 + libs/openengine/gui/layout.hpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/stats_window.cpp b/apps/openmw/mwgui/stats_window.cpp index 42194740f1..b007fc1d40 100644 --- a/apps/openmw/mwgui/stats_window.cpp +++ b/apps/openmw/mwgui/stats_window.cpp @@ -111,6 +111,7 @@ void StatsWindow::setBar(const std::string& name, const std::string& tname, int void StatsWindow::setPlayerName(const std::string& playerName) { static_cast(mMainWidget)->setCaption(playerName); + adjustWindowCaption(); } void StatsWindow::setValue (const std::string& id, const MWMechanics::Stat& value) diff --git a/libs/openengine/gui/layout.hpp b/libs/openengine/gui/layout.hpp index b95dcc4a55..bda8935af2 100644 --- a/libs/openengine/gui/layout.hpp +++ b/libs/openengine/gui/layout.hpp @@ -85,7 +85,7 @@ namespace GUI // adjust the size of the window caption so that all text is visible // NOTE: this assumes that mMainWidget is of type Window. MyGUI::TextBox* box = static_cast(mMainWidget)->getCaptionWidget(); - box->setSize(box->getTextSize().width + 48, box->getSize().height); + box->setSize(box->getTextSize().width + 24, box->getSize().height); // in order to trigger alignment updates, we need to update the parent // mygui doesn't provide a proper way of doing this, so we are just changing size From 424a90aa92fd766db35316b3fafe6be7342951f7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 16 Apr 2012 17:46:54 +0200 Subject: [PATCH 019/325] back & ok button caption --- apps/openmw/mwgui/birth.cpp | 2 ++ apps/openmw/mwgui/class.cpp | 2 ++ apps/openmw/mwgui/race.cpp | 5 ++--- apps/openmw/mwgui/review.cpp | 2 ++ 4 files changed, 8 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwgui/birth.cpp b/apps/openmw/mwgui/birth.cpp index e9c15fab4a..100356e28e 100644 --- a/apps/openmw/mwgui/birth.cpp +++ b/apps/openmw/mwgui/birth.cpp @@ -28,10 +28,12 @@ BirthDialog::BirthDialog(WindowManager& parWindowManager) // TODO: These buttons should be managed by a Dialog class MyGUI::ButtonPtr backButton; getWidget(backButton, "BackButton"); + backButton->setCaption(mWindowManager.getGameSettingString("sBack", "")); backButton->eventMouseButtonClick += MyGUI::newDelegate(this, &BirthDialog::onBackClicked); MyGUI::ButtonPtr okButton; getWidget(okButton, "OKButton"); + okButton->setCaption(mWindowManager.getGameSettingString("sOK", "")); okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &BirthDialog::onOkClicked); updateBirths(); diff --git a/apps/openmw/mwgui/class.cpp b/apps/openmw/mwgui/class.cpp index 75e534b42a..791e24f2a2 100644 --- a/apps/openmw/mwgui/class.cpp +++ b/apps/openmw/mwgui/class.cpp @@ -29,10 +29,12 @@ GenerateClassResultDialog::GenerateClassResultDialog(WindowManager& parWindowMan // TODO: These buttons should be managed by a Dialog class MyGUI::ButtonPtr backButton; getWidget(backButton, "BackButton"); + backButton->setCaption(mWindowManager.getGameSettingString("sBack", "")); backButton->eventMouseButtonClick += MyGUI::newDelegate(this, &GenerateClassResultDialog::onBackClicked); MyGUI::ButtonPtr okButton; getWidget(okButton, "OKButton"); + okButton->setCaption(mWindowManager.getGameSettingString("sOK", "")); okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &GenerateClassResultDialog::onOkClicked); } diff --git a/apps/openmw/mwgui/race.cpp b/apps/openmw/mwgui/race.cpp index 880c0bc520..9a84f551c2 100644 --- a/apps/openmw/mwgui/race.cpp +++ b/apps/openmw/mwgui/race.cpp @@ -72,10 +72,12 @@ RaceDialog::RaceDialog(WindowManager& parWindowManager) // TODO: These buttons should be managed by a Dialog class MyGUI::ButtonPtr backButton; getWidget(backButton, "BackButton"); + backButton->setCaption(mWindowManager.getGameSettingString("sBack", "")); backButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onBackClicked); MyGUI::ButtonPtr okButton; getWidget(okButton, "OKButton"); + okButton->setCaption(mWindowManager.getGameSettingString("sOK", "")); okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onOkClicked); updateRaces(); @@ -94,15 +96,12 @@ void RaceDialog::setNextButtonShow(bool shown) // TODO: All hardcoded coords for buttons are temporary, will be replaced with a dynamic system. if (shown) { - okButton->setCaption("Next"); - // Adjust back button when next is shown backButton->setCoord(MyGUI::IntCoord(471 - 18, 397, 53, 23)); okButton->setCoord(MyGUI::IntCoord(532 - 18, 397, 42 + 18, 23)); } else { - okButton->setCaption("OK"); backButton->setCoord(MyGUI::IntCoord(471, 397, 53, 23)); okButton->setCoord(MyGUI::IntCoord(532, 397, 42, 23)); } diff --git a/apps/openmw/mwgui/review.cpp b/apps/openmw/mwgui/review.cpp index dbd832580e..f531fe5364 100644 --- a/apps/openmw/mwgui/review.cpp +++ b/apps/openmw/mwgui/review.cpp @@ -93,10 +93,12 @@ ReviewDialog::ReviewDialog(WindowManager& parWindowManager) // TODO: These buttons should be managed by a Dialog class MyGUI::ButtonPtr backButton; getWidget(backButton, "BackButton"); + backButton->setCaption(mWindowManager.getGameSettingString("sBack", "")); backButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ReviewDialog::onBackClicked); MyGUI::ButtonPtr okButton; getWidget(okButton, "OKButton"); + okButton->setCaption(mWindowManager.getGameSettingString("sOK", "")); okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ReviewDialog::onOkClicked); } From cfa37b0e7721ee17e98f08ee3b9588783a27271c Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 16 Apr 2012 19:14:05 +0200 Subject: [PATCH 020/325] fix another bunch of gui stuff, some strings were untranslated and buttons were not resized to fit their text --- apps/openmw/mwgui/birth.cpp | 22 ++---- apps/openmw/mwgui/class.cpp | 73 +++++++++---------- apps/openmw/mwgui/map_window.cpp | 8 +- apps/openmw/mwgui/race.cpp | 19 ++--- apps/openmw/mwgui/review.cpp | 6 +- apps/openmw/mwgui/text_input.cpp | 16 ++-- apps/openmw/mwgui/tooltips.hpp | 12 +++ ...w_chargen_generate_class_result_layout.xml | 12 +-- files/mygui/openmw_text.skin.xml | 6 +- 9 files changed, 92 insertions(+), 82 deletions(-) diff --git a/apps/openmw/mwgui/birth.cpp b/apps/openmw/mwgui/birth.cpp index 100356e28e..44c165743d 100644 --- a/apps/openmw/mwgui/birth.cpp +++ b/apps/openmw/mwgui/birth.cpp @@ -25,7 +25,6 @@ BirthDialog::BirthDialog(WindowManager& parWindowManager) birthList->eventListMouseItemActivate += MyGUI::newDelegate(this, &BirthDialog::onSelectBirth); birthList->eventListChangePosition += MyGUI::newDelegate(this, &BirthDialog::onSelectBirth); - // TODO: These buttons should be managed by a Dialog class MyGUI::ButtonPtr backButton; getWidget(backButton, "BackButton"); backButton->setCaption(mWindowManager.getGameSettingString("sBack", "")); @@ -48,21 +47,16 @@ void BirthDialog::setNextButtonShow(bool shown) MyGUI::ButtonPtr okButton; getWidget(okButton, "OKButton"); - // TODO: All hardcoded coords for buttons are temporary, will be replaced with a dynamic system. if (shown) - { - okButton->setCaption("Next"); - - // Adjust back button when next is shown - backButton->setCoord(MyGUI::IntCoord(375 - 18, 340, 53, 23)); - okButton->setCoord(MyGUI::IntCoord(431 - 18, 340, 42 + 18, 23)); - } + okButton->setCaption(mWindowManager.getGameSettingString("sNext", "")); else - { - okButton->setCaption("OK"); - backButton->setCoord(MyGUI::IntCoord(375, 340, 53, 23)); - okButton->setCoord(MyGUI::IntCoord(431, 340, 42, 23)); - } + okButton->setCaption(mWindowManager.getGameSettingString("sOK", "")); + + int okButtonWidth = okButton->getTextSize().width + 24; + int backButtonWidth = backButton->getTextSize().width + 24; + + okButton->setCoord(473 - okButtonWidth, 340, okButtonWidth, 23); + backButton->setCoord(473 - okButtonWidth - backButtonWidth - 6, 340, backButtonWidth, 23); } void BirthDialog::open() diff --git a/apps/openmw/mwgui/class.cpp b/apps/openmw/mwgui/class.cpp index 791e24f2a2..9f1fc5d2a5 100644 --- a/apps/openmw/mwgui/class.cpp +++ b/apps/openmw/mwgui/class.cpp @@ -26,7 +26,6 @@ GenerateClassResultDialog::GenerateClassResultDialog(WindowManager& parWindowMan getWidget(classImage, "ClassImage"); getWidget(className, "ClassName"); - // TODO: These buttons should be managed by a Dialog class MyGUI::ButtonPtr backButton; getWidget(backButton, "BackButton"); backButton->setCaption(mWindowManager.getGameSettingString("sBack", "")); @@ -36,6 +35,11 @@ GenerateClassResultDialog::GenerateClassResultDialog(WindowManager& parWindowMan getWidget(okButton, "OKButton"); okButton->setCaption(mWindowManager.getGameSettingString("sOK", "")); okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &GenerateClassResultDialog::onOkClicked); + + int okButtonWidth = okButton->getTextSize().width + 24; + int backButtonWidth = backButton->getTextSize().width + 24; + okButton->setCoord(315 - okButtonWidth, 219, okButtonWidth, 23); + backButton->setCoord(315 - okButtonWidth - backButtonWidth - 6, 219, backButtonWidth, 23); } void GenerateClassResultDialog::open() @@ -104,7 +108,6 @@ PickClassDialog::PickClassDialog(WindowManager& parWindowManager) getWidget(classImage, "ClassImage"); - // TODO: These buttons should be managed by a Dialog class MyGUI::ButtonPtr backButton; getWidget(backButton, "BackButton"); backButton->eventMouseButtonClick += MyGUI::newDelegate(this, &PickClassDialog::onBackClicked); @@ -125,21 +128,16 @@ void PickClassDialog::setNextButtonShow(bool shown) MyGUI::ButtonPtr okButton; getWidget(okButton, "OKButton"); - // TODO: All hardcoded coords for buttons are temporary, will be replaced with a dynamic system. if (shown) - { - okButton->setCaption("Next"); - - // Adjust back button when next is shown - backButton->setCoord(MyGUI::IntCoord(382 - 18, 265, 53, 23)); - okButton->setCoord(MyGUI::IntCoord(434 - 18, 265, 42 + 18, 23)); - } + okButton->setCaption(mWindowManager.getGameSettingString("sNext", "")); else - { - okButton->setCaption("OK"); - backButton->setCoord(MyGUI::IntCoord(382, 265, 53, 23)); - okButton->setCoord(MyGUI::IntCoord(434, 265, 42, 23)); - } + okButton->setCaption(mWindowManager.getGameSettingString("sOK", "")); + + int okButtonWidth = okButton->getTextSize().width + 24; + int backButtonWidth = backButton->getTextSize().width + 24; + + okButton->setCoord(476 - okButtonWidth, 265, okButtonWidth, 23); + backButton->setCoord(476 - okButtonWidth - backButtonWidth - 6, 265, backButtonWidth, 23); } void PickClassDialog::open() @@ -425,9 +423,9 @@ CreateClassDialog::CreateClassDialog(WindowManager& parWindowManager) // Make sure the edit box has focus MyGUI::InputManager::getInstance().setKeyFocusWidget(editName); - // TODO: These buttons should be managed by a Dialog class MyGUI::ButtonPtr descriptionButton; getWidget(descriptionButton, "DescriptionButton"); + descriptionButton->setCaption(mWindowManager.getGameSettingString("sCreateClassMenu1", "")); descriptionButton->eventMouseButtonClick += MyGUI::newDelegate(this, &CreateClassDialog::onDescriptionClicked); MyGUI::ButtonPtr backButton; @@ -509,32 +507,27 @@ std::vector CreateClassDialog::getMinorSkills() const void CreateClassDialog::setNextButtonShow(bool shown) { - MyGUI::ButtonPtr descriptionButton; - getWidget(descriptionButton, "DescriptionButton"); - MyGUI::ButtonPtr backButton; getWidget(backButton, "BackButton"); MyGUI::ButtonPtr okButton; getWidget(okButton, "OKButton"); - // TODO: All hardcoded coords for buttons are temporary, will be replaced with a dynamic system. - if (shown) - { - okButton->setCaption("Next"); + MyGUI::ButtonPtr descriptionButton; + getWidget(descriptionButton, "DescriptionButton"); - // Adjust back button when next is shown - descriptionButton->setCoord(MyGUI::IntCoord(207 - 18, 158, 143, 23)); - backButton->setCoord(MyGUI::IntCoord(356 - 18, 158, 53, 23)); - okButton->setCoord(MyGUI::IntCoord(417 - 18, 158, 42 + 18, 23)); - } + if (shown) + okButton->setCaption(mWindowManager.getGameSettingString("sNext", "")); else - { - okButton->setCaption("OK"); - descriptionButton->setCoord(MyGUI::IntCoord(207, 158, 143, 23)); - backButton->setCoord(MyGUI::IntCoord(356, 158, 53, 23)); - okButton->setCoord(MyGUI::IntCoord(417, 158, 42, 23)); - } + okButton->setCaption(mWindowManager.getGameSettingString("sOK", "")); + + int okButtonWidth = okButton->getTextSize().width + 24; + int backButtonWidth = backButton->getTextSize().width + 24; + int descriptionButtonWidth = descriptionButton->getTextSize().width + 24; + + okButton->setCoord(459 - okButtonWidth, 158, okButtonWidth, 23); + backButton->setCoord(459 - okButtonWidth - backButtonWidth - 6, 158, backButtonWidth, 23); + descriptionButton->setCoord(459 - okButtonWidth - backButtonWidth - descriptionButtonWidth - 12, 158, descriptionButtonWidth, 23); } void CreateClassDialog::open() @@ -681,11 +674,12 @@ SelectSpecializationDialog::SelectSpecializationDialog(WindowManager& parWindowM specialization2->eventMouseButtonClick += MyGUI::newDelegate(this, &SelectSpecializationDialog::onSpecializationClicked); specializationId = ESM::Class::Combat; - // TODO: These buttons should be managed by a Dialog class MyGUI::ButtonPtr cancelButton; getWidget(cancelButton, "CancelButton"); cancelButton->setCaption(mWindowManager.getGameSettingString("sCancel", "")); cancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SelectSpecializationDialog::onCancelClicked); + int buttonWidth = cancelButton->getTextSize().width + 24; + cancelButton->setCoord(216 - buttonWidth, 90, buttonWidth, 21); } // widget controls @@ -730,11 +724,12 @@ SelectAttributeDialog::SelectAttributeDialog(WindowManager& parWindowManager) attribute->eventClicked += MyGUI::newDelegate(this, &SelectAttributeDialog::onAttributeClicked); } - // TODO: These buttons should be managed by a Dialog class MyGUI::ButtonPtr cancelButton; getWidget(cancelButton, "CancelButton"); cancelButton->setCaption(mWindowManager.getGameSettingString("sCancel", "")); cancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SelectAttributeDialog::onCancelClicked); + int buttonWidth = cancelButton->getTextSize().width + 24; + cancelButton->setCoord(186 - buttonWidth, 180, buttonWidth, 21); } // widget controls @@ -819,11 +814,12 @@ SelectSkillDialog::SelectSkillDialog(WindowManager& parWindowManager) } } - // TODO: These buttons should be managed by a Dialog class MyGUI::ButtonPtr cancelButton; getWidget(cancelButton, "CancelButton"); cancelButton->setCaption(mWindowManager.getGameSettingString("sCancel", "")); cancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SelectSkillDialog::onCancelClicked); + int buttonWidth = cancelButton->getTextSize().width + 24; + cancelButton->setCoord(447 - buttonWidth, 218, buttonWidth, 21); } // widget controls @@ -849,11 +845,12 @@ DescriptionDialog::DescriptionDialog(WindowManager& parWindowManager) getWidget(textEdit, "TextEdit"); - // TODO: These buttons should be managed by a Dialog class MyGUI::ButtonPtr okButton; getWidget(okButton, "OKButton"); okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &DescriptionDialog::onOkClicked); okButton->setCaption(mWindowManager.getGameSettingString("sInputMenu1", "")); + int buttonWidth = okButton->getTextSize().width + 24; + okButton->setCoord(234 - buttonWidth, 214, buttonWidth, 24); // Make sure the edit box has focus MyGUI::InputManager::getInstance().setKeyFocusWidget(textEdit); diff --git a/apps/openmw/mwgui/map_window.cpp b/apps/openmw/mwgui/map_window.cpp index 0e9d57c3c2..e0c828fdc4 100644 --- a/apps/openmw/mwgui/map_window.cpp +++ b/apps/openmw/mwgui/map_window.cpp @@ -29,6 +29,9 @@ MapWindow::MapWindow(WindowManager& parWindowManager) : getWidget(mButton, "WorldButton"); mButton->eventMouseButtonClick += MyGUI::newDelegate(this, &MapWindow::onWorldButtonClicked); + mButton->setCaption(mWindowManager.getGameSettingString("sWorld", "")); + int width = mButton->getTextSize().width + 24; + mButton->setCoord(mMainWidget->getSize().width - width - 22, mMainWidget->getSize().height - 64, width, 22); MyGUI::Button* eventbox; getWidget(eventbox, "EventBox"); @@ -97,7 +100,10 @@ void MapWindow::onWorldButtonClicked(MyGUI::Widget* _sender) mGlobalMap->setVisible(mGlobal); mLocalMap->setVisible(!mGlobal); - mButton->setCaption( mGlobal ? "Local" : "World" ); + mButton->setCaption( mGlobal ? mWindowManager.getGameSettingString("sWorld", "") : + mWindowManager.getGameSettingString("sLocal", "")); + int width = mButton->getTextSize().width + 24; + mButton->setCoord(mMainWidget->getSize().width - width - 22, mMainWidget->getSize().height - 64, width, 22); } void MapWindow::onPinToggled() diff --git a/apps/openmw/mwgui/race.cpp b/apps/openmw/mwgui/race.cpp index 9a84f551c2..275759c9f7 100644 --- a/apps/openmw/mwgui/race.cpp +++ b/apps/openmw/mwgui/race.cpp @@ -69,7 +69,6 @@ RaceDialog::RaceDialog(WindowManager& parWindowManager) setText("SpellPowerT", mWindowManager.getGameSettingString("sRaceMenu7", "Specials")); getWidget(spellPowerList, "SpellPowerList"); - // TODO: These buttons should be managed by a Dialog class MyGUI::ButtonPtr backButton; getWidget(backButton, "BackButton"); backButton->setCaption(mWindowManager.getGameSettingString("sBack", "")); @@ -93,18 +92,16 @@ void RaceDialog::setNextButtonShow(bool shown) MyGUI::ButtonPtr okButton; getWidget(okButton, "OKButton"); - // TODO: All hardcoded coords for buttons are temporary, will be replaced with a dynamic system. if (shown) - { - // Adjust back button when next is shown - backButton->setCoord(MyGUI::IntCoord(471 - 18, 397, 53, 23)); - okButton->setCoord(MyGUI::IntCoord(532 - 18, 397, 42 + 18, 23)); - } + okButton->setCaption(mWindowManager.getGameSettingString("sNext", "")); else - { - backButton->setCoord(MyGUI::IntCoord(471, 397, 53, 23)); - okButton->setCoord(MyGUI::IntCoord(532, 397, 42, 23)); - } + okButton->setCaption(mWindowManager.getGameSettingString("sOK", "")); + + int okButtonWidth = okButton->getTextSize().width + 24; + int backButtonWidth = backButton->getTextSize().width + 24; + + okButton->setCoord(574 - okButtonWidth, 397, okButtonWidth, 23); + backButton->setCoord(574 - okButtonWidth - backButtonWidth - 6, 397, backButtonWidth, 23); } void RaceDialog::open() diff --git a/apps/openmw/mwgui/review.cpp b/apps/openmw/mwgui/review.cpp index f531fe5364..7dfe514def 100644 --- a/apps/openmw/mwgui/review.cpp +++ b/apps/openmw/mwgui/review.cpp @@ -90,7 +90,6 @@ ReviewDialog::ReviewDialog(WindowManager& parWindowManager) static_cast(mMainWidget)->eventWindowChangeCoord += MyGUI::newDelegate(this, &ReviewDialog::onWindowResize); - // TODO: These buttons should be managed by a Dialog class MyGUI::ButtonPtr backButton; getWidget(backButton, "BackButton"); backButton->setCaption(mWindowManager.getGameSettingString("sBack", "")); @@ -100,6 +99,11 @@ ReviewDialog::ReviewDialog(WindowManager& parWindowManager) getWidget(okButton, "OKButton"); okButton->setCaption(mWindowManager.getGameSettingString("sOK", "")); okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ReviewDialog::onOkClicked); + + int backButtonWidth = backButton->getTextSize().width + 24; + int okButtonWidth = okButton->getTextSize().width + 24; + okButton->setCoord(502 - okButtonWidth, 372, okButtonWidth, 23); + backButton->setCoord(502 - okButtonWidth - backButtonWidth - 6, 372, backButtonWidth, 23); } void ReviewDialog::open() diff --git a/apps/openmw/mwgui/text_input.cpp b/apps/openmw/mwgui/text_input.cpp index 8ac07e7668..7d84a9b9fd 100644 --- a/apps/openmw/mwgui/text_input.cpp +++ b/apps/openmw/mwgui/text_input.cpp @@ -12,7 +12,6 @@ TextInputDialog::TextInputDialog(WindowManager& parWindowManager) getWidget(textEdit, "TextEdit"); textEdit->eventEditSelectAccept += newDelegate(this, &TextInputDialog::onTextAccepted); - // TODO: These buttons should be managed by a Dialog class MyGUI::ButtonPtr okButton; getWidget(okButton, "OKButton"); okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &TextInputDialog::onOkClicked); @@ -25,16 +24,15 @@ void TextInputDialog::setNextButtonShow(bool shown) { MyGUI::ButtonPtr okButton; getWidget(okButton, "OKButton"); + if (shown) - { - okButton->setCaption("Next"); - okButton->setCoord(MyGUI::IntCoord(264 - 18, 60, 42 + 18, 23)); - } + okButton->setCaption(mWindowManager.getGameSettingString("sNext", "")); else - { - okButton->setCaption("OK"); - okButton->setCoord(MyGUI::IntCoord(264, 60, 42, 23)); - } + okButton->setCaption(mWindowManager.getGameSettingString("sOK", "")); + + int okButtonWidth = okButton->getTextSize().width + 24; + + okButton->setCoord(306 - okButtonWidth, 60, okButtonWidth, 23); } void TextInputDialog::setTextLabel(const std::string &label) diff --git a/apps/openmw/mwgui/tooltips.hpp b/apps/openmw/mwgui/tooltips.hpp index f546f3976e..a3447eb441 100644 --- a/apps/openmw/mwgui/tooltips.hpp +++ b/apps/openmw/mwgui/tooltips.hpp @@ -9,6 +9,18 @@ namespace MWGui { class WindowManager; + // Info about tooltip that is supplied by the MWWorld::Class object + // Not used yet, but it will replace the if-else-if blocks in tooltips.cpp + struct ToolTipInfo + { + public: + std::string caption; + std::string text; + std::string image; + + /// \todo enchantments (armor, cloth, weapons), magic effects (potions, ingredients) + }; + class ToolTips : public OEngine::GUI::Layout { public: diff --git a/files/mygui/openmw_chargen_generate_class_result_layout.xml b/files/mygui/openmw_chargen_generate_class_result_layout.xml index 7ec926eb05..26ebe17e1f 100644 --- a/files/mygui/openmw_chargen_generate_class_result_layout.xml +++ b/files/mygui/openmw_chargen_generate_class_result_layout.xml @@ -1,27 +1,29 @@ - + - + + + - + - + - + diff --git a/files/mygui/openmw_text.skin.xml b/files/mygui/openmw_text.skin.xml index 6ae14c558b..9f87c93b3c 100644 --- a/files/mygui/openmw_text.skin.xml +++ b/files/mygui/openmw_text.skin.xml @@ -94,19 +94,19 @@ - + - + - + From f1b80c6ff7441f7e1b91d6e3c1b166c275dbdedc Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 16 Apr 2012 19:23:24 +0200 Subject: [PATCH 021/325] fixed text input box --- files/mygui/openmw_text_input_layout.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/files/mygui/openmw_text_input_layout.xml b/files/mygui/openmw_text_input_layout.xml index 6a7ad27f01..c8f76b2575 100644 --- a/files/mygui/openmw_text_input_layout.xml +++ b/files/mygui/openmw_text_input_layout.xml @@ -4,10 +4,10 @@ - + - + From 53b48196f953c388546899d4f209a92809e324db Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 16 Apr 2012 19:30:52 +0200 Subject: [PATCH 022/325] add interface for tooltips to MWWorld::Class --- apps/openmw/mwworld/class.cpp | 10 ++++++++++ apps/openmw/mwworld/class.hpp | 7 +++++++ 2 files changed, 17 insertions(+) diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index d49b98d0fb..c886f2348f 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -173,4 +173,14 @@ namespace MWWorld { throw std::runtime_error ("class does not have an down sound"); } + + MWGui::ToolTipInfo Class::getToolTipInfo (const Ptr& ptr) + { + throw std::runtime_error ("class does not have a tool tip"); + } + + bool Class::hasToolTip (const Ptr& ptr) + { + return false; + } } diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index e474e9b926..5441b874d5 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -12,6 +12,7 @@ #include "physicssystem.hpp" #include "../mwrender/renderinginterface.hpp" +#include "../mwgui/tooltips.hpp" namespace Ogre { @@ -86,6 +87,12 @@ namespace MWWorld ///< Return creature stats or throw an exception, if class does not have creature stats /// (default implementation: throw an exceoption) + virtual bool hasToolTip (const Ptr& ptr) const; + ///< @return true if this object has a tooltip when focused (default implementation: false) + + virtual MWGui::ToolTipInfo getToolTipInfo (const Ptr& ptr) const; + ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. + virtual MWMechanics::NpcStats& getNpcStats (const Ptr& ptr) const; ///< Return NPC stats or throw an exception, if class does not have NPC stats /// (default implementation: throw an exceoption) From 282f37b1b71e04ad51cddc35ac924d2435bd6265 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 16 Apr 2012 19:34:46 +0200 Subject: [PATCH 023/325] fix compilation --- apps/openmw/mwworld/class.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index c886f2348f..10368901b7 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -174,12 +174,12 @@ namespace MWWorld throw std::runtime_error ("class does not have an down sound"); } - MWGui::ToolTipInfo Class::getToolTipInfo (const Ptr& ptr) + MWGui::ToolTipInfo Class::getToolTipInfo (const Ptr& ptr) const { throw std::runtime_error ("class does not have a tool tip"); } - bool Class::hasToolTip (const Ptr& ptr) + bool Class::hasToolTip (const Ptr& ptr) const { return false; } From c4825cdb4300391cb84963abdc63c3e9f35df9fb Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 16 Apr 2012 20:20:18 +0200 Subject: [PATCH 024/325] fixed gold pickup sound for international MW versions, fix npc tooltip --- apps/openmw/mwclass/misc.cpp | 5 +++-- apps/openmw/mwgui/tooltips.cpp | 14 ++++++++++++-- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwclass/misc.cpp b/apps/openmw/mwclass/misc.cpp index 84099caaaf..5963440423 100644 --- a/apps/openmw/mwclass/misc.cpp +++ b/apps/openmw/mwclass/misc.cpp @@ -7,6 +7,7 @@ #include "../mwworld/ptr.hpp" #include "../mwworld/actiontake.hpp" +#include "../mwworld/world.hpp" #include "../mwworld/environment.hpp" #include "../mwrender/objects.hpp" @@ -90,7 +91,7 @@ namespace MWClass ESMS::LiveCellRef *ref = ptr.get(); - if (ref->base->name =="Gold") + if (ref->base->name == environment.mWorld->getStore().gameSettings.search("sGold")->str) { return std::string("Item Gold Up"); } @@ -102,7 +103,7 @@ namespace MWClass ESMS::LiveCellRef *ref = ptr.get(); - if (ref->base->name =="Gold") + if (ref->base->name == environment.mWorld->getStore().gameSettings.search("sGold")->str) { return std::string("Item Gold Down"); } diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 25361ffcc6..ce31741689 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -158,7 +158,12 @@ IntSize ToolTips::getToolTipViaPtr () /// \todo We don't want tooltips for NPCs in combat mode. ESMS::LiveCellRef* ref = mFocusObject.get(); - tooltipSize = createToolTip(ref->base->name, ""); + std::string text; + if (mFullHelp) { + text += "\n Script: " + ref->base->script; + } + + tooltipSize = createToolTip(ref->base->name, text); } // -------------------- Creature ------------------------------- @@ -167,7 +172,12 @@ IntSize ToolTips::getToolTipViaPtr () /// \todo We don't want tooltips for Creatures in combat mode. ESMS::LiveCellRef* ref = mFocusObject.get(); - tooltipSize = createToolTip(ref->base->name, ""); + std::string text; + if (mFullHelp) { + text += "\n Script: " + ref->base->script; + } + + tooltipSize = createToolTip(ref->base->name, text); } // -------------------- Container ------------------------------- From cdd4d83d9e4a73ba10e83ee3ae93662783f39056 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 16 Apr 2012 22:58:16 +0200 Subject: [PATCH 025/325] moved the tooltip info to the appropriate MWWorld::Class classes --- apps/openmw/mwclass/activator.cpp | 27 ++- apps/openmw/mwclass/activator.hpp | 6 + apps/openmw/mwclass/apparatus.cpp | 35 +++ apps/openmw/mwclass/apparatus.hpp | 6 + apps/openmw/mwclass/armor.cpp | 49 ++++ apps/openmw/mwclass/armor.hpp | 6 + apps/openmw/mwclass/book.cpp | 35 +++ apps/openmw/mwclass/book.hpp | 6 + apps/openmw/mwclass/clothing.cpp | 36 +++ apps/openmw/mwclass/clothing.hpp | 6 + apps/openmw/mwclass/container.cpp | 36 +++ apps/openmw/mwclass/container.hpp | 6 + apps/openmw/mwclass/creature.cpp | 25 ++ apps/openmw/mwclass/creature.hpp | 6 + apps/openmw/mwclass/door.cpp | 42 ++++ apps/openmw/mwclass/door.hpp | 6 + apps/openmw/mwclass/ingredient.cpp | 36 +++ apps/openmw/mwclass/ingredient.hpp | 6 + apps/openmw/mwclass/light.cpp | 36 +++ apps/openmw/mwclass/light.hpp | 6 + apps/openmw/mwclass/lockpick.cpp | 39 +++ apps/openmw/mwclass/lockpick.hpp | 6 + apps/openmw/mwclass/misc.cpp | 42 ++++ apps/openmw/mwclass/misc.hpp | 6 + apps/openmw/mwclass/npc.cpp | 25 ++ apps/openmw/mwclass/npc.hpp | 6 + apps/openmw/mwclass/potion.cpp | 36 +++ apps/openmw/mwclass/potion.hpp | 6 + apps/openmw/mwclass/probe.cpp | 39 +++ apps/openmw/mwclass/probe.hpp | 6 + apps/openmw/mwclass/repair.cpp | 39 +++ apps/openmw/mwclass/repair.hpp | 6 + apps/openmw/mwclass/weapon.cpp | 41 ++++ apps/openmw/mwclass/weapon.hpp | 6 + apps/openmw/mwgui/tooltips.cpp | 343 +++------------------------ apps/openmw/mwgui/tooltips.hpp | 19 +- apps/openmw/mwgui/window_manager.cpp | 5 + apps/openmw/mwgui/window_manager.hpp | 1 + apps/openmw/mwworld/class.cpp | 2 +- apps/openmw/mwworld/class.hpp | 2 +- 40 files changed, 769 insertions(+), 323 deletions(-) diff --git a/apps/openmw/mwclass/activator.cpp b/apps/openmw/mwclass/activator.cpp index 6749a2bfd1..1f6badce98 100644 --- a/apps/openmw/mwclass/activator.cpp +++ b/apps/openmw/mwclass/activator.cpp @@ -7,7 +7,8 @@ #include #include "../mwworld/ptr.hpp" - +#include "../mwworld/environment.hpp" +#include "../mwgui/window_manager.hpp" namespace MWClass { @@ -63,4 +64,28 @@ namespace MWClass registerClass (typeid (ESM::Activator).name(), instance); } + + bool Activator::hasToolTip (const MWWorld::Ptr& ptr) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + return (ref->base->name != ""); + } + + MWGui::ToolTipInfo Activator::getToolTipInfo (const MWWorld::Ptr& ptr, MWWorld::Environment& environment) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + MWGui::ToolTipInfo info; + info.caption = ref->base->name; + + std::string text; + if (environment.mWindowManager->getFullHelp()) + text += MWGui::ToolTips::getMiscString(ref->base->script, "Script"); + info.text = text; + + return info; + } } diff --git a/apps/openmw/mwclass/activator.hpp b/apps/openmw/mwclass/activator.hpp index 08be8a5ff1..e5d826e58e 100644 --- a/apps/openmw/mwclass/activator.hpp +++ b/apps/openmw/mwclass/activator.hpp @@ -18,6 +18,12 @@ namespace MWClass ///< \return name (the one that is to be presented to the user; not the internal one); /// can return an empty string. + virtual bool hasToolTip (const MWWorld::Ptr& ptr) const; + ///< @return true if this object has a tooltip when focused (default implementation: false) + + virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::Ptr& ptr, MWWorld::Environment& environment) const; + ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. + virtual std::string getScript (const MWWorld::Ptr& ptr) const; ///< Return name of the script attached to ptr diff --git a/apps/openmw/mwclass/apparatus.cpp b/apps/openmw/mwclass/apparatus.cpp index 90db40b5ae..16e5d8f6ec 100644 --- a/apps/openmw/mwclass/apparatus.cpp +++ b/apps/openmw/mwclass/apparatus.cpp @@ -8,9 +8,13 @@ #include "../mwworld/ptr.hpp" #include "../mwworld/actiontake.hpp" #include "../mwworld/environment.hpp" +#include "../mwworld/world.hpp" #include "../mwrender/objects.hpp" +#include "../mwgui/window_manager.hpp" +#include "../mwgui/tooltips.hpp" + #include "../mwsound/soundmanager.hpp" namespace MWClass @@ -94,4 +98,35 @@ namespace MWClass { return std::string("Item Apparatus Down"); } + + bool Apparatus::hasToolTip (const MWWorld::Ptr& ptr) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + return (ref->base->name != ""); + } + + MWGui::ToolTipInfo Apparatus::getToolTipInfo (const MWWorld::Ptr& ptr, MWWorld::Environment& environment) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + MWGui::ToolTipInfo info; + info.caption = ref->base->name; + info.icon = ref->base->icon; + + std::string text; + text += "\n" + environment.mWorld->getStore().gameSettings.search("sQuality")->str + ": " + MWGui::ToolTips::toString(ref->base->data.quality); + text += "\n" + environment.mWorld->getStore().gameSettings.search("sWeight")->str + ": " + MWGui::ToolTips::toString(ref->base->data.weight); + text += MWGui::ToolTips::getValueString(ref->base->data.value, environment.mWorld->getStore().gameSettings.search("sValue")->str); + + if (environment.mWindowManager->getFullHelp()) { + text += MWGui::ToolTips::getMiscString(ref->ref.owner, "Owner"); + text += MWGui::ToolTips::getMiscString(ref->base->script, "Script"); + } + info.text = text; + + return info; + } } diff --git a/apps/openmw/mwclass/apparatus.hpp b/apps/openmw/mwclass/apparatus.hpp index 861610f6cc..d942ac0cb6 100644 --- a/apps/openmw/mwclass/apparatus.hpp +++ b/apps/openmw/mwclass/apparatus.hpp @@ -28,6 +28,12 @@ namespace MWClass virtual int getValue (const MWWorld::Ptr& ptr) const; ///< Return trade value of the object. Throws an exception, if the object can't be traded. + virtual bool hasToolTip (const MWWorld::Ptr& ptr) const; + ///< @return true if this object has a tooltip when focused (default implementation: false) + + virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::Ptr& ptr, MWWorld::Environment& environment) const; + ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. + static void registerSelf(); virtual std::string getUpSoundId (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index 8e1f81136b..dd343b25d0 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -16,6 +16,8 @@ #include "../mwrender/objects.hpp" +#include "../mwgui/window_manager.hpp" + #include "../mwsound/soundmanager.hpp" namespace MWClass @@ -196,4 +198,51 @@ namespace MWClass else return std::string("Item Armor Heavy Down"); } + + bool Armor::hasToolTip (const MWWorld::Ptr& ptr) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + return (ref->base->name != ""); + } + + MWGui::ToolTipInfo Armor::getToolTipInfo (const MWWorld::Ptr& ptr, MWWorld::Environment& environment) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + MWGui::ToolTipInfo info; + info.caption = ref->base->name; + info.icon = ref->base->icon; + + std::string text; + + // get armor type string (light/medium/heavy) + int armorType = getEquipmentSkill(ptr, environment); + std::string typeText; + if (armorType == ESM::Skill::LightArmor) + typeText = environment.mWorld->getStore().gameSettings.search("sLight")->str; + else if (armorType == ESM::Skill::MediumArmor) + typeText = environment.mWorld->getStore().gameSettings.search("sMedium")->str; + else + typeText = environment.mWorld->getStore().gameSettings.search("sHeavy")->str; + + text += "\n" + environment.mWorld->getStore().gameSettings.search("sArmorRating")->str + ": " + MWGui::ToolTips::toString(ref->base->data.armor); + + /// \todo store the current armor health somewhere + text += "\n" + environment.mWorld->getStore().gameSettings.search("sCondition")->str + ": " + MWGui::ToolTips::toString(ref->base->data.health); + + text += "\n" + environment.mWorld->getStore().gameSettings.search("sWeight")->str + ": " + MWGui::ToolTips::toString(ref->base->data.weight) + " (" + typeText + ")"; + text += MWGui::ToolTips::getValueString(ref->base->data.value, environment.mWorld->getStore().gameSettings.search("sValue")->str); + + if (environment.mWindowManager->getFullHelp()) { + text += MWGui::ToolTips::getMiscString(ref->ref.owner, "Owner"); + text += MWGui::ToolTips::getMiscString(ref->base->script, "Script"); + } + + info.text = text; + + return info; + } } diff --git a/apps/openmw/mwclass/armor.hpp b/apps/openmw/mwclass/armor.hpp index de5ca39835..36366db737 100644 --- a/apps/openmw/mwclass/armor.hpp +++ b/apps/openmw/mwclass/armor.hpp @@ -40,6 +40,12 @@ namespace MWClass /// Return the index of the skill this item corresponds to when equiopped or -1, if there is /// no such skill. + virtual bool hasToolTip (const MWWorld::Ptr& ptr) const; + ///< @return true if this object has a tooltip when focused (default implementation: false) + + virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::Ptr& ptr, MWWorld::Environment& environment) const; + ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. + virtual int getValue (const MWWorld::Ptr& ptr) const; ///< Return trade value of the object. Throws an exception, if the object can't be traded. diff --git a/apps/openmw/mwclass/book.cpp b/apps/openmw/mwclass/book.cpp index 9069d94765..f60f879361 100644 --- a/apps/openmw/mwclass/book.cpp +++ b/apps/openmw/mwclass/book.cpp @@ -8,9 +8,12 @@ #include "../mwworld/ptr.hpp" #include "../mwworld/actiontake.hpp" #include "../mwworld/environment.hpp" +#include "../mwworld/world.hpp" #include "../mwrender/objects.hpp" +#include "../mwgui/window_manager.hpp" + #include "../mwsound/soundmanager.hpp" namespace MWClass @@ -96,4 +99,36 @@ namespace MWClass { return std::string("Item Book Down"); } + + bool Book::hasToolTip (const MWWorld::Ptr& ptr) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + return (ref->base->name != ""); + } + + MWGui::ToolTipInfo Book::getToolTipInfo (const MWWorld::Ptr& ptr, MWWorld::Environment& environment) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + MWGui::ToolTipInfo info; + info.caption = ref->base->name; + info.icon = ref->base->icon; + + std::string text; + + text += "\n" + environment.mWorld->getStore().gameSettings.search("sWeight")->str + ": " + MWGui::ToolTips::toString(ref->base->data.weight); + text += MWGui::ToolTips::getValueString(ref->base->data.value, environment.mWorld->getStore().gameSettings.search("sValue")->str); + + if (environment.mWindowManager->getFullHelp()) { + text += MWGui::ToolTips::getMiscString(ref->ref.owner, "Owner"); + text += MWGui::ToolTips::getMiscString(ref->base->script, "Script"); + } + + info.text = text; + + return info; + } } diff --git a/apps/openmw/mwclass/book.hpp b/apps/openmw/mwclass/book.hpp index 4738187cd6..8ed99db912 100644 --- a/apps/openmw/mwclass/book.hpp +++ b/apps/openmw/mwclass/book.hpp @@ -25,6 +25,12 @@ namespace MWClass virtual std::string getScript (const MWWorld::Ptr& ptr) const; ///< Return name of the script attached to ptr + virtual bool hasToolTip (const MWWorld::Ptr& ptr) const; + ///< @return true if this object has a tooltip when focused (default implementation: false) + + virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::Ptr& ptr, MWWorld::Environment& environment) const; + ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. + virtual int getValue (const MWWorld::Ptr& ptr) const; ///< Return trade value of the object. Throws an exception, if the object can't be traded. diff --git a/apps/openmw/mwclass/clothing.cpp b/apps/openmw/mwclass/clothing.cpp index 672a2b60a0..6835ad2ede 100644 --- a/apps/openmw/mwclass/clothing.cpp +++ b/apps/openmw/mwclass/clothing.cpp @@ -9,6 +9,10 @@ #include "../mwworld/actiontake.hpp" #include "../mwworld/environment.hpp" #include "../mwworld/inventorystore.hpp" +#include "../mwworld/world.hpp" + +#include "../mwgui/tooltips.hpp" +#include "../mwgui/window_manager.hpp" #include "../mwrender/objects.hpp" @@ -161,4 +165,36 @@ namespace MWClass } return std::string("Item Clothes Down"); } + + bool Clothing::hasToolTip (const MWWorld::Ptr& ptr) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + return (ref->base->name != ""); + } + + MWGui::ToolTipInfo Clothing::getToolTipInfo (const MWWorld::Ptr& ptr, MWWorld::Environment& environment) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + MWGui::ToolTipInfo info; + info.caption = ref->base->name; + info.icon = ref->base->icon; + + std::string text; + + text += "\n" + environment.mWorld->getStore().gameSettings.search("sWeight")->str + ": " + MWGui::ToolTips::toString(ref->base->data.weight); + text += MWGui::ToolTips::getValueString(ref->base->data.value, environment.mWorld->getStore().gameSettings.search("sValue")->str); + + if (environment.mWindowManager->getFullHelp()) { + text += MWGui::ToolTips::getMiscString(ref->ref.owner, "Owner"); + text += MWGui::ToolTips::getMiscString(ref->base->script, "Script"); + } + + info.text = text; + + return info; + } } diff --git a/apps/openmw/mwclass/clothing.hpp b/apps/openmw/mwclass/clothing.hpp index 97e09012d5..04bab0edc8 100644 --- a/apps/openmw/mwclass/clothing.hpp +++ b/apps/openmw/mwclass/clothing.hpp @@ -34,6 +34,12 @@ namespace MWClass /// Return the index of the skill this item corresponds to when equiopped or -1, if there is /// no such skill. + virtual bool hasToolTip (const MWWorld::Ptr& ptr) const; + ///< @return true if this object has a tooltip when focused (default implementation: false) + + virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::Ptr& ptr, MWWorld::Environment& environment) const; + ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. + virtual int getValue (const MWWorld::Ptr& ptr) const; ///< Return trade value of the object. Throws an exception, if the object can't be traded. diff --git a/apps/openmw/mwclass/container.cpp b/apps/openmw/mwclass/container.cpp index 29b3331ba9..23c640dc97 100644 --- a/apps/openmw/mwclass/container.cpp +++ b/apps/openmw/mwclass/container.cpp @@ -10,6 +10,10 @@ #include "../mwworld/containerstore.hpp" #include "../mwworld/customdata.hpp" #include "../mwworld/environment.hpp" +#include "../mwworld/world.hpp" + +#include "../mwgui/window_manager.hpp" +#include "../mwgui/tooltips.hpp" #include "../mwrender/objects.hpp" @@ -137,4 +141,36 @@ namespace MWClass registerClass (typeid (ESM::Container).name(), instance); } + + bool Container::hasToolTip (const MWWorld::Ptr& ptr) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + return (ref->base->name != ""); + } + + MWGui::ToolTipInfo Container::getToolTipInfo (const MWWorld::Ptr& ptr, MWWorld::Environment& environment) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + MWGui::ToolTipInfo info; + info.caption = ref->base->name; + + std::string text; + if (ref->ref.lockLevel > 0) + text += "\n" + environment.mWorld->getStore().gameSettings.search("sLockLevel")->str + ": " + MWGui::ToolTips::toString(ref->ref.lockLevel); + if (ref->ref.trap != "") + text += "\n" + environment.mWorld->getStore().gameSettings.search("sTrapped")->str; + + if (environment.mWindowManager->getFullHelp()) { + text += MWGui::ToolTips::getMiscString(ref->ref.owner, "Owner"); + text += MWGui::ToolTips::getMiscString(ref->base->script, "Script"); + } + + info.text = text; + + return info; + } } diff --git a/apps/openmw/mwclass/container.hpp b/apps/openmw/mwclass/container.hpp index 387714176b..3ff40c9177 100644 --- a/apps/openmw/mwclass/container.hpp +++ b/apps/openmw/mwclass/container.hpp @@ -24,6 +24,12 @@ namespace MWClass const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const; ///< Generate action for activation + virtual bool hasToolTip (const MWWorld::Ptr& ptr) const; + ///< @return true if this object has a tooltip when focused (default implementation: false) + + virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::Ptr& ptr, MWWorld::Environment& environment) const; + ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. + virtual MWWorld::ContainerStore& getContainerStore (const MWWorld::Ptr& ptr) const; ///< Return container store diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 7270fd22b9..8d5a53969b 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -12,6 +12,8 @@ #include "../mwworld/customdata.hpp" #include "../mwworld/containerstore.hpp" +#include "../mwgui/window_manager.hpp" + namespace { struct CustomData : public MWWorld::CustomData @@ -140,4 +142,27 @@ namespace MWClass registerClass (typeid (ESM::Creature).name(), instance); } + + bool Creature::hasToolTip (const MWWorld::Ptr& ptr) const + { + /// \todo We don't want tooltips for Creatures in combat mode. + + return true; + } + + MWGui::ToolTipInfo Creature::getToolTipInfo (const MWWorld::Ptr& ptr, MWWorld::Environment& environment) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + MWGui::ToolTipInfo info; + info.caption = ref->base->name; + + std::string text; + if (environment.mWindowManager->getFullHelp()) + text += MWGui::ToolTips::getMiscString(ref->base->script, "Script"); + info.text = text; + + return info; + } } diff --git a/apps/openmw/mwclass/creature.hpp b/apps/openmw/mwclass/creature.hpp index 8eb45e8381..61d9267f9b 100644 --- a/apps/openmw/mwclass/creature.hpp +++ b/apps/openmw/mwclass/creature.hpp @@ -32,6 +32,12 @@ namespace MWClass ///< \return name (the one that is to be presented to the user; not the internal one); /// can return an empty string. + virtual bool hasToolTip (const MWWorld::Ptr& ptr) const; + ///< @return true if this object has a tooltip when focused (default implementation: false) + + virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::Ptr& ptr, MWWorld::Environment& environment) const; + ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. + virtual MWMechanics::CreatureStats& getCreatureStats (const MWWorld::Ptr& ptr) const; ///< Return creature stats diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index 9d6c6a78dc..e06fdecda8 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -12,6 +12,9 @@ #include "../mwworld/environment.hpp" #include "../mwworld/world.hpp" +#include "../mwgui/window_manager.hpp" +#include "../mwgui/tooltips.hpp" + #include "../mwrender/objects.hpp" #include "../mwsound/soundmanager.hpp" @@ -142,4 +145,43 @@ namespace MWClass registerClass (typeid (ESM::Door).name(), instance); } + + bool Door::hasToolTip (const MWWorld::Ptr& ptr) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + return (ref->base->name != ""); + } + + MWGui::ToolTipInfo Door::getToolTipInfo (const MWWorld::Ptr& ptr, MWWorld::Environment& environment) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + MWGui::ToolTipInfo info; + info.caption = ref->base->name; + + std::string text; + + /// \todo If destCell is empty, the teleport target is an exterior cell. In that case we + /// need to fetch that cell (via target position) and retrieve the region name. + if (ref->ref.teleport && (ref->ref.destCell != "")) + { + text += "\n" + environment.mWorld->getStore().gameSettings.search("sTo")->str; + text += "\n"+ref->ref.destCell; + } + + if (ref->ref.lockLevel > 0) + text += "\n" + environment.mWorld->getStore().gameSettings.search("sLockLevel")->str + ": " + MWGui::ToolTips::toString(ref->ref.lockLevel); + if (ref->ref.trap != "") + text += "\n" + environment.mWorld->getStore().gameSettings.search("sTrapped")->str; + + if (environment.mWindowManager->getFullHelp()) + text += MWGui::ToolTips::getMiscString(ref->base->script, "Script"); + + info.text = text; + + return info; + } } diff --git a/apps/openmw/mwclass/door.hpp b/apps/openmw/mwclass/door.hpp index aecb4224cc..c7b7f5d8ce 100644 --- a/apps/openmw/mwclass/door.hpp +++ b/apps/openmw/mwclass/door.hpp @@ -22,6 +22,12 @@ namespace MWClass const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const; ///< Generate action for activation + virtual bool hasToolTip (const MWWorld::Ptr& ptr) const; + ///< @return true if this object has a tooltip when focused (default implementation: false) + + virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::Ptr& ptr, MWWorld::Environment& environment) const; + ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. + virtual void lock (const MWWorld::Ptr& ptr, int lockLevel) const; ///< Lock object diff --git a/apps/openmw/mwclass/ingredient.cpp b/apps/openmw/mwclass/ingredient.cpp index 9707e79a8f..a22f5c60ad 100644 --- a/apps/openmw/mwclass/ingredient.cpp +++ b/apps/openmw/mwclass/ingredient.cpp @@ -8,6 +8,10 @@ #include "../mwworld/ptr.hpp" #include "../mwworld/actiontake.hpp" #include "../mwworld/environment.hpp" +#include "../mwworld/world.hpp" + +#include "../mwgui/window_manager.hpp" +#include "../mwgui/tooltips.hpp" #include "../mwrender/objects.hpp" @@ -92,4 +96,36 @@ namespace MWClass { return std::string("Item Ingredient Down"); } + + bool Ingredient::hasToolTip (const MWWorld::Ptr& ptr) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + return (ref->base->name != ""); + } + + MWGui::ToolTipInfo Ingredient::getToolTipInfo (const MWWorld::Ptr& ptr, MWWorld::Environment& environment) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + MWGui::ToolTipInfo info; + info.caption = ref->base->name; + info.icon = ref->base->icon; + + std::string text; + + text += "\n" + environment.mWorld->getStore().gameSettings.search("sWeight")->str + ": " + MWGui::ToolTips::toString(ref->base->data.weight); + text += MWGui::ToolTips::getValueString(ref->base->data.value, environment.mWorld->getStore().gameSettings.search("sValue")->str); + + if (environment.mWindowManager->getFullHelp()) { + text += MWGui::ToolTips::getMiscString(ref->ref.owner, "Owner"); + text += MWGui::ToolTips::getMiscString(ref->base->script, "Script"); + } + + info.text = text; + + return info; + } } diff --git a/apps/openmw/mwclass/ingredient.hpp b/apps/openmw/mwclass/ingredient.hpp index 2d77176727..ba241c2f3b 100644 --- a/apps/openmw/mwclass/ingredient.hpp +++ b/apps/openmw/mwclass/ingredient.hpp @@ -22,6 +22,12 @@ namespace MWClass const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const; ///< Generate action for activation + virtual bool hasToolTip (const MWWorld::Ptr& ptr) const; + ///< @return true if this object has a tooltip when focused (default implementation: false) + + virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::Ptr& ptr, MWWorld::Environment& environment) const; + ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. + virtual std::string getScript (const MWWorld::Ptr& ptr) const; ///< Return name of the script attached to ptr diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index f67dd4cf05..c01017aafb 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -10,6 +10,10 @@ #include "../mwworld/nullaction.hpp" #include "../mwworld/environment.hpp" #include "../mwworld/inventorystore.hpp" +#include "../mwworld/world.hpp" + +#include "../mwgui/window_manager.hpp" +#include "../mwgui/tooltips.hpp" #include "../mwsound/soundmanager.hpp" @@ -134,4 +138,36 @@ namespace MWClass { return std::string("Item Misc Down"); } + + bool Light::hasToolTip (const MWWorld::Ptr& ptr) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + return (ref->base->name != ""); + } + + MWGui::ToolTipInfo Light::getToolTipInfo (const MWWorld::Ptr& ptr, MWWorld::Environment& environment) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + MWGui::ToolTipInfo info; + info.caption = ref->base->name; + info.icon = ref->base->icon; + + std::string text; + + text += "\n" + environment.mWorld->getStore().gameSettings.search("sWeight")->str + ": " + MWGui::ToolTips::toString(ref->base->data.weight); + text += MWGui::ToolTips::getValueString(ref->base->data.value, environment.mWorld->getStore().gameSettings.search("sValue")->str); + + if (environment.mWindowManager->getFullHelp()) { + text += MWGui::ToolTips::getMiscString(ref->ref.owner, "Owner"); + text += MWGui::ToolTips::getMiscString(ref->base->script, "Script"); + } + + info.text = text; + + return info; + } } diff --git a/apps/openmw/mwclass/light.hpp b/apps/openmw/mwclass/light.hpp index bde252c289..347e551907 100644 --- a/apps/openmw/mwclass/light.hpp +++ b/apps/openmw/mwclass/light.hpp @@ -23,6 +23,12 @@ namespace MWClass ///< \return name (the one that is to be presented to the user; not the internal one); /// can return an empty string. + virtual bool hasToolTip (const MWWorld::Ptr& ptr) const; + ///< @return true if this object has a tooltip when focused (default implementation: false) + + virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::Ptr& ptr, MWWorld::Environment& environment) const; + ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. + virtual boost::shared_ptr activate (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const; ///< Generate action for activation diff --git a/apps/openmw/mwclass/lockpick.cpp b/apps/openmw/mwclass/lockpick.cpp index 76bc3948f6..36a097babe 100644 --- a/apps/openmw/mwclass/lockpick.cpp +++ b/apps/openmw/mwclass/lockpick.cpp @@ -9,6 +9,9 @@ #include "../mwworld/actiontake.hpp" #include "../mwworld/environment.hpp" #include "../mwworld/inventorystore.hpp" +#include "../mwworld/world.hpp" +#include "../mwgui/window_manager.hpp" +#include "../mwgui/tooltips.hpp" #include "../mwrender/objects.hpp" @@ -105,4 +108,40 @@ namespace MWClass { return std::string("Item Lockpick Down"); } + + bool Lockpick::hasToolTip (const MWWorld::Ptr& ptr) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + return (ref->base->name != ""); + } + + MWGui::ToolTipInfo Lockpick::getToolTipInfo (const MWWorld::Ptr& ptr, MWWorld::Environment& environment) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + MWGui::ToolTipInfo info; + info.caption = ref->base->name; + info.icon = ref->base->icon; + + std::string text; + + /// \todo store remaining uses somewhere + + text += "\n" + environment.mWorld->getStore().gameSettings.search("sUses")->str + ": " + MWGui::ToolTips::toString(ref->base->data.uses); + text += "\n" + environment.mWorld->getStore().gameSettings.search("sQuality")->str + ": " + MWGui::ToolTips::toString(ref->base->data.quality); + text += "\n" + environment.mWorld->getStore().gameSettings.search("sWeight")->str + ": " + MWGui::ToolTips::toString(ref->base->data.weight); + text += MWGui::ToolTips::getValueString(ref->base->data.value, environment.mWorld->getStore().gameSettings.search("sValue")->str); + + if (environment.mWindowManager->getFullHelp()) { + text += MWGui::ToolTips::getMiscString(ref->ref.owner, "Owner"); + text += MWGui::ToolTips::getMiscString(ref->base->script, "Script"); + } + + info.text = text; + + return info; + } } diff --git a/apps/openmw/mwclass/lockpick.hpp b/apps/openmw/mwclass/lockpick.hpp index 1b56234af1..8b5f658f56 100644 --- a/apps/openmw/mwclass/lockpick.hpp +++ b/apps/openmw/mwclass/lockpick.hpp @@ -22,6 +22,12 @@ namespace MWClass const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const; ///< Generate action for activation + virtual bool hasToolTip (const MWWorld::Ptr& ptr) const; + ///< @return true if this object has a tooltip when focused (default implementation: false) + + virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::Ptr& ptr, MWWorld::Environment& environment) const; + ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. + virtual std::string getScript (const MWWorld::Ptr& ptr) const; ///< Return name of the script attached to ptr diff --git a/apps/openmw/mwclass/misc.cpp b/apps/openmw/mwclass/misc.cpp index 5963440423..8cd2554a10 100644 --- a/apps/openmw/mwclass/misc.cpp +++ b/apps/openmw/mwclass/misc.cpp @@ -10,10 +10,15 @@ #include "../mwworld/world.hpp" #include "../mwworld/environment.hpp" +#include "../mwgui/window_manager.hpp" +#include "../mwgui/tooltips.hpp" + #include "../mwrender/objects.hpp" #include "../mwsound/soundmanager.hpp" +#include + namespace MWClass { void Miscellaneous::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const @@ -109,4 +114,41 @@ namespace MWClass } return std::string("Item Misc Down"); } + + bool Miscellaneous::hasToolTip (const MWWorld::Ptr& ptr) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + return (ref->base->name != ""); + } + + MWGui::ToolTipInfo Miscellaneous::getToolTipInfo (const MWWorld::Ptr& ptr, MWWorld::Environment& environment) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + MWGui::ToolTipInfo info; + info.caption = ref->base->name; + info.icon = ref->base->icon; + + std::string text; + + if (ref->base->name == environment.mWorld->getStore().gameSettings.search("sGold")->str) + info.caption += " (" + boost::lexical_cast(ref->base->data.value) + ")"; + else + { + text += "\n" + environment.mWorld->getStore().gameSettings.search("sWeight")->str + ": " + MWGui::ToolTips::toString(ref->base->data.weight); + text += MWGui::ToolTips::getValueString(ref->base->data.value, environment.mWorld->getStore().gameSettings.search("sValue")->str); + } + + if (environment.mWindowManager->getFullHelp()) { + text += MWGui::ToolTips::getMiscString(ref->ref.owner, "Owner"); + text += MWGui::ToolTips::getMiscString(ref->base->script, "Script"); + } + + info.text = text; + + return info; + } } diff --git a/apps/openmw/mwclass/misc.hpp b/apps/openmw/mwclass/misc.hpp index fc002280cf..dda8a352e8 100644 --- a/apps/openmw/mwclass/misc.hpp +++ b/apps/openmw/mwclass/misc.hpp @@ -22,6 +22,12 @@ namespace MWClass const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const; ///< Generate action for activation + virtual bool hasToolTip (const MWWorld::Ptr& ptr) const; + ///< @return true if this object has a tooltip when focused (default implementation: false) + + virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::Ptr& ptr, MWWorld::Environment& environment) const; + ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. + virtual std::string getScript (const MWWorld::Ptr& ptr) const; ///< Return name of the script attached to ptr diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index c053ad1306..7f78d53f34 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -19,6 +19,8 @@ #include "../mwworld/inventorystore.hpp" #include "../mwworld/customdata.hpp" +#include "../mwgui/window_manager.hpp" + namespace { const Ogre::Radian kOgrePi (Ogre::Math::PI); @@ -299,4 +301,27 @@ namespace MWClass std::cout << "class npc:" << typeid (ESM::NPC).name(); registerClass (typeid (ESM::NPC).name(), instance); } + + bool Npc::hasToolTip (const MWWorld::Ptr& ptr) const + { + /// \todo We don't want tooltips for NPCs in combat mode. + + return true; + } + + MWGui::ToolTipInfo Npc::getToolTipInfo (const MWWorld::Ptr& ptr, MWWorld::Environment& environment) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + MWGui::ToolTipInfo info; + info.caption = ref->base->name; + + std::string text; + if (environment.mWindowManager->getFullHelp()) + text += MWGui::ToolTips::getMiscString(ref->base->script, "Script"); + info.text = text; + + return info; + } } diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index f210eda5f0..46eccf26a8 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -38,6 +38,12 @@ namespace MWClass virtual MWWorld::ContainerStore& getContainerStore (const MWWorld::Ptr& ptr) const; ///< Return container store + virtual bool hasToolTip (const MWWorld::Ptr& ptr) const; + ///< @return true if this object has a tooltip when focused (default implementation: false) + + virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::Ptr& ptr, MWWorld::Environment& environment) const; + ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. + virtual MWWorld::InventoryStore& getInventoryStore (const MWWorld::Ptr& ptr) const; ///< Return inventory store diff --git a/apps/openmw/mwclass/potion.cpp b/apps/openmw/mwclass/potion.cpp index 642211df3c..2936afd19c 100644 --- a/apps/openmw/mwclass/potion.cpp +++ b/apps/openmw/mwclass/potion.cpp @@ -8,6 +8,10 @@ #include "../mwworld/ptr.hpp" #include "../mwworld/actiontake.hpp" #include "../mwworld/environment.hpp" +#include "../mwworld/world.hpp" + +#include "../mwgui/window_manager.hpp" +#include "../mwgui/tooltips.hpp" #include "../mwrender/objects.hpp" @@ -94,4 +98,36 @@ namespace MWClass { return std::string("Item Potion Down"); } + + bool Potion::hasToolTip (const MWWorld::Ptr& ptr) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + return (ref->base->name != ""); + } + + MWGui::ToolTipInfo Potion::getToolTipInfo (const MWWorld::Ptr& ptr, MWWorld::Environment& environment) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + MWGui::ToolTipInfo info; + info.caption = ref->base->name; + info.icon = ref->base->icon; + + std::string text; + + text += "\n" + environment.mWorld->getStore().gameSettings.search("sWeight")->str + ": " + MWGui::ToolTips::toString(ref->base->data.weight); + text += MWGui::ToolTips::getValueString(ref->base->data.value, environment.mWorld->getStore().gameSettings.search("sValue")->str); + + if (environment.mWindowManager->getFullHelp()) { + text += MWGui::ToolTips::getMiscString(ref->ref.owner, "Owner"); + text += MWGui::ToolTips::getMiscString(ref->base->script, "Script"); + } + + info.text = text; + + return info; + } } diff --git a/apps/openmw/mwclass/potion.hpp b/apps/openmw/mwclass/potion.hpp index 7d30179376..7b98fd897f 100644 --- a/apps/openmw/mwclass/potion.hpp +++ b/apps/openmw/mwclass/potion.hpp @@ -22,6 +22,12 @@ namespace MWClass const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const; ///< Generate action for activation + virtual bool hasToolTip (const MWWorld::Ptr& ptr) const; + ///< @return true if this object has a tooltip when focused (default implementation: false) + + virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::Ptr& ptr, MWWorld::Environment& environment) const; + ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. + virtual std::string getScript (const MWWorld::Ptr& ptr) const; ///< Return name of the script attached to ptr diff --git a/apps/openmw/mwclass/probe.cpp b/apps/openmw/mwclass/probe.cpp index 923c29ee69..c70368642d 100644 --- a/apps/openmw/mwclass/probe.cpp +++ b/apps/openmw/mwclass/probe.cpp @@ -9,6 +9,9 @@ #include "../mwworld/actiontake.hpp" #include "../mwworld/environment.hpp" #include "../mwworld/inventorystore.hpp" +#include "../mwworld/world.hpp" +#include "../mwgui/window_manager.hpp" +#include "../mwgui/tooltips.hpp" #include "../mwrender/objects.hpp" @@ -104,4 +107,40 @@ namespace MWClass { return std::string("Item Probe Down"); } + + bool Probe::hasToolTip (const MWWorld::Ptr& ptr) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + return (ref->base->name != ""); + } + + MWGui::ToolTipInfo Probe::getToolTipInfo (const MWWorld::Ptr& ptr, MWWorld::Environment& environment) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + MWGui::ToolTipInfo info; + info.caption = ref->base->name; + info.icon = ref->base->icon; + + std::string text; + + /// \todo store remaining uses somewhere + + text += "\n" + environment.mWorld->getStore().gameSettings.search("sUses")->str + ": " + MWGui::ToolTips::toString(ref->base->data.uses); + text += "\n" + environment.mWorld->getStore().gameSettings.search("sQuality")->str + ": " + MWGui::ToolTips::toString(ref->base->data.quality); + text += "\n" + environment.mWorld->getStore().gameSettings.search("sWeight")->str + ": " + MWGui::ToolTips::toString(ref->base->data.weight); + text += MWGui::ToolTips::getValueString(ref->base->data.value, environment.mWorld->getStore().gameSettings.search("sValue")->str); + + if (environment.mWindowManager->getFullHelp()) { + text += MWGui::ToolTips::getMiscString(ref->ref.owner, "Owner"); + text += MWGui::ToolTips::getMiscString(ref->base->script, "Script"); + } + + info.text = text; + + return info; + } } diff --git a/apps/openmw/mwclass/probe.hpp b/apps/openmw/mwclass/probe.hpp index 232b523645..e454279a19 100644 --- a/apps/openmw/mwclass/probe.hpp +++ b/apps/openmw/mwclass/probe.hpp @@ -22,6 +22,12 @@ namespace MWClass const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const; ///< Generate action for activation + virtual bool hasToolTip (const MWWorld::Ptr& ptr) const; + ///< @return true if this object has a tooltip when focused (default implementation: false) + + virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::Ptr& ptr, MWWorld::Environment& environment) const; + ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. + virtual std::string getScript (const MWWorld::Ptr& ptr) const; ///< Return name of the script attached to ptr diff --git a/apps/openmw/mwclass/repair.cpp b/apps/openmw/mwclass/repair.cpp index d6433f5df5..2befdaac93 100644 --- a/apps/openmw/mwclass/repair.cpp +++ b/apps/openmw/mwclass/repair.cpp @@ -8,6 +8,9 @@ #include "../mwworld/ptr.hpp" #include "../mwworld/actiontake.hpp" #include "../mwworld/environment.hpp" +#include "../mwworld/world.hpp" +#include "../mwgui/window_manager.hpp" +#include "../mwgui/tooltips.hpp" #include "../mwrender/objects.hpp" @@ -94,4 +97,40 @@ namespace MWClass { return std::string("Item Repair Down"); } + + bool Repair::hasToolTip (const MWWorld::Ptr& ptr) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + return (ref->base->name != ""); + } + + MWGui::ToolTipInfo Repair::getToolTipInfo (const MWWorld::Ptr& ptr, MWWorld::Environment& environment) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + MWGui::ToolTipInfo info; + info.caption = ref->base->name; + info.icon = ref->base->icon; + + std::string text; + + /// \todo store remaining uses somewhere + + text += "\n" + environment.mWorld->getStore().gameSettings.search("sUses")->str + ": " + MWGui::ToolTips::toString(ref->base->data.uses); + text += "\n" + environment.mWorld->getStore().gameSettings.search("sQuality")->str + ": " + MWGui::ToolTips::toString(ref->base->data.quality); + text += "\n" + environment.mWorld->getStore().gameSettings.search("sWeight")->str + ": " + MWGui::ToolTips::toString(ref->base->data.weight); + text += MWGui::ToolTips::getValueString(ref->base->data.value, environment.mWorld->getStore().gameSettings.search("sValue")->str); + + if (environment.mWindowManager->getFullHelp()) { + text += MWGui::ToolTips::getMiscString(ref->ref.owner, "Owner"); + text += MWGui::ToolTips::getMiscString(ref->base->script, "Script"); + } + + info.text = text; + + return info; + } } diff --git a/apps/openmw/mwclass/repair.hpp b/apps/openmw/mwclass/repair.hpp index 0a9d9c2535..2b8eba2f4b 100644 --- a/apps/openmw/mwclass/repair.hpp +++ b/apps/openmw/mwclass/repair.hpp @@ -22,6 +22,12 @@ namespace MWClass const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const; ///< Generate action for activation + virtual bool hasToolTip (const MWWorld::Ptr& ptr) const; + ///< @return true if this object has a tooltip when focused (default implementation: false) + + virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::Ptr& ptr, MWWorld::Environment& environment) const; + ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. + virtual std::string getScript (const MWWorld::Ptr& ptr) const; ///< Return name of the script attached to ptr diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index 7790e6a80b..1fb8715729 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -9,6 +9,10 @@ #include "../mwworld/actiontake.hpp" #include "../mwworld/environment.hpp" #include "../mwworld/inventorystore.hpp" +#include "../mwworld/world.hpp" + +#include "../mwgui/window_manager.hpp" +#include "../mwgui/tooltips.hpp" #include "../mwrender/objects.hpp" @@ -245,4 +249,41 @@ namespace MWClass return std::string("Item Misc Down"); } + + bool Weapon::hasToolTip (const MWWorld::Ptr& ptr) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + return (ref->base->name != ""); + } + + MWGui::ToolTipInfo Weapon::getToolTipInfo (const MWWorld::Ptr& ptr, MWWorld::Environment& environment) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + MWGui::ToolTipInfo info; + info.caption = ref->base->name; + info.icon = ref->base->icon; + + std::string text; + + /// \todo weapon type, damage + + /// \todo store the current weapon health somewhere + text += "\n" + environment.mWorld->getStore().gameSettings.search("sCondition")->str + ": " + MWGui::ToolTips::toString(ref->base->data.health); + + text += "\n" + environment.mWorld->getStore().gameSettings.search("sWeight")->str + ": " + MWGui::ToolTips::toString(ref->base->data.weight); + text += MWGui::ToolTips::getValueString(ref->base->data.value, environment.mWorld->getStore().gameSettings.search("sValue")->str); + + if (environment.mWindowManager->getFullHelp()) { + text += MWGui::ToolTips::getMiscString(ref->ref.owner, "Owner"); + text += MWGui::ToolTips::getMiscString(ref->base->script, "Script"); + } + + info.text = text; + + return info; + } } diff --git a/apps/openmw/mwclass/weapon.hpp b/apps/openmw/mwclass/weapon.hpp index 505c45645f..1956ec1a94 100644 --- a/apps/openmw/mwclass/weapon.hpp +++ b/apps/openmw/mwclass/weapon.hpp @@ -22,6 +22,12 @@ namespace MWClass const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const; ///< Generate action for activation + virtual bool hasToolTip (const MWWorld::Ptr& ptr) const; + ///< @return true if this object has a tooltip when focused (default implementation: false) + + virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::Ptr& ptr, MWWorld::Environment& environment) const; + ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. + virtual bool hasItemHealth (const MWWorld::Ptr& ptr) const; ///< \return Item health data available? diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index ce31741689..345ed847b3 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -1,6 +1,8 @@ #include "tooltips.hpp" #include "window_manager.hpp" +#include "../mwworld/class.hpp" + #include using namespace MWGui; @@ -130,314 +132,24 @@ IntSize ToolTips::getToolTipViaPtr () IntSize tooltipSize; - // -------------------- Door ------------------------------- - if (mFocusObject.getTypeName() == typeid(ESM::Door).name()) + const MWWorld::Class& object = MWWorld::Class::get (mFocusObject); + if (!object.hasToolTip(mFocusObject)) { - ESMS::LiveCellRef* ref = mFocusObject.get(); - - std::string text; - /// \todo If destCell is empty, the teleport target is an exterior cell. In that case we - /// need to fetch that cell (via target position) and retrieve the region name. - if (ref->ref.teleport && (ref->ref.destCell != "")) - { - text += "\n" + mWindowManager->getGameSettingString("sTo", "to"); - text += "\n"+ref->ref.destCell; - } - - if (ref->ref.lockLevel > 0) - text += "\n" + mWindowManager->getGameSettingString("sLockLevel", "Lock") + ": " + toString(ref->ref.lockLevel); - if (ref->ref.trap != "") - text += "\n" + mWindowManager->getGameSettingString("sTrapped", "Trapped!"); - - tooltipSize = createToolTip(ref->base->name, text); + mDynamicToolTipBox->setVisible(false); } - - // -------------------- NPC ------------------------------- - else if (mFocusObject.getTypeName() == typeid(ESM::NPC).name()) - { - /// \todo We don't want tooltips for NPCs in combat mode. - ESMS::LiveCellRef* ref = mFocusObject.get(); - - std::string text; - if (mFullHelp) { - text += "\n Script: " + ref->base->script; - } - - tooltipSize = createToolTip(ref->base->name, text); - } - - // -------------------- Creature ------------------------------- - else if (mFocusObject.getTypeName() == typeid(ESM::Creature).name()) - { - /// \todo We don't want tooltips for Creatures in combat mode. - ESMS::LiveCellRef* ref = mFocusObject.get(); - - std::string text; - if (mFullHelp) { - text += "\n Script: " + ref->base->script; - } - - tooltipSize = createToolTip(ref->base->name, text); - } - - // -------------------- Container ------------------------------- - else if (mFocusObject.getTypeName() == typeid(ESM::Container).name()) - { - ESMS::LiveCellRef* ref = mFocusObject.get(); - - std::string text; - - if (ref->ref.lockLevel > 0) - text += "\n" + mWindowManager->getGameSettingString("sLockLevel", "Lock") + ": " + toString(ref->ref.lockLevel); - if (ref->ref.trap != "") - text += "\n" + mWindowManager->getGameSettingString("sTrapped", "Trapped!"); - - if (mFullHelp) { - text += "\n Owner: " + ref->ref.owner; - text += "\n Script: " + ref->base->script; - } - - tooltipSize = createToolTip(ref->base->name, text); - } - - // -------------------- Potion ------------------------------- - else if (mFocusObject.getTypeName() == typeid(ESM::Potion).name()) - { - ESMS::LiveCellRef* ref = mFocusObject.get(); - - /// \todo magic effects - std::string text; - text += "\n" + mWindowManager->getGameSettingString("sWeight", "Weight") + ": " + toString(ref->base->data.weight); - text += getValueString(ref->base->data.value); - - if (mFullHelp) { - text += "\n Owner: " + ref->ref.owner; - text += "\n Script: " + ref->base->script; - } - - tooltipSize = createImageToolTip(ref->base->name, ref->base->icon, 32, text); - } - - // -------------------- Apparatus ------------------------------- - else if (mFocusObject.getTypeName() == typeid(ESM::Apparatus).name()) - { - ESMS::LiveCellRef* ref = mFocusObject.get(); - - std::string text; - text += "\n" + mWindowManager->getGameSettingString("sQuality", "Quality") + ": " + toString(ref->base->data.quality); - text += "\n" + mWindowManager->getGameSettingString("sWeight", "Weight") + ": " + toString(ref->base->data.weight); - text += getValueString(ref->base->data.value); - - if (mFullHelp) { - text += "\n Owner: " + ref->ref.owner; - text += "\n Script: " + ref->base->script; - } - - tooltipSize = createImageToolTip(ref->base->name, ref->base->icon, 32, text); - } - - // -------------------- Armor ------------------------------- - else if (mFocusObject.getTypeName() == typeid(ESM::Armor).name()) - { - ESMS::LiveCellRef* ref = mFocusObject.get(); - - /// \todo magic effects, armor type (medium/light/heavy) - std::string text; - text += "\n" + mWindowManager->getGameSettingString("sArmorRating", "Armor Rating") + ": " + toString(ref->base->data.armor); - - /// \todo where is the current armor health stored? - //text += "\n" + mWindowManager->getGameSettingString("sCondition", "Condition") + ": " + toString(ref->base->data.health); - text += "\n" + mWindowManager->getGameSettingString("sWeight", "Weight") + ": " + toString(ref->base->data.weight); - text += getValueString(ref->base->data.value); - - if (mFullHelp) { - text += "\n Owner: " + ref->ref.owner; - text += "\n Script: " + ref->base->script; - } - - tooltipSize = createImageToolTip(ref->base->name, ref->base->icon, 32, text); - } - - // -------------------- Book ------------------------------- - else if (mFocusObject.getTypeName() == typeid(ESM::Book).name()) - { - ESMS::LiveCellRef* ref = mFocusObject.get(); - - std::string text; - text += "\n" + mWindowManager->getGameSettingString("sWeight", "Weight") + ": " + toString(ref->base->data.weight); - text += getValueString(ref->base->data.value); - - if (mFullHelp) { - text += "\n Owner: " + ref->ref.owner; - text += "\n Script: " + ref->base->script; - } - - tooltipSize = createImageToolTip(ref->base->name, ref->base->icon, 32, text); - } - - // -------------------- Clothing ------------------------------- - else if (mFocusObject.getTypeName() == typeid(ESM::Clothing).name()) - { - ESMS::LiveCellRef* ref = mFocusObject.get(); - - /// \todo magic effects - std::string text; - text += "\n" + mWindowManager->getGameSettingString("sWeight", "Weight") + ": " + toString(ref->base->data.weight); - text += getValueString(ref->base->data.value); - - if (mFullHelp) { - text += "\n Owner: " + ref->ref.owner; - text += "\n Script: " + ref->base->script; - } - - tooltipSize = createImageToolTip(ref->base->name, ref->base->icon, 32, text); - } - - // -------------------- Ingredient ------------------------------- - else if (mFocusObject.getTypeName() == typeid(ESM::Ingredient).name()) - { - ESMS::LiveCellRef* ref = mFocusObject.get(); - - /// \todo magic effects - std::string text; - text += "\n" + mWindowManager->getGameSettingString("sWeight", "Weight") + ": " + toString(ref->base->data.weight); - text += getValueString(ref->base->data.value); - - if (mFullHelp) { - text += "\n Owner: " + ref->ref.owner; - text += "\n Script: " + ref->base->script; - } - - tooltipSize = createImageToolTip(ref->base->name, ref->base->icon, 32, text); - } - - // -------------------- Light ------------------------------- - else if (mFocusObject.getTypeName() == typeid(ESM::Light).name()) - { - ESMS::LiveCellRef* ref = mFocusObject.get(); - - std::string text; - text += "\n" + mWindowManager->getGameSettingString("sWeight", "Weight") + ": " + toString(ref->base->data.weight); - text += getValueString(ref->base->data.value); - - if (mFullHelp) { - text += "\n Owner: " + ref->ref.owner; - text += "\n Script: " + ref->base->script; - } - - tooltipSize = createImageToolTip(ref->base->name, ref->base->icon, 32, text); - } - - // -------------------- Tool ------------------------------- - else if (mFocusObject.getTypeName() == typeid(ESM::Tool).name()) - { - ESMS::LiveCellRef* ref = mFocusObject.get(); - - std::string text; - text += "\n" + mWindowManager->getGameSettingString("sUses", "Uses") + ": " + toString(ref->base->data.uses); - text += "\n" + mWindowManager->getGameSettingString("sQuality", "Quality") + ": " + toString(ref->base->data.quality); - text += "\n" + mWindowManager->getGameSettingString("sWeight", "Weight") + ": " + toString(ref->base->data.weight); - text += getValueString(ref->base->data.value); - - if (mFullHelp) { - text += "\n Owner: " + ref->ref.owner; - text += "\n Script: " + ref->base->script; - } - - tooltipSize = createImageToolTip(ref->base->name, ref->base->icon, 32, text); - } - - // -------------------- Miscellaneous ------------------------------- - else if (mFocusObject.getTypeName() == typeid(ESM::Miscellaneous).name()) - { - ESMS::LiveCellRef* ref = mFocusObject.get(); - - std::string text; - text += "\n" + mWindowManager->getGameSettingString("sWeight", "Weight") + ": " + toString(ref->base->data.weight); - text += getValueString(ref->base->data.value); - - if (mFullHelp) { - text += "\n Owner: " + ref->ref.owner; - text += "\n Script: " + ref->base->script; - } - - tooltipSize = createImageToolTip(ref->base->name, ref->base->icon, 32, text); - } - - // -------------------- Probe ------------------------------- - else if (mFocusObject.getTypeName() == typeid(ESM::Probe).name()) - { - ESMS::LiveCellRef* ref = mFocusObject.get(); - - std::string text; - text += "\n" + mWindowManager->getGameSettingString("sUses", "Uses") + ": " + toString(ref->base->data.uses); - text += "\n" + mWindowManager->getGameSettingString("sQuality", "Quality") + ": " + toString(ref->base->data.quality); - text += "\n" + mWindowManager->getGameSettingString("sWeight", "Weight") + ": " + toString(ref->base->data.weight); - text += getValueString(ref->base->data.value); - - if (mFullHelp) { - text += "\n Owner: " + ref->ref.owner; - text += "\n Script: " + ref->base->script; - } - - tooltipSize = createImageToolTip(ref->base->name, ref->base->icon, 32, text); - } - - // -------------------- Repair ------------------------------- - else if (mFocusObject.getTypeName() == typeid(ESM::Repair).name()) - { - ESMS::LiveCellRef* ref = mFocusObject.get(); - - std::string text; - text += "\n" + mWindowManager->getGameSettingString("sUses", "Uses") + ": " + toString(ref->base->data.uses); - text += "\n" + mWindowManager->getGameSettingString("sQuality", "Quality") + ": " + toString(ref->base->data.quality); - text += "\n" + mWindowManager->getGameSettingString("sWeight", "Weight") + ": " + toString(ref->base->data.weight); - text += getValueString(ref->base->data.value); - - if (mFullHelp) { - text += "\n Owner: " + ref->ref.owner; - text += "\n Script: " + ref->base->script; - } - - tooltipSize = createImageToolTip(ref->base->name, ref->base->icon, 32, text); - } - - // -------------------- Weapon ------------------------------- - else if (mFocusObject.getTypeName() == typeid(ESM::Weapon).name()) - { - ESMS::LiveCellRef* ref = mFocusObject.get(); - - /// \todo weapon damage, magic effects, health (condition) - - std::string text; - text += "\n" + mWindowManager->getGameSettingString("sWeight", "Weight") + ": " + toString(ref->base->data.weight); - text += getValueString(ref->base->data.value); - - if (mFullHelp) { - text += "\n Owner: " + ref->ref.owner; - text += "\n Script: " + ref->base->script; - } - - tooltipSize = createImageToolTip(ref->base->name, ref->base->icon, 32, text); - } - - // -------------------- Activator ------------------------------- - else if (mFocusObject.getTypeName() == typeid(ESM::Activator).name()) - { - ESMS::LiveCellRef* ref = mFocusObject.get(); - - std::string text; - if (mFullHelp) { - text += "\n Script: " + ref->base->script; - } - - tooltipSize = createToolTip(ref->base->name, text); - } - else { - // object without tooltip - mDynamicToolTipBox->setVisible(false); + mDynamicToolTipBox->setVisible(true); + + ToolTipInfo info = object.getToolTipInfo(mFocusObject, mWindowManager->getEnvironment()); + if (info.icon == "") + { + tooltipSize= createToolTip(info.caption, info.text); + } + else + { + tooltipSize = createImageToolTip(info.caption, info.icon, 32, info.text); + } } return tooltipSize; @@ -490,8 +202,6 @@ IntSize ToolTips::createImageToolTip(const std::string& caption, const std::stri captionWidget->setCoord( (totalSize.width - captionSize.width)/2 + imageSize, (imageSize-captionSize.height)/2, captionSize.width-imageSize, captionSize.height); - mDynamicToolTipBox->setVisible(caption != ""); - return totalSize; } @@ -509,8 +219,6 @@ IntSize ToolTips::createToolTip(const std::string& caption, const std::string& t box->setProperty("WordWrap", "true"); box->setCaption(caption + (realText != "" ? "\n#BF9959" + realText : "")); - mDynamicToolTipBox->setVisible(caption != ""); - return box->getTextSize(); } @@ -523,8 +231,6 @@ IntSize ToolTips::createToolTip(const std::string& text) box->setProperty("WordWrap", "true"); box->setCaption(text); - mDynamicToolTipBox->setVisible(text != ""); - return box->getTextSize(); } @@ -542,15 +248,28 @@ std::string ToolTips::toString(const int value) return stream.str(); } -std::string ToolTips::getValueString(const int value) +std::string ToolTips::getValueString(const int value, const std::string& prefix) { if (value == 0) return ""; else - return "\n" + mWindowManager->getGameSettingString("sValue", "Value") + ": " + toString(value); + return "\n" + prefix + ": " + toString(value); +} + +std::string ToolTips::getMiscString(const std::string& text, const std::string& prefix) +{ + if (text == "") + return ""; + else + return "\n" + prefix + ": " + text; } void ToolTips::toggleFullHelp() { mFullHelp = !mFullHelp; } + +bool ToolTips::getFullHelp() const +{ + return mFullHelp; +} diff --git a/apps/openmw/mwgui/tooltips.hpp b/apps/openmw/mwgui/tooltips.hpp index a3447eb441..46aab38761 100644 --- a/apps/openmw/mwgui/tooltips.hpp +++ b/apps/openmw/mwgui/tooltips.hpp @@ -10,13 +10,12 @@ namespace MWGui class WindowManager; // Info about tooltip that is supplied by the MWWorld::Class object - // Not used yet, but it will replace the if-else-if blocks in tooltips.cpp struct ToolTipInfo { public: std::string caption; std::string text; - std::string image; + std::string icon; /// \todo enchantments (armor, cloth, weapons), magic effects (potions, ingredients) }; @@ -32,9 +31,19 @@ namespace MWGui void enterGuiMode(); void toggleFullHelp(); ///< show extra info in item tooltips (owner, script) + bool getFullHelp() const; void setFocusObject(const MWWorld::Ptr& focus); + static std::string getValueString(const int value, const std::string& prefix); + ///< @return "prefix: value" or "" if value is 0 + + static std::string getMiscString(const std::string& text, const std::string& prefix); + ///< @return "prefix: text" or "" if text is empty + + static std::string toString(const float value); + static std::string toString(const int value); + private: MyGUI::Widget* mDynamicToolTipBox; @@ -56,12 +65,6 @@ namespace MWGui MyGUI::IntSize createToolTip(const std::string& text); ///< @return requested tooltip size - std::string getValueString(const int value); - ///< get "Value: X" string or "" if value is 0 - - std::string toString(const float value); - std::string toString(const int value); - bool mGameMode; bool mFullHelp; diff --git a/apps/openmw/mwgui/window_manager.cpp b/apps/openmw/mwgui/window_manager.cpp index b18ee4e432..f49bcfaf84 100644 --- a/apps/openmw/mwgui/window_manager.cpp +++ b/apps/openmw/mwgui/window_manager.cpp @@ -502,3 +502,8 @@ void WindowManager::toggleFullHelp() { mToolTips->toggleFullHelp(); } + +bool WindowManager::getFullHelp() const +{ + return mToolTips->getFullHelp(); +} diff --git a/apps/openmw/mwgui/window_manager.hpp b/apps/openmw/mwgui/window_manager.hpp index d76d15dd4c..1b1eff1dc9 100644 --- a/apps/openmw/mwgui/window_manager.hpp +++ b/apps/openmw/mwgui/window_manager.hpp @@ -162,6 +162,7 @@ namespace MWGui void toggleFogOfWar(); void toggleFullHelp(); ///< show extra info in item tooltips (owner, script) + bool getFullHelp() const; int toggleFps(); ///< toggle fps display @return resulting fps level diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 10368901b7..aaf19963d6 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -174,7 +174,7 @@ namespace MWWorld throw std::runtime_error ("class does not have an down sound"); } - MWGui::ToolTipInfo Class::getToolTipInfo (const Ptr& ptr) const + MWGui::ToolTipInfo Class::getToolTipInfo (const Ptr& ptr, MWWorld::Environment& environment) const { throw std::runtime_error ("class does not have a tool tip"); } diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 5441b874d5..1b7b8b66ab 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -90,7 +90,7 @@ namespace MWWorld virtual bool hasToolTip (const Ptr& ptr) const; ///< @return true if this object has a tooltip when focused (default implementation: false) - virtual MWGui::ToolTipInfo getToolTipInfo (const Ptr& ptr) const; + virtual MWGui::ToolTipInfo getToolTipInfo (const Ptr& ptr, MWWorld::Environment& environment) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. virtual MWMechanics::NpcStats& getNpcStats (const Ptr& ptr) const; From c044fadcc303ad9f5621a75a21bc54770844e5df Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 17 Apr 2012 15:31:16 +0200 Subject: [PATCH 026/325] show weapon type & damage in the tooltip --- apps/openmw/mwclass/weapon.cpp | 53 ++++++++++++++++++++++++++++++++-- 1 file changed, 51 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index 1fb8715729..d2ea92126b 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -269,10 +269,59 @@ namespace MWClass std::string text; - /// \todo weapon type, damage + // weapon type & damage. arrows / bolts don't have his info. + if (ref->base->data.type < 12) + { + text += "\n" + environment.mWorld->getStore().gameSettings.search("sType")->str + " "; + + std::map > mapping; + mapping[ESM::Weapon::ShortBladeOneHand] = std::make_pair("sSkillShortblade", "sOneHanded"); + mapping[ESM::Weapon::LongBladeOneHand] = std::make_pair("sSkillLongblade", "sOneHanded"); + mapping[ESM::Weapon::LongBladeTwoHand] = std::make_pair("sSkillLongblade", "sTwoHanded"); + mapping[ESM::Weapon::BluntOneHand] = std::make_pair("sSkillBluntweapon", "sOneHanded"); + mapping[ESM::Weapon::BluntTwoClose] = std::make_pair("sSkillBluntweapon", "sTwoHanded"); + mapping[ESM::Weapon::BluntTwoWide] = std::make_pair("sSkillBluntweapon", "sTwoHanded"); + mapping[ESM::Weapon::SpearTwoWide] = std::make_pair("sSkillSpear", "sTwoHanded"); + mapping[ESM::Weapon::AxeOneHand] = std::make_pair("sSkillAxe", "sOneHanded"); + mapping[ESM::Weapon::AxeTwoHand] = std::make_pair("sSkillAxe", "sTwoHanded"); + mapping[ESM::Weapon::MarksmanBow] = std::make_pair("sSkillMarksman", ""); + mapping[ESM::Weapon::MarksmanCrossbow] = std::make_pair("sSkillMarksman", ""); + mapping[ESM::Weapon::MarksmanThrown] = std::make_pair("sSkillMarksman", ""); + + std::string type = mapping[ref->base->data.type].first; + std::string oneOrTwoHanded = mapping[ref->base->data.type].second; + + text += environment.mWorld->getStore().gameSettings.search(type)->str + + ((oneOrTwoHanded != "") ? ", " + environment.mWorld->getStore().gameSettings.search(oneOrTwoHanded)->str : ""); + + // weapon damage + if (ref->base->data.type >= 9) + { + // marksman + text += "\n" + environment.mWorld->getStore().gameSettings.search("sAttack")->str + ": " + + MWGui::ToolTips::toString(static_cast(ref->base->data.chop[0])) + + " - " + MWGui::ToolTips::toString(static_cast(ref->base->data.chop[1])); + } + else + { + // Chop + text += "\n" + environment.mWorld->getStore().gameSettings.search("sChop")->str + ": " + + MWGui::ToolTips::toString(static_cast(ref->base->data.chop[0])) + + " - " + MWGui::ToolTips::toString(static_cast(ref->base->data.chop[1])); + // Slash + text += "\n" + environment.mWorld->getStore().gameSettings.search("sSlash")->str + ": " + + MWGui::ToolTips::toString(static_cast(ref->base->data.slash[0])) + + " - " + MWGui::ToolTips::toString(static_cast(ref->base->data.slash[1])); + // Thrust + text += "\n" + environment.mWorld->getStore().gameSettings.search("sThrust")->str + ": " + + MWGui::ToolTips::toString(static_cast(ref->base->data.thrust[0])) + + " - " + MWGui::ToolTips::toString(static_cast(ref->base->data.thrust[1])); + } + } /// \todo store the current weapon health somewhere - text += "\n" + environment.mWorld->getStore().gameSettings.search("sCondition")->str + ": " + MWGui::ToolTips::toString(ref->base->data.health); + if (ref->base->data.type < 11) // thrown weapons and arrows/bolts don't have health, only quantity + text += "\n" + environment.mWorld->getStore().gameSettings.search("sCondition")->str + ": " + MWGui::ToolTips::toString(ref->base->data.health); text += "\n" + environment.mWorld->getStore().gameSettings.search("sWeight")->str + ": " + MWGui::ToolTips::toString(ref->base->data.weight); text += MWGui::ToolTips::getValueString(ref->base->data.value, environment.mWorld->getStore().gameSettings.search("sValue")->str); From c2fdacc84fc5f1a3f69a9e2f1c74ff875f9d6d8b Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 17 Apr 2012 15:51:02 +0200 Subject: [PATCH 027/325] show the creature name for soul gems (if any) --- apps/openmw/mwclass/misc.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/apps/openmw/mwclass/misc.cpp b/apps/openmw/mwclass/misc.cpp index 8cd2554a10..222ac1b782 100644 --- a/apps/openmw/mwclass/misc.cpp +++ b/apps/openmw/mwclass/misc.cpp @@ -132,6 +132,12 @@ namespace MWClass info.caption = ref->base->name; info.icon = ref->base->icon; + if (ref->ref.soul != "") + { + const ESM::Creature *creature = environment.mWorld->getStore().creatures.search(ref->ref.soul); + info.caption += " (" + creature->name + ")"; + } + std::string text; if (ref->base->name == environment.mWorld->getStore().gameSettings.search("sGold")->str) From 8eb06363449bb638882b77ff28c0ce19901bcda0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 17 Apr 2012 16:00:13 +0200 Subject: [PATCH 028/325] restored gui-mode tooltips --- apps/openmw/mwgui/tooltips.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 345ed847b3..fd44c7d9be 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -89,6 +89,7 @@ void ToolTips::onFrame(float frameDuration) } setCoord(tooltipPosition.left, tooltipPosition.top, size.width, size.height); + mDynamicToolTipBox->setVisible(true); } else { From 94993b515c7abade56d4885d46ea305ea42c7947 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 17 Apr 2012 16:49:28 +0200 Subject: [PATCH 029/325] clean up and tooltip padding --- apps/openmw/mwgui/tooltips.cpp | 100 +++++++++++++++------------------ apps/openmw/mwgui/tooltips.hpp | 8 +-- 2 files changed, 45 insertions(+), 63 deletions(-) diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index fd44c7d9be..ab766dc56a 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -47,9 +47,6 @@ void ToolTips::onFrame(float frameDuration) return; } - // this the maximum width of the tooltip before it starts word-wrapping - setCoord(0, 0, 300, 300); - IntSize tooltipSize; std::string type = focus->getUserString("ToolTipType"); @@ -60,11 +57,11 @@ void ToolTips::onFrame(float frameDuration) return; } else if (type == "Text") - tooltipSize = createToolTip(text); + tooltipSize = createToolTip(text, "", 0, ""); else if (type == "CaptionText") { std::string caption = focus->getUserString("ToolTipCaption"); - tooltipSize = createToolTip(caption, text); + tooltipSize = createToolTip(caption, "", 0, text); } else if (type == "ImageCaptionText") { @@ -72,23 +69,22 @@ void ToolTips::onFrame(float frameDuration) std::string image = focus->getUserString("ToolTipImage"); std::string sizeString = focus->getUserString("ToolTipImageSize"); int size = (sizeString != "" ? boost::lexical_cast(sizeString) : 32); - tooltipSize = createImageToolTip(caption, image, size, text); + tooltipSize = createToolTip(caption, image, size, text); } IntPoint tooltipPosition = InputManager::getInstance().getMousePosition() + IntPoint(0, 24); - IntSize size = tooltipSize + IntSize(6, 6); // make the tooltip stay completely in the viewport - if ((tooltipPosition.left + size.width) > viewSize.width) + if ((tooltipPosition.left + tooltipSize.width) > viewSize.width) { - tooltipPosition.left = viewSize.width - size.width; + tooltipPosition.left = viewSize.width - tooltipSize.width; } - if ((tooltipPosition.top + size.height) > viewSize.height) + if ((tooltipPosition.top + tooltipSize.height) > viewSize.height) { - tooltipPosition.top = viewSize.height - size.height; + tooltipPosition.top = viewSize.height - tooltipSize.height; } - setCoord(tooltipPosition.left, tooltipPosition.top, size.width, size.height); + setCoord(tooltipPosition.left, tooltipPosition.top, tooltipSize.width, tooltipSize.height); mDynamicToolTipBox->setVisible(true); } else @@ -97,8 +93,6 @@ void ToolTips::onFrame(float frameDuration) { IntSize tooltipSize = getToolTipViaPtr(); - tooltipSize += IntSize(6,6); // padding, adjust for skin - // adjust tooltip size to fit its content, position it above the crosshair /// \todo Slide the tooltip along the bounding box of the focused object (like in Morrowind) setCoord(viewSize.width/2 - (tooltipSize.width)/2.f, @@ -145,11 +139,11 @@ IntSize ToolTips::getToolTipViaPtr () ToolTipInfo info = object.getToolTipInfo(mFocusObject, mWindowManager->getEnvironment()); if (info.icon == "") { - tooltipSize= createToolTip(info.caption, info.text); + tooltipSize = createToolTip(info.caption, "", 0, info.text); } else { - tooltipSize = createImageToolTip(info.caption, info.icon, 32, info.text); + tooltipSize = createToolTip(info.caption, info.icon, 32, info.text); } } @@ -170,71 +164,65 @@ void ToolTips::findImageExtension(std::string& image) } } -IntSize ToolTips::createImageToolTip(const std::string& caption, const std::string& image, const int imageSize, const std::string& text) +IntSize ToolTips::createToolTip(const std::string& caption, const std::string& image, const int imageSize, const std::string& text) { // remove the first newline (easier this way) std::string realText = text; if (realText.size() > 0 && realText[0] == '\n') realText.erase(0, 1); + // this the maximum width of the tooltip before it starts word-wrapping + setCoord(0, 0, 300, 300); + + const IntPoint padding(8, 8); + + const int imageCaptionHPadding = 8; + const int imageCaptionVPadding = 4; + std::string realImage = "icons\\" + image; findImageExtension(realImage); EditBox* captionWidget = mDynamicToolTipBox->createWidget("NormalText", IntCoord(0, 0, 300, 300), Align::Left | Align::Top, "ToolTipCaption"); captionWidget->setProperty("Static", "true"); captionWidget->setCaption(caption); - EditBox* textWidget = mDynamicToolTipBox->createWidget("SandText", IntCoord(0, imageSize, 300, 300-imageSize), Align::Stretch, "ToolTipText"); + IntSize captionSize = captionWidget->getTextSize(); + + int captionHeight = std::max(captionSize.height, imageSize); + + EditBox* textWidget = mDynamicToolTipBox->createWidget("SandText", IntCoord(0, captionHeight+imageCaptionVPadding, 300, 300-captionHeight-imageCaptionVPadding), Align::Stretch, "ToolTipText"); textWidget->setProperty("Static", "true"); textWidget->setProperty("MultiLine", "true"); textWidget->setProperty("WordWrap", "true"); textWidget->setCaption(realText); - textWidget->setTextAlign(Align::HCenter); - - IntSize captionSize = captionWidget->getTextSize(); + textWidget->setTextAlign(Align::HCenter | Align::Top); IntSize textSize = textWidget->getTextSize(); captionSize += IntSize(imageSize, 0); // adjust for image - IntSize totalSize = IntSize( std::max(textSize.width, captionSize.width), ((realText != "") ? textSize.height : 0) + imageSize ); + IntSize totalSize = IntSize( std::max(textSize.width, captionSize.width + ((image != "") ? imageCaptionHPadding : 0)), + ((realText != "") ? textSize.height + imageCaptionVPadding : 0) + captionHeight ); - ImageBox* imageWidget = mDynamicToolTipBox->createWidget("ImageBox", - IntCoord((totalSize.width - captionSize.width)/2, 0, imageSize, imageSize), - Align::Left | Align::Top, "ToolTipImage"); - imageWidget->setImageTexture(realImage); + if (image != "") + { + ImageBox* imageWidget = mDynamicToolTipBox->createWidget("ImageBox", + IntCoord((totalSize.width - captionSize.width - imageCaptionHPadding)/2, 0, imageSize, imageSize), + Align::Left | Align::Top, "ToolTipImage"); + imageWidget->setImageTexture(realImage); + imageWidget->setPosition (imageWidget->getPosition() + padding); + } - captionWidget->setCoord( (totalSize.width - captionSize.width)/2 + imageSize, (imageSize-captionSize.height)/2, captionSize.width-imageSize, captionSize.height); + captionWidget->setCoord( (totalSize.width - captionSize.width)/2 + imageSize, + (captionHeight-captionSize.height)/2, + captionSize.width-imageSize, + captionSize.height); + + captionWidget->setPosition (captionWidget->getPosition() + padding); + textWidget->setPosition (textWidget->getPosition() + IntPoint(0, padding.top)); // only apply vertical padding, the horizontal works automatically due to Align::HCenter + + totalSize += IntSize(padding.left*2, padding.top*2); return totalSize; } -IntSize ToolTips::createToolTip(const std::string& caption, const std::string& text) -{ - // remove the first newline (easier this way) - std::string realText = text; - if (realText.size() > 0 && realText[0] == '\n') - realText.erase(0, 1); - - EditBox* box = mDynamicToolTipBox->createWidget("NormalText", IntCoord(0, 0, 300, 300), Align::Stretch, "ToolTip"); - box->setTextAlign(Align::HCenter); - box->setProperty("Static", "true"); - box->setProperty("MultiLine", "true"); - box->setProperty("WordWrap", "true"); - box->setCaption(caption + (realText != "" ? "\n#BF9959" + realText : "")); - - return box->getTextSize(); -} - -IntSize ToolTips::createToolTip(const std::string& text) -{ - EditBox* box = mDynamicToolTipBox->createWidget("SandText", IntCoord(0, 0, 300, 300), Align::Stretch, "ToolTip"); - box->setTextAlign(Align::HCenter); - box->setProperty("Static", "true"); - box->setProperty("MultiLine", "true"); - box->setProperty("WordWrap", "true"); - box->setCaption(text); - - return box->getTextSize(); -} - std::string ToolTips::toString(const float value) { std::ostringstream stream; diff --git a/apps/openmw/mwgui/tooltips.hpp b/apps/openmw/mwgui/tooltips.hpp index 46aab38761..d84a1093be 100644 --- a/apps/openmw/mwgui/tooltips.hpp +++ b/apps/openmw/mwgui/tooltips.hpp @@ -56,13 +56,7 @@ namespace MWGui MyGUI::IntSize getToolTipViaPtr (); ///< @return requested tooltip size - MyGUI::IntSize createImageToolTip(const std::string& caption, const std::string& image, const int imageSize, const std::string& text); - ///< @return requested tooltip size - - MyGUI::IntSize createToolTip(const std::string& caption, const std::string& text); - ///< @return requested tooltip size - - MyGUI::IntSize createToolTip(const std::string& text); + MyGUI::IntSize createToolTip(const std::string& caption, const std::string& image, const int imageSize, const std::string& text); ///< @return requested tooltip size bool mGameMode; From 2e57cf5730ed326d45f1c828d158bb6bb408d1c7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 17 Apr 2012 18:47:51 +0200 Subject: [PATCH 030/325] fixed the tooltip for doors leading to exteriors, fixed map window cell name --- apps/openmw/mwclass/door.cpp | 26 ++++++++++++++++++++++---- apps/openmw/mwgui/window_manager.cpp | 5 ++++- 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index e06fdecda8..794d57d1c2 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -164,12 +164,30 @@ namespace MWClass std::string text; - /// \todo If destCell is empty, the teleport target is an exterior cell. In that case we - /// need to fetch that cell (via target position) and retrieve the region name. - if (ref->ref.teleport && (ref->ref.destCell != "")) + if (ref->ref.teleport) { + std::string dest; + if (ref->ref.destCell != "") + { + // door leads to an interior, use interior name as tooltip + dest = ref->ref.destCell; + } + else + { + // door leads to exterior, use cell name (if any), otherwise translated region name + int x,y; + environment.mWorld->positionToIndex (ref->ref.doorDest.pos[0], ref->ref.doorDest.pos[1], x, y); + const ESM::Cell* cell = environment.mWorld->getStore().cells.findExt(x,y); + if (cell->name != "") + dest = cell->name; + else + { + const ESM::Region* region = environment.mWorld->getStore().regions.search(cell->region); + dest = region->name; + } + } text += "\n" + environment.mWorld->getStore().gameSettings.search("sTo")->str; - text += "\n"+ref->ref.destCell; + text += "\n"+dest; } if (ref->ref.lockLevel > 0) diff --git a/apps/openmw/mwgui/window_manager.cpp b/apps/openmw/mwgui/window_manager.cpp index f49bcfaf84..0188a15b31 100644 --- a/apps/openmw/mwgui/window_manager.cpp +++ b/apps/openmw/mwgui/window_manager.cpp @@ -433,7 +433,10 @@ void WindowManager::changeCell(MWWorld::Ptr::CellStore* cell) if (cell->cell->name != "") name = cell->cell->name; else - name = cell->cell->region; + { + const ESM::Region* region = environment.mWorld->getStore().regions.search(cell->cell->region); + name = region->name; + } map->setCellName( name ); From 5f9056c45d06fadd12a77be438c3eab930e25ecb Mon Sep 17 00:00:00 2001 From: Jason Hooks Date: Tue, 17 Apr 2012 20:31:36 -0400 Subject: [PATCH 031/325] Better no clip --- apps/openmw/mwworld/physicssystem.cpp | 7 ++++--- libs/openengine/bullet/pmove.cpp | 4 +++- libs/openengine/bullet/pmove.h | 4 ++-- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 29c65b411b..98c15e3383 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -127,11 +127,11 @@ namespace MWWorld Ogre::Quaternion pitchQuat = pitchNode->getOrientation(); Ogre::Quaternion both = yawQuat * pitchQuat; - playerphysics->ps.viewangles.x = 0; + playerphysics->ps.viewangles.x = pitchQuat.getPitch().valueDegrees(); playerphysics->ps.viewangles.z = 0; - playerphysics->ps.viewangles.y = both.getYaw().valueDegrees() *-1 + 90; + playerphysics->ps.viewangles.y = yawQuat.getYaw().valueDegrees() *-1 + 90; - //playerphysics->ps.viewangles.z = both.getPitch().valueDegrees(); + if(mFreeFly) @@ -259,6 +259,7 @@ namespace MWWorld { if(playerphysics->ps.move_type==PM_NOCLIP) playerphysics->ps.move_type=PM_NORMAL; + else playerphysics->ps.move_type=PM_NOCLIP; for(std::map::iterator it = mEngine->PhysicActorMap.begin(); it != mEngine->PhysicActorMap.end();it++) diff --git a/libs/openengine/bullet/pmove.cpp b/libs/openengine/bullet/pmove.cpp index 8fb72aa1f0..86d069273e 100644 --- a/libs/openengine/bullet/pmove.cpp +++ b/libs/openengine/bullet/pmove.cpp @@ -632,6 +632,8 @@ float PM_CmdScale(playerMove::playercmd* const cmd) total = sqrtf( (const float)(cmd->forwardmove * cmd->forwardmove + cmd->rightmove * cmd->rightmove + cmd->upmove * cmd->upmove) ); scale = (float)pm->ps.speed * max / ( 127.0f * total ); + if(pm->ps.move_type == PM_NOCLIP) + scale *= 2; return scale; } @@ -1125,7 +1127,7 @@ void AngleVectors( const Ogre::Vector3& angles, Ogre::Vector3* const forward, Og { right->x = (-1 * sr * sp * cy + -1 * cr * -sy); right->y = (-1 * sr * sp * sy + -1 * cr * cy); - right->z = 0.0f;//-1 * sp * cp; + right->z = 0; } if (up) { diff --git a/libs/openengine/bullet/pmove.h b/libs/openengine/bullet/pmove.h index 30572a92a2..304572b021 100644 --- a/libs/openengine/bullet/pmove.h +++ b/libs/openengine/bullet/pmove.h @@ -55,7 +55,7 @@ static const Ogre::Vector3 halfExtents(14.64f * 2, 14.24f * 2, 33.25f * 2); #define CONTENTS_FOG 64 static const float pm_accelerate = 10.0f; static const float pm_stopspeed = 100.0f; -static const float pm_friction = 6.0f; +static const float pm_friction = 12.0f; static const float pm_flightfriction = 3.0f; static const float pm_waterfriction = 1.0f; static const float pm_airaccelerate = 1.0f; @@ -90,7 +90,7 @@ struct playerMove { struct playerStruct { - playerStruct() : gravity(800.0f), speed(320.0f), pmove_framecount(20), groundEntityNum(ENTITYNUM_NONE), commandTime(40), move_type(PM_NOCLIP), pm_time(0) + playerStruct() : gravity(800.0f), speed(480.0f), pmove_framecount(20), groundEntityNum(ENTITYNUM_NONE), commandTime(40), move_type(PM_NOCLIP), pm_time(0) { origin = Ogre::Vector3(733.164f,900.0f, 839.432f); velocity = Ogre::Vector3(0.0f, 0.0f, 0.0f); From 4d07ae7fe031dad3019b8c7d837fc4059a3ffee9 Mon Sep 17 00:00:00 2001 From: Jason Hooks Date: Wed, 18 Apr 2012 00:13:38 -0400 Subject: [PATCH 032/325] Swimming working --- apps/openmw/mwworld/physicssystem.cpp | 7 +++++++ apps/openmw/mwworld/physicssystem.hpp | 2 ++ apps/openmw/mwworld/scene.cpp | 2 ++ libs/openengine/bullet/pmove.cpp | 10 +++++----- 4 files changed, 16 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 98c15e3383..d224385ae5 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -67,6 +67,13 @@ namespace MWWorld return mEngine->rayTest2(from,to); } + void PhysicsSystem::setCurrentWater(bool hasWater, int waterHeight){ + playerphysics->hasWater = hasWater; + if(hasWater){ + playerphysics->waterHeight = waterHeight; + } + + } btVector3 PhysicsSystem::getRayPoint(float extent) { diff --git a/apps/openmw/mwworld/physicssystem.hpp b/apps/openmw/mwworld/physicssystem.hpp index fb15a1486f..2d73cab27c 100644 --- a/apps/openmw/mwworld/physicssystem.hpp +++ b/apps/openmw/mwworld/physicssystem.hpp @@ -49,6 +49,8 @@ namespace MWWorld void insertActorPhysics(const MWWorld::Ptr&, std::string model); OEngine::Physic::PhysicEngine* getEngine(); + + void setCurrentWater(bool hasWater, int waterHeight); private: OEngine::Render::OgreRenderer &mRender; diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 2123b47999..5244d53f83 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -117,6 +117,8 @@ namespace MWWorld void Scene::playerCellChange (Ptr::CellStore *cell, const ESM::Position& position, bool adjustPlayerPos) { + bool hasWater = cell->cell->data.flags & cell->cell->HasWater; + mPhysics->setCurrentWater(hasWater, cell->cell->water); if (adjustPlayerPos) mWorld->getPlayer().setPos (position.pos[0], position.pos[1], position.pos[2]); diff --git a/libs/openengine/bullet/pmove.cpp b/libs/openengine/bullet/pmove.cpp index 86d069273e..214a7e5989 100644 --- a/libs/openengine/bullet/pmove.cpp +++ b/libs/openengine/bullet/pmove.cpp @@ -1715,11 +1715,11 @@ void PM_SetWaterLevel( playerMove* const pm ) point[1] = pm->ps->origin[1]; point[2] = pm->ps->origin[2] + MINS_Z + 1; */ point.x = pm->ps.origin.x; - point.y = pm->ps.origin.y + MINS_Z + 1; - point.z = pm->ps.origin.z; + point.y = pm->ps.origin.y; + point.z = pm->ps.origin.z + MINS_Z + 1; //cont = pm->pointcontents( point, pm->ps->clientNum ); - bool checkWater = (pml.hasWater && pml.waterHeight > point.y); + bool checkWater = (pml.hasWater && pml.waterHeight > point.z); //if ( cont & MASK_WATER ) if ( checkWater) { @@ -1729,14 +1729,14 @@ void PM_SetWaterLevel( playerMove* const pm ) pm->ps.watertype = CONTENTS_WATER;//cont; pm->ps.waterlevel = WL_ANKLE; //point[2] = pm->ps->origin[2] + MINS_Z + sample1; - point.y = pm->ps.origin.y + MINS_Z + sample1; + point.z = pm->ps.origin.z + MINS_Z + sample1; //cont = pm->pointcontents (point, pm->ps->clientNum ); //if ( cont & MASK_WATER ) if (checkWater) { pm->ps.waterlevel = WL_WAIST; //point[2] = pm->ps->origin[2] + MINS_Z + sample2; - point.y = pm->ps.origin.y + MINS_Z + sample2; + point.z = pm->ps.origin.z + MINS_Z + sample2; //cont = pm->pointcontents (point, pm->ps->clientNum ); //if ( cont & MASK_WATER ) if (checkWater ) From f902c8fa6f154db5dd5383878781cc817c2dd01f Mon Sep 17 00:00:00 2001 From: pchan3 Date: Wed, 18 Apr 2012 22:35:35 +1000 Subject: [PATCH 033/325] Fixes on Namespace issue & more. --- apps/openmw/mwgui/container.cpp | 73 ++++++++++++++++++++++++------ apps/openmw/mwworld/actionopen.cpp | 2 +- 2 files changed, 60 insertions(+), 15 deletions(-) diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 3f27351a98..094b958db1 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -28,7 +28,7 @@ ContainerWindow::ContainerWindow(WindowManager& parWindowManager,MWWorld::Enviro mEnvironment(environment) { setText("_Main", "Name of Container"); - center(); + //center(); adjustWindowCaption(); getWidget(containerWidget, "Items"); @@ -90,7 +90,54 @@ void ContainerWindow::open(MWWorld::Ptr& container) containerStore.add(bukkitRef.getPtr()); containerStore.add(bukkitRef.getPtr()); containerStore.add(goldRef.getPtr()); - + containerStore.add(furRef.getPtr()); + containerStore.add(furRef.getPtr()); + containerStore.add(furRef.getPtr()); + containerStore.add(broomRef.getPtr()); + containerStore.add(broomRef.getPtr()); + containerStore.add(broomRef.getPtr()); + containerStore.add(broomRef.getPtr()); + containerStore.add(broomRef.getPtr()); + containerStore.add(broomRef.getPtr()); + containerStore.add(broomRef.getPtr()); + containerStore.add(broomRef.getPtr()); + containerStore.add(broomRef.getPtr()); + containerStore.add(broomRef.getPtr()); + containerStore.add(bukkitRef.getPtr()); + containerStore.add(bukkitRef.getPtr()); + containerStore.add(bukkitRef.getPtr()); + containerStore.add(bukkitRef.getPtr()); + containerStore.add(bukkitRef.getPtr()); + containerStore.add(bukkitRef.getPtr()); + containerStore.add(bukkitRef.getPtr()); + containerStore.add(bukkitRef.getPtr()); + containerStore.add(bukkitRef.getPtr()); + containerStore.add(bukkitRef.getPtr()); + containerStore.add(goldRef.getPtr()); + containerStore.add(furRef.getPtr()); + containerStore.add(furRef.getPtr()); + containerStore.add(furRef.getPtr()); + containerStore.add(broomRef.getPtr()); + containerStore.add(broomRef.getPtr()); + containerStore.add(broomRef.getPtr()); + containerStore.add(broomRef.getPtr()); + containerStore.add(broomRef.getPtr()); + containerStore.add(broomRef.getPtr()); + containerStore.add(broomRef.getPtr()); + containerStore.add(broomRef.getPtr()); + containerStore.add(broomRef.getPtr()); + containerStore.add(broomRef.getPtr()); + containerStore.add(bukkitRef.getPtr()); + containerStore.add(bukkitRef.getPtr()); + containerStore.add(bukkitRef.getPtr()); + containerStore.add(bukkitRef.getPtr()); + containerStore.add(bukkitRef.getPtr()); + containerStore.add(bukkitRef.getPtr()); + containerStore.add(bukkitRef.getPtr()); + containerStore.add(bukkitRef.getPtr()); + containerStore.add(bukkitRef.getPtr()); + containerStore.add(bukkitRef.getPtr()); + containerStore.add(goldRef.getPtr()); // ESMS::LiveCellRef *ref = iter->get(); @@ -103,39 +150,35 @@ void ContainerWindow::open(MWWorld::Ptr& container) for (MWWorld::ContainerStoreIterator iter (containerStore.begin()); iter!=containerStore.end(); ++iter) { std::string path = std::string("icons\\"); - - path+=MWWorld::Class::get(*iter).getInventoryIcon(*iter); count++; - if(count % 8 == 0) + MyGUI::ImageBox* image = containerWidget->createWidget("ImageBox", MyGUI::IntCoord(x, y, 32, 32), MyGUI::Align::Default); + MyGUI::TextBox* text = containerWidget->createWidget("SandBrightText", MyGUI::IntCoord(x, y, 18, 18), MyGUI::Align::Default, std::string("Label")); + + x += 36; + if(count % 20 == 0) { y += 36; x = 4; count = 0; } - x += 36; - - - MyGUI::ImageBox* image = containerWidget->createWidget("ImageBox", MyGUI::IntCoord(x, y, 32, 32), MyGUI::Align::Default); - MyGUI::TextBox* text = containerWidget->createWidget("SandBrightText", MyGUI::IntCoord(x, y, 18, 18), MyGUI::Align::Default, std::string("Label")); if(iter->getRefData().getCount() > 1) text->setCaption(boost::lexical_cast(iter->getRefData().getCount())); - containerWidgets.push_back(image); - int pos = path.rfind("."); path.erase(pos); path.append(".dds"); - //std::cout << path << std::endl; image->setImageTexture(path); } + + setVisible(true); } @@ -146,6 +189,8 @@ void ContainerWindow::Update() void ContainerWindow::onByeClicked(MyGUI::Widget* _sender) { - mEnvironment.mWindowManager->setGuiMode(MWGui::GuiMode::GM_Game); + mEnvironment.mWindowManager->setGuiMode(GM_Game); + + setVisible(false); } diff --git a/apps/openmw/mwworld/actionopen.cpp b/apps/openmw/mwworld/actionopen.cpp index aa4a67b2b5..e245989d7f 100644 --- a/apps/openmw/mwworld/actionopen.cpp +++ b/apps/openmw/mwworld/actionopen.cpp @@ -16,7 +16,7 @@ namespace MWWorld void ActionOpen::execute (Environment& environment) { - environment.mWindowManager->setGuiMode(MWGui::GuiMode::GM_Container); + environment.mWindowManager->setGuiMode(MWGui::GM_Container); environment.mWindowManager->getContainerWindow()->open(mContainer); } } From 215d4e1739a016b094e6ccb5dda3e06e175df4ae Mon Sep 17 00:00:00 2001 From: pchan3 Date: Wed, 18 Apr 2012 23:09:13 +1000 Subject: [PATCH 034/325] Made adjustments to keep container window within the viewscreen. --- apps/openmw/mwgui/container.cpp | 4 ++++ files/mygui/openmw_container_window_layout.xml | 8 ++++---- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 094b958db1..7c63f95d02 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -28,6 +28,10 @@ ContainerWindow::ContainerWindow(WindowManager& parWindowManager,MWWorld::Enviro mEnvironment(environment) { setText("_Main", "Name of Container"); + + int w = MyGUI::RenderManager::getInstance().getViewSize().width; + int h = MyGUI::RenderManager::getInstance().getViewSize().height; + setCoord(w-600,h-300,600,300); //center(); adjustWindowCaption(); diff --git a/files/mygui/openmw_container_window_layout.xml b/files/mygui/openmw_container_window_layout.xml index a9de148804..7fce9e187c 100644 --- a/files/mygui/openmw_container_window_layout.xml +++ b/files/mygui/openmw_container_window_layout.xml @@ -1,13 +1,13 @@ - + - - + - --> + From d568b27b9272ca46670b59ffba4b85336d79cb76 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 18 Apr 2012 16:53:56 +0200 Subject: [PATCH 035/325] spell widget i18n improvements (used e.g. in birth menu) --- apps/openmw/mwclass/weapon.cpp | 30 +++++++++++++++++++++++ apps/openmw/mwgui/tooltips.cpp | 44 +++++++++++++++++++--------------- apps/openmw/mwgui/tooltips.hpp | 14 +++++++++-- apps/openmw/mwgui/widgets.cpp | 20 +++++++++++----- 4 files changed, 81 insertions(+), 27 deletions(-) diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index d2ea92126b..bfb5074b04 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -326,6 +326,36 @@ namespace MWClass text += "\n" + environment.mWorld->getStore().gameSettings.search("sWeight")->str + ": " + MWGui::ToolTips::toString(ref->base->data.weight); text += MWGui::ToolTips::getValueString(ref->base->data.value, environment.mWorld->getStore().gameSettings.search("sValue")->str); + // this should be going into a custom mygui widget MWEnchantment + /* + // enchantments + if (ref->base->enchant != "") + { + const ESM::Enchantment* enchant = environment.mWorld->getStore().enchants.search(ref->base->enchant); + if (enchant->data.type == ESM::Enchantment::CastOnce) + text += "\n" + environment.mWorld->getStore().gameSettings.search("sItemCastOnce")->str; + else if (enchant->data.type == ESM::Enchantment::WhenStrikes) + text += "\n" + environment.mWorld->getStore().gameSettings.search("sItemCastWhenStrikes")->str; + else if (enchant->data.type == ESM::Enchantment::WhenUsed) + text += "\n" + environment.mWorld->getStore().gameSettings.search("sItemCastWhenUsed")->str; + else if (enchant->data.type == ESM::Enchantment::ConstantEffect) + text += "\n" + environment.mWorld->getStore().gameSettings.search("sItemCastConstant")->str; + + if (enchant->data.type == ESM::Enchantment::WhenStrikes + || enchant->data.type == ESM::Enchantment::WhenUsed) + { + /// \todo store the current enchantment charge somewhere + // info.currentCharge = enchant->data.charge; + //info.totalCharge = enchant->data.charge; + } + } + */ + if (ref->base->enchant != "") + { + const ESM::Enchantment* enchant = environment.mWorld->getStore().enchants.search(ref->base->enchant); + info.enchant = enchant; + } + if (environment.mWindowManager->getFullHelp()) { text += MWGui::ToolTips::getMiscString(ref->ref.owner, "Owner"); text += MWGui::ToolTips::getMiscString(ref->base->script, "Script"); diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index ab766dc56a..5c69cedb62 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -51,26 +51,35 @@ void ToolTips::onFrame(float frameDuration) std::string type = focus->getUserString("ToolTipType"); std::string text = focus->getUserString("ToolTipText"); + + ToolTipInfo info; + if (type == "") { mDynamicToolTipBox->setVisible(false); return; - } + } else if (type == "Text") - tooltipSize = createToolTip(text, "", 0, ""); + { + info.caption = text; + } else if (type == "CaptionText") { std::string caption = focus->getUserString("ToolTipCaption"); - tooltipSize = createToolTip(caption, "", 0, text); + info.caption = caption; + info.text = text; } else if (type == "ImageCaptionText") { std::string caption = focus->getUserString("ToolTipCaption"); std::string image = focus->getUserString("ToolTipImage"); std::string sizeString = focus->getUserString("ToolTipImageSize"); - int size = (sizeString != "" ? boost::lexical_cast(sizeString) : 32); - tooltipSize = createToolTip(caption, image, size, text); + + info.text = text; + info.caption = caption; + info.icon = image; } + tooltipSize = createToolTip(info); IntPoint tooltipPosition = InputManager::getInstance().getMousePosition() + IntPoint(0, 24); @@ -137,14 +146,7 @@ IntSize ToolTips::getToolTipViaPtr () mDynamicToolTipBox->setVisible(true); ToolTipInfo info = object.getToolTipInfo(mFocusObject, mWindowManager->getEnvironment()); - if (info.icon == "") - { - tooltipSize = createToolTip(info.caption, "", 0, info.text); - } - else - { - tooltipSize = createToolTip(info.caption, info.icon, 32, info.text); - } + tooltipSize = createToolTip(info); } return tooltipSize; @@ -164,12 +166,16 @@ void ToolTips::findImageExtension(std::string& image) } } -IntSize ToolTips::createToolTip(const std::string& caption, const std::string& image, const int imageSize, const std::string& text) +IntSize ToolTips::createToolTip(const ToolTipInfo& info) { + std::string caption = info.caption; + std::string image = info.icon; + int imageSize = (image != "") ? 32 : 0; + std::string text = info.text; + // remove the first newline (easier this way) - std::string realText = text; - if (realText.size() > 0 && realText[0] == '\n') - realText.erase(0, 1); + if (text.size() > 0 && text[0] == '\n') + text.erase(0, 1); // this the maximum width of the tooltip before it starts word-wrapping setCoord(0, 0, 300, 300); @@ -193,13 +199,13 @@ IntSize ToolTips::createToolTip(const std::string& caption, const std::string& i textWidget->setProperty("Static", "true"); textWidget->setProperty("MultiLine", "true"); textWidget->setProperty("WordWrap", "true"); - textWidget->setCaption(realText); + textWidget->setCaption(text); textWidget->setTextAlign(Align::HCenter | Align::Top); IntSize textSize = textWidget->getTextSize(); captionSize += IntSize(imageSize, 0); // adjust for image IntSize totalSize = IntSize( std::max(textSize.width, captionSize.width + ((image != "") ? imageCaptionHPadding : 0)), - ((realText != "") ? textSize.height + imageCaptionVPadding : 0) + captionHeight ); + ((text != "") ? textSize.height + imageCaptionVPadding : 0) + captionHeight ); if (image != "") { diff --git a/apps/openmw/mwgui/tooltips.hpp b/apps/openmw/mwgui/tooltips.hpp index d84a1093be..c00faba869 100644 --- a/apps/openmw/mwgui/tooltips.hpp +++ b/apps/openmw/mwgui/tooltips.hpp @@ -13,11 +13,21 @@ namespace MWGui struct ToolTipInfo { public: + ToolTipInfo() : + enchant(0), + effects(0) + { + }; + std::string caption; std::string text; std::string icon; - /// \todo enchantments (armor, cloth, weapons), magic effects (potions, ingredients) + // enchantment (for cloth, armor, weapons) + const ESM::Enchantment* enchant; + + // effects (for potions, ingredients) + const ESM::EffectList* effects; }; class ToolTips : public OEngine::GUI::Layout @@ -56,7 +66,7 @@ namespace MWGui MyGUI::IntSize getToolTipViaPtr (); ///< @return requested tooltip size - MyGUI::IntSize createToolTip(const std::string& caption, const std::string& image, const int imageSize, const std::string& text); + MyGUI::IntSize createToolTip(const ToolTipInfo& info); ///< @return requested tooltip size bool mGameMode; diff --git a/apps/openmw/mwgui/widgets.cpp b/apps/openmw/mwgui/widgets.cpp index 74603aaf1c..c833834681 100644 --- a/apps/openmw/mwgui/widgets.cpp +++ b/apps/openmw/mwgui/widgets.cpp @@ -290,6 +290,12 @@ void MWSpellEffect::updateWidgets() { if (magicEffect) { + std::string pt = mWindowManager->getGameSettingString("spoint", ""); + std::string pts = mWindowManager->getGameSettingString("spoints", ""); + std::string to = " " + mWindowManager->getGameSettingString("sTo", "") + " "; + std::string sec = " " + mWindowManager->getGameSettingString("ssecond", ""); + std::string secs = " " + mWindowManager->getGameSettingString("sseconds", ""); + // TODO: Get name of effect from GMST std::string spellLine = ""; if (effect.skill >= 0 && effect.skill < ESM::Skill::Length) @@ -313,22 +319,24 @@ void MWSpellEffect::updateWidgets() if (effect.magnMin >= 0 || effect.magnMax >= 0) { if (effect.magnMin == effect.magnMax) - spellLine += " " + boost::lexical_cast(effect.magnMin) + " pts"; + spellLine += " " + boost::lexical_cast(effect.magnMin) + " " + ((effect.magnMin == 1) ? pt : pts); else { - spellLine += " " + boost::lexical_cast(effect.magnMin) + " to " + boost::lexical_cast(effect.magnMin) + " pts"; + spellLine += " " + boost::lexical_cast(effect.magnMin) + to + boost::lexical_cast(effect.magnMin) + " " + pts; } } if (effect.duration >= 0) { - spellLine += " for " + boost::lexical_cast(effect.duration) + " secs"; + spellLine += " " + mWindowManager->getGameSettingString("sfor", "") + " " + boost::lexical_cast(effect.duration) + ((effect.duration == 1) ? sec : secs); } + + std::string on = mWindowManager->getGameSettingString("sonword", ""); if (effect.range == ESM::RT_Self) - spellLine += " on Self"; + spellLine += " " + on + " " + mWindowManager->getGameSettingString("sRangeSelf", ""); else if (effect.range == ESM::RT_Touch) - spellLine += " on Touch"; + spellLine += " " + on + " " + mWindowManager->getGameSettingString("sRangeTouch", ""); else if (effect.range == ESM::RT_Target) - spellLine += " on Target"; + spellLine += " " + on + " " + mWindowManager->getGameSettingString("sRangeTarget", ""); static_cast(textWidget)->setCaption(spellLine); } else From c7381d44917629cd804875c23ded7ab2d3cbd539 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 18 Apr 2012 18:09:30 +0200 Subject: [PATCH 036/325] adding widget MWEnchantment --- apps/openmw/mwgui/widgets.cpp | 44 +++++++++++++++++++++++++++++++++++ apps/openmw/mwgui/widgets.hpp | 29 ++++++++++++++++++++++- 2 files changed, 72 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/widgets.cpp b/apps/openmw/mwgui/widgets.cpp index c833834681..568b31455c 100644 --- a/apps/openmw/mwgui/widgets.cpp +++ b/apps/openmw/mwgui/widgets.cpp @@ -264,6 +264,50 @@ MWSpell::~MWSpell() { } +/* MWEnchantment */ + +MWEnchantment::MWEnchantment() + : mWindowManager(nullptr) +{ +} + +void MWEnchantment::setEnchantmentId(const std::string &enchantId) +{ + id = enchantId; + updateWidgets(); +} + +void MWEnchantment::createEffectWidgets(std::vector &effects, MyGUI::WidgetPtr creator, MyGUI::IntCoord &coord) +{ + const ESMS::ESMStore &store = mWindowManager->getStore(); + const ESM::Enchantment *enchant = store.enchants.search(id); + MYGUI_ASSERT(enchant, "enchantment with id '" << id << "' not found"); + + MWSpellEffectPtr effect = nullptr; + std::vector::const_iterator end = enchant->effects.list.end(); + for (std::vector::const_iterator it = enchant->effects.list.begin(); it != end; ++it) + { + effect = creator->createWidget("MW_EffectImage", coord, MyGUI::Align::Default); + effect->setWindowManager(mWindowManager); + effect->setSpellEffect(*it); + effects.push_back(effect); + coord.top += effect->getHeight(); + } +} + +void MWEnchantment::updateWidgets() +{ +} + +void MWEnchantment::initialiseOverride() +{ + Base::initialiseOverride(); +} + +MWEnchantment::~MWEnchantment() +{ +} + /* MWSpellEffect */ MWSpellEffect::MWSpellEffect() diff --git a/apps/openmw/mwgui/widgets.hpp b/apps/openmw/mwgui/widgets.hpp index a7916285eb..595ee83b64 100644 --- a/apps/openmw/mwgui/widgets.hpp +++ b/apps/openmw/mwgui/widgets.hpp @@ -126,7 +126,7 @@ namespace MWGui protected: virtual ~MWSpell(); - virtual void initialiseOverride(); + virtual void initialiseOverride(); private: void updateWidgets(); @@ -137,6 +137,33 @@ namespace MWGui }; typedef MWSpell* MWSpellPtr; + class MYGUI_EXPORT MWEnchantment : public Widget + { + MYGUI_RTTI_DERIVED( MWEnchantment ); + public: + MWEnchantment(); + + typedef MWMechanics::Stat EnchantmentValue; + + void setWindowManager(WindowManager* parWindowManager) { mWindowManager = parWindowManager; } + void setEnchantmentId(const std::string &enchantId); + void createEffectWidgets(std::vector &effects, MyGUI::WidgetPtr creator, MyGUI::IntCoord &coord); + + const std::string &getSpellId() const { return id; } + + protected: + virtual ~MWEnchantment(); + + virtual void initialiseOverride(); + + private: + void updateWidgets(); + + WindowManager* mWindowManager; + std::string id; + }; + typedef MWEnchantment* MWEnchantmentPtr; + class MYGUI_EXPORT MWSpellEffect : public Widget { MYGUI_RTTI_DERIVED( MWSpellEffect ); From 4889902b9879aecdf45542b2d5584052de15cb9e Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 18 Apr 2012 21:18:53 +0200 Subject: [PATCH 037/325] magic effect widget improvements, read name of effect from GMST and don't show duration/target for constant effects --- apps/openmw/mwgui/birth.cpp | 2 +- apps/openmw/mwgui/widgets.cpp | 180 ++++++++++++++++++++++++++++--- apps/openmw/mwgui/widgets.hpp | 6 +- files/mygui/openmw_list.skin.xml | 4 + 4 files changed, 178 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwgui/birth.cpp b/apps/openmw/mwgui/birth.cpp index 44c165743d..046017204f 100644 --- a/apps/openmw/mwgui/birth.cpp +++ b/apps/openmw/mwgui/birth.cpp @@ -202,7 +202,7 @@ void BirthDialog::updateSpells() MyGUI::IntCoord spellCoord = coord; spellCoord.height = 24; // TODO: This should be fetched from the skin somehow, or perhaps a widget in the layout as a template? - spellWidget->createEffectWidgets(spellItems, spellArea, spellCoord); + spellWidget->createEffectWidgets(spellItems, spellArea, spellCoord, category); coord.top = spellCoord.top; ++i; diff --git a/apps/openmw/mwgui/widgets.cpp b/apps/openmw/mwgui/widgets.cpp index 568b31455c..58cfee991b 100644 --- a/apps/openmw/mwgui/widgets.cpp +++ b/apps/openmw/mwgui/widgets.cpp @@ -222,7 +222,7 @@ void MWSpell::setSpellId(const std::string &spellId) updateWidgets(); } -void MWSpell::createEffectWidgets(std::vector &effects, MyGUI::WidgetPtr creator, MyGUI::IntCoord &coord) +void MWSpell::createEffectWidgets(std::vector &effects, MyGUI::WidgetPtr creator, MyGUI::IntCoord &coord, const int category) { const ESMS::ESMStore &store = mWindowManager->getStore(); const ESM::Spell *spell = store.spells.search(id); @@ -234,6 +234,7 @@ void MWSpell::createEffectWidgets(std::vector &effects, MyGUI: { effect = creator->createWidget("MW_EffectImage", coord, MyGUI::Align::Default); effect->setWindowManager(mWindowManager); + effect->setConstant(category == 0); effect->setSpellEffect(*it); effects.push_back(effect); coord.top += effect->getHeight(); @@ -340,8 +341,7 @@ void MWSpellEffect::updateWidgets() std::string sec = " " + mWindowManager->getGameSettingString("ssecond", ""); std::string secs = " " + mWindowManager->getGameSettingString("sseconds", ""); - // TODO: Get name of effect from GMST - std::string spellLine = ""; + std::string spellLine = effectIDToString(effect.effectID); if (effect.skill >= 0 && effect.skill < ESM::Skill::Length) { spellLine += " " + mWindowManager->getGameSettingString(ESM::Skill::sSkillNameIds[effect.skill], ""); @@ -369,18 +369,24 @@ void MWSpellEffect::updateWidgets() spellLine += " " + boost::lexical_cast(effect.magnMin) + to + boost::lexical_cast(effect.magnMin) + " " + pts; } } - if (effect.duration >= 0) + + // constant effects have no duration and no target + if (!mIsConstant) { - spellLine += " " + mWindowManager->getGameSettingString("sfor", "") + " " + boost::lexical_cast(effect.duration) + ((effect.duration == 1) ? sec : secs); + if (effect.duration >= 0) + { + spellLine += " " + mWindowManager->getGameSettingString("sfor", "") + " " + boost::lexical_cast(effect.duration) + ((effect.duration == 1) ? sec : secs); + } + + std::string on = mWindowManager->getGameSettingString("sonword", ""); + if (effect.range == ESM::RT_Self) + spellLine += " " + on + " " + mWindowManager->getGameSettingString("sRangeSelf", ""); + else if (effect.range == ESM::RT_Touch) + spellLine += " " + on + " " + mWindowManager->getGameSettingString("sRangeTouch", ""); + else if (effect.range == ESM::RT_Target) + spellLine += " " + on + " " + mWindowManager->getGameSettingString("sRangeTarget", ""); } - std::string on = mWindowManager->getGameSettingString("sonword", ""); - if (effect.range == ESM::RT_Self) - spellLine += " " + on + " " + mWindowManager->getGameSettingString("sRangeSelf", ""); - else if (effect.range == ESM::RT_Touch) - spellLine += " " + on + " " + mWindowManager->getGameSettingString("sRangeTouch", ""); - else if (effect.range == ESM::RT_Target) - spellLine += " " + on + " " + mWindowManager->getGameSettingString("sRangeTarget", ""); static_cast(textWidget)->setCaption(spellLine); } else @@ -394,6 +400,156 @@ void MWSpellEffect::updateWidgets() } } +std::string MWSpellEffect::effectIDToString(const short effectID) +{ + // Map effect ID to GMST name + // http://www.uesp.net/morrow/hints/mweffects.shtml + std::map names; + names[85] ="sEffectAbsorbAttribute"; + names[88] ="sEffectAbsorbFatigue"; + names[86] ="sEffectAbsorbHealth"; + names[87] ="sEffectAbsorbSpellPoints"; + names[89] ="sEffectAbsorbSkill"; + names[63] ="sEffectAlmsiviIntervention"; + names[47] ="sEffectBlind"; + names[123] ="sEffectBoundBattleAxe"; + names[129] ="sEffectBoundBoots"; + names[127] ="sEffectBoundCuirass"; + names[120] ="sEffectBoundDagger"; + names[131] ="sEffectBoundGloves"; + names[128] ="sEffectBoundHelm"; + names[125] ="sEffectBoundLongbow"; + names[121] ="sEffectBoundLongsword"; + names[122] ="sEffectBoundMace"; + names[130] ="sEffectBoundShield"; + names[124] ="sEffectBoundSpear"; + names[7] ="sEffectBurden"; + names[50] ="sEffectCalmCreature"; + names[49] ="sEffectCalmHumanoid"; + names[40] ="sEffectChameleon"; + names[44] ="sEffectCharm"; + names[118] ="sEffectCommandCreatures"; + names[119] ="sEffectCommandHumanoids"; + names[132] ="sEffectCorpus"; // NB this typo. (bethesda made it) + names[70] ="sEffectCureBlightDisease"; + names[69] ="sEffectCureCommonDisease"; + names[71] ="sEffectCureCorprusDisease"; + names[73] ="sEffectCureParalyzation"; + names[72] ="sEffectCurePoison"; + names[22] ="sEffectDamageAttribute"; + names[25] ="sEffectDamageFatigue"; + names[23] ="sEffectDamageHealth"; + names[24] ="sEffectDamageMagicka"; + names[26] ="sEffectDamageSkill"; + names[54] ="sEffectDemoralizeCreature"; + names[53] ="sEffectDemoralizeHumanoid"; + names[64] ="sEffectDetectAnimal"; + names[65] ="sEffectDetectEnchantment"; + names[66] ="sEffectDetectKey"; + names[38] ="sEffectDisintegrateArmor"; + names[37] ="sEffectDisintegrateWeapon"; + names[57] ="sEffectDispel"; + names[62] ="sEffectDivineIntervention"; + names[17] ="sEffectDrainAttribute"; + names[20] ="sEffectDrainFatigue"; + names[18] ="sEffectDrainHealth"; + names[19] ="sEffectDrainSpellpoints"; + names[21] ="sEffectDrainSkill"; + names[8] ="sEffectFeather"; + names[14] ="sEffectFireDamage"; + names[4] ="sEffectFireShield"; + names[117] ="sEffectFortifyAttackBonus"; + names[79] ="sEffectFortifyAttribute"; + names[82] ="sEffectFortifyFatigue"; + names[80] ="sEffectFortifyHealth"; + names[81] ="sEffectFortifySpellpoints"; + names[84] ="sEffectFortifyMagickaMultiplier"; + names[83] ="sEffectFortifySkill"; + names[52] ="sEffectFrenzyCreature"; + names[51] ="sEffectFrenzyHumanoid"; + names[16] ="sEffectFrostDamage"; + names[6] ="sEffectFrostShield"; + names[39] ="sEffectInvisibility"; + names[9] ="sEffectJump"; + names[10] ="sEffectLevitate"; + names[41] ="sEffectLight"; + names[5] ="sEffectLightningShield"; + names[12] ="sEffectLock"; + names[60] ="sEffectMark"; + names[43] ="sEffectNightEye"; + names[13] ="sEffectOpen"; + names[45] ="sEffectParalyze"; + names[27] ="sEffectPoison"; + names[56] ="sEffectRallyCreature"; + names[55] ="sEffectRallyHumanoid"; + names[61] ="sEffectRecall"; + names[68] ="sEffectReflect"; + names[100] ="sEffectRemoveCurse"; + names[95] ="sEffectResistBlightDisease"; + names[94] ="sEffectResistCommonDisease"; + names[96] ="sEffectResistCorprusDisease"; + names[90] ="sEffectResistFire"; + names[91] ="sEffectResistFrost"; + names[93] ="sEffectResistMagicka"; + names[98] ="sEffectResistNormalWeapons"; + names[99] ="sEffectResistParalysis"; + names[97] ="sEffectResistPoison"; + names[92] ="sEffectResistShock"; + names[74] ="sEffectRestoreAttribute"; + names[77] ="sEffectRestoreFatigue"; + names[75] ="sEffectRestoreHealth"; + names[76] ="sEffectRestoreSpellPoints"; + names[78] ="sEffectRestoreSkill"; + names[42] ="sEffectSanctuary"; + names[3] ="sEffectShield"; + names[15] ="sEffectShockDamage"; + names[46] ="sEffectSilence"; + names[11] ="sEffectSlowFall"; + names[58] ="sEffectSoultrap"; + names[48] ="sEffectSound"; + names[67] ="sEffectSpellAbsorption"; + names[136] ="sEffectStuntedMagicka"; + names[106] ="sEffectSummonAncestralGhost"; + names[110] ="sEffectSummonBonelord"; + names[108] ="sEffectSummonLeastBonewalker"; + names[134] ="sEffectSummonCenturionSphere"; + names[103] ="sEffectSummonClannfear"; + names[104] ="sEffectSummonDaedroth"; + names[105] ="sEffectSummonDremora"; + names[114] ="sEffectSummonFlameAtronach"; + names[115] ="sEffectSummonFrostAtronach"; + names[113] ="sEffectSummonGoldenSaint"; + names[109] ="sEffectSummonGreaterBonewalker"; + names[112] ="sEffectSummonHunger"; + names[102] ="sEffectSummonScamp"; + names[107] ="sEffectSummonSkeletalMinion"; + names[116] ="sEffectSummonStormAtronach"; + names[111] ="sEffectSummonWingedTwilight"; + names[135] ="sEffectSunDamage"; + names[1] ="sEffectSwiftSwim"; + names[59] ="sEffectTelekinesis"; + names[101] ="sEffectTurnUndead"; + names[133] ="sEffectVampirism"; + names[0] ="sEffectWaterBreathing"; + names[2] ="sEffectWaterWalking"; + names[33] ="sEffectWeaknesstoBlightDisease"; + names[32] ="sEffectWeaknesstoCommonDisease"; + names[34] ="sEffectWeaknesstoCorprusDisease"; + names[28] ="sEffectWeaknesstoFire"; + names[29] ="sEffectWeaknesstoFrost"; + names[31] ="sEffectWeaknesstoMagicka"; + names[36] ="sEffectWeaknesstoNormalWeapons"; + names[35] ="sEffectWeaknesstoPoison"; + names[30] ="sEffectWeaknesstoShock"; + + assert(names.find(effectID) != names.end() && "Unimplemented effect type"); + std::string res = mWindowManager->getGameSettingString(names[effectID], ""); + if (res == "") + std::cout << "Warning: Unknown effect name " << names[effectID] << std::endl; + + return res; +} + MWSpellEffect::~MWSpellEffect() { } diff --git a/apps/openmw/mwgui/widgets.hpp b/apps/openmw/mwgui/widgets.hpp index 595ee83b64..8ac27795d5 100644 --- a/apps/openmw/mwgui/widgets.hpp +++ b/apps/openmw/mwgui/widgets.hpp @@ -119,7 +119,7 @@ namespace MWGui void setWindowManager(WindowManager* parWindowManager) { mWindowManager = parWindowManager; } void setSpellId(const std::string &id); - void createEffectWidgets(std::vector &effects, MyGUI::WidgetPtr creator, MyGUI::IntCoord &coord); + void createEffectWidgets(std::vector &effects, MyGUI::WidgetPtr creator, MyGUI::IntCoord &coord, const int category); const std::string &getSpellId() const { return id; } @@ -174,6 +174,9 @@ namespace MWGui void setWindowManager(WindowManager* parWindowManager) { mWindowManager = parWindowManager; } void setSpellEffect(SpellEffectValue value); + void setConstant(bool constant) { mIsConstant = constant; } + + std::string effectIDToString(const short effectID); const SpellEffectValue &getSpellEffect() const { return effect; } @@ -188,6 +191,7 @@ namespace MWGui WindowManager* mWindowManager; SpellEffectValue effect; + bool mIsConstant; // constant effect MyGUI::ImageBox* imageWidget; MyGUI::TextBox* textWidget; }; diff --git a/files/mygui/openmw_list.skin.xml b/files/mygui/openmw_list.skin.xml index 5ec975a1b0..02075ad1a6 100644 --- a/files/mygui/openmw_list.skin.xml +++ b/files/mygui/openmw_list.skin.xml @@ -184,6 +184,10 @@ + + + + From 934caf7a2b7efca4f69e2cc3040be41ffe5a42aa Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 19 Apr 2012 01:16:41 +0200 Subject: [PATCH 038/325] removed --report-focus which is now useless --- apps/openmw/engine.cpp | 51 ------------------------------------------ apps/openmw/engine.hpp | 6 ----- apps/openmw/main.cpp | 4 ---- readme.txt | 1 - 4 files changed, 62 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 36a2cb645b..77cb80b0d1 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -72,47 +72,6 @@ void OMW::Engine::executeLocalScripts() localScripts.setIgnore (MWWorld::Ptr()); } -void OMW::Engine::updateFocusReport (float duration) -{ - - if ((mFocusTDiff += duration)>0.25) - { - mFocusTDiff = 0; - - std::string name; - - std::string handle = mEnvironment.mWorld->getFacedHandle(); - - if (!handle.empty()) - { - // the faced handle is not updated immediately, so on a cell change it might - // point to an object that doesn't exist anymore - // therefore, we are catching the "Unknown Ogre handle" exception that occurs in this case - try - { - MWWorld::Ptr ptr = mEnvironment.mWorld->getPtrViaHandle (handle); - - if (!ptr.isEmpty()){ - name = MWWorld::Class::get (ptr).getName (ptr); - - } - } - catch (std::runtime_error& e) - {} - } - - if (name!=mFocusName) - { - mFocusName = name; - - if (mFocusName.empty()) - std::cout << "Unfocus" << std::endl; - else - std::cout << "Focus: " << name << std::endl; - } - } -} - void OMW::Engine::setAnimationVerbose(bool animverbose){ if(animverbose){ NifOgre::NIFLoader::getSingletonPtr()->setOutputAnimFiles(true); @@ -170,10 +129,6 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt) window->getBatchCount()); mEnvironment.mWindowManager->onFrame(mEnvironment.mFrameDuration); - - // report focus object (for debugging) - if (mReportFocus) - updateFocusReport (mEnvironment.mFrameDuration); } catch (const std::exception& e) { @@ -191,7 +146,6 @@ OMW::Engine::Engine(Files::ConfigurationManager& configurationManager) , mNewGame (false) , mUseSound (true) , mCompileAll (false) - , mReportFocus (false) , mFocusTDiff (0) , mScriptContext (0) , mFSStrict (false) @@ -303,11 +257,6 @@ void OMW::Engine::setNewGame(bool newGame) mNewGame = newGame; } -void OMW::Engine::setReportFocus (bool report) -{ - mReportFocus = report; -} - // Initialise and enter main loop. void OMW::Engine::go() diff --git a/apps/openmw/engine.hpp b/apps/openmw/engine.hpp index 6eae20cc0f..a95d4cb5c3 100644 --- a/apps/openmw/engine.hpp +++ b/apps/openmw/engine.hpp @@ -73,7 +73,6 @@ namespace OMW bool mNewGame; bool mUseSound; bool mCompileAll; - bool mReportFocus; float mFocusTDiff; std::string mFocusName; std::map mFallbackMap; @@ -100,8 +99,6 @@ namespace OMW void executeLocalScripts(); - void updateFocusReport (float duration); - virtual bool frameRenderingQueued (const Ogre::FrameEvent& evt); public: @@ -144,9 +141,6 @@ namespace OMW /// Start as a new game. void setNewGame(bool newGame); - /// Write name of focussed object to cout - void setReportFocus (bool report); - /// Initialise and enter main loop. void go(); diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index df52faab14..68aa12fb36 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -155,9 +155,6 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat "\n\twin1251 - Cyrillic alphabet such as Russian, Bulgarian, Serbian Cyrillic and other languages\n" "\n\twin1252 - Western European (Latin) alphabet, used by default") - ("report-focus", bpo::value()->implicit_value(true) - ->default_value(false), "write name of focussed object to cout") - ("fallback", bpo::value()->default_value(FallbackMap(), "") ->multitoken()->composing(), "fallback values") @@ -265,7 +262,6 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat engine.setSoundUsage(!variables["nosound"].as()); engine.setScriptsVerbosity(variables["script-verbose"].as()); engine.setCompileAll(variables["script-all"].as()); - engine.setReportFocus(variables["report-focus"].as()); engine.setAnimationVerbose(variables["anim-verbose"].as()); engine.setFallbackValues(variables["fallback"].as().mMap); diff --git a/readme.txt b/readme.txt index 52c4e11a24..53f4a4c59e 100644 --- a/readme.txt +++ b/readme.txt @@ -87,7 +87,6 @@ Allowed options: win1252 - Western European (Latin) alphabet, used by default - --report-focus [=arg(=1)] (=0) write name of focussed object to cout --fallback arg fallback values From 00260a24ce0c125582b48a1a2ca4d3457913cf5b Mon Sep 17 00:00:00 2001 From: Jason Hooks Date: Wed, 18 Apr 2012 21:28:25 -0400 Subject: [PATCH 039/325] Water corrections --- libs/openengine/bullet/pmove.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libs/openengine/bullet/pmove.cpp b/libs/openengine/bullet/pmove.cpp index 214a7e5989..7741d2f047 100644 --- a/libs/openengine/bullet/pmove.cpp +++ b/libs/openengine/bullet/pmove.cpp @@ -1730,6 +1730,7 @@ void PM_SetWaterLevel( playerMove* const pm ) pm->ps.waterlevel = WL_ANKLE; //point[2] = pm->ps->origin[2] + MINS_Z + sample1; point.z = pm->ps.origin.z + MINS_Z + sample1; + checkWater = (pml.hasWater && pml.waterHeight > point.z); //cont = pm->pointcontents (point, pm->ps->clientNum ); //if ( cont & MASK_WATER ) if (checkWater) @@ -1739,6 +1740,7 @@ void PM_SetWaterLevel( playerMove* const pm ) point.z = pm->ps.origin.z + MINS_Z + sample2; //cont = pm->pointcontents (point, pm->ps->clientNum ); //if ( cont & MASK_WATER ) + checkWater = (pml.hasWater && pml.waterHeight > point.z); if (checkWater ) pm->ps.waterlevel = WL_UNDERWATER; } From 1e8d894e1c9562010847fe4a5632055bab1093b3 Mon Sep 17 00:00:00 2001 From: gugus Date: Sat, 21 Apr 2012 10:51:01 +0200 Subject: [PATCH 040/325] Starting inventory window --- apps/openmw/mwgui/container.cpp | 21 +++++++++++++++++-- apps/openmw/mwgui/container.hpp | 1 + apps/openmw/mwgui/inventorywindow.cpp | 11 ++++++++++ apps/openmw/mwgui/inventorywindow.hpp | 30 +++++++++++++++++++++++++++ apps/openmw/mwgui/window_manager.cpp | 7 ++++++- apps/openmw/mwgui/window_manager.hpp | 2 ++ 6 files changed, 69 insertions(+), 3 deletions(-) create mode 100644 apps/openmw/mwgui/inventorywindow.cpp create mode 100644 apps/openmw/mwgui/inventorywindow.hpp diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 3f27351a98..bc3bcf4752 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -41,6 +41,23 @@ ContainerWindow::ContainerWindow(WindowManager& parWindowManager,MWWorld::Enviro setText("TakeButton","Take All"); } +ContainerWindow::ContainerWindow(WindowManager& parWindowManager,MWWorld::Environment& environment,std::string guiFile) + : WindowBase(guiFile, parWindowManager), + mEnvironment(environment) +{ + setText("_Main", "Name of Container"); + //center(); + adjustWindowCaption(); + + getWidget(containerWidget, "Items"); + //getWidget(takeButton, "TakeButton"); + //getWidget(closeButton, "CloseButton"); + + //closeButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ContainerWindow::onByeClicked); + + //setText("CloseButton","Close"); + //setText("TakeButton","Take All"); +} ContainerWindow::~ContainerWindow() { } @@ -60,7 +77,7 @@ void ContainerWindow::open(MWWorld::Ptr& container) MWWorld::ContainerStore& containerStore = MWWorld::Class::get(container).getContainerStore(container); - MWWorld::ManualRef furRef (mWindowManager.getStore(), "fur_cuirass"); + /*MWWorld::ManualRef furRef (mWindowManager.getStore(), "fur_cuirass"); furRef.getPtr().getRefData().setCount (5); MWWorld::ManualRef bukkitRef (mWindowManager.getStore(), "misc_com_bucket_01"); MWWorld::ManualRef broomRef (mWindowManager.getStore(), "misc_com_broom_01"); @@ -89,7 +106,7 @@ void ContainerWindow::open(MWWorld::Ptr& container) containerStore.add(bukkitRef.getPtr()); containerStore.add(bukkitRef.getPtr()); containerStore.add(bukkitRef.getPtr()); - containerStore.add(goldRef.getPtr()); + containerStore.add(goldRef.getPtr());*/ diff --git a/apps/openmw/mwgui/container.hpp b/apps/openmw/mwgui/container.hpp index 76905a6814..3802d21afb 100644 --- a/apps/openmw/mwgui/container.hpp +++ b/apps/openmw/mwgui/container.hpp @@ -36,6 +36,7 @@ namespace MWGui { public: ContainerWindow(WindowManager& parWindowManager,MWWorld::Environment& environment); + ContainerWindow(WindowManager& parWindowManager,MWWorld::Environment& environment,std::string guiFile); void open(MWWorld::Ptr& container); diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp new file mode 100644 index 0000000000..7f3884bc17 --- /dev/null +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -0,0 +1,11 @@ +#include "inventorywindow.hpp" + +namespace MWGui +{ + + InventoryWindow::InventoryWindow(WindowManager& parWindowManager,MWWorld::Environment& environment) + :ContainerWindow(parWindowManager,environment,"openmw_inventory_window_layout.xml") + { + } + +} \ No newline at end of file diff --git a/apps/openmw/mwgui/inventorywindow.hpp b/apps/openmw/mwgui/inventorywindow.hpp new file mode 100644 index 0000000000..ce177014a1 --- /dev/null +++ b/apps/openmw/mwgui/inventorywindow.hpp @@ -0,0 +1,30 @@ +#ifndef MGUI_Inventory_H +#define MGUI_Inventory_H + +#include "container.hpp" +namespace MWWorld +{ + class Environment; +} + +namespace MyGUI +{ + class Gui; + class Widget; +} + +namespace MWGui +{ + class WindowManager; +} + + +namespace MWGui +{ + class InventoryWindow : public MWGui::ContainerWindow + { + public: + InventoryWindow(WindowManager& parWindowManager,MWWorld::Environment& environment); + }; +} +#endif // Inventory_H diff --git a/apps/openmw/mwgui/window_manager.cpp b/apps/openmw/mwgui/window_manager.cpp index 34048c935d..065141963e 100644 --- a/apps/openmw/mwgui/window_manager.cpp +++ b/apps/openmw/mwgui/window_manager.cpp @@ -8,6 +8,7 @@ #include "stats_window.hpp" #include "messagebox.hpp" #include "container.hpp" +#include "inventorywindow.hpp" #include "../mwmechanics/mechanicsmanager.hpp" #include "../mwinput/inputmanager.hpp" @@ -82,6 +83,7 @@ WindowManager::WindowManager(MWWorld::Environment& environment, mMessageBoxManager = new MessageBoxManager(this); dialogueWindow = new DialogueWindow(*this,environment); containerWindow = new ContainerWindow(*this,environment); + mInventoryWindow = new InventoryWindow(*this,environment); // The HUD is always on hud->setVisible(true); @@ -121,6 +123,7 @@ WindowManager::~WindowManager() delete mJournal; delete dialogueWindow; delete containerWindow; + delete mInventoryWindow; delete mCharGen; cleanupGarbage(); @@ -182,6 +185,7 @@ void WindowManager::updateVisible() mJournal->setVisible(false); dialogueWindow->setVisible(false); containerWindow->setVisible(false); + mInventoryWindow->setVisible(false); // Mouse is visible whenever we're not in game mode MyGUI::PointerManager::getInstance().setVisible(isGuiMode()); @@ -217,11 +221,12 @@ void WindowManager::updateVisible() // Show the windows we want map -> setVisible( (eff & GW_Map) != 0 ); stats -> setVisible( (eff & GW_Stats) != 0 ); - + mInventoryWindow->setVisible(true); break; } case GM_Container: containerWindow->setVisible(true); + mInventoryWindow->setVisible(true); break; case GM_Dialogue: dialogueWindow->open(); diff --git a/apps/openmw/mwgui/window_manager.hpp b/apps/openmw/mwgui/window_manager.hpp index 4f54b41b8a..438a99a0ef 100644 --- a/apps/openmw/mwgui/window_manager.hpp +++ b/apps/openmw/mwgui/window_manager.hpp @@ -63,6 +63,7 @@ namespace MWGui class JournalWindow; class CharacterCreation; class ContainerWindow; + class InventoryWindow; class TextInputDialog; class InfoBoxDialog; class DialogueWindow; @@ -204,6 +205,7 @@ namespace MWGui JournalWindow* mJournal; DialogueWindow *dialogueWindow; ContainerWindow *containerWindow; + InventoryWindow *mInventoryWindow; CharacterCreation* mCharGen; // Various stats about player as needed by window manager From 33654535c19b22f103bcf547dc337620d6ac5feb Mon Sep 17 00:00:00 2001 From: gugus Date: Sat, 21 Apr 2012 11:05:30 +0200 Subject: [PATCH 041/325] The inventory window now display the inventory of the player --- apps/openmw/mwgui/container.hpp | 2 +- apps/openmw/mwgui/inventorywindow.cpp | 23 +++++++++++++++++++++++ apps/openmw/mwgui/inventorywindow.hpp | 2 ++ apps/openmw/mwgui/window_manager.cpp | 2 ++ 4 files changed, 28 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/container.hpp b/apps/openmw/mwgui/container.hpp index 3802d21afb..5bb0192337 100644 --- a/apps/openmw/mwgui/container.hpp +++ b/apps/openmw/mwgui/container.hpp @@ -44,8 +44,8 @@ namespace MWGui void Update(); virtual ~ContainerWindow(); + protected: - private: MWWorld::Environment& mEnvironment; std::vector containerWidgets; MyGUI::WidgetPtr containerWidget; diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 7f3884bc17..188cc3796f 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -1,5 +1,23 @@ #include "inventorywindow.hpp" +#include +#include +#include "window_manager.hpp" +#include "widgets.hpp" +#include "../mwworld/environment.hpp" +#include "../mwworld/manualref.hpp" +#include +#include +#include + +#include +#include +#include "../mwclass/container.hpp" +#include "../mwworld/containerstore.hpp" +#include +#include "../mwworld/class.hpp" +#include "../mwworld/world.hpp" +#include "../mwworld/player.hpp" namespace MWGui { @@ -8,4 +26,9 @@ namespace MWGui { } + void InventoryWindow::openInventory() + { + open(mEnvironment.mWorld->getPlayer().getPlayer()); + } + } \ No newline at end of file diff --git a/apps/openmw/mwgui/inventorywindow.hpp b/apps/openmw/mwgui/inventorywindow.hpp index ce177014a1..bf9be43757 100644 --- a/apps/openmw/mwgui/inventorywindow.hpp +++ b/apps/openmw/mwgui/inventorywindow.hpp @@ -25,6 +25,8 @@ namespace MWGui { public: InventoryWindow(WindowManager& parWindowManager,MWWorld::Environment& environment); + + void openInventory(); }; } #endif // Inventory_H diff --git a/apps/openmw/mwgui/window_manager.cpp b/apps/openmw/mwgui/window_manager.cpp index 065141963e..c15f7077dd 100644 --- a/apps/openmw/mwgui/window_manager.cpp +++ b/apps/openmw/mwgui/window_manager.cpp @@ -222,11 +222,13 @@ void WindowManager::updateVisible() map -> setVisible( (eff & GW_Map) != 0 ); stats -> setVisible( (eff & GW_Stats) != 0 ); mInventoryWindow->setVisible(true); + mInventoryWindow->openInventory(); break; } case GM_Container: containerWindow->setVisible(true); mInventoryWindow->setVisible(true); + mInventoryWindow->openInventory(); break; case GM_Dialogue: dialogueWindow->open(); From d4e9b62436dd691380f1ba78fdc161843503a4c5 Mon Sep 17 00:00:00 2001 From: gugus Date: Sat, 21 Apr 2012 11:11:40 +0200 Subject: [PATCH 042/325] oups forgot to modify CMake --- apps/openmw/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 769bcc6c3d..f37f8dae41 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -25,7 +25,7 @@ add_openmw_dir (mwinput add_openmw_dir (mwgui layouts text_input widgets race class birth review window_manager console dialogue dialogue_history window_base stats_window messagebox journalwindow charactercreation container - map_window window_pinnable_base cursorreplace + map_window window_pinnable_base cursorreplace inventorywindow ) add_openmw_dir (mwdialogue From 25432d97d2d325639fe280d8530e1933d1206cdd Mon Sep 17 00:00:00 2001 From: gugus Date: Sat, 21 Apr 2012 20:35:45 +0200 Subject: [PATCH 043/325] trying to get selected item. Doesn't work. --- apps/openmw/mwgui/container.cpp | 17 +++++++++++------ apps/openmw/mwgui/container.hpp | 6 +++--- files/mygui/openmw_container_window_layout.xml | 10 +++++----- files/mygui/openmw_inventory_window_layout.xml | 2 +- 4 files changed, 20 insertions(+), 15 deletions(-) diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 2c09d6b293..9071c9b35f 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -35,7 +35,7 @@ ContainerWindow::ContainerWindow(WindowManager& parWindowManager,MWWorld::Enviro //center(); adjustWindowCaption(); - getWidget(containerWidget, "Items"); + getWidget(mContainerWidget, "Items"); getWidget(takeButton, "TakeButton"); getWidget(closeButton, "CloseButton"); @@ -43,6 +43,7 @@ ContainerWindow::ContainerWindow(WindowManager& parWindowManager,MWWorld::Enviro setText("CloseButton","Close"); setText("TakeButton","Take All"); + mContainerWidget->eventMouseItemActivate += MyGUI::newDelegate(this,&ContainerWindow::onSelectedItem); } ContainerWindow::ContainerWindow(WindowManager& parWindowManager,MWWorld::Environment& environment,std::string guiFile) @@ -52,8 +53,7 @@ ContainerWindow::ContainerWindow(WindowManager& parWindowManager,MWWorld::Enviro setText("_Main", "Name of Container"); //center(); adjustWindowCaption(); - - getWidget(containerWidget, "Items"); + getWidget(mContainerWidget, "Items"); //getWidget(takeButton, "TakeButton"); //getWidget(closeButton, "CloseButton"); @@ -61,6 +61,7 @@ ContainerWindow::ContainerWindow(WindowManager& parWindowManager,MWWorld::Enviro //setText("CloseButton","Close"); //setText("TakeButton","Take All"); + mContainerWidget->eventMouseItemActivate += MyGUI::newDelegate(this,&ContainerWindow::onSelectedItem); } ContainerWindow::~ContainerWindow() { @@ -126,8 +127,8 @@ void ContainerWindow::open(MWWorld::Ptr& container) path+=MWWorld::Class::get(*iter).getInventoryIcon(*iter); count++; - MyGUI::ImageBox* image = containerWidget->createWidget("ImageBox", MyGUI::IntCoord(x, y, 32, 32), MyGUI::Align::Default); - MyGUI::TextBox* text = containerWidget->createWidget("SandBrightText", MyGUI::IntCoord(x, y, 18, 18), MyGUI::Align::Default, std::string("Label")); + MyGUI::ImageBox* image = mContainerWidget->createWidget("ImageBox", MyGUI::IntCoord(x, y, 32, 32), MyGUI::Align::Default); + MyGUI::TextBox* text = mContainerWidget->createWidget("SandBrightText", MyGUI::IntCoord(x, y, 18, 18), MyGUI::Align::Default, std::string("Label")); x += 36; if(count % 20 == 0) @@ -140,7 +141,7 @@ void ContainerWindow::open(MWWorld::Ptr& container) if(iter->getRefData().getCount() > 1) text->setCaption(boost::lexical_cast(iter->getRefData().getCount())); - containerWidgets.push_back(image); + mContainerWidgets.push_back(image); int pos = path.rfind("."); path.erase(pos); @@ -167,3 +168,7 @@ void ContainerWindow::onByeClicked(MyGUI::Widget* _sender) setVisible(false); } +void ContainerWindow::onSelectedItem(MyGUI::ItemBox* _sender, size_t _index) +{ + std::cout << "selected!"; +} \ No newline at end of file diff --git a/apps/openmw/mwgui/container.hpp b/apps/openmw/mwgui/container.hpp index 5bb0192337..0e68baf021 100644 --- a/apps/openmw/mwgui/container.hpp +++ b/apps/openmw/mwgui/container.hpp @@ -47,15 +47,15 @@ namespace MWGui protected: MWWorld::Environment& mEnvironment; - std::vector containerWidgets; - MyGUI::WidgetPtr containerWidget; + std::vector mContainerWidgets; + MyGUI::ItemBoxPtr mContainerWidget; MyGUI::ButtonPtr takeButton; MyGUI::ButtonPtr closeButton; void onByeClicked(MyGUI::Widget* _sender); - + void onSelectedItem(MyGUI::ItemBox* _sender, size_t _index); //MWWorld::Ptr& mContainer; }; diff --git a/files/mygui/openmw_container_window_layout.xml b/files/mygui/openmw_container_window_layout.xml index 7fce9e187c..31b0364684 100644 --- a/files/mygui/openmw_container_window_layout.xml +++ b/files/mygui/openmw_container_window_layout.xml @@ -1,19 +1,19 @@ - + - + - + diff --git a/files/mygui/openmw_inventory_window_layout.xml b/files/mygui/openmw_inventory_window_layout.xml index c69b6d8fe2..766cacdb1e 100644 --- a/files/mygui/openmw_inventory_window_layout.xml +++ b/files/mygui/openmw_inventory_window_layout.xml @@ -14,7 +14,7 @@ - + From 16855291a7c640d1b796448a529784299c1bd632 Mon Sep 17 00:00:00 2001 From: Jason Hooks Date: Sat, 21 Apr 2012 16:21:30 -0400 Subject: [PATCH 044/325] Implementing snapping --- apps/openmw/mwworld/physicssystem.cpp | 2 + libs/openengine/bullet/pmove.cpp | 84 ++++++++++++++++----------- libs/openengine/bullet/pmove.h | 7 ++- 3 files changed, 58 insertions(+), 35 deletions(-) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index d224385ae5..9af7a72852 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -27,6 +27,8 @@ namespace MWWorld NifBullet::ManualBulletShapeLoader* shapeLoader = new NifBullet::ManualBulletShapeLoader(); mEngine = new OEngine::Physic::PhysicEngine(shapeLoader); playerphysics->mEngine = mEngine; + //playerphysics->ps.snappingImplemented = true; + } diff --git a/libs/openengine/bullet/pmove.cpp b/libs/openengine/bullet/pmove.cpp index 7741d2f047..82f473085f 100644 --- a/libs/openengine/bullet/pmove.cpp +++ b/libs/openengine/bullet/pmove.cpp @@ -417,7 +417,7 @@ int PM_StepSlideMove( bool gravity ) Ogre::Vector3 up, down; float stepSize; - + std::cout << "StepSlideMove\n"; // start_o = pm->ps->origin //VectorCopy (pm->ps->origin, start_o); start_o = pm->ps.origin; @@ -516,6 +516,7 @@ int PM_StepSlideMove( bool gravity ) delta = pm->ps.origin.z - start_o.z; if ( delta > 2 ) { + pm->ps.counter = 10; if (gravity) printf("g on: %f ", delta); else @@ -688,6 +689,7 @@ static bool PM_CheckJump(void) pm->ps.groundEntityNum = ENTITYNUM_NONE; pm->ps.velocity.z = JUMP_VELOCITY; + pm->ps.bSnap = false; //PM_AddEvent( EV_JUMP ); /*if ( pm->cmd.forwardmove >= 0 ) @@ -840,7 +842,7 @@ static void PM_WalkMove( playerMove* const pmove ) playerMove::playercmd cmd; float accelerate; float vel; - + //pm->ps.gravity = 4000; if ( pm->ps.waterlevel > 2 && //DotProduct( pml.forward, pml.groundTrace.plane.normal ) > 0 ) pml.forward.dotProduct(pml.groundTrace.planenormal) > 0.0f) @@ -1142,9 +1144,7 @@ void PM_GroundTraceMissed() { traceResults trace; Ogre::Vector3 point; - - if ( pm->ps.groundEntityNum != ENTITYNUM_NONE ) - { + std::cout << "Ground trace missed\n"; // we just transitioned into freefall //if ( pm->debugLevel ) //Com_Printf("%i:lift\n", c_pmove); @@ -1154,29 +1154,28 @@ void PM_GroundTraceMissed() //VectorCopy( pm->ps->origin, point ); point = pm->ps.origin; //point[2] -= 64; - point.z -= 64; + point.z -= 32; //pm->trace (&trace, pm->ps->origin, pm->mins, pm->maxs, point, pm->ps->clientNum, pm->tracemask); //tracefunc(&trace, *(const D3DXVECTOR3* const)&(pm->ps.origin), *(const D3DXVECTOR3* const)&point, D3DXVECTOR3(0.0f, -64.0f, 0.0f), 0, pml.traceObj); newtrace(&trace, pm->ps.origin, point, halfExtents, Ogre::Math::DegreesToRadians(pm->ps.viewangles.y), pm->isInterior, pm->mEngine); - if ( trace.fraction == 1.0 ) + //It hit the ground below + if ( trace.fraction < 1.0 && pm->ps.origin.z > trace.endpos.z) { - if ( pm->cmd.forwardmove >= 0 ) - { - //PM_ForceLegsAnim( LEGS_JUMP ); - //pm->ps->pm_flags &= ~PMF_BACKWARDS_JUMP; - } - else - { - //PM_ForceLegsAnim( LEGS_JUMPB ); - //pm->ps->pm_flags |= PMF_BACKWARDS_JUMP; - } + pm->ps.origin = trace.endpos; + pml.walking = true; + pml.groundPlane = true; + pm->ps.groundEntityNum = trace.entityNum; + } - } + else{ + pm->ps.groundEntityNum = ENTITYNUM_NONE; + pml.groundPlane = false; + pml.walking = false; + pm->ps.bSnap = false; + } - pm->ps.groundEntityNum = ENTITYNUM_NONE; - pml.groundPlane = false; - pml.walking = false; + } static bool PM_CorrectAllSolid(traceResults* const trace) @@ -1404,19 +1403,26 @@ static void PM_GroundTrace( void ) return; } } - - // if the trace didn't hit anything, we are in free fall - if ( trace.fraction == 1.0 ) + // if the trace didn't hit anything, we are in free fall + if ( trace.fraction == 1.0) { - PM_GroundTraceMissed(); - pml.groundPlane = false; - pml.walking = false; + if(pm->ps.snappingImplemented){ + if(pm->ps.bSnap && pm->ps.counter <= 0) + PM_GroundTraceMissed(); + } + + return; } + else + { + //It hit something, so we are on the ground + pm->ps.bSnap = true; - // check if getting thrown off the ground + } + // check if getting thrown off the ground //if ( pm->ps->velocity[2] > 0 && DotProduct( pm->ps->velocity, trace.plane.normal ) > 10 ) - if (pm->ps.velocity.z > 0 && pm->ps.velocity.dotProduct(trace.planenormal) > 10.0f) + if (pm->ps.velocity.z > 0 && pm->ps.velocity.dotProduct(trace.planenormal) > 10.0f ) { //if ( pm->debugLevel ) //Com_Printf("%i:kickoff\n", c_pmove); @@ -1432,13 +1438,22 @@ static void PM_GroundTrace( void ) PM_ForceLegsAnim( LEGS_JUMPB ); pm->ps->pm_flags |= PMF_BACKWARDS_JUMP; }*/ - + if(!pm->ps.bSnap){ pm->ps.groundEntityNum = ENTITYNUM_NONE; pml.groundPlane = false; pml.walking = false; + } + else + { + pml.groundPlane = true; + pml.walking = true; + } return; } + + + // slopes that are too steep will not be considered onground //if ( trace.plane.normal[2] < MIN_WALK_NORMAL ) if (trace.planenormal.z < MIN_WALK_NORMAL) @@ -1500,7 +1515,7 @@ static void PM_AirMove() float wishspeed; float scale; playerMove::playercmd cmd; - + //pm->ps.gravity = 800; PM_Friction(); fmove = pm->cmd.forwardmove; @@ -1508,7 +1523,6 @@ static void PM_AirMove() cmd = pm->cmd; scale = PM_CmdScale( &cmd ); - // set the movementDir so clients can rotate the legs for strafing //PM_SetMovementDir(); @@ -1749,7 +1763,7 @@ void PM_SetWaterLevel( playerMove* const pm ) void PmoveSingle (playerMove* const pmove) { - + pmove->ps.counter--; //pm = pmove; // Aedra doesn't support Q3-style VM traps D: //while(1); @@ -1763,6 +1777,10 @@ void PmoveSingle (playerMove* const pmove) pm->ps.watertype = 0; pm->ps.waterlevel = WL_DRYLAND; + if(pml.walking) + std::cout << "Walking\n"; + else + std::cout << "Not Walking\n"; //if ( pm->ps->stats[STAT_HEALTH] <= 0 ) //pm->tracemask &= ~CONTENTS_BODY; // corpses can fly through bodies diff --git a/libs/openengine/bullet/pmove.h b/libs/openengine/bullet/pmove.h index 304572b021..a14a1e660d 100644 --- a/libs/openengine/bullet/pmove.h +++ b/libs/openengine/bullet/pmove.h @@ -42,7 +42,7 @@ static const Ogre::Vector3 halfExtents(14.64f * 2, 14.24f * 2, 33.25f * 2); #define ENTITYNUM_NONE (MAX_GENTITIES - 1) #define ENTITYNUM_WORLD (MAX_GENTITIES - 2) #define MIN_WALK_NORMAL 0.7f // can't walk on very steep slopes -#define JUMP_VELOCITY (270 * 1) +#define JUMP_VELOCITY (270) #define PS_PMOVEFRAMECOUNTBITS 6 #define MINS_Z -24 #define DEFAULT_VIEWHEIGHT 26 @@ -90,7 +90,7 @@ struct playerMove { struct playerStruct { - playerStruct() : gravity(800.0f), speed(480.0f), pmove_framecount(20), groundEntityNum(ENTITYNUM_NONE), commandTime(40), move_type(PM_NOCLIP), pm_time(0) + playerStruct() : gravity(800.0f), speed(480.0f), pmove_framecount(20), groundEntityNum(ENTITYNUM_NONE), commandTime(40), move_type(PM_NOCLIP), pm_time(0), snappingImplemented(true), bSnap(false), counter(-1) { origin = Ogre::Vector3(733.164f,900.0f, 839.432f); velocity = Ogre::Vector3(0.0f, 0.0f, 0.0f); @@ -117,6 +117,9 @@ struct playerMove Ogre::Vector3 velocity; Ogre::Vector3 origin; + bool bSnap; + bool snappingImplemented; + int counter; float gravity; // default = 800 float speed; // default = 320 From 8ebae0b7061ee3ef4056c5cbbd123c3917427725 Mon Sep 17 00:00:00 2001 From: Jason Hooks Date: Sat, 21 Apr 2012 16:57:46 -0400 Subject: [PATCH 045/325] Solid trace --- apps/openmw/mwworld/physicssystem.cpp | 2 +- libs/openengine/bullet/pmove.cpp | 4 ---- libs/openengine/bullet/trace.cpp | 2 +- 3 files changed, 2 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 9af7a72852..63bf8dda39 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -27,7 +27,7 @@ namespace MWWorld NifBullet::ManualBulletShapeLoader* shapeLoader = new NifBullet::ManualBulletShapeLoader(); mEngine = new OEngine::Physic::PhysicEngine(shapeLoader); playerphysics->mEngine = mEngine; - //playerphysics->ps.snappingImplemented = true; + } diff --git a/libs/openengine/bullet/pmove.cpp b/libs/openengine/bullet/pmove.cpp index 82f473085f..922fd844c0 100644 --- a/libs/openengine/bullet/pmove.cpp +++ b/libs/openengine/bullet/pmove.cpp @@ -1777,10 +1777,6 @@ void PmoveSingle (playerMove* const pmove) pm->ps.watertype = 0; pm->ps.waterlevel = WL_DRYLAND; - if(pml.walking) - std::cout << "Walking\n"; - else - std::cout << "Not Walking\n"; //if ( pm->ps->stats[STAT_HEALTH] <= 0 ) //pm->tracemask &= ~CONTENTS_BODY; // corpses can fly through bodies diff --git a/libs/openengine/bullet/trace.cpp b/libs/openengine/bullet/trace.cpp index ca68a5d5c0..81c064c2d3 100644 --- a/libs/openengine/bullet/trace.cpp +++ b/libs/openengine/bullet/trace.cpp @@ -172,7 +172,7 @@ const bool NewPhysicsTrace(NewPhysTraceResults* const out, const Ogre::Vector3& if (!TestPointAgainstAabb2(aabbMin, aabbMax, *(const btVector3* const)&(start) ) ) { //We're solid - out->startSolid = false; + out->startSolid = true; } } } From 1b02b503a231dde098c7318b466db583e1da106c Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 22 Apr 2012 21:06:08 +0200 Subject: [PATCH 046/325] gcc compile fix --- apps/openmw/mwgui/container.cpp | 4 ++-- apps/openmw/mwgui/container.hpp | 2 +- apps/openmw/mwgui/inventorywindow.cpp | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 9071c9b35f..ac9330fdce 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -74,7 +74,7 @@ void ContainerWindow::setName(std::string contName) -void ContainerWindow::open(MWWorld::Ptr& container) +void ContainerWindow::open(MWWorld::Ptr container) { setName(MWWorld::Class::get(container).getName(container)); //MWWorld::ContainerStore* containerStore = container.getContainerStore(); @@ -171,4 +171,4 @@ void ContainerWindow::onByeClicked(MyGUI::Widget* _sender) void ContainerWindow::onSelectedItem(MyGUI::ItemBox* _sender, size_t _index) { std::cout << "selected!"; -} \ No newline at end of file +} diff --git a/apps/openmw/mwgui/container.hpp b/apps/openmw/mwgui/container.hpp index 0e68baf021..a7787b3738 100644 --- a/apps/openmw/mwgui/container.hpp +++ b/apps/openmw/mwgui/container.hpp @@ -39,7 +39,7 @@ namespace MWGui ContainerWindow(WindowManager& parWindowManager,MWWorld::Environment& environment,std::string guiFile); - void open(MWWorld::Ptr& container); + void open(MWWorld::Ptr container); void setName(std::string contName); void Update(); diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 188cc3796f..81a1902902 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -31,4 +31,4 @@ namespace MWGui open(mEnvironment.mWorld->getPlayer().getPlayer()); } -} \ No newline at end of file +} From a6419c3596a123584df3ed8a25e4650a9a3e655b Mon Sep 17 00:00:00 2001 From: gugus Date: Thu, 26 Apr 2012 19:35:45 +0200 Subject: [PATCH 047/325] Clicking on an item is now detected. Trying to have items follow the mouse position, but it doesn't work yet. --- apps/openmw/mwgui/container.cpp | 25 +++++++++++++++++++------ apps/openmw/mwgui/container.hpp | 3 ++- 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 9071c9b35f..e3d7574f3a 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -43,7 +43,7 @@ ContainerWindow::ContainerWindow(WindowManager& parWindowManager,MWWorld::Enviro setText("CloseButton","Close"); setText("TakeButton","Take All"); - mContainerWidget->eventMouseItemActivate += MyGUI::newDelegate(this,&ContainerWindow::onSelectedItem); + //mContainerWidget->eventMouseItemActivate += MyGUI::newDelegate(this,&ContainerWindow::onSelectedItem); } ContainerWindow::ContainerWindow(WindowManager& parWindowManager,MWWorld::Environment& environment,std::string guiFile) @@ -61,7 +61,7 @@ ContainerWindow::ContainerWindow(WindowManager& parWindowManager,MWWorld::Enviro //setText("CloseButton","Close"); //setText("TakeButton","Take All"); - mContainerWidget->eventMouseItemActivate += MyGUI::newDelegate(this,&ContainerWindow::onSelectedItem); + //mContainerWidget->eventMouseItemActivate += MyGUI::newDelegate(this,&ContainerWindow::onSelectedItem); } ContainerWindow::~ContainerWindow() { @@ -128,8 +128,9 @@ void ContainerWindow::open(MWWorld::Ptr& container) count++; MyGUI::ImageBox* image = mContainerWidget->createWidget("ImageBox", MyGUI::IntCoord(x, y, 32, 32), MyGUI::Align::Default); - MyGUI::TextBox* text = mContainerWidget->createWidget("SandBrightText", MyGUI::IntCoord(x, y, 18, 18), MyGUI::Align::Default, std::string("Label")); - + MyGUI::TextBox* text = image->createWidget("SandBrightText", MyGUI::IntCoord(x, y, 18, 18), MyGUI::Align::Default, std::string("Label")); + image->eventMouseButtonClick += MyGUI::newDelegate(this,&ContainerWindow::onSelectedItem); + image->eventMouseMove += MyGUI::newDelegate(this,&ContainerWindow::onMouseMove); x += 36; if(count % 20 == 0) { @@ -141,7 +142,7 @@ void ContainerWindow::open(MWWorld::Ptr& container) if(iter->getRefData().getCount() > 1) text->setCaption(boost::lexical_cast(iter->getRefData().getCount())); - mContainerWidgets.push_back(image); + //mContainerWidgets.push_back(image); int pos = path.rfind("."); path.erase(pos); @@ -168,7 +169,19 @@ void ContainerWindow::onByeClicked(MyGUI::Widget* _sender) setVisible(false); } -void ContainerWindow::onSelectedItem(MyGUI::ItemBox* _sender, size_t _index) +void ContainerWindow::onSelectedItem(MyGUI::Widget* _sender) { + _sender->detachFromWidget(); + _sender->attachToWidget(mContainerWidget->getParent()->getParent()); + std::cout << mContainerWidget->getParent()->getParent()->getName(); + _sender->setUserString("drag","on"); std::cout << "selected!"; +} + +void ContainerWindow::onMouseMove(MyGUI::Widget* _sender, int _left, int _top) +{ + if(_sender->getUserString("drag") == "on") + { + _sender->setPosition(_left,_top); + } } \ No newline at end of file diff --git a/apps/openmw/mwgui/container.hpp b/apps/openmw/mwgui/container.hpp index 0e68baf021..6ac9a814f7 100644 --- a/apps/openmw/mwgui/container.hpp +++ b/apps/openmw/mwgui/container.hpp @@ -55,7 +55,8 @@ namespace MWGui void onByeClicked(MyGUI::Widget* _sender); - void onSelectedItem(MyGUI::ItemBox* _sender, size_t _index); + void onSelectedItem(MyGUI::Widget* _sender); + void onMouseMove(MyGUI::Widget* _sender, int _left, int _top); //MWWorld::Ptr& mContainer; }; From 5603cb312cd6f00f06fe88597e5d2e202d53e292 Mon Sep 17 00:00:00 2001 From: gugus Date: Fri, 27 Apr 2012 20:54:39 +0200 Subject: [PATCH 048/325] Objects can now be selected and follow mouse movements. --- apps/openmw/mwgui/container.cpp | 37 +++++++++++++++++++-------- apps/openmw/mwgui/container.hpp | 9 ++++--- apps/openmw/mwgui/inventorywindow.cpp | 4 +-- apps/openmw/mwgui/inventorywindow.hpp | 2 +- apps/openmw/mwgui/window_manager.cpp | 11 +++++--- files/mygui/openmw_layers.xml | 1 + 6 files changed, 45 insertions(+), 19 deletions(-) diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index e3d7574f3a..b3fe7adfbb 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -17,15 +17,17 @@ #include "../mwworld/containerstore.hpp" #include #include "../mwworld/class.hpp" +#include "../mwinput/inputmanager.hpp" using namespace MWGui; using namespace Widgets; -ContainerWindow::ContainerWindow(WindowManager& parWindowManager,MWWorld::Environment& environment) +ContainerWindow::ContainerWindow(WindowManager& parWindowManager,MWWorld::Environment& environment,MyGUI::Widget* dragAndDropWidget) : WindowBase("openmw_container_window_layout.xml", parWindowManager), - mEnvironment(environment) + mEnvironment(environment), + mDragAndDropWidget(dragAndDropWidget) { setText("_Main", "Name of Container"); @@ -43,17 +45,24 @@ ContainerWindow::ContainerWindow(WindowManager& parWindowManager,MWWorld::Enviro setText("CloseButton","Close"); setText("TakeButton","Take All"); + + mIsOnDragAndDrop = false; + mDraggedWidget = 0; //mContainerWidget->eventMouseItemActivate += MyGUI::newDelegate(this,&ContainerWindow::onSelectedItem); } -ContainerWindow::ContainerWindow(WindowManager& parWindowManager,MWWorld::Environment& environment,std::string guiFile) +ContainerWindow::ContainerWindow(WindowManager& parWindowManager,MWWorld::Environment& environment,MyGUI::Widget* dragAndDropWidget,std::string guiFile) : WindowBase(guiFile, parWindowManager), - mEnvironment(environment) + mEnvironment(environment), + mDragAndDropWidget(dragAndDropWidget) { setText("_Main", "Name of Container"); //center(); adjustWindowCaption(); getWidget(mContainerWidget, "Items"); + + mIsOnDragAndDrop = false; + mDraggedWidget = 0; //getWidget(takeButton, "TakeButton"); //getWidget(closeButton, "CloseButton"); @@ -130,7 +139,7 @@ void ContainerWindow::open(MWWorld::Ptr& container) MyGUI::ImageBox* image = mContainerWidget->createWidget("ImageBox", MyGUI::IntCoord(x, y, 32, 32), MyGUI::Align::Default); MyGUI::TextBox* text = image->createWidget("SandBrightText", MyGUI::IntCoord(x, y, 18, 18), MyGUI::Align::Default, std::string("Label")); image->eventMouseButtonClick += MyGUI::newDelegate(this,&ContainerWindow::onSelectedItem); - image->eventMouseMove += MyGUI::newDelegate(this,&ContainerWindow::onMouseMove); + //image->eventMouseMove += MyGUI::newDelegate(this,&ContainerWindow::onMouseMove); x += 36; if(count % 20 == 0) { @@ -159,7 +168,12 @@ void ContainerWindow::open(MWWorld::Ptr& container) void ContainerWindow::Update() { - + if(mIsOnDragAndDrop) + { + if(mDraggedWidget) + mDraggedWidget->setPosition(MyGUI::InputManager::getInstance().getMousePosition()); + else mIsOnDragAndDrop = false; //If this happens, there is a bug. + } } void ContainerWindow::onByeClicked(MyGUI::Widget* _sender) @@ -171,17 +185,20 @@ void ContainerWindow::onByeClicked(MyGUI::Widget* _sender) void ContainerWindow::onSelectedItem(MyGUI::Widget* _sender) { + mIsOnDragAndDrop = true; _sender->detachFromWidget(); - _sender->attachToWidget(mContainerWidget->getParent()->getParent()); - std::cout << mContainerWidget->getParent()->getParent()->getName(); + _sender->attachToWidget(mDragAndDropWidget); + //std::cout << mContainerWidget->getParent()->getParent()->getName(); _sender->setUserString("drag","on"); + mDraggedWidget = _sender; std::cout << "selected!"; } void ContainerWindow::onMouseMove(MyGUI::Widget* _sender, int _left, int _top) { - if(_sender->getUserString("drag") == "on") + /*if(_sender->getUserString("drag") == "on") { _sender->setPosition(_left,_top); - } + + }*/ } \ No newline at end of file diff --git a/apps/openmw/mwgui/container.hpp b/apps/openmw/mwgui/container.hpp index 6ac9a814f7..2d1aa3ac03 100644 --- a/apps/openmw/mwgui/container.hpp +++ b/apps/openmw/mwgui/container.hpp @@ -35,8 +35,9 @@ namespace MWGui class ContainerWindow : public WindowBase { public: - ContainerWindow(WindowManager& parWindowManager,MWWorld::Environment& environment); - ContainerWindow(WindowManager& parWindowManager,MWWorld::Environment& environment,std::string guiFile); + ContainerWindow(WindowManager& parWindowManager,MWWorld::Environment& environment,MyGUI::Widget* dragAndDropWidget); + ContainerWindow(WindowManager& parWindowManager,MWWorld::Environment& environment,MyGUI::Widget* dragAndDropWidget, + std::string guiFile); void open(MWWorld::Ptr& container); @@ -52,7 +53,9 @@ namespace MWGui MyGUI::ButtonPtr takeButton; MyGUI::ButtonPtr closeButton; - + MyGUI::Widget* mDragAndDropWidget; + bool mIsOnDragAndDrop; + MyGUI::Widget* mDraggedWidget; void onByeClicked(MyGUI::Widget* _sender); void onSelectedItem(MyGUI::Widget* _sender); diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 188cc3796f..efc9106e91 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -21,8 +21,8 @@ namespace MWGui { - InventoryWindow::InventoryWindow(WindowManager& parWindowManager,MWWorld::Environment& environment) - :ContainerWindow(parWindowManager,environment,"openmw_inventory_window_layout.xml") + InventoryWindow::InventoryWindow(WindowManager& parWindowManager,MWWorld::Environment& environment,MyGUI::Widget* dragAndDropWidget) + :ContainerWindow(parWindowManager,environment,dragAndDropWidget,"openmw_inventory_window_layout.xml") { } diff --git a/apps/openmw/mwgui/inventorywindow.hpp b/apps/openmw/mwgui/inventorywindow.hpp index bf9be43757..c60889d73f 100644 --- a/apps/openmw/mwgui/inventorywindow.hpp +++ b/apps/openmw/mwgui/inventorywindow.hpp @@ -24,7 +24,7 @@ namespace MWGui class InventoryWindow : public MWGui::ContainerWindow { public: - InventoryWindow(WindowManager& parWindowManager,MWWorld::Environment& environment); + InventoryWindow(WindowManager& parWindowManager,MWWorld::Environment& environment,MyGUI::Widget* dragAndDropWidget); void openInventory(); }; diff --git a/apps/openmw/mwgui/window_manager.cpp b/apps/openmw/mwgui/window_manager.cpp index c15f7077dd..f2adfe1e16 100644 --- a/apps/openmw/mwgui/window_manager.cpp +++ b/apps/openmw/mwgui/window_manager.cpp @@ -65,7 +65,7 @@ WindowManager::WindowManager(MWWorld::Environment& environment, // Set up the GUI system mGuiManager = new OEngine::GUI::MyGUIManager(mOgre->getWindow(), mOgre->getScene(), false, logpath); gui = mGuiManager->getGui(); - + //Register own widgets with MyGUI MyGUI::FactoryManager::getInstance().registerFactory("Widget"); @@ -74,6 +74,9 @@ WindowManager::WindowManager(MWWorld::Environment& environment, int w = MyGUI::RenderManager::getInstance().getViewSize().width; int h = MyGUI::RenderManager::getInstance().getViewSize().height; + MyGUI::Widget* dragAndDropWidget = gui->createWidgetT("Widget","",0,0,w,h,MyGUI::Align::Default,"DragAndDrop","DragAndDropWidget"); + dragAndDropWidget->setVisible(false); + hud = new HUD(w,h, showFPSLevel); menu = new MainMenu(w,h); map = new MapWindow(*this); @@ -82,8 +85,8 @@ WindowManager::WindowManager(MWWorld::Environment& environment, mJournal = new JournalWindow(*this); mMessageBoxManager = new MessageBoxManager(this); dialogueWindow = new DialogueWindow(*this,environment); - containerWindow = new ContainerWindow(*this,environment); - mInventoryWindow = new InventoryWindow(*this,environment); + containerWindow = new ContainerWindow(*this,environment,dragAndDropWidget); + mInventoryWindow = new InventoryWindow(*this,environment,dragAndDropWidget); // The HUD is always on hud->setVisible(true); @@ -422,6 +425,8 @@ void WindowManager::onDialogueWindowBye() void WindowManager::onFrame (float frameDuration) { mMessageBoxManager->onFrame(frameDuration); + mInventoryWindow->Update(); + containerWindow->Update(); } const ESMS::ESMStore& WindowManager::getStore() const diff --git a/files/mygui/openmw_layers.xml b/files/mygui/openmw_layers.xml index a83eb970a8..81cd99fead 100644 --- a/files/mygui/openmw_layers.xml +++ b/files/mygui/openmw_layers.xml @@ -10,4 +10,5 @@ + From af3ccd85e313d3d5e26b50a3ce9b745df6c3d894 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 28 Apr 2012 21:23:24 +0200 Subject: [PATCH 049/325] determine shield weight (tested with some light/medium/heavy shields) --- apps/openmw/mwclass/armor.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index 3a34032611..d4dab13d4b 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -138,8 +138,7 @@ namespace MWClass case ESM::Armor::Boots: typeGmst = "iBootsWeight"; break; case ESM::Armor::LGauntlet: case ESM::Armor::RGauntlet: typeGmst = "iGauntletWeight"; break; -/// \todo how to determine if shield light, medium or heavy? -// case ESM::Armor::Shield: + case ESM::Armor::Shield: typeGmst = "iShieldWeight"; break; case ESM::Armor::LBracer: case ESM::Armor::RBracer: typeGmst = "iGauntletWeight"; break; } From 11ebae3be2d3d5750d532e56af511b2717b7c377 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 29 Apr 2012 03:33:10 +0200 Subject: [PATCH 050/325] toggleCompositors command useful for debugging --- apps/openmw/CMakeLists.txt | 1 + apps/openmw/mwrender/renderingmanager.cpp | 45 ++++++++++++----------- apps/openmw/mwrender/renderingmanager.hpp | 6 +++ apps/openmw/mwrender/water.cpp | 20 ++++------ apps/openmw/mwrender/water.hpp | 4 +- apps/openmw/mwscript/docs/vmformat.txt | 3 +- apps/openmw/mwscript/miscextensions.cpp | 19 ++++++++++ apps/openmw/mwworld/world.hpp | 3 +- 8 files changed, 64 insertions(+), 37 deletions(-) diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index fb0e1db694..deb57cfec0 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -16,6 +16,7 @@ source_group(game FILES ${GAME} ${GAME_HEADER}) add_openmw_dir (mwrender renderingmanager debugging sky player animation npcanimation creatureanimation actors objects renderinginterface localmap occlusionquery terrain terrainmaterial water shadows shaderhelper + compositors ) add_openmw_dir (mwinput diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index a95a179c6c..11d3dca6de 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -18,6 +18,7 @@ #include "shaderhelper.hpp" #include "localmap.hpp" #include "water.hpp" +#include "compositors.hpp" using namespace MWRender; using namespace Ogre; @@ -29,6 +30,8 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const { mRendering.createScene("PlayerCam", Settings::Manager::getFloat("field of view", "General"), 5); + mCompositors = new Compositors(mRendering.getViewport()); + mWater = 0; //The fog type must be set before any terrain objects are created as if the @@ -67,15 +70,15 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const // note that the order is important here if (useMRT()) { - CompositorManager::getSingleton().addCompositor(mRendering.getViewport(), "gbuffer"); - CompositorManager::getSingleton().setCompositorEnabled(mRendering.getViewport(), "gbuffer", true); - CompositorManager::getSingleton().addCompositor(mRendering.getViewport(), "Underwater"); - CompositorManager::getSingleton().addCompositor(mRendering.getViewport(), "gbufferFinalizer"); - CompositorManager::getSingleton().setCompositorEnabled(mRendering.getViewport(), "gbufferFinalizer", true); + mCompositors->addCompositor("gbuffer", 0); + mCompositors->setCompositorEnabled("gbuffer", true); + mCompositors->addCompositor("Underwater", 1); + mCompositors->addCompositor("gbufferFinalizer", 2); + mCompositors->setCompositorEnabled("gbufferFinalizer", true); } else { - CompositorManager::getSingleton().addCompositor(mRendering.getViewport(), "UnderwaterNoMRT"); + mCompositors->addCompositor("UnderwaterNoMRT", 0); } // Turn the entire scene (represented by the 'root' node) -90 @@ -120,6 +123,7 @@ RenderingManager::~RenderingManager () delete mTerrainManager; delete mLocalMap; delete mOcclusionQuery; + delete mCompositors; } MWRender::SkyManager* RenderingManager::getSkyManager() @@ -231,7 +235,7 @@ void RenderingManager::update (float duration){ void RenderingManager::waterAdded (MWWorld::Ptr::CellStore *store){ if(store->cell->data.flags & store->cell->HasWater){ if(mWater == 0) - mWater = new MWRender::Water(mRendering.getCamera(), mSkyManager, store->cell); + mWater = new MWRender::Water(mRendering.getCamera(), this, store->cell); else mWater->changeCell(store->cell); mWater->setActive(true); @@ -292,35 +296,29 @@ void RenderingManager::skySetMoonColour (bool red){ bool RenderingManager::toggleRenderMode(int mode) { - if (mode != MWWorld::World::Render_Wireframe) + if (mode == MWWorld::World::Render_CollisionDebug || mode == MWWorld::World::Render_Pathgrid) return mDebugging->toggleRenderMode(mode); - else // if (mode == MWWorld::World::Render_Wireframe) + else if (mode == MWWorld::World::Render_Wireframe) { if (mRendering.getCamera()->getPolygonMode() == PM_SOLID) { - // disable compositors - if (useMRT()) - { - CompositorManager::getSingleton().setCompositorEnabled(mRendering.getViewport(), "gbuffer", false); - CompositorManager::getSingleton().setCompositorEnabled(mRendering.getViewport(), "gbufferFinalizer", false); - } + mCompositors->setEnabled(false); mRendering.getCamera()->setPolygonMode(PM_WIREFRAME); return true; } else { - // re-enable compositors - if (useMRT()) - { - CompositorManager::getSingleton().setCompositorEnabled(mRendering.getViewport(), "gbuffer", true); - CompositorManager::getSingleton().setCompositorEnabled(mRendering.getViewport(), "gbufferFinalizer", true); - } + mCompositors->setEnabled(true); mRendering.getCamera()->setPolygonMode(PM_SOLID); return false; } } + else //if (mode == MWWorld::World::Render_Compositors) + { + return mCompositors->toggle(); + } } void RenderingManager::configureFog(ESMS::CellStore &mCell) @@ -518,4 +516,9 @@ void RenderingManager::switchToExterior() mRendering.getScene()->setCameraRelativeRendering(true); } +Compositors* RenderingManager::getCompositors() +{ + return mCompositors; +} + } // namespace diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 0d11b3d57d..4e32965989 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -47,6 +47,7 @@ namespace MWRender class ShaderHelper; class LocalMap; class Water; + class Compositors; class RenderingManager: private RenderingInterface { @@ -67,6 +68,7 @@ class RenderingManager: private RenderingInterface { /// to internal details of the rendering system anymore SkyManager* getSkyManager(); + Compositors* getCompositors(); void toggleLight(); bool toggleRenderMode(int mode); @@ -157,6 +159,8 @@ class RenderingManager: private RenderingInterface { bool mSunEnabled; + bool mCompositorsEnabled; + SkyManager* mSkyManager; OcclusionQuery* mOcclusionQuery; @@ -192,6 +196,8 @@ class RenderingManager: private RenderingInterface { MWRender::Shadows* mShadows; MWRender::ShaderHelper* mShaderHelper; + + MWRender::Compositors* mCompositors; }; } diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index c81f23f548..19716f7514 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -2,24 +2,20 @@ #include #include "sky.hpp" #include "renderingmanager.hpp" +#include "compositors.hpp" using namespace Ogre; namespace MWRender { -Water::Water (Ogre::Camera *camera, SkyManager* sky, const ESM::Cell* cell) : +Water::Water (Ogre::Camera *camera, RenderingManager* rend, const ESM::Cell* cell) : mCamera (camera), mViewport (camera->getViewport()), mSceneManager (camera->getSceneManager()), mIsUnderwater(false), mVisibilityFlags(0), mReflectionTarget(0), mActive(1), mToggled(1), - mReflectionRenderActive(false) + mReflectionRenderActive(false), mRendering(rend) { - mSky = sky; - - try - { - CompositorManager::getSingleton().setCompositorEnabled(mViewport, "Water", false); - } catch(...) {} + mSky = rend->getSkyManager(); mTop = cell->water; @@ -147,8 +143,6 @@ Water::~Water() mWaterNode->detachObject(mWater); mSceneManager->destroyEntity(mWater); mSceneManager->destroySceneNode(mWaterNode); - - CompositorManager::getSingleton().removeCompositorChain(mViewport); } void Water::changeCell(const ESM::Cell* cell) @@ -178,13 +172,13 @@ void Water::checkUnderwater(float y) { if (!mActive) { - CompositorManager::getSingleton().setCompositorEnabled(mViewport, mCompositorName, false); + mRendering->getCompositors()->setCompositorEnabled(mCompositorName, false); return; } if ((mIsUnderwater && y > mTop) || !mWater->isVisible() || mCamera->getPolygonMode() != Ogre::PM_SOLID) { - CompositorManager::getSingleton().setCompositorEnabled(mViewport, mCompositorName, false); + mRendering->getCompositors()->setCompositorEnabled(mCompositorName, false); // tell the shader we are not underwater Ogre::Pass* pass = mMaterial->getTechnique(0)->getPass(0); @@ -199,7 +193,7 @@ void Water::checkUnderwater(float y) if (!mIsUnderwater && y < mTop && mWater->isVisible() && mCamera->getPolygonMode() == Ogre::PM_SOLID) { if (mUnderwaterEffect) - CompositorManager::getSingleton().setCompositorEnabled(mViewport, mCompositorName, true); + mRendering->getCompositors()->setCompositorEnabled(mCompositorName, true); // tell the shader we are underwater Ogre::Pass* pass = mMaterial->getTechnique(0)->getPass(0); diff --git a/apps/openmw/mwrender/water.hpp b/apps/openmw/mwrender/water.hpp index c8b8d311ed..25631b4aff 100644 --- a/apps/openmw/mwrender/water.hpp +++ b/apps/openmw/mwrender/water.hpp @@ -9,6 +9,7 @@ namespace MWRender { class SkyManager; + class RenderingManager; /// Water rendering class Water : public Ogre::RenderTargetListener, public Ogre::RenderQueueListener @@ -40,6 +41,7 @@ namespace MWRender { void updateVisible(); + RenderingManager* mRendering; SkyManager* mSky; std::string mCompositorName; @@ -55,7 +57,7 @@ namespace MWRender { int mVisibilityFlags; public: - Water (Ogre::Camera *camera, SkyManager* sky, const ESM::Cell* cell); + Water (Ogre::Camera *camera, RenderingManager* rend, const ESM::Cell* cell); ~Water(); void setActive(bool active); diff --git a/apps/openmw/mwscript/docs/vmformat.txt b/apps/openmw/mwscript/docs/vmformat.txt index 58960aac47..11df70bbcc 100644 --- a/apps/openmw/mwscript/docs/vmformat.txt +++ b/apps/openmw/mwscript/docs/vmformat.txt @@ -144,4 +144,5 @@ op 0x200014d: ModDisposition op 0x200014e: ModDisposition, explicit reference op 0x200014f: ForceGreeting op 0x2000150: ForceGreeting, explicit reference -opcodes 0x2000151-0x3ffffff unused +op 0x2000152: ToggleCompositors +opcodes 0x2000153-0x3ffffff unused diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index 4ba523937c..95129bd763 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -194,6 +194,22 @@ namespace MWScript } }; + class OpToggleCompositors : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + InterpreterContext& context = + static_cast (runtime.getContext()); + + bool enabled = MWBase::Environment::get().getWorld()->toggleRenderMode(MWWorld::World::Render_Compositors); + + context.report (enabled ? + "Compositors -> On" : "Compositors -> Off"); + } + }; + const int opcodeXBox = 0x200000c; const int opcodeOnActivate = 0x200000d; const int opcodeActivate = 0x2000075; @@ -208,6 +224,7 @@ namespace MWScript const int opcodeFadeTo = 0x200013e; const int opcodeToggleWater = 0x2000144; const int opcodeTogglePathgrid = 0x2000146; + const int opcodeToggleCompositors = 0x2000152; void registerExtensions (Compiler::Extensions& extensions) { @@ -229,6 +246,7 @@ namespace MWScript extensions.registerInstruction ("twa", "", opcodeToggleWater); extensions.registerInstruction ("togglepathgrid", "", opcodeTogglePathgrid); extensions.registerInstruction ("tpg", "", opcodeTogglePathgrid); + extensions.registerInstruction ("togglecompositors", "", opcodeToggleCompositors); } void installOpcodes (Interpreter::Interpreter& interpreter) @@ -247,6 +265,7 @@ namespace MWScript interpreter.installSegment5 (opcodeFadeTo, new OpFadeTo); interpreter.installSegment5 (opcodeTogglePathgrid, new OpTogglePathgrid); interpreter.installSegment5 (opcodeToggleWater, new OpToggleWater); + interpreter.installSegment5 (opcodeToggleCompositors, new OpToggleCompositors); } } } diff --git a/apps/openmw/mwworld/world.hpp b/apps/openmw/mwworld/world.hpp index 77e5bcef62..583448e12a 100644 --- a/apps/openmw/mwworld/world.hpp +++ b/apps/openmw/mwworld/world.hpp @@ -63,7 +63,8 @@ namespace MWWorld { Render_CollisionDebug, Render_Wireframe, - Render_Pathgrid + Render_Pathgrid, + Render_Compositors }; private: From 9cf6f27f9629904cadf07302ef760a7367f31149 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 29 Apr 2012 03:38:00 +0200 Subject: [PATCH 051/325] small fix --- apps/openmw/mwrender/compositors.cpp | 49 +++++++++++++++++++++ apps/openmw/mwrender/compositors.hpp | 53 +++++++++++++++++++++++ apps/openmw/mwrender/renderingmanager.hpp | 2 - 3 files changed, 102 insertions(+), 2 deletions(-) create mode 100644 apps/openmw/mwrender/compositors.cpp create mode 100644 apps/openmw/mwrender/compositors.hpp diff --git a/apps/openmw/mwrender/compositors.cpp b/apps/openmw/mwrender/compositors.cpp new file mode 100644 index 0000000000..4c9f08b72e --- /dev/null +++ b/apps/openmw/mwrender/compositors.cpp @@ -0,0 +1,49 @@ +#include "compositors.hpp" + +#include +#include + +using namespace MWRender; + +Compositors::Compositors(Ogre::Viewport* vp) : + mViewport(vp) + , mEnabled(true) +{ +} + +Compositors::~Compositors() +{ + Ogre::CompositorManager::getSingleton().removeCompositorChain(mViewport); +} + +void Compositors::setEnabled (const bool enabled) +{ + for (CompositorMap::iterator it=mCompositors.begin(); + it != mCompositors.end(); ++it) + { + Ogre::CompositorManager::getSingleton().setCompositorEnabled(mViewport, it->first, enabled && it->second.first); + } + mEnabled = enabled; +} + +void Compositors::addCompositor (const std::string& name, const int priority) +{ + int id = 0; + + for (CompositorMap::iterator it=mCompositors.begin(); + it != mCompositors.end(); ++it) + { + if (it->second.second > priority) + break; + ++id; + } + Ogre::CompositorManager::getSingleton().addCompositor (mViewport, name, id); + + mCompositors[name] = std::make_pair(false, priority); +} + +void Compositors::setCompositorEnabled (const std::string& name, const bool enabled) +{ + mCompositors[name].first = enabled; + Ogre::CompositorManager::getSingleton().setCompositorEnabled (mViewport, name, enabled && mEnabled); +} diff --git a/apps/openmw/mwrender/compositors.hpp b/apps/openmw/mwrender/compositors.hpp new file mode 100644 index 0000000000..50b53f84aa --- /dev/null +++ b/apps/openmw/mwrender/compositors.hpp @@ -0,0 +1,53 @@ +#ifndef GAME_MWRENDER_COMPOSITORS_H +#define GAME_MWRENDER_COMPOSITORS_H + +#include +#include + +namespace Ogre +{ + class Viewport; +} + +namespace MWRender +{ + typedef std::map < std::string, std::pair > CompositorMap; + + /// \brief Manages a set of compositors for one viewport + class Compositors + { + public: + Compositors(Ogre::Viewport* vp); + virtual ~Compositors(); + + /** + * enable or disable all compositors globally + */ + void setEnabled (const bool enabled); + + bool toggle() { setEnabled(!mEnabled); return mEnabled; } + + /** + * enable or disable a specific compositor + * @note enable has no effect if all compositors are globally disabled + */ + void setCompositorEnabled (const std::string& name, const bool enabled); + + /** + * @param name of compositor + * @param priority, lower number will be first in the chain + */ + void addCompositor (const std::string& name, const int priority); + + protected: + /// maps compositor name to its "enabled" state + CompositorMap mCompositors; + + bool mEnabled; + + Ogre::Viewport* mViewport; + }; + +} + +#endif diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 4e32965989..09aa1df6d1 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -159,8 +159,6 @@ class RenderingManager: private RenderingInterface { bool mSunEnabled; - bool mCompositorsEnabled; - SkyManager* mSkyManager; OcclusionQuery* mOcclusionQuery; From cca39978d413205e83e548ac2e2050fbb9cbbc09 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 29 Apr 2012 17:46:09 +0200 Subject: [PATCH 052/325] changed messagebox text colors --- files/mygui/openmw_interactive_messagebox_layout.xml | 2 +- files/mygui/openmw_messagebox_layout.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/files/mygui/openmw_interactive_messagebox_layout.xml b/files/mygui/openmw_interactive_messagebox_layout.xml index 744f212276..b8a71c670d 100644 --- a/files/mygui/openmw_interactive_messagebox_layout.xml +++ b/files/mygui/openmw_interactive_messagebox_layout.xml @@ -5,7 +5,7 @@ - + diff --git a/files/mygui/openmw_messagebox_layout.xml b/files/mygui/openmw_messagebox_layout.xml index 81d1c0a57e..c99c00a49e 100644 --- a/files/mygui/openmw_messagebox_layout.xml +++ b/files/mygui/openmw_messagebox_layout.xml @@ -8,7 +8,7 @@ - + From eca18f3e1d5d73c44ee0e05f39ce0d733524c927 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 29 Apr 2012 18:13:03 +0200 Subject: [PATCH 053/325] dialogue topic and choice sorting independent of case --- apps/openmw/mwdialogue/dialoguemanager.cpp | 20 +++++++++++++++++++- apps/openmw/mwgui/dialogue.cpp | 2 +- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwdialogue/dialoguemanager.cpp b/apps/openmw/mwdialogue/dialoguemanager.cpp index 24ee4ee7f6..ac41244d1c 100644 --- a/apps/openmw/mwdialogue/dialoguemanager.cpp +++ b/apps/openmw/mwdialogue/dialoguemanager.cpp @@ -54,6 +54,20 @@ namespace return lowerCase; } + bool stringCompareNoCase (std::string first, std::string second) + { + unsigned int i=0; + while ( (itolower(second[i])) return false; + ++i; + } + if (first.length() bool selectCompare (char comp, T1 value1, T2 value2) @@ -723,7 +737,11 @@ namespace MWDialogue } } } + + // sort again, because the previous sort was case-sensitive + keywordList.sort(stringCompareNoCase); win->setKeywords(keywordList); + mChoice = choice; } @@ -815,7 +833,7 @@ namespace MWDialogue { MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow(); win->askQuestion(question); - mChoiceMap[question] = choice; + mChoiceMap[toLower(question)] = choice; mIsInChoice = true; } diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 2386cf9a32..960ead2ac8 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -84,7 +84,7 @@ void DialogueWindow::onHistoryClicked(MyGUI::Widget* _sender) UString key = history->getColorTextAt(cursorPosition); if(color == "#686EBA") MWBase::Environment::get().getDialogueManager()->keywordSelected(lower_string(key)); - if(color == "#572D21") MWBase::Environment::get().getDialogueManager()->questionAnswered(key); + if(color == "#572D21") MWBase::Environment::get().getDialogueManager()->questionAnswered(lower_string(key)); } } From 397a97814510816284268ed3ef56714eace95324 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 29 Apr 2012 18:57:26 +0200 Subject: [PATCH 054/325] DispositionEdit tweaks --- files/mygui/openmw_dialogue_window_layout.xml | 2 +- files/mygui/openmw_dialogue_window_skin.xml | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/files/mygui/openmw_dialogue_window_layout.xml b/files/mygui/openmw_dialogue_window_layout.xml index 29a3b511ec..b0e437074c 100644 --- a/files/mygui/openmw_dialogue_window_layout.xml +++ b/files/mygui/openmw_dialogue_window_layout.xml @@ -16,7 +16,7 @@ - + diff --git a/files/mygui/openmw_dialogue_window_skin.xml b/files/mygui/openmw_dialogue_window_skin.xml index ecdec8a5c0..31ce626be0 100644 --- a/files/mygui/openmw_dialogue_window_skin.xml +++ b/files/mygui/openmw_dialogue_window_skin.xml @@ -8,12 +8,12 @@ - - + + - + From f733382f749dc3d7755534adcb3f2db7bacee067 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 30 Apr 2012 00:57:41 +0200 Subject: [PATCH 055/325] tooltip now contains info about item enchantment --- apps/openmw/mwclass/armor.cpp | 2 + apps/openmw/mwclass/book.cpp | 2 + apps/openmw/mwclass/clothing.cpp | 2 + apps/openmw/mwclass/weapon.cpp | 30 +--------- apps/openmw/mwgui/dialogue.cpp | 10 +++- apps/openmw/mwgui/dialogue.hpp | 1 + apps/openmw/mwgui/tooltips.cpp | 83 +++++++++++++++++++++++++--- apps/openmw/mwgui/tooltips.hpp | 3 +- apps/openmw/mwgui/widgets.cpp | 35 +++++++++++- apps/openmw/mwgui/widgets.hpp | 21 ++++++- apps/openmw/mwgui/window_manager.cpp | 1 + files/mygui/openmw_text.skin.xml | 5 ++ 12 files changed, 153 insertions(+), 42 deletions(-) diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index a01b28a21c..fb34e4c883 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -242,6 +242,8 @@ namespace MWClass text += MWGui::ToolTips::getMiscString(ref->base->script, "Script"); } + info.enchant = ref->base->enchant; + info.text = text; return info; diff --git a/apps/openmw/mwclass/book.cpp b/apps/openmw/mwclass/book.cpp index aa87b009be..ab659b4805 100644 --- a/apps/openmw/mwclass/book.cpp +++ b/apps/openmw/mwclass/book.cpp @@ -130,6 +130,8 @@ namespace MWClass text += MWGui::ToolTips::getMiscString(ref->base->script, "Script"); } + info.enchant = ref->base->enchant; + info.text = text; return info; diff --git a/apps/openmw/mwclass/clothing.cpp b/apps/openmw/mwclass/clothing.cpp index 669407d84d..620b664cc4 100644 --- a/apps/openmw/mwclass/clothing.cpp +++ b/apps/openmw/mwclass/clothing.cpp @@ -195,6 +195,8 @@ namespace MWClass text += MWGui::ToolTips::getMiscString(ref->base->script, "Script"); } + info.enchant = ref->base->enchant; + info.text = text; return info; diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index 1caedce62b..fcfaebcb7a 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -328,35 +328,7 @@ namespace MWClass text += "\n" + store.gameSettings.search("sWeight")->str + ": " + MWGui::ToolTips::toString(ref->base->data.weight); text += MWGui::ToolTips::getValueString(ref->base->data.value, store.gameSettings.search("sValue")->str); - // this should be going into a custom mygui widget MWEnchantment - /* - // enchantments - if (ref->base->enchant != "") - { - const ESM::Enchantment* enchant = environment.mWorld->getStore().enchants.search(ref->base->enchant); - if (enchant->data.type == ESM::Enchantment::CastOnce) - text += "\n" + environment.mWorld->getStore().gameSettings.search("sItemCastOnce")->str; - else if (enchant->data.type == ESM::Enchantment::WhenStrikes) - text += "\n" + environment.mWorld->getStore().gameSettings.search("sItemCastWhenStrikes")->str; - else if (enchant->data.type == ESM::Enchantment::WhenUsed) - text += "\n" + environment.mWorld->getStore().gameSettings.search("sItemCastWhenUsed")->str; - else if (enchant->data.type == ESM::Enchantment::ConstantEffect) - text += "\n" + environment.mWorld->getStore().gameSettings.search("sItemCastConstant")->str; - - if (enchant->data.type == ESM::Enchantment::WhenStrikes - || enchant->data.type == ESM::Enchantment::WhenUsed) - { - /// \todo store the current enchantment charge somewhere - // info.currentCharge = enchant->data.charge; - //info.totalCharge = enchant->data.charge; - } - } - */ - if (ref->base->enchant != "") - { - const ESM::Enchantment* enchant = store.enchants.search(ref->base->enchant); - info.enchant = enchant; - } + info.enchant = ref->base->enchant; if (MWBase::Environment::get().getWindowManager()->getFullHelp()) { text += MWGui::ToolTips::getMiscString(ref->ref.owner, "Owner"); diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 2386cf9a32..aec405f46d 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -50,9 +50,9 @@ DialogueWindow::DialogueWindow(WindowManager& parWindowManager) //An EditBox cannot receive mouse click events, so we use an //invisible widget on top of the editbox to receive them - /// \todo scrolling the dialogue history with the mouse wheel doesn't work using this solution getWidget(eventbox, "EventBox"); eventbox->eventMouseButtonClick += MyGUI::newDelegate(this, &DialogueWindow::onHistoryClicked); + eventbox->eventMouseWheel += MyGUI::newDelegate(this, &DialogueWindow::onMouseWheel); //Topics list getWidget(topicsList, "TopicsList"); @@ -88,6 +88,14 @@ void DialogueWindow::onHistoryClicked(MyGUI::Widget* _sender) } } +void DialogueWindow::onMouseWheel(MyGUI::Widget* _sender, int _rel) +{ + if (history->getVScrollPosition() - _rel*0.3 < 0) + history->setVScrollPosition(0); + else + history->setVScrollPosition(history->getVScrollPosition() - _rel*0.3); +} + void DialogueWindow::open() { topicsList->removeAllItems(); diff --git a/apps/openmw/mwgui/dialogue.hpp b/apps/openmw/mwgui/dialogue.hpp index 61e8c124c5..5921ca57a2 100644 --- a/apps/openmw/mwgui/dialogue.hpp +++ b/apps/openmw/mwgui/dialogue.hpp @@ -45,6 +45,7 @@ namespace MWGui void onSelectTopic(MyGUI::ListBox* _sender, size_t _index); void onByeClicked(MyGUI::Widget* _sender); void onHistoryClicked(MyGUI::Widget* _sender); + void onMouseWheel(MyGUI::Widget* _sender, int _rel); private: void updateOptions(); diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index ef30b88d7c..f5b140ec1c 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -1,7 +1,10 @@ #include "tooltips.hpp" -#include "window_manager.hpp" +#include "window_manager.hpp" +#include "widgets.hpp" #include "../mwworld/class.hpp" +#include "../mwworld/world.hpp" +#include "../mwbase/environment.hpp" #include @@ -177,6 +180,21 @@ IntSize ToolTips::createToolTip(const ToolTipInfo& info) if (text.size() > 0 && text[0] == '\n') text.erase(0, 1); + const ESM::Enchantment* enchant; + const ESMS::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); + if (info.enchant != "") + { + enchant = store.enchants.search(info.enchant); + if (enchant->data.type == ESM::Enchantment::CastOnce) + text += "\n" + store.gameSettings.search("sItemCastOnce")->str; + else if (enchant->data.type == ESM::Enchantment::WhenStrikes) + text += "\n" + store.gameSettings.search("sItemCastWhenStrikes")->str; + else if (enchant->data.type == ESM::Enchantment::WhenUsed) + text += "\n" + store.gameSettings.search("sItemCastWhenUsed")->str; + else if (enchant->data.type == ESM::Enchantment::ConstantEffect) + text += "\n" + store.gameSettings.search("sItemCastConstant")->str; + } + // this the maximum width of the tooltip before it starts word-wrapping setCoord(0, 0, 300, 300); @@ -207,13 +225,55 @@ IntSize ToolTips::createToolTip(const ToolTipInfo& info) IntSize totalSize = IntSize( std::max(textSize.width, captionSize.width + ((image != "") ? imageCaptionHPadding : 0)), ((text != "") ? textSize.height + imageCaptionVPadding : 0) + captionHeight ); - if (image != "") + if (info.enchant != "") { - ImageBox* imageWidget = mDynamicToolTipBox->createWidget("ImageBox", - IntCoord((totalSize.width - captionSize.width - imageCaptionHPadding)/2, 0, imageSize, imageSize), - Align::Left | Align::Top, "ToolTipImage"); - imageWidget->setImageTexture(realImage); - imageWidget->setPosition (imageWidget->getPosition() + padding); + Widget* enchantArea = mDynamicToolTipBox->createWidget("", + IntCoord(0, totalSize.height, 300, 300-totalSize.height), + Align::Stretch, "ToolTipEnchantArea"); + + IntCoord coord(0, 6, totalSize.width, 24); + + Widgets::MWEnchantmentPtr enchantWidget = enchantArea->createWidget + ("MW_StatName", coord, Align::Default, "ToolTipEnchantWidget"); + enchantWidget->setWindowManager(mWindowManager); + enchantWidget->setEnchantmentId(info.enchant); + + std::vector enchantEffectItems; + enchantWidget->createEffectWidgets(enchantEffectItems, enchantArea, coord, true, (enchant->data.type == ESM::Enchantment::ConstantEffect)); + totalSize.height += coord.top-6; + totalSize.width = std::max(totalSize.width, coord.width); + + if (enchant->data.type == ESM::Enchantment::WhenStrikes + || enchant->data.type == ESM::Enchantment::WhenUsed) + { + /// \todo store the current enchantment charge somewhere + int charge = enchant->data.charge; + + const int chargeWidth = 204; + + TextBox* chargeText = enchantArea->createWidget("SandText", IntCoord(0, 0, 10, 18), Align::Default, "ToolTipEnchantChargeText"); + chargeText->setCaption(store.gameSettings.search("sCharges")->str); + chargeText->setProperty("Static", "true"); + const int chargeTextWidth = chargeText->getTextSize().width + 5; + + const int chargeAndTextWidth = chargeWidth + chargeTextWidth; + chargeText->setCoord((totalSize.width - chargeAndTextWidth)/2, coord.top+6, chargeTextWidth, 18); + + IntCoord chargeCoord; + if (totalSize.width < chargeWidth) + { + totalSize.width = chargeWidth; + chargeCoord = IntCoord(0, coord.top+6, chargeWidth, 18); + } + else + { + chargeCoord = IntCoord((totalSize.width - chargeAndTextWidth)/2 + chargeTextWidth, coord.top+6, chargeWidth, 18); + } + Widgets::MWDynamicStatPtr chargeWidget = enchantArea->createWidget + ("MW_ChargeBar", chargeCoord, Align::Default, "ToolTipEnchantCharge"); + chargeWidget->setValue(charge, charge); + totalSize.height += 24; + } } captionWidget->setCoord( (totalSize.width - captionSize.width)/2 + imageSize, @@ -224,6 +284,15 @@ IntSize ToolTips::createToolTip(const ToolTipInfo& info) captionWidget->setPosition (captionWidget->getPosition() + padding); textWidget->setPosition (textWidget->getPosition() + IntPoint(0, padding.top)); // only apply vertical padding, the horizontal works automatically due to Align::HCenter + if (image != "") + { + ImageBox* imageWidget = mDynamicToolTipBox->createWidget("ImageBox", + IntCoord((totalSize.width - captionSize.width - imageCaptionHPadding)/2, 0, imageSize, imageSize), + Align::Left | Align::Top, "ToolTipImage"); + imageWidget->setImageTexture(realImage); + imageWidget->setPosition (imageWidget->getPosition() + padding); + } + totalSize += IntSize(padding.left*2, padding.top*2); return totalSize; diff --git a/apps/openmw/mwgui/tooltips.hpp b/apps/openmw/mwgui/tooltips.hpp index c00faba869..fafe471a57 100644 --- a/apps/openmw/mwgui/tooltips.hpp +++ b/apps/openmw/mwgui/tooltips.hpp @@ -14,7 +14,6 @@ namespace MWGui { public: ToolTipInfo() : - enchant(0), effects(0) { }; @@ -24,7 +23,7 @@ namespace MWGui std::string icon; // enchantment (for cloth, armor, weapons) - const ESM::Enchantment* enchant; + std::string enchant; // effects (for potions, ingredients) const ESM::EffectList* effects; diff --git a/apps/openmw/mwgui/widgets.cpp b/apps/openmw/mwgui/widgets.cpp index 58cfee991b..769220f7bb 100644 --- a/apps/openmw/mwgui/widgets.cpp +++ b/apps/openmw/mwgui/widgets.cpp @@ -238,6 +238,7 @@ void MWSpell::createEffectWidgets(std::vector &effects, MyGUI: effect->setSpellEffect(*it); effects.push_back(effect); coord.top += effect->getHeight(); + coord.width = std::max(coord.width, effect->getRequestedWidth()); } } @@ -278,22 +279,49 @@ void MWEnchantment::setEnchantmentId(const std::string &enchantId) updateWidgets(); } -void MWEnchantment::createEffectWidgets(std::vector &effects, MyGUI::WidgetPtr creator, MyGUI::IntCoord &coord) +void MWEnchantment::createEffectWidgets(std::vector &effects, MyGUI::WidgetPtr creator, MyGUI::IntCoord &coord, bool center, bool constant) { const ESMS::ESMStore &store = mWindowManager->getStore(); const ESM::Enchantment *enchant = store.enchants.search(id); MYGUI_ASSERT(enchant, "enchantment with id '" << id << "' not found"); + // We don't know the width of all the elements beforehand, so we do it in + // 2 steps: first, create all widgets and check their width MWSpellEffectPtr effect = nullptr; std::vector::const_iterator end = enchant->effects.list.end(); + int maxwidth = coord.width; for (std::vector::const_iterator it = enchant->effects.list.begin(); it != end; ++it) { effect = creator->createWidget("MW_EffectImage", coord, MyGUI::Align::Default); effect->setWindowManager(mWindowManager); effect->setSpellEffect(*it); + effect->setConstant(constant); effects.push_back(effect); + + if (effect->getRequestedWidth() > maxwidth) + maxwidth = effect->getRequestedWidth(); + coord.top += effect->getHeight(); } + + // then adjust the size for all widgets + for (std::vector::iterator it = effects.begin(); it != effects.end(); ++it) + { + effect = static_cast(*it); + bool needcenter = center && (maxwidth > effect->getRequestedWidth()); + int diff = maxwidth - effect->getRequestedWidth(); + if (needcenter) + { + effect->setCoord(diff/2, effect->getCoord().top, effect->getRequestedWidth(), effect->getCoord().height); + } + else + { + effect->setCoord(0, effect->getCoord().top, effect->getRequestedWidth(), effect->getCoord().height); + } + } + + // inform the parent about width + coord.width = maxwidth; } void MWEnchantment::updateWidgets() @@ -315,6 +343,8 @@ MWSpellEffect::MWSpellEffect() : mWindowManager(nullptr) , imageWidget(nullptr) , textWidget(nullptr) + , mRequestedWidth(0) + , mIsConstant(0) { } @@ -366,7 +396,7 @@ void MWSpellEffect::updateWidgets() spellLine += " " + boost::lexical_cast(effect.magnMin) + " " + ((effect.magnMin == 1) ? pt : pts); else { - spellLine += " " + boost::lexical_cast(effect.magnMin) + to + boost::lexical_cast(effect.magnMin) + " " + pts; + spellLine += " " + boost::lexical_cast(effect.magnMin) + to + boost::lexical_cast(effect.magnMax) + " " + pts; } } @@ -388,6 +418,7 @@ void MWSpellEffect::updateWidgets() } static_cast(textWidget)->setCaption(spellLine); + mRequestedWidth = textWidget->getTextSize().width + 24; } else static_cast(textWidget)->setCaption(""); diff --git a/apps/openmw/mwgui/widgets.hpp b/apps/openmw/mwgui/widgets.hpp index 8ac27795d5..b4915ac6aa 100644 --- a/apps/openmw/mwgui/widgets.hpp +++ b/apps/openmw/mwgui/widgets.hpp @@ -119,6 +119,14 @@ namespace MWGui void setWindowManager(WindowManager* parWindowManager) { mWindowManager = parWindowManager; } void setSpellId(const std::string &id); + + /** + * @param vector to store the created effect widgets + * @param parent widget + * @param coordinates to use, will be expanded if more space is needed + * @param spell category, if this is 0, this means the spell effects are permanent and won't display e.g. duration + * @param center the effect widgets horizontally + */ void createEffectWidgets(std::vector &effects, MyGUI::WidgetPtr creator, MyGUI::IntCoord &coord, const int category); const std::string &getSpellId() const { return id; } @@ -147,7 +155,15 @@ namespace MWGui void setWindowManager(WindowManager* parWindowManager) { mWindowManager = parWindowManager; } void setEnchantmentId(const std::string &enchantId); - void createEffectWidgets(std::vector &effects, MyGUI::WidgetPtr creator, MyGUI::IntCoord &coord); + + /** + * @param vector to store the created effect widgets + * @param parent widget + * @param coordinates to use, will be expanded if more space is needed + * @param center the effect widgets horizontally + * @param are the effects of this enchantment constant? + */ + void createEffectWidgets(std::vector &effects, MyGUI::WidgetPtr creator, MyGUI::IntCoord &coord, bool center, bool constant); const std::string &getSpellId() const { return id; } @@ -180,6 +196,8 @@ namespace MWGui const SpellEffectValue &getSpellEffect() const { return effect; } + int getRequestedWidth() const { return mRequestedWidth; } + protected: virtual ~MWSpellEffect(); @@ -194,6 +212,7 @@ namespace MWGui bool mIsConstant; // constant effect MyGUI::ImageBox* imageWidget; MyGUI::TextBox* textWidget; + int mRequestedWidth; }; typedef MWSpellEffect* MWSpellEffectPtr; diff --git a/apps/openmw/mwgui/window_manager.cpp b/apps/openmw/mwgui/window_manager.cpp index a3e44f65bf..ccf558de50 100644 --- a/apps/openmw/mwgui/window_manager.cpp +++ b/apps/openmw/mwgui/window_manager.cpp @@ -104,6 +104,7 @@ WindowManager::WindowManager( MyGUI::FactoryManager::getInstance().registerFactory("Widget"); MyGUI::FactoryManager::getInstance().registerFactory("Widget"); MyGUI::FactoryManager::getInstance().registerFactory("Widget"); + MyGUI::FactoryManager::getInstance().registerFactory("Widget"); MyGUI::FactoryManager::getInstance().registerFactory("Widget"); MyGUI::FactoryManager::getInstance().registerFactory("Widget"); diff --git a/files/mygui/openmw_text.skin.xml b/files/mygui/openmw_text.skin.xml index 9f87c93b3c..36d97e1538 100644 --- a/files/mygui/openmw_text.skin.xml +++ b/files/mygui/openmw_text.skin.xml @@ -93,6 +93,11 @@ + + + + + From b82c39c8be6976e3386b413e4a49298dd6e49e3a Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 30 Apr 2012 01:08:10 +0200 Subject: [PATCH 056/325] renamed Widgets::MWEnchantment to Widgets::MWEffectList so it can be reused for potion effects --- apps/openmw/mwclass/potion.cpp | 2 ++ apps/openmw/mwgui/tooltips.cpp | 2 +- apps/openmw/mwgui/widgets.cpp | 14 +++++++------- apps/openmw/mwgui/widgets.hpp | 10 +++++----- apps/openmw/mwgui/window_manager.cpp | 2 +- 5 files changed, 16 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwclass/potion.cpp b/apps/openmw/mwclass/potion.cpp index 12ce622ee1..edf82cee45 100644 --- a/apps/openmw/mwclass/potion.cpp +++ b/apps/openmw/mwclass/potion.cpp @@ -124,6 +124,8 @@ namespace MWClass text += "\n" + store.gameSettings.search("sWeight")->str + ": " + MWGui::ToolTips::toString(ref->base->data.weight); text += MWGui::ToolTips::getValueString(ref->base->data.value, store.gameSettings.search("sValue")->str); + ESM::EffectList list = ref->base->effects; + if (MWBase::Environment::get().getWindowManager()->getFullHelp()) { text += MWGui::ToolTips::getMiscString(ref->ref.owner, "Owner"); text += MWGui::ToolTips::getMiscString(ref->base->script, "Script"); diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index f5b140ec1c..0cab26b2c7 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -233,7 +233,7 @@ IntSize ToolTips::createToolTip(const ToolTipInfo& info) IntCoord coord(0, 6, totalSize.width, 24); - Widgets::MWEnchantmentPtr enchantWidget = enchantArea->createWidget + Widgets::MWEffectListPtr enchantWidget = enchantArea->createWidget ("MW_StatName", coord, Align::Default, "ToolTipEnchantWidget"); enchantWidget->setWindowManager(mWindowManager); enchantWidget->setEnchantmentId(info.enchant); diff --git a/apps/openmw/mwgui/widgets.cpp b/apps/openmw/mwgui/widgets.cpp index 769220f7bb..f327a9c1ec 100644 --- a/apps/openmw/mwgui/widgets.cpp +++ b/apps/openmw/mwgui/widgets.cpp @@ -266,20 +266,20 @@ MWSpell::~MWSpell() { } -/* MWEnchantment */ +/* MWEffectList */ -MWEnchantment::MWEnchantment() +MWEffectList::MWEffectList() : mWindowManager(nullptr) { } -void MWEnchantment::setEnchantmentId(const std::string &enchantId) +void MWEffectList::setEnchantmentId(const std::string &enchantId) { id = enchantId; updateWidgets(); } -void MWEnchantment::createEffectWidgets(std::vector &effects, MyGUI::WidgetPtr creator, MyGUI::IntCoord &coord, bool center, bool constant) +void MWEffectList::createEffectWidgets(std::vector &effects, MyGUI::WidgetPtr creator, MyGUI::IntCoord &coord, bool center, bool constant) { const ESMS::ESMStore &store = mWindowManager->getStore(); const ESM::Enchantment *enchant = store.enchants.search(id); @@ -324,16 +324,16 @@ void MWEnchantment::createEffectWidgets(std::vector &effects, coord.width = maxwidth; } -void MWEnchantment::updateWidgets() +void MWEffectList::updateWidgets() { } -void MWEnchantment::initialiseOverride() +void MWEffectList::initialiseOverride() { Base::initialiseOverride(); } -MWEnchantment::~MWEnchantment() +MWEffectList::~MWEffectList() { } diff --git a/apps/openmw/mwgui/widgets.hpp b/apps/openmw/mwgui/widgets.hpp index b4915ac6aa..51ad516786 100644 --- a/apps/openmw/mwgui/widgets.hpp +++ b/apps/openmw/mwgui/widgets.hpp @@ -145,11 +145,11 @@ namespace MWGui }; typedef MWSpell* MWSpellPtr; - class MYGUI_EXPORT MWEnchantment : public Widget + class MYGUI_EXPORT MWEffectList : public Widget { - MYGUI_RTTI_DERIVED( MWEnchantment ); + MYGUI_RTTI_DERIVED( MWEffectList ); public: - MWEnchantment(); + MWEffectList(); typedef MWMechanics::Stat EnchantmentValue; @@ -168,7 +168,7 @@ namespace MWGui const std::string &getSpellId() const { return id; } protected: - virtual ~MWEnchantment(); + virtual ~MWEffectList(); virtual void initialiseOverride(); @@ -178,7 +178,7 @@ namespace MWGui WindowManager* mWindowManager; std::string id; }; - typedef MWEnchantment* MWEnchantmentPtr; + typedef MWEffectList* MWEffectListPtr; class MYGUI_EXPORT MWSpellEffect : public Widget { diff --git a/apps/openmw/mwgui/window_manager.cpp b/apps/openmw/mwgui/window_manager.cpp index ccf558de50..0f2df53e1a 100644 --- a/apps/openmw/mwgui/window_manager.cpp +++ b/apps/openmw/mwgui/window_manager.cpp @@ -104,7 +104,7 @@ WindowManager::WindowManager( MyGUI::FactoryManager::getInstance().registerFactory("Widget"); MyGUI::FactoryManager::getInstance().registerFactory("Widget"); MyGUI::FactoryManager::getInstance().registerFactory("Widget"); - MyGUI::FactoryManager::getInstance().registerFactory("Widget"); + MyGUI::FactoryManager::getInstance().registerFactory("Widget"); MyGUI::FactoryManager::getInstance().registerFactory("Widget"); MyGUI::FactoryManager::getInstance().registerFactory("Widget"); From 22f524f8d52408bbca31af711b745889ef32ad1f Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 30 Apr 2012 01:53:22 +0200 Subject: [PATCH 057/325] potion effects in tooltip --- apps/openmw/mwclass/potion.cpp | 2 +- apps/openmw/mwgui/birth.cpp | 2 +- apps/openmw/mwgui/tooltips.cpp | 30 ++++++++++++++- apps/openmw/mwgui/widgets.cpp | 70 ++++++++++++++++++++-------------- apps/openmw/mwgui/widgets.hpp | 20 ++++++---- 5 files changed, 84 insertions(+), 40 deletions(-) diff --git a/apps/openmw/mwclass/potion.cpp b/apps/openmw/mwclass/potion.cpp index edf82cee45..07e7663b38 100644 --- a/apps/openmw/mwclass/potion.cpp +++ b/apps/openmw/mwclass/potion.cpp @@ -124,7 +124,7 @@ namespace MWClass text += "\n" + store.gameSettings.search("sWeight")->str + ": " + MWGui::ToolTips::toString(ref->base->data.weight); text += MWGui::ToolTips::getValueString(ref->base->data.value, store.gameSettings.search("sValue")->str); - ESM::EffectList list = ref->base->effects; + info.effects = &ref->base->effects; if (MWBase::Environment::get().getWindowManager()->getFullHelp()) { text += MWGui::ToolTips::getMiscString(ref->ref.owner, "Owner"); diff --git a/apps/openmw/mwgui/birth.cpp b/apps/openmw/mwgui/birth.cpp index 046017204f..cb15eaf15b 100644 --- a/apps/openmw/mwgui/birth.cpp +++ b/apps/openmw/mwgui/birth.cpp @@ -202,7 +202,7 @@ void BirthDialog::updateSpells() MyGUI::IntCoord spellCoord = coord; spellCoord.height = 24; // TODO: This should be fetched from the skin somehow, or perhaps a widget in the layout as a template? - spellWidget->createEffectWidgets(spellItems, spellArea, spellCoord, category); + spellWidget->createEffectWidgets(spellItems, spellArea, spellCoord, (category == 0) ? MWEffectList::EF_Constant : 0); coord.top = spellCoord.top; ++i; diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 0cab26b2c7..90b5baa679 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -225,6 +225,31 @@ IntSize ToolTips::createToolTip(const ToolTipInfo& info) IntSize totalSize = IntSize( std::max(textSize.width, captionSize.width + ((image != "") ? imageCaptionHPadding : 0)), ((text != "") ? textSize.height + imageCaptionVPadding : 0) + captionHeight ); + if (info.effects != 0) + { + Widget* effectArea = mDynamicToolTipBox->createWidget("", + IntCoord(0, totalSize.height, 300, 300-totalSize.height), + Align::Stretch, "ToolTipEffectArea"); + + IntCoord coord(0, 6, totalSize.width, 24); + + /** + * \todo + * the various potion effects should appear in the tooltip depending if the player + * has enough skill in alchemy to know about the effects of this potion. + */ + + Widgets::MWEffectListPtr effectsWidget = effectArea->createWidget + ("MW_StatName", coord, Align::Default, "ToolTipEffectsWidget"); + effectsWidget->setWindowManager(mWindowManager); + effectsWidget->setEffectList(info.effects); + + std::vector effectItems; + effectsWidget->createEffectWidgets(effectItems, effectArea, coord, true, Widgets::MWEffectList::EF_Potion); + totalSize.height += coord.top-6; + totalSize.width = std::max(totalSize.width, coord.width); + } + if (info.enchant != "") { Widget* enchantArea = mDynamicToolTipBox->createWidget("", @@ -236,10 +261,11 @@ IntSize ToolTips::createToolTip(const ToolTipInfo& info) Widgets::MWEffectListPtr enchantWidget = enchantArea->createWidget ("MW_StatName", coord, Align::Default, "ToolTipEnchantWidget"); enchantWidget->setWindowManager(mWindowManager); - enchantWidget->setEnchantmentId(info.enchant); + enchantWidget->setEffectList(&enchant->effects); std::vector enchantEffectItems; - enchantWidget->createEffectWidgets(enchantEffectItems, enchantArea, coord, true, (enchant->data.type == ESM::Enchantment::ConstantEffect)); + int flag = (enchant->data.type == ESM::Enchantment::ConstantEffect) ? Widgets::MWEffectList::EF_Constant : 0; + enchantWidget->createEffectWidgets(enchantEffectItems, enchantArea, coord, true, flag); totalSize.height += coord.top-6; totalSize.width = std::max(totalSize.width, coord.width); diff --git a/apps/openmw/mwgui/widgets.cpp b/apps/openmw/mwgui/widgets.cpp index f327a9c1ec..2f5af64736 100644 --- a/apps/openmw/mwgui/widgets.cpp +++ b/apps/openmw/mwgui/widgets.cpp @@ -222,7 +222,7 @@ void MWSpell::setSpellId(const std::string &spellId) updateWidgets(); } -void MWSpell::createEffectWidgets(std::vector &effects, MyGUI::WidgetPtr creator, MyGUI::IntCoord &coord, const int category) +void MWSpell::createEffectWidgets(std::vector &effects, MyGUI::WidgetPtr creator, MyGUI::IntCoord &coord, int flags) { const ESMS::ESMStore &store = mWindowManager->getStore(); const ESM::Spell *spell = store.spells.search(id); @@ -234,7 +234,7 @@ void MWSpell::createEffectWidgets(std::vector &effects, MyGUI: { effect = creator->createWidget("MW_EffectImage", coord, MyGUI::Align::Default); effect->setWindowManager(mWindowManager); - effect->setConstant(category == 0); + effect->setFlags(flags); effect->setSpellEffect(*it); effects.push_back(effect); coord.top += effect->getHeight(); @@ -270,32 +270,29 @@ MWSpell::~MWSpell() MWEffectList::MWEffectList() : mWindowManager(nullptr) + , mEffectList(0) { } -void MWEffectList::setEnchantmentId(const std::string &enchantId) +void MWEffectList::setEffectList(const ESM::EffectList* list) { - id = enchantId; + mEffectList = list; updateWidgets(); } -void MWEffectList::createEffectWidgets(std::vector &effects, MyGUI::WidgetPtr creator, MyGUI::IntCoord &coord, bool center, bool constant) +void MWEffectList::createEffectWidgets(std::vector &effects, MyGUI::WidgetPtr creator, MyGUI::IntCoord &coord, bool center, int flags) { - const ESMS::ESMStore &store = mWindowManager->getStore(); - const ESM::Enchantment *enchant = store.enchants.search(id); - MYGUI_ASSERT(enchant, "enchantment with id '" << id << "' not found"); - // We don't know the width of all the elements beforehand, so we do it in // 2 steps: first, create all widgets and check their width MWSpellEffectPtr effect = nullptr; - std::vector::const_iterator end = enchant->effects.list.end(); + std::vector::const_iterator end = mEffectList->list.end(); int maxwidth = coord.width; - for (std::vector::const_iterator it = enchant->effects.list.begin(); it != end; ++it) + for (std::vector::const_iterator it = mEffectList->list.begin(); it != end; ++it) { effect = creator->createWidget("MW_EffectImage", coord, MyGUI::Align::Default); effect->setWindowManager(mWindowManager); + effect->setFlags(flags); effect->setSpellEffect(*it); - effect->setConstant(constant); effects.push_back(effect); if (effect->getRequestedWidth() > maxwidth) @@ -344,7 +341,7 @@ MWSpellEffect::MWSpellEffect() , imageWidget(nullptr) , textWidget(nullptr) , mRequestedWidth(0) - , mIsConstant(0) + , mFlags(0) { } @@ -359,6 +356,18 @@ void MWSpellEffect::updateWidgets() if (!mWindowManager) return; + // lists effects that have no magnitude (e.g. invisiblity) + /// \todo this list is probably incomplete + std::vector effectsWithoutMagnitude; + effectsWithoutMagnitude.push_back("sEffectInvisibility"); + effectsWithoutMagnitude.push_back("sEffectStuntedMagicka"); + effectsWithoutMagnitude.push_back("sEffectParalyze"); + + // lists effects that have no duration (e.g. open lock) + /// \todo this list is probably incomplete + std::vector effectsWithoutDuration; + effectsWithoutDuration.push_back("sEffectOpen"); + const ESMS::ESMStore &store = mWindowManager->getStore(); const ESM::MagicEffect *magicEffect = store.magicEffects.search(effect.effectID); if (textWidget) @@ -371,7 +380,8 @@ void MWSpellEffect::updateWidgets() std::string sec = " " + mWindowManager->getGameSettingString("ssecond", ""); std::string secs = " " + mWindowManager->getGameSettingString("sseconds", ""); - std::string spellLine = effectIDToString(effect.effectID); + std::string effectIDStr = effectIDToString(effect.effectID); + std::string spellLine = mWindowManager->getGameSettingString(effectIDStr, ""); if (effect.skill >= 0 && effect.skill < ESM::Skill::Length) { spellLine += " " + mWindowManager->getGameSettingString(ESM::Skill::sSkillNameIds[effect.skill], ""); @@ -390,7 +400,9 @@ void MWSpellEffect::updateWidgets() }; spellLine += " " + mWindowManager->getGameSettingString(attributes[effect.attribute], ""); } - if (effect.magnMin >= 0 || effect.magnMax >= 0) + + bool hasMagnitude = (std::find(effectsWithoutMagnitude.begin(), effectsWithoutMagnitude.end(), effectIDStr) == effectsWithoutMagnitude.end()); + if ((effect.magnMin >= 0 || effect.magnMax >= 0) && hasMagnitude) { if (effect.magnMin == effect.magnMax) spellLine += " " + boost::lexical_cast(effect.magnMin) + " " + ((effect.magnMin == 1) ? pt : pts); @@ -401,20 +413,25 @@ void MWSpellEffect::updateWidgets() } // constant effects have no duration and no target - if (!mIsConstant) + if (!(mFlags & MWEffectList::EF_Constant)) { - if (effect.duration >= 0) + bool hasDuration = (std::find(effectsWithoutDuration.begin(), effectsWithoutDuration.end(), effectIDStr) == effectsWithoutDuration.end()); + if (effect.duration >= 0 && hasDuration) { spellLine += " " + mWindowManager->getGameSettingString("sfor", "") + " " + boost::lexical_cast(effect.duration) + ((effect.duration == 1) ? sec : secs); } - std::string on = mWindowManager->getGameSettingString("sonword", ""); - if (effect.range == ESM::RT_Self) - spellLine += " " + on + " " + mWindowManager->getGameSettingString("sRangeSelf", ""); - else if (effect.range == ESM::RT_Touch) - spellLine += " " + on + " " + mWindowManager->getGameSettingString("sRangeTouch", ""); - else if (effect.range == ESM::RT_Target) - spellLine += " " + on + " " + mWindowManager->getGameSettingString("sRangeTarget", ""); + // potions have no target + if (!(mFlags & MWEffectList::EF_Potion)) + { + std::string on = mWindowManager->getGameSettingString("sonword", ""); + if (effect.range == ESM::RT_Self) + spellLine += " " + on + " " + mWindowManager->getGameSettingString("sRangeSelf", ""); + else if (effect.range == ESM::RT_Touch) + spellLine += " " + on + " " + mWindowManager->getGameSettingString("sRangeTouch", ""); + else if (effect.range == ESM::RT_Target) + spellLine += " " + on + " " + mWindowManager->getGameSettingString("sRangeTarget", ""); + } } static_cast(textWidget)->setCaption(spellLine); @@ -574,11 +591,8 @@ std::string MWSpellEffect::effectIDToString(const short effectID) names[30] ="sEffectWeaknesstoShock"; assert(names.find(effectID) != names.end() && "Unimplemented effect type"); - std::string res = mWindowManager->getGameSettingString(names[effectID], ""); - if (res == "") - std::cout << "Warning: Unknown effect name " << names[effectID] << std::endl; - return res; + return names[effectID]; } MWSpellEffect::~MWSpellEffect() diff --git a/apps/openmw/mwgui/widgets.hpp b/apps/openmw/mwgui/widgets.hpp index 51ad516786..a1caa3c946 100644 --- a/apps/openmw/mwgui/widgets.hpp +++ b/apps/openmw/mwgui/widgets.hpp @@ -153,19 +153,23 @@ namespace MWGui typedef MWMechanics::Stat EnchantmentValue; + enum EffectFlags + { + EF_Potion = 0x01, // potions have no target (target is always the player) + EF_Constant = 0x02 // constant effect means that duration will not be displayed + }; + void setWindowManager(WindowManager* parWindowManager) { mWindowManager = parWindowManager; } - void setEnchantmentId(const std::string &enchantId); + void setEffectList(const ESM::EffectList* list); /** * @param vector to store the created effect widgets * @param parent widget * @param coordinates to use, will be expanded if more space is needed * @param center the effect widgets horizontally - * @param are the effects of this enchantment constant? + * @param various flags, see MWEffectList::EffectFlags */ - void createEffectWidgets(std::vector &effects, MyGUI::WidgetPtr creator, MyGUI::IntCoord &coord, bool center, bool constant); - - const std::string &getSpellId() const { return id; } + void createEffectWidgets(std::vector &effects, MyGUI::WidgetPtr creator, MyGUI::IntCoord &coord, bool center, int flags); protected: virtual ~MWEffectList(); @@ -176,7 +180,7 @@ namespace MWGui void updateWidgets(); WindowManager* mWindowManager; - std::string id; + const ESM::EffectList* mEffectList; }; typedef MWEffectList* MWEffectListPtr; @@ -190,7 +194,7 @@ namespace MWGui void setWindowManager(WindowManager* parWindowManager) { mWindowManager = parWindowManager; } void setSpellEffect(SpellEffectValue value); - void setConstant(bool constant) { mIsConstant = constant; } + void setFlags(int flags) { mFlags = flags; } std::string effectIDToString(const short effectID); @@ -209,7 +213,7 @@ namespace MWGui WindowManager* mWindowManager; SpellEffectValue effect; - bool mIsConstant; // constant effect + int mFlags; MyGUI::ImageBox* imageWidget; MyGUI::TextBox* textWidget; int mRequestedWidth; From 2f0a69160cffefdba93a70eb9aa5f818e0237643 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 30 Apr 2012 02:10:55 +0200 Subject: [PATCH 058/325] small fix --- apps/openmw/mwgui/widgets.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/widgets.hpp b/apps/openmw/mwgui/widgets.hpp index a1caa3c946..c0e62533d8 100644 --- a/apps/openmw/mwgui/widgets.hpp +++ b/apps/openmw/mwgui/widgets.hpp @@ -125,9 +125,9 @@ namespace MWGui * @param parent widget * @param coordinates to use, will be expanded if more space is needed * @param spell category, if this is 0, this means the spell effects are permanent and won't display e.g. duration - * @param center the effect widgets horizontally + * @param various flags, see MWEffectList::EffectFlags */ - void createEffectWidgets(std::vector &effects, MyGUI::WidgetPtr creator, MyGUI::IntCoord &coord, const int category); + void createEffectWidgets(std::vector &effects, MyGUI::WidgetPtr creator, MyGUI::IntCoord &coord, int flags); const std::string &getSpellId() const { return id; } From 5f8c08b18b65443805dd5f73802497d0d4c87e5c Mon Sep 17 00:00:00 2001 From: gugus Date: Mon, 30 Apr 2012 13:01:18 +0200 Subject: [PATCH 059/325] some work for dropping objects. --- apps/openmw/mwgui/container.cpp | 69 ++++++++++++++++----------- apps/openmw/mwgui/container.hpp | 37 ++++++++------ apps/openmw/mwgui/inventorywindow.cpp | 4 +- apps/openmw/mwgui/inventorywindow.hpp | 2 +- apps/openmw/mwgui/window_manager.cpp | 33 ++++++++----- apps/openmw/mwgui/window_manager.hpp | 10 ++-- 6 files changed, 93 insertions(+), 62 deletions(-) diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index b3fe7adfbb..d5eb8cff7d 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -24,10 +24,10 @@ using namespace MWGui; using namespace Widgets; -ContainerWindow::ContainerWindow(WindowManager& parWindowManager,MWWorld::Environment& environment,MyGUI::Widget* dragAndDropWidget) +ContainerWindow::ContainerWindow(WindowManager& parWindowManager,MWWorld::Environment& environment,DragAndDrop* dragAndDrop) : WindowBase("openmw_container_window_layout.xml", parWindowManager), mEnvironment(environment), - mDragAndDropWidget(dragAndDropWidget) + mDragAndDrop(dragAndDrop) { setText("_Main", "Name of Container"); @@ -42,27 +42,23 @@ ContainerWindow::ContainerWindow(WindowManager& parWindowManager,MWWorld::Enviro getWidget(closeButton, "CloseButton"); closeButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ContainerWindow::onByeClicked); - + mContainerWidget->eventMouseButtonClick += MyGUI::newDelegate(this, &ContainerWindow::onContainerClicked); setText("CloseButton","Close"); setText("TakeButton","Take All"); - mIsOnDragAndDrop = false; - mDraggedWidget = 0; //mContainerWidget->eventMouseItemActivate += MyGUI::newDelegate(this,&ContainerWindow::onSelectedItem); } -ContainerWindow::ContainerWindow(WindowManager& parWindowManager,MWWorld::Environment& environment,MyGUI::Widget* dragAndDropWidget,std::string guiFile) +ContainerWindow::ContainerWindow(WindowManager& parWindowManager,MWWorld::Environment& environment,DragAndDrop* dragAndDrop,std::string guiFile) : WindowBase(guiFile, parWindowManager), mEnvironment(environment), - mDragAndDropWidget(dragAndDropWidget) + mDragAndDrop(dragAndDrop) { setText("_Main", "Name of Container"); //center(); adjustWindowCaption(); getWidget(mContainerWidget, "Items"); - - mIsOnDragAndDrop = false; - mDraggedWidget = 0; + mContainerWidget->eventMouseButtonClick += MyGUI::newDelegate(this, &ContainerWindow::onContainerClicked); //getWidget(takeButton, "TakeButton"); //getWidget(closeButton, "CloseButton"); @@ -151,7 +147,7 @@ void ContainerWindow::open(MWWorld::Ptr& container) if(iter->getRefData().getCount() > 1) text->setCaption(boost::lexical_cast(iter->getRefData().getCount())); - //mContainerWidgets.push_back(image); + //mContainerWidgets int pos = path.rfind("."); path.erase(pos); @@ -168,37 +164,56 @@ void ContainerWindow::open(MWWorld::Ptr& container) void ContainerWindow::Update() { - if(mIsOnDragAndDrop) + if(mDragAndDrop->mIsOnDragAndDrop) { - if(mDraggedWidget) - mDraggedWidget->setPosition(MyGUI::InputManager::getInstance().getMousePosition()); - else mIsOnDragAndDrop = false; //If this happens, there is a bug. + if(mDragAndDrop->mDraggedWidget) + mDragAndDrop->mDraggedWidget->setPosition(MyGUI::InputManager::getInstance().getMousePosition()); + else mDragAndDrop->mIsOnDragAndDrop = false; //If this happens, there is a bug. } } void ContainerWindow::onByeClicked(MyGUI::Widget* _sender) { - mEnvironment.mWindowManager->setGuiMode(GM_Game); - - setVisible(false); + if(!mDragAndDrop->mIsOnDragAndDrop) + { + mEnvironment.mWindowManager->setGuiMode(GM_Game); + setVisible(false); + } } void ContainerWindow::onSelectedItem(MyGUI::Widget* _sender) { - mIsOnDragAndDrop = true; - _sender->detachFromWidget(); - _sender->attachToWidget(mDragAndDropWidget); - //std::cout << mContainerWidget->getParent()->getParent()->getName(); - _sender->setUserString("drag","on"); - mDraggedWidget = _sender; - std::cout << "selected!"; + if(!mDragAndDrop->mIsOnDragAndDrop) + { + mDragAndDrop->mIsOnDragAndDrop = true; + _sender->detachFromWidget(); + _sender->attachToWidget(mDragAndDrop->mDragAndDropWidget); + //std::cout << mContainerWidget->getParent()->getParent()->getName(); + _sender->setUserString("drag","on"); + mDragAndDrop->mDraggedWidget = _sender; + mDragAndDrop->mContainerWindow = const_cast(this); + std::cout << "selected!"; + } } void ContainerWindow::onMouseMove(MyGUI::Widget* _sender, int _left, int _top) { /*if(_sender->getUserString("drag") == "on") { - _sender->setPosition(_left,_top); - + _sender->setPosition(_left,_top); + }*/ +} + +void ContainerWindow::onContainerClicked(MyGUI::Widget* _sender) +{ + std::cout << "container clicked"; + if(mDragAndDrop->mIsOnDragAndDrop) //drop widget here + { + mDragAndDrop->mIsOnDragAndDrop = false; + mDragAndDrop->mDraggedWidget->detachFromWidget(); + mDragAndDrop->mDraggedWidget->attachToWidget(mContainerWidget); + mDragAndDrop->mDraggedWidget = 0; + mDragAndDrop->mContainerWindow = 0; + } } \ No newline at end of file diff --git a/apps/openmw/mwgui/container.hpp b/apps/openmw/mwgui/container.hpp index 2d1aa3ac03..742bb06f04 100644 --- a/apps/openmw/mwgui/container.hpp +++ b/apps/openmw/mwgui/container.hpp @@ -18,47 +18,54 @@ namespace MWWorld namespace MyGUI { - class Gui; - class Widget; + class Gui; + class Widget; } namespace MWGui { class WindowManager; + class ContainerWindow; } namespace MWGui { - + class DragAndDrop + { + public: + bool mIsOnDragAndDrop; + ContainerWindow* mContainerWindow; + MyGUI::Widget* mDraggedWidget; + MyGUI::Widget* mDragAndDropWidget; + }; class ContainerWindow : public WindowBase { - public: - ContainerWindow(WindowManager& parWindowManager,MWWorld::Environment& environment,MyGUI::Widget* dragAndDropWidget); - ContainerWindow(WindowManager& parWindowManager,MWWorld::Environment& environment,MyGUI::Widget* dragAndDropWidget, - std::string guiFile); + public: + ContainerWindow(WindowManager& parWindowManager,MWWorld::Environment& environment,DragAndDrop* dragAndDrop); + ContainerWindow(WindowManager& parWindowManager,MWWorld::Environment& environment,DragAndDrop* dragAndDrop, + std::string guiFile); - void open(MWWorld::Ptr& container); - void setName(std::string contName); - void Update(); + void open(MWWorld::Ptr& container); + void setName(std::string contName); + void Update(); - virtual ~ContainerWindow(); + virtual ~ContainerWindow(); - protected: + protected: MWWorld::Environment& mEnvironment; std::vector mContainerWidgets; MyGUI::ItemBoxPtr mContainerWidget; MyGUI::ButtonPtr takeButton; MyGUI::ButtonPtr closeButton; - MyGUI::Widget* mDragAndDropWidget; - bool mIsOnDragAndDrop; - MyGUI::Widget* mDraggedWidget; + DragAndDrop* mDragAndDrop; void onByeClicked(MyGUI::Widget* _sender); void onSelectedItem(MyGUI::Widget* _sender); + void onContainerClicked(MyGUI::Widget* _sender); void onMouseMove(MyGUI::Widget* _sender, int _left, int _top); //MWWorld::Ptr& mContainer; diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index efc9106e91..cf2cfb5370 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -21,8 +21,8 @@ namespace MWGui { - InventoryWindow::InventoryWindow(WindowManager& parWindowManager,MWWorld::Environment& environment,MyGUI::Widget* dragAndDropWidget) - :ContainerWindow(parWindowManager,environment,dragAndDropWidget,"openmw_inventory_window_layout.xml") + InventoryWindow::InventoryWindow(WindowManager& parWindowManager,MWWorld::Environment& environment,DragAndDrop* dragAndDrop) + :ContainerWindow(parWindowManager,environment,dragAndDrop,"openmw_inventory_window_layout.xml") { } diff --git a/apps/openmw/mwgui/inventorywindow.hpp b/apps/openmw/mwgui/inventorywindow.hpp index c60889d73f..184cab183f 100644 --- a/apps/openmw/mwgui/inventorywindow.hpp +++ b/apps/openmw/mwgui/inventorywindow.hpp @@ -24,7 +24,7 @@ namespace MWGui class InventoryWindow : public MWGui::ContainerWindow { public: - InventoryWindow(WindowManager& parWindowManager,MWWorld::Environment& environment,MyGUI::Widget* dragAndDropWidget); + InventoryWindow(WindowManager& parWindowManager,MWWorld::Environment& environment,DragAndDrop* dragAndDrop); void openInventory(); }; diff --git a/apps/openmw/mwgui/window_manager.cpp b/apps/openmw/mwgui/window_manager.cpp index f2adfe1e16..9db7892e26 100644 --- a/apps/openmw/mwgui/window_manager.cpp +++ b/apps/openmw/mwgui/window_manager.cpp @@ -36,7 +36,7 @@ WindowManager::WindowManager(MWWorld::Environment& environment, , mMessageBoxManager(NULL) , console(NULL) , mJournal(NULL) - , dialogueWindow(nullptr) + , mDialogueWindow(nullptr) , mCharGen(NULL) , playerClass() , playerName() @@ -77,6 +77,12 @@ WindowManager::WindowManager(MWWorld::Environment& environment, MyGUI::Widget* dragAndDropWidget = gui->createWidgetT("Widget","",0,0,w,h,MyGUI::Align::Default,"DragAndDrop","DragAndDropWidget"); dragAndDropWidget->setVisible(false); + DragAndDrop* mDragAndDrop = new DragAndDrop(); + mDragAndDrop->mIsOnDragAndDrop = false; + mDragAndDrop->mDraggedWidget = 0; + mDragAndDrop->mDragAndDropWidget = dragAndDropWidget; + mDragAndDrop->mContainerWindow = 0; + hud = new HUD(w,h, showFPSLevel); menu = new MainMenu(w,h); map = new MapWindow(*this); @@ -84,9 +90,9 @@ WindowManager::WindowManager(MWWorld::Environment& environment, console = new Console(w,h, environment, extensions); mJournal = new JournalWindow(*this); mMessageBoxManager = new MessageBoxManager(this); - dialogueWindow = new DialogueWindow(*this,environment); - containerWindow = new ContainerWindow(*this,environment,dragAndDropWidget); - mInventoryWindow = new InventoryWindow(*this,environment,dragAndDropWidget); + mDialogueWindow = new DialogueWindow(*this,environment); + mContainerWindow = new ContainerWindow(*this,environment,mDragAndDrop); + mInventoryWindow = new InventoryWindow(*this,environment,mDragAndDrop); // The HUD is always on hud->setVisible(true); @@ -124,10 +130,11 @@ WindowManager::~WindowManager() delete menu; delete stats; delete mJournal; - delete dialogueWindow; - delete containerWindow; + delete mDialogueWindow; + delete mContainerWindow; delete mInventoryWindow; delete mCharGen; + delete mDragAndDrop; cleanupGarbage(); } @@ -186,8 +193,8 @@ void WindowManager::updateVisible() stats->setVisible(false); console->disable(); mJournal->setVisible(false); - dialogueWindow->setVisible(false); - containerWindow->setVisible(false); + mDialogueWindow->setVisible(false); + mContainerWindow->setVisible(false); mInventoryWindow->setVisible(false); // Mouse is visible whenever we're not in game mode @@ -229,12 +236,12 @@ void WindowManager::updateVisible() break; } case GM_Container: - containerWindow->setVisible(true); + mContainerWindow->setVisible(true); mInventoryWindow->setVisible(true); mInventoryWindow->openInventory(); break; case GM_Dialogue: - dialogueWindow->open(); + mDialogueWindow->open(); break; case GM_InterMessageBox: if(!mMessageBoxManager->isInteractiveMessageBox()) { @@ -413,11 +420,11 @@ const std::string &WindowManager::getGameSettingString(const std::string &id, co void WindowManager::onDialogueWindowBye() { - if (dialogueWindow) + if (mDialogueWindow) { //FIXME set some state and stuff? //removeDialog(dialogueWindow); - dialogueWindow->setVisible(false); + mDialogueWindow->setVisible(false); } setGuiMode(GM_Game); } @@ -426,7 +433,7 @@ void WindowManager::onFrame (float frameDuration) { mMessageBoxManager->onFrame(frameDuration); mInventoryWindow->Update(); - containerWindow->Update(); + mContainerWindow->Update(); } const ESMS::ESMStore& WindowManager::getStore() const diff --git a/apps/openmw/mwgui/window_manager.hpp b/apps/openmw/mwgui/window_manager.hpp index 438a99a0ef..a666b58543 100644 --- a/apps/openmw/mwgui/window_manager.hpp +++ b/apps/openmw/mwgui/window_manager.hpp @@ -63,6 +63,7 @@ namespace MWGui class JournalWindow; class CharacterCreation; class ContainerWindow; + class DragAndDrop; class InventoryWindow; class TextInputDialog; class InfoBoxDialog; @@ -126,9 +127,9 @@ namespace MWGui updateVisible(); } - MWGui::DialogueWindow* getDialogueWindow() {return dialogueWindow;} + MWGui::DialogueWindow* getDialogueWindow() {return mDialogueWindow;} - MWGui::ContainerWindow* getContainerWindow() {return containerWindow;} + MWGui::ContainerWindow* getContainerWindow() {return mContainerWindow;} MyGUI::Gui* getGui() const { return gui; } @@ -203,8 +204,9 @@ namespace MWGui MessageBoxManager *mMessageBoxManager; Console *console; JournalWindow* mJournal; - DialogueWindow *dialogueWindow; - ContainerWindow *containerWindow; + DialogueWindow *mDialogueWindow; + ContainerWindow *mContainerWindow; + DragAndDrop* mDragAndDrop; InventoryWindow *mInventoryWindow; CharacterCreation* mCharGen; From ea275a8aa85c6952e015a85e5fe5e30d0deced3d Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 30 Apr 2012 18:11:34 +0200 Subject: [PATCH 060/325] extended the list of spells with no magnitude / no duration --- apps/openmw/mwgui/widgets.cpp | 100 ++++++++++++++++++++++++++++------ apps/openmw/mwgui/widgets.hpp | 2 + 2 files changed, 86 insertions(+), 16 deletions(-) diff --git a/apps/openmw/mwgui/widgets.cpp b/apps/openmw/mwgui/widgets.cpp index 2f5af64736..0af035d310 100644 --- a/apps/openmw/mwgui/widgets.cpp +++ b/apps/openmw/mwgui/widgets.cpp @@ -356,18 +356,6 @@ void MWSpellEffect::updateWidgets() if (!mWindowManager) return; - // lists effects that have no magnitude (e.g. invisiblity) - /// \todo this list is probably incomplete - std::vector effectsWithoutMagnitude; - effectsWithoutMagnitude.push_back("sEffectInvisibility"); - effectsWithoutMagnitude.push_back("sEffectStuntedMagicka"); - effectsWithoutMagnitude.push_back("sEffectParalyze"); - - // lists effects that have no duration (e.g. open lock) - /// \todo this list is probably incomplete - std::vector effectsWithoutDuration; - effectsWithoutDuration.push_back("sEffectOpen"); - const ESMS::ESMStore &store = mWindowManager->getStore(); const ESM::MagicEffect *magicEffect = store.magicEffects.search(effect.effectID); if (textWidget) @@ -401,8 +389,7 @@ void MWSpellEffect::updateWidgets() spellLine += " " + mWindowManager->getGameSettingString(attributes[effect.attribute], ""); } - bool hasMagnitude = (std::find(effectsWithoutMagnitude.begin(), effectsWithoutMagnitude.end(), effectIDStr) == effectsWithoutMagnitude.end()); - if ((effect.magnMin >= 0 || effect.magnMax >= 0) && hasMagnitude) + if ((effect.magnMin >= 0 || effect.magnMax >= 0) && effectHasMagnitude(effectIDStr)) { if (effect.magnMin == effect.magnMax) spellLine += " " + boost::lexical_cast(effect.magnMin) + " " + ((effect.magnMin == 1) ? pt : pts); @@ -415,8 +402,7 @@ void MWSpellEffect::updateWidgets() // constant effects have no duration and no target if (!(mFlags & MWEffectList::EF_Constant)) { - bool hasDuration = (std::find(effectsWithoutDuration.begin(), effectsWithoutDuration.end(), effectIDStr) == effectsWithoutDuration.end()); - if (effect.duration >= 0 && hasDuration) + if (effect.duration >= 0 && effectHasDuration(effectIDStr)) { spellLine += " " + mWindowManager->getGameSettingString("sfor", "") + " " + boost::lexical_cast(effect.duration) + ((effect.duration == 1) ? sec : secs); } @@ -590,11 +576,93 @@ std::string MWSpellEffect::effectIDToString(const short effectID) names[35] ="sEffectWeaknesstoPoison"; names[30] ="sEffectWeaknesstoShock"; + /// \todo bloodmoon and tribunal spells - can't find the IDs anywhere? + assert(names.find(effectID) != names.end() && "Unimplemented effect type"); return names[effectID]; } +bool MWSpellEffect::effectHasDuration(const std::string& effect) +{ + // lists effects that have no duration (e.g. open lock) + std::vector effectsWithoutDuration; + effectsWithoutDuration.push_back("sEffectOpen"); + effectsWithoutDuration.push_back("sOpen"); + effectsWithoutDuration.push_back("sLock"); + effectsWithoutDuration.push_back("sDispel"); + effectsWithoutDuration.push_back("sSunDamage"); + effectsWithoutDuration.push_back("sCorprus"); + effectsWithoutDuration.push_back("sVampirism"); + effectsWithoutDuration.push_back("sMark"); + effectsWithoutDuration.push_back("sRecall"); + effectsWithoutDuration.push_back("sDivineIntervention"); + effectsWithoutDuration.push_back("sAlmsiviIntervention"); + effectsWithoutDuration.push_back("sCureCommonDisease"); + effectsWithoutDuration.push_back("sCureBlightDisease"); + effectsWithoutDuration.push_back("sCureCorprusDisease"); + effectsWithoutDuration.push_back("sCurePoison"); + effectsWithoutDuration.push_back("sCureParalyzation"); + effectsWithoutDuration.push_back("sRemoveCurse"); + + return (std::find(effectsWithoutDuration.begin(), effectsWithoutDuration.end(), effect) == effectsWithoutDuration.end()); +} + +bool MWSpellEffect::effectHasMagnitude(const std::string& effect) +{ + // lists effects that have no magnitude (e.g. invisiblity) + std::vector effectsWithoutMagnitude; + effectsWithoutMagnitude.push_back("sEffectInvisibility"); + effectsWithoutMagnitude.push_back("sEffectStuntedMagicka"); + effectsWithoutMagnitude.push_back("sEffectParalyze"); + effectsWithoutMagnitude.push_back("sSoultrap"); + effectsWithoutMagnitude.push_back("sSilence"); + effectsWithoutMagnitude.push_back("sParalyze"); + effectsWithoutMagnitude.push_back("sInvisibility"); + effectsWithoutMagnitude.push_back("sWaterWalking"); + effectsWithoutMagnitude.push_back("sWaterBreathing"); + effectsWithoutMagnitude.push_back("sSummonScamp"); + effectsWithoutMagnitude.push_back("sSummonClannfear"); + effectsWithoutMagnitude.push_back("sSummonDaedroth"); + effectsWithoutMagnitude.push_back("sSummonDremora"); + effectsWithoutMagnitude.push_back("sSummonAncestralGhost"); + effectsWithoutMagnitude.push_back("sSummonSkeletalMinion"); + effectsWithoutMagnitude.push_back("sSummonBonewalker"); + effectsWithoutMagnitude.push_back("sSummonGreaterBonewalker"); + effectsWithoutMagnitude.push_back("sSummonBonelord"); + effectsWithoutMagnitude.push_back("sSummonWingedTwilight"); + effectsWithoutMagnitude.push_back("sSummonHunger"); + effectsWithoutMagnitude.push_back("sSummonGoldenSaint"); + effectsWithoutMagnitude.push_back("sSummonFlameAtronach"); + effectsWithoutMagnitude.push_back("sSummonFrostAtronach"); + effectsWithoutMagnitude.push_back("sSummonStormAtronach"); + effectsWithoutMagnitude.push_back("sSummonCenturionSphere"); + effectsWithoutMagnitude.push_back("sBoundDagger"); + effectsWithoutMagnitude.push_back("sBoundLongsword"); + effectsWithoutMagnitude.push_back("sBoundMace"); + effectsWithoutMagnitude.push_back("sBoundBattleAxe"); + effectsWithoutMagnitude.push_back("sBoundSpear"); + effectsWithoutMagnitude.push_back("sBoundLongbow"); + effectsWithoutMagnitude.push_back("sBoundCuirass"); + effectsWithoutMagnitude.push_back("sBoundHelm"); + effectsWithoutMagnitude.push_back("sBoundBoots"); + effectsWithoutMagnitude.push_back("sBoundShield"); + effectsWithoutMagnitude.push_back("sBoundGloves"); + effectsWithoutMagnitude.push_back("sStuntedMagicka"); + effectsWithoutMagnitude.push_back("sMark"); + effectsWithoutMagnitude.push_back("sRecall"); + effectsWithoutMagnitude.push_back("sDivineIntervention"); + effectsWithoutMagnitude.push_back("sAlmsiviIntervention"); + effectsWithoutMagnitude.push_back("sCureCommonDisease"); + effectsWithoutMagnitude.push_back("sCureBlightDisease"); + effectsWithoutMagnitude.push_back("sCureCorprusDisease"); + effectsWithoutMagnitude.push_back("sCurePoison"); + effectsWithoutMagnitude.push_back("sCureParalyzation"); + effectsWithoutMagnitude.push_back("sRemoveCurse"); + + return (std::find(effectsWithoutMagnitude.begin(), effectsWithoutMagnitude.end(), effect) == effectsWithoutMagnitude.end()); +} + MWSpellEffect::~MWSpellEffect() { } diff --git a/apps/openmw/mwgui/widgets.hpp b/apps/openmw/mwgui/widgets.hpp index c0e62533d8..74da7fc933 100644 --- a/apps/openmw/mwgui/widgets.hpp +++ b/apps/openmw/mwgui/widgets.hpp @@ -197,6 +197,8 @@ namespace MWGui void setFlags(int flags) { mFlags = flags; } std::string effectIDToString(const short effectID); + bool effectHasMagnitude (const std::string& effect); + bool effectHasDuration (const std::string& effect); const SpellEffectValue &getSpellEffect() const { return effect; } From fc06dc72c9f94774851452747d0993b6722c39ed Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 30 Apr 2012 18:20:44 +0200 Subject: [PATCH 061/325] small fix --- apps/openmw/mwgui/widgets.cpp | 120 +++++++++++++++++----------------- 1 file changed, 60 insertions(+), 60 deletions(-) diff --git a/apps/openmw/mwgui/widgets.cpp b/apps/openmw/mwgui/widgets.cpp index 0af035d310..3c7f33ecd4 100644 --- a/apps/openmw/mwgui/widgets.cpp +++ b/apps/openmw/mwgui/widgets.cpp @@ -588,22 +588,22 @@ bool MWSpellEffect::effectHasDuration(const std::string& effect) // lists effects that have no duration (e.g. open lock) std::vector effectsWithoutDuration; effectsWithoutDuration.push_back("sEffectOpen"); - effectsWithoutDuration.push_back("sOpen"); - effectsWithoutDuration.push_back("sLock"); - effectsWithoutDuration.push_back("sDispel"); - effectsWithoutDuration.push_back("sSunDamage"); - effectsWithoutDuration.push_back("sCorprus"); - effectsWithoutDuration.push_back("sVampirism"); - effectsWithoutDuration.push_back("sMark"); - effectsWithoutDuration.push_back("sRecall"); - effectsWithoutDuration.push_back("sDivineIntervention"); - effectsWithoutDuration.push_back("sAlmsiviIntervention"); - effectsWithoutDuration.push_back("sCureCommonDisease"); - effectsWithoutDuration.push_back("sCureBlightDisease"); - effectsWithoutDuration.push_back("sCureCorprusDisease"); - effectsWithoutDuration.push_back("sCurePoison"); - effectsWithoutDuration.push_back("sCureParalyzation"); - effectsWithoutDuration.push_back("sRemoveCurse"); + effectsWithoutDuration.push_back("sEffectLock"); + effectsWithoutDuration.push_back("sEffectDispel"); + effectsWithoutDuration.push_back("sEffectSunDamage"); + effectsWithoutDuration.push_back("sEffectCorpus"); + effectsWithoutDuration.push_back("sEffectVampirism"); + effectsWithoutDuration.push_back("sEffectMark"); + effectsWithoutDuration.push_back("sEffectRecall"); + effectsWithoutDuration.push_back("sEffectDivineIntervention"); + effectsWithoutDuration.push_back("sEffectAlmsiviIntervention"); + effectsWithoutDuration.push_back("sEffectCureCommonDisease"); + effectsWithoutDuration.push_back("sEffectCureBlightDisease"); + effectsWithoutDuration.push_back("sEffectCureCorprusDisease"); + effectsWithoutDuration.push_back("sEffectCurePoison"); + effectsWithoutDuration.push_back("sEffectCureParalyzation"); + effectsWithoutDuration.push_back("sEffectRemoveCurse"); + effectsWithoutDuration.push_back("sEffectRestoreAttribute"); return (std::find(effectsWithoutDuration.begin(), effectsWithoutDuration.end(), effect) == effectsWithoutDuration.end()); } @@ -615,50 +615,50 @@ bool MWSpellEffect::effectHasMagnitude(const std::string& effect) effectsWithoutMagnitude.push_back("sEffectInvisibility"); effectsWithoutMagnitude.push_back("sEffectStuntedMagicka"); effectsWithoutMagnitude.push_back("sEffectParalyze"); - effectsWithoutMagnitude.push_back("sSoultrap"); - effectsWithoutMagnitude.push_back("sSilence"); - effectsWithoutMagnitude.push_back("sParalyze"); - effectsWithoutMagnitude.push_back("sInvisibility"); - effectsWithoutMagnitude.push_back("sWaterWalking"); - effectsWithoutMagnitude.push_back("sWaterBreathing"); - effectsWithoutMagnitude.push_back("sSummonScamp"); - effectsWithoutMagnitude.push_back("sSummonClannfear"); - effectsWithoutMagnitude.push_back("sSummonDaedroth"); - effectsWithoutMagnitude.push_back("sSummonDremora"); - effectsWithoutMagnitude.push_back("sSummonAncestralGhost"); - effectsWithoutMagnitude.push_back("sSummonSkeletalMinion"); - effectsWithoutMagnitude.push_back("sSummonBonewalker"); - effectsWithoutMagnitude.push_back("sSummonGreaterBonewalker"); - effectsWithoutMagnitude.push_back("sSummonBonelord"); - effectsWithoutMagnitude.push_back("sSummonWingedTwilight"); - effectsWithoutMagnitude.push_back("sSummonHunger"); - effectsWithoutMagnitude.push_back("sSummonGoldenSaint"); - effectsWithoutMagnitude.push_back("sSummonFlameAtronach"); - effectsWithoutMagnitude.push_back("sSummonFrostAtronach"); - effectsWithoutMagnitude.push_back("sSummonStormAtronach"); - effectsWithoutMagnitude.push_back("sSummonCenturionSphere"); - effectsWithoutMagnitude.push_back("sBoundDagger"); - effectsWithoutMagnitude.push_back("sBoundLongsword"); - effectsWithoutMagnitude.push_back("sBoundMace"); - effectsWithoutMagnitude.push_back("sBoundBattleAxe"); - effectsWithoutMagnitude.push_back("sBoundSpear"); - effectsWithoutMagnitude.push_back("sBoundLongbow"); - effectsWithoutMagnitude.push_back("sBoundCuirass"); - effectsWithoutMagnitude.push_back("sBoundHelm"); - effectsWithoutMagnitude.push_back("sBoundBoots"); - effectsWithoutMagnitude.push_back("sBoundShield"); - effectsWithoutMagnitude.push_back("sBoundGloves"); - effectsWithoutMagnitude.push_back("sStuntedMagicka"); - effectsWithoutMagnitude.push_back("sMark"); - effectsWithoutMagnitude.push_back("sRecall"); - effectsWithoutMagnitude.push_back("sDivineIntervention"); - effectsWithoutMagnitude.push_back("sAlmsiviIntervention"); - effectsWithoutMagnitude.push_back("sCureCommonDisease"); - effectsWithoutMagnitude.push_back("sCureBlightDisease"); - effectsWithoutMagnitude.push_back("sCureCorprusDisease"); - effectsWithoutMagnitude.push_back("sCurePoison"); - effectsWithoutMagnitude.push_back("sCureParalyzation"); - effectsWithoutMagnitude.push_back("sRemoveCurse"); + effectsWithoutMagnitude.push_back("sEffectSoultrap"); + effectsWithoutMagnitude.push_back("sEffectSilence"); + effectsWithoutMagnitude.push_back("sEffectParalyze"); + effectsWithoutMagnitude.push_back("sEffectInvisibility"); + effectsWithoutMagnitude.push_back("sEffectWaterWalking"); + effectsWithoutMagnitude.push_back("sEffectWaterBreathing"); + effectsWithoutMagnitude.push_back("sEffectSummonScamp"); + effectsWithoutMagnitude.push_back("sEffectSummonClannfear"); + effectsWithoutMagnitude.push_back("sEffectSummonDaedroth"); + effectsWithoutMagnitude.push_back("sEffectSummonDremora"); + effectsWithoutMagnitude.push_back("sEffectSummonAncestralGhost"); + effectsWithoutMagnitude.push_back("sEffectSummonSkeletalMinion"); + effectsWithoutMagnitude.push_back("sEffectSummonBonewalker"); + effectsWithoutMagnitude.push_back("sEffectSummonGreaterBonewalker"); + effectsWithoutMagnitude.push_back("sEffectSummonBonelord"); + effectsWithoutMagnitude.push_back("sEffectSummonWingedTwilight"); + effectsWithoutMagnitude.push_back("sEffectSummonHunger"); + effectsWithoutMagnitude.push_back("sEffectSummonGoldenSaint"); + effectsWithoutMagnitude.push_back("sEffectSummonFlameAtronach"); + effectsWithoutMagnitude.push_back("sEffectSummonFrostAtronach"); + effectsWithoutMagnitude.push_back("sEffectSummonStormAtronach"); + effectsWithoutMagnitude.push_back("sEffectSummonCenturionSphere"); + effectsWithoutMagnitude.push_back("sEffectBoundDagger"); + effectsWithoutMagnitude.push_back("sEffectBoundLongsword"); + effectsWithoutMagnitude.push_back("sEffectBoundMace"); + effectsWithoutMagnitude.push_back("sEffectBoundBattleAxe"); + effectsWithoutMagnitude.push_back("sEffectBoundSpear"); + effectsWithoutMagnitude.push_back("sEffectBoundLongbow"); + effectsWithoutMagnitude.push_back("sEffectBoundCuirass"); + effectsWithoutMagnitude.push_back("sEffectBoundHelm"); + effectsWithoutMagnitude.push_back("sEffectBoundBoots"); + effectsWithoutMagnitude.push_back("sEffectBoundShield"); + effectsWithoutMagnitude.push_back("sEffectBoundGloves"); + effectsWithoutMagnitude.push_back("sEffectStuntedMagicka"); + effectsWithoutMagnitude.push_back("sEffectMark"); + effectsWithoutMagnitude.push_back("sEffectRecall"); + effectsWithoutMagnitude.push_back("sEffectDivineIntervention"); + effectsWithoutMagnitude.push_back("sEffectAlmsiviIntervention"); + effectsWithoutMagnitude.push_back("sEffectCureCommonDisease"); + effectsWithoutMagnitude.push_back("sEffectCureBlightDisease"); + effectsWithoutMagnitude.push_back("sEffectCureCorprusDisease"); + effectsWithoutMagnitude.push_back("sEffectCurePoison"); + effectsWithoutMagnitude.push_back("sEffectCureParalyzation"); + effectsWithoutMagnitude.push_back("sEffectRemoveCurse"); return (std::find(effectsWithoutMagnitude.begin(), effectsWithoutMagnitude.end(), effect) == effectsWithoutMagnitude.end()); } From 6d21fe3115518c36fec2877a1c9048a8941c3927 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 30 Apr 2012 21:07:25 +0200 Subject: [PATCH 062/325] fixed mygui leaking some stuff resulting in lower fps after looking at tooltips and low-quality text --- apps/openmw/mwgui/tooltips.cpp | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 90b5baa679..e1cb051111 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -31,13 +31,10 @@ void ToolTips::onFrame(float frameDuration) { /// \todo Store a MWWorld::Ptr in the widget user data, retrieve it here and construct a tooltip dynamically - /// \todo we are destroying/creating the tooltip widgets every frame here, - /// because the tooltip might change (e.g. when trap is activated) - /// is there maybe a better way (listener when the object changes)? - for (size_t i=0; igetChildCount(); ++i) - { - mDynamicToolTipBox->_destroyChildWidget(mDynamicToolTipBox->getChildAt(i)); - } + MyGUI::Gui::getInstance().destroyWidget(mDynamicToolTipBox); + mDynamicToolTipBox = mMainWidget->createWidget("HUD_Box", + IntCoord(0, 0, mMainWidget->getCoord().width, mMainWidget->getCoord().height), + Align::Stretch, "DynamicToolTipBox"); const IntSize &viewSize = RenderManager::getInstance().getViewSize(); From 9e6531a6c6faf077e402ed1955682026cecfc7d8 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 30 Apr 2012 21:22:26 +0200 Subject: [PATCH 063/325] fix for dark corners bug on some cards --- apps/openmw/mwrender/shaderhelper.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/shaderhelper.cpp b/apps/openmw/mwrender/shaderhelper.cpp index 1d29be2b8d..59154a295c 100644 --- a/apps/openmw/mwrender/shaderhelper.cpp +++ b/apps/openmw/mwrender/shaderhelper.cpp @@ -258,7 +258,7 @@ void ShaderHelper::createShader(const bool mrt, const bool shadows, const bool s outStream << " float3 lightingFinal = lightColour.xyz * diffuse.xyz + ambient.xyz * lightAmbient.xyz + emissive.xyz; \n" " float fogValue = saturate((iDepth - fogParams.y) * fogParams.w); \n" - " oColor.xyz = lerp(lightingFinal * tex.xyz * vertexColour.xyz, fogColour.xyz, fogValue); \n" + " oColor.xyz = saturate(lerp(lightingFinal * tex.xyz * vertexColour.xyz, fogColour.xyz, fogValue)); \n" // saturate output to prevent negative output colors - TODO: replace this once there is HDR-rendering " oColor.a = tex.a * diffuse.a * vertexColour.a; \n"; if (mrt) outStream << From 48e3c4382376089e2657e665469eeb871c1f352b Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 30 Apr 2012 21:36:45 +0200 Subject: [PATCH 064/325] added the bloodmoon/tribunal spells --- apps/openmw/mwgui/widgets.cpp | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/widgets.cpp b/apps/openmw/mwgui/widgets.cpp index 3c7f33ecd4..0422bb0e23 100644 --- a/apps/openmw/mwgui/widgets.cpp +++ b/apps/openmw/mwgui/widgets.cpp @@ -576,7 +576,15 @@ std::string MWSpellEffect::effectIDToString(const short effectID) names[35] ="sEffectWeaknesstoPoison"; names[30] ="sEffectWeaknesstoShock"; - /// \todo bloodmoon and tribunal spells - can't find the IDs anywhere? + // bloodmoon + names[138] ="sEffectSummonCreature01"; + names[139] ="sEffectSummonCreature02"; + names[140] ="sEffectSummonCreature03"; + names[141] ="sEffectSummonCreature04"; + names[142] ="sEffectSummonCreature05"; + + // tribunal + names[137] ="sEffectSummonFabricant"; assert(names.find(effectID) != names.end() && "Unimplemented effect type"); @@ -659,6 +667,12 @@ bool MWSpellEffect::effectHasMagnitude(const std::string& effect) effectsWithoutMagnitude.push_back("sEffectCurePoison"); effectsWithoutMagnitude.push_back("sEffectCureParalyzation"); effectsWithoutMagnitude.push_back("sEffectRemoveCurse"); + effectsWithoutMagnitude.push_back("sEffectSummonCreature01"); + effectsWithoutMagnitude.push_back("sEffectSummonCreature02"); + effectsWithoutMagnitude.push_back("sEffectSummonCreature03"); + effectsWithoutMagnitude.push_back("sEffectSummonCreature04"); + effectsWithoutMagnitude.push_back("sEffectSummonCreature05"); + effectsWithoutMagnitude.push_back("sEffectSummonFabricant"); return (std::find(effectsWithoutMagnitude.begin(), effectsWithoutMagnitude.end(), effect) == effectsWithoutMagnitude.end()); } From bd132074af1541b00b3d458fb7283199a1ba17f0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 30 Apr 2012 22:37:23 +0200 Subject: [PATCH 065/325] some formatting tweaks --- apps/openmw/mwgui/tooltips.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index e1cb051111..9d7a7ee874 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -53,7 +53,6 @@ void ToolTips::onFrame(float frameDuration) std::string text = focus->getUserString("ToolTipText"); ToolTipInfo info; - if (type == "") { mDynamicToolTipBox->setVisible(false); @@ -61,7 +60,7 @@ void ToolTips::onFrame(float frameDuration) } else if (type == "Text") { - info.caption = text; + info.text = text; } else if (type == "CaptionText") { @@ -197,8 +196,8 @@ IntSize ToolTips::createToolTip(const ToolTipInfo& info) const IntPoint padding(8, 8); - const int imageCaptionHPadding = 8; - const int imageCaptionVPadding = 4; + const int imageCaptionHPadding = (caption != "" ? 8 : 0); + const int imageCaptionVPadding = (caption != "" ? 4 : 0); std::string realImage = "icons\\" + image; findImageExtension(realImage); @@ -208,7 +207,7 @@ IntSize ToolTips::createToolTip(const ToolTipInfo& info) captionWidget->setCaption(caption); IntSize captionSize = captionWidget->getTextSize(); - int captionHeight = std::max(captionSize.height, imageSize); + int captionHeight = std::max(caption != "" ? captionSize.height : 0, imageSize); EditBox* textWidget = mDynamicToolTipBox->createWidget("SandText", IntCoord(0, captionHeight+imageCaptionVPadding, 300, 300-captionHeight-imageCaptionVPadding), Align::Stretch, "ToolTipText"); textWidget->setProperty("Static", "true"); From 86b6184f438ad45b15c849a512b138910c70814c Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 30 Apr 2012 23:55:22 +0200 Subject: [PATCH 066/325] pMove in a seperate loop with fixed timestep to prevent frame-dependent movement --- apps/openmw/mwworld/physicssystem.cpp | 103 +++++++++++++------------- apps/openmw/mwworld/physicssystem.hpp | 10 ++- apps/openmw/mwworld/world.cpp | 53 +++++++++---- apps/openmw/mwworld/world.hpp | 8 +- libs/openengine/bullet/physic.cpp | 2 +- 5 files changed, 102 insertions(+), 74 deletions(-) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 7fe83eeabb..fb13e37c6a 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -21,27 +21,24 @@ namespace MWWorld PhysicsSystem::PhysicsSystem(OEngine::Render::OgreRenderer &_rend) : mRender(_rend), mEngine(0), mFreeFly (true) { - + playerphysics = new playerMove; // Create physics. shapeLoader is deleted by the physic engine NifBullet::ManualBulletShapeLoader* shapeLoader = new NifBullet::ManualBulletShapeLoader(); mEngine = new OEngine::Physic::PhysicEngine(shapeLoader); playerphysics->mEngine = mEngine; - - - } PhysicsSystem::~PhysicsSystem() { delete mEngine; - + } OEngine::Physic::PhysicEngine* PhysicsSystem::getEngine() { return mEngine; } - + std::pair PhysicsSystem::getFacedHandle (MWWorld::World& world) { std::string handle = ""; @@ -74,7 +71,7 @@ namespace MWWorld if(hasWater){ playerphysics->waterHeight = waterHeight; } - + } btVector3 PhysicsSystem::getRayPoint(float extent) @@ -86,26 +83,23 @@ namespace MWWorld btVector3 result(centerRay.getPoint(500*extent).x,-centerRay.getPoint(500*extent).z,centerRay.getPoint(500*extent).y); return result; } - + bool PhysicsSystem::castRay(const Vector3& from, const Vector3& to) { btVector3 _from, _to; _from = btVector3(from.x, from.y, from.z); _to = btVector3(to.x, to.y, to.z); - + std::pair result = mEngine->rayTest(_from, _to); - + return !(result.first == ""); } - - std::vector< std::pair > PhysicsSystem::doPhysics (float duration, - const std::vector >& actors) + void PhysicsSystem::doPhysics(float dt, const std::vector >& actors) { //set the DebugRenderingMode. To disable it,set it to 0 //eng->setDebugRenderingMode(1); - - + //set the walkdirection to 0 (no movement) for every actor) for(std::map::iterator it = mEngine->PhysicActorMap.begin(); it != mEngine->PhysicActorMap.end();it++) { @@ -117,8 +111,7 @@ namespace MWWorld pm_ref.rightmove = 0; pm_ref.forwardmove = 0; pm_ref.upmove = 0; - - + //playerphysics->ps.move_type = PM_NOCLIP; for (std::vector >::const_iterator iter (actors.begin()); iter!=actors.end(); ++iter) @@ -133,29 +126,24 @@ namespace MWWorld Ogre::Node* yawNode = sceneNode->getChildIterator().getNext(); Ogre::Node* pitchNode = yawNode->getChildIterator().getNext(); Ogre::Quaternion yawQuat = yawNode->getOrientation(); - Ogre::Quaternion pitchQuat = pitchNode->getOrientation(); + Ogre::Quaternion pitchQuat = pitchNode->getOrientation(); - // unused - //Ogre::Quaternion both = yawQuat * pitchQuat; - - playerphysics->ps.viewangles.x = pitchQuat.getPitch().valueDegrees(); - playerphysics->ps.viewangles.z = 0; + // unused + //Ogre::Quaternion both = yawQuat * pitchQuat; + + playerphysics->ps.viewangles.x = pitchQuat.getPitch().valueDegrees(); + playerphysics->ps.viewangles.z = 0; playerphysics->ps.viewangles.y = yawQuat.getYaw().valueDegrees() *-1 + 90; - - - if(mFreeFly) { - Ogre::Vector3 dir1(iter->second.x,iter->second.z,-iter->second.y); pm_ref.rightmove = -dir1.x; pm_ref.forwardmove = dir1.z; pm_ref.upmove = dir1.y; - - + //std::cout << "Current angle" << yawQuat.getYaw().valueDegrees() - 90<< "\n"; //playerphysics->ps.viewangles.x = pitchQuat.getPitch().valueDegrees(); //std::cout << "Pitch: " << yawQuat.getPitch() << "Yaw:" << yawQuat.getYaw() << "Roll: " << yawQuat.getRoll() << "\n"; @@ -163,46 +151,50 @@ namespace MWWorld } else { - + Ogre::Quaternion quat = yawNode->getOrientation(); Ogre::Vector3 dir1(iter->second.x,iter->second.z,-iter->second.y); - + pm_ref.rightmove = -dir1.x; pm_ref.forwardmove = dir1.z; pm_ref.upmove = dir1.y; - - - + + + dir = 0.025*(quat*dir1); } - + //set the walk direction act->setWalkDirection(btVector3(dir.x,-dir.z,dir.y)); } - mEngine->stepSimulation(duration); - Pmove(playerphysics); + mEngine->stepSimulation(dt); + } + + std::vector< std::pair > PhysicsSystem::doPhysicsFixed ( + const std::vector >& actors) + { + Pmove(playerphysics); - std::vector< std::pair > response; for(std::map::iterator it = mEngine->PhysicActorMap.begin(); it != mEngine->PhysicActorMap.end();it++) { btVector3 newPos = it->second->getPosition(); - - Ogre::Vector3 coord(newPos.x(), newPos.y(), newPos.z()); - if(it->first == "player"){ - - coord = playerphysics->ps.origin; - //std::cout << "ZCoord: " << coord.z << "\n"; - //std::cout << "Coord" << coord << "\n"; - //coord = Ogre::Vector3(coord.x, coord.z, coord.y); //x, z, -y - - } - + Ogre::Vector3 coord(newPos.x(), newPos.y(), newPos.z()); + if(it->first == "player"){ + + coord = playerphysics->ps.origin; + //std::cout << "ZCoord: " << coord.z << "\n"; + //std::cout << "Coord" << coord << "\n"; + //coord = Ogre::Vector3(coord.x, coord.z, coord.y); //x, z, -y + + } + + response.push_back(std::pair(it->first, coord)); } - + return response; } @@ -260,7 +252,14 @@ namespace MWWorld { // TODO very dirty hack to avoid crash during setup -> needs cleaning up to allow // start positions others than 0, 0, 0 - act->setPosition(btVector3(position.x,position.y,position.z)); + if (handle == "player") + { + playerphysics->ps.origin = position; + } + else + { + act->setPosition(btVector3(position.x,position.y,position.z)); + } } } @@ -316,7 +315,7 @@ namespace MWWorld } void PhysicsSystem::insertObjectPhysics(const MWWorld::Ptr& ptr, const std::string model){ - + Ogre::SceneNode* node = ptr.getRefData().getBaseNode(); // unused diff --git a/apps/openmw/mwworld/physicssystem.hpp b/apps/openmw/mwworld/physicssystem.hpp index cb559f0007..1af6bcca2f 100644 --- a/apps/openmw/mwworld/physicssystem.hpp +++ b/apps/openmw/mwworld/physicssystem.hpp @@ -16,8 +16,11 @@ namespace MWWorld PhysicsSystem (OEngine::Render::OgreRenderer &_rend); ~PhysicsSystem (); - std::vector< std::pair > doPhysics (float duration, - const std::vector >& actors); + void doPhysics(float duration, const std::vector >& actors); + ///< do physics with dt - Usage: first call doPhysics with frame dt, then call doPhysicsFixed as often as time steps have passed + + std::vector< std::pair > doPhysicsFixed (const std::vector >& actors); + ///< do physics with fixed timestep - Usage: first call doPhysics with frame dt, then call doPhysicsFixed as often as time steps have passed void addObject (const std::string& handle, const std::string& mesh, const Ogre::Quaternion& rotation, float scale, const Ogre::Vector3& position); @@ -55,7 +58,7 @@ namespace MWWorld void insertActorPhysics(const MWWorld::Ptr&, std::string model); OEngine::Physic::PhysicEngine* getEngine(); - + void setCurrentWater(bool hasWater, int waterHeight); private: @@ -64,7 +67,6 @@ namespace MWWorld bool mFreeFly; playerMove* playerphysics; - PhysicsSystem (const PhysicsSystem&); PhysicsSystem& operator= (const PhysicsSystem&); }; diff --git a/apps/openmw/mwworld/world.cpp b/apps/openmw/mwworld/world.cpp index 04bc999a09..adbdaece61 100644 --- a/apps/openmw/mwworld/world.cpp +++ b/apps/openmw/mwworld/world.cpp @@ -215,6 +215,7 @@ namespace MWWorld setFallbackValues(fallbackMap); + lastTick = mTimer.getMilliseconds(); } @@ -559,8 +560,9 @@ namespace MWWorld } } - void World::moveObjectImp (Ptr ptr, float x, float y, float z) + bool World::moveObjectImp (Ptr ptr, float x, float y, float z) { + bool ret = false; ptr.getRefData().getPosition().pos[0] = x; ptr.getRefData().getPosition().pos[1] = y; ptr.getRefData().getPosition().pos[2] = z; @@ -582,6 +584,7 @@ namespace MWWorld if (currentCell->cell->data.gridX!=cellX || currentCell->cell->data.gridY!=cellY) { mWorldScene->changeCell (cellX, cellY, mPlayer->getPlayer().getRefData().getPosition(), false); + ret = true; } } @@ -591,6 +594,8 @@ namespace MWWorld /// \todo cell change for non-player ref mRendering->moveObject (ptr, Ogre::Vector3 (x, y, z)); + + return ret; } void World::moveObject (Ptr ptr, float x, float y, float z) @@ -632,29 +637,45 @@ namespace MWWorld void World::doPhysics (const std::vector >& actors, float duration) { - std::vector< std::pair > vectors = mPhysics->doPhysics (duration, actors); + mPhysics->doPhysics(duration, actors); - std::vector< std::pair >::iterator player = vectors.end(); + const int tick = 16; // 16 ms ^= 60 Hz - for (std::vector< std::pair >::iterator it = vectors.begin(); - it!= vectors.end(); ++it) + // Game clock part of the loop, contains everything that has to be executed in a fixed timestep + long long dt = mTimer.getMilliseconds() - lastTick; + if (dt >= 100) dt = 100; // throw away wall clock time if necessary to keep the framerate above the minimum of 10 fps + while (dt >= tick) { - if (it->first=="player") + dt -= tick; + lastTick += tick; + + std::vector< std::pair > vectors = mPhysics->doPhysicsFixed (actors); + + std::vector< std::pair >::iterator player = vectors.end(); + + for (std::vector< std::pair >::iterator it = vectors.begin(); + it!= vectors.end(); ++it) { - player = it; + if (it->first=="player") + { + player = it; + } + else + { + MWWorld::Ptr ptr = getPtrViaHandle (it->first); + moveObjectImp (ptr, it->second.x, it->second.y, it->second.z); + } } - else + + // Make sure player is moved last (otherwise the cell might change in the middle of an update + // loop) + if (player!=vectors.end()) { - MWWorld::Ptr ptr = getPtrViaHandle (it->first); - moveObjectImp (ptr, it->second.x, it->second.y, it->second.z); + if (moveObjectImp (getPtrViaHandle (player->first), + player->second.x, player->second.y, player->second.z) == true) + return; // abort the current loop if the cell has changed } } - - // Make sure player is moved last (otherwise the cell might change in the middle of an update - // loop) - if (player!=vectors.end()) - moveObjectImp (getPtrViaHandle (player->first), - player->second.x, player->second.y, player->second.z); } bool World::toggleCollisionMode() diff --git a/apps/openmw/mwworld/world.hpp b/apps/openmw/mwworld/world.hpp index 77e5bcef62..7359f8b902 100644 --- a/apps/openmw/mwworld/world.hpp +++ b/apps/openmw/mwworld/world.hpp @@ -22,6 +22,8 @@ #include #include +#include + namespace Ogre { class Vector3; @@ -100,9 +102,13 @@ namespace MWWorld int mNumFacing; std::map mFallback; + unsigned long lastTick; + Ogre::Timer mTimer; + int getDaysPerMonth (int month) const; - void moveObjectImp (Ptr ptr, float x, float y, float z); + bool moveObjectImp (Ptr ptr, float x, float y, float z); + ///< @return true if the active cell (cell player is in) changed public: diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index 3d507d4eee..42853d8cfa 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -393,7 +393,7 @@ namespace Physic void PhysicEngine::stepSimulation(double deltaT) { - dynamicsWorld->stepSimulation(deltaT,10); + dynamicsWorld->stepSimulation(deltaT,10, 1/60.0); if(isDebugCreated) { mDebugDrawer->step(); From b3caf82714d0b1e2f508ac82481e81472fff6f9a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 1 May 2012 10:12:45 -0700 Subject: [PATCH 067/325] Avoid using vector<>::data(), which requires C++11 --- apps/openmw/mwsound/mpgsnd_decoder.cpp | 2 +- apps/openmw/mwsound/openal_output.cpp | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwsound/mpgsnd_decoder.cpp b/apps/openmw/mwsound/mpgsnd_decoder.cpp index 9b91b4e74e..7f7a84889a 100644 --- a/apps/openmw/mwsound/mpgsnd_decoder.cpp +++ b/apps/openmw/mwsound/mpgsnd_decoder.cpp @@ -189,7 +189,7 @@ void MpgSnd_Decoder::readAll(std::vector &output) { size_t pos = output.size(); output.resize(pos + mSndInfo.frames*mSndInfo.channels*2); - sf_readf_short(mSndFile, (short*)(output.data()+pos), mSndInfo.frames); + sf_readf_short(mSndFile, (short*)(&output[0]+pos), mSndInfo.frames); return; } // Fallback in case we don't know the total already diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index 615def7019..ac4baa8b29 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -222,8 +222,8 @@ void OpenAL_SoundStream::play() for(ALuint i = 0;i < sNumBuffers;i++) { size_t got; - got = mDecoder->read(data.data(), data.size()); - alBufferData(mBuffers[i], mFormat, data.data(), got, mSampleRate); + got = mDecoder->read(&data[0], data.size()); + alBufferData(mBuffers[i], mFormat, &data[0], got, mSampleRate); } throwALerror(); @@ -299,11 +299,11 @@ bool OpenAL_SoundStream::process() if(finished) continue; - got = mDecoder->read(data.data(), data.size()); + got = mDecoder->read(&data[0], data.size()); finished = (got < data.size()); if(got > 0) { - alBufferData(bufid, mFormat, data.data(), got, mSampleRate); + alBufferData(bufid, mFormat, &data[0], got, mSampleRate); alSourceQueueBuffers(mSource, 1, &bufid); } } while(processed > 0); @@ -595,7 +595,7 @@ ALuint OpenAL_Output::getBuffer(const std::string &fname) alGenBuffers(1, &buf); throwALerror(); - alBufferData(buf, format, data.data(), data.size(), srate); + alBufferData(buf, format, &data[0], data.size(), srate); mBufferCache[fname] = buf; mBufferRefs[buf] = 1; From 6acb777c5a3f085f19314b0e599dec37e9958ceb Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 1 May 2012 20:51:32 +0200 Subject: [PATCH 068/325] minimum framerate fix --- apps/openmw/mwworld/world.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/world.cpp b/apps/openmw/mwworld/world.cpp index adbdaece61..4adaf79183 100644 --- a/apps/openmw/mwworld/world.cpp +++ b/apps/openmw/mwworld/world.cpp @@ -643,7 +643,12 @@ namespace MWWorld // Game clock part of the loop, contains everything that has to be executed in a fixed timestep long long dt = mTimer.getMilliseconds() - lastTick; - if (dt >= 100) dt = 100; // throw away wall clock time if necessary to keep the framerate above the minimum of 10 fps + if (dt >= 100) + { + // throw away wall clock time if necessary to keep the framerate above the minimum of 10 fps + lastTick += (dt - 100); + dt = 100; + } while (dt >= tick) { dt -= tick; From 7f15385dc5afa870723a0cf84079740a55ab2a2e Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 1 May 2012 20:58:09 +0200 Subject: [PATCH 069/325] unrelated cleanup --- apps/openmw/engine.cpp | 2 -- apps/openmw/engine.hpp | 1 - 2 files changed, 3 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 539afe1c87..12a5956a98 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -148,7 +148,6 @@ OMW::Engine::Engine(Files::ConfigurationManager& configurationManager) , mNewGame (false) , mUseSound (true) , mCompileAll (false) - , mFocusTDiff (0) , mScriptContext (0) , mFSStrict (false) , mCfgMgr(configurationManager) @@ -263,7 +262,6 @@ void OMW::Engine::setNewGame(bool newGame) void OMW::Engine::go() { - mFocusTDiff = 0; assert (!mCellName.empty()); assert (!mMaster.empty()); assert (!mOgre); diff --git a/apps/openmw/engine.hpp b/apps/openmw/engine.hpp index c834ee438d..09d6bc8201 100644 --- a/apps/openmw/engine.hpp +++ b/apps/openmw/engine.hpp @@ -74,7 +74,6 @@ namespace OMW bool mNewGame; bool mUseSound; bool mCompileAll; - float mFocusTDiff; std::string mFocusName; std::map mFallbackMap; From a13f5423965871737c2fbf08e43de5116c4f1d86 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 1 May 2012 21:01:18 +0200 Subject: [PATCH 070/325] disable snapping underwater --- libs/openengine/bullet/pmove.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libs/openengine/bullet/pmove.cpp b/libs/openengine/bullet/pmove.cpp index e215d8ff63..210f7eb705 100644 --- a/libs/openengine/bullet/pmove.cpp +++ b/libs/openengine/bullet/pmove.cpp @@ -717,6 +717,8 @@ static void PM_WaterMove( playerMove* const pm ) float scale; float vel; + pm->ps.bSnap = false; + /*if ( PM_CheckWaterJump() ) { PM_WaterJumpMove(); From 6850f3945c9ee82cd00d699e653582ce70ba93ef Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 1 May 2012 21:13:41 +0200 Subject: [PATCH 071/325] disable those physics debug prints --- libs/openengine/bullet/pmove.cpp | 16 +++++++++------- libs/openengine/bullet/pmove.h | 4 ++-- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/libs/openengine/bullet/pmove.cpp b/libs/openengine/bullet/pmove.cpp index 210f7eb705..35bbd9c033 100644 --- a/libs/openengine/bullet/pmove.cpp +++ b/libs/openengine/bullet/pmove.cpp @@ -372,7 +372,7 @@ bool PM_SlideMove( bool gravity ) // stop dead at a tripple plane interaction //VectorClear( pm->ps->velocity ); - printf("Stop dead at a triple plane interaction\n"); + //printf("Stop dead at a triple plane interaction\n"); pm->ps.velocity = Ogre::Vector3(0,0,0); return true; } @@ -417,7 +417,7 @@ int PM_StepSlideMove( bool gravity ) Ogre::Vector3 up, down; float stepSize; - std::cout << "StepSlideMove\n"; + //std::cout << "StepSlideMove\n"; // start_o = pm->ps->origin //VectorCopy (pm->ps->origin, start_o); start_o = pm->ps.origin; @@ -517,6 +517,8 @@ int PM_StepSlideMove( bool gravity ) if ( delta > 2 ) { pm->ps.counter = 10; + + /* if (gravity) printf("g on: %f ", delta); else @@ -534,7 +536,7 @@ int PM_StepSlideMove( bool gravity ) else printf("stepped 15+\n"); //PM_AddEvent( EV_STEP_16 ); - + */ } /*if ( pm->debugLevel ) Com_Printf("%i:stepped\n", c_pmove);*/ @@ -863,7 +865,7 @@ static void PM_WalkMove( playerMove* const pmove ) PM_WaterMove(pmove); else PM_AirMove(); - printf("Jumped away\n"); + //printf("Jumped away\n"); return; } @@ -1146,7 +1148,7 @@ void PM_GroundTraceMissed() { traceResults trace; Ogre::Vector3 point; - std::cout << "Ground trace missed\n"; + //std::cout << "Ground trace missed\n"; // we just transitioned into freefall //if ( pm->debugLevel ) //Com_Printf("%i:lift\n", c_pmove); @@ -1292,14 +1294,14 @@ static void PM_CrashLand( void ) if ( delta < 1 ) return; - +/* if (delta > 60) printf("Far crashland: %f\n", delta); else if (delta > 40) printf("Medium crashland: %f\n", delta); else if (delta > 4) printf("Short crashland: %f\n", delta); - +*/ if (delta > 60) { /* diff --git a/libs/openengine/bullet/pmove.h b/libs/openengine/bullet/pmove.h index 2c61b3e7d7..e46eb9d2e7 100644 --- a/libs/openengine/bullet/pmove.h +++ b/libs/openengine/bullet/pmove.h @@ -105,13 +105,13 @@ struct playerMove inline void SpeedUp(void) { - printf("speed up to: %f\n", speed); + //printf("speed up to: %f\n", speed); speed *= 1.25f; } inline void SpeedDown(void) { - printf("speed down to %f\n", speed); + //printf("speed down to %f\n", speed); speed /= 1.25f; } From 04ead5eb42e67b1346f8e5055d16d37d8fa06741 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 1 May 2012 21:22:15 +0200 Subject: [PATCH 072/325] make the no-clip mode move much faster --- libs/openengine/bullet/pmove.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/openengine/bullet/pmove.cpp b/libs/openengine/bullet/pmove.cpp index 35bbd9c033..591f1869f8 100644 --- a/libs/openengine/bullet/pmove.cpp +++ b/libs/openengine/bullet/pmove.cpp @@ -636,7 +636,7 @@ float PM_CmdScale(playerMove::playercmd* const cmd) + cmd->rightmove * cmd->rightmove + cmd->upmove * cmd->upmove) ); scale = (float)pm->ps.speed * max / ( 127.0f * total ); if(pm->ps.move_type == PM_NOCLIP) - scale *= 2; + scale *= 10; return scale; } From e4b057be300169c45e242b946b614311f71d3f70 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 1 May 2012 21:49:00 +0200 Subject: [PATCH 073/325] translated journal notification --- apps/openmw/mwdialogue/journal.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwdialogue/journal.cpp b/apps/openmw/mwdialogue/journal.cpp index e0245406ef..eb828a76cb 100644 --- a/apps/openmw/mwdialogue/journal.cpp +++ b/apps/openmw/mwdialogue/journal.cpp @@ -6,6 +6,8 @@ #include "../mwgui/window_manager.hpp" #include "../mwgui/messagebox.hpp" +#include "../mwworld/world.hpp" + namespace MWDialogue { Quest& Journal::getQuest (const std::string& id) @@ -38,7 +40,7 @@ namespace MWDialogue quest.addEntry (entry, *MWBase::Environment::get().getWorld()); // we are doing slicing on purpose here std::vector empty; - std::string notification = "Your Journal has been updated."; + std::string notification = MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sJournalEntry")->str; MWBase::Environment::get().getWindowManager()->messageBox (notification, empty); } From dd8c66b479d9de8a508ba493d3fa70fbb38958c9 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 1 May 2012 21:54:30 +0200 Subject: [PATCH 074/325] notification when screenshot was taken --- apps/openmw/mwinput/inputmanager.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwinput/inputmanager.cpp b/apps/openmw/mwinput/inputmanager.cpp index c2233f6265..9786c6768e 100644 --- a/apps/openmw/mwinput/inputmanager.cpp +++ b/apps/openmw/mwinput/inputmanager.cpp @@ -132,6 +132,9 @@ namespace MWInput void screenshot() { mEngine.screenshot(); + + std::vector empty; + windows.messageBox ("Screenshot saved", empty); } /* toggleInventory() is called when the user presses the button to toggle the inventory screen. */ From 144d52cf495a93aa7eb7204fd580ff0f9cf0f472 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 1 May 2012 20:30:31 -0700 Subject: [PATCH 075/325] Add voices to the chargen class questions --- apps/openmw/mwgui/charactercreation.cpp | 16 +++++++++++ apps/openmw/mwsound/soundmanager.cpp | 36 +++++++++++++++++++++++++ apps/openmw/mwsound/soundmanager.hpp | 11 ++++++-- 3 files changed, 61 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/charactercreation.cpp b/apps/openmw/mwgui/charactercreation.cpp index 9a23758558..10c4cdcb4f 100644 --- a/apps/openmw/mwgui/charactercreation.cpp +++ b/apps/openmw/mwgui/charactercreation.cpp @@ -9,6 +9,7 @@ #include "mode.hpp" #include "../mwbase/environment.hpp" +#include "../mwsound/soundmanager.hpp" namespace { @@ -16,6 +17,7 @@ namespace { const char* mText; const char* mButtons[3]; + const char* mSound; ESM::Class::Specialization mSpecializations[3]; // The specialization for each answer }; @@ -25,6 +27,7 @@ namespace {"Draw your dagger, mercifully endings its life with a single thrust.", "Use herbs from your pack to put it to sleep.", "Do not interfere in the natural evolution of events, but rather take the opportunity to learn more about a strange animal that you have never seen before."}, + "vo\\misc\\chargen qa1.wav", {ESM::Class::Combat, ESM::Class::Magic, ESM::Class::Stealth} }, // Question 2 @@ -32,6 +35,7 @@ namespace {"Work in the forge with him casting iron for a new plow.", "Gather herbs for your mother who is preparing dinner.", "Go catch fish at the stream using a net and line."}, + "vo\\misc\\chargen qa2.wav", {ESM::Class::Combat, ESM::Class::Magic, ESM::Class::Stealth} }, // Question 3 @@ -39,6 +43,7 @@ namespace {"Beat up your cousin, then tell him that if he ever calls you that nickname again, you will bloody him worse than this time.", "Make up a story that makes your nickname a badge of honor instead of something humiliating.", "Make up an even more embarrassing nickname for him and use it constantly until he learns his lesson."}, + "vo\\misc\\chargen qa3.wav", {ESM::Class::Combat, ESM::Class::Magic, ESM::Class::Stealth} }, // Question 4 @@ -46,6 +51,7 @@ namespace {"This is a terrible practice. A person's thoughts are his own and no one, not even a king, has the right to make such an invasion into another human's mind.", "Loyal followers to the king have nothing to fear from a Telepath. It is important to have a method of finding assassins and spies before it is too late.", "In these times, it is a necessary evil. Although you do not necessarily like the idea, a Telepath could have certain advantages during a time of war or in finding someone innocent of a crime."}, + "vo\\misc\\chargen qa4.wav", {ESM::Class::Combat, ESM::Class::Magic, ESM::Class::Stealth} }, // Question 5 @@ -53,6 +59,7 @@ namespace {"Return to the store and give the shopkeeper his hard-earned money, explaining to him the mistake?", "Decide to put the extra money to good use and purchase items that would help your family?", "Pocket the extra money, knowing that shopkeepers in general tend to overcharge customers anyway?"}, + "vo\\misc\\chargen qa5.wav", {ESM::Class::Combat, ESM::Class::Magic, ESM::Class::Stealth} }, // Question 6 @@ -60,6 +67,7 @@ namespace {"Pick up the bag and signal to the guard, knowing that the only honorable thing to do is return the money to its rightful owner.", "Leave the bag there, knowing that it is better not to get involved.", "Pick up the bag and pocket it, knowing that the extra windfall will help your family in times of trouble."}, + "vo\\misc\\chargen qa6.wav", {ESM::Class::Combat, ESM::Class::Magic, ESM::Class::Stealth} }, // Question 7 @@ -67,6 +75,7 @@ namespace {"Decline his offer, knowing that your father expects you to do the work, and it is better not to be in debt.", "Ask him to help you, knowing that two people can do the job faster than one, and agree to help him with one task of his choosing in the future.", "Accept his offer, reasoning that as long as the stables are cleaned, it matters not who does the cleaning."}, + "vo\\misc\\chargen qa7.wav", {ESM::Class::Combat, ESM::Class::Magic, ESM::Class::Stealth} }, // Question 8 @@ -74,6 +83,7 @@ namespace {"Position yourself between the pipe and your mother.", "Grab the hot pipe and try to push it away.", "Push your mother out of the way."}, + "vo\\misc\\chargen qa8.wav", {ESM::Class::Combat, ESM::Class::Magic, ESM::Class::Stealth} }, // Question 9 @@ -81,6 +91,7 @@ namespace {"Drop the sweetroll and step on it, then get ready for the fight.", "Give him the sweetroll now without argument, knowing that later this afternoon you will have all your friends with you and can come and take whatever he owes you.", "Act like you're going to give him the sweetroll, but at the last minute throw it in the air, hoping that they'll pay attention to it long enough for you to get a shot in on the leader."}, + "vo\\misc\\chargen qa9.wav", {ESM::Class::Combat, ESM::Class::Magic, ESM::Class::Stealth} }, // Question 10 @@ -88,6 +99,7 @@ namespace {"Rush to the town's aid immediately, despite your lack of knowledge of the circumstances.", "Stand aside and allow the man and the mob to pass, realizing it is probably best not to get involved.", "Rush to the man's aid immediately, despite your lack of knowledge of the circumstances."}, + "vo\\misc\\chargen qa10.wav", {ESM::Class::Combat, ESM::Class::Magic, ESM::Class::Stealth} } } }; @@ -479,6 +491,8 @@ void CharacterCreation::onCreateClassDialogBack() void CharacterCreation::onClassQuestionChosen(int _index) { + MWBase::Environment::get().getSoundManager()->stopSay(); + if (mGenerateClassQuestionDialog) mWM->removeDialog(mGenerateClassQuestionDialog); if (_index < 0 || _index >= 3) @@ -584,6 +598,8 @@ void CharacterCreation::showClassQuestionDialog() mGenerateClassQuestionDialog->setButtons(buttons); mGenerateClassQuestionDialog->eventButtonSelected += MyGUI::newDelegate(this, &CharacterCreation::onClassQuestionChosen); mGenerateClassQuestionDialog->open(); + + MWBase::Environment::get().getSoundManager()->say(sGenerateClassSteps[mGenerateClassStep].mSound); } void CharacterCreation::onGenerateClassBack() diff --git a/apps/openmw/mwsound/soundmanager.cpp b/apps/openmw/mwsound/soundmanager.cpp index 4656efb6ed..9eefc7a28d 100644 --- a/apps/openmw/mwsound/soundmanager.cpp +++ b/apps/openmw/mwsound/soundmanager.cpp @@ -228,11 +228,47 @@ namespace MWSound } } + void SoundManager::say(const std::string& filename) + { + if(!mOutput->isInitialized()) + return; + try + { + float basevol = mMasterVolume * mSFXVolume; + std::string filePath = "Sound/"+filename; + + SoundPtr sound = mOutput->playSound(filePath, basevol, 1.0f, Play_Normal); + sound->mBaseVolume = basevol; + + mActiveSounds[sound] = std::make_pair(MWWorld::Ptr(), std::string("_say_sound")); + } + catch(std::exception &e) + { + std::cout <<"Sound Error: "<second.first == ptr && snditer->second.second == "_say_sound") + { + snditer->first->stop(); + mActiveSounds.erase(snditer++); + } + else + snditer++; + } + } + + SoundPtr SoundManager::playSound(const std::string& soundId, float volume, float pitch, int mode) { diff --git a/apps/openmw/mwsound/soundmanager.hpp b/apps/openmw/mwsound/soundmanager.hpp index 8afd488e11..e1816cd1f3 100644 --- a/apps/openmw/mwsound/soundmanager.hpp +++ b/apps/openmw/mwsound/soundmanager.hpp @@ -97,11 +97,18 @@ namespace MWSound void say(MWWorld::Ptr reference, const std::string& filename); ///< Make an actor say some text. - /// \param filename name of a sound file in "Sound/Vo/" in the data directory. + /// \param filename name of a sound file in "Sound/" in the data directory. - bool sayDone(MWWorld::Ptr reference) const; + void say(const std::string& filename); + ///< Say some text, without an actor ref + /// \param filename name of a sound file in "Sound/" in the data directory. + + bool sayDone(MWWorld::Ptr reference=MWWorld::Ptr()) const; ///< Is actor not speaking? + void stopSay(MWWorld::Ptr reference=MWWorld::Ptr()); + ///< Stop an actor speaking + SoundPtr playSound(const std::string& soundId, float volume, float pitch, int mode=Play_Normal); ///< Play a sound, independently of 3D-position From c4b63bdb2fdb98afc809778c1c06a87119c02ffc Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 2 May 2012 23:27:56 +0200 Subject: [PATCH 076/325] .gitmodules --- libs/openengine/.gitmodules | 3 --- 1 file changed, 3 deletions(-) delete mode 100644 libs/openengine/.gitmodules diff --git a/libs/openengine/.gitmodules b/libs/openengine/.gitmodules deleted file mode 100644 index 0a9a9121fd..0000000000 --- a/libs/openengine/.gitmodules +++ /dev/null @@ -1,3 +0,0 @@ -[submodule "mangle"] - path = mangle - url = git://github.com/korslund/mangle From c0e12d0e56d5cadc6125bf46fb9072bb78f9b7df Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 3 May 2012 01:11:49 +0200 Subject: [PATCH 077/325] class dialog fix --- apps/openmw/mwgui/charactercreation.cpp | 1 + apps/openmw/mwgui/class.cpp | 2 ++ 2 files changed, 3 insertions(+) diff --git a/apps/openmw/mwgui/charactercreation.cpp b/apps/openmw/mwgui/charactercreation.cpp index 9a23758558..446961a87b 100644 --- a/apps/openmw/mwgui/charactercreation.cpp +++ b/apps/openmw/mwgui/charactercreation.cpp @@ -171,6 +171,7 @@ void CharacterCreation::spawnDialog(const char id) if (mCreateClassDialog) mWM->removeDialog(mCreateClassDialog); mCreateClassDialog = new CreateClassDialog(*mWM); + mCreateClassDialog->setNextButtonShow(mCreationStage >= CSE_ClassChosen); mCreateClassDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onCreateClassDialogDone); mCreateClassDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onCreateClassDialogBack); mCreateClassDialog->open(); diff --git a/apps/openmw/mwgui/class.cpp b/apps/openmw/mwgui/class.cpp index 9f1fc5d2a5..e654f7c908 100644 --- a/apps/openmw/mwgui/class.cpp +++ b/apps/openmw/mwgui/class.cpp @@ -111,6 +111,7 @@ PickClassDialog::PickClassDialog(WindowManager& parWindowManager) MyGUI::ButtonPtr backButton; getWidget(backButton, "BackButton"); backButton->eventMouseButtonClick += MyGUI::newDelegate(this, &PickClassDialog::onBackClicked); + backButton->setCaption(mWindowManager.getGameSettingString("sBack", "")); MyGUI::ButtonPtr okButton; getWidget(okButton, "OKButton"); @@ -431,6 +432,7 @@ CreateClassDialog::CreateClassDialog(WindowManager& parWindowManager) MyGUI::ButtonPtr backButton; getWidget(backButton, "BackButton"); backButton->eventMouseButtonClick += MyGUI::newDelegate(this, &CreateClassDialog::onBackClicked); + backButton->setCaption(mWindowManager.getGameSettingString("sBack", "")); MyGUI::ButtonPtr okButton; getWidget(okButton, "OKButton"); From 0e6b82284fe0beab83a2bc769c133d66c7c605f2 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 3 May 2012 03:33:33 +0200 Subject: [PATCH 078/325] book & scroll windows --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwgui/bookwindow.cpp | 15 +++++++++++++++ apps/openmw/mwgui/bookwindow.hpp | 20 ++++++++++++++++++++ apps/openmw/mwgui/journalwindow.cpp | 7 ------- apps/openmw/mwgui/journalwindow.hpp | 9 --------- apps/openmw/mwgui/scrollwindow.cpp | 14 ++++++++++++++ apps/openmw/mwgui/scrollwindow.hpp | 19 +++++++++++++++++++ apps/openmw/mwgui/window_manager.cpp | 6 ++++++ apps/openmw/mwgui/window_manager.hpp | 4 ++++ files/mygui/CMakeLists.txt | 3 +++ files/mygui/core.xml | 1 + files/mygui/openmw_book_layout.xml | 20 ++++++++++++++++++++ files/mygui/openmw_journal_layout.xml | 7 ++----- files/mygui/openmw_journal_skin.xml | 6 +++--- files/mygui/openmw_scroll_layout.xml | 16 ++++++++++++++++ files/mygui/openmw_scroll_skin.xml | 15 +++++++++++++++ 16 files changed, 139 insertions(+), 25 deletions(-) create mode 100644 apps/openmw/mwgui/bookwindow.cpp create mode 100644 apps/openmw/mwgui/bookwindow.hpp create mode 100644 apps/openmw/mwgui/scrollwindow.cpp create mode 100644 apps/openmw/mwgui/scrollwindow.hpp create mode 100644 files/mygui/openmw_book_layout.xml create mode 100644 files/mygui/openmw_scroll_layout.xml create mode 100644 files/mygui/openmw_scroll_skin.xml diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 79ea262e68..0fc841ce6e 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -25,7 +25,7 @@ add_openmw_dir (mwinput add_openmw_dir (mwgui layouts text_input widgets race class birth review window_manager console dialogue dialogue_history window_base stats_window messagebox journalwindow charactercreation - map_window window_pinnable_base cursorreplace tooltips + map_window window_pinnable_base cursorreplace tooltips scrollwindow bookwindow ) add_openmw_dir (mwdialogue diff --git a/apps/openmw/mwgui/bookwindow.cpp b/apps/openmw/mwgui/bookwindow.cpp new file mode 100644 index 0000000000..ce816a6693 --- /dev/null +++ b/apps/openmw/mwgui/bookwindow.cpp @@ -0,0 +1,15 @@ +#include "bookwindow.hpp" + +using namespace MWGui; + +BookWindow::BookWindow(WindowManager& parWindowManager) : + WindowBase("openmw_book_layout.xml", parWindowManager) +{ + //setVisible(false); + center(); +} + +void BookWindow::open(MWWorld::Ptr book) +{ +} + diff --git a/apps/openmw/mwgui/bookwindow.hpp b/apps/openmw/mwgui/bookwindow.hpp new file mode 100644 index 0000000000..57f45f0172 --- /dev/null +++ b/apps/openmw/mwgui/bookwindow.hpp @@ -0,0 +1,20 @@ +#ifndef MWGUI_BOOKWINDOW_H +#define MWGUI_BOOKWINDOW_H + +#include "window_base.hpp" + +#include "../mwworld/ptr.hpp" + +namespace MWGui +{ + class BookWindow : public WindowBase + { + public: + BookWindow(WindowManager& parWindowManager); + void open(MWWorld::Ptr book); + }; + +} + +#endif + diff --git a/apps/openmw/mwgui/journalwindow.cpp b/apps/openmw/mwgui/journalwindow.cpp index e67eda7771..4030911a00 100644 --- a/apps/openmw/mwgui/journalwindow.cpp +++ b/apps/openmw/mwgui/journalwindow.cpp @@ -109,9 +109,6 @@ MWGui::JournalWindow::JournalWindow (WindowManager& parWindowManager) //std::list list = formatText("OpenMW rgh dsfg sqef srg ZT uzql n ZLIEHRF LQSJH GLOIjf qjfmj hslkdgn jlkdjhg qlr isgli shli uhs fiuh qksf cg ksjnf lkqsnbf ksbf sbfkl zbf kuyzflkj sbgdfkj zlfh ozhjfmo hzmfh lizuf rty qzt ezy tkyEZT RYYJ DG fgh is an open-source implementation of the game engine found in the game Morrowind. This is a dumb test text msodjbg smojg smoig fiiinnn"); //std::list list = formatText(); //displayLeftText(list.front()); - - MyGUI::WindowPtr t = static_cast(mMainWidget); - t->eventWindowChangeCoord += MyGUI::newDelegate(this, &JournalWindow::onWindowResize); } void MWGui::JournalWindow::open() @@ -159,10 +156,6 @@ void MWGui::JournalWindow::open() } } -void MWGui::JournalWindow::onWindowResize(MyGUI::Window* window) -{ -} - void MWGui::JournalWindow::displayLeftText(std::string text) { mLeftTextWidget->eraseText(0,mLeftTextWidget->getTextLength()); diff --git a/apps/openmw/mwgui/journalwindow.hpp b/apps/openmw/mwgui/journalwindow.hpp index 4656c7a482..c5009d6548 100644 --- a/apps/openmw/mwgui/journalwindow.hpp +++ b/apps/openmw/mwgui/journalwindow.hpp @@ -19,15 +19,6 @@ namespace MWGui void open(); private: - enum ColorStyle - { - CS_Sub, - CS_Normal, - CS_Super - }; - - void onWindowResize(MyGUI::Window* window); - void displayLeftText(std::string text); void displayRightText(std::string text); diff --git a/apps/openmw/mwgui/scrollwindow.cpp b/apps/openmw/mwgui/scrollwindow.cpp new file mode 100644 index 0000000000..ab4065e418 --- /dev/null +++ b/apps/openmw/mwgui/scrollwindow.cpp @@ -0,0 +1,14 @@ +#include "scrollwindow.hpp" + +using namespace MWGui; + +ScrollWindow::ScrollWindow(WindowManager& parWindowManager) : + WindowBase("openmw_scroll_layout.xml", parWindowManager) +{ + setVisible(false); + center(); +} + +void ScrollWindow::open(MWWorld::Ptr scroll) +{ +} diff --git a/apps/openmw/mwgui/scrollwindow.hpp b/apps/openmw/mwgui/scrollwindow.hpp new file mode 100644 index 0000000000..d7f5cd686c --- /dev/null +++ b/apps/openmw/mwgui/scrollwindow.hpp @@ -0,0 +1,19 @@ +#ifndef MWGUI_SCROLLWINDOW_H +#define MWGUI_SCROLLWINDOW_H + +#include "window_base.hpp" + +#include "../mwworld/ptr.hpp" + +namespace MWGui +{ + class ScrollWindow : public WindowBase + { + public: + ScrollWindow(WindowManager& parWindowManager); + void open(MWWorld::Ptr scroll); + }; + +} + +#endif diff --git a/apps/openmw/mwgui/window_manager.cpp b/apps/openmw/mwgui/window_manager.cpp index 0f2df53e1a..40fc9308d7 100644 --- a/apps/openmw/mwgui/window_manager.cpp +++ b/apps/openmw/mwgui/window_manager.cpp @@ -8,6 +8,8 @@ #include "stats_window.hpp" #include "messagebox.hpp" #include "tooltips.hpp" +#include "scrollwindow.hpp" +#include "bookwindow.hpp" #include "../mwmechanics/mechanicsmanager.hpp" #include "../mwinput/inputmanager.hpp" @@ -37,6 +39,8 @@ WindowManager::WindowManager( , mMessageBoxManager(NULL) , console(NULL) , mJournal(NULL) + , mBookWindow(NULL) + , mScrollWindow(NULL) , dialogueWindow(nullptr) , mCharGen(NULL) , playerClass() @@ -84,6 +88,8 @@ WindowManager::WindowManager( mMessageBoxManager = new MessageBoxManager(this); dialogueWindow = new DialogueWindow(*this); mToolTips = new ToolTips(this); + mScrollWindow = new ScrollWindow(*this); + mBookWindow = new BookWindow(*this); // The HUD is always on hud->setVisible(true); diff --git a/apps/openmw/mwgui/window_manager.hpp b/apps/openmw/mwgui/window_manager.hpp index f96660715a..13da6c7f01 100644 --- a/apps/openmw/mwgui/window_manager.hpp +++ b/apps/openmw/mwgui/window_manager.hpp @@ -62,6 +62,8 @@ namespace MWGui class JournalWindow; class CharacterCreation; class ToolTips; + class ScrollWindow; + class BookWindow; class TextInputDialog; class InfoBoxDialog; @@ -203,6 +205,8 @@ namespace MWGui Console *console; JournalWindow* mJournal; DialogueWindow *dialogueWindow; + ScrollWindow* mScrollWindow; + BookWindow* mBookWindow; CharacterCreation* mCharGen; diff --git a/files/mygui/CMakeLists.txt b/files/mygui/CMakeLists.txt index 49055d2ede..ef62fb68ce 100644 --- a/files/mygui/CMakeLists.txt +++ b/files/mygui/CMakeLists.txt @@ -51,6 +51,9 @@ configure_file("${SDIR}/openmw_interactive_messagebox_layout.xml" "${DDIR}/openm configure_file("${SDIR}/openmw_journal_layout.xml" "${DDIR}/openmw_journal_layout.xml" COPYONLY) configure_file("${SDIR}/openmw_journal_skin.xml" "${DDIR}/openmw_journal_skin.xml" COPYONLY) configure_file("${SDIR}/openmw_tooltips.xml" "${DDIR}/openmw_tooltips.xml" COPYONLY) +configure_file("${SDIR}/openmw_scroll_layout.xml" "${DDIR}/openmw_scroll_layout.xml" COPYONLY) +configure_file("${SDIR}/openmw_scroll_skin.xml" "${DDIR}/openmw_scroll_skin.xml" COPYONLY) +configure_file("${SDIR}/openmw_book_layout.xml" "${DDIR}/openmw_book_layout.xml" COPYONLY) configure_file("${SDIR}/smallbars.png" "${DDIR}/smallbars.png" COPYONLY) configure_file("${SDIR}/transparent.png" "${DDIR}/transparent.png" COPYONLY) configure_file("${SDIR}/EBGaramond-Regular.ttf" "${DDIR}/EBGaramond-Regular.ttf" COPYONLY) diff --git a/files/mygui/core.xml b/files/mygui/core.xml index 7417328cf1..c0a29d1f6e 100644 --- a/files/mygui/core.xml +++ b/files/mygui/core.xml @@ -20,6 +20,7 @@ + diff --git a/files/mygui/openmw_book_layout.xml b/files/mygui/openmw_book_layout.xml new file mode 100644 index 0000000000..ccf494860b --- /dev/null +++ b/files/mygui/openmw_book_layout.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/files/mygui/openmw_journal_layout.xml b/files/mygui/openmw_journal_layout.xml index da4fe658bd..5711053aca 100644 --- a/files/mygui/openmw_journal_layout.xml +++ b/files/mygui/openmw_journal_layout.xml @@ -7,11 +7,8 @@ - - - - - + + diff --git a/files/mygui/openmw_journal_skin.xml b/files/mygui/openmw_journal_skin.xml index 0ef87852f4..a983ac523b 100644 --- a/files/mygui/openmw_journal_skin.xml +++ b/files/mygui/openmw_journal_skin.xml @@ -1,9 +1,9 @@ - - - + + + diff --git a/files/mygui/openmw_scroll_layout.xml b/files/mygui/openmw_scroll_layout.xml new file mode 100644 index 0000000000..b396931edd --- /dev/null +++ b/files/mygui/openmw_scroll_layout.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/files/mygui/openmw_scroll_skin.xml b/files/mygui/openmw_scroll_skin.xml new file mode 100644 index 0000000000..e55396ac44 --- /dev/null +++ b/files/mygui/openmw_scroll_skin.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + From 9fc1138a87996be047d05746c9218c5babf889c6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 3 May 2012 05:26:05 +0200 Subject: [PATCH 079/325] opening, closing and taking books/scrolls works --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwclass/book.cpp | 8 ++--- apps/openmw/mwgui/bookwindow.cpp | 49 ++++++++++++++++++++++++++-- apps/openmw/mwgui/bookwindow.hpp | 14 ++++++++ apps/openmw/mwgui/mode.hpp | 4 +-- apps/openmw/mwgui/scrollwindow.cpp | 36 ++++++++++++++++++-- apps/openmw/mwgui/scrollwindow.hpp | 14 ++++++-- apps/openmw/mwgui/window_manager.cpp | 8 +++++ apps/openmw/mwgui/window_manager.hpp | 3 ++ apps/openmw/mwworld/actionread.cpp | 31 ++++++++++++++++++ apps/openmw/mwworld/actionread.hpp | 21 ++++++++++++ 11 files changed, 173 insertions(+), 17 deletions(-) create mode 100644 apps/openmw/mwworld/actionread.cpp create mode 100644 apps/openmw/mwworld/actionread.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 0fc841ce6e..b112c3f38c 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -46,7 +46,7 @@ add_openmw_dir (mwsound add_openmw_dir (mwworld refdata world physicssystem scene globals class action nullaction actionteleport containerstore actiontalk actiontake manualref player cellfunctors - cells localscripts customdata weather inventorystore ptr + cells localscripts customdata weather inventorystore ptr actionread ) add_openmw_dir (mwclass diff --git a/apps/openmw/mwclass/book.cpp b/apps/openmw/mwclass/book.cpp index ab659b4805..2409f95e45 100644 --- a/apps/openmw/mwclass/book.cpp +++ b/apps/openmw/mwclass/book.cpp @@ -8,7 +8,7 @@ #include "../mwbase/environment.hpp" #include "../mwworld/ptr.hpp" -#include "../mwworld/actiontake.hpp" +#include "../mwworld/actionread.hpp" #include "../mwworld/world.hpp" #include "../mwrender/objects.hpp" @@ -60,12 +60,8 @@ namespace MWClass boost::shared_ptr Book::activate (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const { - // TODO implement reading - - MWBase::Environment::get().getSoundManager()->playSound3D (ptr, getUpSoundId(ptr), 1.0, 1.0, MWSound::Play_NoTrack); - return boost::shared_ptr ( - new MWWorld::ActionTake (ptr)); + new MWWorld::ActionRead (ptr)); } std::string Book::getScript (const MWWorld::Ptr& ptr) const diff --git a/apps/openmw/mwgui/bookwindow.cpp b/apps/openmw/mwgui/bookwindow.cpp index ce816a6693..4b6082b814 100644 --- a/apps/openmw/mwgui/bookwindow.cpp +++ b/apps/openmw/mwgui/bookwindow.cpp @@ -1,15 +1,58 @@ #include "bookwindow.hpp" +#include "../mwbase/environment.hpp" +#include "../mwinput/inputmanager.hpp" +#include "../mwsound/soundmanager.hpp" +#include "../mwworld/actiontake.hpp" + using namespace MWGui; -BookWindow::BookWindow(WindowManager& parWindowManager) : +BookWindow::BookWindow (WindowManager& parWindowManager) : WindowBase("openmw_book_layout.xml", parWindowManager) { - //setVisible(false); + getWidget(mCloseButton, "CloseButton"); + mCloseButton->eventMouseButtonClick += MyGUI::newDelegate(this, &BookWindow::onCloseButtonClicked); + + getWidget(mTakeButton, "TakeButton"); + mTakeButton->eventMouseButtonClick += MyGUI::newDelegate(this, &BookWindow::onTakeButtonClicked); + + getWidget(mNextPageButton, "NextPageBTN"); + mNextPageButton->eventMouseButtonClick += MyGUI::newDelegate(this, &BookWindow::onNextPageButtonClicked); + + getWidget(mPrevPageButton, "PrevPageBTN"); + mPrevPageButton->eventMouseButtonClick += MyGUI::newDelegate(this, &BookWindow::onPrevPageButtonClicked); + center(); } -void BookWindow::open(MWWorld::Ptr book) +void BookWindow::open (MWWorld::Ptr book) +{ + MWBase::Environment::get().getSoundManager()->playSound3D (book, "book open", 1.0, 1.0); + + mBook = book; +} + +void BookWindow::onCloseButtonClicked (MyGUI::Widget* _sender) +{ + MWBase::Environment::get().getSoundManager()->playSound3D (mBook, "book close", 1.0, 1.0); + + MWBase::Environment::get().getInputManager()->setGuiMode(MWGui::GM_Game); +} + +void BookWindow::onTakeButtonClicked (MyGUI::Widget* _sender) +{ + MWBase::Environment::get().getSoundManager()->playSound3D (mBook, "Item Book Up", 1.0, 1.0, MWSound::Play_NoTrack); + + MWWorld::ActionTake take(mBook); + take.execute(); + + MWBase::Environment::get().getInputManager()->setGuiMode (GM_Game); +} + +void BookWindow::onNextPageButtonClicked (MyGUI::Widget* _sender) { } +void BookWindow::onPrevPageButtonClicked (MyGUI::Widget* _sender) +{ +} diff --git a/apps/openmw/mwgui/bookwindow.hpp b/apps/openmw/mwgui/bookwindow.hpp index 57f45f0172..bc017e326f 100644 --- a/apps/openmw/mwgui/bookwindow.hpp +++ b/apps/openmw/mwgui/bookwindow.hpp @@ -12,6 +12,20 @@ namespace MWGui public: BookWindow(WindowManager& parWindowManager); void open(MWWorld::Ptr book); + + protected: + void onNextPageButtonClicked (MyGUI::Widget* _sender); + void onPrevPageButtonClicked (MyGUI::Widget* _sender); + void onCloseButtonClicked (MyGUI::Widget* _sender); + void onTakeButtonClicked (MyGUI::Widget* _sender); + + private: + MyGUI::Button* mCloseButton; + MyGUI::Button* mTakeButton; + MyGUI::Button* mNextPageButton; + MyGUI::Button* mPrevPageButton; + + MWWorld::Ptr mBook; }; } diff --git a/apps/openmw/mwgui/mode.hpp b/apps/openmw/mwgui/mode.hpp index 55f0952ce5..fa31bb1c4e 100644 --- a/apps/openmw/mwgui/mode.hpp +++ b/apps/openmw/mwgui/mode.hpp @@ -12,12 +12,12 @@ namespace MWGui GM_Console, // Console mode GM_Journal, // Journal mode - // None of the following are implemented yet + GM_Scroll, // Read scroll + GM_Book, // Read book GM_Dialogue, // NPC interaction GM_Barter, GM_Rest, - // .. more here .. // Startup character creation dialogs GM_Name, diff --git a/apps/openmw/mwgui/scrollwindow.cpp b/apps/openmw/mwgui/scrollwindow.cpp index ab4065e418..a5135722fc 100644 --- a/apps/openmw/mwgui/scrollwindow.cpp +++ b/apps/openmw/mwgui/scrollwindow.cpp @@ -1,14 +1,44 @@ #include "scrollwindow.hpp" +#include "../mwbase/environment.hpp" +#include "../mwinput/inputmanager.hpp" +#include "../mwworld/actiontake.hpp" +#include "../mwsound/soundmanager.hpp" + using namespace MWGui; -ScrollWindow::ScrollWindow(WindowManager& parWindowManager) : +ScrollWindow::ScrollWindow (WindowManager& parWindowManager) : WindowBase("openmw_scroll_layout.xml", parWindowManager) { - setVisible(false); + getWidget(mCloseButton, "CloseButton"); + mCloseButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ScrollWindow::onCloseButtonClicked); + + getWidget(mTakeButton, "TakeButton"); + mTakeButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ScrollWindow::onTakeButtonClicked); + center(); } -void ScrollWindow::open(MWWorld::Ptr scroll) +void ScrollWindow::open (MWWorld::Ptr scroll) { + MWBase::Environment::get().getSoundManager()->playSound3D (scroll, "scroll", 1.0, 1.0); + + mScroll = scroll; +} + +void ScrollWindow::onCloseButtonClicked (MyGUI::Widget* _sender) +{ + MWBase::Environment::get().getSoundManager()->playSound3D (mScroll, "scroll", 1.0, 1.0); + + MWBase::Environment::get().getInputManager()->setGuiMode (GM_Game); +} + +void ScrollWindow::onTakeButtonClicked (MyGUI::Widget* _sender) +{ + MWBase::Environment::get().getSoundManager()->playSound3D (mScroll, "Item Book Up", 1.0, 1.0, MWSound::Play_NoTrack); + + MWWorld::ActionTake take(mScroll); + take.execute(); + + MWBase::Environment::get().getInputManager()->setGuiMode (GM_Game); } diff --git a/apps/openmw/mwgui/scrollwindow.hpp b/apps/openmw/mwgui/scrollwindow.hpp index d7f5cd686c..e4968995e4 100644 --- a/apps/openmw/mwgui/scrollwindow.hpp +++ b/apps/openmw/mwgui/scrollwindow.hpp @@ -10,8 +10,18 @@ namespace MWGui class ScrollWindow : public WindowBase { public: - ScrollWindow(WindowManager& parWindowManager); - void open(MWWorld::Ptr scroll); + ScrollWindow (WindowManager& parWindowManager); + void open (MWWorld::Ptr scroll); + + protected: + void onCloseButtonClicked (MyGUI::Widget* _sender); + void onTakeButtonClicked (MyGUI::Widget* _sender); + + private: + MyGUI::Button* mCloseButton; + MyGUI::Button* mTakeButton; + + MWWorld::Ptr mScroll; }; } diff --git a/apps/openmw/mwgui/window_manager.cpp b/apps/openmw/mwgui/window_manager.cpp index 40fc9308d7..d082efe0c9 100644 --- a/apps/openmw/mwgui/window_manager.cpp +++ b/apps/openmw/mwgui/window_manager.cpp @@ -185,6 +185,8 @@ void WindowManager::updateVisible() stats->setVisible(false); console->disable(); mJournal->setVisible(false); + mScrollWindow->setVisible(false); + mBookWindow->setVisible(false); dialogueWindow->setVisible(false); // Mouse is visible whenever we're not in game mode @@ -205,6 +207,12 @@ void WindowManager::updateVisible() case GM_Console: console->enable(); break; + case GM_Scroll: + mScrollWindow->setVisible(true); + break; + case GM_Book: + mBookWindow->setVisible(true); + break; case GM_Name: case GM_Race: case GM_Class: diff --git a/apps/openmw/mwgui/window_manager.hpp b/apps/openmw/mwgui/window_manager.hpp index 13da6c7f01..b84c74441b 100644 --- a/apps/openmw/mwgui/window_manager.hpp +++ b/apps/openmw/mwgui/window_manager.hpp @@ -127,6 +127,9 @@ namespace MWGui MWGui::DialogueWindow* getDialogueWindow() {return dialogueWindow;} + MWGui::BookWindow* getBookWindow() {return mBookWindow;} + MWGui::ScrollWindow* getScrollWindow() {return mScrollWindow;} + MyGUI::Gui* getGui() const { return gui; } void wmUpdateFps(float fps, size_t triangleCount, size_t batchCount) diff --git a/apps/openmw/mwworld/actionread.cpp b/apps/openmw/mwworld/actionread.cpp new file mode 100644 index 0000000000..0d37e06f58 --- /dev/null +++ b/apps/openmw/mwworld/actionread.cpp @@ -0,0 +1,31 @@ +#include "actionread.hpp" + +#include "../mwbase/environment.hpp" +#include "../mwgui/window_manager.hpp" +#include "../mwgui/bookwindow.hpp" +#include "../mwgui/scrollwindow.hpp" + +namespace MWWorld +{ + ActionRead::ActionRead (const MWWorld::Ptr& object) : mObject (object) + { + } + + void ActionRead::execute () + { + ESMS::LiveCellRef *ref = + mObject.get(); + + if (ref->base->data.isScroll) + { + MWBase::Environment::get().getWindowManager()->setGuiMode(MWGui::GM_Scroll); + MWBase::Environment::get().getWindowManager()->getScrollWindow()->open(mObject); + } + else + { + MWBase::Environment::get().getWindowManager()->setGuiMode(MWGui::GM_Book); + MWBase::Environment::get().getWindowManager()->getBookWindow()->open(mObject); + } + } +} + diff --git a/apps/openmw/mwworld/actionread.hpp b/apps/openmw/mwworld/actionread.hpp new file mode 100644 index 0000000000..a4b495f794 --- /dev/null +++ b/apps/openmw/mwworld/actionread.hpp @@ -0,0 +1,21 @@ +#ifndef GAME_MWWORLD_ACTIONREAD_H +#define GAME_MWWORLD_ACTIONREAD_H + +#include "action.hpp" +#include "ptr.hpp" + +namespace MWWorld +{ + class ActionRead : public Action + { + Ptr mObject; // book or scroll to read + + public: + /// @param book or scroll to read + ActionRead (const Ptr& object); + + virtual void execute (); + }; +} + +#endif // ACTIONOPEN_H From 02dad448fe54cd99f3e672ba3ccfd94f35c37651 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 3 May 2012 05:38:43 +0200 Subject: [PATCH 080/325] make the wireframe mode not affect sky --- apps/openmw/mwrender/sky.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index da2e7446ab..72f88c6c52 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -113,6 +113,7 @@ void BillboardObject::init(const String& textureName, p->setSelfIllumination(1.0,1.0,1.0); p->setDiffuse(0.0,0.0,0.0,1.0); p->setAmbient(0.0,0.0,0.0); + p->setPolygonModeOverrideable(false); p->createTextureUnitState(textureName); mBBSet->setMaterialName("BillboardMaterial"+StringConverter::toString(bodyCount)); @@ -520,6 +521,7 @@ void SkyManager::create() mp->getTechnique(0)->getPass(0)->setSceneBlending(SBT_TRANSPARENT_ALPHA); mp->getTechnique(0)->getPass(0)->setVertexProgram(stars_vp->getName()); mp->getTechnique(0)->getPass(0)->setFragmentProgram(stars_fp->getName()); + mp->getTechnique(0)->getPass(0)->setPolygonModeOverrideable(false); mStarsMaterials[i] = mp; } @@ -535,6 +537,7 @@ void SkyManager::create() mAtmosphereDay = mRootNode->createChildSceneNode(); mAtmosphereDay->attachObject(atmosphere_ent); mAtmosphereMaterial = atmosphere_ent->getSubEntity(0)->getMaterial(); + mAtmosphereMaterial->getTechnique(0)->getPass(0)->setPolygonModeOverrideable(false); // Atmosphere shader HighLevelGpuProgramPtr vshader = mgr.createProgram("Atmosphere_VP", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, @@ -598,6 +601,7 @@ void SkyManager::create() SceneNode* clouds_node = mRootNode->createChildSceneNode(); clouds_node->attachObject(clouds_ent); mCloudMaterial = clouds_ent->getSubEntity(0)->getMaterial(); + mCloudMaterial->getTechnique(0)->getPass(0)->setPolygonModeOverrideable(false); clouds_ent->setCastShadows(false); // Clouds vertex shader From dc378fc6cfc5e0ad01a7cf6d8e636ed7b32f06fb Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 3 May 2012 06:07:41 +0200 Subject: [PATCH 081/325] allow talking with creatures --- apps/openmw/mwdialogue/dialoguemanager.cpp | 48 ++++++++++++++++++---- 1 file changed, 40 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwdialogue/dialoguemanager.cpp b/apps/openmw/mwdialogue/dialoguemanager.cpp index ac41244d1c..282fba3543 100644 --- a/apps/openmw/mwdialogue/dialoguemanager.cpp +++ b/apps/openmw/mwdialogue/dialoguemanager.cpp @@ -161,6 +161,8 @@ namespace MWDialogue bool DialogueManager::functionFilter(const MWWorld::Ptr& actor, const ESM::DialInfo& info,bool choice) { + bool isCreature = (actor.getTypeName() != typeid(ESM::NPC).name()); + for (std::vector::const_iterator iter (info.selects.begin()); iter != info.selects.end(); ++iter) { @@ -195,6 +197,9 @@ namespace MWDialogue case 46://Same faction { + if (isCreature) + return false; + MWMechanics::NpcStats PCstats = MWWorld::Class::get(MWBase::Environment::get().getWorld()->getPlayer().getPlayer()).getNpcStats(MWBase::Environment::get().getWorld()->getPlayer().getPlayer()); MWMechanics::NpcStats NPCstats = MWWorld::Class::get(actor).getNpcStats(actor); int sameFaction = 0; @@ -283,6 +288,8 @@ namespace MWDialogue bool DialogueManager::isMatching (const MWWorld::Ptr& actor, const ESM::DialInfo::SelectStruct& select) const { + bool isCreature = (actor.getTypeName() != typeid(ESM::NPC).name()); + char type = select.selectRule[1]; if (type!='0') @@ -380,6 +387,9 @@ namespace MWDialogue return true; case '8':// not faction + if (isCreature) + return false; + if(select.type==ESM::VT_Int) { ESMS::LiveCellRef* npc = actor.get(); @@ -394,6 +404,9 @@ namespace MWDialogue return true; case '9':// not class + if (isCreature) + return false; + if(select.type==ESM::VT_Int) { ESMS::LiveCellRef* npc = actor.get(); @@ -408,6 +421,9 @@ namespace MWDialogue return true; case 'A'://not Race + if (isCreature) + return false; + if(select.type==ESM::VT_Int) { ESMS::LiveCellRef* npc = actor.get(); @@ -464,6 +480,8 @@ namespace MWDialogue bool DialogueManager::isMatching (const MWWorld::Ptr& actor, const ESM::DialInfo& info) const { + bool isCreature = (actor.getTypeName() != typeid(ESM::NPC).name()); + // actor id if (!info.actor.empty()) if (toLower (info.actor)!=MWWorld::Class::get (actor).getId (actor)) @@ -472,6 +490,9 @@ namespace MWDialogue //NPC race if (!info.race.empty()) { + if (isCreature) + return false; + ESMS::LiveCellRef *cellRef = actor.get(); if (!cellRef) @@ -484,6 +505,9 @@ namespace MWDialogue //NPC class if (!info.clas.empty()) { + if (isCreature) + return false; + ESMS::LiveCellRef *cellRef = actor.get(); if (!cellRef) @@ -496,6 +520,9 @@ namespace MWDialogue //NPC faction if (!info.npcFaction.empty()) { + if (isCreature) + return false; + //MWWorld::Class npcClass = MWWorld::Class::get(actor); MWMechanics::NpcStats stats = MWWorld::Class::get(actor).getNpcStats(actor); std::map::iterator it = stats.mFactionRank.find(info.npcFaction); @@ -529,16 +556,18 @@ namespace MWDialogue } //check gender - ESMS::LiveCellRef* npc = actor.get(); - if(npc->base->flags&npc->base->Female) + if (!isCreature) { - if(static_cast (info.data.gender)==0) return false; + ESMS::LiveCellRef* npc = actor.get(); + if(npc->base->flags&npc->base->Female) + { + if(static_cast (info.data.gender)==0) return false; + } + else + { + if(static_cast (info.data.gender)==1) return false; + } } - else - { - if(static_cast (info.data.gender)==1) return false; - } - // check cell if (!info.cell.empty()) @@ -839,6 +868,9 @@ namespace MWDialogue std::string DialogueManager::getFaction() { + if (mActor.getTypeName() != typeid(ESM::NPC).name()) + return ""; + std::string factionID(""); MWMechanics::NpcStats stats = MWWorld::Class::get(mActor).getNpcStats(mActor); if(stats.mFactionRank.empty()) From 5028a83d1108f7ee01555d826fabe05a21bf518c Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 3 May 2012 07:03:04 +0200 Subject: [PATCH 082/325] fix stats window layout resizing --- apps/openmw/mwgui/review.cpp | 2 +- apps/openmw/mwgui/stats_window.cpp | 2 +- files/mygui/openmw_stats_window_layout.xml | 36 +++++++++++----------- 3 files changed, 20 insertions(+), 20 deletions(-) diff --git a/apps/openmw/mwgui/review.cpp b/apps/openmw/mwgui/review.cpp index 7dfe514def..81a87b07b6 100644 --- a/apps/openmw/mwgui/review.cpp +++ b/apps/openmw/mwgui/review.cpp @@ -248,7 +248,7 @@ MyGUI::TextBox* ReviewDialog::addValueItem(const std::string text, const std::st skillNameWidget = skillClientWidget->createWidget("SandText", coord1, MyGUI::Align::Default); skillNameWidget->setCaption(text); - skillValueWidget = skillClientWidget->createWidget("SandTextRight", coord2, MyGUI::Align::Default); + skillValueWidget = skillClientWidget->createWidget("SandTextRight", coord2, MyGUI::Align::Top | MyGUI::Align::Right); skillValueWidget->setCaption(value); skillValueWidget->_setWidgetState(state); diff --git a/apps/openmw/mwgui/stats_window.cpp b/apps/openmw/mwgui/stats_window.cpp index b007fc1d40..168b2efc66 100644 --- a/apps/openmw/mwgui/stats_window.cpp +++ b/apps/openmw/mwgui/stats_window.cpp @@ -256,7 +256,7 @@ MyGUI::TextBox* StatsWindow::addValueItem(const std::string& text, const std::st skillNameWidget->setUserString("ToolTipType", "Text"); skillNameWidget->setUserString("ToolTipText", tooltip); - skillValueWidget = skillClientWidget->createWidget("SandTextRight", coord2, MyGUI::Align::Default); + skillValueWidget = skillClientWidget->createWidget("SandTextRight", coord2, MyGUI::Align::Right | MyGUI::Align::Top); skillValueWidget->setUserString("ToolTipType", "Text"); skillValueWidget->setUserString("ToolTipText", tooltip); skillValueWidget->setCaption(value); diff --git a/files/mygui/openmw_stats_window_layout.xml b/files/mygui/openmw_stats_window_layout.xml index fd99f863e5..4f3f80e895 100644 --- a/files/mygui/openmw_stats_window_layout.xml +++ b/files/mygui/openmw_stats_window_layout.xml @@ -26,34 +26,34 @@ - - - + + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - + From b653f047acfbe61f0d7b4b21f8548e1ee3202c5a Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 3 May 2012 09:15:56 +0200 Subject: [PATCH 083/325] removed a file that wasn't supposed to be there --- apps/openmw/physicssystem.cpp | 225 ---------------------------------- 1 file changed, 225 deletions(-) delete mode 100644 apps/openmw/physicssystem.cpp diff --git a/apps/openmw/physicssystem.cpp b/apps/openmw/physicssystem.cpp deleted file mode 100644 index a07358f8ee..0000000000 --- a/apps/openmw/physicssystem.cpp +++ /dev/null @@ -1,225 +0,0 @@ -#include - -#include "physicssystem.hpp" -#include "../mwworld/ptr.hpp" -#include "../mwworld/world.hpp" // FIXME -#include - -#include "OgreRoot.h" -#include "OgreRenderWindow.h" -#include "OgreSceneManager.h" -#include "OgreViewport.h" -#include "OgreCamera.h" -#include "OgreTextureManager.h" - - -using namespace Ogre; -namespace MWWorld -{ - - PhysicsSystem::PhysicsSystem(OEngine::Render::OgreRenderer &_rend) : - mRender(_rend), mEngine(0), mFreeFly (true) - { - // Create physics. shapeLoader is deleted by the physic engine - NifBullet::ManualBulletShapeLoader* shapeLoader = new NifBullet::ManualBulletShapeLoader(); - mEngine = new OEngine::Physic::PhysicEngine(shapeLoader); - } - - PhysicsSystem::~PhysicsSystem() - { - delete mEngine; - - } - OEngine::Physic::PhysicEngine* PhysicsSystem::getEngine() - { - return mEngine; - } - - std::pair PhysicsSystem::getFacedHandle (MWWorld::World& world) - { - std::string handle = ""; - - //get a ray pointing to the center of the viewport - Ray centerRay = mRender.getCamera()->getCameraToViewportRay( - mRender.getViewport()->getWidth()/2, - mRender.getViewport()->getHeight()/2); - //let's avoid the capsule shape of the player. - centerRay.setOrigin(centerRay.getOrigin() + 20*centerRay.getDirection()); - btVector3 from(centerRay.getOrigin().x,-centerRay.getOrigin().z,centerRay.getOrigin().y); - btVector3 to(centerRay.getPoint(500).x,-centerRay.getPoint(500).z,centerRay.getPoint(500).y); - - return mEngine->rayTest(from,to); - } - - bool PhysicsSystem::castRay(const Vector3& from, const Vector3& to) - { - btVector3 _from, _to; - _from = btVector3(from.x, from.y, from.z); - _to = btVector3(to.x, to.y, to.z); - - std::pair result = mEngine->rayTest(_from, _to); - - return !(result.first == ""); - } - - - std::vector< std::pair > PhysicsSystem::doPhysics (float duration, - const std::vector >& actors) - { - //set the DebugRenderingMode. To disable it,set it to 0 - //eng->setDebugRenderingMode(1); - - //set the walkdirection to 0 (no movement) for every actor) - for(std::map::iterator it = mEngine->PhysicActorMap.begin(); it != mEngine->PhysicActorMap.end();it++) - { - OEngine::Physic::PhysicActor* act = it->second; - act->setWalkDirection(btVector3(0,0,0)); - } - - for (std::vector >::const_iterator iter (actors.begin()); - iter!=actors.end(); ++iter) - { - OEngine::Physic::PhysicActor* act = mEngine->getCharacter(iter->first); - - //dirty stuff to get the camera orientation. Must be changed! - - Ogre::SceneNode *sceneNode = mRender.getScene()->getSceneNode (iter->first); - Ogre::Vector3 dir; - Ogre::Node* yawNode = sceneNode->getChildIterator().getNext(); - Ogre::Node* pitchNode = yawNode->getChildIterator().getNext(); - if(mFreeFly) - { - Ogre::Quaternion yawQuat = yawNode->getOrientation(); - Ogre::Quaternion pitchQuat = pitchNode->getOrientation(); - Ogre::Vector3 dir1(iter->second.x,iter->second.z,-iter->second.y); - dir = 0.07*(yawQuat*pitchQuat*dir1); - } - else - { - Ogre::Quaternion quat = yawNode->getOrientation(); - Ogre::Vector3 dir1(iter->second.x,iter->second.z,-iter->second.y); - dir = 0.025*(quat*dir1); - } - - //set the walk direction - act->setWalkDirection(btVector3(dir.x,-dir.z,dir.y)); - } - mEngine->stepSimulation(duration); - - std::vector< std::pair > response; - for(std::map::iterator it = mEngine->PhysicActorMap.begin(); it != mEngine->PhysicActorMap.end();it++) - { - btVector3 newPos = it->second->getPosition(); - Ogre::Vector3 coord(newPos.x(), newPos.y(), newPos.z()); - - response.push_back(std::pair(it->first, coord)); - } - return response; - } - - void PhysicsSystem::addObject (const std::string& handle, const std::string& mesh, - const Ogre::Quaternion& rotation, float scale, const Ogre::Vector3& position) - { - OEngine::Physic::RigidBody* body = mEngine->createRigidBody(mesh,handle,scale); - mEngine->addRigidBody(body); - btTransform tr; - tr.setOrigin(btVector3(position.x,position.y,position.z)); - std::cout << "Position object:" << position << "\n"; - tr.setRotation(btQuaternion(rotation.x,rotation.y,rotation.z,rotation.w)); - body->setWorldTransform(tr); - } - - void PhysicsSystem::addActor (const std::string& handle, const std::string& mesh, - const Ogre::Vector3& position) - { - //TODO:optimize this. Searching the std::map isn't very efficient i think. - mEngine->addCharacter(handle); - OEngine::Physic::PhysicActor* act = mEngine->getCharacter(handle); - act->setPosition(btVector3(position.x,position.y,position.z)); - } - - void PhysicsSystem::removeObject (const std::string& handle) - { - //TODO:check if actor??? - mEngine->removeCharacter(handle); - mEngine->removeRigidBody(handle); - mEngine->deleteRigidBody(handle); - } - - void PhysicsSystem::moveObject (const std::string& handle, const Ogre::Vector3& position) - { - if (OEngine::Physic::RigidBody* body = mEngine->getRigidBody(handle)) - { - // TODO very dirty hack to avoid crash during setup -> needs cleaning up to allow - // start positions others than 0, 0, 0 - btTransform tr = body->getWorldTransform(); - tr.setOrigin(btVector3(position.x,position.y,position.z)); - body->setWorldTransform(tr); - } - if (OEngine::Physic::PhysicActor* act = mEngine->getCharacter(handle)) - { - // TODO very dirty hack to avoid crash during setup -> needs cleaning up to allow - // start positions others than 0, 0, 0 - act->setPosition(btVector3(position.x,position.y,position.z)); - } - } - - void PhysicsSystem::rotateObject (const std::string& handle, const Ogre::Quaternion& rotation) - { - if (OEngine::Physic::PhysicActor* act = mEngine->getCharacter(handle)) - { - // TODO very dirty hack to avoid crash during setup -> needs cleaning up to allow - // start positions others than 0, 0, 0 - act->setRotation(btQuaternion(rotation.x, rotation.y, rotation.z, rotation.w)); - } - } - - void PhysicsSystem::scaleObject (const std::string& handle, float scale) - { - - } - - bool PhysicsSystem::toggleCollisionMode() - { - for(std::map::iterator it = mEngine->PhysicActorMap.begin(); it != mEngine->PhysicActorMap.end();it++) - { - if (it->first=="player") - { - OEngine::Physic::PhysicActor* act = it->second; - - bool cmode = act->getCollisionMode(); - if(cmode) - { - act->enableCollisions(false); - act->setGravity(0.); - act->setVerticalVelocity(0); - mFreeFly = true; - return false; - } - else - { - mFreeFly = false; - act->enableCollisions(true); - act->setGravity(4.); - act->setVerticalVelocity(0); - return true; - } - } - } - - throw std::logic_error ("can't find player"); - } - - void PhysicsSystem::insertObjectPhysics(const MWWorld::Ptr& ptr, const std::string model){ - Ogre::SceneNode* node = ptr.getRefData().getBaseNode(); - addObject (node->getName(), model, node->getOrientation(), - node->getScale().x, node->getPosition()); - } - - void PhysicsSystem::insertActorPhysics(const MWWorld::Ptr& ptr, const std::string model){ - Ogre::SceneNode* node = ptr.getRefData().getBaseNode(); - // std::cout << "Adding node with name" << node->getName(); - addActor (node->getName(), model, node->getPosition()); - } - -} From e26f39e56394d2cd9af09b10234b9c09e94c311f Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 4 May 2012 17:20:57 +0200 Subject: [PATCH 084/325] fixed exception handling during subsystem setup --- apps/openmw/engine.cpp | 8 +------ apps/openmw/engine.hpp | 2 +- apps/openmw/mwbase/environment.cpp | 38 ++++++++++++++++++++++++++++++ apps/openmw/mwbase/environment.hpp | 5 +++- 4 files changed, 44 insertions(+), 9 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 12a5956a98..319c42bbd7 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -158,13 +158,7 @@ OMW::Engine::Engine(Files::ConfigurationManager& configurationManager) OMW::Engine::~Engine() { - delete MWBase::Environment::get().getInputManager(); - delete MWBase::Environment::get().getSoundManager(); - delete MWBase::Environment::get().getMechanicsManager(); - delete MWBase::Environment::get().getDialogueManager(); - delete MWBase::Environment::get().getJournal(); - delete MWBase::Environment::get().getScriptManager(); - delete MWBase::Environment::get().getWorld(); + mEnvironment.cleanup(); delete mScriptContext; delete mOgre; } diff --git a/apps/openmw/engine.hpp b/apps/openmw/engine.hpp index 09d6bc8201..63464a40d9 100644 --- a/apps/openmw/engine.hpp +++ b/apps/openmw/engine.hpp @@ -62,6 +62,7 @@ namespace OMW /// \brief Main engine class, that brings together all the components of OpenMW class Engine : private Ogre::FrameListener { + MWBase::Environment mEnvironment; std::string mEncoding; Files::PathContainer mDataDirs; boost::filesystem::path mResDir; @@ -77,7 +78,6 @@ namespace OMW std::string mFocusName; std::map mFallbackMap; - MWBase::Environment mEnvironment; Compiler::Extensions mExtensions; Compiler::Context *mScriptContext; diff --git a/apps/openmw/mwbase/environment.cpp b/apps/openmw/mwbase/environment.cpp index 8e9a9cfce3..792e240f4b 100644 --- a/apps/openmw/mwbase/environment.cpp +++ b/apps/openmw/mwbase/environment.cpp @@ -3,6 +3,19 @@ #include +#include "../mwinput/inputmanager.hpp" + +#include "../mwscript/scriptmanager.hpp" + +#include "../mwsound/soundmanager.hpp" + +#include "../mwworld/world.hpp" + +#include "../mwdialogue/dialoguemanager.hpp" +#include "../mwdialogue/journal.hpp" + +#include "../mwmechanics/mechanicsmanager.hpp" + MWBase::Environment *MWBase::Environment::sThis = 0; MWBase::Environment::Environment() @@ -15,6 +28,7 @@ MWBase::Environment::Environment() MWBase::Environment::~Environment() { + cleanup(); sThis = 0; } @@ -116,6 +130,30 @@ float MWBase::Environment::getFrameDuration() const return mFrameDuration; } +void MWBase::Environment::cleanup() +{ + delete mInputManager; + mInputManager = 0; + + delete mSoundManager; + mSoundManager = 0; + + delete mMechanicsManager; + mMechanicsManager = 0; + + delete mDialogueManager; + mDialogueManager = 0; + + delete mJournal; + mJournal = 0; + + delete mScriptManager; + mScriptManager = 0; + + delete mWorld; + mWorld = 0; +} + const MWBase::Environment& MWBase::Environment::get() { assert (sThis); diff --git a/apps/openmw/mwbase/environment.hpp b/apps/openmw/mwbase/environment.hpp index a010e7faa0..521beee0aa 100644 --- a/apps/openmw/mwbase/environment.hpp +++ b/apps/openmw/mwbase/environment.hpp @@ -43,7 +43,7 @@ namespace MWBase /// /// This class allows each mw-subsystem to access any others subsystem's top-level manager class. /// - /// \attention Environment does not take ownership of the manager class instances it is handed over in + /// \attention Environment takes ownership of the manager class instances it is handed over in /// the set* functions. class Environment { @@ -108,6 +108,9 @@ namespace MWBase float getFrameDuration() const; + void cleanup(); + ///< Delete all mw*-subsystems. + static const Environment& get(); ///< Return instance of this class. }; From a4d6d1bafff74e1e08aeb07792df92f312dee5a8 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 4 May 2012 18:09:45 +0200 Subject: [PATCH 085/325] added a utility for creating texture atlas at runtime --- CMakeLists.txt | 1 + apps/openmw/mwgui/cursorreplace.cpp | 3 + files/mygui/CMakeLists.txt | 1 + files/mygui/atlas1.cfg | 27 +++++++ libs/openengine/ogre/atlas.cpp | 113 ++++++++++++++++++++++++++++ libs/openengine/ogre/atlas.hpp | 27 +++++++ 6 files changed, 172 insertions(+) create mode 100644 files/mygui/atlas1.cfg create mode 100644 libs/openengine/ogre/atlas.cpp create mode 100644 libs/openengine/ogre/atlas.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index ca3fe0eeb8..668fcd83aa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -103,6 +103,7 @@ set(OENGINE_OGRE ${LIBDIR}/openengine/ogre/mouselook.cpp ${LIBDIR}/openengine/ogre/fader.cpp ${LIBDIR}/openengine/ogre/imagerotate.cpp + ${LIBDIR}/openengine/ogre/atlas.cpp ) set(OENGINE_GUI ${LIBDIR}/openengine/gui/events.cpp diff --git a/apps/openmw/mwgui/cursorreplace.cpp b/apps/openmw/mwgui/cursorreplace.cpp index 2079538fc2..e66f543266 100644 --- a/apps/openmw/mwgui/cursorreplace.cpp +++ b/apps/openmw/mwgui/cursorreplace.cpp @@ -2,6 +2,7 @@ #include #include +#include #include #include @@ -13,4 +14,6 @@ CursorReplace::CursorReplace() OEngine::Render::ImageRotate::rotate("textures\\tx_cursormove.dds", "mwpointer_vresize.png", 90); OEngine::Render::ImageRotate::rotate("textures\\tx_cursormove.dds", "mwpointer_dresize1.png", -45); OEngine::Render::ImageRotate::rotate("textures\\tx_cursormove.dds", "mwpointer_dresize2.png", 45); + + OEngine::Render::Atlas::createFromFile("atlas1.cfg", "mwgui1", "textures\\"); } diff --git a/files/mygui/CMakeLists.txt b/files/mygui/CMakeLists.txt index ef62fb68ce..2c380cd7e9 100644 --- a/files/mygui/CMakeLists.txt +++ b/files/mygui/CMakeLists.txt @@ -54,6 +54,7 @@ configure_file("${SDIR}/openmw_tooltips.xml" "${DDIR}/openmw_tooltips.xml" COPYO configure_file("${SDIR}/openmw_scroll_layout.xml" "${DDIR}/openmw_scroll_layout.xml" COPYONLY) configure_file("${SDIR}/openmw_scroll_skin.xml" "${DDIR}/openmw_scroll_skin.xml" COPYONLY) configure_file("${SDIR}/openmw_book_layout.xml" "${DDIR}/openmw_book_layout.xml" COPYONLY) +configure_file("${SDIR}/atlas1.cfg" "${DDIR}/atlas1.cfg" COPYONLY) configure_file("${SDIR}/smallbars.png" "${DDIR}/smallbars.png" COPYONLY) configure_file("${SDIR}/transparent.png" "${DDIR}/transparent.png" COPYONLY) configure_file("${SDIR}/EBGaramond-Regular.ttf" "${DDIR}/EBGaramond-Regular.ttf" COPYONLY) diff --git a/files/mygui/atlas1.cfg b/files/mygui/atlas1.cfg new file mode 100644 index 0000000000..2a9716b771 --- /dev/null +++ b/files/mygui/atlas1.cfg @@ -0,0 +1,27 @@ +[settings] + size_x = 512 + size_y = 512 + +[tx_menubook_close_idle.dds] + x = 0 + y = 0 + +[tx_menubook_close_over.dds] + x = 128 + y = 0 + +[tx_menubook_close_pressed.dds] + x = 256 + y = 0 + +[tx_menubook_take_idle.dds] + x = 384 + y = 0 + +[tx_menubook_take_over.dds] + x = 0 + y = 32 + +[tx_menubook_take_pressed.dds] + x = 128 + y = 32 diff --git a/libs/openengine/ogre/atlas.cpp b/libs/openengine/ogre/atlas.cpp new file mode 100644 index 0000000000..01b84afabc --- /dev/null +++ b/libs/openengine/ogre/atlas.cpp @@ -0,0 +1,113 @@ +#include "atlas.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace Ogre; +using namespace OEngine::Render; + +void Atlas::createFromFile (const std::string& filename, const std::string& textureName, const std::string& texturePrefix) +{ + ConfigFile file; + file.load(filename, ResourceGroupManager::AUTODETECT_RESOURCE_GROUP_NAME, "\t:=", true); + + Root* root = Ogre::Root::getSingletonPtr(); + + SceneManager* sceneMgr = root->createSceneManager(ST_GENERIC); + Camera* camera = sceneMgr->createCamera("AtlasCamera"); + + int width = StringConverter::parseInt(file.getSetting("size_x", "settings")); + int height = StringConverter::parseInt(file.getSetting("size_y", "settings")); + + std::vector rectangles; + int i = 0; + + ConfigFile::SectionIterator seci = file.getSectionIterator(); + while (seci.hasMoreElements()) + { + Ogre::String sectionName = seci.peekNextKey(); + seci.getNext(); + + if (sectionName == "settings" || sectionName == "") + continue; + + MaterialPtr material = MaterialManager::getSingleton().create("AtlasMaterial" + StringConverter::toString(i), ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); + material->getTechnique(0)->getPass(0)->setLightingEnabled(false); + material->getTechnique(0)->getPass(0)->setDepthCheckEnabled(false); + TextureUnitState* tus = material->getTechnique(0)->getPass(0)->createTextureUnitState(texturePrefix + sectionName); + tus->setTextureBorderColour(ColourValue(0, 0, 0, 0)); + + Rectangle2D* rect = new Rectangle2D(true); + rect->setMaterial("AtlasMaterial" + StringConverter::toString(i)); + rect->setRenderQueueGroup(RENDER_QUEUE_BACKGROUND); + + int x = StringConverter::parseInt(file.getSetting("x", sectionName)); + int y = StringConverter::parseInt(file.getSetting("y", sectionName)); + + TexturePtr texture = TextureManager::getSingleton().getByName(texturePrefix + sectionName); + if (texture.isNull()) + { + std::cerr << "OEngine::Render::Atlas: Can't find texture " << texturePrefix + sectionName << ", skipping..." << std::endl; + continue; + } + int textureWidth = texture->getWidth(); + int textureHeight = texture->getHeight(); + + float left = x/float(width) * 2 - 1; + float top = (1-(y/float(height))) * 2 - 1; + float right = ((x+textureWidth))/float(width) * 2 - 1; + float bottom = (1-((y+textureHeight)/float(height))) * 2 - 1; + rect->setCorners(left, top, right, bottom); + + // Use infinite AAB to always stay visible + AxisAlignedBox aabInf; + aabInf.setInfinite(); + rect->setBoundingBox(aabInf); + + // Attach background to the scene + SceneNode* node = sceneMgr->getRootSceneNode()->createChildSceneNode(); + node->attachObject(rect); + + rectangles.push_back(rect); + ++i; + } + + TexturePtr destTexture = TextureManager::getSingleton().createManual( + textureName, + ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, + TEX_TYPE_2D, + width, height, + 0, + PF_FLOAT16_RGBA, + TU_RENDERTARGET); + + RenderTarget* rtt = destTexture->getBuffer()->getRenderTarget(); + rtt->setAutoUpdated(false); + Viewport* vp = rtt->addViewport(camera); + vp->setOverlaysEnabled(false); + vp->setShadowsEnabled(false); + vp->setBackgroundColour(ColourValue(0,0,0,0)); + + rtt->update(); + + // remove all the junk we've created + for (std::vector::iterator it=rectangles.begin(); + it!=rectangles.end(); ++it) + { + delete (*it); + } + while (i > 0) + { + MaterialManager::getSingleton().remove("AtlasMaterial" + StringConverter::toString(i-1)); + --i; + } + root->destroySceneManager(sceneMgr); +} diff --git a/libs/openengine/ogre/atlas.hpp b/libs/openengine/ogre/atlas.hpp new file mode 100644 index 0000000000..5dcd409ca5 --- /dev/null +++ b/libs/openengine/ogre/atlas.hpp @@ -0,0 +1,27 @@ +#ifndef OENGINE_OGRE_ATLAS_HPP +#define OENGINE_OGRE_ATLAS_HPP + +#include + +namespace OEngine +{ +namespace Render +{ + + /// \brief Creates a texture atlas at runtime + class Atlas + { + public: + /** + * @param absolute path to file that specifies layout of the texture (positions of the textures it contains) + * @param name of the destination texture to save to (in memory) + * @param texture directory prefix + */ + static void createFromFile (const std::string& filename, const std::string& textureName, const std::string& texturePrefix="textures\\"); + }; + +} +} + +#endif + From c125fba9d2d36e074d4a2a64963b258188e163d7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 4 May 2012 18:44:46 +0200 Subject: [PATCH 086/325] button mouse-over image change working --- files/mygui/CMakeLists.txt | 2 +- files/mygui/core.xml | 2 +- files/mygui/openmw_book_layout.xml | 8 ++- files/mygui/openmw_images.xml | 39 ------------- files/mygui/openmw_resources.xml | 86 ++++++++++++++++++++++++++++ files/mygui/openmw_scroll_layout.xml | 9 ++- 6 files changed, 101 insertions(+), 45 deletions(-) delete mode 100644 files/mygui/openmw_images.xml create mode 100644 files/mygui/openmw_resources.xml diff --git a/files/mygui/CMakeLists.txt b/files/mygui/CMakeLists.txt index 2c380cd7e9..f712ea67d3 100644 --- a/files/mygui/CMakeLists.txt +++ b/files/mygui/CMakeLists.txt @@ -9,7 +9,7 @@ configure_file("${SDIR}/black.png" "${DDIR}/black.png" COPYONLY) configure_file("${SDIR}/core.skin" "${DDIR}/core.skin" COPYONLY) configure_file("${SDIR}/core.xml" "${DDIR}/core.xml" COPYONLY) configure_file("${SDIR}/mwgui.png" "${DDIR}/mwgui.png" COPYONLY) -configure_file("${SDIR}/openmw_images.xml" "${DDIR}/openmw_images.xml" COPYONLY) +configure_file("${SDIR}/openmw_resources.xml" "${DDIR}/openmw_resources.xml" COPYONLY) configure_file("${SDIR}/openmw_settings.xml" "${DDIR}/openmw_settings.xml" COPYONLY) configure_file("${SDIR}/openmw_box.skin.xml" "${DDIR}/openmw_box.skin.xml" COPYONLY) configure_file("${SDIR}/openmw_button.skin.xml" "${DDIR}/openmw_button.skin.xml" COPYONLY) diff --git a/files/mygui/core.xml b/files/mygui/core.xml index c0a29d1f6e..e1fb1b5e21 100644 --- a/files/mygui/core.xml +++ b/files/mygui/core.xml @@ -2,7 +2,7 @@ - + diff --git a/files/mygui/openmw_book_layout.xml b/files/mygui/openmw_book_layout.xml index ccf494860b..f43c38b5ef 100644 --- a/files/mygui/openmw_book_layout.xml +++ b/files/mygui/openmw_book_layout.xml @@ -9,8 +9,12 @@ - - + + + + + + diff --git a/files/mygui/openmw_images.xml b/files/mygui/openmw_images.xml deleted file mode 100644 index e149273e29..0000000000 --- a/files/mygui/openmw_images.xml +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/files/mygui/openmw_resources.xml b/files/mygui/openmw_resources.xml new file mode 100644 index 0000000000..3dfc82cd19 --- /dev/null +++ b/files/mygui/openmw_resources.xml @@ -0,0 +1,86 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/mygui/openmw_scroll_layout.xml b/files/mygui/openmw_scroll_layout.xml index b396931edd..8e2b1765f2 100644 --- a/files/mygui/openmw_scroll_layout.xml +++ b/files/mygui/openmw_scroll_layout.xml @@ -7,9 +7,14 @@ - + + + + + + + - From a3d99767f7e971f7c732d5da9ee0e27f8e56481e Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 4 May 2012 19:11:32 +0200 Subject: [PATCH 087/325] next & prev button mouseover --- files/mygui/atlas1.cfg | 24 ++++++++++++++++ files/mygui/openmw_book_layout.xml | 12 +++++--- files/mygui/openmw_journal_layout.xml | 9 ++++-- files/mygui/openmw_journal_skin.xml | 12 -------- files/mygui/openmw_resources.xml | 40 +++++++++++++++++++++++++-- files/mygui/openmw_scroll_layout.xml | 4 +-- files/mygui/openmw_scroll_skin.xml | 10 ------- 7 files changed, 77 insertions(+), 34 deletions(-) diff --git a/files/mygui/atlas1.cfg b/files/mygui/atlas1.cfg index 2a9716b771..d1e05e0412 100644 --- a/files/mygui/atlas1.cfg +++ b/files/mygui/atlas1.cfg @@ -25,3 +25,27 @@ [tx_menubook_take_pressed.dds] x = 128 y = 32 + +[tx_menubook_next_idle.dds] + x = 256 + y = 32 + +[tx_menubook_next_over.dds] + x = 384 + y = 32 + +[tx_menubook_next_pressed.dds] + x = 0 + y = 64 + +[tx_menubook_prev_idle.dds] + x = 128 + y = 64 + +[tx_menubook_prev_over.dds] + x = 256 + y = 64 + +[tx_menubook_prev_pressed.dds] + x = 384 + y = 64 diff --git a/files/mygui/openmw_book_layout.xml b/files/mygui/openmw_book_layout.xml index f43c38b5ef..36f93a067a 100644 --- a/files/mygui/openmw_book_layout.xml +++ b/files/mygui/openmw_book_layout.xml @@ -7,12 +7,16 @@ - - - + + + + + + + - + diff --git a/files/mygui/openmw_journal_layout.xml b/files/mygui/openmw_journal_layout.xml index 5711053aca..906e872976 100644 --- a/files/mygui/openmw_journal_layout.xml +++ b/files/mygui/openmw_journal_layout.xml @@ -7,9 +7,12 @@ - - - + + + + + + diff --git a/files/mygui/openmw_journal_skin.xml b/files/mygui/openmw_journal_skin.xml index a983ac523b..9f82e907ff 100644 --- a/files/mygui/openmw_journal_skin.xml +++ b/files/mygui/openmw_journal_skin.xml @@ -1,18 +1,6 @@ - - - - - - - - - - - - diff --git a/files/mygui/openmw_resources.xml b/files/mygui/openmw_resources.xml index 3dfc82cd19..455765aadf 100644 --- a/files/mygui/openmw_resources.xml +++ b/files/mygui/openmw_resources.xml @@ -38,7 +38,7 @@ - + @@ -55,7 +55,7 @@ - + @@ -71,9 +71,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + diff --git a/files/mygui/openmw_scroll_layout.xml b/files/mygui/openmw_scroll_layout.xml index 8e2b1765f2..4c9ab10e20 100644 --- a/files/mygui/openmw_scroll_layout.xml +++ b/files/mygui/openmw_scroll_layout.xml @@ -7,11 +7,11 @@ - + - + diff --git a/files/mygui/openmw_scroll_skin.xml b/files/mygui/openmw_scroll_skin.xml index e55396ac44..20b952d582 100644 --- a/files/mygui/openmw_scroll_skin.xml +++ b/files/mygui/openmw_scroll_skin.xml @@ -1,15 +1,5 @@ - - - - - - - - - - From 499dd263988ca7ae96142253bf863c8dde5f6d15 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 4 May 2012 23:53:50 +0200 Subject: [PATCH 088/325] dialogue window topic list word-wrapping --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwgui/dialogue.cpp | 19 ++- apps/openmw/mwgui/dialogue.hpp | 9 +- apps/openmw/mwgui/list.cpp | 116 ++++++++++++++++++ apps/openmw/mwgui/list.hpp | 54 ++++++++ apps/openmw/mwgui/window_manager.cpp | 15 +-- files/mygui/openmw_dialogue_window_layout.xml | 2 +- files/mygui/openmw_list.skin.xml | 14 +++ files/mygui/openmw_scroll_layout.xml | 13 ++ files/mygui/openmw_scroll_skin.xml | 6 + 10 files changed, 228 insertions(+), 22 deletions(-) create mode 100644 apps/openmw/mwgui/list.cpp create mode 100644 apps/openmw/mwgui/list.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index b112c3f38c..29bc86fe34 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -25,7 +25,7 @@ add_openmw_dir (mwinput add_openmw_dir (mwgui layouts text_input widgets race class birth review window_manager console dialogue dialogue_history window_base stats_window messagebox journalwindow charactercreation - map_window window_pinnable_base cursorreplace tooltips scrollwindow bookwindow + map_window window_pinnable_base cursorreplace tooltips scrollwindow bookwindow list ) add_openmw_dir (mwdialogue diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 0238446ebe..3d47aa7dc3 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -2,6 +2,7 @@ #include "dialogue_history.hpp" #include "window_manager.hpp" #include "widgets.hpp" +#include "list.hpp" #include "components/esm_store/store.hpp" #include "../mwbase/environment.hpp" #include "../mwdialogue/dialoguemanager.hpp" @@ -56,9 +57,8 @@ DialogueWindow::DialogueWindow(WindowManager& parWindowManager) //Topics list getWidget(topicsList, "TopicsList"); - topicsList->setScrollVisible(true); //topicsList->eventListSelectAccept += MyGUI::newDelegate(this, &DialogueWindow::onSelectTopic); - topicsList->eventListMouseItemActivate += MyGUI::newDelegate(this, &DialogueWindow::onSelectTopic); + topicsList->eventItemSelected += MyGUI::newDelegate(this, &DialogueWindow::onSelectTopic); //topicsList->eventListChangePosition += MyGUI::newDelegate(this, &DialogueWindow::onSelectTopic); MyGUI::ButtonPtr byeButton; @@ -98,7 +98,7 @@ void DialogueWindow::onMouseWheel(MyGUI::Widget* _sender, int _rel) void DialogueWindow::open() { - topicsList->removeAllItems(); + topicsList->clear(); pTopicsText.clear(); history->eraseText(0,history->getTextLength()); updateOptions(); @@ -110,11 +110,8 @@ void DialogueWindow::onByeClicked(MyGUI::Widget* _sender) MWBase::Environment::get().getDialogueManager()->goodbyeSelected(); } -void DialogueWindow::onSelectTopic(MyGUI::ListBox* _sender, size_t _index) +void DialogueWindow::onSelectTopic(std::string topic) { - if (_index == MyGUI::ITEM_NONE) - return; - std::string topic = _sender->getItemNameAt(_index); MWBase::Environment::get().getDialogueManager()->keywordSelected(lower_string(topic)); } @@ -126,7 +123,7 @@ void DialogueWindow::startDialogue(std::string npcName) void DialogueWindow::setKeywords(std::list keyWords) { - topicsList->removeAllItems(); + topicsList->clear(); for(std::list::iterator it = keyWords.begin(); it != keyWords.end(); it++) { topicsList->addItem(*it); @@ -135,9 +132,9 @@ void DialogueWindow::setKeywords(std::list keyWords) void DialogueWindow::removeKeyword(std::string keyWord) { - if(topicsList->findItemIndexWith(keyWord) != MyGUI::ITEM_NONE) + if(topicsList->hasItem(keyWord)) { - topicsList->removeItemAt(topicsList->findItemIndexWith(keyWord)); + topicsList->removeItem(keyWord); pTopicsText.erase(keyWord); } } @@ -211,7 +208,7 @@ void DialogueWindow::askQuestion(std::string question) void DialogueWindow::updateOptions() { //Clear the list of topics - topicsList->removeAllItems(); + topicsList->clear(); pTopicsText.clear(); history->eraseText(0,history->getTextLength()); diff --git a/apps/openmw/mwgui/dialogue.hpp b/apps/openmw/mwgui/dialogue.hpp index 5921ca57a2..ac29e9ec8d 100644 --- a/apps/openmw/mwgui/dialogue.hpp +++ b/apps/openmw/mwgui/dialogue.hpp @@ -7,6 +7,11 @@ namespace MWGui { class WindowManager; + + namespace Widgets + { + class MWList; + } } /* @@ -42,7 +47,7 @@ namespace MWGui void askQuestion(std::string question); protected: - void onSelectTopic(MyGUI::ListBox* _sender, size_t _index); + void onSelectTopic(std::string topic); void onByeClicked(MyGUI::Widget* _sender); void onHistoryClicked(MyGUI::Widget* _sender); void onMouseWheel(MyGUI::Widget* _sender, int _rel); @@ -55,7 +60,7 @@ namespace MWGui std::string parseText(std::string text); DialogueHistory* history; - MyGUI::ListBox* topicsList; + Widgets::MWList* topicsList; MyGUI::ProgressPtr pDispositionBar; MyGUI::EditPtr pDispositionText; std::map pTopicsText;// this map links keyword and "real" text. diff --git a/apps/openmw/mwgui/list.cpp b/apps/openmw/mwgui/list.cpp new file mode 100644 index 0000000000..733654b8c5 --- /dev/null +++ b/apps/openmw/mwgui/list.cpp @@ -0,0 +1,116 @@ +#include "list.hpp" + +#include + +using namespace MWGui; +using namespace MWGui::Widgets; + +MWList::MWList() : + mClient(0) + , mScrollView(0) + , mItemHeight(0) +{ +} + +void MWList::initialiseOverride() +{ + Base::initialiseOverride(); + + assignWidget(mClient, "Client"); + if (mClient == 0) + mClient = this; + + mScrollView = mClient->createWidgetReal( + "MW_ScrollView", MyGUI::FloatCoord(0.0, 0.0, 1.0, 1.0), + MyGUI::Align::Top | MyGUI::Align::Left | MyGUI::Align::Stretch, getName() + "_ScrollView"); +} + +void MWList::addItem(const std::string& name) +{ + mItems.push_back(name); + + redraw(); +} + +void MWList::redraw(bool scrollbarShown) +{ + const int _scrollBarWidth = 24; // fetch this from skin? + const int scrollBarWidth = scrollbarShown ? _scrollBarWidth : 0; + const int spacing = 3; + + while (mScrollView->getChildCount()) + { + MyGUI::Gui::getInstance().destroyWidget(mScrollView->getChildAt(0)); + } + + mItemHeight = 0; + for (std::vector::const_iterator it=mItems.begin(); + it!=mItems.end(); ++it) + { + MyGUI::Button* button = mScrollView->createWidget( + "MW_ListLine", MyGUI::IntCoord(0, mItemHeight, mScrollView->getSize().width - scrollBarWidth - 2, 24), + MyGUI::Align::Left | MyGUI::Align::Top, getName() + "_item_" + (*it)); + button->setCaption((*it)); + button->getSubWidgetText()->setWordWrap(true); + button->getSubWidgetText()->setTextAlign(MyGUI::Align::Left); + button->eventMouseWheel += MyGUI::newDelegate(this, &MWList::onMouseWheel); + button->eventMouseButtonClick += MyGUI::newDelegate(this, &MWList::onItemSelected); + + int height = button->getTextSize().height; + button->setSize(MyGUI::IntSize(button->getSize().width, height)); + + mItemHeight += height + spacing; + } + mScrollView->setCanvasSize(mClient->getSize().width + (_scrollBarWidth-scrollBarWidth), std::max(mItemHeight, mClient->getSize().height)); + mScrollView->setViewOffset(MyGUI::IntPoint(0,0)); + + if (!scrollbarShown && mItemHeight > mClient->getSize().height) + redraw(true); +} + +bool MWList::hasItem(const std::string& name) +{ + return (std::find(mItems.begin(), mItems.end(), name) != mItems.end()); +} + +unsigned int MWList::getItemCount() +{ + return mItems.size(); +} + +std::string MWList::getItemNameAt(unsigned int at) +{ + assert(at < mItems.size() && "List item out of bounds"); + return mItems[at]; +} + +void MWList::removeItem(const std::string& name) +{ + assert( std::find(mItems.begin(), mItems.end(), name) != mItems.end() ); + mItems.erase( std::find(mItems.begin(), mItems.end(), name) ); + + redraw(); +} + +void MWList::clear() +{ + mItems.clear(); + + redraw(); +} + +void MWList::onMouseWheel(MyGUI::Widget* _sender, int _rel) +{ + //NB view offset is negative + if (mScrollView->getViewOffset().top + _rel*0.3 > 0) + mScrollView->setViewOffset(MyGUI::IntPoint(0, 0)); + else + mScrollView->setViewOffset(MyGUI::IntPoint(0, mScrollView->getViewOffset().top + _rel*0.3)); +} + +void MWList::onItemSelected(MyGUI::Widget* _sender) +{ + std::string name = static_cast(_sender)->getCaption(); + + eventItemSelected(name); +} diff --git a/apps/openmw/mwgui/list.hpp b/apps/openmw/mwgui/list.hpp new file mode 100644 index 0000000000..eedcae066f --- /dev/null +++ b/apps/openmw/mwgui/list.hpp @@ -0,0 +1,54 @@ +#ifndef MWGUI_LIST_HPP +#define MWGUI_LIST_HPP + +#include + +namespace MWGui +{ + namespace Widgets + { + /** + * \brief a very simple list widget that supports word-wrapping entries + * \note does not handle changing the width of the list at runtime + */ + class MWList : public MyGUI::Widget + { + MYGUI_RTTI_DERIVED(MWList) + public: + MWList(); + + typedef MyGUI::delegates::CMultiDelegate1 EventHandle_String; + + /** + * Event: Item selected with the mouse. + * signature: void method(std::string itemName) + */ + EventHandle_String eventItemSelected; + + void addItem(const std::string& name); + void removeItem(const std::string& name); + bool hasItem(const std::string& name); + unsigned int getItemCount(); + std::string getItemNameAt(unsigned int at); + void clear(); + + protected: + void initialiseOverride(); + + void redraw(bool scrollbarShown = false); + + void onMouseWheel(MyGUI::Widget* _sender, int _rel); + void onItemSelected(MyGUI::Widget* _sender); + + private: + MyGUI::ScrollView* mScrollView; + MyGUI::Widget* mClient; + + std::vector mItems; + + int mItemHeight; // height of all items + }; + } +} + +#endif diff --git a/apps/openmw/mwgui/window_manager.cpp b/apps/openmw/mwgui/window_manager.cpp index d082efe0c9..dfac55beb9 100644 --- a/apps/openmw/mwgui/window_manager.cpp +++ b/apps/openmw/mwgui/window_manager.cpp @@ -10,6 +10,7 @@ #include "tooltips.hpp" #include "scrollwindow.hpp" #include "bookwindow.hpp" +#include "list.hpp" #include "../mwmechanics/mechanicsmanager.hpp" #include "../mwinput/inputmanager.hpp" @@ -73,6 +74,13 @@ WindowManager::WindowManager( //Register own widgets with MyGUI MyGUI::FactoryManager::getInstance().registerFactory("Widget"); + MyGUI::FactoryManager::getInstance().registerFactory("Widget"); + MyGUI::FactoryManager::getInstance().registerFactory("Widget"); + MyGUI::FactoryManager::getInstance().registerFactory("Widget"); + MyGUI::FactoryManager::getInstance().registerFactory("Widget"); + MyGUI::FactoryManager::getInstance().registerFactory("Widget"); + MyGUI::FactoryManager::getInstance().registerFactory("Widget"); + MyGUI::FactoryManager::getInstance().registerFactory("Widget"); // Get size info from the Gui object assert(gui); @@ -107,13 +115,6 @@ WindowManager::WindowManager( playerSkillValues.insert(std::make_pair(ESM::Skill::skillIds[i], MWMechanics::Stat())); } - MyGUI::FactoryManager::getInstance().registerFactory("Widget"); - MyGUI::FactoryManager::getInstance().registerFactory("Widget"); - MyGUI::FactoryManager::getInstance().registerFactory("Widget"); - MyGUI::FactoryManager::getInstance().registerFactory("Widget"); - MyGUI::FactoryManager::getInstance().registerFactory("Widget"); - MyGUI::FactoryManager::getInstance().registerFactory("Widget"); - // Set up visibility updateVisible(); } diff --git a/files/mygui/openmw_dialogue_window_layout.xml b/files/mygui/openmw_dialogue_window_layout.xml index b0e437074c..d45de4bd44 100644 --- a/files/mygui/openmw_dialogue_window_layout.xml +++ b/files/mygui/openmw_dialogue_window_layout.xml @@ -19,7 +19,7 @@ - + diff --git a/files/mygui/openmw_list.skin.xml b/files/mygui/openmw_list.skin.xml index 02075ad1a6..89cc73123c 100644 --- a/files/mygui/openmw_list.skin.xml +++ b/files/mygui/openmw_list.skin.xml @@ -212,6 +212,20 @@ + + + + + + + + + + + + + + diff --git a/files/mygui/openmw_scroll_layout.xml b/files/mygui/openmw_scroll_layout.xml index 4c9ab10e20..8641a0511e 100644 --- a/files/mygui/openmw_scroll_layout.xml +++ b/files/mygui/openmw_scroll_layout.xml @@ -15,6 +15,19 @@ + + + + + + + + + + + + + diff --git a/files/mygui/openmw_scroll_skin.xml b/files/mygui/openmw_scroll_skin.xml index 20b952d582..39437d54e7 100644 --- a/files/mygui/openmw_scroll_skin.xml +++ b/files/mygui/openmw_scroll_skin.xml @@ -2,4 +2,10 @@ + + + + + + From f20d4eeb414e9b3fdb73115f487996718ca1db63 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 5 May 2012 01:44:51 +0200 Subject: [PATCH 089/325] Bug #281 , openmw.font.xml update --- files/mygui/openmw.font.xml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/files/mygui/openmw.font.xml b/files/mygui/openmw.font.xml index e7d0f50c8a..25c44d5ed9 100644 --- a/files/mygui/openmw.font.xml +++ b/files/mygui/openmw.font.xml @@ -6,13 +6,13 @@ - + @@ -25,7 +25,6 @@ - @@ -37,4 +36,4 @@ - \ No newline at end of file + From 60ad6f01d40af09443868ed9019173db460ea850 Mon Sep 17 00:00:00 2001 From: gugus Date: Sun, 6 May 2012 11:04:07 +0200 Subject: [PATCH 090/325] another step towards drand and drop. --- apps/openmw/mwgui/container.cpp | 104 ++++++++++++++++++++++---------- apps/openmw/mwgui/container.hpp | 8 +++ 2 files changed, 81 insertions(+), 31 deletions(-) diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index d5eb8cff7d..083ce2f646 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -22,12 +22,29 @@ using namespace MWGui; using namespace Widgets; +class ItemWidget: public MyGUI::ImageBox +{ +public: + ItemWidget() + :ImageBox() + { + } + virtual ~ItemWidget() + { + } + + void setPtr(MWWorld::Ptr &ptr,int pos){mPtr = ptr;mPos = pos;} + + MWWorld::Ptr mPtr; + int mPos; +}; ContainerWindow::ContainerWindow(WindowManager& parWindowManager,MWWorld::Environment& environment,DragAndDrop* dragAndDrop) : WindowBase("openmw_container_window_layout.xml", parWindowManager), mEnvironment(environment), - mDragAndDrop(dragAndDrop) + mDragAndDrop(dragAndDrop), + mContainer() { setText("_Main", "Name of Container"); @@ -52,7 +69,8 @@ ContainerWindow::ContainerWindow(WindowManager& parWindowManager,MWWorld::Enviro ContainerWindow::ContainerWindow(WindowManager& parWindowManager,MWWorld::Environment& environment,DragAndDrop* dragAndDrop,std::string guiFile) : WindowBase(guiFile, parWindowManager), mEnvironment(environment), - mDragAndDrop(dragAndDrop) + mDragAndDrop(dragAndDrop), + mContainer() { setText("_Main", "Name of Container"); //center(); @@ -81,11 +99,18 @@ void ContainerWindow::setName(std::string contName) void ContainerWindow::open(MWWorld::Ptr& container) { + mContainer = container; setName(MWWorld::Class::get(container).getName(container)); //MWWorld::ContainerStore* containerStore = container.getContainerStore(); + drawItems(); + setVisible(true); +} - MWWorld::ContainerStore& containerStore = MWWorld::Class::get(container).getContainerStore(container); - +void ContainerWindow::drawItems() +{ + MyGUI::Gui::getInstance().destroyWidgets(mContainerWidget->getEnumerator()); + MWWorld::ContainerStore& containerStore = MWWorld::Class::get(mContainer).getContainerStore(mContainer); + //mContainerWidget-> /*MWWorld::ManualRef furRef (mWindowManager.getStore(), "fur_cuirass"); furRef.getPtr().getRefData().setCount (5); @@ -121,45 +146,45 @@ void ContainerWindow::open(MWWorld::Ptr& container) // ESMS::LiveCellRef *ref = iter->get(); - int x = 4; int y = 4; int count = 0; + for (MWWorld::ContainerStoreIterator iter (containerStore.begin()); iter!=containerStore.end(); ++iter) { - std::string path = std::string("icons\\"); - path+=MWWorld::Class::get(*iter).getInventoryIcon(*iter); count++; - - MyGUI::ImageBox* image = mContainerWidget->createWidget("ImageBox", MyGUI::IntCoord(x, y, 32, 32), MyGUI::Align::Default); - MyGUI::TextBox* text = image->createWidget("SandBrightText", MyGUI::IntCoord(x, y, 18, 18), MyGUI::Align::Default, std::string("Label")); - image->eventMouseButtonClick += MyGUI::newDelegate(this,&ContainerWindow::onSelectedItem); - //image->eventMouseMove += MyGUI::newDelegate(this,&ContainerWindow::onMouseMove); - x += 36; - if(count % 20 == 0) + if(iter->getRefData().getCount() > 0) { + std::string path = std::string("icons\\"); + path+=MWWorld::Class::get(*iter).getInventoryIcon(*iter); + ItemWidget* image = mContainerWidget->createWidget("ImageBox", MyGUI::IntCoord(x, y, 32, 32), MyGUI::Align::Default); + MyGUI::TextBox* text = image->createWidget("SandBrightText", MyGUI::IntCoord(x, y, 18, 18), MyGUI::Align::Default, std::string("Label")); + image->eventMouseButtonClick += MyGUI::newDelegate(this,&ContainerWindow::onSelectedItem); + //image->setPtr(*iter,count); + image->mPos = count; + + //image->mPtr = *iter; + //image->eventMouseMove += MyGUI::newDelegate(this,&ContainerWindow::onMouseMove); + /*x += 36; + if(count % 20 == 0) + { y += 36; x = 4; count = 0; + }*/ + + if(iter->getRefData().getCount() > 1) + text->setCaption(boost::lexical_cast(iter->getRefData().getCount())); + //mContainerWidgets + + int pos = path.rfind("."); + path.erase(pos); + path.append(".dds"); + //std::cout << path << std::endl; + image->setImageTexture(path); } - - if(iter->getRefData().getCount() > 1) - text->setCaption(boost::lexical_cast(iter->getRefData().getCount())); - - //mContainerWidgets - - int pos = path.rfind("."); - path.erase(pos); - path.append(".dds"); - //std::cout << path << std::endl; - image->setImageTexture(path); - } - - - - - setVisible(true); + } } void ContainerWindow::Update() @@ -188,10 +213,26 @@ void ContainerWindow::onSelectedItem(MyGUI::Widget* _sender) mDragAndDrop->mIsOnDragAndDrop = true; _sender->detachFromWidget(); _sender->attachToWidget(mDragAndDrop->mDragAndDropWidget); + + ItemWidget* item = static_cast(_sender); + + int count = 0; + MWWorld::ContainerStore& containerStore = MWWorld::Class::get(mContainer).getContainerStore(mContainer); + for (MWWorld::ContainerStoreIterator iter (containerStore.begin()); iter!=containerStore.end(); ++iter) + { + count++; + if(count == item->mPos) + { + iter->getRefData().setCount(0); + break; + } + } + //containerStore. //std::cout << mContainerWidget->getParent()->getParent()->getName(); _sender->setUserString("drag","on"); mDragAndDrop->mDraggedWidget = _sender; mDragAndDrop->mContainerWindow = const_cast(this); + drawItems(); std::cout << "selected!"; } } @@ -210,6 +251,7 @@ void ContainerWindow::onContainerClicked(MyGUI::Widget* _sender) std::cout << "container clicked"; if(mDragAndDrop->mIsOnDragAndDrop) //drop widget here { + //mContainer.getContainerStore()->add(mDragAndDrop->mDraggedWidget-> mDragAndDrop->mIsOnDragAndDrop = false; mDragAndDrop->mDraggedWidget->detachFromWidget(); mDragAndDrop->mDraggedWidget->attachToWidget(mContainerWidget); diff --git a/apps/openmw/mwgui/container.hpp b/apps/openmw/mwgui/container.hpp index 742bb06f04..b8f76a355c 100644 --- a/apps/openmw/mwgui/container.hpp +++ b/apps/openmw/mwgui/container.hpp @@ -10,6 +10,7 @@ #include "window_base.hpp" #include "../mwworld/ptr.hpp" #include "../mwworld/containerstore.hpp" +#include namespace MWWorld { @@ -38,6 +39,8 @@ namespace MWGui ContainerWindow* mContainerWindow; MyGUI::Widget* mDraggedWidget; MyGUI::Widget* mDragAndDropWidget; + + MWWorld::Ptr mItem; }; class ContainerWindow : public WindowBase @@ -63,6 +66,11 @@ namespace MWGui MyGUI::ButtonPtr closeButton; DragAndDrop* mDragAndDrop; + MWWorld::Ptr mContainer; + bool mIsValid;//is in the right GUI Mode + + void drawItems(); + void onByeClicked(MyGUI::Widget* _sender); void onSelectedItem(MyGUI::Widget* _sender); void onContainerClicked(MyGUI::Widget* _sender); From 9dd53b32b80ec78e8af5e2ab0c66f85cbaf7769e Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 7 May 2012 02:00:31 +0200 Subject: [PATCH 091/325] added daedric font for magic scrolls --- Daedric Font License.txt | 10 ++++++++++ files/mygui/CMakeLists.txt | 2 ++ files/mygui/Oblivion Worn.ttf | Bin 0 -> 158008 bytes files/mygui/Oblivion.ttf | Bin 0 -> 55364 bytes files/mygui/openmw.font.xml | 13 +++++++++++++ 5 files changed, 25 insertions(+) create mode 100644 Daedric Font License.txt create mode 100644 files/mygui/Oblivion Worn.ttf create mode 100644 files/mygui/Oblivion.ttf diff --git a/Daedric Font License.txt b/Daedric Font License.txt new file mode 100644 index 0000000000..a1553d0b04 --- /dev/null +++ b/Daedric Font License.txt @@ -0,0 +1,10 @@ +Dongle's Oblivion Daedric font set +http://www.uesp.net/wiki/Lore:Daedric_Alphabet#Daedric_Font + +--------------------------------------------------- + +This was done entirely as a personal project. Bethesda Softworks graciously granted me the permission for it. I am not connected with them in any way. +You may freely use these fonts to create anything you'd like. You may re-distribute the fonts freely, over the Internet, or by any other means. Always keep the .zip file intact, and this read me included. +Please do not modify and redistribute the fonts without my permission. +You may NOT sell any of these fonts under any circumstances. This includes putting them on compilation font CDs for sale, putting them in a "members only" pay-area of a website, or any other means of financial gain connected in ANY way with the redistribution of any of these fonts. +You have my permission to create and sell any artwork made with these fonts, however you may need to contact Bethesda Softworks before doing so. diff --git a/files/mygui/CMakeLists.txt b/files/mygui/CMakeLists.txt index f712ea67d3..d7e86ecfff 100644 --- a/files/mygui/CMakeLists.txt +++ b/files/mygui/CMakeLists.txt @@ -58,4 +58,6 @@ configure_file("${SDIR}/atlas1.cfg" "${DDIR}/atlas1.cfg" COPYONLY) configure_file("${SDIR}/smallbars.png" "${DDIR}/smallbars.png" COPYONLY) configure_file("${SDIR}/transparent.png" "${DDIR}/transparent.png" COPYONLY) configure_file("${SDIR}/EBGaramond-Regular.ttf" "${DDIR}/EBGaramond-Regular.ttf" COPYONLY) +configure_file("${SDIR}/Oblivion Worn.ttf" "${DDIR}/Oblivion Worn.ttf" COPYONLY) +configure_file("${SDIR}/Oblivion.ttf" "${DDIR}/Oblivion.ttf" COPYONLY) configure_file("${SDIR}/VeraMono.ttf" "${DDIR}/VeraMono.ttf" COPYONLY) diff --git a/files/mygui/Oblivion Worn.ttf b/files/mygui/Oblivion Worn.ttf new file mode 100644 index 0000000000000000000000000000000000000000..d48f19ebd55483019353b859760a09a4674ade0c GIT binary patch literal 158008 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 z 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�F<|P?9a@w`oo$3M&$Lf0C&= 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�HFq)5sM`sR*^AXmwda0Pf}SO?yVaNsQ|}y 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

u$FrTv*e$4WDs1l)(lF(hkk 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 aQwX;Q3YTj~5Wt;51nvqNz%Yo0%l`{pxIU%; literal 0 HcmV?d00001 diff --git a/files/mygui/Oblivion.ttf b/files/mygui/Oblivion.ttf new file mode 100644 index 0000000000000000000000000000000000000000..ab7e85e745858a629bb030bb21e1466255e12225 GIT binary patch literal 55364 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 veh2)udT8+*>Opk~_#3qV{Han+D literal 0 HcmV?d00001 diff --git a/files/mygui/openmw.font.xml b/files/mygui/openmw.font.xml index 25c44d5ed9..e93c9b770f 100644 --- a/files/mygui/openmw.font.xml +++ b/files/mygui/openmw.font.xml @@ -19,6 +19,19 @@ + + + + + + + + + + + + + From 3c69d265715cffd27f59ca2b9e01dd71f438aefe Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 7 May 2012 19:42:04 +0200 Subject: [PATCH 092/325] journal close sound --- apps/openmw/mwgui/journalwindow.cpp | 10 ++++++++++ apps/openmw/mwgui/journalwindow.hpp | 3 +++ 2 files changed, 13 insertions(+) diff --git a/apps/openmw/mwgui/journalwindow.cpp b/apps/openmw/mwgui/journalwindow.cpp index 4030911a00..e4c38496dc 100644 --- a/apps/openmw/mwgui/journalwindow.cpp +++ b/apps/openmw/mwgui/journalwindow.cpp @@ -82,6 +82,7 @@ book formatText(std::string text,book mBook,int maxLine, int lineSize) MWGui::JournalWindow::JournalWindow (WindowManager& parWindowManager) : WindowBase("openmw_journal_layout.xml", parWindowManager) , lastPos(0) + , mVisible(false) { //setCoord(0,0,498, 342); center(); @@ -111,6 +112,15 @@ MWGui::JournalWindow::JournalWindow (WindowManager& parWindowManager) //displayLeftText(list.front()); } +void MWGui::JournalWindow::setVisible(bool visible) +{ + if (mVisible && !visible) + MWBase::Environment::get().getSoundManager()->playSound ("book close", 1.0, 1.0); + mVisible = visible; + + mMainWidget->setVisible(visible); +} + void MWGui::JournalWindow::open() { mPageNumber = 0; diff --git a/apps/openmw/mwgui/journalwindow.hpp b/apps/openmw/mwgui/journalwindow.hpp index c5009d6548..cacdb9414c 100644 --- a/apps/openmw/mwgui/journalwindow.hpp +++ b/apps/openmw/mwgui/journalwindow.hpp @@ -18,6 +18,8 @@ namespace MWGui JournalWindow(WindowManager& parWindowManager); void open(); + virtual void setVisible(bool visible); // only used to play close sound + private: void displayLeftText(std::string text); void displayRightText(std::string text); @@ -41,6 +43,7 @@ namespace MWGui std::vector leftPages; std::vector rightPages; int mPageNumber; //store the number of the current left page + bool mVisible; }; } From 2b584300d6cc94dc1b1e54cda5700589fcafb9f2 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 7 May 2012 23:16:29 +0200 Subject: [PATCH 093/325] throw an exception when no default settings file is found, which indicates a packaging error --- apps/openmw/engine.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 319c42bbd7..c1bbeb5869 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -281,6 +281,8 @@ void OMW::Engine::go() settings.loadDefault(localdefault); else if (boost::filesystem::exists(globaldefault)) settings.loadDefault(globaldefault); + else + throw std::runtime_error ("No default settings file found! Make sure the file \"settings-default.cfg\" was properly installed."); // load user settings if they exist, otherwise just load the default settings as user settings const std::string settingspath = mCfgMgr.getUserPath().string() + "/settings.cfg"; From cd351ba3af196d6591cef3577358fd19a3893c28 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 8 May 2012 00:39:52 +0200 Subject: [PATCH 094/325] simple scroll text parsing (tags are ignored until now) --- apps/openmw/CMakeLists.txt | 1 + apps/openmw/mwgui/bookwindow.cpp | 8 +++ apps/openmw/mwgui/formatting.cpp | 95 ++++++++++++++++++++++++++++ apps/openmw/mwgui/formatting.hpp | 38 +++++++++++ apps/openmw/mwgui/scrollwindow.cpp | 17 +++++ apps/openmw/mwgui/scrollwindow.hpp | 1 + files/mygui/openmw_scroll_layout.xml | 9 --- 7 files changed, 160 insertions(+), 9 deletions(-) create mode 100644 apps/openmw/mwgui/formatting.cpp create mode 100644 apps/openmw/mwgui/formatting.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 29bc86fe34..d7c229cf9f 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -26,6 +26,7 @@ add_openmw_dir (mwgui layouts text_input widgets race class birth review window_manager console dialogue dialogue_history window_base stats_window messagebox journalwindow charactercreation map_window window_pinnable_base cursorreplace tooltips scrollwindow bookwindow list + formatting ) add_openmw_dir (mwdialogue diff --git a/apps/openmw/mwgui/bookwindow.cpp b/apps/openmw/mwgui/bookwindow.cpp index 4b6082b814..3491e69183 100644 --- a/apps/openmw/mwgui/bookwindow.cpp +++ b/apps/openmw/mwgui/bookwindow.cpp @@ -1,5 +1,7 @@ #include "bookwindow.hpp" +#include "formatting.hpp" + #include "../mwbase/environment.hpp" #include "../mwinput/inputmanager.hpp" #include "../mwsound/soundmanager.hpp" @@ -30,6 +32,12 @@ void BookWindow::open (MWWorld::Ptr book) MWBase::Environment::get().getSoundManager()->playSound3D (book, "book open", 1.0, 1.0); mBook = book; + + ESMS::LiveCellRef *ref = + mBook.get(); + + //BookTextParser parser; + //parser.parse(ref->base->text, 0, 0); } void BookWindow::onCloseButtonClicked (MyGUI::Widget* _sender) diff --git a/apps/openmw/mwgui/formatting.cpp b/apps/openmw/mwgui/formatting.cpp new file mode 100644 index 0000000000..547c12c35d --- /dev/null +++ b/apps/openmw/mwgui/formatting.cpp @@ -0,0 +1,95 @@ +#include "formatting.hpp" + +#include +#include +#include + +using namespace MWGui; + +MyGUI::IntSize BookTextParser::parse(std::string text, MyGUI::Widget* parent, const int width) +{ + mParent = parent; + mWidth = width; + + assert(mParent); + while (mParent->getChildCount()) + { + MyGUI::Gui::getInstance().destroyWidget(mParent->getChildAt(0)); + } + + boost::algorithm::replace_all(text, "
", "\n"); + + // remove leading newlines + //while (text[0] == '\n') + // text.erase(0); + + // remove trailing " and newlines + if (text[text.size()-1] == '\"') + text.erase(text.size()-1); + while (text[text.size()-1] == '\n') + text.erase(text.size()-1); + + return parseSubText(text, -1, MyGUI::Align::Left | MyGUI::Align::Top); +} + +MyGUI::IntSize BookTextParser::parseSubText(std::string text, int textSize, MyGUI::Align textAlign) +{ + MyGUI::IntSize size(mWidth,0); + + bool tagFound = false; + std::string realText; // real text, without tags + for (unsigned int i=0; i= text.size()) + throw std::runtime_error("BookTextParser Error: Tag is not terminated"); + ++i; + c = text[i]; + } + continue; + } + else + { + tagFound = true; + while (c != '>') + { + if (i >= text.size()) + throw std::runtime_error("BookTextParser Error: Tag is not terminated"); + + c = text[++i]; + } + ++i; + /// \todo parse tags + size += parseSubText(text.substr(i, text.size()), textSize, textAlign); + break; + } + } + else + realText += c; + } + + if (!tagFound) + { + MyGUI::EditBox* box = mParent->createWidget("NormalText", + MyGUI::IntCoord(0, size.height, mWidth, 24), MyGUI::Align::Left | MyGUI::Align::Top, + mParent->getName() + boost::lexical_cast(mParent->getChildCount())); + box->setProperty("Static", "true"); + box->setProperty("MultiLine", "true"); + box->setProperty("WordWrap", "true"); + box->setProperty("NeedMouse", "false"); + box->setMaxTextLength(realText.size()); + box->setTextAlign(textAlign); + box->setTextColour(MyGUI::Colour(0,0,0)); + box->setCaption(realText); + box->setSize(box->getSize().width, box->getTextSize().height); + size += MyGUI::IntSize(0, box->getTextSize().height); + } + + return size; +} diff --git a/apps/openmw/mwgui/formatting.hpp b/apps/openmw/mwgui/formatting.hpp new file mode 100644 index 0000000000..b60137f355 --- /dev/null +++ b/apps/openmw/mwgui/formatting.hpp @@ -0,0 +1,38 @@ +#ifndef MWGUI_FORMATTING_H +#define MWGUI_FORMATTING_H + +#include + +#include + +namespace MWGui +{ + /// \brief utilities for parsing book/scroll text as mygui widgets + class BookTextParser + { + public: + /** + * Parse markup as MyGUI widgets + * @param markup to parse + * @param parent for the created widgets + * @param maximum width + * @return size of the created widgets + */ + MyGUI::IntSize parse(std::string text, MyGUI::Widget* parent, const int width); + + protected: + /** + * @param text to parse + * @param text size (-1 means default) + * @param text align + * @return size of the created widgets + */ + MyGUI::IntSize parseSubText(std::string text, int textSize, MyGUI::Align textAlign); + + private: + MyGUI::Widget* mParent; + int mWidth; + }; +} + +#endif diff --git a/apps/openmw/mwgui/scrollwindow.cpp b/apps/openmw/mwgui/scrollwindow.cpp index a5135722fc..babf439acc 100644 --- a/apps/openmw/mwgui/scrollwindow.cpp +++ b/apps/openmw/mwgui/scrollwindow.cpp @@ -1,5 +1,7 @@ #include "scrollwindow.hpp" +#include "formatting.hpp" + #include "../mwbase/environment.hpp" #include "../mwinput/inputmanager.hpp" #include "../mwworld/actiontake.hpp" @@ -10,6 +12,8 @@ using namespace MWGui; ScrollWindow::ScrollWindow (WindowManager& parWindowManager) : WindowBase("openmw_scroll_layout.xml", parWindowManager) { + getWidget(mTextView, "TextView"); + getWidget(mCloseButton, "CloseButton"); mCloseButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ScrollWindow::onCloseButtonClicked); @@ -24,6 +28,19 @@ void ScrollWindow::open (MWWorld::Ptr scroll) MWBase::Environment::get().getSoundManager()->playSound3D (scroll, "scroll", 1.0, 1.0); mScroll = scroll; + + ESMS::LiveCellRef *ref = + mScroll.get(); + + BookTextParser parser; + MyGUI::IntSize size = parser.parse(ref->base->text, mTextView, 390); + + if (size.height > mTextView->getSize().height) + mTextView->setCanvasSize(size); + else + mTextView->setCanvasSize(390, mTextView->getSize().height); + + mTextView->setViewOffset(MyGUI::IntPoint(0,0)); } void ScrollWindow::onCloseButtonClicked (MyGUI::Widget* _sender) diff --git a/apps/openmw/mwgui/scrollwindow.hpp b/apps/openmw/mwgui/scrollwindow.hpp index e4968995e4..918a3d3ef0 100644 --- a/apps/openmw/mwgui/scrollwindow.hpp +++ b/apps/openmw/mwgui/scrollwindow.hpp @@ -20,6 +20,7 @@ namespace MWGui private: MyGUI::Button* mCloseButton; MyGUI::Button* mTakeButton; + MyGUI::ScrollView* mTextView; MWWorld::Ptr mScroll; }; diff --git a/files/mygui/openmw_scroll_layout.xml b/files/mygui/openmw_scroll_layout.xml index 8641a0511e..0f4a0be3e8 100644 --- a/files/mygui/openmw_scroll_layout.xml +++ b/files/mygui/openmw_scroll_layout.xml @@ -17,15 +17,6 @@ - - - - - - - - - From e9134717d62c95b6d16c2c8e515516a5a372c136 Mon Sep 17 00:00:00 2001 From: gugus Date: Tue, 8 May 2012 12:59:47 +0200 Subject: [PATCH 095/325] the GUI part of drag and drop is working --- apps/openmw/mwgui/container.cpp | 42 ++++++++++------------------ apps/openmw/mwgui/itemwidget.hpp | 18 ++++++++++++ apps/openmw/mwgui/window_manager.cpp | 2 ++ 3 files changed, 35 insertions(+), 27 deletions(-) create mode 100644 apps/openmw/mwgui/itemwidget.hpp diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 083ce2f646..454dd05c37 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -18,26 +18,11 @@ #include #include "../mwworld/class.hpp" #include "../mwinput/inputmanager.hpp" +#include "itemwidget.hpp" using namespace MWGui; using namespace Widgets; -class ItemWidget: public MyGUI::ImageBox -{ -public: - ItemWidget() - :ImageBox() - { - } - virtual ~ItemWidget() - { - } - - void setPtr(MWWorld::Ptr &ptr,int pos){mPtr = ptr;mPos = pos;} - - MWWorld::Ptr mPtr; - int mPos; -}; ContainerWindow::ContainerWindow(WindowManager& parWindowManager,MWWorld::Environment& environment,DragAndDrop* dragAndDrop) @@ -149,39 +134,36 @@ void ContainerWindow::drawItems() int x = 4; int y = 4; int count = 0; - + int index = 0; for (MWWorld::ContainerStoreIterator iter (containerStore.begin()); iter!=containerStore.end(); ++iter) { - count++; + index++; if(iter->getRefData().getCount() > 0) { + count++; std::string path = std::string("icons\\"); path+=MWWorld::Class::get(*iter).getInventoryIcon(*iter); ItemWidget* image = mContainerWidget->createWidget("ImageBox", MyGUI::IntCoord(x, y, 32, 32), MyGUI::Align::Default); MyGUI::TextBox* text = image->createWidget("SandBrightText", MyGUI::IntCoord(x, y, 18, 18), MyGUI::Align::Default, std::string("Label")); image->eventMouseButtonClick += MyGUI::newDelegate(this,&ContainerWindow::onSelectedItem); - //image->setPtr(*iter,count); - image->mPos = count; - - //image->mPtr = *iter; + image->mPos = index; + image->mPtr = *iter; //image->eventMouseMove += MyGUI::newDelegate(this,&ContainerWindow::onMouseMove); - /*x += 36; + x += 36; if(count % 20 == 0) { y += 36; x = 4; count = 0; - }*/ + } if(iter->getRefData().getCount() > 1) text->setCaption(boost::lexical_cast(iter->getRefData().getCount())); - //mContainerWidgets int pos = path.rfind("."); path.erase(pos); path.append(".dds"); - //std::cout << path << std::endl; image->setImageTexture(path); } } @@ -251,7 +233,13 @@ void ContainerWindow::onContainerClicked(MyGUI::Widget* _sender) std::cout << "container clicked"; if(mDragAndDrop->mIsOnDragAndDrop) //drop widget here { - //mContainer.getContainerStore()->add(mDragAndDrop->mDraggedWidget-> + ItemWidget* item = static_cast(mDragAndDrop->mDraggedWidget); + std::cout << item->mPos << item->mPtr.getTypeName(); + if(item->mPtr.getContainerStore() == 0) std::cout << "nocontainer!"; + std::cout << item->mPtr.getContainerStore()->getType(item->mPtr); + MWWorld::Ptr ptr = item->mPtr; + //MWWorld::World + //mContainer.getContainerStore()->add(item->mPtr); mDragAndDrop->mIsOnDragAndDrop = false; mDragAndDrop->mDraggedWidget->detachFromWidget(); mDragAndDrop->mDraggedWidget->attachToWidget(mContainerWidget); diff --git a/apps/openmw/mwgui/itemwidget.hpp b/apps/openmw/mwgui/itemwidget.hpp new file mode 100644 index 0000000000..ff65bfd4d0 --- /dev/null +++ b/apps/openmw/mwgui/itemwidget.hpp @@ -0,0 +1,18 @@ +#ifndef MWGUI_ITEM_WIDGET_H +#define MWGUI_ITEM_WIDGET_H +#include +#include "../mwworld/ptr.hpp" + +namespace MWGui +{ + class ItemWidget: public MyGUI::ImageBox + { + MYGUI_RTTI_DERIVED( ItemWidget ) + public: + + MWWorld::Ptr mPtr; + int mPos; + }; +} + +#endif \ No newline at end of file diff --git a/apps/openmw/mwgui/window_manager.cpp b/apps/openmw/mwgui/window_manager.cpp index 9db7892e26..e72f635bf0 100644 --- a/apps/openmw/mwgui/window_manager.cpp +++ b/apps/openmw/mwgui/window_manager.cpp @@ -9,6 +9,7 @@ #include "messagebox.hpp" #include "container.hpp" #include "inventorywindow.hpp" +#include "itemwidget.hpp" #include "../mwmechanics/mechanicsmanager.hpp" #include "../mwinput/inputmanager.hpp" @@ -68,6 +69,7 @@ WindowManager::WindowManager(MWWorld::Environment& environment, //Register own widgets with MyGUI MyGUI::FactoryManager::getInstance().registerFactory("Widget"); + MyGUI::FactoryManager::getInstance().registerFactory("Widget"); // Get size info from the Gui object assert(gui); From 8e7ab09a25bc9db3edc82916ff58eeb36d699a6f Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 9 May 2012 01:34:32 +0200 Subject: [PATCH 096/325] scroll window image tags working --- apps/openmw/mwgui/bookwindow.cpp | 2 + apps/openmw/mwgui/formatting.cpp | 96 ++++++++++++++++++++---------- apps/openmw/mwgui/formatting.hpp | 30 +++++++--- apps/openmw/mwgui/scrollwindow.cpp | 6 +- 4 files changed, 93 insertions(+), 41 deletions(-) diff --git a/apps/openmw/mwgui/bookwindow.cpp b/apps/openmw/mwgui/bookwindow.cpp index 3491e69183..75be6280ad 100644 --- a/apps/openmw/mwgui/bookwindow.cpp +++ b/apps/openmw/mwgui/bookwindow.cpp @@ -54,6 +54,8 @@ void BookWindow::onTakeButtonClicked (MyGUI::Widget* _sender) MWWorld::ActionTake take(mBook); take.execute(); + /// \todo what about scripts? + MWBase::Environment::get().getInputManager()->setGuiMode (GM_Game); } diff --git a/apps/openmw/mwgui/formatting.cpp b/apps/openmw/mwgui/formatting.cpp index 547c12c35d..6c53c6873f 100644 --- a/apps/openmw/mwgui/formatting.cpp +++ b/apps/openmw/mwgui/formatting.cpp @@ -10,6 +10,7 @@ MyGUI::IntSize BookTextParser::parse(std::string text, MyGUI::Widget* parent, co { mParent = parent; mWidth = width; + mHeight = 0; assert(mParent); while (mParent->getChildCount()) @@ -29,16 +30,58 @@ MyGUI::IntSize BookTextParser::parse(std::string text, MyGUI::Widget* parent, co while (text[text.size()-1] == '\n') text.erase(text.size()-1); - return parseSubText(text, -1, MyGUI::Align::Left | MyGUI::Align::Top); + parseSubText(text); + return MyGUI::IntSize(mWidth, mHeight); } -MyGUI::IntSize BookTextParser::parseSubText(std::string text, int textSize, MyGUI::Align textAlign) +void BookTextParser::parseImage(std::string tag) { - MyGUI::IntSize size(mWidth,0); + int src_start = tag.find("SRC=")+5; + std::string image = tag.substr(src_start, tag.find('"', src_start)-src_start); + + // fix texture extension to .dds + if (image.size() > 4) + { + image[image.size()-3] = 'd'; + image[image.size()-2] = 'd'; + image[image.size()-1] = 's'; + } + + int width_start = tag.find("WIDTH=")+7; + int width = boost::lexical_cast(tag.substr(width_start, tag.find('"', width_start)-width_start)); + + int height_start = tag.find("HEIGHT=")+8; + int height = boost::lexical_cast(tag.substr(height_start, tag.find('"', height_start)-height_start)); + + MyGUI::ImageBox* box = mParent->createWidget ("ImageBox", + MyGUI::IntCoord(0, mHeight, width, height), MyGUI::Align::Left | MyGUI::Align::Top, + mParent->getName() + boost::lexical_cast(mParent->getChildCount())); + box->setImageTexture("bookart\\" + image); + box->setProperty("NeedMouse", "false"); + + mWidth = std::max(mWidth, width); + mHeight += height; +} + +void BookTextParser::parseSubText(std::string text) +{ + if (text[0] == '<') + { + if (text.find('>') == std::string::npos) + throw std::runtime_error("BookTextParser Error: Tag is not terminated"); + + if (text.size() > 4 && text.substr(0, 4) == "'))); + } + + text.erase(0, text.find('>')+1); + } bool tagFound = false; std::string realText; // real text, without tags - for (unsigned int i=0; i= text.size()) - throw std::runtime_error("BookTextParser Error: Tag is not terminated"); - - c = text[++i]; - } - ++i; - /// \todo parse tags - size += parseSubText(text.substr(i, text.size()), textSize, textAlign); break; } } @@ -74,22 +107,23 @@ MyGUI::IntSize BookTextParser::parseSubText(std::string text, int textSize, MyGU realText += c; } - if (!tagFound) - { - MyGUI::EditBox* box = mParent->createWidget("NormalText", - MyGUI::IntCoord(0, size.height, mWidth, 24), MyGUI::Align::Left | MyGUI::Align::Top, - mParent->getName() + boost::lexical_cast(mParent->getChildCount())); - box->setProperty("Static", "true"); - box->setProperty("MultiLine", "true"); - box->setProperty("WordWrap", "true"); - box->setProperty("NeedMouse", "false"); - box->setMaxTextLength(realText.size()); - box->setTextAlign(textAlign); - box->setTextColour(MyGUI::Colour(0,0,0)); - box->setCaption(realText); - box->setSize(box->getSize().width, box->getTextSize().height); - size += MyGUI::IntSize(0, box->getTextSize().height); - } + MyGUI::EditBox* box = mParent->createWidget("NormalText", + MyGUI::IntCoord(0, mHeight, mWidth, 24), MyGUI::Align::Left | MyGUI::Align::Top, + mParent->getName() + boost::lexical_cast(mParent->getChildCount())); + box->setProperty("Static", "true"); + box->setProperty("MultiLine", "true"); + box->setProperty("WordWrap", "true"); + box->setProperty("NeedMouse", "false"); + box->setMaxTextLength(realText.size()); + box->setTextAlign(mTextStyle.mTextAlign); + box->setTextColour(mTextStyle.mColour); + box->setFontName(mTextStyle.mFont); + box->setCaption(realText); + box->setSize(box->getSize().width, box->getTextSize().height); + mHeight += box->getTextSize().height; - return size; + if (tagFound) + { + parseSubText(text.substr(i, text.size())); + } } diff --git a/apps/openmw/mwgui/formatting.hpp b/apps/openmw/mwgui/formatting.hpp index b60137f355..9fd8150039 100644 --- a/apps/openmw/mwgui/formatting.hpp +++ b/apps/openmw/mwgui/formatting.hpp @@ -7,6 +7,22 @@ namespace MWGui { + struct TextStyle + { + TextStyle() : + mColour(0,0,0) + , mFont("Default") + , mTextSize(16) + , mTextAlign(MyGUI::Align::Left | MyGUI::Align::Top) + { + } + + MyGUI::Colour mColour; + std::string mFont; + int mTextSize; + MyGUI::Align mTextAlign; + }; + /// \brief utilities for parsing book/scroll text as mygui widgets class BookTextParser { @@ -21,17 +37,15 @@ namespace MWGui MyGUI::IntSize parse(std::string text, MyGUI::Widget* parent, const int width); protected: - /** - * @param text to parse - * @param text size (-1 means default) - * @param text align - * @return size of the created widgets - */ - MyGUI::IntSize parseSubText(std::string text, int textSize, MyGUI::Align textAlign); + void parseSubText(std::string text); + + void parseImage(std::string tag); private: MyGUI::Widget* mParent; - int mWidth; + int mWidth; // maximum width + int mHeight; // current height + TextStyle mTextStyle; }; } diff --git a/apps/openmw/mwgui/scrollwindow.cpp b/apps/openmw/mwgui/scrollwindow.cpp index babf439acc..b1c5ec3373 100644 --- a/apps/openmw/mwgui/scrollwindow.cpp +++ b/apps/openmw/mwgui/scrollwindow.cpp @@ -36,9 +36,9 @@ void ScrollWindow::open (MWWorld::Ptr scroll) MyGUI::IntSize size = parser.parse(ref->base->text, mTextView, 390); if (size.height > mTextView->getSize().height) - mTextView->setCanvasSize(size); + mTextView->setCanvasSize(MyGUI::IntSize(410, size.height)); else - mTextView->setCanvasSize(390, mTextView->getSize().height); + mTextView->setCanvasSize(410, mTextView->getSize().height); mTextView->setViewOffset(MyGUI::IntPoint(0,0)); } @@ -57,5 +57,7 @@ void ScrollWindow::onTakeButtonClicked (MyGUI::Widget* _sender) MWWorld::ActionTake take(mScroll); take.execute(); + /// \todo what about scripts? + MWBase::Environment::get().getInputManager()->setGuiMode (GM_Game); } From e5e8663bb4e2f49644504f3d0fb182cba2c6300a Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 9 May 2012 02:11:44 +0200 Subject: [PATCH 097/325] parse

and

--- apps/openmw/mwgui/formatting.cpp | 109 +++++++++++++++++++++++++++++-- apps/openmw/mwgui/formatting.hpp | 3 +- 2 files changed, 106 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwgui/formatting.cpp b/apps/openmw/mwgui/formatting.cpp index 6c53c6873f..6b50fd04d0 100644 --- a/apps/openmw/mwgui/formatting.cpp +++ b/apps/openmw/mwgui/formatting.cpp @@ -6,6 +6,65 @@ using namespace MWGui; +namespace +{ + int convertFromHex(std::string hex) + { + int value = 0; + + int a = 0; + int b = hex.length() - 1; + for (; b >= 0; a++, b--) + { + if (hex[b] >= '0' && hex[b] <= '9') + { + value += (hex[b] - '0') * (1 << (a * 4)); + } + else + { + switch (hex[b]) + { + case 'A': + case 'a': + value += 10 * (1 << (a * 4)); + break; + + case 'B': + case 'b': + value += 11 * (1 << (a * 4)); + break; + + case 'C': + case 'c': + value += 12 * (1 << (a * 4)); + break; + + case 'D': + case 'd': + value += 13 * (1 << (a * 4)); + break; + + case 'E': + case 'e': + value += 14 * (1 << (a * 4)); + break; + + case 'F': + case 'f': + value += 15 * (1 << (a * 4)); + break; + + default: + throw std::runtime_error("invalid character in hex number"); + break; + } + } + } + + return value; + } +} + MyGUI::IntSize BookTextParser::parse(std::string text, MyGUI::Widget* parent, const int width) { mParent = parent; @@ -19,16 +78,15 @@ MyGUI::IntSize BookTextParser::parse(std::string text, MyGUI::Widget* parent, co } boost::algorithm::replace_all(text, "
", "\n"); + boost::algorithm::replace_all(text, "

", "\n\n"); // remove leading newlines //while (text[0] == '\n') // text.erase(0); - // remove trailing " and newlines + // remove trailing " if (text[text.size()-1] == '\"') text.erase(text.size()-1); - while (text[text.size()-1] == '\n') - text.erase(text.size()-1); parseSubText(text); return MyGUI::IntSize(mWidth, mHeight); @@ -63,6 +121,45 @@ void BookTextParser::parseImage(std::string tag) mHeight += height; } +void BookTextParser::parseDiv(std::string tag) +{ + if (tag.find("ALIGN=") == std::string::npos) + return; + + int align_start = tag.find("ALIGN=")+7; + std::string align = tag.substr(align_start, tag.find('"', align_start)-align_start); + if (align == "CENTER") + mTextStyle.mTextAlign = MyGUI::Align::HCenter; + else if (align == "LEFT") + mTextStyle.mTextAlign = MyGUI::Align::Left; +} + +void BookTextParser::parseFont(std::string tag) +{ + if (tag.find("COLOR=") != std::string::npos) + { + int color_start = tag.find("COLOR=")+7; + std::string color = tag.substr(color_start, tag.find('"', color_start)-color_start); + + mTextStyle.mColour = MyGUI::Colour( + convertFromHex(color.substr(0, 2))/255.0, + convertFromHex(color.substr(2, 2))/255.0, + convertFromHex(color.substr(4, 2))/255.0); + } + if (tag.find("FACE=") != std::string::npos) + { + int face_start = tag.find("FACE=")+6; + std::string face = tag.substr(face_start, tag.find('"', face_start)-face_start); + + if (face != "Magic Cards") + mTextStyle.mFont = face; + } + if (tag.find("SIZE=") != std::string::npos) + { + /// \todo + } +} + void BookTextParser::parseSubText(std::string text) { if (text[0] == '<') @@ -71,9 +168,11 @@ void BookTextParser::parseSubText(std::string text) throw std::runtime_error("BookTextParser Error: Tag is not terminated"); if (text.size() > 4 && text.substr(0, 4) == "'))); - } + else if (text.size() > 5 && text.substr(0, 5) == "'))); + else if (text.size() > 4 && text.substr(0, 4) == "'))); text.erase(0, text.find('>')+1); } diff --git a/apps/openmw/mwgui/formatting.hpp b/apps/openmw/mwgui/formatting.hpp index 9fd8150039..19b6969183 100644 --- a/apps/openmw/mwgui/formatting.hpp +++ b/apps/openmw/mwgui/formatting.hpp @@ -40,7 +40,8 @@ namespace MWGui void parseSubText(std::string text); void parseImage(std::string tag); - + void parseDiv(std::string tag); + void parseFont(std::string tag); private: MyGUI::Widget* mParent; int mWidth; // maximum width From d69501b061f6443a485139ee46d2edbebafb4e27 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 9 May 2012 02:16:10 +0200 Subject: [PATCH 098/325] change daedric font to .zip resource --- apps/openmw/engine.cpp | 7 +++++++ apps/openmw/engine.hpp | 4 +++- files/mygui/CMakeLists.txt | 3 +-- files/mygui/Oblivion Worn.ttf | Bin 158008 -> 0 bytes files/mygui/Oblivion.ttf | Bin 55364 -> 0 bytes files/mygui/Obliviontt.zip | Bin 0 -> 138502 bytes files/mygui/openmw.font.xml | 4 ++-- 7 files changed, 13 insertions(+), 5 deletions(-) delete mode 100644 files/mygui/Oblivion Worn.ttf delete mode 100644 files/mygui/Oblivion.ttf create mode 100644 files/mygui/Obliviontt.zip diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 319c42bbd7..a00d764b06 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -194,6 +194,12 @@ void OMW::Engine::addResourcesDirectory (const boost::filesystem::path& path) Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, true); } +void OMW::Engine::addZipResource (const boost::filesystem::path& path) +{ + mOgre->getRoot()->addResourceLocation (path.string(), "Zip", + Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, false); +} + void OMW::Engine::enableFSStrict(bool fsStrict) { mFSStrict = fsStrict; @@ -314,6 +320,7 @@ void OMW::Engine::go() addResourcesDirectory(mResDir / "water"); addResourcesDirectory(mResDir / "gbuffer"); addResourcesDirectory(mResDir / "shadows"); + addZipResource(mResDir / "mygui" / "Obliviontt.zip"); // Create the window mOgre->createWindow("OpenMW"); diff --git a/apps/openmw/engine.hpp b/apps/openmw/engine.hpp index 63464a40d9..cf1ef3b9c9 100644 --- a/apps/openmw/engine.hpp +++ b/apps/openmw/engine.hpp @@ -91,9 +91,11 @@ namespace OMW /// add resources directory /// \note This function works recursively. - void addResourcesDirectory (const boost::filesystem::path& path); + /// add a .zip resource + void addZipResource (const boost::filesystem::path& path); + /// Load all BSA files in data directory. void loadBSA(); diff --git a/files/mygui/CMakeLists.txt b/files/mygui/CMakeLists.txt index d7e86ecfff..ac803646e4 100644 --- a/files/mygui/CMakeLists.txt +++ b/files/mygui/CMakeLists.txt @@ -58,6 +58,5 @@ configure_file("${SDIR}/atlas1.cfg" "${DDIR}/atlas1.cfg" COPYONLY) configure_file("${SDIR}/smallbars.png" "${DDIR}/smallbars.png" COPYONLY) configure_file("${SDIR}/transparent.png" "${DDIR}/transparent.png" COPYONLY) configure_file("${SDIR}/EBGaramond-Regular.ttf" "${DDIR}/EBGaramond-Regular.ttf" COPYONLY) -configure_file("${SDIR}/Oblivion Worn.ttf" "${DDIR}/Oblivion Worn.ttf" COPYONLY) -configure_file("${SDIR}/Oblivion.ttf" "${DDIR}/Oblivion.ttf" COPYONLY) +configure_file("${SDIR}/Obliviontt.zip" "${DDIR}/Obliviontt.zip" COPYONLY) configure_file("${SDIR}/VeraMono.ttf" "${DDIR}/VeraMono.ttf" COPYONLY) diff --git a/files/mygui/Oblivion Worn.ttf b/files/mygui/Oblivion Worn.ttf deleted file mode 100644 index d48f19ebd55483019353b859760a09a4674ade0c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 158008 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 z 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�F<|P?9a@w`oo$3M&$Lf0C&= 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�HFq)5sM`sR*^AXmwda0Pf}SO?yVaNsQ|}y zLlV%@Nw*y4$}86O?jUs}{Imq3rA-jgFjd5YrEyUZ_Nz#>*dd@$>5e zR~|TAR}K0!uP$1;0g<`vmrJD>(yJRlv9eptSN%FSAjoD6kGT0#iMn&=wdcG8rYUZK z5xu4v=+4JVp;UxB$S~5aqNrRYXNF3IcND{XyaD@jpl_4hsBKIThTU2I*kdGTs}_hRS7zV6=n#>QL) z1|>-`nyYnssAk^s-hz5r&~8-vRcamVnbAl`NNMJ=+@RrwwOX&AFZI9Uq(z%D%o0A~ z!l;N~L8D$fu(94O){DbpB_EXeVf12vDDCaMqFxBh9bXK)UbynOIs;jw6mz|W@7+)e z89-5z7%!+#k7J4%-@_L8nqZQ+VLfIHO%_krAnk#+3 zd*!uP&-9i%FK*LB*~?0=eQJ5;SSPInS2ogw&QNjvLa8v=b)a+T(VbFBS57fEfKuG5 zw>mS$D4N}Oc;?FM;jwCb?=LcjJKh}{$QihzO6gdG5v-tIr%4A`j-y23l)x8jD1hBr zgrRSi>TZz{&yN}{hPBdo72bk)GFH?7s>LLsvxQ!_vyWcQ(b7e_u2}DB(5n=^ zeUMv4cp*tev(RNKR!l|=4WwKJbAfpK_RN<{g`m#;DfL1PRz!aeie8n5m<{Xo>$rxE z)(7WO(T|Tsr5Zz=8N_Ff(iP?(?3oyQbUWe-A+C~8$BHM@w&mxe)3rgwuYK!VN zwTHf0xZAyhlRoap{QBYCmvY~5mYsvnqnw+aH#qNgKI0y6FL9se{-pb>?jO4U!wbDD zyzlp3?ftseeDpZCZ9{r<=O2ZJn{8*5sJ(FgII75n@}?mQf0tXi>*JtHKO}QQt!~IhIGiK*UFoUr+mv zk;$dbv^J$PO0hEPoAePWDLYgPtM*`6X`?`m$%-7%4~&xJEAf`XX|$PXYIF|t3h8ku zIu}eFq6ltloYE(hfiRH9*+$<$2@xtNo!BH)G({anj31*~N#Qga)V8*HK>C|fN!vt6 zlYTu4(JD|^WD1?4l%f$q4RlcHi2XdejVgzpX*9zvEtA*evpG6=ww8%zCUps&#?-6t zq(sA%Ate;WOgb4_EZBndWVm6kYtN`?)F`4Goy@AVif>$x2{!5^3b4Rblnh#OmynJH z9md9xVjIek>O2k87z=29n{%dQlG!9{)J@(^O!FEw6PlxH(6lltSpC z(-4Wi38TXaGLk`~3DrWuOobf`g3g#Jh#<)NmgY1MpLW@dARR3tLwoUzvj;V(= zqaHuc6_E1^9XgVyaGSxv~s>-_xx;AD}naq^WcEO1Y zjm2|P>e2qKO?9gnTZU|cq{#~0w3fG>*@vUVBa$)cs&rUmY;1*F2oOV~4w39wLyV1` zhDT$Hqkprwfw^Io?RL7}NGkl!jIt~JGJ~YvZP*gnVPFerr9)OnU{so2wh>byGE?`F zu~jBK*uiErV9Zqvl|}t5Zfkw8}?+dffF%X8)F1ql6WmU$|#1Z zzi9~KLR8h?*dUiO6V`DT7pt_HxS^~hWVv4$skQdI+Qh%JwaD4+B3_h&C`3Hn4N&xF zkd-2jeH2IvNi<06D8XDykq@t7dNg+xp^9m-#2nX>4^cyyR3(?_t{Vi2@EX(ttOZya z(EgCp(8tQ?oNlRA^NLzOkSMmu^o!nxD1`v=pCY%!jd;i;git=>TvQ5}r~Ot<${gB_ z<18t!K$jTh^Pk9ja}__~zB{ILZfMCD0}>#_qH0RQDMl5~If=Fxd--F$EOt-0v0rcc z)gXUqP%Uu96FBQWsr-}34^)tuxpC9?o3(}%*uZa?(4kM|bbAu=kK`-Q|0o(4x`rf7 z7ad8Lx=1$!bI~P#dp>Bz$PZdO;afyPj4UK|2!xu3bfWrI(Z@U=(}N#G=(-gta9TD& zboaP!#B)kfd!fj$q!g%$6gm4`s7M6QuSJltgkT7fl?XY-NAWY%^h-}claQQBI)ocq z7aCAKbOeYBV$PMI6BOOJ9#qIVPjL`pH_9hspIh-Iuoa#}AzYp+YJyOZpYV))NhOUa zoxhg0C1EIAO$n9N$%n|Qp%*7rZt{~f?gfQng$sc}@2wFsf?F7LwYa=DH;nov-ve zyXTPAD+M(1+H9P3;F+*cqJ4|C##>N9Dpj3NY?z4V&lwatB9`dV5nX}CZg z0R40&ZLXwfluG74THWs!jaK=ncchNUPaP=1bRKS%6f1rYEXJ=C6Liiw!y#e48DmXa z+MiF&0OO73FkR4z(sW6K1HAy#2<*!s0n?*Gc+EB(CetFS5e6D;ag>d5j2k(1eKKlC z7CWZFOl&yotjLoke^jD7*ORDHuW39(L*)J^`U0k=nm4S~Zs(3EboEjp-rzdQ0Ly6F zJIvd;8|WlvSec7&FjavGFtotYbk2N}J4cskaQY(Q`8z4uTVZsh4sP*xF=;u3tUSmjWcIa>OAV9d14l!3~qB`paL(n zWJbJFStdjpT%(V1N~F^C%(k#05ncR>rbxy(&S1|_CvDDup27G2{5>Tb4}CJYaJ>Az zTajdoBbF3PaychI#oO0xzNJzx<{d0%7!3NgK4!1{uGJVDX};C0%_WTg!D@o-3yZTM zT2xJL6nTS2vp1Jde#*WxZLGnT*KeLJ>sD;4PGzth_@#bm3gNy}jF+8Ssm?&}27^Iw zf%$Hl>n*<9sr7nM^6s=Z=yeDA_z6jkF=J;|(5aT(TpP~R4)5OATcJCf;d)vU4IQlX zR{E1#QcdH1!zJeD+1hi`j-OAjNq1o@fX}!QKH8PuGTM>0vTv|lYevl98@*+ujXYC3 zxFbn$+t+gM3OCpXzlv83!*Gr3T=SM%8s!^|)!pX1YYCGf^D2#2jfR1ndeL0c4uUQ> z!FspF`Pq5b@2%DtJDI_QR&Rz86XL~RskgD)8~Z*sHf!jJ+x3}d2Tu0NJ>Iz4yIsF0_wL+>IH_`%bJ)4u zxzTyR`8(%Z+>~~u`~B{JazE;R$^E*wj6cMs-c!6cc<=E(li!u!%s(^#&iwzI|1bH! z$p4Ff#J|gbzW+Y|gZ_W>|05E)^3F(se8OM))?a`aE=k@LN*-iR;HkHj5ttOeGQv~Dh{4oE&}p@p_#Yb4{StX z1uKNXrs}k1zL7~wHP}%BW4y^KplifrzoAi3R%u>&Hqaz$d=)d+fRZ)#wgqQOdCOGR zjbmj+szn!Oo5bTx{d5Snf(Sz8p9^$nD)BtH>tb>Xg63` zwiDWd8kxQZBTU4enEODLgs9V&Tj_iQ<5fU9_}185(A6)P5JXJ6w%GivgsVFeZWxlB zRpKek}g+_9@)kJmtbE?pYNty$*-*IaVZ)lI^WU;PFfzD#)kr}E{PNh)0(q^r&GuEoXL zq+jh6t8*+G6+<+}L&ZY7J8Bm<57qMCgPym#QY&}dD#Cr#42wt?xVdz{%Zx+oVsm|egJajc zVYDcu$MbQs?|kt3;}?)Wut9F2n7TxYxh(%b=@mSJPY5*Yz7om5I5x*r+X` z6&1@(v?3&@S{*FYz4gj$>>b{7u-PlJBJ8{Mq(bcOQlqxe1eLgkeDY5%$B&D3iN&KU z_w75@9v`yMwQtxA>WjmLJ^Q+m`yoU#)`_YS zg79(+VYh?4#>#b362IpaqM2b=dO-e|BuA=@zJdIQFez;V7YL-3JQ=VQQM@#S?uisr z{!2_}fsXZAFRoWSme5fZydinWmZGf}KM?wrGJ>ikWF##V%h)f5#YV+ku8bAcB_fkrz zVi)0VUY0bgy8N~1Es;z-R;FNVSC5V1KpIu~Ldt#k&S;T2A(rP|LRcvZ6XbLFi4u_1 z@ga!tvyqxY6nMB$Ec3+Q%bUerWmn=llqQ3u$W_wBF@myFh-akmJgHgOUl)52t6*Zq zEPR<*T88%vGwh=Ap4=+#tE*;OmQ&LuIFcwYR@eC|c9fO#v0ClSKUQm?>lB)Gl2w)& z5fE2VRB%@*zd5P0rb|V0J!`l0EFC4tiFu;Z4 zK~z3DTE3`Sqzl4$vO17+d5*riFm4_?g02_M5ndnn5BZ%aYSdOLtS#X*K+A!BrN4jI zVxx>r1HHo_M;>mme#^f7PhZ6WiV?d}pDEu|rH5dh5cW1g`9S}>Dn;qBbzV!hx%-JbNJQ{UP?ujNIW!DWb?%Si<)yq+WxvBu18WY zx6{y*^bdb`I;xkIB%WsJ+CPQ6>hCkjK{{*~o@Q7l&|xWtd!jkm1Nc{MO>+9z2f|?u!_#= zcmw=0=oH1_kP${o54=x*L#NkR9MZ+>703tQdgz_fnPj8g84*swL!^FwyuHIb-UiG? zjba>DSSp5Ty*w732+NdLuB-HlhS3;%Erx(7Sj#uz?mRBDt8w>owRPU>7Os)Q3%U|W zKr9v3S_;ETgG5rQ^WLpgA#_IQTl7?To1qhvU4BOTD@(!j@LIjhTMZ9NBfO4xE9q_Rx5EXNTt%`Ey+}MHaN9Y3f%AgL$B96 z0h30!T;aMFl`&-DaEY^+<2T?Ycpm#Y=BGHuR#_~%J=`3%zTkJ5{b@SJMC36^0GNoF zW3@u!2F&41xSF4wFpijfc-2Ycd{Tf(aCq@zY`+y;T`=gUQ(>cmodlb?!-@bV45l3{ zmP^;}9$vrKaiRtG7dS~3{|Nl!=u5Jy!Q{9h1+}^(<6VGl-B<(VK3a@I{?XYPqL}^2 z32X{cL$XS#Up8ar?%m6k)_7^zd+Frhnp+#Eez5zohuu~Q??W8b{E}O$PfGa&8I{uf zfKnJP@qg4<2Ui!%g?bY^avax^sOI3o7R=?DS_3zR@1r`1x`hHBJ!xF1mZRCZu9he; zJ!{0Ib_^WIH({ZH?YhuxAWE?YkuYL0wxkiuAJye1Q#x}ixZ|KyYFGEHuBCL=_HyO% zzj@m|e|FEp?mf%JRxvq{;!G2?8cC(aJnIHYFKQ0U$wFFaR#^k9l>D^6P$|wQ(4)Cf zEL5?P`z0EhX*cofy?UI-RnUn_Nm!XFM77l=R!7Ra({#15`NHqMYu}M)KK04Dfb-!z z_jTSpeJsE#^aSSx&fDo>jF{=>SPThUTF%UR86EBHZZ=xR_LB87I?PrdL-!L*#}ga# zpH4^*KwZp&;M=qNm{tnuV)SRj&U5Za2R@wB#Y{&x9SmKG{8_KIC6E^AJL+Iq*6Ax- z-3zQhoQyaSLp^b4zmke;dKDXewk-;ZeP|@p5WU%UVdL1)LbubPVRG159Sw0VXp*PD zJhFBc>DtTVcFOo54V)id;Pt3}Z*bTVjeM5zuy3!qH=X%xvs$foG?BVqQ9f1j#Wcbn zJybrXbXnE~5Y0kdot?5%W5$px8)7EYpp3l;$wXCbIvoGtr_(<3HRcC;Gv2X`Ez+J`GxdZlS7_J*D^Tg< z!zNYbPm*>#U}h~Raxo7IOnF4f<681hQMpiNtiWm=Rq^jF6sXy}^Uc3uR^wt&3u;Mu07k*Yiai@2A$GOD|1Sbn+r zs2M+x18{Nk-V>)@duglN>#{~1%&{@j$7QxqV6_0NZ=vSLIIp)Vtiqzcgu80_29Bw2 zxfPZwEY}95uHUHzH4po<+ydi4D`W^547$Ust~@m}I(GD;M}Z-uR^o>Ztr)W=ho5UX zW@$~MG@3dk%FYZ?sR+^1ghc?a9K;PNBP=eXZ?K-4eCt&~k`$WxYLl*7=oTZ^EE`qS zLh+=_-5F~+7fbRy_evhkJ&F@cUz+>5-2cZZ0UfL#Cpk0!N1YEif9LLVPrCQGuXTUK z{b~1e?%#TeH{+e~?)QG#`>6NZ-q-R^$iF}TYyLIT)o;D!My*PIPbdZv4t6SY${NWWH2}J5~D7=14&pL)Gk>C$*oeFV8Tx z5w2~vRL1(oCS__vk%Zo7eqGUMpog7S!&YHADSHVARvZJ+|^(pNJkxI^M(W1@HGmV>ft+F@WK(E zZeVBHg8A^6!`&#bqthJGXlezR8tx*B>5r?{aSYR?v5$f})elEOO5Suy3J`}#Vprob zox-5)){>nk&0;_}q7l=hI>AY1dvZmP@Ki-f?G#LQ+IE}8(4IKvZ*$_)co=Ao9%q|d zvA*-p1TBxmuD<4ZP=iJHIL!%GZH&Er*KU6$h-|eXPu6bAv10(~Soj#@k7jT|rqPB{ zUAlt&v$;;iWkt7W;SjokC*#I=)s#{E)kph6@Ps1ow=S|ueBwCk1C1LS`bV?-YS zy*=(Q5Mhkx*TkNPWwBHrU*r6Y);cf6RE8{OQHcQAuGPmVgS~?=Gy&9~ay9f(oEiY` z)#8{~dD=RvqcDfq#?@2f#)cRjY&D*Us$rl4TjN6}HMwRjYv@CybCNUY7`;s60B_aa z+j;E7i_9~`mY|N7Na$)KG_VOGoE$BOEpVlE8b;beLs zPB>x!-|(dME{b65pWOHkLZ@ZPjF!O-%EDw@;uMh>Tr;Yg78094wSj}k4&8RhkXF<@ zWX>wH!lrtrx8M!&ykyF-BJDa$b^$v~N78f;j`cCSAi+h$DYJ^0A*8d2lB_^LC*#*? z31T#Z^)_`%TZ%y15!JFo2~*1uPL(PE%2K(r2i}X#Gp#^n@}&RJnj^d)M(=K?Y^x3! zrZm8W8rn9PoW^W^o!hB+8@<5j-NaH%uvcB_cJ!ao=6Jb9iDvE(52h7HJLXDrU6SD$ z!+pVMyiVt!R()r4eWdE+l?fXy(Z-sJ_T=?FYMHqvFarrg(W?7-$3ZYcdeliplAaJ2 zvB@Dzmc6i#JcS4;X;zCZSl=XJA-nR8*`HlpY`H^DRwzQS0uduo&J`W;xS9{_b?SPN z{h3JeiZS*To=`@4z>3r|4~YBupe9VP&`^j!Ffuw`PAZ~I>7Ys(Qt|Y zS4A^&JCIa15oHtL?F4;o9@=?=#&L00tjkga_~6&2YM9z7fO^v!p7Sc<%5%j;$JC*` z^+KqCm5gH@H3lInj;N?ndc}jO91$J2r!NH+Fx-ncF1iknj!5Kk9s>=8QSQax{8>0F zTCJy8<=Rq~Fr#D0Cny=T2%{ayxl+^CGhJjW1u+O_K4tORqxx_JMT{vI8%rLxBvoPx5?o%+BMacx<_mruAmyWj;Q$vSL<2*m0^P)oI-7 zeYl;n1<1!tTaK{Bf^Ob<6bq18m9U1E7rS1OF%2^T2(HZ(FD0O=d}m0=!Zr#AK4n(N;xR79HBfYtz)7;>grgi~ImII{0q7(lE3w z(k)nv!sZh{BJ;fyr>ssDH`In&q4rbX^77o@ZX?Sr59fR!2QNxR&pH?Ge z*>I}t=+^E>^+H+VO~0p|<&VwMhm0M04EY4KcBNDoyC~L2b$8haXl!a%$UmMw3;OZ` zW05?-&`AM!x{HZ79Ori14JhsshfIYM_=Tz{x;^CeoG)|A*1Y5PiIe@gex07czYDye z8jtiQ8;8lr5S6HuNjpP3hH_K7gCnepZ-UMam@R9v|A?K%I2v%&736xx0HzELcD$C= z7+!N~rU+g@WP_F>;26s=F{F7-p{}>c`YNHeuA~qz>aa&z-i%+Eo>-?cu}MSs*!ojZ zilwsb5TRBlz$+4B=!N^8R$Wb~^5CxxI^YT(S`oszby|*=-k41SmW-kc^ss+huS60t7Nub^XHW+(O#%#DkX!7pjBO$+J|{>?H0BGH zD(u8h*IAAtoJjZA7g$ve%JwbYezDfmNJut8iG?z4=Pb8Fbp(?WAuB;CiaMPZ422U! zb3Y!@_MH>g7iMWrAxPvxHEH5RTa3D83N?XgsD8*lF);3{b=kexIW3I!FPLKzG5AB7 zQj~%#IuqTnxf_}?oO%Jp(L3oDM~H9!<7v@m+W{tZvS8e&--#vk7RFL;^dogh&+QRL z?;=Lv&uD!JPTR}Ae+YuZhpLSOwMHfPVuX2!tA$%VkC`wpV z$*<_ML)Pyy+A-V_K_%l-T4774pG8&JR%B@DdI{?U#KN;!SSv+&T3VxNio@~;`j2*; z>lk|(U9pjQ(Y0qD=hSO)qW%zI?}}R3yTW!*=oAZy^Zfdmo1K@!OiR};wtBrzSPt1k zKsHV}DwoX+PURpv&J@OMM^pM7EwQWS*O3&xayuwh@_sdpyFsU>=~&(yEPa%sxfX|K z$Z)sxm}Q~M)XFHv3@!W%U8XoX`wi66)`vif!JI3L9mh^EQDX$fl>y5hl+%_Cc$En( z*fqZ}OR6YM*lO<>vmPc*1|!;@br3IKK6A!#250_3(KW(W8PrU>Dg!H7h`SgkZRtmE z-E7Sfp?lC8R_T$5gFcN<`>OrbblMIgV`?M{U`th;i2W>BQdv6@7X`&)60*w6))_5F zt2SyWEydb<^iN+Lv39$tVPyhL43B&W?Kn6 zdFOjc$oU*augKX7@HeuCJZ={J7e3l)k)`i0*xVJ*$=#95J@i)psQ2bv$T5WtZcQ5G zM!7xQHhVO83HOITEq7b)dDt~yk$X+%8cKj%K0`%ULM=ZVhKoM$^Pc3$ng(Rr)$ zlla>HuJdW<&z!G1fA9PgBlE1g%iVB~x+mPny3cZ-?Y_Xh56Q9a&3XI1gWh59O7Ah= zZQcvL@Auy9{kZo&?`OPU@jmJOiT7pi>vW<=D5WS)0&--isDgS!^$^PB=?!M4}jsG_PC;eZ{5^ zSofu&@{B$`@+@3o7wu@t#@S4XBg@KYzc)@XNwr33sgrPH6}MlMy7k5?E0-*KPR1K4 z8q{PXb%?o6icMDf#w??(qb;GZrD#@T8yU??1`d*Mq^OCL6X=jU5Ffp3)S%?`{f-b= zUpC(yT*whe>-ZcKK98zWTdaD5DZdOJ4pcf?f%F;?*gzuj*W_mT2F zF|C}flPbK~Ql*5r|D9GGi^)0lW+iCkh@?81X{7cb!`4`&ZjE*3n8+VO%oHMxY&)Q+ zj?$fJSQ|G<%-R)AL*fb~{!Wu`6{++X-?q|2U(5?)lTVr z70mu&o*$&etFzqqmRJpB&*jWoi zj-Q7VS@h421#cCr;y;`l@UcEW0b)C0I4O}lf zZn;tk)`CW>>Xp4}z3R13-`%?RBd>^lC@EH&g?3mDoVet0Hr3=0!}y-C&3-DsH`imK zk^_wVUUHO!JU$k7lcTZoVNP;7>_>%4yzsA|=%SF7q9nK^>7XE?!9Ssfa*KqUB+sa{ z*umCFzN->%<~gH;Sf`S%TtC@Yd2_Xd^Cl=$aXW6zmPAe=GrMsswW`;-soAAL>q z&NAdFq{vIi;%-o%{9#nQGwei(oA32|hz6FC`7l(xt9|dU zyt43)im2FPL$3}%s*{LgRc7Xpv5}!8=$W3m%d}cbtI-gCvsFjBsMKhhJMM11=vQ79 zy~ELZ=gV$Ua;j;fbtu#rTFG*xq{MDp&4kbxLQ(U(F`S= zn@=UZEVG+!W|1;W$*fkox>}ldR2lZ~iRefWZ1?lpreZ&SU9r|Elnb>=(FtZN&cPQ& zceURC&cdrVV9Z2SD^?nXmo}@yFsl4Y8X=U=&;T@|YPu9eKhW}K76$ms_@&#uQl*Bm zM5P?qQA)gyB?9N;e!{sk)q3IAUl^Tk{nR@Oueza7HuN(sDaO7B?{gLP{!Uc(@|LRu zIQ*Xf==J7JA?2X(^89z(f`yWSjb=P)`a@I8&`%qfYUg_eOWqM$xNP6i3Oes>+=tac-3C zUq~ADADL2*eY9zzc=u8ieSgcH84mE9@=Leba@0!Sc{%hHQ%snI&fS$p0|nIksYfj4 z@zqm=qQ*RdH#F7`ECs<}d8KmjRQ;}7nlrcc z+p}nI?b?}-cE_vj!ph!-*6i+sVY%Nv^Wp8-yOZ^eePKTw?^`JpPc`mtx8JJhwGm7) zk2g#-yZb=x?&}b>q_MPXuGK1a;(l{nD>eKmovk%5 z$9=?kZ~He&r2)t9l?ug+cg<}_VavRU6F+>EhskBMjr~C|&gu$Bv}>Q*e)Y%|3n~|? zmvgE+K9JUj)O`VSNYvkB=;d6#Bir)&p?%>T^x6fz>USA>ZKd%mN+Lq_QqkU0&e`*w zrq9YeFN5deZ_jSx9p8u2I2E;-OE^nTq`VYUp=enwirnnE6W- zJ2^|`i+k|qe{7v<+||0RJCCnil}8eCD!Nznb4! zqnB@2Ms;&8+fmX@wld)^>h-&(BK>K-zIeeJo%sh_qt@5Yt5KqQ)VHhk*E`DD(LDX# z)0QclhI)@_pR+2&QvX@?nKn^4`ajb`wMT3qN}+wutxfL4L;v>BJHkKqUYqOXuE;$j z_uAY~p!0vu30cFs%DKh4-+71gapzB+uX9?#vio@Vx$f)T_qiW&KZBugmff|-y_>xI zydU-6>wVDsg!cvSFTKC@9?FmNm*D60-2Ce}dHloqUq^%g+x!`pWONAYvVXDvME^Pd z8~yhOpAWtk<~T29IhXTU#xzT+TA55xKFxX2$8pKAPQx6EZ2^{H6W5$h-pT+RXOOV9 zn0y@l-P0N}Is}WPV+BZw@kT^tSy&lM;qbJt_LvhY;t0oQ^ek4Zl?w~mOWWDVBUx+h zCj0O^#?Uy`%%q3%bU|^9(G)L4dL6}Om+}JTY)u{KyX97^JpOVMqK^Oz6HhyPKcwj>~Zcp zOE{mf@xZo*@!?RTdG_3_bE2vtFA#T0h@IbS%y33KLD-F!1{}3FB|zu1`{LOzv$)2= z`(fjnVUJeWZ$>%xeVb7)!_B_*Fn&(^qC9NiBMk|b9eKGiePo}EN@NpwrOIlolz zZR4nV0mkXkFlOZ`-ckVxQUCO#vanx(iw@`JH z&SGbNg-toVC%ndQjEAE!?h*AdUPKN5Ig|Bgo>SA(qtBQKO3FV+2||_9VS4bbIUE~@J0D?=dq3g&SI|H&SOAuIa6vSG}<$s!HGOcnzV#a zD>?Hgtdg$7g7@!7=`y7N~E zle24&p|27>pY5U$ZU_bDp@5pDJ6EFqKc~WHhV{U?C`oGZVdsAKC8P^`W@(7ZJPpCY z;>n34$!t;?%(mR;og4i=PJE9#^Lu9E*$Oe*+M>H1-+5W@#uN8VSPhP+L`gcM-u$?f zzqYn5HlE_a572JK}cZ5M#MvSR+2#Ck*_?t7Nmvj~^1z2x{!9heW!?1}lj za%Zu-u#1)SR?r+TEH2lvN7u)T>S_VyE{;vWG6Bt?hc{Sh*Mc1=8OwTREb}J!zxc%~ z$M*FLEJhc*&4dBccb7I9AaT2i=FEucySF9@qg2-U#kj#UZ|Sm1l=n)l`LvH4N!Y&b z@bMeFrjYUf9Yl}c`1b$Pm^wdGY4_r|*RG@qcC%Y=oG4gA3;1{0rQ)1 zmw9eLOqRk|=DSNfTOsheHy*#=xpaL(_hM4cW^y}|enO*?hFh1pyf=i%A5!ee1u_a6 z-$83Kx$S7prLJ1j_d7Qof63az<(m)EXMSgxt-tt!h~eD-?b+<%5&PC#W{2>qxBGeb zt>VBY`i(j`b(Y)nusALu?(JT6I6u2k_cg4`exH63fo5tOE(lO$_r+WsKJ zB=%1o*XQ1IhdaMK_xpHK7O-zGjBeLBIJ-~_m}N?p0ta6ncK&=P7hH%K-lH1hyt^_$Df96w$(JF0Cr((Wx<<{HJNoB;qd(KZ<`1eqeLql-4V&|Ev zxUB62!67Zual_^!L$uk>a`RyNBAnnC*Ieua^e127qB_n!IJ zb7M2~K74dG+SvZKgA9);^!FWGS-F_;mBTJ@LgdgiGm6iaXBfpbn=IE&8z9PRSi`GK z5$0BAHZIor7+I3!#NkIuz+7_i%913*9Sr5v`ispex&{w3&MVWR7=N(T4CBrDDHh30 z`S1x-B)+;JkzBknvogo9|1j}qdq&RDYnwn5+AcGqP5HLD*sqz%re~Snc^|i&;1pXb z^otJeE~jQ=b}%y)a?Z-^sYiIn4V`NbebxVzH_UyLopc(=q$8sKNP)5chwRUlPRYiA zL*cfzPG1Pvo69CIUJ{j4l<}3?N+u0T8&9Mq>I!wa*b@)`dZV5ya2Sl2rC;LaFOvcK zu}QA&2_^tN(3k|+Gm>RXk&2w{y_E+2zx1CS`4rn`ukIFN7_i!b|1P$_7PuTkK7)mP zGM8Yn##QK<&#cbji;Bv_u)}{gb82t6U!AF?F22Xr81GvaHMRfNTe*HOM=uaJZZhL` z*ZZR@mhg8RT{6=@I$))+I;i3q*Wc{-)_ZZi&_CSAj|x$ZWjK!fVY4{*1mR1IXIY`Z zc|drwb0TYa?HjKf?s?i%@v}uBZuO7!I7~KbMBP1Uf$i%HwLEv#U~zA;9<0sxK{ame zOSwRyyT7~oq}ASmZn~%0+SOveI#cirTleK#>AJgdkHz!3=r?c?#+`~QUF2C?(FGh# z=kQGdM?@|WY8Fy&rdsadUWOwtSGE*`+OSrgPh5`6sRYfHI{xWytyhS3P(-7JQ$3q% zIatCREx>W3faRbnf4iU(RR?&i=`x^7x7%a;Xj1O;26Xp6Zg(@D(dim~IgJW&HLP(M zXxLim#H>>`5u5WI5EUn^iuvVUxzvfOO->wgOS8E4v9Qd>{zBX>={OT4i-eP}_M(&F z5thT3>%c>2yk~o3{JI+WbnVKm<~DQ3IVtho+=uYza6N1;MjPwb96~lOxC%(kh8EoN zLvx;5n#Ef(4nv#PA8AwG42tZ?M1`nkw&`d?*&&$L262pp-t2cUlN@RjUr%i;B!{qX ziGe-#Si+cxmU)Nc6T7fTs6N$dlZ4k$ZHP65sQw8#Lh&+Ko+yX5drQ6$EJu}S5G2vT zGjCrA%E7AhcISuA-1S&C4j*yuVS&v5)=x*JD8Ct1{5R2%m*9oyw!GqZp{vbRYX@;1 z{HA1F&fImb_q&TLjndMtrE*j#cMoq|8yDKO+RE;6rLnTuLpB(6{BZS>E9WMMn(@L~ zzYyTpS4tb;JiB({qP>CNnM;HC@&oNdM-KPGPOE%>aq;-ovkkX?`0*$9RckZyQ{8*y zaAob;Prq!lbonhW_}=I2#u>1JZDC>cqRj&d>$!#EtZp_M9edo`i4*RRa;nNAE_{6) z1rMEh+X$ai>UievGk4uc$fk1_4wT{habP?Q1H6%y_(#FTUrox_Gy9K1?;w8P-})E! zzRX1E_e;rOZnhNZTzRxNoO|1I>%AHWpHv&oD4v@iR=T^F78~jAQ7R9l4mBEM4*%uyu-<%O;R#Q9 z%HEZyJ>%wU*4cVqh*ytae#u7ViJTMWqb~&c{^CNRv|`5LF9i+ndz^#ZH%j}OG0_fh z+9kF1KQU*EV58(T6!uy1jnRrNX+&V_l^t$5`GETgQC~{~S^Iytd#`P=> zVw{? z=#=A1kweam_wXFUv}2s0+pSh>c3%&E3mbSM!}4_wQD(NlKfT!8i%=Q1@l|&huUIN@ zTuNI$GgZ&uGQb2#lY&n}bq*{_;_!$(i9?lEo

u$FrTv*e$4WDs1l)(lF(hkk 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 aQwX;Q3YTj~5Wt;51nvqNz%Yo0%l`{pxIU%; diff --git a/files/mygui/Oblivion.ttf b/files/mygui/Oblivion.ttf deleted file mode 100644 index ab7e85e745858a629bb030bb21e1466255e12225..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 55364 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 veh2)udT8+*>Opk~_#3qV{Han+D diff --git a/files/mygui/Obliviontt.zip b/files/mygui/Obliviontt.zip new file mode 100644 index 0000000000000000000000000000000000000000..af4f809fd846cff444d5b1f09c7e86df1b6207d1 GIT binary patch literal 138502 zcma&M1#lffj5cU?%*@Qp%y!Jo95XXBL(CL2GsJAiF~s=H%rP@F(=)wy*?;%H+q!viC{-o}ynrZc@C5@UQGz=ode;l$u!&(1V%i!+7UboY5g5@c(-^DHmrtPYo+GOJyroPhZahy&D&zKNz2+BCFNja*&o<7ga1y)@JHArx(y$FNMz&mCBFb5~gDY?!e=_={$Wl zU74HK7Va{|T&9L@*0U%JOI5P`L^hM|z~=L6cW(>5;GEC)ko()kr_VuiKSjJ@*ezDF zMzY{k7qWIibP$sP6=l8FZk(&-=KY>rTGC%{$r7|54$MwY8JXYm5KT!HZW0hYLtcJB z>9~{czU4GiYQ>Rm3VP4ne3eLE#cE&I9m+@=b5iINxG}17;;C3zT3tWufQ6}?%iKVA zfbirQC7fl1qC)Mc(^B^7*<&cI$Ri9vm-b54 zfFq_h2VPp~E2DQrGH5EV?H1kRP(8m99Buy|>sbga%7x6jD~gMpVrFrhnDUE}*Pl)3 zr&bb4l4(`r>7Dg(jlQNv*o-q!O4TR7YjG%U`=~aGUmX3z#4I($lZZ|Zn`?-6#aS^A z<)2X?H!97<9{gJpTk5HG1(SOY7Kr8fkvq-(EhWkPP3AN!#dCHs(ZKdz=~FA4B*2!E zdE;1L@j1C`@mD%i79<1nlB!}poklMP;e@{#`QuWqLgpm$g;V`Ahj_1dOu=8y$8WII zYU&?mDJ_G@rC1UsgTl%@os+UGJ(&b$W>Q97VF7qX6Pva|k#Y9$+!@claFr|DOR{c# zh&DVaFu^>k6@P7vLfK1vaeEjABs%LhlW>yBfHjQ_Y@4UG z?5Q*~O7&i8gB`De@gVfu44fhkaol1*=Y^>8VpBJyBRNN z++V@3{svq0%e092gNM!VO)zV0du!1J)U20HE9ol8Nxd_#@65G-bUhL*m z{6L*iQIV0n0UjZOIw^x#_sM+~m8OY;ka}_*(Z*5j*GEz1dXI8TLOAqC@ zOq*o$fmhaHyhC$W7ACG@?8~CNnf*@j$>{LlcCPudLtZUJBQvgT=2I1YrFMLIZws=w z6h%OV58c^1?mYyBd;K5J3E`EEO{CuYw^T-)VA^d6BeUCZLD%>{!HkWa!YTsUUkmtw zfqo%f9iQ3J*#CWQEfdVfx*bGkS#cm zzsk5fHxrGV*#@;3*Cp9u5Dl9H&w9Tej>(*l3_6*Mt27$>&4t}46yLCa(_P7r#9p6{ zl00A4e8Z|o=`@7E!zojIA_gtj)_cG<=s$nb+OS@(n+@}h99OM0b~P}K4F9_H66tO0 zRWah7zUG#t9H~CV!cd^YC`m~ZFTkZ6{4^b^Avr{I za#}o(C#bpawO`ju=N~pN(NUWq_g4GqM!w^PHfu1ueF78MxAXFu=5Z5r)w&YA{IU5E z6fpA8t>`$fh3vx=o#g5B4ZJ$w}UOxL_4L$X9eO{OAo3 z0mmr{v%R%5HT?PLO#a;1yYVwlxS2+4=s1fCc4=+zf4FCA4(>kdY&UK>%x`zO?`9r) zaq+uY+Thy~cyAmLZVYHYDSF+{AZl29u1)sK@;5%Bm{kNlOeAKx0Mn2_XIy$dgu!Co zG`L!>N??B;@vcwdOGAlRAY0GP`y~<@iHPqb zbjC(F6)@XR6g;q~`%(KL(hJr;YIBbTb%kbqO9>w6T6mSdHj4qyTH-utKVYyy`Qn2` zxXOG@_CMp6cxs_}>t2T36eB?(jsmyX`E%1VnsJ>m4MDnasxBo)Ta~){yrRl+P9Cv%bBFL|~KE zH`@9!XZaSXd+Ixc3!325#rsgSc$Nd0>=$+4~&+TAo1MktL zqb+2zmG9BS<0@)8ug&5osNLcN3v;iiC^wLI-ll)d^8EX zdNQ2Z04@_X_I~(phjhJi53zMl#md3kMN6O+R=Fi=;1PROoStf6pO)i}7oNwRm zf~mF}pLq`+WNxnX?r~j&jAus|61SC$gKv<#od>{)K$&IzeU=e$#Ws{N*qwPJX04=1 z_G*-^@o;CJ&(L@C;#GIWJR$goGQnRU(-CmbB7D9C?EA8lj}i#&^5W0jhugSvdeblp z>dAPyb2rX=zC~o-ikam*ZL{iAJ>Y0K{M-z6Ig_*P;`6=Pb=!_QiU(%%LT>@6`o7OX zUft1>dQiE9B{@L{FDBO;PoA6;cDn%H@_ZG!4aCRO=_h@kmt@I1!~y9C1+^ZRt*i?U=2^+6 zvohUS#>ef?S$!8EvH+3BY~_H{*pW>RSnRB{f;+#0 z)7S@G4zlYu#&anf=j!o!yekU{enjjxxm`dDemDv-ymyfV^Aer-e%T?7o)^B+R(N#r z-Ux=L?yPcqoHy6W}y*AL&r>=3YnGb*T&fW0H#xlyw&GSs3C6_TZr4Fu{d0e^xCe~-{o11N6`4@qH(a}aIIji&s4!9^ipADybJJ;pwXy-1c zb0>b(&+bv*Du7Hp&&S5iM{wX6?%bVairW#sMIj+9r#Z zWtPJ#Uuf1)o8S_(bGG!t7pR9HWo$V&zP+!i-8Z6dL=R78eUH=gCV8q5VxEtN$C%6^ zh`>DAkocRVTyX!14@uB?<9@r?zzwSDD;40yZ{%`iHpTU0rc8FKkMy(Q)x+`RcbV*` zmu$#I$mwb02ac@Ct*!-82n?~s>tPxE^m{UBJ>;J)2+koVe2%V;q!r$PtMT5bjQ7c+ zZ%+2R?6Q5~y2tvkZxovyiAG)l^DfyZ&7d2Lof`fQRpOxW_q;MOo{gTIZMs|LPZZ}? zG7e>qMw|0N&V!((3r>e_`D1;TA7Zn4COJ1OH)5_ zz>CwyGLyZBs-8WdXJC8o?4nC^t7z&{OZ5*tX|ouyQV9Niv=Y{s1Ns57?Jx+S31)PO z%Lf41O9oTSp1Y7wIHKQLTexf?clC-)h$lHOMye||_tO_;pE?OEGHELgMo8=X7U>+f#OU(eW&6yw@Q6--{f-#b4>*BY`Pms+aq*6fMnEtlyhKZZp1zF$l#HF8?F|NgJE z2btO5x=%i6S|wG=f-UD}NBQ1JjSSn2`Y4V3AVhDrdY``+BufU%w!8IZGT`$knX=ry zACsq-m3H_QOY1dQGj-n2Pi%#Y#5IzO1#fSix{WL3L35y8Ifo^G<5AK*y;{9OFHau9 z&hy0Xva)&Y3;VggBpDl<`qW7Eq!WsnU-T39i5@BeLG=L>m(6}@CqAYsxxsFOgAKc5 z_N_9lQ4|jR-@0|0E&koc+sE6RPms~5fJEe}5cO?kX@1G5v0PoNq$TACGqXvW!z;Y-1yf61{d>$Hzz_%xdh0 zN>o7dq~O!i)wQ;!eQ|YW@6FrA;i~K7a|3kS0lqN_zP;h)w^<(BqKy=IIJK{AZ7rRa zf7*I3H;HXMIR~De0>XT}wDQvY|B?TBTCPZ1C+*Agu1QO~i-s;$@`0dr@o$5~G<)4y z?JVOB9xK;zeI_^+Tko%5{8bxQHa0foqc?_9L{@W>XpOsW`_>k!yhNq8LKY%yX>^J_g2}wxi$9grvIr@J%8?&Zh!LAYpq>d zSrm$m8k+G`wts&9%6gUa_tIIZfWzuMp?BP9u}YMfzS!9LZSw&O-f zaG`FV?-kn6#o?Ka{|u$}q==_=Mt*}p<07rx7b-0Z6)jwoLbR&y5qUR-+#SG2loMt_ zA2|N`)gqOrN|l23p*@wt<@~=QUiXL9B8yFiDJ68uMGGryV*DP*mv)N*@NYI#g`5E+ z2?UE(v$-7X{H^VU)*^N~_1<1q84V0vqM&}U0?yx;Q?;`u?rva9x%&{2tvt~n|DE4w zX;m}X+!gTeTs;C7>*>}1USAHU$9nm7e~CV{B$qX>4cg;u0k4lv2zUzAuitW_baOFw zZ=JbfFCyYs5nuog3b|cbJnnh(;;SR-ax|?uDF}825aDO@cpcZBaluzkpI#IRc$nUs zf)jEUn;arO7js8h@N>INU7yomJ#5%cP58NOW-bLDqKtV$meU)$1qB*;34?-`3_OS<}Xk z0AM*MJcl?(I43w~J?A~AGRHaxUEEU~Q7kJl8=4d<$STBRM?k&WIV!x+JQ^@fF?U<7 z*|VCz%OfFK%rR#_Cta*uoF^_M?h|nhE%HSWqQ)rd^Me$iDh{#=m>Ly)&Tc1$LJ4?B zf$>|EAGJ^#6@BpYU?V#_X;w!gdWwRD2SDET0Cb^Ds)3BVwV^^BmS|CzKaP%*!@zpM z4%hI#CU+)K;EMe|IFQ3|2+~J;Tpz>-?C^W&3j>Jq77s@Z<|Adl5h6tT4ssVd4h@P- z>x2DvFs={f!)bU28dSI+0td1g219+Y#gV}Wf4f5q3;78|*rh98&TT%vZ?-n^sB5QF zIj4<{KGg>8Zx`N2bp2lAi&!2)5yAtH9qS$;L6r+%gxHUX6-PW$YcA=-}>vb(iY}mLXxAqn+v1QaA}5 zN2vHEn|B2{mV|3Fmb-XMB^Sf@s$qK$Ky1oj7?&6=dh8hcG~47fG=!g#?mZKyx6Z8r%ip95yK9a$gu-HbR@NKxrKJ3tkNp$LMb?O7^9cFn^HyGG&lXtp+XT^PaeH*@I-Xg8rgt?kW4 zB|wL{l}XS9^u}7*1N^dSv+&Dw%JEWKP-~WXm^9D8*G43Y$m78qIOK4 z#9>oHZ8B(tnUBbj6@o2AacaB(C3o{dd`kPVF?@|_h?$gHSQU%N>^VbLkcKFCZrJqu zLCm?`lqRgFSI+Ktl2_Ukuf(Kcr7`xG+P5j`z^QJ_0rTTX7S35S((huwmQDL&rM62ItdaF+-N|ND!|q$fWX8k`cG2N(~uN z<&xC8eN(=bC9CC5{s9#amLC>Nj^gB4HI%tz_&Jv(#i{t%!2S#9w2@P=I`CDRtQ`V-n_a+ehfR774O<%YX1@nnKt6o_W@#K%7RP80ja{IL;cn zF;tK(+LE3`p74u(LbIvG{;#ZJ8M%)h85&Z`-%{)r`vxq&bk8@+YIMF`r_t^u=IU}i z+{iu1RR@j|?gE5L{d3HO1IhcsJ&{E#ZKGvCfMk{zqz}XO{0-ef5GRv#HxqQW zEIc~_nkgqKz*0DL+!rG441)FmQfUM_JK?_+Y8790>BzyHg$pa@>8>dXI! zrh-X4Ll8^lW2?6U8~pr#Hiat|RYK5(KKsoCl>@qGp+a=-oOie4$Y6ri?u>VP2B$7b z;adVWIlD&tt4QIC{E4To-Pr$u|0VvP!Q|zHM9i8<(lp7)F)A7oEy*c%cVDCx+xQ>8 z6N|OiI5wzWxjVsKuQ)c?UadPTKo&zV*KHn7{2PNW^evpgH;*HWZPEOrqPs*dK3-5j z^x-FO5SV>iOqdx+1t3!o%nI&9y6N&JCC+~&=uS;%mq4c6sQ zT})+7jGyB70!V_`A&$zn1Og)dT=^i*u9goJ$h>qexk`#dd%}oH@K2dOxqEqa6h}6i z26c-OiIBU$)kDZN9M<|%`8@@213bREnCw}5)uQLNrrRh?!ePHWWQMGAsySp=VhF@n zs*ea_2P6n#=VXerVxC0l8bkXpKzdf{JZ5 zb}Lrx=A8yZaQ08k3sjheayz5HA4>anu|rReCq{2!ftjud$NsA!5C$`SCw+15Jo{?9 z8`_;(!OdL!Hyn0m-L#F!!CLV|1gN1?;8L6+1h+Twe35cqjGE@Rv^dTLMWO|k(6ldb zs?5APH1SW2Z_2D6Ndk-pMq1(r_!&p*dP}nY$R=R3$hJnHaokZn$x_%Y;x0~{DvYT5-8g`b zDeCm1pwbuTmT}kys;C;+3TV_uR^JLJ*k6I}GroiUXI(qq{x& zcQ^oD`t9-y=aF}7Bkxw$F5H`y^IsQUYl*&n>RC?E+m*lqz>Q`1iqPR}pBbNRhudY%wHA|ZQQ;eX7C6e6RM*i=8WO`yo1Uk{XqT?f5^SmT# zw8){W-arvFDBpb22_Xa?DAbYda=q$cJ&!8M3}G7{C2mo?R2(m!C(ak<9eNG71@DjU z3E_$Vhcy6xlvvAx%)ZgF$|1$h~eE>!~WY5K~cW86}gU8SsrlL zLS2+PDgd?uPEM@kmm-yNBiK6ax7%gfn7`v-apu9S;)(}I(>nOyHM?Md;HNeu2d(Wj z$j8}9(F2st#~?T&nGD2k*{Dg$Xc%&EPE$@_dQE2CewmACeotaW&Z9x*?WO&lPc87O znIrjIUuVW)i8`6kPkJbKH7LVmrS4MVUa53hkC^!omM|@nD<9&QmibB`XQnKJ=i8UA zSk<|>&&Y5C*XggA%%9{`@pR*i40*;3wiV{XKWicvwDvXbOGy}>4bf<42Cm1`H z(vmp~FNxW%r)q2;g}*AJeqTPfpuqlWpRTbBn%^M~+RQ&NF$W3j{n-(M?gXkV_s*WK zx)9C{iw%K#WZ+rW4xTK|PswnRd-qWoNufwJgwcEp_hA7@*l1*_FEqX;rIRvYvN(N& zz@@lhJw_n)ZW?wGVqlHAnNG);rAHLiT7F6DG;ExFsea?C0*}p4t$(ul{1VJ* z+F{D2CgxvQzs6LU;x8ldo3YG?RK_TUDE@)}6#oOS;Qx0NsD;Y_PoZx~$NLiOc>OsT z-hbXr64$@ojm7|i-W5{|q`NJM6GQw^A0~qaW$y=s-Do@VY!p;jJBY$O$6n>Wpxr!x zhP!vVid!6DCpl4KDE@=SIRAeU(`0(YPv*r?=0$S-sA~>r9Y;VMK?F`-jd_#FVug^6 z71Y2DY;dD_2JER|&O7PDbHL3@f@r%#p1JsQJGXf0i3mS2fY6o$@x)$t1%cBta${E()6+mJLWF+fO^z<+%>X|Z=FT1pe z#%md6H+OIq7hX)^Vz$KoF`J2_y#L3Mi@X-n;}`kR$|DCxVnsBw&8Le#?ch2#BX zNCCnd3p3eD%sr;DlrXPD=uV_QqlN8nayX$rJHUkrAE0X?Do|iY#o=)bBW6KoYj4zI zsr%)$h>XVa6)s{#)lEUEX8>LzH9i;i@bCQ^O;m>Lz#i?eww2sK7}jycFF4CQdNd(_ z%B-W2=3FGi_^>w-dC3zu`vK_> z+dJadBX_QVF;n?;f!F`VLB0hLwoX_iq1t8Ll+MgSBbNQ z|5Y$TE!8>i>el`pTR+@wAB^^}f0mqa3HG!C560D(9C(h-xpi8c@^5i?qKm=;v4?BX z#@`8p#NcmEPJPrYdOUC>6Q5>uk$IN8!G190Un(NfQcr4Mak-V8BLwfIbb~P`gR3WlQ9c}o`(Q!!rUzz5svLi< zvFO`A1iXPa;BM$;4;>xbddkC3=6LK zFuX~Qyob&d7~99lRnHETP%db%yEQ(&Z< z4|*>CjbZ-4+2Jph>K-E-rH(ZkjWC^;Y$n`^9mT^is~e6}5!>#clRfA3{@u7m$u5(h z*L~u)Q0m%JGrb=g`Ul!=FG%k!%fK~HP`Gj%4P@`PftoPQeSJ(qCYbj=8b$jY&?GGR z92yB~s_KsZFj^lcj_3Kgde7uv@NH_yJbwn$-QB_&{zf;?A7B4LnBQWk*UcQtkqS>| zNGaKIXK0U}0rI13AkGz#1Y=f%;qk5MlzHOZub_T8qkQgJzN;=WvG-@Lj{Pq&c_tT} z0$gFP(OuJZ`TbD|`i3X=X4I!p==FZ!`B2aqyXLyo=FfXv*GSV-M=P5>8gkiyzbP>! z+TY(1gX=@|)0aPZh(};v>4%ob1jt79^Iz17(?9d5+rrb0HD6Qi`CtGvW#o;+=eTs0 zU;L!XzKoGjC4tB-isDx<#|>r~`#KsILyf2o-^iiEr4o)HyU@*BJ%^~Jw6P`(cY|_; z^&RoM`TlGX4Oq?=f0iZ753Lll_CJ~7xWhCAK|v<4ut45fT5nLs+#Vf!1;vn9Dq)1B z&}ZO1C6Dm$DHrf$uMKhx@{V?Cul(J6VtXY^s42*(s>uf2?Vr2B3(Y z43*3{!jXd$=ceSj`CZ_haWp?D!(yg)g2Tq-D7&T6U2CQGZ+;NcFynBYMr_!R%H2Y1 z4Cz{04cQff1wW@4O8@A`Eo~tM+1>!&azl-HQ+x=2r zm#i{KA6qb0K;7WT9j!kI_%kxco8^9cwZO4ZK3QxC3UyI2N0rzdNpvZ^MeEiIb~^C# zVrR#A_(OfjuSd14(WdN4AMxrh-d z$cZ>d7&UQPt8RJW-(PWfCv@1qyV2v+O4(sj=cp{$*(Y`ZFD5-14+S)<#)bQ@VV|;> z@ZBg@^mZso@uP@+36F7ipRaKfKCuJZw@ea8-rO9n!GhtqkIsNJ{mZllf;$ zMuvanv;1Ku9!+1L)8)8d)+4Ej4_PJDxM==qhA=&c$-&gNw|@}_4D|!SHKbYOdNO%K z)JEY{`J+F2O?^}U>d63+>6|0SywN)ZfL-m&PxvFi5s^fARs3;>AXj_1F{%)CaGcFI zOsyckqOxG0F?D2zZkgUW-W$Aa?H0#m$xXLKELJJb)V2khtGivXAj`adD0~R+-@o?2 zw$~U^c1u|FP+KdEn0O|B>^&)d5rOZy5jYK+mADB&_22QBdoPUGe)%tzjYa;yp-_}F z_egZvM|jc@@w+CFV1*`o)a~F#vdympoo@x?4Z)*mD>r)kZzN*h`YbXoeCpgk?K3WP z99cX*rNy&MU142v%^k{vH-F3{fPv_TuCj$JEZ#}}-u|?}Ud+OKDNn5)|ZGup`H~O(U?uWlhR6u7Ct|HyNvmwrWBfY(;9=onzu+ z(q@c!XnkZGMAOXitH?9ObLd%!$KR2J`D6;q;^IW5bC~N_^1hh?cT-;(QO+?LCd^Ah zFyvELMQK=fV;H2k_bx+gjwxI48Pmd7^DQ~6kA}HRN+>Chk9g6=4gdkf-$W8_O?86S z{e-s|#LhF+Rxrwxr$uM)bI0qj*Tk^|mtwj67A-TIV`IYusefV;^&>CI$?c8F?|WCx z{fyGzGn6%9=L3>)mmMp<_Xr8^P=DZW&o|E+9!{SKgg?v%hoa4fe@wE=TSBBsJcu)i zJBVM1=Sgfx2uXB_qlG?)qlVjO{Sb&kp^5dumHWr}2)NOHL;Z&PjryD5H_30T-$;)T zwrr>5r|NTD#Z=@x>FE(_w1%Z-)Vlw+wZ^hu)`DF+V+$;LomSb+vFxu>arOLp{QGry z*}BzOrex)Ari7KlB%wuqf6PCoYDorp=0t?IMNH{R06CFgB)Olg8KZ2^f7re;?ka|{ zX@AJ<@-gCSV$;&QF>sHou`j23XazdvkggVs8$0p!*FKsnCgBS$C^mNFMe#^AdIVm;bh`}#_Y$6HcnJMILD$Mlp!0o+WfN5Y5r63E77`mA*@W&;#YtHC|4K#vhMl~mb8jVQg@VQAIbuYfpP zQJRP#nXlHvao?ryGo}*K)raT9TZ`@jH zSoV!RcI&VPFUJ)(Y3aTD?2hdr*m`E?=E=X;M`$*uC#ku!{Z_pN{NjDXobndpGP>y} zbUd@c;j^9e=fQibpxxrSo5bVfDqHCPqq_M|J9z?UMx@vQy+?V1x;iUed^YFXg(SS& z@mk7EiEMqk;MR>ASK&6cu3uld!^eSM7#S`vx3yJJ~6hza#>r@fyw*H&>`RM zs=~zTfvREPbkEI76>=2Ka$nSGudVna=A-i}6brBA?YoBreo2Zv{n4FG+`Q7>_0_yI zr3)X)`V#)KNoxK-PC98Y8klWkQ)A6T<)umTy(fAlX@U=&#!7g~R0If|+L$5s=~>yl zc9q5DCaUSg_ zsUlBIyH zI=d>v(A|}uithruT?2&MCBm+~OKFbU$^D*E_(mb}BzfJr_!wZQZ@PXp)Zd$rcXSg5 zHnvAAH~v4w7UVq6mD{S~S^=TYR)Wt~o!40?jx@qB!sWiCx5C4`ldfiG!legXll1zB z7HUEAgdh0dS3*J!_lR{DD7eSGQ)WP4=Fj<>6mNw?U?Syj_kk}MUS#8N zV?Nk@;m9$%d7hl@WA^iFnZG!rGTDd}Qz2CCb4{=OOOpcU{ZH50TVkj1G>{Q7)$(uu zGK^p4LytXsAvhuPZ-%GxBNG)}&ceosqqoeBnxQTKD}T5GUN78ATR6~^^T;oV4taFU zJy@!Tz3DgzWAXKANO;Ov z{85h2^FC%TUuK3sx-(8rJU9$PNKA~Tih8%3(ZVGF5B$S4g^JCw*zJ7Gt0S4DWX^((?X22&paB=KiNz^<4*Z%Bk<#+ zg*!DQ6Khx%U+6$t+mY(cMnL`JAr4tg>Elp~UgM{sl*AtN5Tdm>LFQ{S%gl5$)kx1> zv&ZH)FMX12%2-yR=kl!vTD1G_x;$?i*C!D>@h;zD?v*(+*%@axBaND)Vba(w3EjgO znK%?v0#F9lnj#wBU5Wa*g$eJn^9%FrK#n{O0}1h4Ryw4)cCI$Z#WJJ1wE}dH9u_n& z&HWV4gN8a3gGj-`*%)(dNqD-JEyM5Bxyu}&J=Bt3N2F5$#s)$vx`wB+jrBxH6lhu| zs$<{5{Tn8n#@^7$Pf;^?jy#UFlpH-ibp@s)c@ZQFbxdR;(cz$>zPSRvbRztd*j2o7 zUj=)ov1iDgkCuKwGW#7f|)x` z>SlEvg}-SJKS^z}m7aLuB(o#6Jxh1W4kxhI!4!qpHvj2x>*{QQX# zZ8`oW`v#ua6=P{UmRcWT9~F~ILD}B;7gZDi!HQ9JknO z)i3W`GrH`n!CaG|EOVmOXEVB{t3eghjp#`L?})hs`Uk=8EPXE-FnE~PA^G`uCk$+K z=K+{y_*W*I#Rk*ehA=Ke2#n+^jp{`l;ya`eTjb3Jdl1O=^TVLxD5}A(F5&e=zvc#G ztoW>U<=?UE7luW@YU%5)Ho;^CXktrF-&HcTy<%rUyFhFguj+XH*{nWy|D(Bd0iae{p0vF4RSssvw3A zUn+h><`h_>a!cUIcG7H13&r?;czwTC0jHB47dx&t@Oze+;>$UOVUk>6m3+%gctFI! z5H%@FrY|?+(N{=o14(8DdSm9ln{Jb;jCHYATC7Z#K0#yO%f@C3fq3yJhTcMEnf8D{ zrs}tCdvDI^wN;}EbC!MAM%ksBj)7RC*qKqt`#BrVHflV?82*P^K`Jaw)`u!?LWx(M zg28GA$@tWhSd?h#FK`>5(B>@IkaU|⁡xddcV`NI&{-&A;hf~zQpRC??m3?0ZBLV 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 Z|2M=R(QxzpFvfG(^Em(jU#TDd{1aQG&olr4 literal 0 HcmV?d00001 diff --git a/files/mygui/openmw.font.xml b/files/mygui/openmw.font.xml index e93c9b770f..252499a5f1 100644 --- a/files/mygui/openmw.font.xml +++ b/files/mygui/openmw.font.xml @@ -20,8 +20,8 @@ - - + + From 8a9e05a96b73e47238084305f456a869ecc9abe2 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 10 May 2012 11:03:27 +0200 Subject: [PATCH 099/325] display text on the book window --- apps/openmw/mwgui/bookwindow.cpp | 84 ++++++++++++++-- apps/openmw/mwgui/bookwindow.hpp | 10 ++ apps/openmw/mwgui/formatting.cpp | 132 +++++++++++++++++++++++--- apps/openmw/mwgui/formatting.hpp | 7 +- apps/openmw/mwgui/scrollwindow.cpp | 2 - files/mygui/openmw_book_layout.xml | 11 ++- files/mygui/openmw_journal_layout.xml | 4 +- 7 files changed, 223 insertions(+), 27 deletions(-) diff --git a/apps/openmw/mwgui/bookwindow.cpp b/apps/openmw/mwgui/bookwindow.cpp index 75be6280ad..8de45984cd 100644 --- a/apps/openmw/mwgui/bookwindow.cpp +++ b/apps/openmw/mwgui/bookwindow.cpp @@ -7,6 +7,8 @@ #include "../mwsound/soundmanager.hpp" #include "../mwworld/actiontake.hpp" +#include + using namespace MWGui; BookWindow::BookWindow (WindowManager& parWindowManager) : @@ -24,20 +26,57 @@ BookWindow::BookWindow (WindowManager& parWindowManager) : getWidget(mPrevPageButton, "PrevPageBTN"); mPrevPageButton->eventMouseButtonClick += MyGUI::newDelegate(this, &BookWindow::onPrevPageButtonClicked); + getWidget(mLeftPageNumber, "LeftPageNumber"); + getWidget(mRightPageNumber, "RightPageNumber"); + + getWidget(mLeftPage, "LeftPage"); + getWidget(mRightPage, "RightPage"); + center(); } +void BookWindow::clearPages() +{ + for (std::vector::iterator it=mPages.begin(); + it!=mPages.end(); ++it) + { + MyGUI::Gui::getInstance().destroyWidget(*it); + } + mPages.clear(); +} + void BookWindow::open (MWWorld::Ptr book) { - MWBase::Environment::get().getSoundManager()->playSound3D (book, "book open", 1.0, 1.0); - mBook = book; + clearPages(); + mCurrentPage = 0; + + MWBase::Environment::get().getSoundManager()->playSound3D (book, "book open", 1.0, 1.0); + ESMS::LiveCellRef *ref = mBook.get(); - //BookTextParser parser; - //parser.parse(ref->base->text, 0, 0); + BookTextParser parser; + std::vector results = parser.split(ref->base->text, mLeftPage->getSize().width, mLeftPage->getSize().height); + + int i=0; + for (std::vector::iterator it=results.begin(); + it!=results.end(); ++it) + { + MyGUI::Widget* parent; + if (i%2 == 0) + parent = mLeftPage; + else + parent = mRightPage; + + MyGUI::Widget* pageWidget = parent->createWidgetReal("", MyGUI::FloatCoord(0.0,0.0,1.0,1.0), MyGUI::Align::Default, "BookPage" + boost::lexical_cast(i)); + parser.parse(*it, pageWidget, mLeftPage->getSize().width); + mPages.push_back(pageWidget); + ++i; + } + + updatePages(); } void BookWindow::onCloseButtonClicked (MyGUI::Widget* _sender) @@ -54,15 +93,48 @@ void BookWindow::onTakeButtonClicked (MyGUI::Widget* _sender) MWWorld::ActionTake take(mBook); take.execute(); - /// \todo what about scripts? - MWBase::Environment::get().getInputManager()->setGuiMode (GM_Game); } void BookWindow::onNextPageButtonClicked (MyGUI::Widget* _sender) { + if ((mCurrentPage+1)*2 < mPages.size()) + { + MWBase::Environment::get().getSoundManager()->playSound ("book page2", 1.0, 1.0); + + ++mCurrentPage; + + updatePages(); + } } void BookWindow::onPrevPageButtonClicked (MyGUI::Widget* _sender) { + if (mCurrentPage > 0) + { + MWBase::Environment::get().getSoundManager()->playSound ("book page", 1.0, 1.0); + + --mCurrentPage; + + updatePages(); + } +} + +void BookWindow::updatePages() +{ + mLeftPageNumber->setCaption( boost::lexical_cast(mCurrentPage*2 + 1) ); + mRightPageNumber->setCaption( boost::lexical_cast(mCurrentPage*2 + 2) ); + + unsigned int i=0; + for (std::vector::iterator it = mPages.begin(); + it != mPages.end(); ++it) + { + if (mCurrentPage*2 == i || mCurrentPage*2+1 == i) + (*it)->setVisible(true); + else + { + (*it)->setVisible(false); + } + ++i; + } } diff --git a/apps/openmw/mwgui/bookwindow.hpp b/apps/openmw/mwgui/bookwindow.hpp index bc017e326f..fcea1d11f2 100644 --- a/apps/openmw/mwgui/bookwindow.hpp +++ b/apps/openmw/mwgui/bookwindow.hpp @@ -19,11 +19,21 @@ namespace MWGui void onCloseButtonClicked (MyGUI::Widget* _sender); void onTakeButtonClicked (MyGUI::Widget* _sender); + void updatePages(); + void clearPages(); + private: MyGUI::Button* mCloseButton; MyGUI::Button* mTakeButton; MyGUI::Button* mNextPageButton; MyGUI::Button* mPrevPageButton; + MyGUI::TextBox* mLeftPageNumber; + MyGUI::TextBox* mRightPageNumber; + MyGUI::Widget* mLeftPage; + MyGUI::Widget* mRightPage; + + unsigned int mCurrentPage; // 0 is first page + std::vector mPages; MWWorld::Ptr mBook; }; diff --git a/apps/openmw/mwgui/formatting.cpp b/apps/openmw/mwgui/formatting.cpp index 6b50fd04d0..e031678aef 100644 --- a/apps/openmw/mwgui/formatting.cpp +++ b/apps/openmw/mwgui/formatting.cpp @@ -11,7 +11,7 @@ namespace int convertFromHex(std::string hex) { int value = 0; - + int a = 0; int b = hex.length() - 1; for (; b >= 0; a++, b--) @@ -28,43 +28,144 @@ namespace case 'a': value += 10 * (1 << (a * 4)); break; - + case 'B': case 'b': value += 11 * (1 << (a * 4)); break; - + case 'C': case 'c': value += 12 * (1 << (a * 4)); break; - + case 'D': case 'd': value += 13 * (1 << (a * 4)); break; - + case 'E': case 'e': value += 14 * (1 << (a * 4)); break; - + case 'F': case 'f': value += 15 * (1 << (a * 4)); break; - + default: throw std::runtime_error("invalid character in hex number"); break; } } } - + return value; } } +std::vector BookTextParser::split(std::string text, const int width, const int height) +{ + std::vector result; + + boost::algorithm::replace_all(text, "
", "\n"); + boost::algorithm::replace_all(text, "

", "\n\n"); + + const int spacing = 48; + + while (text.size() > 0) + { + // read in characters until we have exceeded the size, or run out of text + int currentWidth = 0; + int currentHeight = 0; + std::string currentText; + std::string currentWord; + + unsigned int i=0; + while (currentHeight <= height-spacing && i', i) == std::string::npos) + throw std::runtime_error("BookTextParser Error: Tag is not terminated"); + + if (text.size() > i+4 && text.substr(i, 4) == "', i)-i), false); + currentHeight += (mHeight-h); + currentWidth = 0; + } + else if (text.size() > i+5 && text.substr(i, 5) == "', i)-i)); + currentHeight += 18; // keep this in sync with the font size + currentWidth = 0; + } + else if (text.size() > i+4 && text.substr(i, 4) == "', i)-i)); + currentHeight += 18; // keep this in sync with the font size + currentWidth = 0; + } + + currentText += text.substr(i, text.find('>', i)-i+1); + i = text.find('>', i); + } + else if (text[i] == '\n') + { + currentHeight += 18; // keep this in sync with the font size + currentWidth = 0; + currentWord = ""; + currentText += text[i]; + } + else if (text[i] == ' ') + { + currentWidth += 3; // keep this in sync with the font's SpaceWidth property + currentWord = ""; + currentText += text[i]; + } + else + { + currentWidth += + MyGUI::FontManager::getInstance().getByName (mTextStyle.mFont == "Default" ? "EB Garamond" : mTextStyle.mFont) + ->getGlyphInfo(static_cast(text[i]))->width; + currentWord += text[i]; + currentText += text[i]; + } + + if (currentWidth > width) + { + currentHeight += 18; // keep this in sync with the font size + currentWidth = 0; + + // add size of the current word + unsigned int j=0; + while (jgetGlyphInfo(static_cast(currentWord[j]))->width; + ++j; + } + } + + ++i; + } + if (currentHeight > height-spacing) + { + // remove the last word + currentText.erase(currentText.size()-currentWord.size(), currentText.size()); + } + + result.push_back(currentText); + text.erase(0, currentText.size()); + } + + return result; +} + MyGUI::IntSize BookTextParser::parse(std::string text, MyGUI::Widget* parent, const int width) { mParent = parent; @@ -92,7 +193,7 @@ MyGUI::IntSize BookTextParser::parse(std::string text, MyGUI::Widget* parent, co return MyGUI::IntSize(mWidth, mHeight); } -void BookTextParser::parseImage(std::string tag) +void BookTextParser::parseImage(std::string tag, bool createWidget) { int src_start = tag.find("SRC=")+5; std::string image = tag.substr(src_start, tag.find('"', src_start)-src_start); @@ -111,11 +212,14 @@ void BookTextParser::parseImage(std::string tag) int height_start = tag.find("HEIGHT=")+8; int height = boost::lexical_cast(tag.substr(height_start, tag.find('"', height_start)-height_start)); - MyGUI::ImageBox* box = mParent->createWidget ("ImageBox", - MyGUI::IntCoord(0, mHeight, width, height), MyGUI::Align::Left | MyGUI::Align::Top, - mParent->getName() + boost::lexical_cast(mParent->getChildCount())); - box->setImageTexture("bookart\\" + image); - box->setProperty("NeedMouse", "false"); + if (createWidget) + { + MyGUI::ImageBox* box = mParent->createWidget ("ImageBox", + MyGUI::IntCoord(0, mHeight, width, height), MyGUI::Align::Left | MyGUI::Align::Top, + mParent->getName() + boost::lexical_cast(mParent->getChildCount())); + box->setImageTexture("bookart\\" + image); + box->setProperty("NeedMouse", "false"); + } mWidth = std::max(mWidth, width); mHeight += height; diff --git a/apps/openmw/mwgui/formatting.hpp b/apps/openmw/mwgui/formatting.hpp index 19b6969183..c8f2c9e445 100644 --- a/apps/openmw/mwgui/formatting.hpp +++ b/apps/openmw/mwgui/formatting.hpp @@ -36,10 +36,15 @@ namespace MWGui */ MyGUI::IntSize parse(std::string text, MyGUI::Widget* parent, const int width); + /** + * Split the specified text into pieces that fit in the area specified by width and height parameters + */ + std::vector split(std::string text, const int width, const int height); + protected: void parseSubText(std::string text); - void parseImage(std::string tag); + void parseImage(std::string tag, bool createWidget=true); void parseDiv(std::string tag); void parseFont(std::string tag); private: diff --git a/apps/openmw/mwgui/scrollwindow.cpp b/apps/openmw/mwgui/scrollwindow.cpp index b1c5ec3373..38e2f77c17 100644 --- a/apps/openmw/mwgui/scrollwindow.cpp +++ b/apps/openmw/mwgui/scrollwindow.cpp @@ -57,7 +57,5 @@ void ScrollWindow::onTakeButtonClicked (MyGUI::Widget* _sender) MWWorld::ActionTake take(mScroll); take.execute(); - /// \todo what about scripts? - MWBase::Environment::get().getInputManager()->setGuiMode (GM_Game); } diff --git a/files/mygui/openmw_book_layout.xml b/files/mygui/openmw_book_layout.xml index 36f93a067a..07ebf5030a 100644 --- a/files/mygui/openmw_book_layout.xml +++ b/files/mygui/openmw_book_layout.xml @@ -20,8 +20,15 @@ - - + + + + + + + + + diff --git a/files/mygui/openmw_journal_layout.xml b/files/mygui/openmw_journal_layout.xml index 906e872976..75bb5eea17 100644 --- a/files/mygui/openmw_journal_layout.xml +++ b/files/mygui/openmw_journal_layout.xml @@ -13,8 +13,8 @@ - - + + From de995e3a69f60c9bff28c15ccfe3f9cd4c3fcc67 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 10 May 2012 11:19:22 +0200 Subject: [PATCH 100/325] adjust topic list on window resize --- apps/openmw/mwgui/dialogue.cpp | 7 +++++++ apps/openmw/mwgui/dialogue.hpp | 1 + apps/openmw/mwgui/list.cpp | 5 +++++ apps/openmw/mwgui/list.hpp | 7 ++++++- 4 files changed, 19 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 3d47aa7dc3..2e74290555 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -67,6 +67,8 @@ DialogueWindow::DialogueWindow(WindowManager& parWindowManager) getWidget(pDispositionBar, "Disposition"); getWidget(pDispositionText,"DispositionText"); + + static_cast(mMainWidget)->eventWindowChangeCoord += MyGUI::newDelegate(this, &DialogueWindow::onWindowResize); } void DialogueWindow::onHistoryClicked(MyGUI::Widget* _sender) @@ -88,6 +90,11 @@ void DialogueWindow::onHistoryClicked(MyGUI::Widget* _sender) } } +void DialogueWindow::onWindowResize(MyGUI::Window* _sender) +{ + topicsList->adjustSize(); +} + void DialogueWindow::onMouseWheel(MyGUI::Widget* _sender, int _rel) { if (history->getVScrollPosition() - _rel*0.3 < 0) diff --git a/apps/openmw/mwgui/dialogue.hpp b/apps/openmw/mwgui/dialogue.hpp index ac29e9ec8d..a8fed7d31e 100644 --- a/apps/openmw/mwgui/dialogue.hpp +++ b/apps/openmw/mwgui/dialogue.hpp @@ -51,6 +51,7 @@ namespace MWGui void onByeClicked(MyGUI::Widget* _sender); void onHistoryClicked(MyGUI::Widget* _sender); void onMouseWheel(MyGUI::Widget* _sender, int _rel); + void onWindowResize(MyGUI::Window* _sender); private: void updateOptions(); diff --git a/apps/openmw/mwgui/list.cpp b/apps/openmw/mwgui/list.cpp index 733654b8c5..d66cc6f89b 100644 --- a/apps/openmw/mwgui/list.cpp +++ b/apps/openmw/mwgui/list.cpp @@ -32,6 +32,11 @@ void MWList::addItem(const std::string& name) redraw(); } +void MWList::adjustSize() +{ + redraw(); +} + void MWList::redraw(bool scrollbarShown) { const int _scrollBarWidth = 24; // fetch this from skin? diff --git a/apps/openmw/mwgui/list.hpp b/apps/openmw/mwgui/list.hpp index eedcae066f..a2e9afcd1e 100644 --- a/apps/openmw/mwgui/list.hpp +++ b/apps/openmw/mwgui/list.hpp @@ -9,7 +9,7 @@ namespace MWGui { /** * \brief a very simple list widget that supports word-wrapping entries - * \note does not handle changing the width of the list at runtime + * \note if the width or height of the list changes, you must call adjustSize() method */ class MWList : public MyGUI::Widget { @@ -25,6 +25,11 @@ namespace MWGui */ EventHandle_String eventItemSelected; + /** + * Call after the size of the list changed + */ + void adjustSize(); + void addItem(const std::string& name); void removeItem(const std::string& name); bool hasItem(const std::string& name); From 4ce50c503bc28f4dd81b074fe578a82268b794ef Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 10 May 2012 11:29:28 +0200 Subject: [PATCH 101/325] a few tweaks --- apps/openmw/mwgui/stats_window.cpp | 10 +++++++--- apps/openmw/mwgui/tooltips.cpp | 4 ++-- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwgui/stats_window.cpp b/apps/openmw/mwgui/stats_window.cpp index 168b2efc66..8b688984fb 100644 --- a/apps/openmw/mwgui/stats_window.cpp +++ b/apps/openmw/mwgui/stats_window.cpp @@ -230,7 +230,9 @@ void StatsWindow::setBirthSign (const std::string& signId) void StatsWindow::addSeparator(MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) { - MyGUI::ImageBox* separator = skillClientWidget->createWidget("MW_HLine", MyGUI::IntCoord(10, coord1.top, coord1.width + coord2.width - 4, 18), MyGUI::Align::Default); + MyGUI::ImageBox* separator = skillClientWidget->createWidget("MW_HLine", + MyGUI::IntCoord(10, coord1.top, coord1.width + coord2.width - 4, 18), + MyGUI::Align::Left | MyGUI::Align::Top | MyGUI::Align::HStretch); skillWidgets.push_back(separator); coord1.top += separator->getHeight(); @@ -239,7 +241,9 @@ void StatsWindow::addSeparator(MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) void StatsWindow::addGroup(const std::string &label, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) { - MyGUI::TextBox* groupWidget = skillClientWidget->createWidget("SandBrightText", MyGUI::IntCoord(0, coord1.top, coord1.width + coord2.width, coord1.height), MyGUI::Align::Default); + MyGUI::TextBox* groupWidget = skillClientWidget->createWidget("SandBrightText", + MyGUI::IntCoord(0, coord1.top, coord1.width + coord2.width, coord1.height), + MyGUI::Align::Left | MyGUI::Align::Top | MyGUI::Align::HStretch); groupWidget->setCaption(label); skillWidgets.push_back(groupWidget); @@ -251,7 +255,7 @@ MyGUI::TextBox* StatsWindow::addValueItem(const std::string& text, const std::st { MyGUI::TextBox *skillNameWidget, *skillValueWidget; - skillNameWidget = skillClientWidget->createWidget("SandText", coord1, MyGUI::Align::Default); + skillNameWidget = skillClientWidget->createWidget("SandText", coord1, MyGUI::Align::Left | MyGUI::Align::Top | MyGUI::Align::HStretch); skillNameWidget->setCaption(text); skillNameWidget->setUserString("ToolTipType", "Text"); skillNameWidget->setUserString("ToolTipText", tooltip); diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 9d7a7ee874..1dbe909681 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -103,8 +103,8 @@ void ToolTips::onFrame(float frameDuration) // adjust tooltip size to fit its content, position it above the crosshair /// \todo Slide the tooltip along the bounding box of the focused object (like in Morrowind) - setCoord(viewSize.width/2 - (tooltipSize.width)/2.f, - viewSize.height/2 - (tooltipSize.height) - 32, + setCoord(std::max(0, viewSize.width/2 - (tooltipSize.width)/2), + std::max(0, viewSize.height/2 - (tooltipSize.height) - 32), tooltipSize.width, tooltipSize.height); } From 3d9e89c8378b962b49940b8c3920dd9867614817 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 10 May 2012 12:44:01 +0200 Subject: [PATCH 102/325] removed unnecessary include --- apps/openmw/mwgui/formatting.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/openmw/mwgui/formatting.cpp b/apps/openmw/mwgui/formatting.cpp index e031678aef..53c23c25d5 100644 --- a/apps/openmw/mwgui/formatting.cpp +++ b/apps/openmw/mwgui/formatting.cpp @@ -2,7 +2,6 @@ #include #include -#include using namespace MWGui; From 60affb5288f7d2abb53be16bf33a9b846bb2f96d Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 10 May 2012 12:47:15 +0200 Subject: [PATCH 103/325] removed include 2 --- apps/openmw/mwgui/formatting.hpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/apps/openmw/mwgui/formatting.hpp b/apps/openmw/mwgui/formatting.hpp index c8f2c9e445..a1e115491d 100644 --- a/apps/openmw/mwgui/formatting.hpp +++ b/apps/openmw/mwgui/formatting.hpp @@ -3,8 +3,6 @@ #include -#include - namespace MWGui { struct TextStyle From 37095b62c696674fc0122d541c4321eb1595a51e Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 10 May 2012 12:51:40 +0200 Subject: [PATCH 104/325] removed another include --- apps/openmw/mwgui/formatting.hpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/apps/openmw/mwgui/formatting.hpp b/apps/openmw/mwgui/formatting.hpp index c8f2c9e445..a1e115491d 100644 --- a/apps/openmw/mwgui/formatting.hpp +++ b/apps/openmw/mwgui/formatting.hpp @@ -3,8 +3,6 @@ #include -#include - namespace MWGui { struct TextStyle From c4aae96d94e1a1dab397095f17e9b4f110b2451e Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 11 May 2012 07:18:41 +0200 Subject: [PATCH 105/325] implemented "goodbye" script function that force-cancels dialogue --- apps/openmw/mwdialogue/dialoguemanager.cpp | 7 +++++++ apps/openmw/mwdialogue/dialoguemanager.hpp | 2 ++ apps/openmw/mwgui/dialogue.cpp | 17 +++++++++++++++++ apps/openmw/mwgui/dialogue.hpp | 3 +++ apps/openmw/mwscript/dialogueextensions.cpp | 13 +++++++++++++ apps/openmw/mwscript/docs/vmformat.txt | 3 ++- 6 files changed, 44 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwdialogue/dialoguemanager.cpp b/apps/openmw/mwdialogue/dialoguemanager.cpp index 282fba3543..7baf589c44 100644 --- a/apps/openmw/mwdialogue/dialoguemanager.cpp +++ b/apps/openmw/mwdialogue/dialoguemanager.cpp @@ -883,4 +883,11 @@ namespace MWDialogue } return factionID; } + + void DialogueManager::goodbye() + { + MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow(); + + win->goodbye(); + } } diff --git a/apps/openmw/mwdialogue/dialoguemanager.hpp b/apps/openmw/mwdialogue/dialoguemanager.hpp index a3e37987db..992175c0cf 100644 --- a/apps/openmw/mwdialogue/dialoguemanager.hpp +++ b/apps/openmw/mwdialogue/dialoguemanager.hpp @@ -56,6 +56,8 @@ namespace MWDialogue void askQuestion(std::string question,int choice); + void goodbye(); + ///get the faction of the actor you are talking with std::string getFaction(); diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 2e74290555..45163017a6 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -39,6 +39,7 @@ std::string::size_type find_str_ci(const std::string& str, const std::string& su DialogueWindow::DialogueWindow(WindowManager& parWindowManager) : WindowBase("openmw_dialogue_window_layout.xml", parWindowManager) + , mEnabled(true) { // Centre dialog center(); @@ -64,6 +65,7 @@ DialogueWindow::DialogueWindow(WindowManager& parWindowManager) MyGUI::ButtonPtr byeButton; getWidget(byeButton, "ByeButton"); byeButton->eventMouseButtonClick += MyGUI::newDelegate(this, &DialogueWindow::onByeClicked); + byeButton->setCaption(MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sGoodbye")->str); getWidget(pDispositionBar, "Disposition"); getWidget(pDispositionText,"DispositionText"); @@ -81,6 +83,10 @@ void DialogueWindow::onHistoryClicked(MyGUI::Widget* _sender) size_t cursorPosition = t->getCursorPosition(lastPressed); MyGUI::UString color = history->getColorAtPos(cursorPosition); + + if (!mEnabled && color == "#572D21") + MWBase::Environment::get().getDialogueManager()->goodbyeSelected(); + if(color != "#B29154") { UString key = history->getColorTextAt(cursorPosition); @@ -119,11 +125,15 @@ void DialogueWindow::onByeClicked(MyGUI::Widget* _sender) void DialogueWindow::onSelectTopic(std::string topic) { + if (!mEnabled) return; + MWBase::Environment::get().getDialogueManager()->keywordSelected(lower_string(topic)); } void DialogueWindow::startDialogue(std::string npcName) { + mEnabled = true; + topicsList->setEnabled(true); static_cast(mMainWidget)->setCaption(npcName); adjustWindowCaption(); } @@ -224,3 +234,10 @@ void DialogueWindow::updateOptions() pDispositionText->eraseText(0,pDispositionText->getTextLength()); pDispositionText->addText("#B29154"+std::string("40/100")+"#B29154"); } + +void DialogueWindow::goodbye() +{ + history->addDialogText("\n#572D21" + MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sGoodbye")->str); + topicsList->setEnabled(false); + mEnabled = false; +} diff --git a/apps/openmw/mwgui/dialogue.hpp b/apps/openmw/mwgui/dialogue.hpp index a8fed7d31e..a29e737997 100644 --- a/apps/openmw/mwgui/dialogue.hpp +++ b/apps/openmw/mwgui/dialogue.hpp @@ -45,6 +45,7 @@ namespace MWGui void addText(std::string text); void addTitle(std::string text); void askQuestion(std::string question); + void goodbye(); protected: void onSelectTopic(std::string topic); @@ -60,6 +61,8 @@ namespace MWGui */ std::string parseText(std::string text); + bool mEnabled; + DialogueHistory* history; Widgets::MWList* topicsList; MyGUI::ProgressPtr pDispositionBar; diff --git a/apps/openmw/mwscript/dialogueextensions.cpp b/apps/openmw/mwscript/dialogueextensions.cpp index b99d55999c..ec8ab59b41 100644 --- a/apps/openmw/mwscript/dialogueextensions.cpp +++ b/apps/openmw/mwscript/dialogueextensions.cpp @@ -115,6 +115,16 @@ namespace MWScript } }; + class OpGoodbye : public Interpreter::Opcode0 + { + public: + + virtual void execute(Interpreter::Runtime& runtime) + { + MWBase::Environment::get().getDialogueManager()->goodbye(); + } + }; + const int opcodeJournal = 0x2000133; const int opcodeSetJournalIndex = 0x2000134; const int opcodeGetJournalIndex = 0x2000135; @@ -122,6 +132,7 @@ namespace MWScript const int opcodeChoice = 0x2000a; const int opcodeForceGreeting = 0x200014f; const int opcodeForceGreetingExplicit = 0x2000150; + const int opcodeGoodbye = 0x2000152; void registerExtensions (Compiler::Extensions& extensions) { @@ -133,6 +144,7 @@ namespace MWScript extensions.registerInstruction("forcegreeting","",opcodeForceGreeting); extensions.registerInstruction("forcegreeting","",opcodeForceGreeting, opcodeForceGreetingExplicit); + extensions.registerInstruction("goodbye", "", opcodeGoodbye); } void installOpcodes (Interpreter::Interpreter& interpreter) @@ -144,6 +156,7 @@ namespace MWScript interpreter.installSegment3 (opcodeChoice,new OpChoice); interpreter.installSegment5 (opcodeForceGreeting, new OpForceGreeting); interpreter.installSegment5 (opcodeForceGreetingExplicit, new OpForceGreeting); + interpreter.installSegment5 (opcodeGoodbye, new OpGoodbye); } } diff --git a/apps/openmw/mwscript/docs/vmformat.txt b/apps/openmw/mwscript/docs/vmformat.txt index 378b2412a5..0920c72f8e 100644 --- a/apps/openmw/mwscript/docs/vmformat.txt +++ b/apps/openmw/mwscript/docs/vmformat.txt @@ -145,4 +145,5 @@ op 0x200014e: ModDisposition, explicit reference op 0x200014f: ForceGreeting op 0x2000150: ForceGreeting, explicit reference op 0x2000151: ToggleFullHelp -opcodes 0x2000152-0x3ffffff unused +op 0x2000152: Goodbye +opcodes 0x2000153-0x3ffffff unused From 65ccfba191318fd7b3bd4307ae62e08c9c6a26ac Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 11 May 2012 08:15:22 +0200 Subject: [PATCH 106/325] resize both the left and the right pane of the stats window --- apps/openmw/mwgui/stats_window.cpp | 4 + apps/openmw/mwgui/stats_window.hpp | 3 + files/mygui/openmw_stats_window_layout.xml | 109 +++++++++++---------- 3 files changed, 66 insertions(+), 50 deletions(-) diff --git a/apps/openmw/mwgui/stats_window.cpp b/apps/openmw/mwgui/stats_window.cpp index 8b688984fb..9e6e173918 100644 --- a/apps/openmw/mwgui/stats_window.cpp +++ b/apps/openmw/mwgui/stats_window.cpp @@ -60,6 +60,8 @@ StatsWindow::StatsWindow (WindowManager& parWindowManager) getWidget(skillAreaWidget, "Skills"); getWidget(skillClientWidget, "SkillClient"); getWidget(skillScrollerWidget, "SkillScroller"); + getWidget(mLeftPane, "LeftPane"); + getWidget(mRightPane, "RightPane"); skillScrollerWidget->eventScrollChangePosition += MyGUI::newDelegate(this, &StatsWindow::onScrollChangePosition); updateScroller(); @@ -93,6 +95,8 @@ void StatsWindow::onScrollChangePosition(MyGUI::ScrollBar* scroller, size_t pos) void StatsWindow::onWindowResize(MyGUI::Window* window) { + mLeftPane->setCoord( MyGUI::IntCoord(0, 0, 0.44*window->getSize().width, window->getSize().height) ); + mRightPane->setCoord( MyGUI::IntCoord(0.44*window->getSize().width, 0, 0.56*window->getSize().width, window->getSize().height) ); updateScroller(); } diff --git a/apps/openmw/mwgui/stats_window.hpp b/apps/openmw/mwgui/stats_window.hpp index ecbc82894e..b201b33879 100644 --- a/apps/openmw/mwgui/stats_window.hpp +++ b/apps/openmw/mwgui/stats_window.hpp @@ -57,6 +57,9 @@ namespace MWGui static const int lineHeight; + MyGUI::Widget* mLeftPane; + MyGUI::Widget* mRightPane; + MyGUI::WidgetPtr skillAreaWidget, skillClientWidget; MyGUI::ScrollBar* skillScrollerWidget; int lastPos, clientHeight; diff --git a/files/mygui/openmw_stats_window_layout.xml b/files/mygui/openmw_stats_window_layout.xml index 4f3f80e895..4056216ade 100644 --- a/files/mygui/openmw_stats_window_layout.xml +++ b/files/mygui/openmw_stats_window_layout.xml @@ -3,59 +3,68 @@ - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - From 1f1edea6af072a49889c5fac07fe2ab01aece314 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 11 May 2012 08:45:03 +0200 Subject: [PATCH 107/325] make it possible to use scroll wheel when mouse is over a skill in the stats window; set the correct track size for the scrollbar --- apps/openmw/mwgui/stats_window.cpp | 23 +++++++++++++++++++++- apps/openmw/mwgui/stats_window.hpp | 1 + files/mygui/openmw_stats_window_layout.xml | 2 +- 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/stats_window.cpp b/apps/openmw/mwgui/stats_window.cpp index 9e6e173918..2736270e1c 100644 --- a/apps/openmw/mwgui/stats_window.cpp +++ b/apps/openmw/mwgui/stats_window.cpp @@ -63,6 +63,8 @@ StatsWindow::StatsWindow (WindowManager& parWindowManager) getWidget(mLeftPane, "LeftPane"); getWidget(mRightPane, "RightPane"); + skillClientWidget->eventMouseWheel += MyGUI::newDelegate(this, &StatsWindow::onMouseWheel); + skillScrollerWidget->eventScrollChangePosition += MyGUI::newDelegate(this, &StatsWindow::onScrollChangePosition); updateScroller(); @@ -93,6 +95,18 @@ void StatsWindow::onScrollChangePosition(MyGUI::ScrollBar* scroller, size_t pos) } } +void StatsWindow::onMouseWheel(MyGUI::Widget* _sender, int _rel) +{ + if (skillScrollerWidget->getScrollPosition() - _rel*0.3 < 0) + skillScrollerWidget->setScrollPosition(0); + else if (skillScrollerWidget->getScrollPosition() - _rel*0.3 > skillScrollerWidget->getScrollRange()-1) + skillScrollerWidget->setScrollPosition(skillScrollerWidget->getScrollRange()-1); + else + skillScrollerWidget->setScrollPosition(skillScrollerWidget->getScrollPosition() - _rel*0.3); + + onScrollChangePosition(skillScrollerWidget, skillScrollerWidget->getScrollPosition()); +} + void StatsWindow::onWindowResize(MyGUI::Window* window) { mLeftPane->setCoord( MyGUI::IntCoord(0, 0, 0.44*window->getSize().width, window->getSize().height) ); @@ -237,6 +251,7 @@ void StatsWindow::addSeparator(MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) MyGUI::ImageBox* separator = skillClientWidget->createWidget("MW_HLine", MyGUI::IntCoord(10, coord1.top, coord1.width + coord2.width - 4, 18), MyGUI::Align::Left | MyGUI::Align::Top | MyGUI::Align::HStretch); + separator->eventMouseWheel += MyGUI::newDelegate(this, &StatsWindow::onMouseWheel); skillWidgets.push_back(separator); coord1.top += separator->getHeight(); @@ -249,6 +264,7 @@ void StatsWindow::addGroup(const std::string &label, MyGUI::IntCoord &coord1, My MyGUI::IntCoord(0, coord1.top, coord1.width + coord2.width, coord1.height), MyGUI::Align::Left | MyGUI::Align::Top | MyGUI::Align::HStretch); groupWidget->setCaption(label); + groupWidget->eventMouseWheel += MyGUI::newDelegate(this, &StatsWindow::onMouseWheel); skillWidgets.push_back(groupWidget); coord1.top += lineHeight; @@ -263,12 +279,14 @@ MyGUI::TextBox* StatsWindow::addValueItem(const std::string& text, const std::st skillNameWidget->setCaption(text); skillNameWidget->setUserString("ToolTipType", "Text"); skillNameWidget->setUserString("ToolTipText", tooltip); + skillNameWidget->eventMouseWheel += MyGUI::newDelegate(this, &StatsWindow::onMouseWheel); skillValueWidget = skillClientWidget->createWidget("SandTextRight", coord2, MyGUI::Align::Right | MyGUI::Align::Top); skillValueWidget->setUserString("ToolTipType", "Text"); skillValueWidget->setUserString("ToolTipText", tooltip); skillValueWidget->setCaption(value); skillValueWidget->_setWidgetState(state); + skillValueWidget->eventMouseWheel += MyGUI::newDelegate(this, &StatsWindow::onMouseWheel); skillWidgets.push_back(skillNameWidget); skillWidgets.push_back(skillValueWidget); @@ -285,6 +303,7 @@ void StatsWindow::addItem(const std::string text, MyGUI::IntCoord &coord1, MyGUI skillNameWidget = skillClientWidget->createWidget("SandText", coord1 + MyGUI::IntSize(coord2.width, 0), MyGUI::Align::Default); skillNameWidget->setCaption(text); + skillNameWidget->eventMouseWheel += MyGUI::newDelegate(this, &StatsWindow::onMouseWheel); skillWidgets.push_back(skillNameWidget); @@ -370,7 +389,7 @@ void StatsWindow::updateSkillArea() if (!skillWidgets.empty()) addSeparator(coord1, coord2); - addGroup(mWindowManager.getGameSettingString("sSign", "Sign"), coord1, coord2); + addGroup(mWindowManager.getGameSettingString("sBirthSign", "Sign"), coord1, coord2); const ESM::BirthSign *sign = store.birthSigns.find(birthSignId); addItem(sign->name, coord1, coord2); } @@ -394,6 +413,8 @@ void StatsWindow::updateScroller() { skillScrollerWidget->setScrollRange(std::max(clientHeight - skillClientWidget->getHeight(), 0)); skillScrollerWidget->setScrollPage(std::max(skillClientWidget->getHeight() - lineHeight, 0)); + if (clientHeight != 0) + skillScrollerWidget->setTrackSize( (skillAreaWidget->getHeight() / float(clientHeight)) * skillAreaWidget->getHeight() ); } void StatsWindow::onPinToggled() diff --git a/apps/openmw/mwgui/stats_window.hpp b/apps/openmw/mwgui/stats_window.hpp index b201b33879..08c5148ecc 100644 --- a/apps/openmw/mwgui/stats_window.hpp +++ b/apps/openmw/mwgui/stats_window.hpp @@ -54,6 +54,7 @@ namespace MWGui void onScrollChangePosition(MyGUI::ScrollBar* scroller, size_t pos); void onWindowResize(MyGUI::Window* window); + void onMouseWheel(MyGUI::Widget* _sender, int _rel); static const int lineHeight; diff --git a/files/mygui/openmw_stats_window_layout.xml b/files/mygui/openmw_stats_window_layout.xml index 4056216ade..9406fe6bdd 100644 --- a/files/mygui/openmw_stats_window_layout.xml +++ b/files/mygui/openmw_stats_window_layout.xml @@ -60,7 +60,7 @@ - + From 83e434e2e91c8a21becb88fac8687271cf42d8c2 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 11 May 2012 09:35:18 +0200 Subject: [PATCH 108/325] small fix --- apps/openmw/mwgui/stats_window.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/stats_window.cpp b/apps/openmw/mwgui/stats_window.cpp index 2736270e1c..1866682226 100644 --- a/apps/openmw/mwgui/stats_window.cpp +++ b/apps/openmw/mwgui/stats_window.cpp @@ -414,7 +414,7 @@ void StatsWindow::updateScroller() skillScrollerWidget->setScrollRange(std::max(clientHeight - skillClientWidget->getHeight(), 0)); skillScrollerWidget->setScrollPage(std::max(skillClientWidget->getHeight() - lineHeight, 0)); if (clientHeight != 0) - skillScrollerWidget->setTrackSize( (skillAreaWidget->getHeight() / float(clientHeight)) * skillAreaWidget->getHeight() ); + skillScrollerWidget->setTrackSize( (skillAreaWidget->getHeight() / float(clientHeight)) * skillScrollerWidget->getLineSize() ); } void StatsWindow::onPinToggled() From a99f74702ed26f9c3bacfca5ed9688816c618132 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 11 May 2012 09:57:43 +0200 Subject: [PATCH 109/325] workaround for a white square that appears in menubook_next texture --- files/mygui/openmw_book_layout.xml | 2 +- files/mygui/openmw_journal_layout.xml | 2 +- files/mygui/openmw_resources.xml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/files/mygui/openmw_book_layout.xml b/files/mygui/openmw_book_layout.xml index 07ebf5030a..6c708cdd3d 100644 --- a/files/mygui/openmw_book_layout.xml +++ b/files/mygui/openmw_book_layout.xml @@ -7,7 +7,7 @@ - + diff --git a/files/mygui/openmw_journal_layout.xml b/files/mygui/openmw_journal_layout.xml index 75bb5eea17..e4c3c7e472 100644 --- a/files/mygui/openmw_journal_layout.xml +++ b/files/mygui/openmw_journal_layout.xml @@ -7,7 +7,7 @@ - + diff --git a/files/mygui/openmw_resources.xml b/files/mygui/openmw_resources.xml index 455765aadf..b2bd90d105 100644 --- a/files/mygui/openmw_resources.xml +++ b/files/mygui/openmw_resources.xml @@ -72,7 +72,7 @@ - + From 9dd65dce30b4910b11d1b89f66d2bed10c06d0c3 Mon Sep 17 00:00:00 2001 From: gugus Date: Fri, 11 May 2012 11:52:07 +0200 Subject: [PATCH 110/325] Finished merging. --- apps/openmw/mwgui/container.cpp | 10 ++++------ apps/openmw/mwgui/container.hpp | 5 ++--- apps/openmw/mwgui/inventorywindow.cpp | 8 ++++---- apps/openmw/mwgui/inventorywindow.hpp | 2 +- apps/openmw/mwgui/tooltips.cpp | 2 +- apps/openmw/mwgui/window_manager.cpp | 6 +++--- apps/openmw/mwrender/objects.cpp | 4 ++-- apps/openmw/mwworld/actionopen.cpp | 8 ++++---- apps/openmw/mwworld/actionopen.hpp | 2 +- 9 files changed, 22 insertions(+), 25 deletions(-) diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 454dd05c37..b4f38b4e17 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -5,7 +5,7 @@ #include "window_manager.hpp" #include "widgets.hpp" -#include "../mwworld/environment.hpp" +#include "../mwbase/environment.hpp" #include "../mwworld/manualref.hpp" #include #include @@ -25,9 +25,8 @@ using namespace MWGui; using namespace Widgets; -ContainerWindow::ContainerWindow(WindowManager& parWindowManager,MWWorld::Environment& environment,DragAndDrop* dragAndDrop) +ContainerWindow::ContainerWindow(WindowManager& parWindowManager,DragAndDrop* dragAndDrop) : WindowBase("openmw_container_window_layout.xml", parWindowManager), - mEnvironment(environment), mDragAndDrop(dragAndDrop), mContainer() { @@ -51,9 +50,8 @@ ContainerWindow::ContainerWindow(WindowManager& parWindowManager,MWWorld::Enviro //mContainerWidget->eventMouseItemActivate += MyGUI::newDelegate(this,&ContainerWindow::onSelectedItem); } -ContainerWindow::ContainerWindow(WindowManager& parWindowManager,MWWorld::Environment& environment,DragAndDrop* dragAndDrop,std::string guiFile) +ContainerWindow::ContainerWindow(WindowManager& parWindowManager,DragAndDrop* dragAndDrop,std::string guiFile) : WindowBase(guiFile, parWindowManager), - mEnvironment(environment), mDragAndDrop(dragAndDrop), mContainer() { @@ -183,7 +181,7 @@ void ContainerWindow::onByeClicked(MyGUI::Widget* _sender) { if(!mDragAndDrop->mIsOnDragAndDrop) { - mEnvironment.mWindowManager->setGuiMode(GM_Game); + MWBase::Environment::get().getWindowManager()->setGuiMode(GM_Game); setVisible(false); } } diff --git a/apps/openmw/mwgui/container.hpp b/apps/openmw/mwgui/container.hpp index b8f76a355c..08ac7eba24 100644 --- a/apps/openmw/mwgui/container.hpp +++ b/apps/openmw/mwgui/container.hpp @@ -46,8 +46,8 @@ namespace MWGui class ContainerWindow : public WindowBase { public: - ContainerWindow(WindowManager& parWindowManager,MWWorld::Environment& environment,DragAndDrop* dragAndDrop); - ContainerWindow(WindowManager& parWindowManager,MWWorld::Environment& environment,DragAndDrop* dragAndDrop, + ContainerWindow(WindowManager& parWindowManager,DragAndDrop* dragAndDrop); + ContainerWindow(WindowManager& parWindowManager,DragAndDrop* dragAndDrop, std::string guiFile); @@ -58,7 +58,6 @@ namespace MWGui virtual ~ContainerWindow(); protected: - MWWorld::Environment& mEnvironment; std::vector mContainerWidgets; MyGUI::ItemBoxPtr mContainerWidget; diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index cf2cfb5370..3ae2ee9ebd 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -4,7 +4,7 @@ #include "window_manager.hpp" #include "widgets.hpp" -#include "../mwworld/environment.hpp" +#include "../mwbase/environment.hpp" #include "../mwworld/manualref.hpp" #include #include @@ -21,14 +21,14 @@ namespace MWGui { - InventoryWindow::InventoryWindow(WindowManager& parWindowManager,MWWorld::Environment& environment,DragAndDrop* dragAndDrop) - :ContainerWindow(parWindowManager,environment,dragAndDrop,"openmw_inventory_window_layout.xml") + InventoryWindow::InventoryWindow(WindowManager& parWindowManager,DragAndDrop* dragAndDrop) + :ContainerWindow(parWindowManager,dragAndDrop,"openmw_inventory_window_layout.xml") { } void InventoryWindow::openInventory() { - open(mEnvironment.mWorld->getPlayer().getPlayer()); + open(MWBase::Environment::get().getWorld()->getPlayer().getPlayer()); } } \ No newline at end of file diff --git a/apps/openmw/mwgui/inventorywindow.hpp b/apps/openmw/mwgui/inventorywindow.hpp index 184cab183f..21f27b12fb 100644 --- a/apps/openmw/mwgui/inventorywindow.hpp +++ b/apps/openmw/mwgui/inventorywindow.hpp @@ -24,7 +24,7 @@ namespace MWGui class InventoryWindow : public MWGui::ContainerWindow { public: - InventoryWindow(WindowManager& parWindowManager,MWWorld::Environment& environment,DragAndDrop* dragAndDrop); + InventoryWindow(WindowManager& parWindowManager,DragAndDrop* dragAndDrop); void openInventory(); }; diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 9d7a7ee874..757563efaf 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -165,7 +165,7 @@ void ToolTips::findImageExtension(std::string& image) } } -IntSize ToolTips::createToolTip(const ToolTipInfo& info) +IntSize ToolTips::createToolTip(const MWGui::ToolTipInfo& info) { std::string caption = info.caption; std::string image = info.icon; diff --git a/apps/openmw/mwgui/window_manager.cpp b/apps/openmw/mwgui/window_manager.cpp index ccd51d9db3..db5a51f0cb 100644 --- a/apps/openmw/mwgui/window_manager.cpp +++ b/apps/openmw/mwgui/window_manager.cpp @@ -95,9 +95,9 @@ WindowManager::WindowManager( console = new Console(w,h, extensions); mJournal = new JournalWindow(*this); mMessageBoxManager = new MessageBoxManager(this); - mDialogueWindow = new DialogueWindow(*this,environment); - mContainerWindow = new ContainerWindow(*this,environment,mDragAndDrop); - mInventoryWindow = new InventoryWindow(*this,environment,mDragAndDrop); + mDialogueWindow = new DialogueWindow(*this); + mContainerWindow = new ContainerWindow(*this,mDragAndDrop); + mInventoryWindow = new InventoryWindow(*this,mDragAndDrop); mToolTips = new ToolTips(this); // The HUD is always on diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index 27c3f818e8..b9efcd3f5d 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -219,7 +219,7 @@ void Objects::insertLight (const MWWorld::Ptr& ptr, float r, float g, float b, f info.type = LT_Normal; // random starting phase for the animation - info.time = Ogre::Math::RangeRandom(0, 2 * M_PI); + info.time = Ogre::Math::RangeRandom(0, 2 * Ogre::Math::PI); // adjust the lights depending if we're in an interior or exterior cell // quadratic means the light intensity falls off quite fast, resulting in a @@ -367,7 +367,7 @@ void Objects::update(const float dt) // Light animation (pulse & flicker) it->time += dt; - const float phase = std::fmod(static_cast (it->time), (32 * 2 * M_PI)) * 20; + const float phase = std::fmod(static_cast (it->time), static_cast(32 * 2 * Ogre::Math::PI)) * 20; float pulseConstant; // These formulas are just guesswork, but they work pretty well diff --git a/apps/openmw/mwworld/actionopen.cpp b/apps/openmw/mwworld/actionopen.cpp index e245989d7f..e450585e63 100644 --- a/apps/openmw/mwworld/actionopen.cpp +++ b/apps/openmw/mwworld/actionopen.cpp @@ -1,6 +1,6 @@ #include "actionopen.hpp" -#include "environment.hpp" +#include "../mwbase/environment.hpp" #include "class.hpp" #include "world.hpp" #include "containerstore.hpp" @@ -14,9 +14,9 @@ namespace MWWorld mContainer = container; } - void ActionOpen::execute (Environment& environment) + void ActionOpen::execute () { - environment.mWindowManager->setGuiMode(MWGui::GM_Container); - environment.mWindowManager->getContainerWindow()->open(mContainer); + MWBase::Environment::get().getWindowManager()->setGuiMode(MWGui::GM_Container); + MWBase::Environment::get().getWindowManager()->getContainerWindow()->open(mContainer); } } diff --git a/apps/openmw/mwworld/actionopen.hpp b/apps/openmw/mwworld/actionopen.hpp index 7c660e4c94..eff26c78c1 100644 --- a/apps/openmw/mwworld/actionopen.hpp +++ b/apps/openmw/mwworld/actionopen.hpp @@ -15,7 +15,7 @@ namespace MWWorld public: ActionOpen (const Ptr& container); ///< \param The Container the Player has activated. - virtual void execute (Environment& environment); + virtual void execute (); }; } From cfb7aa4343e17fc810e0be72da1c965e72bd9673 Mon Sep 17 00:00:00 2001 From: gugus Date: Fri, 11 May 2012 12:50:30 +0200 Subject: [PATCH 111/325] Drag and drop works. There is a bug with item count when doing d&d. Clean-up time :p --- apps/openmw/mwgui/container.cpp | 11 ++++++----- apps/openmw/mwgui/container.hpp | 2 +- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index b4f38b4e17..fd69e1a658 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -203,6 +203,7 @@ void ContainerWindow::onSelectedItem(MyGUI::Widget* _sender) count++; if(count == item->mPos) { + mDragAndDrop->mStore.add(*iter); iter->getRefData().setCount(0); break; } @@ -232,16 +233,16 @@ void ContainerWindow::onContainerClicked(MyGUI::Widget* _sender) if(mDragAndDrop->mIsOnDragAndDrop) //drop widget here { ItemWidget* item = static_cast(mDragAndDrop->mDraggedWidget); - std::cout << item->mPos << item->mPtr.getTypeName(); + std::cout << item->mPos << (*mDragAndDrop->mStore.begin()).getTypeName(); if(item->mPtr.getContainerStore() == 0) std::cout << "nocontainer!"; - std::cout << item->mPtr.getContainerStore()->getType(item->mPtr); - MWWorld::Ptr ptr = item->mPtr; - //MWWorld::World - //mContainer.getContainerStore()->add(item->mPtr); + MWWorld::ContainerStore& containerStore = MWWorld::Class::get(mContainer).getContainerStore(mContainer); + containerStore.add(*mDragAndDrop->mStore.begin()); + mDragAndDrop->mStore.clear(); mDragAndDrop->mIsOnDragAndDrop = false; mDragAndDrop->mDraggedWidget->detachFromWidget(); mDragAndDrop->mDraggedWidget->attachToWidget(mContainerWidget); mDragAndDrop->mDraggedWidget = 0; mDragAndDrop->mContainerWindow = 0; + drawItems(); } } \ No newline at end of file diff --git a/apps/openmw/mwgui/container.hpp b/apps/openmw/mwgui/container.hpp index 08ac7eba24..0d047bacff 100644 --- a/apps/openmw/mwgui/container.hpp +++ b/apps/openmw/mwgui/container.hpp @@ -39,7 +39,7 @@ namespace MWGui ContainerWindow* mContainerWindow; MyGUI::Widget* mDraggedWidget; MyGUI::Widget* mDragAndDropWidget; - + MWWorld::ContainerStore mStore; MWWorld::Ptr mItem; }; From 007a202debacd911a918a96f6cc40bf03158abe3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 11 May 2012 16:34:36 +0200 Subject: [PATCH 112/325] cleanup 1 --- apps/openmw/mwgui/container.cpp | 2 +- apps/openmw/mwgui/container.hpp | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index b040f9d7a4..8c36254685 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -180,7 +180,7 @@ void ContainerWindow::Update() } } -void ContainerWindow::onByeClicked(MyGUI::Widget* _sender) +void ContainerWindow::onCloseButtonClicked(MyGUI::Widget* _sender) { if(!mDragAndDrop->mIsOnDragAndDrop) { diff --git a/apps/openmw/mwgui/container.hpp b/apps/openmw/mwgui/container.hpp index 33a12968b9..607138f96f 100644 --- a/apps/openmw/mwgui/container.hpp +++ b/apps/openmw/mwgui/container.hpp @@ -69,12 +69,10 @@ namespace MWGui void drawItems(); - void onByeClicked(MyGUI::Widget* _sender); + void onCloseButtonClicked(MyGUI::Widget* _sender); void onSelectedItem(MyGUI::Widget* _sender); void onContainerClicked(MyGUI::Widget* _sender); void onMouseMove(MyGUI::Widget* _sender, int _left, int _top); - - //MWWorld::Ptr& mContainer; }; } #endif // CONTAINER_H From 3a6fde5039dcfc4dfc5c8525ebff075db93e94d3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 11 May 2012 16:58:07 +0200 Subject: [PATCH 113/325] cleanup 2 --- apps/openmw/mwgui/container.cpp | 58 ++++++++++--------- apps/openmw/mwgui/container.hpp | 1 + .../mygui/openmw_container_window_layout.xml | 16 +---- 3 files changed, 36 insertions(+), 39 deletions(-) diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 7daa287757..b46dfdf530 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -1,24 +1,24 @@ #include "container.hpp" -#include -#include #include "window_manager.hpp" #include "widgets.hpp" +#include "itemwidget.hpp" #include "../mwbase/environment.hpp" #include "../mwworld/manualref.hpp" +#include "../mwworld/world.hpp" +#include "../mwworld/containerstore.hpp" +#include "../mwworld/class.hpp" +#include "../mwclass/container.hpp" +#include "../mwinput/inputmanager.hpp" + #include #include #include - #include #include -#include "../mwclass/container.hpp" -#include "../mwworld/containerstore.hpp" + #include -#include "../mwworld/class.hpp" -#include "../mwinput/inputmanager.hpp" -#include "itemwidget.hpp" using namespace MWGui; @@ -32,22 +32,26 @@ ContainerWindow::ContainerWindow(WindowManager& parWindowManager,DragAndDrop* dr { setText("_Main", "Name of Container"); - int w = MyGUI::RenderManager::getInstance().getViewSize().width; - int h = MyGUI::RenderManager::getInstance().getViewSize().height; - setCoord(w-600,h-300,600,300); - //center(); - adjustWindowCaption(); - getWidget(mContainerWidget, "Items"); getWidget(mTakeButton, "TakeButton"); getWidget(mCloseButton, "CloseButton"); mCloseButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ContainerWindow::onCloseButtonClicked); + mTakeButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ContainerWindow::onTakeAllButtonClicked); mContainerWidget->eventMouseButtonClick += MyGUI::newDelegate(this, &ContainerWindow::onContainerClicked); - setText("CloseButton","Close"); - setText("TakeButton","Take All"); - //mContainerWidget->eventMouseItemActivate += MyGUI::newDelegate(this,&ContainerWindow::onSelectedItem); + setText("CloseButton", MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sClose")->str); + setText("TakeButton", MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sTakeAll")->str); + + // adjust buttons size to fit text + int closeButtonWidth = mCloseButton->getTextSize().width+24; + int takeButtonWidth = mTakeButton->getTextSize().width+24; + mCloseButton->setCoord(600-20-closeButtonWidth, mCloseButton->getCoord().top, closeButtonWidth, mCloseButton->getCoord().height); + mTakeButton->setCoord(600-20-closeButtonWidth-takeButtonWidth-8, mTakeButton->getCoord().top, takeButtonWidth, mTakeButton->getCoord().height); + + int w = MyGUI::RenderManager::getInstance().getViewSize().width; + int h = MyGUI::RenderManager::getInstance().getViewSize().height; + setCoord(w-600,h-300,600,300); } ContainerWindow::ContainerWindow(WindowManager& parWindowManager,DragAndDrop* dragAndDrop,std::string guiFile) @@ -56,18 +60,9 @@ ContainerWindow::ContainerWindow(WindowManager& parWindowManager,DragAndDrop* dr mContainer() { setText("_Main", "Name of Container"); - //center(); adjustWindowCaption(); getWidget(mContainerWidget, "Items"); mContainerWidget->eventMouseButtonClick += MyGUI::newDelegate(this, &ContainerWindow::onContainerClicked); - //getWidget(takeButton, "TakeButton"); - //getWidget(closeButton, "CloseButton"); - - //closeButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ContainerWindow::onByeClicked); - - //setText("CloseButton","Close"); - //setText("TakeButton","Take All"); - //mContainerWidget->eventMouseItemActivate += MyGUI::newDelegate(this,&ContainerWindow::onSelectedItem); } ContainerWindow::~ContainerWindow() { @@ -76,6 +71,7 @@ ContainerWindow::~ContainerWindow() void ContainerWindow::setName(std::string contName) { setText("_Main", contName); + adjustWindowCaption(); } @@ -189,6 +185,16 @@ void ContainerWindow::onCloseButtonClicked(MyGUI::Widget* _sender) } } +void ContainerWindow::onTakeAllButtonClicked(MyGUI::Widget* _sender) +{ + if(!mDragAndDrop->mIsOnDragAndDrop) + { + /// \todo + MWBase::Environment::get().getWindowManager()->setGuiMode(GM_Game); + setVisible(false); + } +} + void ContainerWindow::onSelectedItem(MyGUI::Widget* _sender) { if(!mDragAndDrop->mIsOnDragAndDrop) diff --git a/apps/openmw/mwgui/container.hpp b/apps/openmw/mwgui/container.hpp index db1f973e74..ad029ae805 100644 --- a/apps/openmw/mwgui/container.hpp +++ b/apps/openmw/mwgui/container.hpp @@ -70,6 +70,7 @@ namespace MWGui void drawItems(); void onCloseButtonClicked(MyGUI::Widget* _sender); + void onTakeAllButtonClicked(MyGUI::Widget* _sender); void onSelectedItem(MyGUI::Widget* _sender); void onContainerClicked(MyGUI::Widget* _sender); void onMouseMove(MyGUI::Widget* _sender, int _left, int _top); diff --git a/files/mygui/openmw_container_window_layout.xml b/files/mygui/openmw_container_window_layout.xml index 31b0364684..25156c5a2a 100644 --- a/files/mygui/openmw_container_window_layout.xml +++ b/files/mygui/openmw_container_window_layout.xml @@ -3,22 +3,12 @@ - - - - - - - - - + + + From d9e39bd90e742fa17707a9202e58d486660af4e5 Mon Sep 17 00:00:00 2001 From: Lukasz Gromanowski Date: Fri, 11 May 2012 21:32:38 +0200 Subject: [PATCH 114/325] Changed order of plugins.cfg file paths. Changed order of plugins.cfg file paths - before when plugins.cfg file was found in global path then it was used as default one. Now the behavoiur is opposite if plugins.cfg file exists in local path then it is used as default one. --- components/files/configurationmanager.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/files/configurationmanager.cpp b/components/files/configurationmanager.cpp index ef45b6543e..d5f322ebd4 100644 --- a/components/files/configurationmanager.cpp +++ b/components/files/configurationmanager.cpp @@ -28,10 +28,10 @@ ConfigurationManager::ConfigurationManager() { setupTokensMapping(); - mPluginsCfgPath = mFixedPath.getGlobalPath() / pluginsCfgFile; + mPluginsCfgPath = mFixedPath.getLocalPath() / pluginsCfgFile; if (!boost::filesystem::is_regular_file(mPluginsCfgPath)) { - mPluginsCfgPath = mFixedPath.getLocalPath() / pluginsCfgFile; + mPluginsCfgPath = mFixedPath.getGlobalPath() / pluginsCfgFile; if (!boost::filesystem::is_regular_file(mPluginsCfgPath)) { std::cerr << "Failed to find " << pluginsCfgFile << " file!" << std::endl; From ed6ff0a94ac090d3357ee6885c2f4fb309530db6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 12 May 2012 13:12:37 +0200 Subject: [PATCH 115/325] cleanup 3 --- apps/openmw/mwgui/container.cpp | 304 ++++++++---------- apps/openmw/mwgui/container.hpp | 40 ++- apps/openmw/mwgui/inventorywindow.cpp | 2 +- apps/openmw/mwgui/inventorywindow.hpp | 2 +- .../mygui/openmw_container_window_layout.xml | 9 +- .../mygui/openmw_inventory_window_layout.xml | 9 +- files/mygui/openmw_scroll_skin.xml | 1 - 7 files changed, 173 insertions(+), 194 deletions(-) diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index b46dfdf530..b4d3698061 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -25,177 +25,23 @@ using namespace MWGui; using namespace Widgets; -ContainerWindow::ContainerWindow(WindowManager& parWindowManager,DragAndDrop* dragAndDrop) - : WindowBase("openmw_container_window_layout.xml", parWindowManager), - mDragAndDrop(dragAndDrop), - mContainer() -{ - setText("_Main", "Name of Container"); - - getWidget(mContainerWidget, "Items"); - getWidget(mTakeButton, "TakeButton"); - getWidget(mCloseButton, "CloseButton"); - - mCloseButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ContainerWindow::onCloseButtonClicked); - mTakeButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ContainerWindow::onTakeAllButtonClicked); - mContainerWidget->eventMouseButtonClick += MyGUI::newDelegate(this, &ContainerWindow::onContainerClicked); - - setText("CloseButton", MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sClose")->str); - setText("TakeButton", MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sTakeAll")->str); - - // adjust buttons size to fit text - int closeButtonWidth = mCloseButton->getTextSize().width+24; - int takeButtonWidth = mTakeButton->getTextSize().width+24; - mCloseButton->setCoord(600-20-closeButtonWidth, mCloseButton->getCoord().top, closeButtonWidth, mCloseButton->getCoord().height); - mTakeButton->setCoord(600-20-closeButtonWidth-takeButtonWidth-8, mTakeButton->getCoord().top, takeButtonWidth, mTakeButton->getCoord().height); - - int w = MyGUI::RenderManager::getInstance().getViewSize().width; - int h = MyGUI::RenderManager::getInstance().getViewSize().height; - setCoord(w-600,h-300,600,300); -} - -ContainerWindow::ContainerWindow(WindowManager& parWindowManager,DragAndDrop* dragAndDrop,std::string guiFile) +ContainerBase::ContainerBase(WindowManager& parWindowManager,DragAndDrop* dragAndDrop,std::string guiFile) : WindowBase(guiFile, parWindowManager), mDragAndDrop(dragAndDrop), mContainer() { - setText("_Main", "Name of Container"); - adjustWindowCaption(); getWidget(mContainerWidget, "Items"); - mContainerWidget->eventMouseButtonClick += MyGUI::newDelegate(this, &ContainerWindow::onContainerClicked); + getWidget(mItemView, "ItemView"); + + mContainerWidget->eventMouseButtonClick += MyGUI::newDelegate(this, &ContainerBase::onContainerClicked); + static_cast(mMainWidget)->eventWindowChangeCoord += MyGUI::newDelegate(this, &ContainerBase::onWindowResize); } -ContainerWindow::~ContainerWindow() + +ContainerBase::~ContainerBase() { } -void ContainerWindow::setName(std::string contName) -{ - setText("_Main", contName); - adjustWindowCaption(); -} - - - -void ContainerWindow::open(MWWorld::Ptr container) -{ - mContainer = container; - setName(MWWorld::Class::get(container).getName(container)); - //MWWorld::ContainerStore* containerStore = container.getContainerStore(); - drawItems(); - setVisible(true); -} - -void ContainerWindow::drawItems() -{ - while (mContainerWidget->getChildCount()) - { - MyGUI::Gui::getInstance().destroyWidget(mContainerWidget->getChildAt(0)); - } - MWWorld::ContainerStore& containerStore = MWWorld::Class::get(mContainer).getContainerStore(mContainer); - //mContainerWidget-> - - /*MWWorld::ManualRef furRef (mWindowManager.getStore(), "fur_cuirass"); - furRef.getPtr().getRefData().setCount (5); - MWWorld::ManualRef bukkitRef (mWindowManager.getStore(), "misc_com_bucket_01"); - MWWorld::ManualRef broomRef (mWindowManager.getStore(), "misc_com_broom_01"); - MWWorld::ManualRef goldRef (mWindowManager.getStore(), "gold_100"); - - containerStore.add(furRef.getPtr()); - containerStore.add(furRef.getPtr()); - containerStore.add(furRef.getPtr()); - containerStore.add(broomRef.getPtr()); - containerStore.add(broomRef.getPtr()); - containerStore.add(broomRef.getPtr()); - containerStore.add(broomRef.getPtr()); - containerStore.add(broomRef.getPtr()); - containerStore.add(broomRef.getPtr()); - containerStore.add(broomRef.getPtr()); - containerStore.add(broomRef.getPtr()); - containerStore.add(broomRef.getPtr()); - containerStore.add(broomRef.getPtr()); - containerStore.add(bukkitRef.getPtr()); - containerStore.add(bukkitRef.getPtr()); - containerStore.add(bukkitRef.getPtr()); - containerStore.add(bukkitRef.getPtr()); - containerStore.add(bukkitRef.getPtr()); - containerStore.add(bukkitRef.getPtr()); - containerStore.add(bukkitRef.getPtr()); - containerStore.add(bukkitRef.getPtr()); - containerStore.add(bukkitRef.getPtr()); - containerStore.add(bukkitRef.getPtr()); - containerStore.add(goldRef.getPtr());*/ - - - // ESMS::LiveCellRef *ref = iter->get(); - - int x = 4; - int y = 4; - int count = 0; - int index = 0; - - for (MWWorld::ContainerStoreIterator iter (containerStore.begin()); iter!=containerStore.end(); ++iter) - { - index++; - if(iter->getRefData().getCount() > 0) - { - count++; - std::string path = std::string("icons\\"); - path+=MWWorld::Class::get(*iter).getInventoryIcon(*iter); - ItemWidget* image = mContainerWidget->createWidget("ImageBox", MyGUI::IntCoord(x, y, 32, 32), MyGUI::Align::Default); - MyGUI::TextBox* text = image->createWidget("SandBrightText", MyGUI::IntCoord(x, y, 18, 18), MyGUI::Align::Default, std::string("Label")); - image->eventMouseButtonClick += MyGUI::newDelegate(this,&ContainerWindow::onSelectedItem); - image->mPos = index; - image->mPtr = *iter; - //image->eventMouseMove += MyGUI::newDelegate(this,&ContainerWindow::onMouseMove); - x += 36; - if(count % 20 == 0) - { - y += 36; - x = 4; - count = 0; - } - - if(iter->getRefData().getCount() > 1) - text->setCaption(boost::lexical_cast(iter->getRefData().getCount())); - - int pos = path.rfind("."); - path.erase(pos); - path.append(".dds"); - image->setImageTexture(path); - } - } -} - -void ContainerWindow::Update() -{ - if(mDragAndDrop->mIsOnDragAndDrop) - { - if(mDragAndDrop->mDraggedWidget) - mDragAndDrop->mDraggedWidget->setPosition(MyGUI::InputManager::getInstance().getMousePosition()); - else mDragAndDrop->mIsOnDragAndDrop = false; //If this happens, there is a bug. - } -} - -void ContainerWindow::onCloseButtonClicked(MyGUI::Widget* _sender) -{ - if(!mDragAndDrop->mIsOnDragAndDrop) - { - MWBase::Environment::get().getWindowManager()->setGuiMode(GM_Game); - setVisible(false); - } -} - -void ContainerWindow::onTakeAllButtonClicked(MyGUI::Widget* _sender) -{ - if(!mDragAndDrop->mIsOnDragAndDrop) - { - /// \todo - MWBase::Environment::get().getWindowManager()->setGuiMode(GM_Game); - setVisible(false); - } -} - -void ContainerWindow::onSelectedItem(MyGUI::Widget* _sender) +void ContainerBase::onSelectedItem(MyGUI::Widget* _sender) { if(!mDragAndDrop->mIsOnDragAndDrop) { @@ -221,22 +67,13 @@ void ContainerWindow::onSelectedItem(MyGUI::Widget* _sender) //std::cout << mContainerWidget->getParent()->getParent()->getName(); _sender->setUserString("drag","on"); mDragAndDrop->mDraggedWidget = _sender; - mDragAndDrop->mContainerWindow = const_cast(this); + mDragAndDrop->mContainerWindow = const_cast(this); drawItems(); std::cout << "selected!"; } } -void ContainerWindow::onMouseMove(MyGUI::Widget* _sender, int _left, int _top) -{ - /*if(_sender->getUserString("drag") == "on") - { - _sender->setPosition(_left,_top); - - }*/ -} - -void ContainerWindow::onContainerClicked(MyGUI::Widget* _sender) +void ContainerBase::onContainerClicked(MyGUI::Widget* _sender) { std::cout << "container clicked"; if(mDragAndDrop->mIsOnDragAndDrop) //drop widget here @@ -255,3 +92,124 @@ void ContainerWindow::onContainerClicked(MyGUI::Widget* _sender) drawItems(); } } + +void ContainerBase::onWindowResize(MyGUI::Window* window) +{ +} + +void ContainerBase::setName(std::string contName) +{ + setText("_Main", contName); + adjustWindowCaption(); +} + +void ContainerBase::open(MWWorld::Ptr container) +{ + mContainer = container; + setName(MWWorld::Class::get(container).getName(container)); + drawItems(); + setVisible(true); +} + +void ContainerBase::drawItems() +{ + while (mContainerWidget->getChildCount()) + { + MyGUI::Gui::getInstance().destroyWidget(mContainerWidget->getChildAt(0)); + } + MWWorld::ContainerStore& containerStore = MWWorld::Class::get(mContainer).getContainerStore(mContainer); + + int x = 4; + int y = 4; + int count = 0; + int index = 0; + + for (MWWorld::ContainerStoreIterator iter (containerStore.begin()); iter!=containerStore.end(); ++iter) + { + index++; + if(iter->getRefData().getCount() > 0) + { + count++; + std::string path = std::string("icons\\"); + path+=MWWorld::Class::get(*iter).getInventoryIcon(*iter); + ItemWidget* image = mContainerWidget->createWidget("ImageBox", MyGUI::IntCoord(x, y, 32, 32), MyGUI::Align::Default); + MyGUI::TextBox* text = image->createWidget("SandBrightText", MyGUI::IntCoord(x, y, 18, 18), MyGUI::Align::Default, std::string("Label")); + image->eventMouseButtonClick += MyGUI::newDelegate(this,&ContainerBase::onSelectedItem); + image->mPos = index; + image->mPtr = *iter; + x += 36; + if(count % 20 == 0) + { + y += 36; + x = 4; + count = 0; + } + + if(iter->getRefData().getCount() > 1) + text->setCaption(boost::lexical_cast(iter->getRefData().getCount())); + + int pos = path.rfind("."); + path.erase(pos); + path.append(".dds"); + image->setImageTexture(path); + } + } +} + +void ContainerBase::Update() +{ + if(mDragAndDrop->mIsOnDragAndDrop) + { + if(mDragAndDrop->mDraggedWidget) + mDragAndDrop->mDraggedWidget->setPosition(MyGUI::InputManager::getInstance().getMousePosition()); + else mDragAndDrop->mIsOnDragAndDrop = false; //If this happens, there is a bug. + } +} + +// ------------------------------------------------------------------------------------------------ + +ContainerWindow::ContainerWindow(WindowManager& parWindowManager,DragAndDrop* dragAndDrop) + : ContainerBase(parWindowManager, dragAndDrop, "openmw_container_window_layout.xml") +{ + getWidget(mTakeButton, "TakeButton"); + getWidget(mCloseButton, "CloseButton"); + + mCloseButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ContainerWindow::onCloseButtonClicked); + mTakeButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ContainerWindow::onTakeAllButtonClicked); + + setText("CloseButton", MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sClose")->str); + setText("TakeButton", MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sTakeAll")->str); + + // adjust buttons size to fit text + int closeButtonWidth = mCloseButton->getTextSize().width+24; + int takeButtonWidth = mTakeButton->getTextSize().width+24; + mCloseButton->setCoord(600-20-closeButtonWidth, mCloseButton->getCoord().top, closeButtonWidth, mCloseButton->getCoord().height); + mTakeButton->setCoord(600-20-closeButtonWidth-takeButtonWidth-8, mTakeButton->getCoord().top, takeButtonWidth, mTakeButton->getCoord().height); + + int w = MyGUI::RenderManager::getInstance().getViewSize().width; + int h = MyGUI::RenderManager::getInstance().getViewSize().height; + setCoord(w-600,h-300,600,300); +} + +ContainerWindow::~ContainerWindow() +{ +} + +void ContainerWindow::onCloseButtonClicked(MyGUI::Widget* _sender) +{ + if(!mDragAndDrop->mIsOnDragAndDrop) + { + MWBase::Environment::get().getWindowManager()->setGuiMode(GM_Game); + setVisible(false); + } +} + +void ContainerWindow::onTakeAllButtonClicked(MyGUI::Widget* _sender) +{ + if(!mDragAndDrop->mIsOnDragAndDrop) + { + /// \todo + MWBase::Environment::get().getWindowManager()->setGuiMode(GM_Game); + setVisible(false); + } +} diff --git a/apps/openmw/mwgui/container.hpp b/apps/openmw/mwgui/container.hpp index ad029ae805..84b63abc8e 100644 --- a/apps/openmw/mwgui/container.hpp +++ b/apps/openmw/mwgui/container.hpp @@ -27,6 +27,7 @@ namespace MWGui { class WindowManager; class ContainerWindow; + class ContainerBase; } @@ -36,44 +37,55 @@ namespace MWGui { public: bool mIsOnDragAndDrop; - ContainerWindow* mContainerWindow; + ContainerBase* mContainerWindow; MyGUI::Widget* mDraggedWidget; MyGUI::Widget* mDragAndDropWidget; MWWorld::ContainerStore mStore; MWWorld::Ptr mItem; }; - class ContainerWindow : public WindowBase + class ContainerBase : public WindowBase { public: - ContainerWindow(WindowManager& parWindowManager,DragAndDrop* dragAndDrop); - ContainerWindow(WindowManager& parWindowManager,DragAndDrop* dragAndDrop, - std::string guiFile); + ContainerBase(WindowManager& parWindowManager, DragAndDrop* dragAndDrop, std::string guiFile); + virtual ~ContainerBase(); void open(MWWorld::Ptr container); void setName(std::string contName); void Update(); + protected: + MyGUI::ScrollView* mItemView; + MyGUI::Widget* mContainerWidget; + + DragAndDrop* mDragAndDrop; + MWWorld::Ptr mContainer; + + void onSelectedItem(MyGUI::Widget* _sender); + void onContainerClicked(MyGUI::Widget* _sender); + void onWindowResize(MyGUI::Window* window); + + void drawItems(); + }; + + class ContainerWindow : public ContainerBase + { + public: + ContainerWindow(WindowManager& parWindowManager,DragAndDrop* dragAndDrop); + virtual ~ContainerWindow(); protected: std::vector mContainerWidgets; - MyGUI::ItemBoxPtr mContainerWidget; - MyGUI::ButtonPtr mTakeButton; - MyGUI::ButtonPtr mCloseButton; - DragAndDrop* mDragAndDrop; + MyGUI::Button* mTakeButton; + MyGUI::Button* mCloseButton; - MWWorld::Ptr mContainer; bool mIsValid;//is in the right GUI Mode - void drawItems(); void onCloseButtonClicked(MyGUI::Widget* _sender); void onTakeAllButtonClicked(MyGUI::Widget* _sender); - void onSelectedItem(MyGUI::Widget* _sender); - void onContainerClicked(MyGUI::Widget* _sender); - void onMouseMove(MyGUI::Widget* _sender, int _left, int _top); }; } #endif // CONTAINER_H diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index cb628ba4a7..416be53677 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -22,7 +22,7 @@ namespace MWGui { InventoryWindow::InventoryWindow(WindowManager& parWindowManager,DragAndDrop* dragAndDrop) - :ContainerWindow(parWindowManager,dragAndDrop,"openmw_inventory_window_layout.xml") + : ContainerBase(parWindowManager,dragAndDrop,"openmw_inventory_window_layout.xml") { } diff --git a/apps/openmw/mwgui/inventorywindow.hpp b/apps/openmw/mwgui/inventorywindow.hpp index 21f27b12fb..152f8b0d0f 100644 --- a/apps/openmw/mwgui/inventorywindow.hpp +++ b/apps/openmw/mwgui/inventorywindow.hpp @@ -21,7 +21,7 @@ namespace MWGui namespace MWGui { - class InventoryWindow : public MWGui::ContainerWindow + class InventoryWindow : public MWGui::ContainerBase { public: InventoryWindow(WindowManager& parWindowManager,DragAndDrop* dragAndDrop); diff --git a/files/mygui/openmw_container_window_layout.xml b/files/mygui/openmw_container_window_layout.xml index 25156c5a2a..9679519d4a 100644 --- a/files/mygui/openmw_container_window_layout.xml +++ b/files/mygui/openmw_container_window_layout.xml @@ -3,8 +3,13 @@ - - + + + + + + + diff --git a/files/mygui/openmw_inventory_window_layout.xml b/files/mygui/openmw_inventory_window_layout.xml index 766cacdb1e..40d89f2213 100644 --- a/files/mygui/openmw_inventory_window_layout.xml +++ b/files/mygui/openmw_inventory_window_layout.xml @@ -3,7 +3,7 @@ - + @@ -14,7 +14,12 @@ - + + + + + + diff --git a/files/mygui/openmw_scroll_skin.xml b/files/mygui/openmw_scroll_skin.xml index 39437d54e7..64e4676615 100644 --- a/files/mygui/openmw_scroll_skin.xml +++ b/files/mygui/openmw_scroll_skin.xml @@ -4,7 +4,6 @@ - From 7723044df0009c58beb4fc4a1c00478cf352a147 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 12 May 2012 13:30:34 +0200 Subject: [PATCH 116/325] added the item tooltips --- apps/openmw/mwgui/container.cpp | 5 +++-- apps/openmw/mwgui/itemwidget.hpp | 3 +-- apps/openmw/mwgui/tooltips.cpp | 9 ++++++++- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index b4d3698061..65df9a9dd3 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -80,7 +80,7 @@ void ContainerBase::onContainerClicked(MyGUI::Widget* _sender) { ItemWidget* item = static_cast(mDragAndDrop->mDraggedWidget); std::cout << item->mPos << (*mDragAndDrop->mStore.begin()).getTypeName(); - if(item->mPtr.getContainerStore() == 0) std::cout << "nocontainer!"; + if((*item->getUserData()).getContainerStore() == 0) std::cout << "nocontainer!"; MWWorld::ContainerStore& containerStore = MWWorld::Class::get(mContainer).getContainerStore(mContainer); containerStore.add(*mDragAndDrop->mStore.begin()); mDragAndDrop->mStore.clear(); @@ -135,8 +135,9 @@ void ContainerBase::drawItems() ItemWidget* image = mContainerWidget->createWidget("ImageBox", MyGUI::IntCoord(x, y, 32, 32), MyGUI::Align::Default); MyGUI::TextBox* text = image->createWidget("SandBrightText", MyGUI::IntCoord(x, y, 18, 18), MyGUI::Align::Default, std::string("Label")); image->eventMouseButtonClick += MyGUI::newDelegate(this,&ContainerBase::onSelectedItem); + image->setUserString("ToolTipType", "ItemPtr"); + image->setUserData(*iter); image->mPos = index; - image->mPtr = *iter; x += 36; if(count % 20 == 0) { diff --git a/apps/openmw/mwgui/itemwidget.hpp b/apps/openmw/mwgui/itemwidget.hpp index ff65bfd4d0..0b204b10ea 100644 --- a/apps/openmw/mwgui/itemwidget.hpp +++ b/apps/openmw/mwgui/itemwidget.hpp @@ -10,9 +10,8 @@ namespace MWGui MYGUI_RTTI_DERIVED( ItemWidget ) public: - MWWorld::Ptr mPtr; int mPos; }; } -#endif \ No newline at end of file +#endif diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 7dc1ecba73..baa38f430b 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -61,12 +61,14 @@ void ToolTips::onFrame(float frameDuration) else if (type == "Text") { info.text = text; + tooltipSize = createToolTip(info); } else if (type == "CaptionText") { std::string caption = focus->getUserString("ToolTipCaption"); info.caption = caption; info.text = text; + tooltipSize = createToolTip(info); } else if (type == "ImageCaptionText") { @@ -77,8 +79,13 @@ void ToolTips::onFrame(float frameDuration) info.text = text; info.caption = caption; info.icon = image; + tooltipSize = createToolTip(info); + } + else if (type == "ItemPtr") + { + mFocusObject = *focus->getUserData(); + tooltipSize = getToolTipViaPtr(); } - tooltipSize = createToolTip(info); IntPoint tooltipPosition = InputManager::getInstance().getMousePosition() + IntPoint(0, 24); From d64fccec6fe71e9eca42750edf4043aa17a65c06 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 12 May 2012 13:46:03 +0200 Subject: [PATCH 117/325] display the item count in the tooltip --- apps/openmw/mwclass/activator.cpp | 2 +- apps/openmw/mwclass/apparatus.cpp | 2 +- apps/openmw/mwclass/armor.cpp | 2 +- apps/openmw/mwclass/book.cpp | 2 +- apps/openmw/mwclass/clothing.cpp | 2 +- apps/openmw/mwclass/ingredient.cpp | 2 +- apps/openmw/mwclass/light.cpp | 2 +- apps/openmw/mwclass/lockpick.cpp | 2 +- apps/openmw/mwclass/misc.cpp | 2 +- apps/openmw/mwclass/potion.cpp | 2 +- apps/openmw/mwclass/probe.cpp | 2 +- apps/openmw/mwclass/repair.cpp | 2 +- apps/openmw/mwclass/weapon.cpp | 2 +- apps/openmw/mwgui/container.cpp | 11 ++++++----- apps/openmw/mwgui/container.hpp | 3 +-- apps/openmw/mwgui/tooltips.cpp | 8 ++++++++ apps/openmw/mwgui/tooltips.hpp | 3 +++ 17 files changed, 31 insertions(+), 20 deletions(-) diff --git a/apps/openmw/mwclass/activator.cpp b/apps/openmw/mwclass/activator.cpp index 6faaacf319..505f61f4ca 100644 --- a/apps/openmw/mwclass/activator.cpp +++ b/apps/openmw/mwclass/activator.cpp @@ -79,7 +79,7 @@ namespace MWClass ptr.get(); MWGui::ToolTipInfo info; - info.caption = ref->base->name; + info.caption = ref->base->name + MWGui::ToolTips::getCountString(ptr.getRefData().getCount()); std::string text; if (MWBase::Environment::get().getWindowManager()->getFullHelp()) diff --git a/apps/openmw/mwclass/apparatus.cpp b/apps/openmw/mwclass/apparatus.cpp index 24d08b8042..0ce01024db 100644 --- a/apps/openmw/mwclass/apparatus.cpp +++ b/apps/openmw/mwclass/apparatus.cpp @@ -122,7 +122,7 @@ namespace MWClass ptr.get(); MWGui::ToolTipInfo info; - info.caption = ref->base->name; + info.caption = ref->base->name + MWGui::ToolTips::getCountString(ptr.getRefData().getCount()); info.icon = ref->base->icon; const ESMS::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index 1598085f39..9bd5f03d6f 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -220,7 +220,7 @@ namespace MWClass ptr.get(); MWGui::ToolTipInfo info; - info.caption = ref->base->name; + info.caption = ref->base->name + MWGui::ToolTips::getCountString(ptr.getRefData().getCount()); info.icon = ref->base->icon; std::string text; diff --git a/apps/openmw/mwclass/book.cpp b/apps/openmw/mwclass/book.cpp index 72ebb4b801..3d8adf0144 100644 --- a/apps/openmw/mwclass/book.cpp +++ b/apps/openmw/mwclass/book.cpp @@ -119,7 +119,7 @@ namespace MWClass ptr.get(); MWGui::ToolTipInfo info; - info.caption = ref->base->name; + info.caption = ref->base->name + MWGui::ToolTips::getCountString(ptr.getRefData().getCount()); info.icon = ref->base->icon; const ESMS::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); diff --git a/apps/openmw/mwclass/clothing.cpp b/apps/openmw/mwclass/clothing.cpp index 57d5e1a64e..e81bb7419e 100644 --- a/apps/openmw/mwclass/clothing.cpp +++ b/apps/openmw/mwclass/clothing.cpp @@ -188,7 +188,7 @@ namespace MWClass ptr.get(); MWGui::ToolTipInfo info; - info.caption = ref->base->name; + info.caption = ref->base->name + MWGui::ToolTips::getCountString(ptr.getRefData().getCount()); info.icon = ref->base->icon; const ESMS::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); diff --git a/apps/openmw/mwclass/ingredient.cpp b/apps/openmw/mwclass/ingredient.cpp index 7a1cea7ff9..c0186da37a 100644 --- a/apps/openmw/mwclass/ingredient.cpp +++ b/apps/openmw/mwclass/ingredient.cpp @@ -120,7 +120,7 @@ namespace MWClass ptr.get(); MWGui::ToolTipInfo info; - info.caption = ref->base->name; + info.caption = ref->base->name + MWGui::ToolTips::getCountString(ptr.getRefData().getCount()); info.icon = ref->base->icon; const ESMS::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index 49c80b0119..d9af2e73f3 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -163,7 +163,7 @@ namespace MWClass ptr.get(); MWGui::ToolTipInfo info; - info.caption = ref->base->name; + info.caption = ref->base->name + MWGui::ToolTips::getCountString(ptr.getRefData().getCount()); info.icon = ref->base->icon; const ESMS::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); diff --git a/apps/openmw/mwclass/lockpick.cpp b/apps/openmw/mwclass/lockpick.cpp index 89cff28557..5bb6776465 100644 --- a/apps/openmw/mwclass/lockpick.cpp +++ b/apps/openmw/mwclass/lockpick.cpp @@ -132,7 +132,7 @@ namespace MWClass ptr.get(); MWGui::ToolTipInfo info; - info.caption = ref->base->name; + info.caption = ref->base->name + MWGui::ToolTips::getCountString(ptr.getRefData().getCount()); info.icon = ref->base->icon; const ESMS::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); diff --git a/apps/openmw/mwclass/misc.cpp b/apps/openmw/mwclass/misc.cpp index 76444318bf..70ba16c031 100644 --- a/apps/openmw/mwclass/misc.cpp +++ b/apps/openmw/mwclass/misc.cpp @@ -138,7 +138,7 @@ namespace MWClass ptr.get(); MWGui::ToolTipInfo info; - info.caption = ref->base->name; + info.caption = ref->base->name + MWGui::ToolTips::getCountString(ptr.getRefData().getCount()); info.icon = ref->base->icon; const ESMS::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); diff --git a/apps/openmw/mwclass/potion.cpp b/apps/openmw/mwclass/potion.cpp index 51d3fefae6..ffc8386396 100644 --- a/apps/openmw/mwclass/potion.cpp +++ b/apps/openmw/mwclass/potion.cpp @@ -122,7 +122,7 @@ namespace MWClass ptr.get(); MWGui::ToolTipInfo info; - info.caption = ref->base->name; + info.caption = ref->base->name + MWGui::ToolTips::getCountString(ptr.getRefData().getCount()); info.icon = ref->base->icon; const ESMS::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); diff --git a/apps/openmw/mwclass/probe.cpp b/apps/openmw/mwclass/probe.cpp index 5161301e0e..1e713f0a5d 100644 --- a/apps/openmw/mwclass/probe.cpp +++ b/apps/openmw/mwclass/probe.cpp @@ -131,7 +131,7 @@ namespace MWClass ptr.get(); MWGui::ToolTipInfo info; - info.caption = ref->base->name; + info.caption = ref->base->name + MWGui::ToolTips::getCountString(ptr.getRefData().getCount()); info.icon = ref->base->icon; const ESMS::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); diff --git a/apps/openmw/mwclass/repair.cpp b/apps/openmw/mwclass/repair.cpp index ce68843ed5..5666a95a50 100644 --- a/apps/openmw/mwclass/repair.cpp +++ b/apps/openmw/mwclass/repair.cpp @@ -121,7 +121,7 @@ namespace MWClass ptr.get(); MWGui::ToolTipInfo info; - info.caption = ref->base->name; + info.caption = ref->base->name + MWGui::ToolTips::getCountString(ptr.getRefData().getCount()); info.icon = ref->base->icon; std::string text; diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index ed31606d0f..3865358bda 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -272,7 +272,7 @@ namespace MWClass ptr.get(); MWGui::ToolTipInfo info; - info.caption = ref->base->name; + info.caption = ref->base->name + MWGui::ToolTips::getCountString(ptr.getRefData().getCount()); info.icon = ref->base->icon; const ESMS::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 65df9a9dd3..792010f38e 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -34,7 +34,6 @@ ContainerBase::ContainerBase(WindowManager& parWindowManager,DragAndDrop* dragAn getWidget(mItemView, "ItemView"); mContainerWidget->eventMouseButtonClick += MyGUI::newDelegate(this, &ContainerBase::onContainerClicked); - static_cast(mMainWidget)->eventWindowChangeCoord += MyGUI::newDelegate(this, &ContainerBase::onWindowResize); } ContainerBase::~ContainerBase() @@ -93,10 +92,6 @@ void ContainerBase::onContainerClicked(MyGUI::Widget* _sender) } } -void ContainerBase::onWindowResize(MyGUI::Window* window) -{ -} - void ContainerBase::setName(std::string contName) { setText("_Main", contName); @@ -190,12 +185,18 @@ ContainerWindow::ContainerWindow(WindowManager& parWindowManager,DragAndDrop* dr int w = MyGUI::RenderManager::getInstance().getViewSize().width; int h = MyGUI::RenderManager::getInstance().getViewSize().height; setCoord(w-600,h-300,600,300); + + static_cast(mMainWidget)->eventWindowChangeCoord += MyGUI::newDelegate(this, &ContainerWindow::onWindowResize); } ContainerWindow::~ContainerWindow() { } +void ContainerWindow::onWindowResize(MyGUI::Window* window) +{ +} + void ContainerWindow::onCloseButtonClicked(MyGUI::Widget* _sender) { if(!mDragAndDrop->mIsOnDragAndDrop) diff --git a/apps/openmw/mwgui/container.hpp b/apps/openmw/mwgui/container.hpp index 84b63abc8e..2552922f86 100644 --- a/apps/openmw/mwgui/container.hpp +++ b/apps/openmw/mwgui/container.hpp @@ -63,7 +63,6 @@ namespace MWGui void onSelectedItem(MyGUI::Widget* _sender); void onContainerClicked(MyGUI::Widget* _sender); - void onWindowResize(MyGUI::Window* window); void drawItems(); }; @@ -83,7 +82,7 @@ namespace MWGui bool mIsValid;//is in the right GUI Mode - + void onWindowResize(MyGUI::Window* window); void onCloseButtonClicked(MyGUI::Widget* _sender); void onTakeAllButtonClicked(MyGUI::Widget* _sender); }; diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index baa38f430b..aa189b2e86 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -357,6 +357,14 @@ std::string ToolTips::getMiscString(const std::string& text, const std::string& return "\n" + prefix + ": " + text; } +std::string ToolTips::getCountString(const int value) +{ + if (value == 1) + return ""; + else + return " (" + boost::lexical_cast(value) + ")"; +} + void ToolTips::toggleFullHelp() { mFullHelp = !mFullHelp; diff --git a/apps/openmw/mwgui/tooltips.hpp b/apps/openmw/mwgui/tooltips.hpp index fafe471a57..d20360a796 100644 --- a/apps/openmw/mwgui/tooltips.hpp +++ b/apps/openmw/mwgui/tooltips.hpp @@ -53,6 +53,9 @@ namespace MWGui static std::string toString(const float value); static std::string toString(const int value); + static std::string getCountString(const int value); + ///< @return blank string if count is 1, or else " (value)" + private: MyGUI::Widget* mDynamicToolTipBox; From 722af60337e4faecc0e13a2ba2eefd8f244eebb7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 12 May 2012 14:01:59 +0200 Subject: [PATCH 118/325] implemented the "Take all" button --- apps/openmw/mwgui/container.cpp | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 792010f38e..0b264d48ce 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -9,6 +9,7 @@ #include "../mwworld/world.hpp" #include "../mwworld/containerstore.hpp" #include "../mwworld/class.hpp" +#include "../mwworld/player.hpp" #include "../mwclass/container.hpp" #include "../mwinput/inputmanager.hpp" @@ -210,7 +211,22 @@ void ContainerWindow::onTakeAllButtonClicked(MyGUI::Widget* _sender) { if(!mDragAndDrop->mIsOnDragAndDrop) { - /// \todo + // transfer everything into the player's inventory + MWWorld::ContainerStore& containerStore = MWWorld::Class::get(mContainer).getContainerStore(mContainer); + + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + MWWorld::ContainerStore& playerStore = MWWorld::Class::get(player).getContainerStore(player); + + for (MWWorld::ContainerStoreIterator iter (containerStore.begin()); iter!=containerStore.end(); ++iter) + { + if(iter->getRefData().getCount() > 0) + { + playerStore.add(*iter); + } + } + + containerStore.clear(); + MWBase::Environment::get().getWindowManager()->setGuiMode(GM_Game); setVisible(false); } From a31a9e51d3e3b853ca02db3d667fd417dbf2d5df Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 12 May 2012 14:29:49 +0200 Subject: [PATCH 119/325] add the sound for item drag&drop --- apps/openmw/mwclass/misc.cpp | 15 ++++++++++----- apps/openmw/mwgui/container.cpp | 20 ++++++++++++++------ 2 files changed, 24 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwclass/misc.cpp b/apps/openmw/mwclass/misc.cpp index 70ba16c031..936dc4558d 100644 --- a/apps/openmw/mwclass/misc.cpp +++ b/apps/openmw/mwclass/misc.cpp @@ -138,11 +138,18 @@ namespace MWClass ptr.get(); MWGui::ToolTipInfo info; - info.caption = ref->base->name + MWGui::ToolTips::getCountString(ptr.getRefData().getCount()); - info.icon = ref->base->icon; const ESMS::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); + int count = ptr.getRefData().getCount(); + // gold has count both as reference count and as value, multiply them together to get real count + bool isGold = (ref->base->name == store.gameSettings.search("sGold")->str); + if (isGold) + count *= ref->base->data.value; + + info.caption = ref->base->name + MWGui::ToolTips::getCountString(count); + info.icon = ref->base->icon; + if (ref->ref.soul != "") { const ESM::Creature *creature = store.creatures.search(ref->ref.soul); @@ -151,9 +158,7 @@ namespace MWClass std::string text; - if (ref->base->name == store.gameSettings.search("sGold")->str) - info.caption += " (" + boost::lexical_cast(ref->base->data.value) + ")"; - else + if (!isGold) { text += "\n" + store.gameSettings.search("sWeight")->str + ": " + MWGui::ToolTips::toString(ref->base->data.weight); text += MWGui::ToolTips::getValueString(ref->base->data.value, store.gameSettings.search("sValue")->str); diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 0b264d48ce..661495559e 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -12,6 +12,7 @@ #include "../mwworld/player.hpp" #include "../mwclass/container.hpp" #include "../mwinput/inputmanager.hpp" +#include "../mwsound/soundmanager.hpp" #include #include @@ -53,34 +54,41 @@ void ContainerBase::onSelectedItem(MyGUI::Widget* _sender) int count = 0; MWWorld::ContainerStore& containerStore = MWWorld::Class::get(mContainer).getContainerStore(mContainer); + MWWorld::Ptr object; for (MWWorld::ContainerStoreIterator iter (containerStore.begin()); iter!=containerStore.end(); ++iter) { count++; if(count == item->mPos) { mDragAndDrop->mStore.add(*iter); + object = *iter; iter->getRefData().setCount(0); break; } } - //containerStore. - //std::cout << mContainerWidget->getParent()->getParent()->getName(); + + std::string sound = MWWorld::Class::get(object).getUpSoundId(object); + MWBase::Environment::get().getSoundManager()->playSound (sound, 1.0, 1.0); + _sender->setUserString("drag","on"); mDragAndDrop->mDraggedWidget = _sender; mDragAndDrop->mContainerWindow = const_cast(this); drawItems(); - std::cout << "selected!"; } } void ContainerBase::onContainerClicked(MyGUI::Widget* _sender) { - std::cout << "container clicked"; if(mDragAndDrop->mIsOnDragAndDrop) //drop widget here { ItemWidget* item = static_cast(mDragAndDrop->mDraggedWidget); - std::cout << item->mPos << (*mDragAndDrop->mStore.begin()).getTypeName(); - if((*item->getUserData()).getContainerStore() == 0) std::cout << "nocontainer!"; + + MWWorld::Ptr object = *item->getUserData(); + assert(object.getContainerStore() && "Item is not in a container!"); + + std::string sound = MWWorld::Class::get(object).getDownSoundId(object); + MWBase::Environment::get().getSoundManager()->playSound (sound, 1.0, 1.0); + MWWorld::ContainerStore& containerStore = MWWorld::Class::get(mContainer).getContainerStore(mContainer); containerStore.add(*mDragAndDrop->mStore.begin()); mDragAndDrop->mStore.clear(); From 5b0251b09f1123874b5af665aa44eae5e452489c Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 12 May 2012 16:17:03 +0200 Subject: [PATCH 120/325] item stacking --- apps/openmw/mwclass/armor.cpp | 8 ++++++++ apps/openmw/mwclass/armor.hpp | 3 +++ apps/openmw/mwclass/clothing.cpp | 8 ++++++++ apps/openmw/mwclass/clothing.hpp | 3 +++ apps/openmw/mwclass/weapon.cpp | 8 ++++++++ apps/openmw/mwclass/weapon.hpp | 3 +++ apps/openmw/mwworld/class.cpp | 5 +++++ apps/openmw/mwworld/class.hpp | 6 +++++- apps/openmw/mwworld/containerstore.cpp | 18 +++++++++++++++++- 9 files changed, 60 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index fb34e4c883..87a5dde27a 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -248,4 +248,12 @@ namespace MWClass return info; } + + std::string Armor::getEnchantment (const MWWorld::Ptr& ptr) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + return ref->base->enchant; + } } diff --git a/apps/openmw/mwclass/armor.hpp b/apps/openmw/mwclass/armor.hpp index c757587e5e..3ff101a5e5 100644 --- a/apps/openmw/mwclass/armor.hpp +++ b/apps/openmw/mwclass/armor.hpp @@ -55,6 +55,9 @@ namespace MWClass virtual std::string getDownSoundId (const MWWorld::Ptr& ptr) const; ///< Return the put down sound Id + + virtual std::string getEnchantment (const MWWorld::Ptr& ptr) const; + ///< @return the enchantment ID if the object is enchanted, otherwise an empty string }; } diff --git a/apps/openmw/mwclass/clothing.cpp b/apps/openmw/mwclass/clothing.cpp index 620b664cc4..a242874df3 100644 --- a/apps/openmw/mwclass/clothing.cpp +++ b/apps/openmw/mwclass/clothing.cpp @@ -201,4 +201,12 @@ namespace MWClass return info; } + + std::string Clothing::getEnchantment (const MWWorld::Ptr& ptr) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + return ref->base->enchant; + } } diff --git a/apps/openmw/mwclass/clothing.hpp b/apps/openmw/mwclass/clothing.hpp index afb1849995..9b9322969a 100644 --- a/apps/openmw/mwclass/clothing.hpp +++ b/apps/openmw/mwclass/clothing.hpp @@ -49,6 +49,9 @@ namespace MWClass virtual std::string getDownSoundId (const MWWorld::Ptr& ptr) const; ///< Return the put down sound Id + + virtual std::string getEnchantment (const MWWorld::Ptr& ptr) const; + ///< @return the enchantment ID if the object is enchanted, otherwise an empty string }; } diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index fcfaebcb7a..0ddf19d3cc 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -339,4 +339,12 @@ namespace MWClass return info; } + + std::string Weapon::getEnchantment (const MWWorld::Ptr& ptr) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + return ref->base->enchant; + } } diff --git a/apps/openmw/mwclass/weapon.hpp b/apps/openmw/mwclass/weapon.hpp index 9c5f43bd3f..c27a39620d 100644 --- a/apps/openmw/mwclass/weapon.hpp +++ b/apps/openmw/mwclass/weapon.hpp @@ -55,6 +55,9 @@ namespace MWClass virtual std::string getDownSoundId (const MWWorld::Ptr& ptr) const; ///< Return the put down sound Id + + virtual std::string getEnchantment (const MWWorld::Ptr& ptr) const; + ///< @return the enchantment ID if the object is enchanted, otherwise an empty string }; } diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 78ed5ca2e5..151d913bed 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -181,4 +181,9 @@ namespace MWWorld { return false; } + + std::string Class::getEnchantment (const Ptr& ptr) const + { + return ""; + } } diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index e69b8f2ac9..d7a2d2d759 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -136,7 +136,7 @@ namespace MWWorld ///< Set or unset a stance. virtual bool getStance (const Ptr& ptr, Stance stance, bool ignoreForce = false) const; - ////< Check if a stance is active or not. + ///< Check if a stance is active or not. virtual float getSpeed (const Ptr& ptr) const; ///< Return movement speed. @@ -179,6 +179,10 @@ namespace MWWorld virtual std::string getDownSoundId (const Ptr& ptr) const; ///< Return the down sound ID of \a ptr or throw an exception, if class does not support ID retrieval /// (default implementation: throw an exception) + + virtual std::string getEnchantment (const MWWorld::Ptr& ptr) const; + ///< @return the enchantment ID if the object is enchanted, otherwise an empty string + /// (default implementation: return empty string) }; } diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index 2800b6f3c1..4f799f5766 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -9,6 +9,7 @@ #include "manualref.hpp" #include "refdata.hpp" +#include "class.hpp" namespace { @@ -46,7 +47,22 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::end() void MWWorld::ContainerStore::add (const Ptr& ptr) { - /// \todo implement item stacking + // determine whether to stack or not + // item stacking depends on owner, script, enchantment and name + for (MWWorld::ContainerStoreIterator iter (begin(getType(ptr))); iter!=end(); ++iter) + { + if ( iter->mCellRef->refID == ptr.mCellRef->refID + && MWWorld::Class::get(*iter).getScript(*iter) == MWWorld::Class::get(ptr).getScript(ptr) + && MWWorld::Class::get(*iter).getEnchantment(*iter) == MWWorld::Class::get(ptr).getEnchantment(ptr) + && iter->mCellRef->owner == ptr.mCellRef->owner) + { + // stack + iter->getRefData().setCount( iter->getRefData().getCount() + ptr.getRefData().getCount() ); + + flagAsModified(); + return; + } + } switch (getType (ptr)) { From 9f2595183b039a29f3c79788a4048063041521d9 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 12 May 2012 16:30:27 +0200 Subject: [PATCH 121/325] type --- apps/openmw/mwworld/containerstore.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index 4f799f5766..32e2da0ae1 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -47,9 +47,11 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::end() void MWWorld::ContainerStore::add (const Ptr& ptr) { + int type = getType(ptr); + // determine whether to stack or not // item stacking depends on owner, script, enchantment and name - for (MWWorld::ContainerStoreIterator iter (begin(getType(ptr))); iter!=end(); ++iter) + for (MWWorld::ContainerStoreIterator iter (begin(type)); iter!=end(); ++iter) { if ( iter->mCellRef->refID == ptr.mCellRef->refID && MWWorld::Class::get(*iter).getScript(*iter) == MWWorld::Class::get(ptr).getScript(ptr) @@ -64,7 +66,7 @@ void MWWorld::ContainerStore::add (const Ptr& ptr) } } - switch (getType (ptr)) + switch (type) { case Type_Potion: potions.list.push_back (*ptr.get()); break; case Type_Apparatus: appas.list.push_back (*ptr.get()); break; From 1abf70692cb2381886e9586a66d766333fbd42b6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 12 May 2012 18:24:47 +0200 Subject: [PATCH 122/325] added a scrollbar to the item container, dynamic positioning of items, fixed the item count display bug --- apps/openmw/mwgui/container.cpp | 24 ++++++++++++------- apps/openmw/mwgui/inventorywindow.cpp | 6 +++++ apps/openmw/mwgui/inventorywindow.hpp | 3 +++ .../mygui/openmw_container_window_layout.xml | 6 ++--- .../mygui/openmw_inventory_window_layout.xml | 2 +- files/mygui/openmw_list.skin.xml | 3 ++- files/mygui/openmw_scroll_skin.xml | 5 ++++ 7 files changed, 35 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 661495559e..d79693114a 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -125,7 +125,8 @@ void ContainerBase::drawItems() int x = 4; int y = 4; - int count = 0; + int maxHeight = mItemView->getSize().height - 48; + int index = 0; for (MWWorld::ContainerStoreIterator iter (containerStore.begin()); iter!=containerStore.end(); ++iter) @@ -133,21 +134,21 @@ void ContainerBase::drawItems() index++; if(iter->getRefData().getCount() > 0) { - count++; std::string path = std::string("icons\\"); path+=MWWorld::Class::get(*iter).getInventoryIcon(*iter); ItemWidget* image = mContainerWidget->createWidget("ImageBox", MyGUI::IntCoord(x, y, 32, 32), MyGUI::Align::Default); - MyGUI::TextBox* text = image->createWidget("SandBrightText", MyGUI::IntCoord(x, y, 18, 18), MyGUI::Align::Default, std::string("Label")); + MyGUI::TextBox* text = image->createWidget("SandBrightText", MyGUI::IntCoord(14, 14, 18, 18), MyGUI::Align::Default, std::string("Label")); + text->setTextAlign(MyGUI::Align::Right); + text->setNeedMouseFocus(false); image->eventMouseButtonClick += MyGUI::newDelegate(this,&ContainerBase::onSelectedItem); image->setUserString("ToolTipType", "ItemPtr"); image->setUserData(*iter); image->mPos = index; - x += 36; - if(count % 20 == 0) - { y += 36; - x = 4; - count = 0; + if (y > maxHeight) + { + x += 36; + y = 4; } if(iter->getRefData().getCount() > 1) @@ -158,7 +159,11 @@ void ContainerBase::drawItems() path.append(".dds"); image->setImageTexture(path); } - } + } + + MyGUI::IntSize size = MyGUI::IntSize(std::max(mItemView->getSize().width, x), 2048); + mItemView->setCanvasSize(size); + mContainerWidget->setSize(size); } void ContainerBase::Update() @@ -204,6 +209,7 @@ ContainerWindow::~ContainerWindow() void ContainerWindow::onWindowResize(MyGUI::Window* window) { + drawItems(); } void ContainerWindow::onCloseButtonClicked(MyGUI::Widget* _sender) diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 416be53677..b85380968d 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -24,6 +24,7 @@ namespace MWGui InventoryWindow::InventoryWindow(WindowManager& parWindowManager,DragAndDrop* dragAndDrop) : ContainerBase(parWindowManager,dragAndDrop,"openmw_inventory_window_layout.xml") { + static_cast(mMainWidget)->eventWindowChangeCoord += MyGUI::newDelegate(this, &InventoryWindow::onWindowResize); } void InventoryWindow::openInventory() @@ -31,4 +32,9 @@ namespace MWGui open(MWBase::Environment::get().getWorld()->getPlayer().getPlayer()); } + void InventoryWindow::onWindowResize(MyGUI::Window* _sender) + { + drawItems(); + } + } diff --git a/apps/openmw/mwgui/inventorywindow.hpp b/apps/openmw/mwgui/inventorywindow.hpp index 152f8b0d0f..813fc88ab8 100644 --- a/apps/openmw/mwgui/inventorywindow.hpp +++ b/apps/openmw/mwgui/inventorywindow.hpp @@ -27,6 +27,9 @@ namespace MWGui InventoryWindow(WindowManager& parWindowManager,DragAndDrop* dragAndDrop); void openInventory(); + + protected: + void onWindowResize(MyGUI::Window* _sender); }; } #endif // Inventory_H diff --git a/files/mygui/openmw_container_window_layout.xml b/files/mygui/openmw_container_window_layout.xml index 9679519d4a..26fe0a3d30 100644 --- a/files/mygui/openmw_container_window_layout.xml +++ b/files/mygui/openmw_container_window_layout.xml @@ -4,10 +4,10 @@ - - + + - + diff --git a/files/mygui/openmw_inventory_window_layout.xml b/files/mygui/openmw_inventory_window_layout.xml index 40d89f2213..a347a510e7 100644 --- a/files/mygui/openmw_inventory_window_layout.xml +++ b/files/mygui/openmw_inventory_window_layout.xml @@ -15,7 +15,7 @@ - + diff --git a/files/mygui/openmw_list.skin.xml b/files/mygui/openmw_list.skin.xml index 89cc73123c..213e8470f5 100644 --- a/files/mygui/openmw_list.skin.xml +++ b/files/mygui/openmw_list.skin.xml @@ -131,6 +131,7 @@ + @@ -143,7 +144,7 @@ - + diff --git a/files/mygui/openmw_scroll_skin.xml b/files/mygui/openmw_scroll_skin.xml index 64e4676615..70fad3f4b4 100644 --- a/files/mygui/openmw_scroll_skin.xml +++ b/files/mygui/openmw_scroll_skin.xml @@ -7,4 +7,9 @@ + + + + + From e714b77df8a5ea34b1b8295688ebe6350832fc2d Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 12 May 2012 18:28:14 +0200 Subject: [PATCH 123/325] small fix --- apps/openmw/mwgui/container.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index d79693114a..ba9a3213da 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -161,7 +161,7 @@ void ContainerBase::drawItems() } } - MyGUI::IntSize size = MyGUI::IntSize(std::max(mItemView->getSize().width, x), 2048); + MyGUI::IntSize size = MyGUI::IntSize(std::max(mItemView->getSize().width, x), mItemView->getSize().height); mItemView->setCanvasSize(size); mContainerWidget->setSize(size); } From 19e8e84f9ac4224c785a68799c645f7cad276464 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 12 May 2012 18:50:19 +0200 Subject: [PATCH 124/325] more cleanup, removed the redundant ItemWidget and use widget userdata --- apps/openmw/mwgui/container.cpp | 68 ++++++++++++---------------- apps/openmw/mwgui/itemwidget.hpp | 17 ------- apps/openmw/mwgui/window_manager.cpp | 2 - 3 files changed, 30 insertions(+), 57 deletions(-) delete mode 100644 apps/openmw/mwgui/itemwidget.hpp diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index ba9a3213da..1f6a6f2f6f 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -2,7 +2,6 @@ #include "window_manager.hpp" #include "widgets.hpp" -#include "itemwidget.hpp" #include "../mwbase/environment.hpp" #include "../mwworld/manualref.hpp" @@ -50,22 +49,9 @@ void ContainerBase::onSelectedItem(MyGUI::Widget* _sender) _sender->detachFromWidget(); _sender->attachToWidget(mDragAndDrop->mDragAndDropWidget); - ItemWidget* item = static_cast(_sender); - - int count = 0; - MWWorld::ContainerStore& containerStore = MWWorld::Class::get(mContainer).getContainerStore(mContainer); - MWWorld::Ptr object; - for (MWWorld::ContainerStoreIterator iter (containerStore.begin()); iter!=containerStore.end(); ++iter) - { - count++; - if(count == item->mPos) - { - mDragAndDrop->mStore.add(*iter); - object = *iter; - iter->getRefData().setCount(0); - break; - } - } + MWWorld::Ptr object = *_sender->getUserData(); + mDragAndDrop->mStore.add(object); + object.getRefData().setCount(0); std::string sound = MWWorld::Class::get(object).getUpSoundId(object); MWBase::Environment::get().getSoundManager()->playSound (sound, 1.0, 1.0); @@ -81,9 +67,7 @@ void ContainerBase::onContainerClicked(MyGUI::Widget* _sender) { if(mDragAndDrop->mIsOnDragAndDrop) //drop widget here { - ItemWidget* item = static_cast(mDragAndDrop->mDraggedWidget); - - MWWorld::Ptr object = *item->getUserData(); + MWWorld::Ptr object = *mDragAndDrop->mDraggedWidget->getUserData(); assert(object.getContainerStore() && "Item is not in a container!"); std::string sound = MWWorld::Class::get(object).getDownSoundId(object); @@ -123,8 +107,8 @@ void ContainerBase::drawItems() } MWWorld::ContainerStore& containerStore = MWWorld::Class::get(mContainer).getContainerStore(mContainer); - int x = 4; - int y = 4; + int x = 0; + int y = 0; int maxHeight = mItemView->getSize().height - 48; int index = 0; @@ -136,28 +120,36 @@ void ContainerBase::drawItems() { std::string path = std::string("icons\\"); path+=MWWorld::Class::get(*iter).getInventoryIcon(*iter); - ItemWidget* image = mContainerWidget->createWidget("ImageBox", MyGUI::IntCoord(x, y, 32, 32), MyGUI::Align::Default); - MyGUI::TextBox* text = image->createWidget("SandBrightText", MyGUI::IntCoord(14, 14, 18, 18), MyGUI::Align::Default, std::string("Label")); - text->setTextAlign(MyGUI::Align::Right); - text->setNeedMouseFocus(false); - image->eventMouseButtonClick += MyGUI::newDelegate(this,&ContainerBase::onSelectedItem); - image->setUserString("ToolTipType", "ItemPtr"); - image->setUserData(*iter); - image->mPos = index; - y += 36; - if (y > maxHeight) - { - x += 36; - y = 4; - } - if(iter->getRefData().getCount() > 1) - text->setCaption(boost::lexical_cast(iter->getRefData().getCount())); + // background widget (for the "equipped" frame and magic item background image) + bool isMagic = (MWWorld::Class::get(*iter).getEnchantment(*iter) != ""); + MyGUI::Widget* backgroundWidget = mContainerWidget->createWidget(isMagic ? "ItemBackgroundMagic" : "ItemBackground", MyGUI::IntCoord(x, y, 42, 42), MyGUI::Align::Default); + backgroundWidget->setUserString("ToolTipType", "ItemPtr"); + backgroundWidget->setUserData(*iter); + backgroundWidget->eventMouseButtonClick += MyGUI::newDelegate(this,&ContainerBase::onSelectedItem); + // image + ImageBox* image = backgroundWidget->createWidget("ImageBox", MyGUI::IntCoord(5, 5, 32, 32), MyGUI::Align::Default); int pos = path.rfind("."); path.erase(pos); path.append(".dds"); image->setImageTexture(path); + image->setNeedMouseFocus(false); + + // text widget that shows item count + MyGUI::TextBox* text = image->createWidget("SandBrightText", MyGUI::IntCoord(14, 14, 18, 18), MyGUI::Align::Default, std::string("Label")); + text->setTextAlign(MyGUI::Align::Right); + text->setNeedMouseFocus(false); + + y += 36; + if (y > maxHeight) + { + x += 36; + y = 0; + } + + if(iter->getRefData().getCount() > 1) + text->setCaption(boost::lexical_cast(iter->getRefData().getCount())); } } diff --git a/apps/openmw/mwgui/itemwidget.hpp b/apps/openmw/mwgui/itemwidget.hpp deleted file mode 100644 index 0b204b10ea..0000000000 --- a/apps/openmw/mwgui/itemwidget.hpp +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef MWGUI_ITEM_WIDGET_H -#define MWGUI_ITEM_WIDGET_H -#include -#include "../mwworld/ptr.hpp" - -namespace MWGui -{ - class ItemWidget: public MyGUI::ImageBox - { - MYGUI_RTTI_DERIVED( ItemWidget ) - public: - - int mPos; - }; -} - -#endif diff --git a/apps/openmw/mwgui/window_manager.cpp b/apps/openmw/mwgui/window_manager.cpp index 95fe3492ab..6dfdc3bb49 100644 --- a/apps/openmw/mwgui/window_manager.cpp +++ b/apps/openmw/mwgui/window_manager.cpp @@ -9,7 +9,6 @@ #include "messagebox.hpp" #include "container.hpp" #include "inventorywindow.hpp" -#include "itemwidget.hpp" #include "tooltips.hpp" #include "scrollwindow.hpp" #include "bookwindow.hpp" @@ -77,7 +76,6 @@ WindowManager::WindowManager( //Register own widgets with MyGUI MyGUI::FactoryManager::getInstance().registerFactory("Widget"); - MyGUI::FactoryManager::getInstance().registerFactory("Widget"); MyGUI::FactoryManager::getInstance().registerFactory("Widget"); MyGUI::FactoryManager::getInstance().registerFactory("Widget"); MyGUI::FactoryManager::getInstance().registerFactory("Widget"); From 54c23c74224e273dbbe576fd72cbb571e944e4c0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 12 May 2012 19:48:01 +0200 Subject: [PATCH 125/325] show the background texture for enchanted items in inventory/container --- apps/openmw/mwgui/container.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 1f6a6f2f6f..e2be9147ce 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -59,6 +59,8 @@ void ContainerBase::onSelectedItem(MyGUI::Widget* _sender) _sender->setUserString("drag","on"); mDragAndDrop->mDraggedWidget = _sender; mDragAndDrop->mContainerWindow = const_cast(this); + // hide the count text + _sender->getChildAt(0)->getChildAt(0)->setVisible(false); drawItems(); } } @@ -123,9 +125,11 @@ void ContainerBase::drawItems() // background widget (for the "equipped" frame and magic item background image) bool isMagic = (MWWorld::Class::get(*iter).getEnchantment(*iter) != ""); - MyGUI::Widget* backgroundWidget = mContainerWidget->createWidget(isMagic ? "ItemBackgroundMagic" : "ItemBackground", MyGUI::IntCoord(x, y, 42, 42), MyGUI::Align::Default); + MyGUI::ImageBox* backgroundWidget = mContainerWidget->createWidget("ImageBox", MyGUI::IntCoord(x, y, 42, 42), MyGUI::Align::Default); backgroundWidget->setUserString("ToolTipType", "ItemPtr"); backgroundWidget->setUserData(*iter); + backgroundWidget->setImageTexture( isMagic ? "textures\\menu_icon_magic.dds" : ""); + backgroundWidget->setProperty("ImageCoord", "0 0 42 42"); backgroundWidget->eventMouseButtonClick += MyGUI::newDelegate(this,&ContainerBase::onSelectedItem); // image @@ -137,7 +141,7 @@ void ContainerBase::drawItems() image->setNeedMouseFocus(false); // text widget that shows item count - MyGUI::TextBox* text = image->createWidget("SandBrightText", MyGUI::IntCoord(14, 14, 18, 18), MyGUI::Align::Default, std::string("Label")); + MyGUI::TextBox* text = image->createWidget("SandBrightText", MyGUI::IntCoord(0, 14, 32, 18), MyGUI::Align::Default, std::string("Label")); text->setTextAlign(MyGUI::Align::Right); text->setNeedMouseFocus(false); From f3c88adc0b6f8ff8cb86d49ec6d5ee50cdcd365c Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 12 May 2012 20:06:44 +0200 Subject: [PATCH 126/325] items can now also be dropped on another item (and will be placed in container) --- apps/openmw/mwgui/container.cpp | 2 ++ apps/openmw/mwgui/tooltips.cpp | 3 +-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index e2be9147ce..448ae64821 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -63,6 +63,8 @@ void ContainerBase::onSelectedItem(MyGUI::Widget* _sender) _sender->getChildAt(0)->getChildAt(0)->setVisible(false); drawItems(); } + else + onContainerClicked(mContainerWidget); } void ContainerBase::onContainerClicked(MyGUI::Widget* _sender) diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index aa189b2e86..67479e3f98 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -29,8 +29,6 @@ ToolTips::ToolTips(WindowManager* windowManager) : void ToolTips::onFrame(float frameDuration) { - /// \todo Store a MWWorld::Ptr in the widget user data, retrieve it here and construct a tooltip dynamically - MyGUI::Gui::getInstance().destroyWidget(mDynamicToolTipBox); mDynamicToolTipBox = mMainWidget->createWidget("HUD_Box", IntCoord(0, 0, mMainWidget->getCoord().width, mMainWidget->getCoord().height), @@ -110,6 +108,7 @@ void ToolTips::onFrame(float frameDuration) // adjust tooltip size to fit its content, position it above the crosshair /// \todo Slide the tooltip along the bounding box of the focused object (like in Morrowind) + /// relevant link: http://www.ogre3d.org/tikiwiki/ObjectTextDisplay setCoord(std::max(0, viewSize.width/2 - (tooltipSize.width)/2), std::max(0, viewSize.height/2 - (tooltipSize.height) - 32), tooltipSize.width, From e6e50f4ad41a4b3bc5c1f50661953cdd71de5d98 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 12 May 2012 20:14:19 +0200 Subject: [PATCH 127/325] fix items getting cut off --- apps/openmw/mwgui/container.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 448ae64821..84b1582cbd 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -147,10 +147,10 @@ void ContainerBase::drawItems() text->setTextAlign(MyGUI::Align::Right); text->setNeedMouseFocus(false); - y += 36; + y += 42; if (y > maxHeight) { - x += 36; + x += 42; y = 0; } @@ -159,7 +159,7 @@ void ContainerBase::drawItems() } } - MyGUI::IntSize size = MyGUI::IntSize(std::max(mItemView->getSize().width, x), mItemView->getSize().height); + MyGUI::IntSize size = MyGUI::IntSize(std::max(mItemView->getSize().width, x+42), mItemView->getSize().height); mItemView->setCanvasSize(size); mContainerWidget->setSize(size); } From 24e54a81bdf91a0b832d613324fcb1f9c7c5ec02 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 12 May 2012 20:28:12 +0200 Subject: [PATCH 128/325] don't show icons in the inventory tooltips, exactly like MW does --- apps/openmw/mwgui/tooltips.cpp | 6 ++++-- apps/openmw/mwgui/tooltips.hpp | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 67479e3f98..7fc29f8c3d 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -82,7 +82,7 @@ void ToolTips::onFrame(float frameDuration) else if (type == "ItemPtr") { mFocusObject = *focus->getUserData(); - tooltipSize = getToolTipViaPtr(); + tooltipSize = getToolTipViaPtr(false); } IntPoint tooltipPosition = InputManager::getInstance().getMousePosition() + IntPoint(0, 24); @@ -134,7 +134,7 @@ void ToolTips::setFocusObject(const MWWorld::Ptr& focus) mFocusObject = focus; } -IntSize ToolTips::getToolTipViaPtr () +IntSize ToolTips::getToolTipViaPtr (bool image) { // this the maximum width of the tooltip before it starts word-wrapping setCoord(0, 0, 300, 300); @@ -151,6 +151,8 @@ IntSize ToolTips::getToolTipViaPtr () mDynamicToolTipBox->setVisible(true); ToolTipInfo info = object.getToolTipInfo(mFocusObject); + if (!image) + info.icon = ""; tooltipSize = createToolTip(info); } diff --git a/apps/openmw/mwgui/tooltips.hpp b/apps/openmw/mwgui/tooltips.hpp index d20360a796..8d09709654 100644 --- a/apps/openmw/mwgui/tooltips.hpp +++ b/apps/openmw/mwgui/tooltips.hpp @@ -65,7 +65,7 @@ namespace MWGui void findImageExtension(std::string& image); - MyGUI::IntSize getToolTipViaPtr (); + MyGUI::IntSize getToolTipViaPtr (bool image=true); ///< @return requested tooltip size MyGUI::IntSize createToolTip(const ToolTipInfo& info); From fd18c95c5f812ff86009b8833db23aae3385adf4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 12 May 2012 20:35:50 +0200 Subject: [PATCH 129/325] implemented filters (no gui yet) --- apps/openmw/mwgui/container.cpp | 9 ++++++++- apps/openmw/mwgui/container.hpp | 3 +++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 84b1582cbd..c4407152df 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -29,6 +29,7 @@ using namespace Widgets; ContainerBase::ContainerBase(WindowManager& parWindowManager,DragAndDrop* dragAndDrop,std::string guiFile) : WindowBase(guiFile, parWindowManager), mDragAndDrop(dragAndDrop), + mFilter(MWWorld::ContainerStore::Type_All), mContainer() { getWidget(mContainerWidget, "Items"); @@ -95,6 +96,12 @@ void ContainerBase::setName(std::string contName) adjustWindowCaption(); } +void ContainerBase::setFilter(int filter) +{ + mFilter = filter; + drawItems(); +} + void ContainerBase::open(MWWorld::Ptr container) { mContainer = container; @@ -117,7 +124,7 @@ void ContainerBase::drawItems() int index = 0; - for (MWWorld::ContainerStoreIterator iter (containerStore.begin()); iter!=containerStore.end(); ++iter) + for (MWWorld::ContainerStoreIterator iter (containerStore.begin(mFilter)); iter!=containerStore.end(); ++iter) { index++; if(iter->getRefData().getCount() > 0) diff --git a/apps/openmw/mwgui/container.hpp b/apps/openmw/mwgui/container.hpp index 2552922f86..a34d22c775 100644 --- a/apps/openmw/mwgui/container.hpp +++ b/apps/openmw/mwgui/container.hpp @@ -52,6 +52,7 @@ namespace MWGui void open(MWWorld::Ptr container); void setName(std::string contName); + void setFilter(int filter); ///< set category filter void Update(); protected: @@ -61,6 +62,8 @@ namespace MWGui DragAndDrop* mDragAndDrop; MWWorld::Ptr mContainer; + int mFilter; + void onSelectedItem(MyGUI::Widget* _sender); void onContainerClicked(MyGUI::Widget* _sender); From 8e6c9434009d390d055fe154b705c310d8c03696 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 12 May 2012 20:39:21 +0200 Subject: [PATCH 130/325] "take all"-button sound (first item) --- apps/openmw/mwgui/container.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index c4407152df..39bd577af5 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -236,11 +236,21 @@ void ContainerWindow::onTakeAllButtonClicked(MyGUI::Widget* _sender) MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); MWWorld::ContainerStore& playerStore = MWWorld::Class::get(player).getContainerStore(player); + int i=0; for (MWWorld::ContainerStoreIterator iter (containerStore.begin()); iter!=containerStore.end(); ++iter) { if(iter->getRefData().getCount() > 0) { playerStore.add(*iter); + + if (i==0) + { + // play the sound of the first object + std::string sound = MWWorld::Class::get(*iter).getUpSoundId(*iter); + MWBase::Environment::get().getSoundManager()->playSound (sound, 1.0, 1.0); + } + + ++i; } } From 0114bf948c8d4397a40a509f4d2d88725c9a29ed Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 12 May 2012 21:28:04 +0200 Subject: [PATCH 131/325] revised filters --- apps/openmw/mwgui/container.cpp | 30 ++++++++++++++--- apps/openmw/mwgui/container.hpp | 13 ++++++-- apps/openmw/mwgui/inventorywindow.cpp | 11 +++++++ apps/openmw/mwgui/inventorywindow.hpp | 11 +++++++ .../mygui/openmw_container_window_layout.xml | 4 +-- .../mygui/openmw_inventory_window_layout.xml | 32 +++++++++++-------- 6 files changed, 80 insertions(+), 21 deletions(-) diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 39bd577af5..2de8e2bb32 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -29,7 +29,7 @@ using namespace Widgets; ContainerBase::ContainerBase(WindowManager& parWindowManager,DragAndDrop* dragAndDrop,std::string guiFile) : WindowBase(guiFile, parWindowManager), mDragAndDrop(dragAndDrop), - mFilter(MWWorld::ContainerStore::Type_All), + mFilter(ContainerBase::Filter_All), mContainer() { getWidget(mContainerWidget, "Items"); @@ -96,7 +96,7 @@ void ContainerBase::setName(std::string contName) adjustWindowCaption(); } -void ContainerBase::setFilter(int filter) +void ContainerBase::setFilter(ContainerBase::Filter filter) { mFilter = filter; drawItems(); @@ -124,10 +124,32 @@ void ContainerBase::drawItems() int index = 0; - for (MWWorld::ContainerStoreIterator iter (containerStore.begin(mFilter)); iter!=containerStore.end(); ++iter) + + bool onlyMagic = false; + int categories; + if (mFilter == Filter_All) + categories = MWWorld::ContainerStore::Type_All; + else if (mFilter == Filter_Weapon) + categories = MWWorld::ContainerStore::Type_Weapon; + else if (mFilter == Filter_Apparel) + categories = MWWorld::ContainerStore::Type_Clothing + MWWorld::ContainerStore::Type_Armor; + else if (mFilter == Filter_Magic) + { + categories = MWWorld::ContainerStore::Type_Clothing + MWWorld::ContainerStore::Type_Armor + + MWWorld::ContainerStore::Type_Weapon + MWWorld::ContainerStore::Type_Book + + MWWorld::ContainerStore::Type_Potion; + onlyMagic = true; + } + else if (mFilter == Filter_Misc) + { + categories = MWWorld::ContainerStore::Type_Miscellaneous + MWWorld::ContainerStore::Type_Book + + MWWorld::ContainerStore::Type_Ingredient; + } + + for (MWWorld::ContainerStoreIterator iter (containerStore.begin(categories)); iter!=containerStore.end(); ++iter) { index++; - if(iter->getRefData().getCount() > 0) + if(iter->getRefData().getCount() > 0 && !(onlyMagic && MWWorld::Class::get(*iter).getEnchantment(*iter) == "" && iter->getTypeName() != typeid(ESM::Potion).name())) { std::string path = std::string("icons\\"); path+=MWWorld::Class::get(*iter).getInventoryIcon(*iter); diff --git a/apps/openmw/mwgui/container.hpp b/apps/openmw/mwgui/container.hpp index a34d22c775..a8c12bb6ad 100644 --- a/apps/openmw/mwgui/container.hpp +++ b/apps/openmw/mwgui/container.hpp @@ -50,9 +50,18 @@ namespace MWGui ContainerBase(WindowManager& parWindowManager, DragAndDrop* dragAndDrop, std::string guiFile); virtual ~ContainerBase(); + enum Filter + { + Filter_All = 0x01, + Filter_Weapon = 0x02, + Filter_Apparel = 0x03, + Filter_Magic = 0x04, + Filter_Misc = 0x05 + }; + void open(MWWorld::Ptr container); void setName(std::string contName); - void setFilter(int filter); ///< set category filter + void setFilter(Filter filter); ///< set category filter void Update(); protected: @@ -62,7 +71,7 @@ namespace MWGui DragAndDrop* mDragAndDrop; MWWorld::Ptr mContainer; - int mFilter; + Filter mFilter; void onSelectedItem(MyGUI::Widget* _sender); void onContainerClicked(MyGUI::Widget* _sender); diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index b85380968d..738ab578a6 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -25,11 +25,22 @@ namespace MWGui : ContainerBase(parWindowManager,dragAndDrop,"openmw_inventory_window_layout.xml") { static_cast(mMainWidget)->eventWindowChangeCoord += MyGUI::newDelegate(this, &InventoryWindow::onWindowResize); + + getWidget(mAvatar, "Avatar"); + getWidget(mEncumbranceBar, "EncumbranceBar"); + getWidget(mEncumbranceText, "EncumbranceBarT"); + getWidget(mFilterAll, "AllButton"); + getWidget(mFilterWeapon, "WeaponButton"); + getWidget(mFilterApparel, "ApparelButton"); + getWidget(mFilterMagic, "MagicButton"); + getWidget(mFilterMisc, "MiscButton"); } void InventoryWindow::openInventory() { open(MWBase::Environment::get().getWorld()->getPlayer().getPlayer()); + + onWindowResize(static_cast(mMainWidget)); } void InventoryWindow::onWindowResize(MyGUI::Window* _sender) diff --git a/apps/openmw/mwgui/inventorywindow.hpp b/apps/openmw/mwgui/inventorywindow.hpp index 813fc88ab8..db105a2f8c 100644 --- a/apps/openmw/mwgui/inventorywindow.hpp +++ b/apps/openmw/mwgui/inventorywindow.hpp @@ -29,6 +29,17 @@ namespace MWGui void openInventory(); protected: + MyGUI::Widget* mAvatar; + MyGUI::TextBox* mArmorRating; + MyGUI::ProgressBar* mEncumbranceBar; + MyGUI::TextBox* mEncumbranceText; + + MyGUI::Button* mFilterAll; + MyGUI::Button* mFilterWeapon; + MyGUI::Button* mFilterApparel; + MyGUI::Button* mFilterMagic; + MyGUI::Button* mFilterMisc; + void onWindowResize(MyGUI::Window* _sender); }; } diff --git a/files/mygui/openmw_container_window_layout.xml b/files/mygui/openmw_container_window_layout.xml index 26fe0a3d30..7b14f5b580 100644 --- a/files/mygui/openmw_container_window_layout.xml +++ b/files/mygui/openmw_container_window_layout.xml @@ -5,9 +5,9 @@ - + - + diff --git a/files/mygui/openmw_inventory_window_layout.xml b/files/mygui/openmw_inventory_window_layout.xml index a347a510e7..b2b32ea2cc 100644 --- a/files/mygui/openmw_inventory_window_layout.xml +++ b/files/mygui/openmw_inventory_window_layout.xml @@ -4,30 +4,36 @@ - - + + + + + + - - + + + + - - + + - + - - - - - - + + + + + + From 902309a554f96370f652ec4bb32dd141d7a60815 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 12 May 2012 21:44:33 +0200 Subject: [PATCH 132/325] working filters --- apps/openmw/mwclass/book.cpp | 8 +++++ apps/openmw/mwclass/book.hpp | 3 ++ apps/openmw/mwgui/inventorywindow.cpp | 46 +++++++++++++++++++++++++++ apps/openmw/mwgui/inventorywindow.hpp | 1 + 4 files changed, 58 insertions(+) diff --git a/apps/openmw/mwclass/book.cpp b/apps/openmw/mwclass/book.cpp index 3d8adf0144..f58eac7ecb 100644 --- a/apps/openmw/mwclass/book.cpp +++ b/apps/openmw/mwclass/book.cpp @@ -140,4 +140,12 @@ namespace MWClass return info; } + + std::string Book::getEnchantment (const MWWorld::Ptr& ptr) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + return ref->base->enchant; + } } diff --git a/apps/openmw/mwclass/book.hpp b/apps/openmw/mwclass/book.hpp index fd6e38e04e..6858bac7f5 100644 --- a/apps/openmw/mwclass/book.hpp +++ b/apps/openmw/mwclass/book.hpp @@ -44,6 +44,9 @@ namespace MWClass virtual std::string getInventoryIcon (const MWWorld::Ptr& ptr) const; ///< Return name of inventory icon. + + virtual std::string getEnchantment (const MWWorld::Ptr& ptr) const; + ///< @return the enchantment ID if the object is enchanted, otherwise an empty string }; } diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 738ab578a6..7e02a63e85 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -34,6 +34,38 @@ namespace MWGui getWidget(mFilterApparel, "ApparelButton"); getWidget(mFilterMagic, "MagicButton"); getWidget(mFilterMisc, "MiscButton"); + + mFilterAll->setCaption (MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sAllTab")->str); + mFilterWeapon->setCaption (MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sWeaponTab")->str); + mFilterApparel->setCaption (MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sApparelTab")->str); + mFilterMagic->setCaption (MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sMagicTab")->str); + mFilterMisc->setCaption (MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sMiscTab")->str); + + // adjust size of buttons to fit text + int curX = 0; + mFilterAll->setSize( mFilterAll->getTextSize().width + 24, mFilterAll->getSize().height ); + curX += mFilterAll->getTextSize().width + 24 + 4; + + mFilterWeapon->setPosition(curX, mFilterWeapon->getPosition().top); + mFilterWeapon->setSize( mFilterWeapon->getTextSize().width + 24, mFilterWeapon->getSize().height ); + curX += mFilterWeapon->getTextSize().width + 24 + 4; + + mFilterApparel->setPosition(curX, mFilterApparel->getPosition().top); + mFilterApparel->setSize( mFilterApparel->getTextSize().width + 24, mFilterApparel->getSize().height ); + curX += mFilterApparel->getTextSize().width + 24 + 4; + + mFilterMagic->setPosition(curX, mFilterMagic->getPosition().top); + mFilterMagic->setSize( mFilterMagic->getTextSize().width + 24, mFilterMagic->getSize().height ); + curX += mFilterMagic->getTextSize().width + 24 + 4; + + mFilterMisc->setPosition(curX, mFilterMisc->getPosition().top); + mFilterMisc->setSize( mFilterMisc->getTextSize().width + 24, mFilterMisc->getSize().height ); + + mFilterAll->eventMouseButtonClick += MyGUI::newDelegate(this, &InventoryWindow::onFilterChanged); + mFilterWeapon->eventMouseButtonClick += MyGUI::newDelegate(this, &InventoryWindow::onFilterChanged); + mFilterApparel->eventMouseButtonClick += MyGUI::newDelegate(this, &InventoryWindow::onFilterChanged); + mFilterMagic->eventMouseButtonClick += MyGUI::newDelegate(this, &InventoryWindow::onFilterChanged); + mFilterMisc->eventMouseButtonClick += MyGUI::newDelegate(this, &InventoryWindow::onFilterChanged); } void InventoryWindow::openInventory() @@ -48,4 +80,18 @@ namespace MWGui drawItems(); } + void InventoryWindow::onFilterChanged(MyGUI::Widget* _sender) + { + if (_sender == mFilterAll) + setFilter(ContainerBase::Filter_All); + else if (_sender == mFilterWeapon) + setFilter(ContainerBase::Filter_Weapon); + else if (_sender == mFilterApparel) + setFilter(ContainerBase::Filter_Apparel); + else if (_sender == mFilterMagic) + setFilter(ContainerBase::Filter_Magic); + else if (_sender == mFilterMisc) + setFilter(ContainerBase::Filter_Misc); + } + } diff --git a/apps/openmw/mwgui/inventorywindow.hpp b/apps/openmw/mwgui/inventorywindow.hpp index db105a2f8c..63188e84ba 100644 --- a/apps/openmw/mwgui/inventorywindow.hpp +++ b/apps/openmw/mwgui/inventorywindow.hpp @@ -41,6 +41,7 @@ namespace MWGui MyGUI::Button* mFilterMisc; void onWindowResize(MyGUI::Window* _sender); + void onFilterChanged(MyGUI::Widget* _sender); }; } #endif // Inventory_H From 822e5fbe1e2c01cfc93079edf7bcffb88b97adab Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 12 May 2012 22:00:15 +0200 Subject: [PATCH 133/325] add indication which filter is selected --- apps/openmw/mwgui/inventorywindow.cpp | 10 ++++++++++ files/mygui/openmw_button.skin.xml | 4 ++++ 2 files changed, 14 insertions(+) diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 7e02a63e85..340c03562a 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -66,6 +66,8 @@ namespace MWGui mFilterApparel->eventMouseButtonClick += MyGUI::newDelegate(this, &InventoryWindow::onFilterChanged); mFilterMagic->eventMouseButtonClick += MyGUI::newDelegate(this, &InventoryWindow::onFilterChanged); mFilterMisc->eventMouseButtonClick += MyGUI::newDelegate(this, &InventoryWindow::onFilterChanged); + + mFilterAll->setStateSelected(true); } void InventoryWindow::openInventory() @@ -92,6 +94,14 @@ namespace MWGui setFilter(ContainerBase::Filter_Magic); else if (_sender == mFilterMisc) setFilter(ContainerBase::Filter_Misc); + + mFilterAll->setStateSelected(false); + mFilterWeapon->setStateSelected(false); + mFilterApparel->setStateSelected(false); + mFilterMagic->setStateSelected(false); + mFilterMisc->setStateSelected(false); + + static_cast(_sender)->setStateSelected(true); } } diff --git a/files/mygui/openmw_button.skin.xml b/files/mygui/openmw_button.skin.xml index b88e994066..9efcf776f8 100644 --- a/files/mygui/openmw_button.skin.xml +++ b/files/mygui/openmw_button.skin.xml @@ -62,6 +62,10 @@ + + + + From 78b06d0ebfc7e3a2ebf63d7a5fe9c9f92031b617 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 12 May 2012 22:44:12 +0200 Subject: [PATCH 134/325] inventory window pinning --- apps/openmw/mwgui/container.cpp | 39 +++++++++++-------- apps/openmw/mwgui/container.hpp | 13 ++++--- apps/openmw/mwgui/inventorywindow.cpp | 16 +++++++- apps/openmw/mwgui/inventorywindow.hpp | 5 ++- apps/openmw/mwgui/window_manager.cpp | 10 +++++ apps/openmw/mwgui/window_manager.hpp | 2 + .../mygui/openmw_inventory_window_layout.xml | 2 +- libs/openengine/gui/layout.hpp | 7 ++++ 8 files changed, 69 insertions(+), 25 deletions(-) diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 2de8e2bb32..8742bf4f7f 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -26,14 +26,16 @@ using namespace MWGui; using namespace Widgets; -ContainerBase::ContainerBase(WindowManager& parWindowManager,DragAndDrop* dragAndDrop,std::string guiFile) - : WindowBase(guiFile, parWindowManager), +ContainerBase::ContainerBase(DragAndDrop* dragAndDrop) : mDragAndDrop(dragAndDrop), - mFilter(ContainerBase::Filter_All), - mContainer() + mFilter(ContainerBase::Filter_All) { - getWidget(mContainerWidget, "Items"); - getWidget(mItemView, "ItemView"); +} + +void ContainerBase::setWidgets(Widget* containerWidget, ScrollView* itemView) +{ + mContainerWidget = containerWidget; + mItemView = itemView; mContainerWidget->eventMouseButtonClick += MyGUI::newDelegate(this, &ContainerBase::onContainerClicked); } @@ -90,24 +92,16 @@ void ContainerBase::onContainerClicked(MyGUI::Widget* _sender) } } -void ContainerBase::setName(std::string contName) -{ - setText("_Main", contName); - adjustWindowCaption(); -} - void ContainerBase::setFilter(ContainerBase::Filter filter) { mFilter = filter; drawItems(); } -void ContainerBase::open(MWWorld::Ptr container) +void ContainerBase::openContainer(MWWorld::Ptr container) { mContainer = container; - setName(MWWorld::Class::get(container).getName(container)); drawItems(); - setVisible(true); } void ContainerBase::drawItems() @@ -206,11 +200,18 @@ void ContainerBase::Update() // ------------------------------------------------------------------------------------------------ ContainerWindow::ContainerWindow(WindowManager& parWindowManager,DragAndDrop* dragAndDrop) - : ContainerBase(parWindowManager, dragAndDrop, "openmw_container_window_layout.xml") + : ContainerBase(dragAndDrop) + , WindowBase("openmw_container_window_layout.xml", parWindowManager) { getWidget(mTakeButton, "TakeButton"); getWidget(mCloseButton, "CloseButton"); + MyGUI::ScrollView* itemView; + MyGUI::Widget* containerWidget; + getWidget(containerWidget, "Items"); + getWidget(itemView, "ItemView"); + setWidgets(containerWidget, itemView); + mCloseButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ContainerWindow::onCloseButtonClicked); mTakeButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ContainerWindow::onTakeAllButtonClicked); @@ -239,6 +240,12 @@ void ContainerWindow::onWindowResize(MyGUI::Window* window) drawItems(); } +void ContainerWindow::open(MWWorld::Ptr container) +{ + openContainer(container); + setTitle(MWWorld::Class::get(container).getName(container)); +} + void ContainerWindow::onCloseButtonClicked(MyGUI::Widget* _sender) { if(!mDragAndDrop->mIsOnDragAndDrop) diff --git a/apps/openmw/mwgui/container.hpp b/apps/openmw/mwgui/container.hpp index a8c12bb6ad..7fe04cd488 100644 --- a/apps/openmw/mwgui/container.hpp +++ b/apps/openmw/mwgui/container.hpp @@ -44,10 +44,10 @@ namespace MWGui MWWorld::Ptr mItem; }; - class ContainerBase : public WindowBase + class ContainerBase { public: - ContainerBase(WindowManager& parWindowManager, DragAndDrop* dragAndDrop, std::string guiFile); + ContainerBase(DragAndDrop* dragAndDrop); virtual ~ContainerBase(); enum Filter @@ -59,8 +59,9 @@ namespace MWGui Filter_Misc = 0x05 }; - void open(MWWorld::Ptr container); - void setName(std::string contName); + void setWidgets(MyGUI::Widget* containerWidget, MyGUI::ScrollView* itemView); ///< only call once + + void openContainer(MWWorld::Ptr container); void setFilter(Filter filter); ///< set category filter void Update(); @@ -79,13 +80,15 @@ namespace MWGui void drawItems(); }; - class ContainerWindow : public ContainerBase + class ContainerWindow : public ContainerBase, public WindowBase { public: ContainerWindow(WindowManager& parWindowManager,DragAndDrop* dragAndDrop); virtual ~ContainerWindow(); + void open(MWWorld::Ptr container); + protected: std::vector mContainerWidgets; diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 340c03562a..560e940d83 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -22,7 +22,8 @@ namespace MWGui { InventoryWindow::InventoryWindow(WindowManager& parWindowManager,DragAndDrop* dragAndDrop) - : ContainerBase(parWindowManager,dragAndDrop,"openmw_inventory_window_layout.xml") + : ContainerBase(dragAndDrop) + , WindowPinnableBase("openmw_inventory_window_layout.xml", parWindowManager) { static_cast(mMainWidget)->eventWindowChangeCoord += MyGUI::newDelegate(this, &InventoryWindow::onWindowResize); @@ -35,6 +36,12 @@ namespace MWGui getWidget(mFilterMagic, "MagicButton"); getWidget(mFilterMisc, "MiscButton"); + MyGUI::ScrollView* itemView; + MyGUI::Widget* containerWidget; + getWidget(containerWidget, "Items"); + getWidget(itemView, "ItemView"); + setWidgets(containerWidget, itemView); + mFilterAll->setCaption (MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sAllTab")->str); mFilterWeapon->setCaption (MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sWeaponTab")->str); mFilterApparel->setCaption (MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sApparelTab")->str); @@ -72,7 +79,7 @@ namespace MWGui void InventoryWindow::openInventory() { - open(MWBase::Environment::get().getWorld()->getPlayer().getPlayer()); + openContainer(MWBase::Environment::get().getWorld()->getPlayer().getPlayer()); onWindowResize(static_cast(mMainWidget)); } @@ -104,4 +111,9 @@ namespace MWGui static_cast(_sender)->setStateSelected(true); } + void InventoryWindow::onPinToggled() + { + mWindowManager.setWeaponVisibility(!mPinned); + } + } diff --git a/apps/openmw/mwgui/inventorywindow.hpp b/apps/openmw/mwgui/inventorywindow.hpp index 63188e84ba..dd4ff90b60 100644 --- a/apps/openmw/mwgui/inventorywindow.hpp +++ b/apps/openmw/mwgui/inventorywindow.hpp @@ -2,6 +2,8 @@ #define MGUI_Inventory_H #include "container.hpp" +#include "window_pinnable_base.hpp" + namespace MWWorld { class Environment; @@ -21,7 +23,7 @@ namespace MWGui namespace MWGui { - class InventoryWindow : public MWGui::ContainerBase + class InventoryWindow : public ContainerBase, public WindowPinnableBase { public: InventoryWindow(WindowManager& parWindowManager,DragAndDrop* dragAndDrop); @@ -42,6 +44,7 @@ namespace MWGui void onWindowResize(MyGUI::Window* _sender); void onFilterChanged(MyGUI::Widget* _sender); + void onPinToggled(); }; } #endif // Inventory_H diff --git a/apps/openmw/mwgui/window_manager.cpp b/apps/openmw/mwgui/window_manager.cpp index 6dfdc3bb49..249f1fcfd0 100644 --- a/apps/openmw/mwgui/window_manager.cpp +++ b/apps/openmw/mwgui/window_manager.cpp @@ -548,3 +548,13 @@ bool WindowManager::getFullHelp() const { return mToolTips->getFullHelp(); } + +void WindowManager::setWeaponVisibility(bool visible) +{ + hud->weapBox->setVisible(visible); +} + +void WindowManager::setSpellVisibility(bool visible) +{ + hud->spellBox->setVisible(visible); +} diff --git a/apps/openmw/mwgui/window_manager.hpp b/apps/openmw/mwgui/window_manager.hpp index c3fb2b9f91..1ea4f267f5 100644 --- a/apps/openmw/mwgui/window_manager.hpp +++ b/apps/openmw/mwgui/window_manager.hpp @@ -180,6 +180,8 @@ namespace MWGui void setHMSVisibility(bool visible); // sets the visibility of the hud minimap void setMinimapVisibility(bool visible); + void setWeaponVisibility(bool visible); + void setSpellVisibility(bool visible); template void removeDialog(T*& dialog); ///< Casts to OEngine::GUI::Layout and calls removeDialog, then resets pointer to nullptr. diff --git a/files/mygui/openmw_inventory_window_layout.xml b/files/mygui/openmw_inventory_window_layout.xml index b2b32ea2cc..0e8abf45bc 100644 --- a/files/mygui/openmw_inventory_window_layout.xml +++ b/files/mygui/openmw_inventory_window_layout.xml @@ -1,7 +1,7 @@ - + diff --git a/libs/openengine/gui/layout.hpp b/libs/openengine/gui/layout.hpp index bda8935af2..abcc017539 100644 --- a/libs/openengine/gui/layout.hpp +++ b/libs/openengine/gui/layout.hpp @@ -115,6 +115,13 @@ namespace GUI static_cast(pt)->setCaption(caption); } + void setTitle(const std::string& title) + { + // NOTE: this assume that mMainWidget is of type Window. + static_cast(mMainWidget)->setCaption(title); + adjustWindowCaption(); + } + void setState(const std::string& widget, const std::string& state) { MyGUI::Widget* pt; From 16522ddc59dfe697c3b4fe73f6b91beae96222bc Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 12 May 2012 23:09:03 +0200 Subject: [PATCH 135/325] InventoryStore re-stacking unequipped items --- apps/openmw/mwworld/containerstore.cpp | 19 ++++++++++++++----- apps/openmw/mwworld/containerstore.hpp | 3 +++ apps/openmw/mwworld/inventorystore.cpp | 20 ++++++++++++++++++-- 3 files changed, 35 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index 32e2da0ae1..e28346de51 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -45,18 +45,27 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::end() return ContainerStoreIterator (this); } +bool MWWorld::ContainerStore::stacks(const Ptr& ptr1, const Ptr& ptr2) const +{ + /// \todo add current weapon/armor health, remaining lockpick/repair uses, current enchantment charge here as soon as they are implemented + if ( ptr1.mCellRef->refID == ptr2.mCellRef->refID + && (MWWorld::Class::get(ptr1).getScript(ptr1) == "" && MWWorld::Class::get(ptr2).getScript(ptr2) == "") // item with a script never stacks + && ptr1.mCellRef->owner == ptr2.mCellRef->owner + && ptr1.mCellRef->soul == ptr2.mCellRef->soul + && ptr1.mCellRef->charge == ptr2.mCellRef->charge) + return true; + + return false; +} + void MWWorld::ContainerStore::add (const Ptr& ptr) { int type = getType(ptr); // determine whether to stack or not - // item stacking depends on owner, script, enchantment and name for (MWWorld::ContainerStoreIterator iter (begin(type)); iter!=end(); ++iter) { - if ( iter->mCellRef->refID == ptr.mCellRef->refID - && MWWorld::Class::get(*iter).getScript(*iter) == MWWorld::Class::get(ptr).getScript(ptr) - && MWWorld::Class::get(*iter).getEnchantment(*iter) == MWWorld::Class::get(ptr).getEnchantment(ptr) - && iter->mCellRef->owner == ptr.mCellRef->owner) + if (stacks(*iter, ptr)) { // stack iter->getRefData().setCount( iter->getRefData().getCount() + ptr.getRefData().getCount() ); diff --git a/apps/openmw/mwworld/containerstore.hpp b/apps/openmw/mwworld/containerstore.hpp index da5424fe08..2d330f6ea7 100644 --- a/apps/openmw/mwworld/containerstore.hpp +++ b/apps/openmw/mwworld/containerstore.hpp @@ -66,6 +66,9 @@ namespace MWWorld ContainerStoreIterator end(); + bool stacks (const Ptr& ptr1, const Ptr& ptr2) const; + ///< @return true if the two specified objects can stack with each other + void add (const Ptr& ptr); ///< Add the item pointed to by \a ptr to this container. /// diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index 576f2371f9..f149513dfd 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -67,9 +67,25 @@ void MWWorld::InventoryStore::equip (int slot, const ContainerStoreIterator& ite throw std::runtime_error ("invalid slot"); } - /// \todo restack item previously in this slot (if required) + // restack item previously in this slot (if required) + if (mSlots[slot] != end()) + { + for (MWWorld::ContainerStoreIterator iter (begin()); iter!=end(); ++iter) + { + if (stacks(*iter, *mSlots[slot])) + { + iter->getRefData().setCount( iter->getRefData().getCount() + mSlots[slot]->getRefData().getCount() ); + mSlots[slot]->getRefData().setCount(0); + break; + } + } + } - /// \todo unstack item pointed to by iterator if required) + // unstack item pointed to by iterator if required + if (iterator->getRefData().getCount() > 1) + { + /// \ŧodo ??? + } mSlots[slot] = iterator; From f31853d30bfca002dec038169f60d3f89eaa89a1 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 13 May 2012 01:27:17 +0200 Subject: [PATCH 136/325] mouse wheel works when mouse is over an item --- apps/openmw/mwgui/container.cpp | 12 +++++++++++- apps/openmw/mwgui/container.hpp | 1 + 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 8742bf4f7f..fd83bddfc8 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -38,6 +38,7 @@ void ContainerBase::setWidgets(Widget* containerWidget, ScrollView* itemView) mItemView = itemView; mContainerWidget->eventMouseButtonClick += MyGUI::newDelegate(this, &ContainerBase::onContainerClicked); + mContainerWidget->eventMouseWheel += MyGUI::newDelegate(this, &ContainerWindow::onMouseWheel); } ContainerBase::~ContainerBase() @@ -92,6 +93,14 @@ void ContainerBase::onContainerClicked(MyGUI::Widget* _sender) } } +void ContainerBase::onMouseWheel(MyGUI::Widget* _sender, int _rel) +{ + if (mItemView->getViewOffset().left + _rel*0.3 > 0) + mItemView->setViewOffset(MyGUI::IntPoint(0, 0)); + else + mItemView->setViewOffset(MyGUI::IntPoint(mItemView->getViewOffset().left + _rel*0.3, 0)); +} + void ContainerBase::setFilter(ContainerBase::Filter filter) { mFilter = filter; @@ -155,7 +164,8 @@ void ContainerBase::drawItems() backgroundWidget->setUserData(*iter); backgroundWidget->setImageTexture( isMagic ? "textures\\menu_icon_magic.dds" : ""); backgroundWidget->setProperty("ImageCoord", "0 0 42 42"); - backgroundWidget->eventMouseButtonClick += MyGUI::newDelegate(this,&ContainerBase::onSelectedItem); + backgroundWidget->eventMouseButtonClick += MyGUI::newDelegate(this, &ContainerBase::onSelectedItem); + backgroundWidget->eventMouseWheel += MyGUI::newDelegate(this, &ContainerBase::onMouseWheel); // image ImageBox* image = backgroundWidget->createWidget("ImageBox", MyGUI::IntCoord(5, 5, 32, 32), MyGUI::Align::Default); diff --git a/apps/openmw/mwgui/container.hpp b/apps/openmw/mwgui/container.hpp index 7fe04cd488..6bfee13465 100644 --- a/apps/openmw/mwgui/container.hpp +++ b/apps/openmw/mwgui/container.hpp @@ -76,6 +76,7 @@ namespace MWGui void onSelectedItem(MyGUI::Widget* _sender); void onContainerClicked(MyGUI::Widget* _sender); + void onMouseWheel(MyGUI::Widget* _sender, int _rel); void drawItems(); }; From d266b4fe87a5a7377d5846076562339b18415539 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 13 May 2012 10:18:17 +0200 Subject: [PATCH 137/325] hide the cursor during drag&drop and don't allow hotkeys that change guimode --- apps/openmw/mwgui/container.cpp | 11 +++++++++-- apps/openmw/mwgui/window_manager.cpp | 5 +++++ apps/openmw/mwgui/window_manager.hpp | 2 ++ apps/openmw/mwinput/inputmanager.cpp | 21 ++++++++++++++++++++- apps/openmw/mwinput/inputmanager.hpp | 2 ++ 5 files changed, 38 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index fd83bddfc8..0236e17c2d 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -60,12 +60,14 @@ void ContainerBase::onSelectedItem(MyGUI::Widget* _sender) std::string sound = MWWorld::Class::get(object).getUpSoundId(object); MWBase::Environment::get().getSoundManager()->playSound (sound, 1.0, 1.0); - _sender->setUserString("drag","on"); mDragAndDrop->mDraggedWidget = _sender; mDragAndDrop->mContainerWindow = const_cast(this); // hide the count text _sender->getChildAt(0)->getChildAt(0)->setVisible(false); drawItems(); + + MWBase::Environment::get().getInputManager()->setDragDrop(true); + MWBase::Environment::get().getWindowManager()->setMouseVisible(false); } else onContainerClicked(mContainerWidget); @@ -90,6 +92,9 @@ void ContainerBase::onContainerClicked(MyGUI::Widget* _sender) mDragAndDrop->mDraggedWidget = 0; mDragAndDrop->mContainerWindow = 0; drawItems(); + + MWBase::Environment::get().getInputManager()->setDragDrop(false); + MWBase::Environment::get().getWindowManager()->setMouseVisible(true); } } @@ -146,7 +151,9 @@ void ContainerBase::drawItems() else if (mFilter == Filter_Misc) { categories = MWWorld::ContainerStore::Type_Miscellaneous + MWWorld::ContainerStore::Type_Book - + MWWorld::ContainerStore::Type_Ingredient; + + MWWorld::ContainerStore::Type_Ingredient + MWWorld::ContainerStore::Type_Repair + + MWWorld::ContainerStore::Type_Lockpick + MWWorld::ContainerStore::Type_Light + + MWWorld::ContainerStore::Type_Apparatus; } for (MWWorld::ContainerStoreIterator iter (containerStore.begin(categories)); iter!=containerStore.end(); ++iter) diff --git a/apps/openmw/mwgui/window_manager.cpp b/apps/openmw/mwgui/window_manager.cpp index 249f1fcfd0..067d67ca4e 100644 --- a/apps/openmw/mwgui/window_manager.cpp +++ b/apps/openmw/mwgui/window_manager.cpp @@ -558,3 +558,8 @@ void WindowManager::setSpellVisibility(bool visible) { hud->spellBox->setVisible(visible); } + +void WindowManager::setMouseVisible(bool visible) +{ + MyGUI::PointerManager::getInstance().setVisible(visible); +} diff --git a/apps/openmw/mwgui/window_manager.hpp b/apps/openmw/mwgui/window_manager.hpp index 1ea4f267f5..b55b425a87 100644 --- a/apps/openmw/mwgui/window_manager.hpp +++ b/apps/openmw/mwgui/window_manager.hpp @@ -166,6 +166,8 @@ namespace MWGui void setFocusObject(const MWWorld::Ptr& focus); + void setMouseVisible(bool visible); + void toggleFogOfWar(); void toggleFullHelp(); ///< show extra info in item tooltips (owner, script) bool getFullHelp() const; diff --git a/apps/openmw/mwinput/inputmanager.cpp b/apps/openmw/mwinput/inputmanager.cpp index 9026cdf640..4d79eb3217 100644 --- a/apps/openmw/mwinput/inputmanager.cpp +++ b/apps/openmw/mwinput/inputmanager.cpp @@ -88,6 +88,8 @@ namespace MWInput MWGui::WindowManager &windows; OMW::Engine& mEngine; + bool mDragDrop; + /* InputImpl Methods */ @@ -143,6 +145,9 @@ namespace MWInput { using namespace MWGui; + if (mDragDrop) + return; + GuiMode mode = windows.getMode(); // Toggle between game mode and inventory mode @@ -159,6 +164,9 @@ namespace MWInput { using namespace MWGui; + if (mDragDrop) + return; + GuiMode mode = windows.getMode(); // Switch to console mode no matter what mode we are currently @@ -219,7 +227,8 @@ namespace MWInput poller(input), player(_player), windows(_windows), - mEngine (engine) + mEngine (engine), + mDragDrop(false) { using namespace OEngine::Input; using namespace OEngine::Render; @@ -319,6 +328,11 @@ namespace MWInput poller.bind(A_Crouch, KC_LCONTROL); } + void setDragDrop(bool dragDrop) + { + mDragDrop = dragDrop; + } + //NOTE: Used to check for movement keys void update () { @@ -426,4 +440,9 @@ namespace MWInput { impl->update(); } + + void MWInputManager::setDragDrop(bool dragDrop) + { + impl->setDragDrop(dragDrop); + } } diff --git a/apps/openmw/mwinput/inputmanager.hpp b/apps/openmw/mwinput/inputmanager.hpp index 721c77d9fd..158d05f0ee 100644 --- a/apps/openmw/mwinput/inputmanager.hpp +++ b/apps/openmw/mwinput/inputmanager.hpp @@ -50,6 +50,8 @@ namespace MWInput void update(); + void setDragDrop(bool dragDrop); + void setGuiMode(MWGui::GuiMode mode); }; } From 3a93df8db4d58479c5c82fa103339787d4f2743a Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 13 May 2012 11:25:35 +0200 Subject: [PATCH 138/325] dynamic inventory layout like morrowind --- apps/openmw/mwgui/container.cpp | 17 +++--- apps/openmw/mwgui/inventorywindow.cpp | 8 +++ apps/openmw/mwgui/inventorywindow.hpp | 3 + apps/openmw/mwgui/tooltips.cpp | 12 ++++ apps/openmw/mwgui/tooltips.hpp | 4 ++ apps/openmw/mwgui/window_manager.cpp | 7 +++ apps/openmw/mwgui/window_manager.hpp | 3 +- .../mygui/openmw_inventory_window_layout.xml | 57 +++++++++++-------- 8 files changed, 78 insertions(+), 33 deletions(-) diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 0236e17c2d..1b165f995a 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -66,8 +66,7 @@ void ContainerBase::onSelectedItem(MyGUI::Widget* _sender) _sender->getChildAt(0)->getChildAt(0)->setVisible(false); drawItems(); - MWBase::Environment::get().getInputManager()->setDragDrop(true); - MWBase::Environment::get().getWindowManager()->setMouseVisible(false); + MWBase::Environment::get().getWindowManager()->setDragDrop(true); } else onContainerClicked(mContainerWidget); @@ -93,8 +92,7 @@ void ContainerBase::onContainerClicked(MyGUI::Widget* _sender) mDragAndDrop->mContainerWindow = 0; drawItems(); - MWBase::Environment::get().getInputManager()->setDragDrop(false); - MWBase::Environment::get().getWindowManager()->setMouseVisible(true); + MWBase::Environment::get().getWindowManager()->setDragDrop(false); } } @@ -128,7 +126,7 @@ void ContainerBase::drawItems() int x = 0; int y = 0; - int maxHeight = mItemView->getSize().height - 48; + int maxHeight = mItemView->getSize().height - 58; int index = 0; @@ -195,7 +193,12 @@ void ContainerBase::drawItems() } if(iter->getRefData().getCount() > 1) - text->setCaption(boost::lexical_cast(iter->getRefData().getCount())); + { + if (iter->getRefData().getCount() > 9999) + text->setCaption(boost::lexical_cast(iter->getRefData().getCount()/1000.f) + "k"); + else + text->setCaption(boost::lexical_cast(iter->getRefData().getCount())); + } } } @@ -209,7 +212,7 @@ void ContainerBase::Update() if(mDragAndDrop->mIsOnDragAndDrop) { if(mDragAndDrop->mDraggedWidget) - mDragAndDrop->mDraggedWidget->setPosition(MyGUI::InputManager::getInstance().getMousePosition()); + mDragAndDrop->mDraggedWidget->setPosition(MyGUI::InputManager::getInstance().getMousePosition() - MyGUI::IntPoint(21, 21)); else mDragAndDrop->mIsOnDragAndDrop = false; //If this happens, there is a bug. } } diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 560e940d83..4bd4fe88c8 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -35,6 +35,8 @@ namespace MWGui getWidget(mFilterApparel, "ApparelButton"); getWidget(mFilterMagic, "MagicButton"); getWidget(mFilterMisc, "MiscButton"); + getWidget(mLeftPane, "LeftPane"); + getWidget(mRightPane, "RightPane"); MyGUI::ScrollView* itemView; MyGUI::Widget* containerWidget; @@ -86,6 +88,12 @@ namespace MWGui void InventoryWindow::onWindowResize(MyGUI::Window* _sender) { + const float aspect = 0.5; // fixed aspect ratio for the left pane + mLeftPane->setSize( (_sender->getSize().height-44) * aspect, _sender->getSize().height-44 ); + mRightPane->setCoord( mLeftPane->getPosition().left + (_sender->getSize().height-44) * aspect + 4, + mRightPane->getPosition().top, + _sender->getSize().width - 12 - (_sender->getSize().height-44) * aspect - 15, + _sender->getSize().height-44 ); drawItems(); } diff --git a/apps/openmw/mwgui/inventorywindow.hpp b/apps/openmw/mwgui/inventorywindow.hpp index dd4ff90b60..f16dcf4331 100644 --- a/apps/openmw/mwgui/inventorywindow.hpp +++ b/apps/openmw/mwgui/inventorywindow.hpp @@ -36,6 +36,9 @@ namespace MWGui MyGUI::ProgressBar* mEncumbranceBar; MyGUI::TextBox* mEncumbranceText; + MyGUI::Widget* mLeftPane; + MyGUI::Widget* mRightPane; + MyGUI::Button* mFilterAll; MyGUI::Button* mFilterWeapon; MyGUI::Button* mFilterApparel; diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 7fc29f8c3d..635e9481b9 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -16,6 +16,7 @@ ToolTips::ToolTips(WindowManager* windowManager) : , mGameMode(true) , mWindowManager(windowManager) , mFullHelp(false) + , mEnabled(true) { getWidget(mDynamicToolTipBox, "DynamicToolTipBox"); @@ -27,6 +28,11 @@ ToolTips::ToolTips(WindowManager* windowManager) : mMainWidget->setNeedMouseFocus(false); } +void ToolTips::setEnabled(bool enabled) +{ + mEnabled = enabled; +} + void ToolTips::onFrame(float frameDuration) { MyGUI::Gui::getInstance().destroyWidget(mDynamicToolTipBox); @@ -36,6 +42,12 @@ void ToolTips::onFrame(float frameDuration) const IntSize &viewSize = RenderManager::getInstance().getViewSize(); + if (!mEnabled) + { + mDynamicToolTipBox->setVisible(false); + return; + } + if (!mGameMode) { Widget* focus = InputManager::getInstance().getMouseFocusWidget(); diff --git a/apps/openmw/mwgui/tooltips.hpp b/apps/openmw/mwgui/tooltips.hpp index 8d09709654..87b9e97bff 100644 --- a/apps/openmw/mwgui/tooltips.hpp +++ b/apps/openmw/mwgui/tooltips.hpp @@ -39,6 +39,8 @@ namespace MWGui void enterGameMode(); void enterGuiMode(); + void setEnabled(bool enabled); + void toggleFullHelp(); ///< show extra info in item tooltips (owner, script) bool getFullHelp() const; @@ -73,6 +75,8 @@ namespace MWGui bool mGameMode; + bool mEnabled; + bool mFullHelp; }; } diff --git a/apps/openmw/mwgui/window_manager.cpp b/apps/openmw/mwgui/window_manager.cpp index 067d67ca4e..47fae20030 100644 --- a/apps/openmw/mwgui/window_manager.cpp +++ b/apps/openmw/mwgui/window_manager.cpp @@ -563,3 +563,10 @@ void WindowManager::setMouseVisible(bool visible) { MyGUI::PointerManager::getInstance().setVisible(visible); } + +void WindowManager::setDragDrop(bool dragDrop) +{ + mToolTips->setEnabled(!dragDrop); + MWBase::Environment::get().getInputManager()->setDragDrop(dragDrop); + setMouseVisible(!dragDrop); +} diff --git a/apps/openmw/mwgui/window_manager.hpp b/apps/openmw/mwgui/window_manager.hpp index b55b425a87..5dfcf64708 100644 --- a/apps/openmw/mwgui/window_manager.hpp +++ b/apps/openmw/mwgui/window_manager.hpp @@ -166,7 +166,8 @@ namespace MWGui void setFocusObject(const MWWorld::Ptr& focus); - void setMouseVisible(bool visible); + void setMouseVisible(bool visible); + void setDragDrop(bool dragDrop); void toggleFogOfWar(); void toggleFullHelp(); ///< show extra info in item tooltips (owner, script) diff --git a/files/mygui/openmw_inventory_window_layout.xml b/files/mygui/openmw_inventory_window_layout.xml index 0e8abf45bc..cd6e1469e4 100644 --- a/files/mygui/openmw_inventory_window_layout.xml +++ b/files/mygui/openmw_inventory_window_layout.xml @@ -3,37 +3,44 @@ - - - - - - + + + + + + + + + + + + + + + + + - - - - - - + - - - - - + + + + + + + + + + + + + + - - - - - - - - From ee7e482cba639a8c34b3b94e4433827032725a80 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 13 May 2012 11:52:17 +0200 Subject: [PATCH 139/325] implemented un-stacking --- apps/openmw/mwworld/containerstore.cpp | 8 +++++++- apps/openmw/mwworld/containerstore.hpp | 8 +++++++- apps/openmw/mwworld/inventorystore.cpp | 19 +++++++++++++++++-- 3 files changed, 31 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index e28346de51..94df222d4f 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -75,7 +75,13 @@ void MWWorld::ContainerStore::add (const Ptr& ptr) } } - switch (type) + // if we got here, this means no stacking + addImpl(ptr); +} + +void MWWorld::ContainerStore::addImpl (const Ptr& ptr) +{ + switch (getType(ptr)) { case Type_Potion: potions.list.push_back (*ptr.get()); break; case Type_Apparatus: appas.list.push_back (*ptr.get()); break; diff --git a/apps/openmw/mwworld/containerstore.hpp b/apps/openmw/mwworld/containerstore.hpp index 2d330f6ea7..9b9d29c576 100644 --- a/apps/openmw/mwworld/containerstore.hpp +++ b/apps/openmw/mwworld/containerstore.hpp @@ -70,13 +70,19 @@ namespace MWWorld ///< @return true if the two specified objects can stack with each other void add (const Ptr& ptr); - ///< Add the item pointed to by \a ptr to this container. + ///< Add the item pointed to by \a ptr to this container. (Stacks automatically if needed) /// /// \note The item pointed to is not required to exist beyond this function call. /// /// \attention Do not add items to an existing stack by increasing the count instead of /// calling this function! + protected: + void addImpl (const Ptr& ptr); + ///< Add the item to this container (no stacking) + + public: + void fill (const ESM::InventoryList& items, const ESMS::ESMStore& store); ///< Insert items into *this. diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index f149513dfd..ea295e9034 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -84,7 +84,11 @@ void MWWorld::InventoryStore::equip (int slot, const ContainerStoreIterator& ite // unstack item pointed to by iterator if required if (iterator->getRefData().getCount() > 1) { - /// \ŧodo ??? + // add the item again with a count of count-1, then set the count of the original (that will be equipped) to 1 + int count = iterator->getRefData().getCount(); + iterator->getRefData().setCount(count-1); + addImpl(*iterator); + iterator->getRefData().setCount(1); } mSlots[slot] = iterator; @@ -163,7 +167,18 @@ void MWWorld::InventoryStore::autoEquip (const MWMechanics::NpcStats& stats) } } - /// \todo unstack, if reqquired (itemsSlots.second) + if (!itemsSlots.second) // if itemsSlots.second is true, item can stay stacked when equipped + { + // unstack item pointed to by iterator if required + if (iter->getRefData().getCount() > 1) + { + // add the item again with a count of count-1, then set the count of the original (that will be equipped) to 1 + int count = iter->getRefData().getCount(); + iter->getRefData().setCount(count-1); + addImpl(*iter); + iter->getRefData().setCount(1); + } + } slots[*iter2] = iter; break; From a54e52586b5d3a213ad8a1fa25de05eb3a3a64c5 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 13 May 2012 12:17:07 +0200 Subject: [PATCH 140/325] fix for a potential directx problem --- files/shadows/depthshadowcaster.material | 92 +++++++++++++----------- 1 file changed, 49 insertions(+), 43 deletions(-) diff --git a/files/shadows/depthshadowcaster.material b/files/shadows/depthshadowcaster.material index 9ff51c5b17..f645cad019 100644 --- a/files/shadows/depthshadowcaster.material +++ b/files/shadows/depthshadowcaster.material @@ -1,67 +1,73 @@ vertex_program depth_shadow_caster_vs cg { - source depthshadowcaster.cg - profiles vs_1_1 arbvp1 - entry_point main_vp + source depthshadowcaster.cg + profiles vs_1_1 arbvp1 + entry_point main_vp - default_params - { - param_named_auto wvpMat worldviewproj_matrix - } + default_params + { + param_named_auto wvpMat worldviewproj_matrix + } } fragment_program depth_shadow_caster_ps cg { - source depthshadowcaster.cg - profiles ps_2_0 arbfp1 - entry_point main_fp + source depthshadowcaster.cg + profiles ps_2_0 arbfp1 + entry_point main_fp - default_params - { - } + default_params + { + } } fragment_program depth_shadow_caster_ps_noalpha cg { - source depthshadowcaster.cg - profiles ps_2_0 arbfp1 - entry_point main_fp_noalpha + source depthshadowcaster.cg + profiles ps_2_0 arbfp1 + entry_point main_fp_noalpha - default_params - { - } + default_params + { + } } material depth_shadow_caster { - technique - { - pass - { - vertex_program_ref depth_shadow_caster_vs - { - } + technique + { + pass + { + // force-disable fog (relevant for DirectX profiles below SM3 that always apply fixed function fog) + fog_override true - fragment_program_ref depth_shadow_caster_ps - { - } - } - } + vertex_program_ref depth_shadow_caster_vs + { + } + + fragment_program_ref depth_shadow_caster_ps + { + } + } + } } material depth_shadow_caster_noalpha { - technique - { - pass - { - vertex_program_ref depth_shadow_caster_vs - { - } + technique + { + pass + { + // force-disable fog (relevant for DirectX profiles below SM3 that always apply fixed function fog) + fog_override true - fragment_program_ref depth_shadow_caster_ps_noalpha - { - } - } - } + vertex_program_ref depth_shadow_caster_vs + { + } + + fragment_program_ref depth_shadow_caster_ps_noalpha + { + } + } + } } From ddb0a9199408c68fbf9c378b80e8f1fae6246004 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 13 May 2012 12:19:49 +0200 Subject: [PATCH 141/325] addition to last commit --- components/nifogre/ogre_nif_loader.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 05d35b85f6..80b2fc469b 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -326,6 +326,8 @@ void NIFLoader::createMaterial(const String &name, { material->getTechnique(0)->getPass(0)->setVertexProgram("main_vp"); material->getTechnique(0)->getPass(0)->setFragmentProgram("main_fp"); + + material->getTechnique(0)->getPass(0)->setFog(true); // force-disable fixed function fog, it is calculated in shader } // Create a fallback technique without shadows and without mrt @@ -338,6 +340,7 @@ void NIFLoader::createMaterial(const String &name, { pass2->setVertexProgram("main_fallback_vp"); pass2->setFragmentProgram("main_fallback_fp"); + pass2->setFog(true); // force-disable fixed function fog, it is calculated in shader } // Add material bells and whistles From d341d2113c8585093781f3c6975b3d7c3b1fabd4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 13 May 2012 14:58:38 +0200 Subject: [PATCH 142/325] fixed some issues --- apps/openmw/mwworld/containerstore.cpp | 2 +- apps/openmw/mwworld/containerstore.hpp | 7 ++++--- apps/openmw/mwworld/inventorystore.cpp | 22 ++++++++++++++++++++-- apps/openmw/mwworld/inventorystore.hpp | 7 +++++++ 4 files changed, 32 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index 94df222d4f..dcddc333b0 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -49,7 +49,7 @@ bool MWWorld::ContainerStore::stacks(const Ptr& ptr1, const Ptr& ptr2) const { /// \todo add current weapon/armor health, remaining lockpick/repair uses, current enchantment charge here as soon as they are implemented if ( ptr1.mCellRef->refID == ptr2.mCellRef->refID - && (MWWorld::Class::get(ptr1).getScript(ptr1) == "" && MWWorld::Class::get(ptr2).getScript(ptr2) == "") // item with a script never stacks + && MWWorld::Class::get(ptr1).getScript(ptr1) == "" // item with a script never stacks && ptr1.mCellRef->owner == ptr2.mCellRef->owner && ptr1.mCellRef->soul == ptr2.mCellRef->soul && ptr1.mCellRef->charge == ptr2.mCellRef->charge) diff --git a/apps/openmw/mwworld/containerstore.hpp b/apps/openmw/mwworld/containerstore.hpp index 9b9d29c576..f0e9d7e4ab 100644 --- a/apps/openmw/mwworld/containerstore.hpp +++ b/apps/openmw/mwworld/containerstore.hpp @@ -66,9 +66,6 @@ namespace MWWorld ContainerStoreIterator end(); - bool stacks (const Ptr& ptr1, const Ptr& ptr2) const; - ///< @return true if the two specified objects can stack with each other - void add (const Ptr& ptr); ///< Add the item pointed to by \a ptr to this container. (Stacks automatically if needed) /// @@ -81,6 +78,10 @@ namespace MWWorld void addImpl (const Ptr& ptr); ///< Add the item to this container (no stacking) + virtual bool stacks (const Ptr& ptr1, const Ptr& ptr2) const; + ///< @return true if the two specified objects can stack with each other + /// @note ptr1 is the item that is already in this container + public: void fill (const ESM::InventoryList& items, const ESMS::ESMStore& store); diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index ea295e9034..6cf35ac644 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -59,9 +59,10 @@ void MWWorld::InventoryStore::equip (int slot, const ContainerStoreIterator& ite if (iterator.getContainerStore()!=this) throw std::runtime_error ("attempt to equip an item that is not in the inventory"); + std::pair, bool> slots; if (iterator!=end()) { - std::pair, bool> slots = Class::get (*iterator).getEquipmentSlots (*iterator); + slots = Class::get (*iterator).getEquipmentSlots (*iterator); if (std::find (slots.first.begin(), slots.first.end(), slot)==slots.first.end()) throw std::runtime_error ("invalid slot"); @@ -82,7 +83,7 @@ void MWWorld::InventoryStore::equip (int slot, const ContainerStoreIterator& ite } // unstack item pointed to by iterator if required - if (iterator->getRefData().getCount() > 1) + if (iterator!=end() && !slots.second && iterator->getRefData().getCount() > 1) // if slots.second is true, item can stay stacked when equipped { // add the item again with a count of count-1, then set the count of the original (that will be equipped) to 1 int count = iterator->getRefData().getCount(); @@ -199,3 +200,20 @@ void MWWorld::InventoryStore::autoEquip (const MWMechanics::NpcStats& stats) flagAsModified(); } } + +bool MWWorld::InventoryStore::stacks(const Ptr& ptr1, const Ptr& ptr2) const +{ + bool canStack = MWWorld::ContainerStore::stacks(ptr1, ptr2); + if (!canStack) + return false; + + // don't stack if the item being checked against is currently equipped. + for (TSlots::const_iterator iter (mSlots.begin()); + iter!=mSlots.end(); ++iter) + { + if (ptr1 == **iter) + return false; + } + + return true; +} diff --git a/apps/openmw/mwworld/inventorystore.hpp b/apps/openmw/mwworld/inventorystore.hpp index 5eeaf570d0..4162c7e2e8 100644 --- a/apps/openmw/mwworld/inventorystore.hpp +++ b/apps/openmw/mwworld/inventorystore.hpp @@ -64,6 +64,13 @@ namespace MWWorld void autoEquip (const MWMechanics::NpcStats& stats); ///< Auto equip items according to stats and item value. + + protected: + + virtual bool stacks (const Ptr& ptr1, const Ptr& ptr2) const; + ///< @return true if the two specified objects can stack with each other + /// @note ptr1 is the item that is already in this container + }; } From a47d29c184f335f86f9c3972c8bbc253cad91944 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 13 May 2012 16:41:00 +0200 Subject: [PATCH 143/325] fix the inventory window overlapping with over windows in default layout --- apps/openmw/mwgui/container.cpp | 5 +++-- apps/openmw/mwgui/inventorywindow.cpp | 2 ++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 1b165f995a..de7419b80f 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -245,10 +245,11 @@ ContainerWindow::ContainerWindow(WindowManager& parWindowManager,DragAndDrop* dr mTakeButton->setCoord(600-20-closeButtonWidth-takeButtonWidth-8, mTakeButton->getCoord().top, takeButtonWidth, mTakeButton->getCoord().height); int w = MyGUI::RenderManager::getInstance().getViewSize().width; - int h = MyGUI::RenderManager::getInstance().getViewSize().height; - setCoord(w-600,h-300,600,300); + //int h = MyGUI::RenderManager::getInstance().getViewSize().height; static_cast(mMainWidget)->eventWindowChangeCoord += MyGUI::newDelegate(this, &ContainerWindow::onWindowResize); + + setCoord(w-600,0,600,300); } ContainerWindow::~ContainerWindow() diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 4bd4fe88c8..23e4949f78 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -77,6 +77,8 @@ namespace MWGui mFilterMisc->eventMouseButtonClick += MyGUI::newDelegate(this, &InventoryWindow::onFilterChanged); mFilterAll->setStateSelected(true); + + setCoord(0, 342, 600, 258); } void InventoryWindow::openInventory() From 82b9f835b1a907f72acec44a325cb1d5a74bf85e Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 13 May 2012 16:54:18 +0200 Subject: [PATCH 144/325] make sure iterator is not end() before trying to get the equipped item --- apps/openmw/mwworld/containerstore.cpp | 2 +- apps/openmw/mwworld/containerstore.hpp | 2 +- apps/openmw/mwworld/inventorystore.cpp | 4 ++-- apps/openmw/mwworld/inventorystore.hpp | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index dcddc333b0..ee1b620cd7 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -45,7 +45,7 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::end() return ContainerStoreIterator (this); } -bool MWWorld::ContainerStore::stacks(const Ptr& ptr1, const Ptr& ptr2) const +bool MWWorld::ContainerStore::stacks(const Ptr& ptr1, const Ptr& ptr2) { /// \todo add current weapon/armor health, remaining lockpick/repair uses, current enchantment charge here as soon as they are implemented if ( ptr1.mCellRef->refID == ptr2.mCellRef->refID diff --git a/apps/openmw/mwworld/containerstore.hpp b/apps/openmw/mwworld/containerstore.hpp index f0e9d7e4ab..3cb3f3bdc5 100644 --- a/apps/openmw/mwworld/containerstore.hpp +++ b/apps/openmw/mwworld/containerstore.hpp @@ -78,7 +78,7 @@ namespace MWWorld void addImpl (const Ptr& ptr); ///< Add the item to this container (no stacking) - virtual bool stacks (const Ptr& ptr1, const Ptr& ptr2) const; + virtual bool stacks (const Ptr& ptr1, const Ptr& ptr2); ///< @return true if the two specified objects can stack with each other /// @note ptr1 is the item that is already in this container diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index 6cf35ac644..3e535793c0 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -201,7 +201,7 @@ void MWWorld::InventoryStore::autoEquip (const MWMechanics::NpcStats& stats) } } -bool MWWorld::InventoryStore::stacks(const Ptr& ptr1, const Ptr& ptr2) const +bool MWWorld::InventoryStore::stacks(const Ptr& ptr1, const Ptr& ptr2) { bool canStack = MWWorld::ContainerStore::stacks(ptr1, ptr2); if (!canStack) @@ -211,7 +211,7 @@ bool MWWorld::InventoryStore::stacks(const Ptr& ptr1, const Ptr& ptr2) const for (TSlots::const_iterator iter (mSlots.begin()); iter!=mSlots.end(); ++iter) { - if (ptr1 == **iter) + if (*iter != end() && ptr1 == **iter) return false; } diff --git a/apps/openmw/mwworld/inventorystore.hpp b/apps/openmw/mwworld/inventorystore.hpp index 4162c7e2e8..05fc651ee7 100644 --- a/apps/openmw/mwworld/inventorystore.hpp +++ b/apps/openmw/mwworld/inventorystore.hpp @@ -67,7 +67,7 @@ namespace MWWorld protected: - virtual bool stacks (const Ptr& ptr1, const Ptr& ptr2) const; + virtual bool stacks (const Ptr& ptr1, const Ptr& ptr2); ///< @return true if the two specified objects can stack with each other /// @note ptr1 is the item that is already in this container From 967fb13fca9d0e4c9265c9840643b0070e7d80ef Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 13 May 2012 18:14:03 +0200 Subject: [PATCH 145/325] remove the old inventory code, split HUD, map and mainmenu into seperate implementation files --- apps/openmw/CMakeLists.txt | 4 +- apps/openmw/mwgui/{layouts.cpp => hud.cpp} | 97 +-------- apps/openmw/mwgui/hud.hpp | 50 +++++ apps/openmw/mwgui/layouts.hpp | 236 --------------------- apps/openmw/mwgui/mainmenu.hpp | 16 ++ apps/openmw/mwgui/map_window.cpp | 94 +++++++- apps/openmw/mwgui/map_window.hpp | 30 ++- apps/openmw/mwgui/window_manager.cpp | 3 +- 8 files changed, 190 insertions(+), 340 deletions(-) rename apps/openmw/mwgui/{layouts.cpp => hud.cpp} (72%) create mode 100644 apps/openmw/mwgui/hud.hpp delete mode 100644 apps/openmw/mwgui/layouts.hpp create mode 100644 apps/openmw/mwgui/mainmenu.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index be99cefdd7..5ecb2eea80 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -23,10 +23,10 @@ add_openmw_dir (mwinput ) add_openmw_dir (mwgui - layouts text_input widgets race class birth review window_manager console dialogue + text_input widgets race class birth review window_manager console dialogue dialogue_history window_base stats_window messagebox journalwindow charactercreation map_window window_pinnable_base cursorreplace tooltips scrollwindow bookwindow list - formatting itemwidget inventorywindow container + formatting itemwidget inventorywindow container hud ) add_openmw_dir (mwdialogue diff --git a/apps/openmw/mwgui/layouts.cpp b/apps/openmw/mwgui/hud.cpp similarity index 72% rename from apps/openmw/mwgui/layouts.cpp rename to apps/openmw/mwgui/hud.cpp index 21302d7c1d..ffee9f6c7f 100644 --- a/apps/openmw/mwgui/layouts.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -1,18 +1,14 @@ -#include "layouts.hpp" - -#include "../mwmechanics/mechanicsmanager.hpp" -#include "window_manager.hpp" +#include "hud.hpp" #include -#include -#include -#undef min -#undef max +#include + +#include + using namespace MWGui; - HUD::HUD(int width, int height, int fpsLevel) : Layout("openmw_hud_layout.xml") , health(NULL) @@ -247,86 +243,3 @@ void HUD::setBottomRightVisibility(bool effectBoxVisible, bool minimapBoxVisible effectBox->setVisible(effectBoxVisible); } -LocalMapBase::LocalMapBase() - : mCurX(0) - , mCurY(0) - , mInterior(false) - , mFogOfWar(true) - , mLocalMap(NULL) - , mPrefix() - , mChanged(true) - , mLayout(NULL) - , mLastPositionX(0.0f) - , mLastPositionY(0.0f) - , mLastDirectionX(0.0f) - , mLastDirectionY(0.0f) -{ -} - -void LocalMapBase::init(MyGUI::ScrollView* widget, OEngine::GUI::Layout* layout) -{ - mLocalMap = widget; - mLayout = layout; -} - -void LocalMapBase::setCellPrefix(const std::string& prefix) -{ - mPrefix = prefix; - mChanged = true; -} - -void LocalMapBase::toggleFogOfWar() -{ - mFogOfWar = !mFogOfWar; - applyFogOfWar(); -} - -void LocalMapBase::applyFogOfWar() -{ - for (int mx=0; mx<3; ++mx) - { - for (int my=0; my<3; ++my) - { - std::string name = "Map_" + boost::lexical_cast(mx) + "_" - + boost::lexical_cast(my); - std::string image = mPrefix+"_"+ boost::lexical_cast(mCurX + (mx-1)) + "_" - + boost::lexical_cast(mCurY + (mInterior ? (my-1) : -1*(my-1))); - MyGUI::ImageBox* fog; - mLayout->getWidget(fog, name+"_fog"); - fog->setImageTexture(mFogOfWar ? - ((MyGUI::RenderManager::getInstance().getTexture(image+"_fog") != 0) ? image+"_fog" - : "black.png" ) - : ""); - } - } -} - -void LocalMapBase::setActiveCell(const int x, const int y, bool interior) -{ - if (x==mCurX && y==mCurY && mInterior==interior && !mChanged) return; // don't do anything if we're still in the same cell - for (int mx=0; mx<3; ++mx) - { - for (int my=0; my<3; ++my) - { - std::string name = "Map_" + boost::lexical_cast(mx) + "_" - + boost::lexical_cast(my); - - std::string image = mPrefix+"_"+ boost::lexical_cast(x + (mx-1)) + "_" - + boost::lexical_cast(y + (interior ? (my-1) : -1*(my-1))); - - MyGUI::ImageBox* box; - mLayout->getWidget(box, name); - - if (MyGUI::RenderManager::getInstance().getTexture(image) != 0) - box->setImageTexture(image); - else - box->setImageTexture("black.png"); - } - } - mInterior = interior; - mCurX = x; - mCurY = y; - mChanged = false; - applyFogOfWar(); -} - diff --git a/apps/openmw/mwgui/hud.hpp b/apps/openmw/mwgui/hud.hpp new file mode 100644 index 0000000000..831707511e --- /dev/null +++ b/apps/openmw/mwgui/hud.hpp @@ -0,0 +1,50 @@ +#include "map_window.hpp" + +#include + +#include "../mwmechanics/stat.hpp" + +namespace MWGui +{ + class HUD : public OEngine::GUI::Layout, public LocalMapBase + { + public: + HUD(int width, int height, int fpsLevel); + void setStats(int h, int hmax, int m, int mmax, int s, int smax); + void setWeapIcon(const char *str); + void setSpellIcon(const char *str); + void setWeapStatus(int s, int smax); + void setSpellStatus(int s, int smax); + void setEffect(const char *img); + void setValue (const std::string& id, const MWMechanics::DynamicStat& value); + void setFPS(float fps); + void setTriangleCount(size_t count); + void setBatchCount(size_t count); + void setPlayerDir(const float x, const float y); + void setPlayerPos(const float x, const float y); + void setBottomLeftVisibility(bool hmsVisible, bool weapVisible, bool spellVisible); + void setBottomRightVisibility(bool effectBoxVisible, bool minimapVisible); + void setFpsLevel(const int level); + + MyGUI::ProgressPtr health, magicka, stamina; + MyGUI::Widget *weapBox, *spellBox; + MyGUI::ImageBox *weapImage, *spellImage; + MyGUI::ProgressPtr weapStatus, spellStatus; + MyGUI::Widget *effectBox, *minimapBox; + MyGUI::ImageBox* effect1; + MyGUI::ScrollView* minimap; + MyGUI::ImageBox* compass; + MyGUI::ImageBox* crosshair; + + MyGUI::WidgetPtr fpsbox; + MyGUI::TextBox* fpscounter; + MyGUI::TextBox* trianglecounter; + MyGUI::TextBox* batchcounter; + + private: + // bottom left elements + int hmsBaseLeft, weapBoxBaseLeft, spellBoxBaseLeft; + // bottom right elements + int minimapBoxBaseRight, effectBoxBaseRight; + }; +} diff --git a/apps/openmw/mwgui/layouts.hpp b/apps/openmw/mwgui/layouts.hpp deleted file mode 100644 index 19d96d2efa..0000000000 --- a/apps/openmw/mwgui/layouts.hpp +++ /dev/null @@ -1,236 +0,0 @@ -#ifndef MWGUI_LAYOUTS_H -#define MWGUI_LAYOUTS_H - -#include - -#include -#include - -#include -#include -#include -#include - -#include "../mwmechanics/stat.hpp" -#include "window_base.hpp" - -#include - -/* - This file contains classes corresponding to window layouts - defined in resources/mygui/ *.xml. - - Each class inherites GUI::Layout and loads the XML file, and - provides some helper functions to manipulate the elements of the - window. - - The windows are never created or destroyed (except at startup and - shutdown), they are only hid. You can control visibility with - setVisible(). - */ - -namespace MWGui -{ - class LocalMapBase - { - public: - LocalMapBase(); - void init(MyGUI::ScrollView* widget, OEngine::GUI::Layout* layout); - - void setCellPrefix(const std::string& prefix); - void setActiveCell(const int x, const int y, bool interior=false); - - void toggleFogOfWar(); - - protected: - int mCurX, mCurY; - bool mInterior; - MyGUI::ScrollView* mLocalMap; - std::string mPrefix; - bool mChanged; - bool mFogOfWar; - - void applyFogOfWar(); - - OEngine::GUI::Layout* mLayout; - - float mLastPositionX; - float mLastPositionY; - float mLastDirectionX; - float mLastDirectionY; - }; - - class HUD : public OEngine::GUI::Layout, public LocalMapBase - { - public: - HUD(int width, int height, int fpsLevel); - void setStats(int h, int hmax, int m, int mmax, int s, int smax); - void setWeapIcon(const char *str); - void setSpellIcon(const char *str); - void setWeapStatus(int s, int smax); - void setSpellStatus(int s, int smax); - void setEffect(const char *img); - void setValue (const std::string& id, const MWMechanics::DynamicStat& value); - void setFPS(float fps); - void setTriangleCount(size_t count); - void setBatchCount(size_t count); - void setPlayerDir(const float x, const float y); - void setPlayerPos(const float x, const float y); - void setBottomLeftVisibility(bool hmsVisible, bool weapVisible, bool spellVisible); - void setBottomRightVisibility(bool effectBoxVisible, bool minimapVisible); - void setFpsLevel(const int level); - - MyGUI::ProgressPtr health, magicka, stamina; - MyGUI::Widget *weapBox, *spellBox; - MyGUI::ImageBox *weapImage, *spellImage; - MyGUI::ProgressPtr weapStatus, spellStatus; - MyGUI::Widget *effectBox, *minimapBox; - MyGUI::ImageBox* effect1; - MyGUI::ScrollView* minimap; - MyGUI::ImageBox* compass; - MyGUI::ImageBox* crosshair; - - MyGUI::WidgetPtr fpsbox; - MyGUI::TextBox* fpscounter; - MyGUI::TextBox* trianglecounter; - MyGUI::TextBox* batchcounter; - - private: - // bottom left elements - int hmsBaseLeft, weapBoxBaseLeft, spellBoxBaseLeft; - // bottom right elements - int minimapBoxBaseRight, effectBoxBaseRight; - }; - - class MainMenu : public OEngine::GUI::Layout - { - public: - MainMenu(int w, int h) - : Layout("openmw_mainmenu_layout.xml") - { - setCoord(0,0,w,h); - } - }; - -#if 0 - class InventoryWindow : public OEngine::GUI::Layout - { - public: - enum CategoryMode - { - CM_All = 0, // All items - CM_Weapon = 1, // Only weapons - CM_Apparel = 2, // Apparel - CM_Magic = 3, // Magic - CM_Misc = 4 // Misc - }; - - InventoryWindow () - : Layout("openmw_inventory_window_layout.xml") - , categoryMode(CM_All) - - // color should be fetched from skin - , activeColor(0, 0, 1) - , inactiveColor(0.7, 0.7, 0.7) - { - setCoord(0, 200, 600, 400); - - // These are just demo values, you should replace these with - // real calls from outside the class later. - - mMainWidget->setCaption("Glass Frostsword"); - setText("EncumbranceBarT", "176/210"); - - MyGUI::ProgressPtr pt; - getWidget(pt, "EncumbranceBar"); - pt->setProgressRange(210); - pt->setProgressPosition(176); - - MyGUI::WidgetPtr avatar; - getWidget(avatar, "Avatar"); - - // Adjust armor rating text to bottom of avatar widget - MyGUI::TextBox* armor_rating; - getWidget(armor_rating, "ArmorRating"); - armor_rating->setCaption("Armor: 11"); - MyGUI::IntCoord coord = armor_rating->getCoord(); - coord.top = avatar->getCoord().height - 4 - coord.height; - armor_rating->setCoord(coord); - - names[0] = "All"; - names[1] = "Weapon"; - names[2] = "Apparel"; - names[3] = "Magic"; - names[4] = "Misc"; - - boost::array categories = { { - CM_All, CM_Weapon, CM_Apparel, CM_Magic, CM_Misc - } }; - - // Initialize buttons with text and adjust sizes, also mark All as active button - int margin = 2; - int last_x = 0; - for (int i = 0; i < categories.size(); ++i) - { - CategoryMode mode = categories[i]; - std::string name = names[mode]; - name += "Button"; - setText(name, names[mode]); - getWidget(buttons[mode], name); - - MyGUI::ButtonPtr &button_pt = buttons[mode]; - if (mode == CM_All) - button_pt->setTextColour(activeColor); - else - button_pt->setTextColour(inactiveColor); - MyGUI::IntCoord coord = button_pt->getCoord(); - coord.left = last_x; - last_x += coord.width + margin; - button_pt->setCoord(coord); - - button_pt->eventMouseButtonClick += MyGUI::newDelegate(this, &InventoryWindow::onCategorySelected); - } - } - - void setCategory(CategoryMode mode) - { - MyGUI::ButtonPtr pt = getCategoryButton(categoryMode); - pt->setTextColour(inactiveColor); - - pt = getCategoryButton(mode); - pt->setTextColour(activeColor); - categoryMode = mode; - } - - MyGUI::ButtonPtr getCategoryButton(CategoryMode mode) - { - return buttons[mode]; - } - - void onCategorySelected(MyGUI::Widget *widget) - { - boost::array categories = { { - CM_All, CM_Weapon, CM_Apparel, CM_Magic, CM_Misc - } }; - - for (int i = 0; i < categories.size(); ++i) - { - CategoryMode mode = categories[i]; - if (widget == buttons[mode]) - { - setCategory(mode); - return; - } - } - } - - CategoryMode categoryMode; // Current category filter - MyGUI::ButtonPtr buttons[5]; // Button pointers - std::string names[5]; // Names of category buttons - - MyGUI::Colour activeColor; - MyGUI::Colour inactiveColor; - }; -#endif -} -#endif diff --git a/apps/openmw/mwgui/mainmenu.hpp b/apps/openmw/mwgui/mainmenu.hpp new file mode 100644 index 0000000000..b32f2d900b --- /dev/null +++ b/apps/openmw/mwgui/mainmenu.hpp @@ -0,0 +1,16 @@ +#include + +namespace MWGui +{ + + class MainMenu : public OEngine::GUI::Layout + { + public: + MainMenu(int w, int h) + : Layout("openmw_mainmenu_layout.xml") + { + setCoord(0,0,w,h); + } + }; + +} diff --git a/apps/openmw/mwgui/map_window.cpp b/apps/openmw/mwgui/map_window.cpp index e0c828fdc4..d3541f774a 100644 --- a/apps/openmw/mwgui/map_window.cpp +++ b/apps/openmw/mwgui/map_window.cpp @@ -1,17 +1,95 @@ #include "map_window.hpp" #include "window_manager.hpp" -/* -#include "../mwmechanics/mechanicsmanager.hpp" -#include -#include -#include +#include -#undef min -#undef max -*/ using namespace MWGui; +LocalMapBase::LocalMapBase() + : mCurX(0) + , mCurY(0) + , mInterior(false) + , mFogOfWar(true) + , mLocalMap(NULL) + , mPrefix() + , mChanged(true) + , mLayout(NULL) + , mLastPositionX(0.0f) + , mLastPositionY(0.0f) + , mLastDirectionX(0.0f) + , mLastDirectionY(0.0f) +{ +} + +void LocalMapBase::init(MyGUI::ScrollView* widget, OEngine::GUI::Layout* layout) +{ + mLocalMap = widget; + mLayout = layout; +} + +void LocalMapBase::setCellPrefix(const std::string& prefix) +{ + mPrefix = prefix; + mChanged = true; +} + +void LocalMapBase::toggleFogOfWar() +{ + mFogOfWar = !mFogOfWar; + applyFogOfWar(); +} + +void LocalMapBase::applyFogOfWar() +{ + for (int mx=0; mx<3; ++mx) + { + for (int my=0; my<3; ++my) + { + std::string name = "Map_" + boost::lexical_cast(mx) + "_" + + boost::lexical_cast(my); + std::string image = mPrefix+"_"+ boost::lexical_cast(mCurX + (mx-1)) + "_" + + boost::lexical_cast(mCurY + (mInterior ? (my-1) : -1*(my-1))); + MyGUI::ImageBox* fog; + mLayout->getWidget(fog, name+"_fog"); + fog->setImageTexture(mFogOfWar ? + ((MyGUI::RenderManager::getInstance().getTexture(image+"_fog") != 0) ? image+"_fog" + : "black.png" ) + : ""); + } + } +} + +void LocalMapBase::setActiveCell(const int x, const int y, bool interior) +{ + if (x==mCurX && y==mCurY && mInterior==interior && !mChanged) return; // don't do anything if we're still in the same cell + for (int mx=0; mx<3; ++mx) + { + for (int my=0; my<3; ++my) + { + std::string name = "Map_" + boost::lexical_cast(mx) + "_" + + boost::lexical_cast(my); + + std::string image = mPrefix+"_"+ boost::lexical_cast(x + (mx-1)) + "_" + + boost::lexical_cast(y + (interior ? (my-1) : -1*(my-1))); + + MyGUI::ImageBox* box; + mLayout->getWidget(box, name); + + if (MyGUI::RenderManager::getInstance().getTexture(image) != 0) + box->setImageTexture(image); + else + box->setImageTexture("black.png"); + } + } + mInterior = interior; + mCurX = x; + mCurY = y; + mChanged = false; + applyFogOfWar(); +} + +// ------------------------------------------------------------------------------------------ + MapWindow::MapWindow(WindowManager& parWindowManager) : MWGui::WindowPinnableBase("openmw_map_window_layout.xml", parWindowManager), mGlobal(false) diff --git a/apps/openmw/mwgui/map_window.hpp b/apps/openmw/mwgui/map_window.hpp index d14221a408..e7318f4e45 100644 --- a/apps/openmw/mwgui/map_window.hpp +++ b/apps/openmw/mwgui/map_window.hpp @@ -1,11 +1,39 @@ #ifndef MWGUI_MAPWINDOW_H #define MWGUI_MAPWINDOW_H -#include "layouts.hpp" #include "window_pinnable_base.hpp" namespace MWGui { + class LocalMapBase + { + public: + LocalMapBase(); + void init(MyGUI::ScrollView* widget, OEngine::GUI::Layout* layout); + + void setCellPrefix(const std::string& prefix); + void setActiveCell(const int x, const int y, bool interior=false); + + void toggleFogOfWar(); + + protected: + int mCurX, mCurY; + bool mInterior; + MyGUI::ScrollView* mLocalMap; + std::string mPrefix; + bool mChanged; + bool mFogOfWar; + + void applyFogOfWar(); + + OEngine::GUI::Layout* mLayout; + + float mLastPositionX; + float mLastPositionY; + float mLastDirectionX; + float mLastDirectionY; + }; + class MapWindow : public MWGui::WindowPinnableBase, public LocalMapBase { public: diff --git a/apps/openmw/mwgui/window_manager.cpp b/apps/openmw/mwgui/window_manager.cpp index 47fae20030..290e0029a5 100644 --- a/apps/openmw/mwgui/window_manager.cpp +++ b/apps/openmw/mwgui/window_manager.cpp @@ -1,5 +1,4 @@ #include "window_manager.hpp" -#include "layouts.hpp" #include "text_input.hpp" #include "review.hpp" #include "dialogue.hpp" @@ -13,6 +12,8 @@ #include "scrollwindow.hpp" #include "bookwindow.hpp" #include "list.hpp" +#include "hud.hpp" +#include "mainmenu.hpp" #include "../mwmechanics/mechanicsmanager.hpp" #include "../mwinput/inputmanager.hpp" From 6c9f75b322d54c0079d9ad95299b014da51b19c9 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 13 May 2012 18:35:56 +0200 Subject: [PATCH 146/325] some unfinished work for dropping objects into the gameworld --- apps/openmw/mwgui/hud.cpp | 26 +++++++++++++++++++++++++- apps/openmw/mwgui/hud.hpp | 8 +++++++- apps/openmw/mwgui/window_manager.cpp | 2 +- 3 files changed, 33 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index ffee9f6c7f..47bf277992 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -6,10 +6,14 @@ #include +#include "../mwbase/environment.hpp" + +#include "window_manager.hpp" +#include "container.hpp" using namespace MWGui; -HUD::HUD(int width, int height, int fpsLevel) +HUD::HUD(int width, int height, int fpsLevel, DragAndDrop* dragAndDrop) : Layout("openmw_hud_layout.xml") , health(NULL) , magicka(NULL) @@ -32,6 +36,7 @@ HUD::HUD(int width, int height, int fpsLevel) , spellBoxBaseLeft(0) , effectBoxBaseRight(0) , minimapBoxBaseRight(0) + , mDragAndDrop(dragAndDrop) { setCoord(0,0, width, height); @@ -80,6 +85,8 @@ HUD::HUD(int width, int height, int fpsLevel) setEffect("icons\\s\\tx_s_chameleon.dds"); LocalMapBase::init(minimap, this); + + mMainWidget->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onWorldClicked); } void HUD::setFpsLevel(int level) @@ -243,3 +250,20 @@ void HUD::setBottomRightVisibility(bool effectBoxVisible, bool minimapBoxVisible effectBox->setVisible(effectBoxVisible); } +void HUD::onWorldClicked(MyGUI::Widget* _sender) +{ + if (mDragAndDrop->mIsOnDragAndDrop) + { + // drop item into the gameworld + + + mDragAndDrop->mStore.clear(); + mDragAndDrop->mIsOnDragAndDrop = false; + MyGUI::Gui::getInstance().destroyWidget(mDragAndDrop->mDraggedWidget); + mDragAndDrop->mDraggedWidget = 0; + mDragAndDrop->mContainerWindow = 0; + + MWBase::Environment::get().getWindowManager()->setDragDrop(false); + } +} + diff --git a/apps/openmw/mwgui/hud.hpp b/apps/openmw/mwgui/hud.hpp index 831707511e..22b1b87385 100644 --- a/apps/openmw/mwgui/hud.hpp +++ b/apps/openmw/mwgui/hud.hpp @@ -6,10 +6,12 @@ namespace MWGui { + class DragAndDrop; + class HUD : public OEngine::GUI::Layout, public LocalMapBase { public: - HUD(int width, int height, int fpsLevel); + HUD(int width, int height, int fpsLevel, DragAndDrop* dragAndDrop); void setStats(int h, int hmax, int m, int mmax, int s, int smax); void setWeapIcon(const char *str); void setSpellIcon(const char *str); @@ -46,5 +48,9 @@ namespace MWGui int hmsBaseLeft, weapBoxBaseLeft, spellBoxBaseLeft; // bottom right elements int minimapBoxBaseRight, effectBoxBaseRight; + + DragAndDrop* mDragAndDrop; + + void onWorldClicked(MyGUI::Widget* _sender); }; } diff --git a/apps/openmw/mwgui/window_manager.cpp b/apps/openmw/mwgui/window_manager.cpp index 290e0029a5..bb533e698f 100644 --- a/apps/openmw/mwgui/window_manager.cpp +++ b/apps/openmw/mwgui/window_manager.cpp @@ -99,7 +99,6 @@ WindowManager::WindowManager( mDragAndDrop->mDragAndDropWidget = dragAndDropWidget; mDragAndDrop->mContainerWindow = 0; - hud = new HUD(w,h, showFPSLevel); menu = new MainMenu(w,h); map = new MapWindow(*this); stats = new StatsWindow(*this); @@ -109,6 +108,7 @@ WindowManager::WindowManager( mDialogueWindow = new DialogueWindow(*this); mContainerWindow = new ContainerWindow(*this,mDragAndDrop); mInventoryWindow = new InventoryWindow(*this,mDragAndDrop); + hud = new HUD(w,h, showFPSLevel, mDragAndDrop); mToolTips = new ToolTips(this); mScrollWindow = new ScrollWindow(*this); mBookWindow = new BookWindow(*this); From d3e162ec830087be3cd04a5ff51ae90192bedab8 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 14 May 2012 17:41:17 +0200 Subject: [PATCH 147/325] dropping items works --- apps/openmw/mwgui/container.cpp | 2 + apps/openmw/mwgui/container.hpp | 1 - apps/openmw/mwgui/hud.cpp | 18 +++++ apps/openmw/mwworld/scene.cpp | 135 ++++++++++++++++++++------------ apps/openmw/mwworld/scene.hpp | 4 + apps/openmw/mwworld/world.cpp | 5 ++ apps/openmw/mwworld/world.hpp | 3 + 7 files changed, 119 insertions(+), 49 deletions(-) diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index de7419b80f..99a4b686e4 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -184,6 +184,8 @@ void ContainerBase::drawItems() MyGUI::TextBox* text = image->createWidget("SandBrightText", MyGUI::IntCoord(0, 14, 32, 18), MyGUI::Align::Default, std::string("Label")); text->setTextAlign(MyGUI::Align::Right); text->setNeedMouseFocus(false); + text->setTextShadow(true); + text->setTextShadowColour(MyGUI::Colour(0,0,0)); y += 42; if (y > maxHeight) diff --git a/apps/openmw/mwgui/container.hpp b/apps/openmw/mwgui/container.hpp index 6bfee13465..88fc552173 100644 --- a/apps/openmw/mwgui/container.hpp +++ b/apps/openmw/mwgui/container.hpp @@ -41,7 +41,6 @@ namespace MWGui MyGUI::Widget* mDraggedWidget; MyGUI::Widget* mDragAndDropWidget; MWWorld::ContainerStore mStore; - MWWorld::Ptr mItem; }; class ContainerBase diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index 47bf277992..80c02cd82f 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -7,6 +7,10 @@ #include #include "../mwbase/environment.hpp" +#include "../mwsound/soundmanager.hpp" +#include "../mwworld/class.hpp" +#include "../mwworld/world.hpp" +#include "../mwworld/player.hpp" #include "window_manager.hpp" #include "container.hpp" @@ -255,7 +259,21 @@ void HUD::onWorldClicked(MyGUI::Widget* _sender) if (mDragAndDrop->mIsOnDragAndDrop) { // drop item into the gameworld + MWWorld::Ptr object = *mDragAndDrop->mStore.begin(); + float* playerPos; + playerPos = MWBase::Environment::get().getWorld()->getPlayer().getPlayer().getRefData().getPosition().pos; + MWWorld::Ptr::CellStore* cell = MWBase::Environment::get().getWorld()->getPlayer().getPlayer().getCell(); /// \todo this might be a different cell + + ESM::Position& pos = object.getRefData().getPosition(); + pos.pos[0] = playerPos[0]; + pos.pos[1] = playerPos[1]; + pos.pos[2] = playerPos[2]; + + MWBase::Environment::get().getWorld()->insertObject(object, cell); + + std::string sound = MWWorld::Class::get(object).getDownSoundId(object); + MWBase::Environment::get().getSoundManager()->playSound (sound, 1.0, 1.0); mDragAndDrop->mStore.clear(); mDragAndDrop->mIsOnDragAndDrop = false; diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 6f9f3ed3ed..1d4f078d5a 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -15,39 +15,40 @@ #include "cellfunctors.hpp" -namespace { - -template -void insertCellRefList(MWRender::RenderingManager& rendering, - T& cellRefList, ESMS::CellStore &cell, MWWorld::PhysicsSystem& physics) +namespace { - if (!cellRefList.list.empty()) + + template + void insertCellRefList(MWRender::RenderingManager& rendering, + T& cellRefList, ESMS::CellStore &cell, MWWorld::PhysicsSystem& physics) { - const MWWorld::Class& class_ = - MWWorld::Class::get (MWWorld::Ptr (&*cellRefList.list.begin(), &cell)); - - for (typename T::List::iterator it = cellRefList.list.begin(); - it != cellRefList.list.end(); it++) + if (!cellRefList.list.empty()) { - if (it->mData.getCount() || it->mData.isEnabled()) - { - MWWorld::Ptr ptr (&*it, &cell); + const MWWorld::Class& class_ = + MWWorld::Class::get (MWWorld::Ptr (&*cellRefList.list.begin(), &cell)); - try + for (typename T::List::iterator it = cellRefList.list.begin(); + it != cellRefList.list.end(); it++) + { + if (it->mData.getCount() || it->mData.isEnabled()) { - rendering.addObject(ptr); - class_.insertObject(ptr, physics); - class_.enable (ptr); - } - catch (const std::exception& e) - { - std::string error ("error during rendering: "); - std::cerr << error + e.what() << std::endl; + MWWorld::Ptr ptr (&*it, &cell); + + try + { + rendering.addObject(ptr); + class_.insertObject(ptr, physics); + class_.enable (ptr); + } + catch (const std::exception& e) + { + std::string error ("error during rendering: "); + std::cerr << error + e.what() << std::endl; + } } } } } -} } @@ -300,30 +301,68 @@ namespace MWWorld mCellChanged = false; } -void Scene::insertCell(ESMS::CellStore &cell) -{ - // Loop through all references in the cell - insertCellRefList(mRendering, cell.activators, cell, *mPhysics); - insertCellRefList(mRendering, cell.potions, cell, *mPhysics); - insertCellRefList(mRendering, cell.appas, cell, *mPhysics); - insertCellRefList(mRendering, cell.armors, cell, *mPhysics); - insertCellRefList(mRendering, cell.books, cell, *mPhysics); - insertCellRefList(mRendering, cell.clothes, cell, *mPhysics); - insertCellRefList(mRendering, cell.containers, cell, *mPhysics); - insertCellRefList(mRendering, cell.creatures, cell, *mPhysics); - insertCellRefList(mRendering, cell.doors, cell, *mPhysics); - insertCellRefList(mRendering, cell.ingreds, cell, *mPhysics); - insertCellRefList(mRendering, cell.creatureLists, cell, *mPhysics); - insertCellRefList(mRendering, cell.itemLists, cell, *mPhysics); - insertCellRefList(mRendering, cell.lights, cell, *mPhysics); - insertCellRefList(mRendering, cell.lockpicks, cell, *mPhysics); - insertCellRefList(mRendering, cell.miscItems, cell, *mPhysics); - insertCellRefList(mRendering, cell.npcs, cell, *mPhysics); - insertCellRefList(mRendering, cell.probes, cell, *mPhysics); - insertCellRefList(mRendering, cell.repairs, cell, *mPhysics); - insertCellRefList(mRendering, cell.statics, cell, *mPhysics); - insertCellRefList(mRendering, cell.weapons, cell, *mPhysics); -} + void Scene::insertCell(ESMS::CellStore &cell) + { + // Loop through all references in the cell + insertCellRefList(mRendering, cell.activators, cell, *mPhysics); + insertCellRefList(mRendering, cell.potions, cell, *mPhysics); + insertCellRefList(mRendering, cell.appas, cell, *mPhysics); + insertCellRefList(mRendering, cell.armors, cell, *mPhysics); + insertCellRefList(mRendering, cell.books, cell, *mPhysics); + insertCellRefList(mRendering, cell.clothes, cell, *mPhysics); + insertCellRefList(mRendering, cell.containers, cell, *mPhysics); + insertCellRefList(mRendering, cell.creatures, cell, *mPhysics); + insertCellRefList(mRendering, cell.doors, cell, *mPhysics); + insertCellRefList(mRendering, cell.ingreds, cell, *mPhysics); + insertCellRefList(mRendering, cell.creatureLists, cell, *mPhysics); + insertCellRefList(mRendering, cell.itemLists, cell, *mPhysics); + insertCellRefList(mRendering, cell.lights, cell, *mPhysics); + insertCellRefList(mRendering, cell.lockpicks, cell, *mPhysics); + insertCellRefList(mRendering, cell.miscItems, cell, *mPhysics); + insertCellRefList(mRendering, cell.npcs, cell, *mPhysics); + insertCellRefList(mRendering, cell.probes, cell, *mPhysics); + insertCellRefList(mRendering, cell.repairs, cell, *mPhysics); + insertCellRefList(mRendering, cell.statics, cell, *mPhysics); + insertCellRefList(mRendering, cell.weapons, cell, *mPhysics); + } + void Scene::insertObject(MWWorld::Ptr ptr, Ptr::CellStore* cell) + { + ptr.mCell = cell; + + mRendering.addObject(ptr); + MWWorld::Class::get(ptr).insertObject(ptr, *mPhysics); + MWWorld::Class::get(ptr).enable(ptr); + + std::string type = ptr.getTypeName(); + + // insert into the correct CellRefList + if (type == typeid(ESM::Potion).name()) + cell->potions.list.push_back( *ptr.get() ); + else if (type == typeid(ESM::Apparatus).name()) + cell->appas.list.push_back( *ptr.get() ); + else if (type == typeid(ESM::Armor).name()) + cell->armors.list.push_back( *ptr.get() ); + else if (type == typeid(ESM::Book).name()) + cell->books.list.push_back( *ptr.get() ); + else if (type == typeid(ESM::Clothing).name()) + cell->clothes.list.push_back( *ptr.get() ); + else if (type == typeid(ESM::Ingredient).name()) + cell->ingreds.list.push_back( *ptr.get() ); + else if (type == typeid(ESM::Light).name()) + cell->lights.list.push_back( *ptr.get() ); + else if (type == typeid(ESM::Tool).name()) + cell->lockpicks.list.push_back( *ptr.get() ); + else if (type == typeid(ESM::Repair).name()) + cell->repairs.list.push_back( *ptr.get() ); + else if (type == typeid(ESM::Probe).name()) + cell->probes.list.push_back( *ptr.get() ); + else if (type == typeid(ESM::Weapon).name()) + cell->weapons.list.push_back( *ptr.get() ); + else if (type == typeid(ESM::Miscellaneous).name()) + cell->miscItems.list.push_back( *ptr.get() ); + else + throw std::runtime_error("Trying to insert object of unhandled type"); + } } diff --git a/apps/openmw/mwworld/scene.hpp b/apps/openmw/mwworld/scene.hpp index 1a9f2f271a..857ee50d1e 100644 --- a/apps/openmw/mwworld/scene.hpp +++ b/apps/openmw/mwworld/scene.hpp @@ -100,6 +100,10 @@ namespace MWWorld void insertCell(ESMS::CellStore &cell); + /// this method is only meant for dropping objects into the gameworld from a container + /// and thus only handles object types that can be placed in a container + void insertObject(MWWorld::Ptr object, Ptr::CellStore* cell); + void update (float duration); }; } diff --git a/apps/openmw/mwworld/world.cpp b/apps/openmw/mwworld/world.cpp index 4adaf79183..d2b6877425 100644 --- a/apps/openmw/mwworld/world.cpp +++ b/apps/openmw/mwworld/world.cpp @@ -948,4 +948,9 @@ namespace MWWorld mRendering->toggleWater(); } + void World::insertObject(MWWorld::Ptr ptr, Ptr::CellStore* cell) + { + mWorldScene->insertObject(ptr, cell); + } + } diff --git a/apps/openmw/mwworld/world.hpp b/apps/openmw/mwworld/world.hpp index 7359f8b902..3b56dea970 100644 --- a/apps/openmw/mwworld/world.hpp +++ b/apps/openmw/mwworld/world.hpp @@ -263,6 +263,9 @@ namespace MWWorld void update (float duration); + void insertObject (MWWorld::Ptr ptr, Ptr::CellStore* cell); + ///< insert object in a given cell + /// \note this method is only meant for dropping items into the gameworld from a container }; } From 933a40de14f1dc64c6d74685388841dca0fbc54d Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 14 May 2012 21:37:43 +0200 Subject: [PATCH 148/325] better floating object label positioning. --- apps/openmw/mwgui/tooltips.cpp | 15 ++++++--- apps/openmw/mwgui/tooltips.hpp | 5 +++ apps/openmw/mwgui/window_manager.cpp | 5 +++ apps/openmw/mwgui/window_manager.hpp | 1 + apps/openmw/mwrender/renderingmanager.cpp | 39 +++++++++++++++++++++++ apps/openmw/mwrender/renderingmanager.hpp | 4 +++ apps/openmw/mwworld/world.cpp | 19 ++++++++++- 7 files changed, 82 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 635e9481b9..6f84345356 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -17,6 +17,8 @@ ToolTips::ToolTips(WindowManager* windowManager) : , mWindowManager(windowManager) , mFullHelp(false) , mEnabled(true) + , mFocusToolTipX(0.0) + , mFocusToolTipY(0.0) { getWidget(mDynamicToolTipBox, "DynamicToolTipBox"); @@ -118,11 +120,8 @@ void ToolTips::onFrame(float frameDuration) { IntSize tooltipSize = getToolTipViaPtr(); - // adjust tooltip size to fit its content, position it above the crosshair - /// \todo Slide the tooltip along the bounding box of the focused object (like in Morrowind) - /// relevant link: http://www.ogre3d.org/tikiwiki/ObjectTextDisplay - setCoord(std::max(0, viewSize.width/2 - (tooltipSize.width)/2), - std::max(0, viewSize.height/2 - (tooltipSize.height) - 32), + setCoord(viewSize.width/2 - tooltipSize.width/2, + std::max(0, int(mFocusToolTipY*viewSize.height - tooltipSize.height)), tooltipSize.width, tooltipSize.height); } @@ -387,3 +386,9 @@ bool ToolTips::getFullHelp() const { return mFullHelp; } + +void ToolTips::setFocusObjectScreenCoords(float min_x, float min_y, float max_x, float max_y) +{ + mFocusToolTipX = (min_x + max_x) / 2; + mFocusToolTipY = min_y; +} diff --git a/apps/openmw/mwgui/tooltips.hpp b/apps/openmw/mwgui/tooltips.hpp index 87b9e97bff..4be0baff9d 100644 --- a/apps/openmw/mwgui/tooltips.hpp +++ b/apps/openmw/mwgui/tooltips.hpp @@ -45,6 +45,8 @@ namespace MWGui bool getFullHelp() const; void setFocusObject(const MWWorld::Ptr& focus); + void setFocusObjectScreenCoords(float min_x, float min_y, float max_x, float max_y); + ///< set the screen-space position of the tooltip for focused object static std::string getValueString(const int value, const std::string& prefix); ///< @return "prefix: value" or "" if value is 0 @@ -73,6 +75,9 @@ namespace MWGui MyGUI::IntSize createToolTip(const ToolTipInfo& info); ///< @return requested tooltip size + float mFocusToolTipX; + float mFocusToolTipY; + bool mGameMode; bool mEnabled; diff --git a/apps/openmw/mwgui/window_manager.cpp b/apps/openmw/mwgui/window_manager.cpp index bb533e698f..c93d5303cf 100644 --- a/apps/openmw/mwgui/window_manager.cpp +++ b/apps/openmw/mwgui/window_manager.cpp @@ -540,6 +540,11 @@ void WindowManager::setFocusObject(const MWWorld::Ptr& focus) mToolTips->setFocusObject(focus); } +void WindowManager::setFocusObjectScreenCoords(float min_x, float min_y, float max_x, float max_y) +{ + mToolTips->setFocusObjectScreenCoords(min_x, min_y, max_x, max_y); +} + void WindowManager::toggleFullHelp() { mToolTips->toggleFullHelp(); diff --git a/apps/openmw/mwgui/window_manager.hpp b/apps/openmw/mwgui/window_manager.hpp index 5dfcf64708..cff93266cb 100644 --- a/apps/openmw/mwgui/window_manager.hpp +++ b/apps/openmw/mwgui/window_manager.hpp @@ -165,6 +165,7 @@ namespace MWGui void setPlayerDir(const float x, const float y); ///< set player view direction in map space void setFocusObject(const MWWorld::Ptr& focus); + void setFocusObjectScreenCoords(float min_x, float min_y, float max_x, float max_y); void setMouseVisible(bool visible); void setDragDrop(bool dragDrop); diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index a95a179c6c..f795ed3721 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -518,4 +518,43 @@ void RenderingManager::switchToExterior() mRendering.getScene()->setCameraRelativeRendering(true); } +Ogre::Vector4 RenderingManager::boundingBoxToScreen(Ogre::AxisAlignedBox bounds) +{ + Ogre::Matrix4 mat = mRendering.getCamera()->getViewMatrix(); + + const Ogre::Vector3* corners = bounds.getAllCorners(); + + float min_x = 1.0f, max_x = 0.0f, min_y = 1.0f, max_y = 0.0f; + + // expand the screen-space bounding-box so that it completely encloses + // the object's AABB + for (int i=0; i<8; i++) + { + Ogre::Vector3 corner = corners[i]; + + // multiply the AABB corner vertex by the view matrix to + // get a camera-space vertex + corner = mat * corner; + + // make 2D relative/normalized coords from the view-space vertex + // by dividing out the Z (depth) factor -- this is an approximation + float x = corner.x / corner.z + 0.5; + float y = corner.y / corner.z + 0.5; + + if (x < min_x) + min_x = x; + + if (x > max_x) + max_x = x; + + if (y < min_y) + min_y = y; + + if (y > max_y) + max_y = y; + } + + return Vector4(min_x, min_y, max_x, max_y); +} + } // namespace diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 0d11b3d57d..8b457997de 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -151,6 +151,10 @@ class RenderingManager: private RenderingInterface { ///< Skip the animation for the given MW-reference for one frame. Calls to this function for /// references that are currently not in the rendered scene should be ignored. + Ogre::Vector4 boundingBoxToScreen(Ogre::AxisAlignedBox bounds); + ///< transform the specified bounding box (in world coordinates) into screen coordinates. + /// @return packed vector4 (min_x, min_y, max_x, max_y) + private: void setAmbientMode(); diff --git a/apps/openmw/mwworld/world.cpp b/apps/openmw/mwworld/world.cpp index d2b6877425..0474d894c5 100644 --- a/apps/openmw/mwworld/world.cpp +++ b/apps/openmw/mwworld/world.cpp @@ -768,7 +768,24 @@ namespace MWWorld // inform the GUI about focused object try { - MWBase::Environment::get().getWindowManager()->setFocusObject(getPtrViaHandle(mFacedHandle)); + MWWorld::Ptr object = getPtrViaHandle(mFacedHandle); + MWBase::Environment::get().getWindowManager()->setFocusObject(object); + + // retrieve object dimensions so we know where to place the floating label + Ogre::SceneNode* node = object.getRefData().getBaseNode(); + Ogre::AxisAlignedBox bounds; + int i; + for (i=0; inumAttachedObjects(); ++i) + { + Ogre::MovableObject* ob = node->getAttachedObject(i); + bounds.merge(ob->getWorldBoundingBox()); + } + if (bounds.isFinite()) + { + Vector4 screenCoords = mRendering->boundingBoxToScreen(bounds); + MWBase::Environment::get().getWindowManager()->setFocusObjectScreenCoords( + screenCoords[0], screenCoords[1], screenCoords[2], screenCoords[3]); + } } catch (std::runtime_error&) { From 320cc7d020f3d68a1104d8207f8020ed0933f6bd Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 15 May 2012 11:02:50 +0200 Subject: [PATCH 149/325] implemented ctrl and shift-keys for item drag&drop (take all, take 1) --- apps/openmw/mwgui/container.cpp | 74 +++++++++++++++++++--------- apps/openmw/mwgui/container.hpp | 7 ++- apps/openmw/mwinput/inputmanager.cpp | 39 ++++++++++++--- apps/openmw/mwinput/inputmanager.hpp | 3 ++ 4 files changed, 89 insertions(+), 34 deletions(-) diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 99a4b686e4..82b695a2b8 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -49,29 +49,49 @@ void ContainerBase::onSelectedItem(MyGUI::Widget* _sender) { if(!mDragAndDrop->mIsOnDragAndDrop) { - mDragAndDrop->mIsOnDragAndDrop = true; - _sender->detachFromWidget(); - _sender->attachToWidget(mDragAndDrop->mDragAndDropWidget); + int count = (*_sender->getUserData()).getRefData().getCount(); - MWWorld::Ptr object = *_sender->getUserData(); - mDragAndDrop->mStore.add(object); - object.getRefData().setCount(0); - - std::string sound = MWWorld::Class::get(object).getUpSoundId(object); - MWBase::Environment::get().getSoundManager()->playSound (sound, 1.0, 1.0); - - mDragAndDrop->mDraggedWidget = _sender; - mDragAndDrop->mContainerWindow = const_cast(this); - // hide the count text - _sender->getChildAt(0)->getChildAt(0)->setVisible(false); - drawItems(); - - MWBase::Environment::get().getWindowManager()->setDragDrop(true); + if (MWBase::Environment::get().getInputManager()->getShiftDown() || count == 1) + { + onSelectedItemImpl(_sender, count); + } + else if (MWBase::Environment::get().getInputManager()->getCtrlDown()) + { + onSelectedItemImpl(_sender, 1); + } + else + { + /// \todo count selection window + onSelectedItemImpl(_sender, count); + } } else onContainerClicked(mContainerWidget); } +void ContainerBase::onSelectedItemImpl(MyGUI::Widget* _sender, int count) +{ + mDragAndDrop->mIsOnDragAndDrop = true; + _sender->detachFromWidget(); + _sender->attachToWidget(mDragAndDrop->mDragAndDropWidget); + + MWWorld::Ptr object = *_sender->getUserData(); + int originalCount = object.getRefData().getCount(); + object.getRefData().setCount(count); + mDragAndDrop->mStore.add(object); + object.getRefData().setCount(originalCount - count); + + std::string sound = MWWorld::Class::get(object).getUpSoundId(object); + MWBase::Environment::get().getSoundManager()->playSound (sound, 1.0, 1.0); + + mDragAndDrop->mDraggedWidget = _sender; + mDragAndDrop->mContainerWindow = const_cast(this); + static_cast(_sender->getChildAt(0)->getChildAt(0))->setCaption(getCountString((*mDragAndDrop->mStore.begin()).getRefData().getCount())); + drawItems(); + + MWBase::Environment::get().getWindowManager()->setDragDrop(true); +} + void ContainerBase::onContainerClicked(MyGUI::Widget* _sender) { if(mDragAndDrop->mIsOnDragAndDrop) //drop widget here @@ -154,6 +174,8 @@ void ContainerBase::drawItems() + MWWorld::ContainerStore::Type_Apparatus; } + /// \todo performance improvement: don't create/destroy all the widgets everytime the container window changes size, only reposition them + for (MWWorld::ContainerStoreIterator iter (containerStore.begin(categories)); iter!=containerStore.end(); ++iter) { index++; @@ -194,13 +216,7 @@ void ContainerBase::drawItems() y = 0; } - if(iter->getRefData().getCount() > 1) - { - if (iter->getRefData().getCount() > 9999) - text->setCaption(boost::lexical_cast(iter->getRefData().getCount()/1000.f) + "k"); - else - text->setCaption(boost::lexical_cast(iter->getRefData().getCount())); - } + text->setCaption(getCountString(iter->getRefData().getCount())); } } @@ -209,6 +225,16 @@ void ContainerBase::drawItems() mContainerWidget->setSize(size); } +std::string ContainerBase::getCountString(const int count) +{ + if (count == 1) + return ""; + if (count > 9999) + return boost::lexical_cast(count/1000.f) + "k"; + else + return boost::lexical_cast(count); +} + void ContainerBase::Update() { if(mDragAndDrop->mIsOnDragAndDrop) diff --git a/apps/openmw/mwgui/container.hpp b/apps/openmw/mwgui/container.hpp index 88fc552173..5cdc8ef1de 100644 --- a/apps/openmw/mwgui/container.hpp +++ b/apps/openmw/mwgui/container.hpp @@ -74,9 +74,12 @@ namespace MWGui Filter mFilter; void onSelectedItem(MyGUI::Widget* _sender); + void onSelectedItemImpl(MyGUI::Widget* _sender, int count); void onContainerClicked(MyGUI::Widget* _sender); void onMouseWheel(MyGUI::Widget* _sender, int _rel); + std::string getCountString(const int count); + void drawItems(); }; @@ -90,13 +93,9 @@ namespace MWGui void open(MWWorld::Ptr container); protected: - std::vector mContainerWidgets; - MyGUI::Button* mTakeButton; MyGUI::Button* mCloseButton; - bool mIsValid;//is in the right GUI Mode - void onWindowResize(MyGUI::Window* window); void onCloseButtonClicked(MyGUI::Widget* _sender); void onTakeAllButtonClicked(MyGUI::Widget* _sender); diff --git a/apps/openmw/mwinput/inputmanager.cpp b/apps/openmw/mwinput/inputmanager.cpp index 4d79eb3217..787f12f252 100644 --- a/apps/openmw/mwinput/inputmanager.cpp +++ b/apps/openmw/mwinput/inputmanager.cpp @@ -60,7 +60,7 @@ namespace MWInput A_CycleWeaponRight, A_ToggleSneak, //Toggles Sneak, add Push-Sneak later A_ToggleWalk, //Toggle Walking/Running - A_Crouch, + A_Crouch, A_QuickSave, A_QuickLoad, @@ -69,6 +69,8 @@ namespace MWInput A_ToggleWeapon, A_ToggleSpell, + A_Shift, + A_ToggleFps, // Toggle FPS display (this is temporary) A_LAST // Marker for the last item @@ -90,6 +92,14 @@ namespace MWInput bool mDragDrop; + bool mShiftDown; + bool mCtrlDown; + +public: + bool getShiftDown() { return mShiftDown; } + bool getCtrlDown() { return mCtrlDown; } + +private: /* InputImpl Methods */ @@ -228,7 +238,9 @@ namespace MWInput player(_player), windows(_windows), mEngine (engine), - mDragDrop(false) + mDragDrop(false), + mShiftDown(false), + mCtrlDown(false) { using namespace OEngine::Input; using namespace OEngine::Render; @@ -323,9 +335,11 @@ namespace MWInput poller.bind(A_MoveRight, KC_D); poller.bind(A_MoveForward, KC_W); poller.bind(A_MoveBackward, KC_S); - - poller.bind(A_Jump, KC_E); - poller.bind(A_Crouch, KC_LCONTROL); + + poller.bind(A_Jump, KC_E); + poller.bind(A_Crouch, KC_LCONTROL); + + poller.bind(A_Shift, KC_LSHIFT); } void setDragDrop(bool dragDrop) @@ -347,6 +361,9 @@ namespace MWInput // event callbacks (which may crash) windows.update(); + mShiftDown = poller.isDown(A_Shift); + mCtrlDown = poller.isDown(A_Crouch); + // Disable movement in Gui mode if (windows.isGuiMode()) return; @@ -378,7 +395,7 @@ namespace MWInput else player.setForwardBackward (0); - if (poller.isDown(A_Jump)) + if (poller.isDown(A_Jump)) player.setUpDown (1); else if (poller.isDown(A_Crouch)) player.setUpDown (-1); @@ -445,4 +462,14 @@ namespace MWInput { impl->setDragDrop(dragDrop); } + + bool MWInputManager::getShiftDown() + { + return impl->getShiftDown(); + } + + bool MWInputManager::getCtrlDown() + { + return impl->getCtrlDown(); + } } diff --git a/apps/openmw/mwinput/inputmanager.hpp b/apps/openmw/mwinput/inputmanager.hpp index 158d05f0ee..9e46e59a37 100644 --- a/apps/openmw/mwinput/inputmanager.hpp +++ b/apps/openmw/mwinput/inputmanager.hpp @@ -50,6 +50,9 @@ namespace MWInput void update(); + bool getShiftDown(); + bool getCtrlDown(); + void setDragDrop(bool dragDrop); void setGuiMode(MWGui::GuiMode mode); From 24a0fecd37576cc3045e7cf69011d1f2472b8487 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 15 May 2012 12:51:51 +0200 Subject: [PATCH 150/325] implemented item count selection dialog --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwgui/class.hpp | 2 +- apps/openmw/mwgui/container.cpp | 42 ++++---- apps/openmw/mwgui/container.hpp | 2 + apps/openmw/mwgui/countdialog.cpp | 110 +++++++++++++++++++++ apps/openmw/mwgui/countdialog.hpp | 39 ++++++++ apps/openmw/mwgui/window_manager.cpp | 3 + apps/openmw/mwgui/window_manager.hpp | 3 + files/mygui/CMakeLists.txt | 1 + files/mygui/openmw_count_window_layout.xml | 27 +++++ 10 files changed, 211 insertions(+), 20 deletions(-) create mode 100644 apps/openmw/mwgui/countdialog.cpp create mode 100644 apps/openmw/mwgui/countdialog.hpp create mode 100644 files/mygui/openmw_count_window_layout.xml diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 5ecb2eea80..972c7f2e4c 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -26,7 +26,7 @@ add_openmw_dir (mwgui text_input widgets race class birth review window_manager console dialogue dialogue_history window_base stats_window messagebox journalwindow charactercreation map_window window_pinnable_base cursorreplace tooltips scrollwindow bookwindow list - formatting itemwidget inventorywindow container hud + formatting itemwidget inventorywindow container hud countdialog ) add_openmw_dir (mwdialogue diff --git a/apps/openmw/mwgui/class.hpp b/apps/openmw/mwgui/class.hpp index 0e3348086d..6f0138aa4d 100644 --- a/apps/openmw/mwgui/class.hpp +++ b/apps/openmw/mwgui/class.hpp @@ -34,7 +34,7 @@ namespace MWGui typedef delegates::CMultiDelegate1 EventHandle_Int; /** Event : Button was clicked.\n - signature : void method(MyGUI::WidgetPtr widget, int index)\n + signature : void method(int index)\n */ EventHandle_Int eventButtonSelected; diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 82b695a2b8..afcd398a49 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -1,7 +1,12 @@ #include "container.hpp" -#include "window_manager.hpp" -#include "widgets.hpp" +#include +#include +#include +#include +#include + +#include #include "../mwbase/environment.hpp" #include "../mwworld/manualref.hpp" @@ -13,14 +18,9 @@ #include "../mwinput/inputmanager.hpp" #include "../mwsound/soundmanager.hpp" -#include -#include -#include -#include -#include - -#include - +#include "window_manager.hpp" +#include "widgets.hpp" +#include "countdialog.hpp" using namespace MWGui; using namespace Widgets; @@ -49,7 +49,10 @@ void ContainerBase::onSelectedItem(MyGUI::Widget* _sender) { if(!mDragAndDrop->mIsOnDragAndDrop) { - int count = (*_sender->getUserData()).getRefData().getCount(); + mSelectedItem = _sender; + + MWWorld::Ptr object = (*_sender->getUserData()); + int count = object.getRefData().getCount(); if (MWBase::Environment::get().getInputManager()->getShiftDown() || count == 1) { @@ -61,8 +64,10 @@ void ContainerBase::onSelectedItem(MyGUI::Widget* _sender) } else { - /// \todo count selection window - onSelectedItemImpl(_sender, count); + CountDialog* dialog = MWBase::Environment::get().getWindowManager()->getCountDialog(); + dialog->open(MWWorld::Class::get(object).getName(object), count); + dialog->eventOkClicked.clear(); + dialog->eventOkClicked += MyGUI::newDelegate(this, &ContainerBase::onSelectedItemImpl); } } else @@ -72,10 +77,10 @@ void ContainerBase::onSelectedItem(MyGUI::Widget* _sender) void ContainerBase::onSelectedItemImpl(MyGUI::Widget* _sender, int count) { mDragAndDrop->mIsOnDragAndDrop = true; - _sender->detachFromWidget(); - _sender->attachToWidget(mDragAndDrop->mDragAndDropWidget); + mSelectedItem->detachFromWidget(); + mSelectedItem->attachToWidget(mDragAndDrop->mDragAndDropWidget); - MWWorld::Ptr object = *_sender->getUserData(); + MWWorld::Ptr object = *mSelectedItem->getUserData(); int originalCount = object.getRefData().getCount(); object.getRefData().setCount(count); mDragAndDrop->mStore.add(object); @@ -84,9 +89,10 @@ void ContainerBase::onSelectedItemImpl(MyGUI::Widget* _sender, int count) std::string sound = MWWorld::Class::get(object).getUpSoundId(object); MWBase::Environment::get().getSoundManager()->playSound (sound, 1.0, 1.0); - mDragAndDrop->mDraggedWidget = _sender; + mDragAndDrop->mDraggedWidget = mSelectedItem; mDragAndDrop->mContainerWindow = const_cast(this); - static_cast(_sender->getChildAt(0)->getChildAt(0))->setCaption(getCountString((*mDragAndDrop->mStore.begin()).getRefData().getCount())); + static_cast(mSelectedItem->getChildAt(0)->getChildAt(0))->setCaption( + getCountString((*mDragAndDrop->mStore.begin()).getRefData().getCount())); drawItems(); MWBase::Environment::get().getWindowManager()->setDragDrop(true); diff --git a/apps/openmw/mwgui/container.hpp b/apps/openmw/mwgui/container.hpp index 5cdc8ef1de..20dc16ccaa 100644 --- a/apps/openmw/mwgui/container.hpp +++ b/apps/openmw/mwgui/container.hpp @@ -68,6 +68,8 @@ namespace MWGui MyGUI::ScrollView* mItemView; MyGUI::Widget* mContainerWidget; + MyGUI::Widget* mSelectedItem; + DragAndDrop* mDragAndDrop; MWWorld::Ptr mContainer; diff --git a/apps/openmw/mwgui/countdialog.cpp b/apps/openmw/mwgui/countdialog.cpp new file mode 100644 index 0000000000..dc7e75e0ea --- /dev/null +++ b/apps/openmw/mwgui/countdialog.cpp @@ -0,0 +1,110 @@ +#include "countdialog.hpp" + +#include + +#include "../mwbase/environment.hpp" +#include "../mwworld/world.hpp" + +namespace MWGui +{ + CountDialog::CountDialog(WindowManager& parWindowManager) : + WindowBase("openmw_count_window_layout.xml", parWindowManager) + { + getWidget(mSlider, "CountSlider"); + getWidget(mItemEdit, "ItemEdit"); + getWidget(mItemText, "ItemText"); + getWidget(mLabelText, "LabelText"); + getWidget(mOkButton, "OkButton"); + getWidget(mCancelButton, "CancelButton"); + + mOkButton->setCaption(MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sOk")->str); + mCancelButton->setCaption(MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sCancel")->str); + mLabelText->setCaption(MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sTake")->str); + + mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &CountDialog::onCancelButtonClicked); + mOkButton->eventMouseButtonClick += MyGUI::newDelegate(this, &CountDialog::onOkButtonClicked); + mItemEdit->eventEditTextChange += MyGUI::newDelegate(this, &CountDialog::onEditTextChange); + mSlider->eventScrollChangePosition += MyGUI::newDelegate(this, &CountDialog::onSliderMoved); + } + + void CountDialog::open(const std::string& item, const int maxCount) + { + setVisible(true); + + MyGUI::IntSize viewSize = MyGUI::RenderManager::getInstance().getViewSize(); + + mSlider->setScrollRange(maxCount); + mItemText->setCaption(item); + + int width = std::max(mItemText->getTextSize().width + 128, 320); + setCoord(viewSize.width/2 - width/2, + viewSize.height/2 - mMainWidget->getHeight()/2, + width, + mMainWidget->getHeight()); + + // make other gui elements inaccessible while this dialog is open + MyGUI::InputManager::getInstance().addWidgetModal(mMainWidget); + + MyGUI::InputManager::getInstance().setKeyFocusWidget(mItemEdit); + + mSlider->setScrollPosition(maxCount-1); + mItemEdit->setCaption(boost::lexical_cast(maxCount)); + + int okButtonWidth = mOkButton->getTextSize().width + 24; + mOkButton->setCoord(width - 30 - okButtonWidth, + mOkButton->getTop(), + okButtonWidth, + mOkButton->getHeight()); + + int cancelButtonWidth = mCancelButton->getTextSize().width + 24; + mCancelButton->setCoord(width - 30 - okButtonWidth - cancelButtonWidth - 8, + mCancelButton->getTop(), + cancelButtonWidth, + mCancelButton->getHeight()); + } + + void CountDialog::onCancelButtonClicked(MyGUI::Widget* _sender) + { + close(); + } + + void CountDialog::onOkButtonClicked(MyGUI::Widget* _sender) + { + eventOkClicked(NULL, mSlider->getScrollPosition()+1); + + close(); + } + + void CountDialog::onEditTextChange(MyGUI::EditBox* _sender) + { + if (_sender->getCaption() == "") + return; + + unsigned int count; + try + { + count = boost::lexical_cast(_sender->getCaption()); + } + catch (std::bad_cast&) + { + count = 1; + } + if (count > mSlider->getScrollRange()) + { + count = mSlider->getScrollRange(); + } + mSlider->setScrollPosition(count-1); + onSliderMoved(mSlider, count-1); + } + + void CountDialog::onSliderMoved(MyGUI::ScrollBar* _sender, size_t _position) + { + mItemEdit->setCaption(boost::lexical_cast(_position+1)); + } + + void CountDialog::close() + { + setVisible(false); + MyGUI::InputManager::getInstance().removeWidgetModal(mMainWidget); + } +} diff --git a/apps/openmw/mwgui/countdialog.hpp b/apps/openmw/mwgui/countdialog.hpp new file mode 100644 index 0000000000..b6c836c9dc --- /dev/null +++ b/apps/openmw/mwgui/countdialog.hpp @@ -0,0 +1,39 @@ +#ifndef MWGUI_COUNTDIALOG_H +#define MWGUI_COUNTDIALOG_H + +#include "window_base.hpp" + +namespace MWGui +{ + class CountDialog : public WindowBase + { + public: + CountDialog(WindowManager& parWindowManager); + void open(const std::string& item, const int maxCount); + + typedef MyGUI::delegates::CMultiDelegate2 EventHandle_WidgetInt; + + /** Event : Ok button was clicked.\n + signature : void method(MyGUI::Widget* _sender, int _count)\n + */ + EventHandle_WidgetInt eventOkClicked; + + private: + MyGUI::ScrollBar* mSlider; + MyGUI::EditBox* mItemEdit; + MyGUI::TextBox* mItemText; + MyGUI::TextBox* mLabelText; + MyGUI::Button* mOkButton; + MyGUI::Button* mCancelButton; + + void onCancelButtonClicked(MyGUI::Widget* _sender); + void onOkButtonClicked(MyGUI::Widget* _sender); + void onEditTextChange(MyGUI::EditBox* _sender); + void onSliderMoved(MyGUI::ScrollBar* _sender, size_t _position); + + void close(); + }; + +} + +#endif diff --git a/apps/openmw/mwgui/window_manager.cpp b/apps/openmw/mwgui/window_manager.cpp index c93d5303cf..a068de7d91 100644 --- a/apps/openmw/mwgui/window_manager.cpp +++ b/apps/openmw/mwgui/window_manager.cpp @@ -14,6 +14,7 @@ #include "list.hpp" #include "hud.hpp" #include "mainmenu.hpp" +#include "countdialog.hpp" #include "../mwmechanics/mechanicsmanager.hpp" #include "../mwinput/inputmanager.hpp" @@ -46,6 +47,7 @@ WindowManager::WindowManager( , mDialogueWindow(nullptr) , mBookWindow(NULL) , mScrollWindow(NULL) + , mCountDialog(NULL) , mCharGen(NULL) , playerClass() , playerName() @@ -112,6 +114,7 @@ WindowManager::WindowManager( mToolTips = new ToolTips(this); mScrollWindow = new ScrollWindow(*this); mBookWindow = new BookWindow(*this); + mCountDialog = new CountDialog(*this); // The HUD is always on hud->setVisible(true); diff --git a/apps/openmw/mwgui/window_manager.hpp b/apps/openmw/mwgui/window_manager.hpp index cff93266cb..3f5df5789f 100644 --- a/apps/openmw/mwgui/window_manager.hpp +++ b/apps/openmw/mwgui/window_manager.hpp @@ -71,6 +71,7 @@ namespace MWGui class InfoBoxDialog; class DialogueWindow; class MessageBoxManager; + class CountDialog; struct ClassPoint { @@ -133,6 +134,7 @@ namespace MWGui MWGui::BookWindow* getBookWindow() {return mBookWindow;} MWGui::ScrollWindow* getScrollWindow() {return mScrollWindow;} + MWGui::CountDialog* getCountDialog() {return mCountDialog;} MyGUI::Gui* getGui() const { return gui; } @@ -223,6 +225,7 @@ namespace MWGui InventoryWindow *mInventoryWindow; ScrollWindow* mScrollWindow; BookWindow* mBookWindow; + CountDialog* mCountDialog; CharacterCreation* mCharGen; diff --git a/files/mygui/CMakeLists.txt b/files/mygui/CMakeLists.txt index ae9ddd395a..2ee823d2ae 100644 --- a/files/mygui/CMakeLists.txt +++ b/files/mygui/CMakeLists.txt @@ -55,6 +55,7 @@ configure_file("${SDIR}/openmw_tooltips.xml" "${DDIR}/openmw_tooltips.xml" COPYO configure_file("${SDIR}/openmw_scroll_layout.xml" "${DDIR}/openmw_scroll_layout.xml" COPYONLY) configure_file("${SDIR}/openmw_scroll_skin.xml" "${DDIR}/openmw_scroll_skin.xml" COPYONLY) configure_file("${SDIR}/openmw_book_layout.xml" "${DDIR}/openmw_book_layout.xml" COPYONLY) +configure_file("${SDIR}/openmw_count_window_layout.xml" "${DDIR}/openmw_count_window_layout.xml" COPYONLY) configure_file("${SDIR}/atlas1.cfg" "${DDIR}/atlas1.cfg" COPYONLY) configure_file("${SDIR}/smallbars.png" "${DDIR}/smallbars.png" COPYONLY) configure_file("${SDIR}/transparent.png" "${DDIR}/transparent.png" COPYONLY) diff --git a/files/mygui/openmw_count_window_layout.xml b/files/mygui/openmw_count_window_layout.xml new file mode 100644 index 0000000000..38ba7644f6 --- /dev/null +++ b/files/mygui/openmw_count_window_layout.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + From 7fbee0d488383d7e7aeddd1c46a0a7b436768ccd Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 15 May 2012 13:00:26 +0200 Subject: [PATCH 151/325] use MyGUI::InputManager instead of MWInputManager to detect ctrl/shift --- apps/openmw/mwgui/container.cpp | 6 ++---- apps/openmw/mwgui/container.hpp | 1 - apps/openmw/mwgui/hud.cpp | 1 - apps/openmw/mwgui/window_manager.cpp | 1 - apps/openmw/mwinput/inputmanager.cpp | 29 +--------------------------- apps/openmw/mwinput/inputmanager.hpp | 3 --- 6 files changed, 3 insertions(+), 38 deletions(-) diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index afcd398a49..d926346d3a 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -54,11 +54,11 @@ void ContainerBase::onSelectedItem(MyGUI::Widget* _sender) MWWorld::Ptr object = (*_sender->getUserData()); int count = object.getRefData().getCount(); - if (MWBase::Environment::get().getInputManager()->getShiftDown() || count == 1) + if (MyGUI::InputManager::getInstance().isShiftPressed() || count == 1) { onSelectedItemImpl(_sender, count); } - else if (MWBase::Environment::get().getInputManager()->getCtrlDown()) + else if (MyGUI::InputManager::getInstance().isControlPressed()) { onSelectedItemImpl(_sender, 1); } @@ -90,7 +90,6 @@ void ContainerBase::onSelectedItemImpl(MyGUI::Widget* _sender, int count) MWBase::Environment::get().getSoundManager()->playSound (sound, 1.0, 1.0); mDragAndDrop->mDraggedWidget = mSelectedItem; - mDragAndDrop->mContainerWindow = const_cast(this); static_cast(mSelectedItem->getChildAt(0)->getChildAt(0))->setCaption( getCountString((*mDragAndDrop->mStore.begin()).getRefData().getCount())); drawItems(); @@ -115,7 +114,6 @@ void ContainerBase::onContainerClicked(MyGUI::Widget* _sender) mDragAndDrop->mDraggedWidget->detachFromWidget(); mDragAndDrop->mDraggedWidget->attachToWidget(mContainerWidget); mDragAndDrop->mDraggedWidget = 0; - mDragAndDrop->mContainerWindow = 0; drawItems(); MWBase::Environment::get().getWindowManager()->setDragDrop(false); diff --git a/apps/openmw/mwgui/container.hpp b/apps/openmw/mwgui/container.hpp index 20dc16ccaa..b90044ab5f 100644 --- a/apps/openmw/mwgui/container.hpp +++ b/apps/openmw/mwgui/container.hpp @@ -37,7 +37,6 @@ namespace MWGui { public: bool mIsOnDragAndDrop; - ContainerBase* mContainerWindow; MyGUI::Widget* mDraggedWidget; MyGUI::Widget* mDragAndDropWidget; MWWorld::ContainerStore mStore; diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index 80c02cd82f..482047b9bb 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -279,7 +279,6 @@ void HUD::onWorldClicked(MyGUI::Widget* _sender) mDragAndDrop->mIsOnDragAndDrop = false; MyGUI::Gui::getInstance().destroyWidget(mDragAndDrop->mDraggedWidget); mDragAndDrop->mDraggedWidget = 0; - mDragAndDrop->mContainerWindow = 0; MWBase::Environment::get().getWindowManager()->setDragDrop(false); } diff --git a/apps/openmw/mwgui/window_manager.cpp b/apps/openmw/mwgui/window_manager.cpp index a068de7d91..8624699cda 100644 --- a/apps/openmw/mwgui/window_manager.cpp +++ b/apps/openmw/mwgui/window_manager.cpp @@ -99,7 +99,6 @@ WindowManager::WindowManager( mDragAndDrop->mIsOnDragAndDrop = false; mDragAndDrop->mDraggedWidget = 0; mDragAndDrop->mDragAndDropWidget = dragAndDropWidget; - mDragAndDrop->mContainerWindow = 0; menu = new MainMenu(w,h); map = new MapWindow(*this); diff --git a/apps/openmw/mwinput/inputmanager.cpp b/apps/openmw/mwinput/inputmanager.cpp index 787f12f252..8f8f1e1ee2 100644 --- a/apps/openmw/mwinput/inputmanager.cpp +++ b/apps/openmw/mwinput/inputmanager.cpp @@ -69,8 +69,6 @@ namespace MWInput A_ToggleWeapon, A_ToggleSpell, - A_Shift, - A_ToggleFps, // Toggle FPS display (this is temporary) A_LAST // Marker for the last item @@ -92,14 +90,6 @@ namespace MWInput bool mDragDrop; - bool mShiftDown; - bool mCtrlDown; - -public: - bool getShiftDown() { return mShiftDown; } - bool getCtrlDown() { return mCtrlDown; } - -private: /* InputImpl Methods */ @@ -238,9 +228,7 @@ private: player(_player), windows(_windows), mEngine (engine), - mDragDrop(false), - mShiftDown(false), - mCtrlDown(false) + mDragDrop(false) { using namespace OEngine::Input; using namespace OEngine::Render; @@ -338,8 +326,6 @@ private: poller.bind(A_Jump, KC_E); poller.bind(A_Crouch, KC_LCONTROL); - - poller.bind(A_Shift, KC_LSHIFT); } void setDragDrop(bool dragDrop) @@ -361,9 +347,6 @@ private: // event callbacks (which may crash) windows.update(); - mShiftDown = poller.isDown(A_Shift); - mCtrlDown = poller.isDown(A_Crouch); - // Disable movement in Gui mode if (windows.isGuiMode()) return; @@ -462,14 +445,4 @@ private: { impl->setDragDrop(dragDrop); } - - bool MWInputManager::getShiftDown() - { - return impl->getShiftDown(); - } - - bool MWInputManager::getCtrlDown() - { - return impl->getCtrlDown(); - } } diff --git a/apps/openmw/mwinput/inputmanager.hpp b/apps/openmw/mwinput/inputmanager.hpp index 9e46e59a37..158d05f0ee 100644 --- a/apps/openmw/mwinput/inputmanager.hpp +++ b/apps/openmw/mwinput/inputmanager.hpp @@ -50,9 +50,6 @@ namespace MWInput void update(); - bool getShiftDown(); - bool getCtrlDown(); - void setDragDrop(bool dragDrop); void setGuiMode(MWGui::GuiMode mode); From b18ee198b4b882879a9722d8e93630dca379f94b Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 15 May 2012 16:47:23 +0200 Subject: [PATCH 152/325] use a raycast to determine where to place object, if distance is too far drop it on the ground --- apps/openmw/mwgui/container.cpp | 2 +- apps/openmw/mwgui/hud.cpp | 47 +++++++++++++++++++----- apps/openmw/mwgui/hud.hpp | 1 + apps/openmw/mwgui/window_manager.cpp | 1 - apps/openmw/mwworld/physicssystem.cpp | 25 ++++++++++++- apps/openmw/mwworld/physicssystem.hpp | 3 ++ apps/openmw/mwworld/world.cpp | 52 +++++++++++++++++++++++++-- apps/openmw/mwworld/world.hpp | 14 ++++++-- files/mygui/openmw.pointer.xml | 5 +++ files/mygui/openmw_layers.xml | 3 +- files/mygui/openmw_resources.xml | 7 ++++ 11 files changed, 142 insertions(+), 18 deletions(-) diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index d926346d3a..bab0051b81 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -244,7 +244,7 @@ void ContainerBase::Update() if(mDragAndDrop->mIsOnDragAndDrop) { if(mDragAndDrop->mDraggedWidget) - mDragAndDrop->mDraggedWidget->setPosition(MyGUI::InputManager::getInstance().getMousePosition() - MyGUI::IntPoint(21, 21)); + mDragAndDrop->mDraggedWidget->setPosition(MyGUI::InputManager::getInstance().getMousePosition()); else mDragAndDrop->mIsOnDragAndDrop = false; //If this happens, there is a bug. } } diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index 482047b9bb..b992764401 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -91,6 +91,7 @@ HUD::HUD(int width, int height, int fpsLevel, DragAndDrop* dragAndDrop) LocalMapBase::init(minimap, this); mMainWidget->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onWorldClicked); + mMainWidget->eventMouseMove += MyGUI::newDelegate(this, &HUD::onWorldMouseOver); } void HUD::setFpsLevel(int level) @@ -261,16 +262,19 @@ void HUD::onWorldClicked(MyGUI::Widget* _sender) // drop item into the gameworld MWWorld::Ptr object = *mDragAndDrop->mStore.begin(); - float* playerPos; - playerPos = MWBase::Environment::get().getWorld()->getPlayer().getPlayer().getRefData().getPosition().pos; - MWWorld::Ptr::CellStore* cell = MWBase::Environment::get().getWorld()->getPlayer().getPlayer().getCell(); /// \todo this might be a different cell + MWWorld::World* world = MWBase::Environment::get().getWorld(); - ESM::Position& pos = object.getRefData().getPosition(); - pos.pos[0] = playerPos[0]; - pos.pos[1] = playerPos[1]; - pos.pos[2] = playerPos[2]; + MyGUI::IntSize viewSize = MyGUI::RenderManager::getInstance().getViewSize(); + MyGUI::IntPoint cursorPosition = MyGUI::InputManager::getInstance().getMousePosition(); + float mouseX = cursorPosition.left / float(viewSize.width); + float mouseY = cursorPosition.top / float(viewSize.height); - MWBase::Environment::get().getWorld()->insertObject(object, cell); + if (world->canPlaceObject(mouseX, mouseY)) + world->placeObject(object, mouseX, mouseY); + else + world->dropObjectOnGround(object); + + MyGUI::PointerManager::getInstance().setPointer("arrow"); std::string sound = MWWorld::Class::get(object).getDownSoundId(object); MWBase::Environment::get().getSoundManager()->playSound (sound, 1.0, 1.0); @@ -284,3 +288,30 @@ void HUD::onWorldClicked(MyGUI::Widget* _sender) } } +void HUD::onWorldMouseOver(MyGUI::Widget* _sender, int x, int y) +{ + if (mDragAndDrop->mIsOnDragAndDrop) + { + MyGUI::IntSize viewSize = MyGUI::RenderManager::getInstance().getViewSize(); + MyGUI::IntPoint cursorPosition = MyGUI::InputManager::getInstance().getMousePosition(); + float mouseX = cursorPosition.left / float(viewSize.width); + float mouseY = cursorPosition.top / float(viewSize.height); + + MWWorld::World* world = MWBase::Environment::get().getWorld(); + + // if we can't drop the object at the wanted position, show the "drop on ground" cursor. + bool canDrop = world->canPlaceObject(mouseX, mouseY); + + if (!canDrop) + MyGUI::PointerManager::getInstance().setPointer("drop_ground"); + else + MyGUI::PointerManager::getInstance().setPointer("arrow"); + + } + else + { + MyGUI::PointerManager::getInstance().setPointer("arrow"); + /// \todo make it possible to pick up objects with the mouse, if inventory or container window is open + } +} + diff --git a/apps/openmw/mwgui/hud.hpp b/apps/openmw/mwgui/hud.hpp index 22b1b87385..cccfb0541c 100644 --- a/apps/openmw/mwgui/hud.hpp +++ b/apps/openmw/mwgui/hud.hpp @@ -52,5 +52,6 @@ namespace MWGui DragAndDrop* mDragAndDrop; void onWorldClicked(MyGUI::Widget* _sender); + void onWorldMouseOver(MyGUI::Widget* _sender, int x, int y); }; } diff --git a/apps/openmw/mwgui/window_manager.cpp b/apps/openmw/mwgui/window_manager.cpp index 8624699cda..a4788ad3b0 100644 --- a/apps/openmw/mwgui/window_manager.cpp +++ b/apps/openmw/mwgui/window_manager.cpp @@ -576,5 +576,4 @@ void WindowManager::setDragDrop(bool dragDrop) { mToolTips->setEnabled(!dragDrop); MWBase::Environment::get().getInputManager()->setDragDrop(dragDrop); - setMouseVisible(!dragDrop); } diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index fb13e37c6a..808c712a07 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -80,7 +80,7 @@ namespace MWWorld Ray centerRay = mRender.getCamera()->getCameraToViewportRay( mRender.getViewport()->getWidth()/2, mRender.getViewport()->getHeight()/2); - btVector3 result(centerRay.getPoint(500*extent).x,-centerRay.getPoint(500*extent).z,centerRay.getPoint(500*extent).y); + btVector3 result(centerRay.getPoint(500*extent).x,-centerRay.getPoint(500*extent).z,centerRay.getPoint(500*extent).y); /// \todo make this distance (ray length) configurable return result; } @@ -95,6 +95,29 @@ namespace MWWorld return !(result.first == ""); } + std::pair PhysicsSystem::castRay(float mouseX, float mouseY) + { + Ogre::Ray ray = mRender.getCamera()->getCameraToViewportRay( + mouseX, + mouseY); + Ogre::Vector3 from = ray.getOrigin(); + Ogre::Vector3 to = ray.getPoint(200); /// \todo make this distance (ray length) configurable + + btVector3 _from, _to; + // OGRE to MW coordinates + _from = btVector3(from.x, -from.z, from.y); + _to = btVector3(to.x, -to.z, to.y); + + std::pair result = mEngine->rayTest(_from, _to); + + if (result.first == "") + return std::make_pair(false, Ogre::Vector3()); + else + { + return std::make_pair(true, ray.getPoint(200*result.second)); /// \todo make this distance (ray length) configurable + } + } + void PhysicsSystem::doPhysics(float dt, const std::vector >& actors) { //set the DebugRenderingMode. To disable it,set it to 0 diff --git a/apps/openmw/mwworld/physicssystem.hpp b/apps/openmw/mwworld/physicssystem.hpp index 1af6bcca2f..9b03d2124f 100644 --- a/apps/openmw/mwworld/physicssystem.hpp +++ b/apps/openmw/mwworld/physicssystem.hpp @@ -53,6 +53,9 @@ namespace MWWorld // cast ray, return true if it hit something bool castRay(const Ogre::Vector3& from, const Ogre::Vector3& to); + std::pair castRay(float mouseX, float mouseY); + ///< cast ray from the mouse, return true if it hit something and the first result (in OGRE coordinates) + void insertObjectPhysics(const MWWorld::Ptr& ptr, std::string model); void insertActorPhysics(const MWWorld::Ptr&, std::string model); diff --git a/apps/openmw/mwworld/world.cpp b/apps/openmw/mwworld/world.cpp index 0474d894c5..973407b0c6 100644 --- a/apps/openmw/mwworld/world.cpp +++ b/apps/openmw/mwworld/world.cpp @@ -965,9 +965,57 @@ namespace MWWorld mRendering->toggleWater(); } - void World::insertObject(MWWorld::Ptr ptr, Ptr::CellStore* cell) + bool World::placeObject(MWWorld::Ptr object, float cursorX, float cursorY) { - mWorldScene->insertObject(ptr, cell); + std::pair result = mPhysics->castRay(cursorX, cursorY); + + if (!result.first) + return false; + + MWWorld::Ptr::CellStore* cell; + if (isCellExterior()) + { + int cellX, cellY; + positionToIndex(result.second[0], -result.second[2], cellX, cellY); + cell = mCells.getExterior(cellX, cellY); + } + else + cell = getPlayer().getPlayer().getCell(); + + ESM::Position& pos = object.getRefData().getPosition(); + pos.pos[0] = result.second[0]; + pos.pos[1] = -result.second[2]; + pos.pos[2] = result.second[1]; + + mWorldScene->insertObject(object, cell); + + /// \todo retrieve the bounds of the object and translate it accordingly + + return true; } + bool World::canPlaceObject(float cursorX, float cursorY) + { + std::pair result = mPhysics->castRay(cursorX, cursorY); + + /// \todo also check if the wanted position is on a flat surface, and not e.g. against a vertical wall! + + if (!result.first) + return false; + return true; + } + + void World::dropObjectOnGround(MWWorld::Ptr object) + { + MWWorld::Ptr::CellStore* cell = getPlayer().getPlayer().getCell(); + + float* playerPos = getPlayer().getPlayer().getRefData().getPosition().pos; + + ESM::Position& pos = object.getRefData().getPosition(); + pos.pos[0] = playerPos[0]; + pos.pos[1] = playerPos[1]; + pos.pos[2] = playerPos[2]; + + mWorldScene->insertObject(object, cell); + } } diff --git a/apps/openmw/mwworld/world.hpp b/apps/openmw/mwworld/world.hpp index 3b56dea970..1ed6a976ed 100644 --- a/apps/openmw/mwworld/world.hpp +++ b/apps/openmw/mwworld/world.hpp @@ -263,9 +263,17 @@ namespace MWWorld void update (float duration); - void insertObject (MWWorld::Ptr ptr, Ptr::CellStore* cell); - ///< insert object in a given cell - /// \note this method is only meant for dropping items into the gameworld from a container + bool placeObject(MWWorld::Ptr object, float cursorX, float cursorY); + ///< place an object into the gameworld at the specified cursor position + /// @param object + /// @param cursor X (relative 0-1) + /// @param cursor Y (relative 0-1) + /// @return true if the object was placed, or false if it was rejected because the position is too far away + + void dropObjectOnGround(MWWorld::Ptr object); + + bool canPlaceObject(float cursorX, float cursorY); + ///< @return true if it is possible to place on object at specified cursor location }; } diff --git a/files/mygui/openmw.pointer.xml b/files/mygui/openmw.pointer.xml index 0fbef2fdf5..42ee5d4351 100644 --- a/files/mygui/openmw.pointer.xml +++ b/files/mygui/openmw.pointer.xml @@ -26,4 +26,9 @@ + + + + + diff --git a/files/mygui/openmw_layers.xml b/files/mygui/openmw_layers.xml index 81cd99fead..a5044fb78e 100644 --- a/files/mygui/openmw_layers.xml +++ b/files/mygui/openmw_layers.xml @@ -8,7 +8,6 @@ + - - diff --git a/files/mygui/openmw_resources.xml b/files/mygui/openmw_resources.xml index b2bd90d105..4c509ae13d 100644 --- a/files/mygui/openmw_resources.xml +++ b/files/mygui/openmw_resources.xml @@ -36,6 +36,13 @@ + + + + + + + From ab6336b745ca83e96cecb81185ec8912fcf37661 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 15 May 2012 18:05:53 +0200 Subject: [PATCH 153/325] using items via the inventory is now possible by dragging them on the avatar (only implemented for books right now) --- apps/openmw/engine.cpp | 18 +------- apps/openmw/mwclass/book.cpp | 6 +++ apps/openmw/mwclass/book.hpp | 3 ++ apps/openmw/mwgui/bookwindow.cpp | 14 ++++-- apps/openmw/mwgui/bookwindow.hpp | 2 + apps/openmw/mwgui/container.cpp | 7 +-- apps/openmw/mwgui/container.hpp | 8 ++++ apps/openmw/mwgui/inventorywindow.cpp | 62 +++++++++++++++++++++++---- apps/openmw/mwgui/inventorywindow.hpp | 3 ++ apps/openmw/mwgui/scrollwindow.cpp | 14 ++++-- apps/openmw/mwgui/scrollwindow.hpp | 2 + apps/openmw/mwworld/actiontake.cpp | 5 ++- apps/openmw/mwworld/ptr.hpp | 5 +++ apps/openmw/mwworld/world.cpp | 27 ++++++++++++ apps/openmw/mwworld/world.hpp | 3 ++ 15 files changed, 144 insertions(+), 35 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 85b0557b1a..a9e7c82b08 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -437,25 +437,11 @@ void OMW::Engine::activate() return; } - MWScript::InterpreterContext interpreterContext (&ptr.getRefData().getLocals(), ptr); - boost::shared_ptr action = MWWorld::Class::get (ptr).activate (ptr, MWBase::Environment::get().getWorld()->getPlayer().getPlayer()); - interpreterContext.activate (ptr, action); - - std::string script = MWWorld::Class::get (ptr).getScript (ptr); - - if (!script.empty()) - { - MWBase::Environment::get().getWorld()->getLocalScripts().setIgnore (ptr); - MWBase::Environment::get().getScriptManager()->run (script, interpreterContext); - } - - if (!interpreterContext.hasActivationBeenHandled()) - { - interpreterContext.executeActivation(); - } + // execute action and script + MWBase::Environment::get().getWorld()->executeActionScript(ptr, action); } void OMW::Engine::screenshot() diff --git a/apps/openmw/mwclass/book.cpp b/apps/openmw/mwclass/book.cpp index f58eac7ecb..a107d9b210 100644 --- a/apps/openmw/mwclass/book.cpp +++ b/apps/openmw/mwclass/book.cpp @@ -148,4 +148,10 @@ namespace MWClass return ref->base->enchant; } + + boost::shared_ptr Book::use (const MWWorld::Ptr& ptr) const + { + return boost::shared_ptr(new MWWorld::ActionRead(ptr)); + } + } diff --git a/apps/openmw/mwclass/book.hpp b/apps/openmw/mwclass/book.hpp index 6858bac7f5..ee3aac8d81 100644 --- a/apps/openmw/mwclass/book.hpp +++ b/apps/openmw/mwclass/book.hpp @@ -47,6 +47,9 @@ namespace MWClass virtual std::string getEnchantment (const MWWorld::Ptr& ptr) const; ///< @return the enchantment ID if the object is enchanted, otherwise an empty string + + virtual boost::shared_ptr use (const MWWorld::Ptr& ptr) const; + ///< Generate action for using via inventory menu }; } diff --git a/apps/openmw/mwgui/bookwindow.cpp b/apps/openmw/mwgui/bookwindow.cpp index 8de45984cd..c6411175d1 100644 --- a/apps/openmw/mwgui/bookwindow.cpp +++ b/apps/openmw/mwgui/bookwindow.cpp @@ -52,7 +52,7 @@ void BookWindow::open (MWWorld::Ptr book) clearPages(); mCurrentPage = 0; - MWBase::Environment::get().getSoundManager()->playSound3D (book, "book open", 1.0, 1.0); + MWBase::Environment::get().getSoundManager()->playSound ("book open", 1.0, 1.0); ESMS::LiveCellRef *ref = mBook.get(); @@ -77,18 +77,26 @@ void BookWindow::open (MWWorld::Ptr book) } updatePages(); + + setTakeButtonShow(true); +} + +void BookWindow::setTakeButtonShow(bool show) +{ + mTakeButton->setVisible(show); } void BookWindow::onCloseButtonClicked (MyGUI::Widget* _sender) { - MWBase::Environment::get().getSoundManager()->playSound3D (mBook, "book close", 1.0, 1.0); + // no 3d sounds because the object could be in a container. + MWBase::Environment::get().getSoundManager()->playSound ("book close", 1.0, 1.0); MWBase::Environment::get().getInputManager()->setGuiMode(MWGui::GM_Game); } void BookWindow::onTakeButtonClicked (MyGUI::Widget* _sender) { - MWBase::Environment::get().getSoundManager()->playSound3D (mBook, "Item Book Up", 1.0, 1.0, MWSound::Play_NoTrack); + MWBase::Environment::get().getSoundManager()->playSound ("Item Book Up", 1.0, 1.0, MWSound::Play_NoTrack); MWWorld::ActionTake take(mBook); take.execute(); diff --git a/apps/openmw/mwgui/bookwindow.hpp b/apps/openmw/mwgui/bookwindow.hpp index fcea1d11f2..9ea0114338 100644 --- a/apps/openmw/mwgui/bookwindow.hpp +++ b/apps/openmw/mwgui/bookwindow.hpp @@ -11,7 +11,9 @@ namespace MWGui { public: BookWindow(WindowManager& parWindowManager); + void open(MWWorld::Ptr book); + void setTakeButtonShow(bool show); protected: void onNextPageButtonClicked (MyGUI::Widget* _sender); diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index bab0051b81..ff7bb889e2 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -92,6 +92,9 @@ void ContainerBase::onSelectedItemImpl(MyGUI::Widget* _sender, int count) mDragAndDrop->mDraggedWidget = mSelectedItem; static_cast(mSelectedItem->getChildAt(0)->getChildAt(0))->setCaption( getCountString((*mDragAndDrop->mStore.begin()).getRefData().getCount())); + + mDragAndDrop->mWasInInventory = isInventory(); + drawItems(); MWBase::Environment::get().getWindowManager()->setDragDrop(true); @@ -111,9 +114,7 @@ void ContainerBase::onContainerClicked(MyGUI::Widget* _sender) containerStore.add(*mDragAndDrop->mStore.begin()); mDragAndDrop->mStore.clear(); mDragAndDrop->mIsOnDragAndDrop = false; - mDragAndDrop->mDraggedWidget->detachFromWidget(); - mDragAndDrop->mDraggedWidget->attachToWidget(mContainerWidget); - mDragAndDrop->mDraggedWidget = 0; + MyGUI::Gui::getInstance().destroyWidget(mDragAndDrop->mDraggedWidget); drawItems(); MWBase::Environment::get().getWindowManager()->setDragDrop(false); diff --git a/apps/openmw/mwgui/container.hpp b/apps/openmw/mwgui/container.hpp index b90044ab5f..8a1307967a 100644 --- a/apps/openmw/mwgui/container.hpp +++ b/apps/openmw/mwgui/container.hpp @@ -36,10 +36,16 @@ namespace MWGui class DragAndDrop { public: + DragAndDrop() : + mWasInInventory(false) + { + } + bool mIsOnDragAndDrop; MyGUI::Widget* mDraggedWidget; MyGUI::Widget* mDragAndDropWidget; MWWorld::ContainerStore mStore; + bool mWasInInventory; // was the item in inventory before it was dragged }; class ContainerBase @@ -81,6 +87,8 @@ namespace MWGui std::string getCountString(const int count); + virtual bool isInventory() { return false; } + void drawItems(); }; diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 23e4949f78..e9c3af7d47 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -1,23 +1,33 @@ #include "inventorywindow.hpp" -#include -#include -#include "window_manager.hpp" -#include "widgets.hpp" -#include "../mwbase/environment.hpp" -#include "../mwworld/manualref.hpp" #include #include #include - #include #include + +#include + #include "../mwclass/container.hpp" #include "../mwworld/containerstore.hpp" -#include #include "../mwworld/class.hpp" #include "../mwworld/world.hpp" #include "../mwworld/player.hpp" +#include "../mwbase/environment.hpp" +#include "../mwworld/manualref.hpp" + +#include "../mwscript/scriptmanager.hpp" +#include "../mwscript/compilercontext.hpp" +#include "../mwscript/interpretercontext.hpp" +#include "../mwscript/extensions.hpp" +#include "../mwscript/globalscripts.hpp" + + +#include "window_manager.hpp" +#include "widgets.hpp" +#include "bookwindow.hpp" +#include "scrollwindow.hpp" + namespace MWGui { @@ -38,6 +48,8 @@ namespace MWGui getWidget(mLeftPane, "LeftPane"); getWidget(mRightPane, "RightPane"); + mAvatar->eventMouseButtonClick += MyGUI::newDelegate(this, &InventoryWindow::onAvatarClicked); + MyGUI::ScrollView* itemView; MyGUI::Widget* containerWidget; getWidget(containerWidget, "Items"); @@ -126,4 +138,38 @@ namespace MWGui mWindowManager.setWeaponVisibility(!mPinned); } + void InventoryWindow::onAvatarClicked(MyGUI::Widget* _sender) + { + if (mDragAndDrop->mIsOnDragAndDrop) + { + MWWorld::Ptr ptr = *mDragAndDrop->mStore.begin(); + + boost::shared_ptr action = MWWorld::Class::get(ptr).use(ptr); + + // execute action and script + MWBase::Environment::get().getWorld()->executeActionScript(ptr, action); + + // this is necessary for books/scrolls: if they are already in the player's inventory, + // the "Take" button should not be visible. + // NOTE: the take button is "reset" when the window opens, so we can safely do the following + // without screwing up future book windows + if (mDragAndDrop->mWasInInventory) + { + mWindowManager.getBookWindow()->setTakeButtonShow(false); + mWindowManager.getScrollWindow()->setTakeButtonShow(false); + } + + // put back in inventory + MWWorld::ContainerStore& containerStore = MWWorld::Class::get(mContainer).getContainerStore(mContainer); + containerStore.add(ptr); + drawItems(); + + mDragAndDrop->mStore.clear(); + mDragAndDrop->mIsOnDragAndDrop = false; + MyGUI::Gui::getInstance().destroyWidget(mDragAndDrop->mDraggedWidget); + + mWindowManager.setDragDrop(false); + } + } + } diff --git a/apps/openmw/mwgui/inventorywindow.hpp b/apps/openmw/mwgui/inventorywindow.hpp index f16dcf4331..b09ff8521a 100644 --- a/apps/openmw/mwgui/inventorywindow.hpp +++ b/apps/openmw/mwgui/inventorywindow.hpp @@ -47,7 +47,10 @@ namespace MWGui void onWindowResize(MyGUI::Window* _sender); void onFilterChanged(MyGUI::Widget* _sender); + void onAvatarClicked(MyGUI::Widget* _sender); void onPinToggled(); + + virtual bool isInventory() { return true; } }; } #endif // Inventory_H diff --git a/apps/openmw/mwgui/scrollwindow.cpp b/apps/openmw/mwgui/scrollwindow.cpp index 38e2f77c17..877864cfed 100644 --- a/apps/openmw/mwgui/scrollwindow.cpp +++ b/apps/openmw/mwgui/scrollwindow.cpp @@ -25,7 +25,8 @@ ScrollWindow::ScrollWindow (WindowManager& parWindowManager) : void ScrollWindow::open (MWWorld::Ptr scroll) { - MWBase::Environment::get().getSoundManager()->playSound3D (scroll, "scroll", 1.0, 1.0); + // no 3d sounds because the object could be in a container. + MWBase::Environment::get().getSoundManager()->playSound ("scroll", 1.0, 1.0); mScroll = scroll; @@ -41,18 +42,25 @@ void ScrollWindow::open (MWWorld::Ptr scroll) mTextView->setCanvasSize(410, mTextView->getSize().height); mTextView->setViewOffset(MyGUI::IntPoint(0,0)); + + setTakeButtonShow(true); +} + +void ScrollWindow::setTakeButtonShow(bool show) +{ + mTakeButton->setVisible(show); } void ScrollWindow::onCloseButtonClicked (MyGUI::Widget* _sender) { - MWBase::Environment::get().getSoundManager()->playSound3D (mScroll, "scroll", 1.0, 1.0); + MWBase::Environment::get().getSoundManager()->playSound ("scroll", 1.0, 1.0); MWBase::Environment::get().getInputManager()->setGuiMode (GM_Game); } void ScrollWindow::onTakeButtonClicked (MyGUI::Widget* _sender) { - MWBase::Environment::get().getSoundManager()->playSound3D (mScroll, "Item Book Up", 1.0, 1.0, MWSound::Play_NoTrack); + MWBase::Environment::get().getSoundManager()->playSound ("Item Book Up", 1.0, 1.0, MWSound::Play_NoTrack); MWWorld::ActionTake take(mScroll); take.execute(); diff --git a/apps/openmw/mwgui/scrollwindow.hpp b/apps/openmw/mwgui/scrollwindow.hpp index 918a3d3ef0..d58596b4be 100644 --- a/apps/openmw/mwgui/scrollwindow.hpp +++ b/apps/openmw/mwgui/scrollwindow.hpp @@ -11,7 +11,9 @@ namespace MWGui { public: ScrollWindow (WindowManager& parWindowManager); + void open (MWWorld::Ptr scroll); + void setTakeButtonShow(bool show); protected: void onCloseButtonClicked (MyGUI::Widget* _sender); diff --git a/apps/openmw/mwworld/actiontake.cpp b/apps/openmw/mwworld/actiontake.cpp index b1e2e1fc3d..384cb3ffe1 100644 --- a/apps/openmw/mwworld/actiontake.cpp +++ b/apps/openmw/mwworld/actiontake.cpp @@ -18,7 +18,8 @@ namespace MWWorld MWWorld::Class::get (player).getContainerStore (player).add (mObject); - // remove from world - MWBase::Environment::get().getWorld()->deleteObject (mObject); + // remove from world, if the item is currently in the world (it could also be in a container) + if (mObject.isInCell()) + MWBase::Environment::get().getWorld()->deleteObject (mObject); } } diff --git a/apps/openmw/mwworld/ptr.hpp b/apps/openmw/mwworld/ptr.hpp index d6e485f419..4cf3e98da4 100644 --- a/apps/openmw/mwworld/ptr.hpp +++ b/apps/openmw/mwworld/ptr.hpp @@ -77,6 +77,11 @@ namespace MWWorld return mCell; } + bool isInCell() const + { + return (mCell != 0); + } + void setContainerStore (ContainerStore *store); ///< Must not be called on references that are in a cell. diff --git a/apps/openmw/mwworld/world.cpp b/apps/openmw/mwworld/world.cpp index 973407b0c6..ce78212806 100644 --- a/apps/openmw/mwworld/world.cpp +++ b/apps/openmw/mwworld/world.cpp @@ -17,6 +17,13 @@ #include "../mwgui/window_manager.hpp" +#include "../mwscript/scriptmanager.hpp" +#include "../mwscript/compilercontext.hpp" +#include "../mwscript/interpretercontext.hpp" +#include "../mwscript/extensions.hpp" +#include "../mwscript/globalscripts.hpp" + + #include "ptr.hpp" #include "class.hpp" #include "player.hpp" @@ -1018,4 +1025,24 @@ namespace MWWorld mWorldScene->insertObject(object, cell); } + + void World::executeActionScript(MWWorld::Ptr ptr, boost::shared_ptr action) + { + MWScript::InterpreterContext interpreterContext (&ptr.getRefData().getLocals(), ptr); + + action->execute(); + + // execute script + interpreterContext.activate (ptr, action); + std::string script = MWWorld::Class::get (ptr).getScript (ptr); + if (!script.empty()) + { + getLocalScripts().setIgnore (ptr); + MWBase::Environment::get().getScriptManager()->run (script, interpreterContext); + } + if (!interpreterContext.hasActivationBeenHandled()) + { + interpreterContext.executeActivation(); + } + } } diff --git a/apps/openmw/mwworld/world.hpp b/apps/openmw/mwworld/world.hpp index 1ed6a976ed..c1d4ace206 100644 --- a/apps/openmw/mwworld/world.hpp +++ b/apps/openmw/mwworld/world.hpp @@ -274,6 +274,9 @@ namespace MWWorld bool canPlaceObject(float cursorX, float cursorY); ///< @return true if it is possible to place on object at specified cursor location + + void executeActionScript(MWWorld::Ptr ptr, boost::shared_ptr action); + ///< execute the activation script of an object (when activating the object with space, or when activating it via the inventory) }; } From 765881a61d8b770ff2509f287953198b6dafb721 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 15 May 2012 18:20:32 +0200 Subject: [PATCH 154/325] equipping items in the inventorywindow (there is no visual indication yet) --- apps/openmw/mwgui/inventorywindow.cpp | 55 +++++++++++++++++++-------- 1 file changed, 40 insertions(+), 15 deletions(-) diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index e9c3af7d47..956961b63f 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -144,24 +144,49 @@ namespace MWGui { MWWorld::Ptr ptr = *mDragAndDrop->mStore.begin(); - boost::shared_ptr action = MWWorld::Class::get(ptr).use(ptr); - - // execute action and script - MWBase::Environment::get().getWorld()->executeActionScript(ptr, action); - - // this is necessary for books/scrolls: if they are already in the player's inventory, - // the "Take" button should not be visible. - // NOTE: the take button is "reset" when the window opens, so we can safely do the following - // without screwing up future book windows - if (mDragAndDrop->mWasInInventory) + // can the object be equipped? + std::pair, bool> slots = MWWorld::Class::get(ptr).getEquipmentSlots(ptr); + if (slots.first.empty()) { - mWindowManager.getBookWindow()->setTakeButtonShow(false); - mWindowManager.getScrollWindow()->setTakeButtonShow(false); + // can't be equipped, try to use instead + boost::shared_ptr action = MWWorld::Class::get(ptr).use(ptr); + + // execute action and script + MWBase::Environment::get().getWorld()->executeActionScript(ptr, action); + + // this is necessary for books/scrolls: if they are already in the player's inventory, + // the "Take" button should not be visible. + // NOTE: the take button is "reset" when the window opens, so we can safely do the following + // without screwing up future book windows + if (mDragAndDrop->mWasInInventory) + { + mWindowManager.getBookWindow()->setTakeButtonShow(false); + mWindowManager.getScrollWindow()->setTakeButtonShow(false); + } + + // put back in inventory + MWWorld::ContainerStore& containerStore = MWWorld::Class::get(mContainer).getContainerStore(mContainer); + containerStore.add(ptr); + } + else + { + // put back in inventory + MWWorld::InventoryStore& invStore = static_cast(MWWorld::Class::get(mContainer).getContainerStore(mContainer)); + invStore.add(ptr); + + // get a ContainerStoreIterator to the item we just re-added into the inventory + MWWorld::ContainerStoreIterator it = invStore.begin(); + MWWorld::ContainerStoreIterator nextIt = ++it; + while (nextIt != invStore.end()) + { + ++it; + ++nextIt; + } + + // equip the item in the first available slot + invStore.equip(slots.first.front(), it); } - // put back in inventory - MWWorld::ContainerStore& containerStore = MWWorld::Class::get(mContainer).getContainerStore(mContainer); - containerStore.add(ptr); drawItems(); mDragAndDrop->mStore.clear(); From 71de10cb7ed0e19db20e050f37df41bec65ef480 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 15 May 2012 20:33:34 +0200 Subject: [PATCH 155/325] equipping items works, but only if you have more than one of the item that you're equipping --- apps/openmw/mwgui/container.cpp | 57 +++++++++++++++++++++- apps/openmw/mwgui/container.hpp | 12 +++++ apps/openmw/mwgui/inventorywindow.cpp | 66 +++++++++++++++++++++++--- apps/openmw/mwgui/inventorywindow.hpp | 2 + apps/openmw/mwworld/containerstore.cpp | 5 +- apps/openmw/mwworld/containerstore.hpp | 4 +- apps/openmw/mwworld/inventorystore.cpp | 7 +++ apps/openmw/mwworld/inventorystore.hpp | 3 ++ 8 files changed, 145 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index ff7bb889e2..6bf6a589e0 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -81,6 +81,8 @@ void ContainerBase::onSelectedItemImpl(MyGUI::Widget* _sender, int count) mSelectedItem->attachToWidget(mDragAndDrop->mDragAndDropWidget); MWWorld::Ptr object = *mSelectedItem->getUserData(); + _unequipItem(object); + int originalCount = object.getRefData().getCount(); object.getRefData().setCount(count); mDragAndDrop->mStore.add(object); @@ -90,6 +92,7 @@ void ContainerBase::onSelectedItemImpl(MyGUI::Widget* _sender, int count) MWBase::Environment::get().getSoundManager()->playSound (sound, 1.0, 1.0); mDragAndDrop->mDraggedWidget = mSelectedItem; + static_cast(mSelectedItem)->setImageTexture(""); // remove the background texture (not visible during drag) static_cast(mSelectedItem->getChildAt(0)->getChildAt(0))->setCaption( getCountString((*mDragAndDrop->mStore.begin()).getRefData().getCount())); @@ -181,9 +184,46 @@ void ContainerBase::drawItems() /// \todo performance improvement: don't create/destroy all the widgets everytime the container window changes size, only reposition them + std::vector< std::pair > items; + + std::vector equippedItems = getEquippedItems(); + + // filter out the equipped items of categories we don't want + std::vector unwantedItems = equippedItems; for (MWWorld::ContainerStoreIterator iter (containerStore.begin(categories)); iter!=containerStore.end(); ++iter) + { + std::vector::iterator found = std::find(unwantedItems.begin(), unwantedItems.end(), *iter); + if (found != unwantedItems.end()) + { + unwantedItems.erase(found); + } + } + // now erase everything that's still in unwantedItems. + for (std::vector::iterator it=unwantedItems.begin(); + it != unwantedItems.end(); ++it) + { + equippedItems.erase(std::find(unwantedItems.begin(), unwantedItems.end(), *it)); + } + // and add the items that are left (= have the correct category) + for (std::vector::const_iterator it=equippedItems.begin(); + it != equippedItems.end(); ++it) + { + items.push_back( std::make_pair(*it, ItemState_Equipped) ); + } + + // now add the regular items + for (MWWorld::ContainerStoreIterator iter (containerStore.begin(categories)); iter!=containerStore.end(); ++iter) + { + /// \todo sorting + if (std::find(equippedItems.begin(), equippedItems.end(), *iter) == equippedItems.end()) + items.push_back( std::make_pair(*iter, ItemState_Normal) ); + } + + for (std::vector< std::pair >::const_iterator it=items.begin(); + it != items.end(); ++it) { index++; + const MWWorld::Ptr* iter = &((*it).first); if(iter->getRefData().getCount() > 0 && !(onlyMagic && MWWorld::Class::get(*iter).getEnchantment(*iter) == "" && iter->getTypeName() != typeid(ESM::Potion).name())) { std::string path = std::string("icons\\"); @@ -194,7 +234,22 @@ void ContainerBase::drawItems() MyGUI::ImageBox* backgroundWidget = mContainerWidget->createWidget("ImageBox", MyGUI::IntCoord(x, y, 42, 42), MyGUI::Align::Default); backgroundWidget->setUserString("ToolTipType", "ItemPtr"); backgroundWidget->setUserData(*iter); - backgroundWidget->setImageTexture( isMagic ? "textures\\menu_icon_magic.dds" : ""); + + std::string backgroundTex = "textures\\menu_icon"; + if (isMagic) + backgroundTex += "_magic"; + if (it->second == ItemState_Normal) + { + if (!isMagic) + backgroundTex = ""; + } + else if (it->second == ItemState_Equipped) + { + backgroundTex += "_equip"; + } + backgroundTex += ".dds"; + + backgroundWidget->setImageTexture(backgroundTex); backgroundWidget->setProperty("ImageCoord", "0 0 42 42"); backgroundWidget->eventMouseButtonClick += MyGUI::newDelegate(this, &ContainerBase::onSelectedItem); backgroundWidget->eventMouseWheel += MyGUI::newDelegate(this, &ContainerBase::onMouseWheel); diff --git a/apps/openmw/mwgui/container.hpp b/apps/openmw/mwgui/container.hpp index 8a1307967a..9f994be16c 100644 --- a/apps/openmw/mwgui/container.hpp +++ b/apps/openmw/mwgui/container.hpp @@ -63,6 +63,15 @@ namespace MWGui Filter_Misc = 0x05 }; + enum ItemState + { + ItemState_Normal = 0x01, + ItemState_Equipped = 0x02, + + // unimplemented + ItemState_Barter = 0x03 + }; + void setWidgets(MyGUI::Widget* containerWidget, MyGUI::ScrollView* itemView); ///< only call once void openContainer(MWWorld::Ptr container); @@ -87,7 +96,10 @@ namespace MWGui std::string getCountString(const int count); + // to be reimplemented by InventoryWindow virtual bool isInventory() { return false; } + virtual std::vector getEquippedItems() { return std::vector(); } + virtual void _unequipItem(MWWorld::Ptr item) { ; } void drawItems(); }; diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 956961b63f..e466c34d1f 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -151,6 +151,8 @@ namespace MWGui // can't be equipped, try to use instead boost::shared_ptr action = MWWorld::Class::get(ptr).use(ptr); + std::cout << "Item can't be equipped" << std::endl; + // execute action and script MWBase::Environment::get().getWorld()->executeActionScript(ptr, action); @@ -172,19 +174,31 @@ namespace MWGui { // put back in inventory MWWorld::InventoryStore& invStore = static_cast(MWWorld::Class::get(mContainer).getContainerStore(mContainer)); - invStore.add(ptr); - // get a ContainerStoreIterator to the item we just re-added into the inventory - MWWorld::ContainerStoreIterator it = invStore.begin(); - MWWorld::ContainerStoreIterator nextIt = ++it; - while (nextIt != invStore.end()) + MWWorld::ContainerStoreIterator it = invStore.add(ptr); + + // retrieve iterator to the item we just re-added (if stacking didn't happen). + // if stacking happened, the iterator was already returned by the add() call + /// \todo this does not work! + if (it == invStore.end()) { - ++it; - ++nextIt; + std::cout << "stacking didn't happen" << std::endl; + for (MWWorld::ContainerStoreIterator it2 = invStore.begin(); + it2 != invStore.end(); ++it2) + { + if (*it2 == ptr) + { + std::cout << "found iterator" << std::endl; + it = it2; + return; + } + } } // equip the item in the first available slot invStore.equip(slots.first.front(), it); + + std::cout << "Equipped item in slot " << slots.first.front() << std::endl; } drawItems(); @@ -197,4 +211,42 @@ namespace MWGui } } + std::vector InventoryWindow::getEquippedItems() + { + MWWorld::InventoryStore& invStore = static_cast(MWWorld::Class::get(mContainer).getContainerStore(mContainer)); + + std::vector items; + + for (int slot=0; slot < MWWorld::InventoryStore::Slots; ++slot) + { + MWWorld::ContainerStoreIterator it = invStore.getSlot(slot); + if (it != invStore.end()) + { + std::cout << "slot " << slot << " is equipped" << std::endl; + items.push_back(*it); + } + else + { + std::cout << "slot " << slot << " is empty " << std::endl; + } + + } + + return items; + } + + void InventoryWindow::_unequipItem(MWWorld::Ptr item) + { + MWWorld::InventoryStore& invStore = static_cast(MWWorld::Class::get(mContainer).getContainerStore(mContainer)); + + for (int slot=0; slot < MWWorld::InventoryStore::Slots; ++slot) + { + MWWorld::ContainerStoreIterator it = invStore.getSlot(slot); + if (it != invStore.end() && *it == item) + { + invStore._freeSlot(slot); + return; + } + } + } } diff --git a/apps/openmw/mwgui/inventorywindow.hpp b/apps/openmw/mwgui/inventorywindow.hpp index b09ff8521a..18dc913fcd 100644 --- a/apps/openmw/mwgui/inventorywindow.hpp +++ b/apps/openmw/mwgui/inventorywindow.hpp @@ -51,6 +51,8 @@ namespace MWGui void onPinToggled(); virtual bool isInventory() { return true; } + virtual std::vector getEquippedItems(); + virtual void _unequipItem(MWWorld::Ptr item); }; } #endif // Inventory_H diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index ee1b620cd7..2e69de9c39 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -58,7 +58,7 @@ bool MWWorld::ContainerStore::stacks(const Ptr& ptr1, const Ptr& ptr2) return false; } -void MWWorld::ContainerStore::add (const Ptr& ptr) +MWWorld::ContainerStoreIterator MWWorld::ContainerStore::add (const Ptr& ptr) { int type = getType(ptr); @@ -71,12 +71,13 @@ void MWWorld::ContainerStore::add (const Ptr& ptr) iter->getRefData().setCount( iter->getRefData().getCount() + ptr.getRefData().getCount() ); flagAsModified(); - return; + return iter; } } // if we got here, this means no stacking addImpl(ptr); + return end(); } void MWWorld::ContainerStore::addImpl (const Ptr& ptr) diff --git a/apps/openmw/mwworld/containerstore.hpp b/apps/openmw/mwworld/containerstore.hpp index 3cb3f3bdc5..26c9f55a3b 100644 --- a/apps/openmw/mwworld/containerstore.hpp +++ b/apps/openmw/mwworld/containerstore.hpp @@ -66,13 +66,15 @@ namespace MWWorld ContainerStoreIterator end(); - void add (const Ptr& ptr); + ContainerStoreIterator add (const Ptr& ptr); ///< Add the item pointed to by \a ptr to this container. (Stacks automatically if needed) /// /// \note The item pointed to is not required to exist beyond this function call. /// /// \attention Do not add items to an existing stack by increasing the count instead of /// calling this function! + /// + /// @return if stacking happened, return iterator to the item that was stacked against, otherwise end() iterator protected: void addImpl (const Ptr& ptr); diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index 3e535793c0..b38167d701 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -97,6 +97,13 @@ void MWWorld::InventoryStore::equip (int slot, const ContainerStoreIterator& ite flagAsModified(); } +void MWWorld::InventoryStore::_freeSlot(int slot) +{ + mSlots[slot] = end(); + + flagAsModified(); +} + MWWorld::ContainerStoreIterator MWWorld::InventoryStore::getSlot (int slot) { if (slot<0 || slot>=static_cast (mSlots.size())) diff --git a/apps/openmw/mwworld/inventorystore.hpp b/apps/openmw/mwworld/inventorystore.hpp index 05fc651ee7..303604f4de 100644 --- a/apps/openmw/mwworld/inventorystore.hpp +++ b/apps/openmw/mwworld/inventorystore.hpp @@ -60,6 +60,9 @@ namespace MWWorld void equip (int slot, const ContainerStoreIterator& iterator); ///< \note \a iteartor can be an end-iterator + void _freeSlot(int slot); + ///< this method is dangerous, as it doesn't do re-stacking items - you probably want to use equip() + ContainerStoreIterator getSlot (int slot); void autoEquip (const MWMechanics::NpcStats& stats); From ca4fa21d64256244615a4fe86ffa2126be79ec35 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 15 May 2012 20:51:19 +0200 Subject: [PATCH 156/325] removed the attempt to unify activation and use scripts which was incorrect --- apps/openmw/engine.cpp | 18 ++++++++++++++++-- apps/openmw/mwgui/inventorywindow.cpp | 5 +++-- apps/openmw/mwworld/world.cpp | 27 --------------------------- apps/openmw/mwworld/world.hpp | 3 --- 4 files changed, 19 insertions(+), 34 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index a9e7c82b08..85b0557b1a 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -437,11 +437,25 @@ void OMW::Engine::activate() return; } + MWScript::InterpreterContext interpreterContext (&ptr.getRefData().getLocals(), ptr); + boost::shared_ptr action = MWWorld::Class::get (ptr).activate (ptr, MWBase::Environment::get().getWorld()->getPlayer().getPlayer()); - // execute action and script - MWBase::Environment::get().getWorld()->executeActionScript(ptr, action); + interpreterContext.activate (ptr, action); + + std::string script = MWWorld::Class::get (ptr).getScript (ptr); + + if (!script.empty()) + { + MWBase::Environment::get().getWorld()->getLocalScripts().setIgnore (ptr); + MWBase::Environment::get().getScriptManager()->run (script, interpreterContext); + } + + if (!interpreterContext.hasActivationBeenHandled()) + { + interpreterContext.executeActivation(); + } } void OMW::Engine::screenshot() diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index e466c34d1f..ef41bf10ab 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -153,8 +153,9 @@ namespace MWGui std::cout << "Item can't be equipped" << std::endl; - // execute action and script - MWBase::Environment::get().getWorld()->executeActionScript(ptr, action); + action->execute(); + + /// \todo scripts // this is necessary for books/scrolls: if they are already in the player's inventory, // the "Take" button should not be visible. diff --git a/apps/openmw/mwworld/world.cpp b/apps/openmw/mwworld/world.cpp index ce78212806..973407b0c6 100644 --- a/apps/openmw/mwworld/world.cpp +++ b/apps/openmw/mwworld/world.cpp @@ -17,13 +17,6 @@ #include "../mwgui/window_manager.hpp" -#include "../mwscript/scriptmanager.hpp" -#include "../mwscript/compilercontext.hpp" -#include "../mwscript/interpretercontext.hpp" -#include "../mwscript/extensions.hpp" -#include "../mwscript/globalscripts.hpp" - - #include "ptr.hpp" #include "class.hpp" #include "player.hpp" @@ -1025,24 +1018,4 @@ namespace MWWorld mWorldScene->insertObject(object, cell); } - - void World::executeActionScript(MWWorld::Ptr ptr, boost::shared_ptr action) - { - MWScript::InterpreterContext interpreterContext (&ptr.getRefData().getLocals(), ptr); - - action->execute(); - - // execute script - interpreterContext.activate (ptr, action); - std::string script = MWWorld::Class::get (ptr).getScript (ptr); - if (!script.empty()) - { - getLocalScripts().setIgnore (ptr); - MWBase::Environment::get().getScriptManager()->run (script, interpreterContext); - } - if (!interpreterContext.hasActivationBeenHandled()) - { - interpreterContext.executeActivation(); - } - } } diff --git a/apps/openmw/mwworld/world.hpp b/apps/openmw/mwworld/world.hpp index c1d4ace206..1ed6a976ed 100644 --- a/apps/openmw/mwworld/world.hpp +++ b/apps/openmw/mwworld/world.hpp @@ -274,9 +274,6 @@ namespace MWWorld bool canPlaceObject(float cursorX, float cursorY); ///< @return true if it is possible to place on object at specified cursor location - - void executeActionScript(MWWorld::Ptr ptr, boost::shared_ptr action); - ///< execute the activation script of an object (when activating the object with space, or when activating it via the inventory) }; } From c6493fb133b36bec6aeccb634d1cfb4b3bd1335f Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 15 May 2012 21:17:00 +0200 Subject: [PATCH 157/325] added getCapacity function --- apps/openmw/mwclass/container.cpp | 8 ++++++++ apps/openmw/mwclass/container.hpp | 4 ++++ apps/openmw/mwclass/creature.cpp | 6 ++++++ apps/openmw/mwclass/creature.hpp | 4 ++++ apps/openmw/mwclass/npc.cpp | 6 ++++++ apps/openmw/mwclass/npc.hpp | 4 ++++ apps/openmw/mwworld/class.cpp | 5 +++++ apps/openmw/mwworld/class.hpp | 5 +++++ 8 files changed, 42 insertions(+) diff --git a/apps/openmw/mwclass/container.cpp b/apps/openmw/mwclass/container.cpp index a9def96aa6..82a9212a25 100644 --- a/apps/openmw/mwclass/container.cpp +++ b/apps/openmw/mwclass/container.cpp @@ -176,4 +176,12 @@ namespace MWClass return info; } + + float Container::getCapactiy (const MWWorld::Ptr& ptr) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + return ref->base->weight; + } } diff --git a/apps/openmw/mwclass/container.hpp b/apps/openmw/mwclass/container.hpp index 3b1c8de09a..0231ce26bb 100644 --- a/apps/openmw/mwclass/container.hpp +++ b/apps/openmw/mwclass/container.hpp @@ -36,6 +36,10 @@ namespace MWClass virtual std::string getScript (const MWWorld::Ptr& ptr) const; ///< Return name of the script attached to ptr + virtual float getCapactiy (const MWWorld::Ptr& ptr) const; + ///< Return total weight that fits into the object (including modifications from magic + /// effects). Throws an exception, if the object can't hold other objects. + static void registerSelf(); }; } diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index cf00f361bc..a164554304 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -166,4 +166,10 @@ namespace MWClass return info; } + + float Creature::getCapactiy (const MWWorld::Ptr& ptr) const + { + const MWMechanics::CreatureStats& stats = getCreatureStats (ptr); + return stats.mAttributes[0].getModified()*5; + } } diff --git a/apps/openmw/mwclass/creature.hpp b/apps/openmw/mwclass/creature.hpp index 4a1a8285fd..c68d1995d5 100644 --- a/apps/openmw/mwclass/creature.hpp +++ b/apps/openmw/mwclass/creature.hpp @@ -52,6 +52,10 @@ namespace MWClass virtual std::string getScript (const MWWorld::Ptr& ptr) const; ///< Return name of the script attached to ptr + virtual float getCapactiy (const MWWorld::Ptr& ptr) const; + ///< Return total weight that fits into the object (including modifications from magic + /// effects). Throws an exception, if the object can't hold other objects. + static void registerSelf(); }; } diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 444fe9965f..3c1c0e29ab 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -325,4 +325,10 @@ namespace MWClass return info; } + + float Npc::getCapactiy (const MWWorld::Ptr& ptr) const + { + const MWMechanics::CreatureStats& stats = getCreatureStats (ptr); + return stats.mAttributes[0].getModified()*5; + } } diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index 38b0ba03f0..d2ecc7aa70 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -74,6 +74,10 @@ namespace MWClass ///< Return desired movement vector (determined based on movement settings, /// stance and stats). + virtual float getCapactiy (const MWWorld::Ptr& ptr) const; + ///< Return total weight that fits into the object (including modifications from magic + /// effects). Throws an exception, if the object can't hold other objects. + static void registerSelf(); }; } diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 151d913bed..24d2d07f1b 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -142,6 +142,11 @@ namespace MWWorld throw std::logic_error ("value not supported by this class"); } + float Class::getCapactiy (const MWWorld::Ptr& ptr) const + { + throw std::runtime_error ("capacity not supported by class"); + } + const Class& Class::get (const std::string& key) { std::map >::const_iterator iter = sClasses.find (key); diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index d7a2d2d759..34e61c54a7 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -164,6 +164,11 @@ namespace MWWorld ///< Return trade value of the object. Throws an exception, if the object can't be traded. /// (default implementation: throws an exception) + virtual float getCapactiy (const MWWorld::Ptr& ptr) const; + ///< Return total weight that fits into the object (including modifications from magic + /// effects). Throws an exception, if the object can't hold other objects. + /// (default implementation: throws an exception) + static const Class& get (const std::string& key); ///< If there is no class for this \a key, an exception is thrown. From 7e00fea18b3666529d33a968b371b4297fb85bfc Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 15 May 2012 21:34:00 +0200 Subject: [PATCH 158/325] added getEncumbrance function --- apps/openmw/mwclass/container.cpp | 5 +++++ apps/openmw/mwclass/container.hpp | 6 +++++- apps/openmw/mwclass/creature.cpp | 17 +++++++++++++++++ apps/openmw/mwclass/creature.hpp | 6 +++++- apps/openmw/mwclass/npc.cpp | 16 ++++++++++++++++ apps/openmw/mwclass/npc.hpp | 6 +++++- apps/openmw/mwworld/class.cpp | 7 ++++++- apps/openmw/mwworld/class.hpp | 7 ++++++- 8 files changed, 65 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwclass/container.cpp b/apps/openmw/mwclass/container.cpp index 82a9212a25..34d6b6c60e 100644 --- a/apps/openmw/mwclass/container.cpp +++ b/apps/openmw/mwclass/container.cpp @@ -184,4 +184,9 @@ namespace MWClass return ref->base->weight; } + + float Container::getEncumbrance (const MWWorld::Ptr& ptr) const + { + return getContainerStore (ptr).getWeight(); + } } diff --git a/apps/openmw/mwclass/container.hpp b/apps/openmw/mwclass/container.hpp index 0231ce26bb..61a0d912bc 100644 --- a/apps/openmw/mwclass/container.hpp +++ b/apps/openmw/mwclass/container.hpp @@ -37,7 +37,11 @@ namespace MWClass ///< Return name of the script attached to ptr virtual float getCapactiy (const MWWorld::Ptr& ptr) const; - ///< Return total weight that fits into the object (including modifications from magic + ///< Return total weight that fits into the object. Throws an exception, if the object can't + /// hold other objects. + + virtual float getEncumbrance (const MWWorld::Ptr& ptr) const; + ///< Returns total weight of objects inside this object (including modifications from magic /// effects). Throws an exception, if the object can't hold other objects. static void registerSelf(); diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index a164554304..a0b2225dbb 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -5,6 +5,7 @@ #include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/mechanicsmanager.hpp" +#include "../mwmechanics/magiceffects.hpp" #include "../mwbase/environment.hpp" @@ -172,4 +173,20 @@ namespace MWClass const MWMechanics::CreatureStats& stats = getCreatureStats (ptr); return stats.mAttributes[0].getModified()*5; } + + float Creature::getEncumbrance (const MWWorld::Ptr& ptr) const + { + float weight = getContainerStore (ptr).getWeight(); + + const MWMechanics::CreatureStats& stats = getCreatureStats (ptr); + + weight -= stats.mMagicEffects.get (MWMechanics::EffectKey (8)).mMagnitude; // feather + + weight += stats.mMagicEffects.get (MWMechanics::EffectKey (7)).mMagnitude; // burden + + if (weight<0) + weight = 0; + + return weight; + } } diff --git a/apps/openmw/mwclass/creature.hpp b/apps/openmw/mwclass/creature.hpp index c68d1995d5..7224d3ee13 100644 --- a/apps/openmw/mwclass/creature.hpp +++ b/apps/openmw/mwclass/creature.hpp @@ -53,7 +53,11 @@ namespace MWClass ///< Return name of the script attached to ptr virtual float getCapactiy (const MWWorld::Ptr& ptr) const; - ///< Return total weight that fits into the object (including modifications from magic + ///< Return total weight that fits into the object. Throws an exception, if the object can't + /// hold other objects. + + virtual float getEncumbrance (const MWWorld::Ptr& ptr) const; + ///< Returns total weight of objects inside this object (including modifications from magic /// effects). Throws an exception, if the object can't hold other objects. static void registerSelf(); diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 3c1c0e29ab..3bb4519c2f 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -331,4 +331,20 @@ namespace MWClass const MWMechanics::CreatureStats& stats = getCreatureStats (ptr); return stats.mAttributes[0].getModified()*5; } + + float Npc::getEncumbrance (const MWWorld::Ptr& ptr) const + { + float weight = getContainerStore (ptr).getWeight(); + + const MWMechanics::CreatureStats& stats = getCreatureStats (ptr); + + weight -= stats.mMagicEffects.get (MWMechanics::EffectKey (8)).mMagnitude; // feather + + weight += stats.mMagicEffects.get (MWMechanics::EffectKey (7)).mMagnitude; // burden + + if (weight<0) + weight = 0; + + return weight; + } } diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index d2ecc7aa70..0cfad0347c 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -75,7 +75,11 @@ namespace MWClass /// stance and stats). virtual float getCapactiy (const MWWorld::Ptr& ptr) const; - ///< Return total weight that fits into the object (including modifications from magic + ///< Return total weight that fits into the object. Throws an exception, if the object can't + /// hold other objects. + + virtual float getEncumbrance (const MWWorld::Ptr& ptr) const; + ///< Returns total weight of objects inside this object (including modifications from magic /// effects). Throws an exception, if the object can't hold other objects. static void registerSelf(); diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 24d2d07f1b..5fb5038479 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -144,7 +144,12 @@ namespace MWWorld float Class::getCapactiy (const MWWorld::Ptr& ptr) const { - throw std::runtime_error ("capacity not supported by class"); + throw std::runtime_error ("capacity not supported by this class"); + } + + float Class::getEncumbrance (const MWWorld::Ptr& ptr) const + { + throw std::runtime_error ("encumbrance not supported by class"); } const Class& Class::get (const std::string& key) diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 34e61c54a7..513dc942b5 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -165,7 +165,12 @@ namespace MWWorld /// (default implementation: throws an exception) virtual float getCapactiy (const MWWorld::Ptr& ptr) const; - ///< Return total weight that fits into the object (including modifications from magic + ///< Return total weight that fits into the object. Throws an exception, if the object can't + /// hold other objects. + /// (default implementation: throws an exception) + + virtual float getEncumbrance (const MWWorld::Ptr& ptr) const; + ///< Returns total weight of objects inside this object (including modifications from magic /// effects). Throws an exception, if the object can't hold other objects. /// (default implementation: throws an exception) From fdfddc8be7d8b720a8eb54aed365a17bb60bd082 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 15 May 2012 21:34:32 +0200 Subject: [PATCH 159/325] some todo comment cleanup --- apps/openmw/mwclass/creature.cpp | 2 -- apps/openmw/mwclass/npc.cpp | 4 +--- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index a0b2225dbb..c2623500d8 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -57,8 +57,6 @@ namespace MWClass data->mCreatureStats.mLevel = ref->base->data.level; - // \todo add initial container content - // store ptr.getRefData().setCustomData (data.release()); } diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 3bb4519c2f..556798bf44 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -88,11 +88,9 @@ namespace MWClass } else { - //TODO: do something with npdt12 maybe:p + /// \todo do something with npdt12 maybe:p } - // \todo add initial container content - // store ptr.getRefData().setCustomData (data.release()); } From 175623bf22ab3608231524fae7164d05bb2154ae Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 15 May 2012 21:44:57 +0200 Subject: [PATCH 160/325] change the drag&drop to not use a seperate containerstore --- apps/openmw/mwgui/container.cpp | 40 ++++++++++++++++++--------- apps/openmw/mwgui/container.hpp | 7 +++-- apps/openmw/mwgui/hud.cpp | 6 ++-- apps/openmw/mwgui/inventorywindow.cpp | 34 +++++++---------------- 4 files changed, 45 insertions(+), 42 deletions(-) diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 6bf6a589e0..66ccfd50f4 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -83,10 +83,9 @@ void ContainerBase::onSelectedItemImpl(MyGUI::Widget* _sender, int count) MWWorld::Ptr object = *mSelectedItem->getUserData(); _unequipItem(object); - int originalCount = object.getRefData().getCount(); - object.getRefData().setCount(count); - mDragAndDrop->mStore.add(object); - object.getRefData().setCount(originalCount - count); + mDragAndDrop->mDraggedCount = count; + + mDragAndDrop->mDraggedFrom = this; std::string sound = MWWorld::Class::get(object).getUpSoundId(object); MWBase::Environment::get().getSoundManager()->playSound (sound, 1.0, 1.0); @@ -94,7 +93,7 @@ void ContainerBase::onSelectedItemImpl(MyGUI::Widget* _sender, int count) mDragAndDrop->mDraggedWidget = mSelectedItem; static_cast(mSelectedItem)->setImageTexture(""); // remove the background texture (not visible during drag) static_cast(mSelectedItem->getChildAt(0)->getChildAt(0))->setCaption( - getCountString((*mDragAndDrop->mStore.begin()).getRefData().getCount())); + getCountString(mDragAndDrop->mDraggedCount)); mDragAndDrop->mWasInInventory = isInventory(); @@ -108,19 +107,27 @@ void ContainerBase::onContainerClicked(MyGUI::Widget* _sender) if(mDragAndDrop->mIsOnDragAndDrop) //drop widget here { MWWorld::Ptr object = *mDragAndDrop->mDraggedWidget->getUserData(); - assert(object.getContainerStore() && "Item is not in a container!"); - std::string sound = MWWorld::Class::get(object).getDownSoundId(object); - MWBase::Environment::get().getSoundManager()->playSound (sound, 1.0, 1.0); + if (mDragAndDrop->mDraggedFrom != this) + { + assert(object.getContainerStore() && "Item is not in a container!"); + + MWWorld::ContainerStore& containerStore = MWWorld::Class::get(mContainer).getContainerStore(mContainer); + int origCount = object.getRefData().getCount(); + object.getRefData().setCount (mDragAndDrop->mDraggedCount); + containerStore.add(object); + object.getRefData().setCount (origCount - mDragAndDrop->mDraggedCount); + } - MWWorld::ContainerStore& containerStore = MWWorld::Class::get(mContainer).getContainerStore(mContainer); - containerStore.add(*mDragAndDrop->mStore.begin()); - mDragAndDrop->mStore.clear(); mDragAndDrop->mIsOnDragAndDrop = false; MyGUI::Gui::getInstance().destroyWidget(mDragAndDrop->mDraggedWidget); drawItems(); + mDragAndDrop->mDraggedFrom->drawItems(); MWBase::Environment::get().getWindowManager()->setDragDrop(false); + + std::string sound = MWWorld::Class::get(object).getDownSoundId(object); + MWBase::Environment::get().getSoundManager()->playSound (sound, 1.0, 1.0); } } @@ -224,7 +231,14 @@ void ContainerBase::drawItems() { index++; const MWWorld::Ptr* iter = &((*it).first); - if(iter->getRefData().getCount() > 0 && !(onlyMagic && MWWorld::Class::get(*iter).getEnchantment(*iter) == "" && iter->getTypeName() != typeid(ESM::Potion).name())) + + int displayCount = iter->getRefData().getCount(); + if (mDragAndDrop->mIsOnDragAndDrop && *iter == *mDragAndDrop->mDraggedWidget->getUserData()) + { + std::cout << "beep" << std::endl; + displayCount -= mDragAndDrop->mDraggedCount; +} + if(displayCount > 0 && !(onlyMagic && MWWorld::Class::get(*iter).getEnchantment(*iter) == "" && iter->getTypeName() != typeid(ESM::Potion).name())) { std::string path = std::string("icons\\"); path+=MWWorld::Class::get(*iter).getInventoryIcon(*iter); @@ -276,7 +290,7 @@ void ContainerBase::drawItems() y = 0; } - text->setCaption(getCountString(iter->getRefData().getCount())); + text->setCaption(getCountString(displayCount)); } } diff --git a/apps/openmw/mwgui/container.hpp b/apps/openmw/mwgui/container.hpp index 9f994be16c..a19f9e91f2 100644 --- a/apps/openmw/mwgui/container.hpp +++ b/apps/openmw/mwgui/container.hpp @@ -44,7 +44,8 @@ namespace MWGui bool mIsOnDragAndDrop; MyGUI::Widget* mDraggedWidget; MyGUI::Widget* mDragAndDropWidget; - MWWorld::ContainerStore mStore; + ContainerBase* mDraggedFrom; + int mDraggedCount; bool mWasInInventory; // was the item in inventory before it was dragged }; @@ -77,6 +78,8 @@ namespace MWGui void openContainer(MWWorld::Ptr container); void setFilter(Filter filter); ///< set category filter void Update(); + void drawItems(); + protected: MyGUI::ScrollView* mItemView; @@ -100,8 +103,6 @@ namespace MWGui virtual bool isInventory() { return false; } virtual std::vector getEquippedItems() { return std::vector(); } virtual void _unequipItem(MWWorld::Ptr item) { ; } - - void drawItems(); }; class ContainerWindow : public ContainerBase, public WindowBase diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index b992764401..90adb80d5c 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -260,7 +260,7 @@ void HUD::onWorldClicked(MyGUI::Widget* _sender) if (mDragAndDrop->mIsOnDragAndDrop) { // drop item into the gameworld - MWWorld::Ptr object = *mDragAndDrop->mStore.begin(); + MWWorld::Ptr object = *mDragAndDrop->mDraggedWidget->getUserData(); MWWorld::World* world = MWBase::Environment::get().getWorld(); @@ -279,7 +279,9 @@ void HUD::onWorldClicked(MyGUI::Widget* _sender) std::string sound = MWWorld::Class::get(object).getDownSoundId(object); MWBase::Environment::get().getSoundManager()->playSound (sound, 1.0, 1.0); - mDragAndDrop->mStore.clear(); + // remove object from the container it was coming from + object.getRefData().setCount(0); + mDragAndDrop->mIsOnDragAndDrop = false; MyGUI::Gui::getInstance().destroyWidget(mDragAndDrop->mDraggedWidget); mDragAndDrop->mDraggedWidget = 0; diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index ef41bf10ab..0c8ac459ff 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -142,7 +142,7 @@ namespace MWGui { if (mDragAndDrop->mIsOnDragAndDrop) { - MWWorld::Ptr ptr = *mDragAndDrop->mStore.begin(); + MWWorld::Ptr ptr = *mDragAndDrop->mDraggedWidget->getUserData(); // can the object be equipped? std::pair, bool> slots = MWWorld::Class::get(ptr).getEquipmentSlots(ptr); @@ -166,49 +166,35 @@ namespace MWGui mWindowManager.getBookWindow()->setTakeButtonShow(false); mWindowManager.getScrollWindow()->setTakeButtonShow(false); } - - // put back in inventory - MWWorld::ContainerStore& containerStore = MWWorld::Class::get(mContainer).getContainerStore(mContainer); - containerStore.add(ptr); } else { - // put back in inventory MWWorld::InventoryStore& invStore = static_cast(MWWorld::Class::get(mContainer).getContainerStore(mContainer)); - MWWorld::ContainerStoreIterator it = invStore.add(ptr); - - // retrieve iterator to the item we just re-added (if stacking didn't happen). - // if stacking happened, the iterator was already returned by the add() call - /// \todo this does not work! - if (it == invStore.end()) + // retrieve iterator to the item + MWWorld::ContainerStoreIterator it = invStore.begin(); + for (; it != invStore.end(); ++it) { - std::cout << "stacking didn't happen" << std::endl; - for (MWWorld::ContainerStoreIterator it2 = invStore.begin(); - it2 != invStore.end(); ++it2) + if (*it == ptr) { - if (*it2 == ptr) - { - std::cout << "found iterator" << std::endl; - it = it2; - return; - } + break; } } + assert(it != invStore.end()); + // equip the item in the first available slot invStore.equip(slots.first.front(), it); std::cout << "Equipped item in slot " << slots.first.front() << std::endl; } - drawItems(); - - mDragAndDrop->mStore.clear(); mDragAndDrop->mIsOnDragAndDrop = false; MyGUI::Gui::getInstance().destroyWidget(mDragAndDrop->mDraggedWidget); mWindowManager.setDragDrop(false); + + drawItems(); } } From d3a53ae0b8f295cff46f0dfafa01d576e8aac15f Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 15 May 2012 22:01:09 +0200 Subject: [PATCH 161/325] removed the _freeSlot method which is now unneeded --- apps/openmw/mwgui/inventorywindow.cpp | 2 +- apps/openmw/mwworld/inventorystore.cpp | 7 ------- apps/openmw/mwworld/inventorystore.hpp | 3 --- 3 files changed, 1 insertion(+), 11 deletions(-) diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 0c8ac459ff..5e33d46005 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -231,7 +231,7 @@ namespace MWGui MWWorld::ContainerStoreIterator it = invStore.getSlot(slot); if (it != invStore.end() && *it == item) { - invStore._freeSlot(slot); + invStore.equip(slot, invStore.end()); return; } } diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index b38167d701..3e535793c0 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -97,13 +97,6 @@ void MWWorld::InventoryStore::equip (int slot, const ContainerStoreIterator& ite flagAsModified(); } -void MWWorld::InventoryStore::_freeSlot(int slot) -{ - mSlots[slot] = end(); - - flagAsModified(); -} - MWWorld::ContainerStoreIterator MWWorld::InventoryStore::getSlot (int slot) { if (slot<0 || slot>=static_cast (mSlots.size())) diff --git a/apps/openmw/mwworld/inventorystore.hpp b/apps/openmw/mwworld/inventorystore.hpp index 303604f4de..05fc651ee7 100644 --- a/apps/openmw/mwworld/inventorystore.hpp +++ b/apps/openmw/mwworld/inventorystore.hpp @@ -60,9 +60,6 @@ namespace MWWorld void equip (int slot, const ContainerStoreIterator& iterator); ///< \note \a iteartor can be an end-iterator - void _freeSlot(int slot); - ///< this method is dangerous, as it doesn't do re-stacking items - you probably want to use equip() - ContainerStoreIterator getSlot (int slot); void autoEquip (const MWMechanics::NpcStats& stats); From e9ea1fba4e85ab99fc030ace36512f64d1140d9c Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 15 May 2012 22:31:52 +0200 Subject: [PATCH 162/325] fixed typo getCapacity method --- apps/openmw/mwclass/container.cpp | 2 +- apps/openmw/mwclass/container.hpp | 2 +- apps/openmw/mwclass/creature.cpp | 2 +- apps/openmw/mwclass/creature.hpp | 2 +- apps/openmw/mwclass/npc.cpp | 2 +- apps/openmw/mwclass/npc.hpp | 2 +- apps/openmw/mwworld/class.cpp | 2 +- apps/openmw/mwworld/class.hpp | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwclass/container.cpp b/apps/openmw/mwclass/container.cpp index 2e0d2d8663..e9b8ce31fc 100644 --- a/apps/openmw/mwclass/container.cpp +++ b/apps/openmw/mwclass/container.cpp @@ -180,7 +180,7 @@ namespace MWClass return info; } - float Container::getCapactiy (const MWWorld::Ptr& ptr) const + float Container::getCapacity (const MWWorld::Ptr& ptr) const { ESMS::LiveCellRef *ref = ptr.get(); diff --git a/apps/openmw/mwclass/container.hpp b/apps/openmw/mwclass/container.hpp index 61a0d912bc..44f0fe927b 100644 --- a/apps/openmw/mwclass/container.hpp +++ b/apps/openmw/mwclass/container.hpp @@ -36,7 +36,7 @@ namespace MWClass virtual std::string getScript (const MWWorld::Ptr& ptr) const; ///< Return name of the script attached to ptr - virtual float getCapactiy (const MWWorld::Ptr& ptr) const; + virtual float getCapacity (const MWWorld::Ptr& ptr) const; ///< Return total weight that fits into the object. Throws an exception, if the object can't /// hold other objects. diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index c2623500d8..653fabd089 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -166,7 +166,7 @@ namespace MWClass return info; } - float Creature::getCapactiy (const MWWorld::Ptr& ptr) const + float Creature::getCapacity (const MWWorld::Ptr& ptr) const { const MWMechanics::CreatureStats& stats = getCreatureStats (ptr); return stats.mAttributes[0].getModified()*5; diff --git a/apps/openmw/mwclass/creature.hpp b/apps/openmw/mwclass/creature.hpp index 7224d3ee13..9d94915795 100644 --- a/apps/openmw/mwclass/creature.hpp +++ b/apps/openmw/mwclass/creature.hpp @@ -52,7 +52,7 @@ namespace MWClass virtual std::string getScript (const MWWorld::Ptr& ptr) const; ///< Return name of the script attached to ptr - virtual float getCapactiy (const MWWorld::Ptr& ptr) const; + virtual float getCapacity (const MWWorld::Ptr& ptr) const; ///< Return total weight that fits into the object. Throws an exception, if the object can't /// hold other objects. diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 556798bf44..db0a6460ce 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -324,7 +324,7 @@ namespace MWClass return info; } - float Npc::getCapactiy (const MWWorld::Ptr& ptr) const + float Npc::getCapacity (const MWWorld::Ptr& ptr) const { const MWMechanics::CreatureStats& stats = getCreatureStats (ptr); return stats.mAttributes[0].getModified()*5; diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index 0cfad0347c..ef154bad41 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -74,7 +74,7 @@ namespace MWClass ///< Return desired movement vector (determined based on movement settings, /// stance and stats). - virtual float getCapactiy (const MWWorld::Ptr& ptr) const; + virtual float getCapacity (const MWWorld::Ptr& ptr) const; ///< Return total weight that fits into the object. Throws an exception, if the object can't /// hold other objects. diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index c014fb3751..15bc405cef 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -142,7 +142,7 @@ namespace MWWorld throw std::logic_error ("value not supported by this class"); } - float Class::getCapactiy (const MWWorld::Ptr& ptr) const + float Class::getCapacity (const MWWorld::Ptr& ptr) const { throw std::runtime_error ("capacity not supported by this class"); } diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 7bf13d822d..a8f2aba177 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -164,7 +164,7 @@ namespace MWWorld ///< Return trade value of the object. Throws an exception, if the object can't be traded. /// (default implementation: throws an exception) - virtual float getCapactiy (const MWWorld::Ptr& ptr) const; + virtual float getCapacity (const MWWorld::Ptr& ptr) const; ///< Return total weight that fits into the object. Throws an exception, if the object can't /// hold other objects. /// (default implementation: throws an exception) From 3f4ce327270e862cdd91667ea3782984d9bf56b2 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 15 May 2012 22:45:46 +0200 Subject: [PATCH 163/325] implemented player encumbrance bar --- apps/openmw/mwgui/container.cpp | 2 ++ apps/openmw/mwgui/container.hpp | 1 + apps/openmw/mwgui/hud.cpp | 1 + apps/openmw/mwgui/inventorywindow.cpp | 21 ++++++++++++++++++++- apps/openmw/mwgui/inventorywindow.hpp | 4 ++++ 5 files changed, 28 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 66ccfd50f4..52714fd22a 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -297,6 +297,8 @@ void ContainerBase::drawItems() MyGUI::IntSize size = MyGUI::IntSize(std::max(mItemView->getSize().width, x+42), mItemView->getSize().height); mItemView->setCanvasSize(size); mContainerWidget->setSize(size); + + notifyContentChanged(); } std::string ContainerBase::getCountString(const int count) diff --git a/apps/openmw/mwgui/container.hpp b/apps/openmw/mwgui/container.hpp index a19f9e91f2..d93cdd187d 100644 --- a/apps/openmw/mwgui/container.hpp +++ b/apps/openmw/mwgui/container.hpp @@ -80,6 +80,7 @@ namespace MWGui void Update(); void drawItems(); + virtual void notifyContentChanged() { } protected: MyGUI::ScrollView* mItemView; diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index 90adb80d5c..d327653f07 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -281,6 +281,7 @@ void HUD::onWorldClicked(MyGUI::Widget* _sender) // remove object from the container it was coming from object.getRefData().setCount(0); + mDragAndDrop->mDraggedFrom->notifyContentChanged(); mDragAndDrop->mIsOnDragAndDrop = false; MyGUI::Gui::getInstance().destroyWidget(mDragAndDrop->mDraggedWidget); diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 5e33d46005..8eb4b7bb1f 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -95,9 +95,12 @@ namespace MWGui void InventoryWindow::openInventory() { - openContainer(MWBase::Environment::get().getWorld()->getPlayer().getPlayer()); + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + openContainer(player); onWindowResize(static_cast(mMainWidget)); + + updateEncumbranceBar(); } void InventoryWindow::onWindowResize(MyGUI::Window* _sender) @@ -236,4 +239,20 @@ namespace MWGui } } } + + void InventoryWindow::updateEncumbranceBar() + { + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + + float capacity = MWWorld::Class::get(player).getCapacity(player); + float encumbrance = MWWorld::Class::get(player).getEncumbrance(player); + mEncumbranceBar->setProgressRange(capacity); + mEncumbranceBar->setProgressPosition(encumbrance); + mEncumbranceText->setCaption( boost::lexical_cast(int(encumbrance)) + "/" + boost::lexical_cast(int(capacity)) ); + } + + void InventoryWindow::notifyContentChanged() + { + updateEncumbranceBar(); + } } diff --git a/apps/openmw/mwgui/inventorywindow.hpp b/apps/openmw/mwgui/inventorywindow.hpp index 18dc913fcd..c1a36bd561 100644 --- a/apps/openmw/mwgui/inventorywindow.hpp +++ b/apps/openmw/mwgui/inventorywindow.hpp @@ -30,6 +30,8 @@ namespace MWGui void openInventory(); + virtual void notifyContentChanged(); + protected: MyGUI::Widget* mAvatar; MyGUI::TextBox* mArmorRating; @@ -50,6 +52,8 @@ namespace MWGui void onAvatarClicked(MyGUI::Widget* _sender); void onPinToggled(); + void updateEncumbranceBar(); + virtual bool isInventory() { return true; } virtual std::vector getEquippedItems(); virtual void _unequipItem(MWWorld::Ptr item); From 5a43fe3e5ff3d2d6fedb15d56f43291663dc40d3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 15 May 2012 22:48:14 +0200 Subject: [PATCH 164/325] remove debug prints --- apps/openmw/mwgui/container.cpp | 1 - apps/openmw/mwgui/inventorywindow.cpp | 10 ---------- 2 files changed, 11 deletions(-) diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 52714fd22a..6d80c16edd 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -235,7 +235,6 @@ void ContainerBase::drawItems() int displayCount = iter->getRefData().getCount(); if (mDragAndDrop->mIsOnDragAndDrop && *iter == *mDragAndDrop->mDraggedWidget->getUserData()) { - std::cout << "beep" << std::endl; displayCount -= mDragAndDrop->mDraggedCount; } if(displayCount > 0 && !(onlyMagic && MWWorld::Class::get(*iter).getEnchantment(*iter) == "" && iter->getTypeName() != typeid(ESM::Potion).name())) diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 8eb4b7bb1f..dbf335e5f0 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -154,8 +154,6 @@ namespace MWGui // can't be equipped, try to use instead boost::shared_ptr action = MWWorld::Class::get(ptr).use(ptr); - std::cout << "Item can't be equipped" << std::endl; - action->execute(); /// \todo scripts @@ -188,8 +186,6 @@ namespace MWGui // equip the item in the first available slot invStore.equip(slots.first.front(), it); - - std::cout << "Equipped item in slot " << slots.first.front() << std::endl; } mDragAndDrop->mIsOnDragAndDrop = false; @@ -212,14 +208,8 @@ namespace MWGui MWWorld::ContainerStoreIterator it = invStore.getSlot(slot); if (it != invStore.end()) { - std::cout << "slot " << slot << " is equipped" << std::endl; items.push_back(*it); } - else - { - std::cout << "slot " << slot << " is empty " << std::endl; - } - } return items; From 0f811edb4705c31c930bd11d7bf976319a1ca4dc Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 15 May 2012 22:54:28 +0200 Subject: [PATCH 165/325] fixed a bug with dropping items on the ground --- apps/openmw/mwgui/hud.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index d327653f07..96c971c4e8 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -280,7 +280,7 @@ void HUD::onWorldClicked(MyGUI::Widget* _sender) MWBase::Environment::get().getSoundManager()->playSound (sound, 1.0, 1.0); // remove object from the container it was coming from - object.getRefData().setCount(0); + object.getRefData().setCount(object.getRefData().getCount() - mDragAndDrop->mDraggedCount); mDragAndDrop->mDraggedFrom->notifyContentChanged(); mDragAndDrop->mIsOnDragAndDrop = false; From 477f1b42ab48495c320f02a32caa4aa99b994f0c Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 15 May 2012 23:28:04 +0200 Subject: [PATCH 166/325] fixed another item dropping bug --- apps/openmw/mwgui/container.cpp | 11 +++++++++++ apps/openmw/mwgui/container.hpp | 2 +- apps/openmw/mwgui/hud.cpp | 5 ++++- apps/openmw/mwgui/inventorywindow.cpp | 6 ++++++ apps/openmw/mwgui/inventorywindow.hpp | 1 + 5 files changed, 23 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 6d80c16edd..5ae943ea49 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -118,6 +118,17 @@ void ContainerBase::onContainerClicked(MyGUI::Widget* _sender) containerStore.add(object); object.getRefData().setCount (origCount - mDragAndDrop->mDraggedCount); } + else + { + // check that we don't exceed the allowed weight (only for containers, not for inventory) + if (isInventory()) + { + float curWeight = MWWorld::Class::get(mContainer).getEncumbrance(mContainer); + float capacity = MWWorld::Class::get(mContainer).getCapacity(mContainer); + + + } + } mDragAndDrop->mIsOnDragAndDrop = false; MyGUI::Gui::getInstance().destroyWidget(mDragAndDrop->mDraggedWidget); diff --git a/apps/openmw/mwgui/container.hpp b/apps/openmw/mwgui/container.hpp index d93cdd187d..174f18f9a5 100644 --- a/apps/openmw/mwgui/container.hpp +++ b/apps/openmw/mwgui/container.hpp @@ -77,7 +77,7 @@ namespace MWGui void openContainer(MWWorld::Ptr container); void setFilter(Filter filter); ///< set category filter - void Update(); + virtual void Update(); void drawItems(); virtual void notifyContentChanged() { } diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index 96c971c4e8..c15801da4d 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -269,6 +269,9 @@ void HUD::onWorldClicked(MyGUI::Widget* _sender) float mouseX = cursorPosition.left / float(viewSize.width); float mouseY = cursorPosition.top / float(viewSize.height); + int origCount = object.getRefData().getCount(); + object.getRefData().setCount(mDragAndDrop->mDraggedCount); + if (world->canPlaceObject(mouseX, mouseY)) world->placeObject(object, mouseX, mouseY); else @@ -280,7 +283,7 @@ void HUD::onWorldClicked(MyGUI::Widget* _sender) MWBase::Environment::get().getSoundManager()->playSound (sound, 1.0, 1.0); // remove object from the container it was coming from - object.getRefData().setCount(object.getRefData().getCount() - mDragAndDrop->mDraggedCount); + object.getRefData().setCount(origCount - mDragAndDrop->mDraggedCount); mDragAndDrop->mDraggedFrom->notifyContentChanged(); mDragAndDrop->mIsOnDragAndDrop = false; diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index dbf335e5f0..a1e73d0edd 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -242,7 +242,13 @@ namespace MWGui } void InventoryWindow::notifyContentChanged() + { + } + + void InventoryWindow::Update() { updateEncumbranceBar(); + + ContainerBase::Update(); } } diff --git a/apps/openmw/mwgui/inventorywindow.hpp b/apps/openmw/mwgui/inventorywindow.hpp index c1a36bd561..ae0d809867 100644 --- a/apps/openmw/mwgui/inventorywindow.hpp +++ b/apps/openmw/mwgui/inventorywindow.hpp @@ -30,6 +30,7 @@ namespace MWGui void openInventory(); + virtual void Update(); virtual void notifyContentChanged(); protected: From 2fa7ce0c1903fed551da09300f65bc5389416b25 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 16 May 2012 00:02:05 +0200 Subject: [PATCH 167/325] equipping works also when the item wasn't in player inventory before. --- apps/openmw/mwgui/inventorywindow.cpp | 39 +++++++++++++++--- apps/openmw/mwworld/containerstore.cpp | 57 +++++++++++++++++++------- apps/openmw/mwworld/containerstore.hpp | 16 +++++++- 3 files changed, 90 insertions(+), 22 deletions(-) diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index a1e73d0edd..b3da52b02d 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -172,20 +172,47 @@ namespace MWGui { MWWorld::InventoryStore& invStore = static_cast(MWWorld::Class::get(mContainer).getContainerStore(mContainer)); - // retrieve iterator to the item MWWorld::ContainerStoreIterator it = invStore.begin(); - for (; it != invStore.end(); ++it) + + if (mDragAndDrop->mDraggedFrom != this) { - if (*it == ptr) + // add item to the player's inventory + int origCount = ptr.getRefData().getCount(); + ptr.getRefData().setCount(origCount - mDragAndDrop->mDraggedCount); + it = invStore.add(ptr); + (*it).getRefData().setCount(mDragAndDrop->mDraggedCount); + } + else + { + // retrieve iterator to the item + for (; it != invStore.end(); ++it) { - break; + if (*it == ptr) + { + break; + } } } assert(it != invStore.end()); - // equip the item in the first available slot - invStore.equip(slots.first.front(), it); + // equip the item in the first free slot + for (std::vector::const_iterator slot=slots.first.begin(); + slot!=slots.first.end(); ++slot) + { + // if all slots are occupied, replace the last slot + if (slot == --slots.first.end()) + { + invStore.equip(*slot, it); + break; + } + + if (invStore.getSlot(*slot) == invStore.end()) + { + invStore.equip(*slot, it); + break; + } + } } mDragAndDrop->mIsOnDragAndDrop = false; diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index 2e69de9c39..eca7206030 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -76,29 +76,31 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::add (const Ptr& ptr) } // if we got here, this means no stacking - addImpl(ptr); - return end(); + return addImpl(ptr); } -void MWWorld::ContainerStore::addImpl (const Ptr& ptr) +MWWorld::ContainerStoreIterator MWWorld::ContainerStore::addImpl (const Ptr& ptr) { + ContainerStoreIterator it = begin(); + switch (getType(ptr)) { - case Type_Potion: potions.list.push_back (*ptr.get()); break; - case Type_Apparatus: appas.list.push_back (*ptr.get()); break; - case Type_Armor: armors.list.push_back (*ptr.get()); break; - case Type_Book: books.list.push_back (*ptr.get()); break; - case Type_Clothing: clothes.list.push_back (*ptr.get()); break; - case Type_Ingredient: ingreds.list.push_back (*ptr.get()); break; - case Type_Light: lights.list.push_back (*ptr.get()); break; - case Type_Lockpick: lockpicks.list.push_back (*ptr.get()); break; - case Type_Miscellaneous: miscItems.list.push_back (*ptr.get()); break; - case Type_Probe: probes.list.push_back (*ptr.get()); break; - case Type_Repair: repairs.list.push_back (*ptr.get()); break; - case Type_Weapon: weapons.list.push_back (*ptr.get()); break; + case Type_Potion: potions.list.push_back (*ptr.get()); it = ContainerStoreIterator(this, --potions.list.end()); break; + case Type_Apparatus: appas.list.push_back (*ptr.get()); it = ContainerStoreIterator(this, --appas.list.end()); break; + case Type_Armor: armors.list.push_back (*ptr.get()); it = ContainerStoreIterator(this, --armors.list.end()); break; + case Type_Book: books.list.push_back (*ptr.get()); it = ContainerStoreIterator(this, --books.list.end()); break; + case Type_Clothing: clothes.list.push_back (*ptr.get()); it = ContainerStoreIterator(this, --clothes.list.end()); break; + case Type_Ingredient: ingreds.list.push_back (*ptr.get()); it = ContainerStoreIterator(this, --ingreds.list.end()); break; + case Type_Light: lights.list.push_back (*ptr.get()); it = ContainerStoreIterator(this, --lights.list.end()); break; + case Type_Lockpick: lockpicks.list.push_back (*ptr.get()); it = ContainerStoreIterator(this, --lockpicks.list.end()); break; + case Type_Miscellaneous: miscItems.list.push_back (*ptr.get()); it = ContainerStoreIterator(this, --miscItems.list.end()); break; + case Type_Probe: probes.list.push_back (*ptr.get()); it = ContainerStoreIterator(this, --probes.list.end()); break; + case Type_Repair: repairs.list.push_back (*ptr.get()); it = ContainerStoreIterator(this, --repairs.list.end()); break; + case Type_Weapon: weapons.list.push_back (*ptr.get()); it = ContainerStoreIterator(this, --weapons.list.end()); break; } flagAsModified(); + return it; } void MWWorld::ContainerStore::fill (const ESM::InventoryList& items, const ESMS::ESMStore& store) @@ -231,6 +233,31 @@ MWWorld::ContainerStoreIterator::ContainerStoreIterator (int mask, ContainerStor nextType(); } +MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, ESMS::CellRefList::List::iterator iterator) + : mType(MWWorld::ContainerStore::Type_Potion), mMask(MWWorld::ContainerStore::Type_All), mContainer(container), mPotion(iterator){} +MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, ESMS::CellRefList::List::iterator iterator) + : mType(MWWorld::ContainerStore::Type_Apparatus), mMask(MWWorld::ContainerStore::Type_All), mContainer(container), mApparatus(iterator){} +MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, ESMS::CellRefList::List::iterator iterator) + : mType(MWWorld::ContainerStore::Type_Armor), mMask(MWWorld::ContainerStore::Type_All), mContainer(container), mArmor(iterator){} +MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, ESMS::CellRefList::List::iterator iterator) + : mType(MWWorld::ContainerStore::Type_Book), mMask(MWWorld::ContainerStore::Type_All), mContainer(container), mBook(iterator){} +MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, ESMS::CellRefList::List::iterator iterator) + : mType(MWWorld::ContainerStore::Type_Clothing), mMask(MWWorld::ContainerStore::Type_All), mContainer(container), mClothing(iterator){} +MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, ESMS::CellRefList::List::iterator iterator) + : mType(MWWorld::ContainerStore::Type_Ingredient), mMask(MWWorld::ContainerStore::Type_All), mContainer(container), mIngredient(iterator){} +MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, ESMS::CellRefList::List::iterator iterator) + : mType(MWWorld::ContainerStore::Type_Light), mMask(MWWorld::ContainerStore::Type_All), mContainer(container), mLight(iterator){} +MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, ESMS::CellRefList::List::iterator iterator) + : mType(MWWorld::ContainerStore::Type_Lockpick), mMask(MWWorld::ContainerStore::Type_All), mContainer(container), mLockpick(iterator){} +MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, ESMS::CellRefList::List::iterator iterator) + : mType(MWWorld::ContainerStore::Type_Miscellaneous), mMask(MWWorld::ContainerStore::Type_All), mContainer(container), mMiscellaneous(iterator){} +MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, ESMS::CellRefList::List::iterator iterator) + : mType(MWWorld::ContainerStore::Type_Probe), mMask(MWWorld::ContainerStore::Type_All), mContainer(container), mProbe(iterator){} +MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, ESMS::CellRefList::List::iterator iterator) + : mType(MWWorld::ContainerStore::Type_Repair), mMask(MWWorld::ContainerStore::Type_All), mContainer(container), mRepair(iterator){} +MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, ESMS::CellRefList::List::iterator iterator) + : mType(MWWorld::ContainerStore::Type_Weapon), mMask(MWWorld::ContainerStore::Type_All), mContainer(container), mWeapon(iterator){} + void MWWorld::ContainerStoreIterator::incType() { if (mType==0) diff --git a/apps/openmw/mwworld/containerstore.hpp b/apps/openmw/mwworld/containerstore.hpp index 26c9f55a3b..96c97415d3 100644 --- a/apps/openmw/mwworld/containerstore.hpp +++ b/apps/openmw/mwworld/containerstore.hpp @@ -77,7 +77,7 @@ namespace MWWorld /// @return if stacking happened, return iterator to the item that was stacked against, otherwise end() iterator protected: - void addImpl (const Ptr& ptr); + ContainerStoreIterator addImpl (const Ptr& ptr); ///< Add the item to this container (no stacking) virtual bool stacks (const Ptr& ptr1, const Ptr& ptr2); @@ -143,6 +143,20 @@ namespace MWWorld ContainerStoreIterator (int mask, ContainerStore *container); ///< Begin-iterator + // construct iterator using a CellRefList iterator + ContainerStoreIterator (ContainerStore *container, ESMS::CellRefList::List::iterator); + ContainerStoreIterator (ContainerStore *container, ESMS::CellRefList::List::iterator); + ContainerStoreIterator (ContainerStore *container, ESMS::CellRefList::List::iterator); + ContainerStoreIterator (ContainerStore *container, ESMS::CellRefList::List::iterator); + ContainerStoreIterator (ContainerStore *container, ESMS::CellRefList::List::iterator); + ContainerStoreIterator (ContainerStore *container, ESMS::CellRefList::List::iterator); + ContainerStoreIterator (ContainerStore *container, ESMS::CellRefList::List::iterator); + ContainerStoreIterator (ContainerStore *container, ESMS::CellRefList::List::iterator); + ContainerStoreIterator (ContainerStore *container, ESMS::CellRefList::List::iterator); + ContainerStoreIterator (ContainerStore *container, ESMS::CellRefList::List::iterator); + ContainerStoreIterator (ContainerStore *container, ESMS::CellRefList::List::iterator); + ContainerStoreIterator (ContainerStore *container, ESMS::CellRefList::List::iterator); + void incType(); void nextType(); From f8c20ef77f934939a9489fbd7c89f632cf36a9c6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 16 May 2012 00:20:24 +0200 Subject: [PATCH 168/325] don't allow putting items into a container if the weight is exceeded. --- apps/openmw/mwgui/container.cpp | 41 ++++++++++++++++++++++++--------- 1 file changed, 30 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 5ae943ea49..b7e0bf8b50 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -107,26 +107,45 @@ void ContainerBase::onContainerClicked(MyGUI::Widget* _sender) if(mDragAndDrop->mIsOnDragAndDrop) //drop widget here { MWWorld::Ptr object = *mDragAndDrop->mDraggedWidget->getUserData(); + MWWorld::ContainerStore& containerStore = MWWorld::Class::get(mContainer).getContainerStore(mContainer); if (mDragAndDrop->mDraggedFrom != this) { assert(object.getContainerStore() && "Item is not in a container!"); - MWWorld::ContainerStore& containerStore = MWWorld::Class::get(mContainer).getContainerStore(mContainer); - int origCount = object.getRefData().getCount(); - object.getRefData().setCount (mDragAndDrop->mDraggedCount); - containerStore.add(object); - object.getRefData().setCount (origCount - mDragAndDrop->mDraggedCount); - } - else - { + // check that we don't exceed the allowed weight (only for containers, not for inventory) - if (isInventory()) + if (!isInventory()) { - float curWeight = MWWorld::Class::get(mContainer).getEncumbrance(mContainer); float capacity = MWWorld::Class::get(mContainer).getCapacity(mContainer); - + // try adding the item, and if weight is exceeded, just remove it again. + int origCount = object.getRefData().getCount(); + object.getRefData().setCount(mDragAndDrop->mDraggedCount); + MWWorld::ContainerStoreIterator it = containerStore.add(object); + + float curWeight = MWWorld::Class::get(mContainer).getEncumbrance(mContainer); + if (curWeight > capacity) + { + it->getRefData().setCount(0); + object.getRefData().setCount(origCount); + // user notification + MWBase::Environment::get().getWindowManager()-> + messageBox(MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sContentsMessage3")->str, std::vector()); + return; + } + else + { + object.getRefData().setCount(origCount - mDragAndDrop->mDraggedCount); + } + std::cout << "container weight " << curWeight << "/" << capacity << std::endl; + } + else + { + int origCount = object.getRefData().getCount(); + object.getRefData().setCount (mDragAndDrop->mDraggedCount); + containerStore.add(object); + object.getRefData().setCount (origCount - mDragAndDrop->mDraggedCount); } } From c5d685c780c119f676c7bcff9dc53aa057f7a1db Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 16 May 2012 14:28:57 +0200 Subject: [PATCH 169/325] added an assert --- apps/openmw/mwgui/container.cpp | 6 ++++-- apps/openmw/mwgui/inventorywindow.cpp | 1 + apps/openmw/mwgui/window_manager.cpp | 2 ++ libs/openengine/gui/layout.hpp | 2 +- 4 files changed, 8 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index b7e0bf8b50..844d5d89a4 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -239,7 +239,9 @@ void ContainerBase::drawItems() for (std::vector::iterator it=unwantedItems.begin(); it != unwantedItems.end(); ++it) { - equippedItems.erase(std::find(unwantedItems.begin(), unwantedItems.end(), *it)); + std::vector::iterator found = std::find(unwantedItems.begin(), unwantedItems.end(), *it); + assert(found != unwantedItems.end()); + equippedItems.erase(found); } // and add the items that are left (= have the correct category) for (std::vector::const_iterator it=equippedItems.begin(); @@ -266,7 +268,7 @@ void ContainerBase::drawItems() if (mDragAndDrop->mIsOnDragAndDrop && *iter == *mDragAndDrop->mDraggedWidget->getUserData()) { displayCount -= mDragAndDrop->mDraggedCount; -} + } if(displayCount > 0 && !(onlyMagic && MWWorld::Class::get(*iter).getEnchantment(*iter) == "" && iter->getTypeName() != typeid(ESM::Potion).name())) { std::string path = std::string("icons\\"); diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index b3da52b02d..7160fa4f8c 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -209,6 +209,7 @@ namespace MWGui if (invStore.getSlot(*slot) == invStore.end()) { + // slot is not occupied invStore.equip(*slot, it); break; } diff --git a/apps/openmw/mwgui/window_manager.cpp b/apps/openmw/mwgui/window_manager.cpp index a4788ad3b0..5c005835c8 100644 --- a/apps/openmw/mwgui/window_manager.cpp +++ b/apps/openmw/mwgui/window_manager.cpp @@ -151,6 +151,8 @@ WindowManager::~WindowManager() delete mToolTips; delete mCharGen; delete mDragAndDrop; + delete mBookWindow; + delete mScrollWindow; cleanupGarbage(); } diff --git a/libs/openengine/gui/layout.hpp b/libs/openengine/gui/layout.hpp index abcc017539..d9eefe0510 100644 --- a/libs/openengine/gui/layout.hpp +++ b/libs/openengine/gui/layout.hpp @@ -71,7 +71,7 @@ namespace GUI void shutdown() { - MyGUI::LayoutManager::getInstance().unloadLayout(mListWindowRoot); + MyGUI::Gui::getInstance().destroyWidget(mMainWidget); mListWindowRoot.clear(); } From 6a0cb32b7ee781857cec0fcc4676ce3607bfb339 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 16 May 2012 14:30:02 +0200 Subject: [PATCH 170/325] removed unnecessary code --- apps/openmw/mwgui/container.cpp | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 844d5d89a4..bdb06dd26e 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -424,19 +424,16 @@ void ContainerWindow::onTakeAllButtonClicked(MyGUI::Widget* _sender) int i=0; for (MWWorld::ContainerStoreIterator iter (containerStore.begin()); iter!=containerStore.end(); ++iter) { - if(iter->getRefData().getCount() > 0) + playerStore.add(*iter); + + if (i==0) { - playerStore.add(*iter); - - if (i==0) - { - // play the sound of the first object - std::string sound = MWWorld::Class::get(*iter).getUpSoundId(*iter); - MWBase::Environment::get().getSoundManager()->playSound (sound, 1.0, 1.0); - } - - ++i; + // play the sound of the first object + std::string sound = MWWorld::Class::get(*iter).getUpSoundId(*iter); + MWBase::Environment::get().getSoundManager()->playSound (sound, 1.0, 1.0); } + + ++i; } containerStore.clear(); From 398a7dc65c0e8875f08d458661639d777abb9488 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 16 May 2012 14:32:48 +0200 Subject: [PATCH 171/325] crash fix (hopefully) --- apps/openmw/mwgui/container.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index bdb06dd26e..20bef98b9a 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -239,8 +239,8 @@ void ContainerBase::drawItems() for (std::vector::iterator it=unwantedItems.begin(); it != unwantedItems.end(); ++it) { - std::vector::iterator found = std::find(unwantedItems.begin(), unwantedItems.end(), *it); - assert(found != unwantedItems.end()); + std::vector::iterator found = std::find(equippedItems.begin(), equippedItems.end(), *it); + assert(found != equippedItems.end()); equippedItems.erase(found); } // and add the items that are left (= have the correct category) From 9a01e18b29f08eda5a2bb603c30b995df645975c Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 16 May 2012 15:00:20 +0200 Subject: [PATCH 172/325] fix some MessageBox code that was using deleted pointers sometimes --- apps/openmw/mwgui/messagebox.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/apps/openmw/mwgui/messagebox.cpp b/apps/openmw/mwgui/messagebox.cpp index c103bcb8b8..a6b9025ce4 100644 --- a/apps/openmw/mwgui/messagebox.cpp +++ b/apps/openmw/mwgui/messagebox.cpp @@ -15,6 +15,13 @@ void MessageBoxManager::onFrame (float frameDuration) std::vector::iterator it; for(it = mTimers.begin(); it != mTimers.end();) { + // if this messagebox is already deleted, remove the timer and move on + if (std::find(mMessageBoxes.begin(), mMessageBoxes.end(), it->messageBox) == mMessageBoxes.end()) + { + it = mTimers.erase(it); + continue; + } + it->current += frameDuration; if(it->current >= it->max) { From 9c4243782ee51dca419a617dc3d2677953fcbb17 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 16 May 2012 15:17:55 +0200 Subject: [PATCH 173/325] sorting items --- apps/openmw/mwgui/container.cpp | 52 +++++++++++++++++++++++++++++++-- 1 file changed, 50 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 20bef98b9a..8bb3976da6 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -26,6 +26,47 @@ using namespace MWGui; using namespace Widgets; +namespace +{ + bool compareType(std::string type1, std::string type2) + { + // this defines the sorting order of types. types that are first in the vector, appear before other types. + std::vector mapping; + mapping.push_back( typeid(ESM::Weapon).name() ); + mapping.push_back( typeid(ESM::Armor).name() ); + mapping.push_back( typeid(ESM::Clothing).name() ); + mapping.push_back( typeid(ESM::Potion).name() ); + mapping.push_back( typeid(ESM::Ingredient).name() ); + mapping.push_back( typeid(ESM::Apparatus).name() ); + mapping.push_back( typeid(ESM::Book).name() ); + mapping.push_back( typeid(ESM::Light).name() ); + mapping.push_back( typeid(ESM::Miscellaneous).name() ); + mapping.push_back( typeid(ESM::Tool).name() ); + mapping.push_back( typeid(ESM::Repair).name() ); + mapping.push_back( typeid(ESM::Probe).name() ); + + assert( std::find(mapping.begin(), mapping.end(), type1) != mapping.end() ); + assert( std::find(mapping.begin(), mapping.end(), type2) != mapping.end() ); + + return std::find(mapping.begin(), mapping.end(), type1) < std::find(mapping.begin(), mapping.end(), type2); + } + + bool sortItems(MWWorld::Ptr left, MWWorld::Ptr right) + { + if (left.getTypeName() == right.getTypeName()) + { + int cmp = MWWorld::Class::get(left).getName(left).compare( + MWWorld::Class::get(right).getName(right)); + return cmp < 0; + } + else + { + return compareType(left.getTypeName(), right.getTypeName()); + } + } +} + + ContainerBase::ContainerBase(DragAndDrop* dragAndDrop) : mDragAndDrop(dragAndDrop), mFilter(ContainerBase::Filter_All) @@ -251,11 +292,18 @@ void ContainerBase::drawItems() } // now add the regular items + std::vector regularItems; for (MWWorld::ContainerStoreIterator iter (containerStore.begin(categories)); iter!=containerStore.end(); ++iter) { - /// \todo sorting if (std::find(equippedItems.begin(), equippedItems.end(), *iter) == equippedItems.end()) - items.push_back( std::make_pair(*iter, ItemState_Normal) ); + regularItems.push_back(*iter); + } + + // sort them and add + std::sort(regularItems.begin(), regularItems.end(), sortItems); + for (std::vector::const_iterator it=regularItems.begin(); it!=regularItems.end(); ++it) + { + items.push_back( std::make_pair(*it, ItemState_Normal) ); } for (std::vector< std::pair >::const_iterator it=items.begin(); From 0f1e09d2c1959eeb42204d6b888c3108bb369f3f Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 16 May 2012 16:08:55 +0200 Subject: [PATCH 174/325] make Class::use method return an equip action for equippable items, add sound for equipping --- apps/openmw/CMakeLists.txt | 1 + apps/openmw/mwclass/armor.cpp | 8 +++ apps/openmw/mwclass/armor.hpp | 5 ++ apps/openmw/mwclass/clothing.cpp | 8 +++ apps/openmw/mwclass/clothing.hpp | 4 ++ apps/openmw/mwclass/weapon.cpp | 8 +++ apps/openmw/mwclass/weapon.hpp | 5 ++ apps/openmw/mwgui/inventorywindow.cpp | 79 +++++++-------------------- apps/openmw/mwworld/actionequip.cpp | 54 ++++++++++++++++++ apps/openmw/mwworld/actionequip.hpp | 21 +++++++ 10 files changed, 133 insertions(+), 60 deletions(-) create mode 100644 apps/openmw/mwworld/actionequip.cpp create mode 100644 apps/openmw/mwworld/actionequip.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 972c7f2e4c..c105f28b12 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -48,6 +48,7 @@ add_openmw_dir (mwworld refdata world physicssystem scene globals class action nullaction actionteleport containerstore actiontalk actiontake manualref player cellfunctors cells localscripts customdata weather inventorystore ptr actionopen actionread + actionequip ) add_openmw_dir (mwclass diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index abd351fb46..83c0120c78 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -9,6 +9,7 @@ #include "../mwworld/ptr.hpp" #include "../mwworld/actiontake.hpp" +#include "../mwworld/actionequip.hpp" #include "../mwworld/inventorystore.hpp" #include "../mwworld/world.hpp" @@ -264,4 +265,11 @@ namespace MWClass return ref->base->enchant; } + + boost::shared_ptr Armor::use (const MWWorld::Ptr& ptr) const + { + MWBase::Environment::get().getSoundManager()->playSound (getUpSoundId(ptr), 1.0, 1.0); + + return boost::shared_ptr(new MWWorld::ActionEquip(ptr)); + } } diff --git a/apps/openmw/mwclass/armor.hpp b/apps/openmw/mwclass/armor.hpp index 9842c50207..a638061625 100644 --- a/apps/openmw/mwclass/armor.hpp +++ b/apps/openmw/mwclass/armor.hpp @@ -61,6 +61,11 @@ namespace MWClass virtual std::string getEnchantment (const MWWorld::Ptr& ptr) const; ///< @return the enchantment ID if the object is enchanted, otherwise an empty string + + virtual boost::shared_ptr use (const MWWorld::Ptr& ptr) + const; + ///< Generate action for using via inventory menu + }; } diff --git a/apps/openmw/mwclass/clothing.cpp b/apps/openmw/mwclass/clothing.cpp index 181af35cd8..11b515faf7 100644 --- a/apps/openmw/mwclass/clothing.cpp +++ b/apps/openmw/mwclass/clothing.cpp @@ -9,6 +9,7 @@ #include "../mwworld/ptr.hpp" #include "../mwworld/actiontake.hpp" +#include "../mwworld/actionequip.hpp" #include "../mwworld/inventorystore.hpp" #include "../mwworld/world.hpp" @@ -217,4 +218,11 @@ namespace MWClass return ref->base->enchant; } + + boost::shared_ptr Clothing::use (const MWWorld::Ptr& ptr) const + { + MWBase::Environment::get().getSoundManager()->playSound (getUpSoundId(ptr), 1.0, 1.0); + + return boost::shared_ptr(new MWWorld::ActionEquip(ptr)); + } } diff --git a/apps/openmw/mwclass/clothing.hpp b/apps/openmw/mwclass/clothing.hpp index 64b857e26c..aba317be0e 100644 --- a/apps/openmw/mwclass/clothing.hpp +++ b/apps/openmw/mwclass/clothing.hpp @@ -55,6 +55,10 @@ namespace MWClass virtual std::string getEnchantment (const MWWorld::Ptr& ptr) const; ///< @return the enchantment ID if the object is enchanted, otherwise an empty string + + virtual boost::shared_ptr use (const MWWorld::Ptr& ptr) + const; + ///< Generate action for using via inventory menu }; } diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index ab5a57a3d4..482d618b01 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -9,6 +9,7 @@ #include "../mwworld/ptr.hpp" #include "../mwworld/actiontake.hpp" +#include "../mwworld/actionequip.hpp" #include "../mwworld/inventorystore.hpp" #include "../mwworld/world.hpp" @@ -355,4 +356,11 @@ namespace MWClass return ref->base->enchant; } + + boost::shared_ptr Weapon::use (const MWWorld::Ptr& ptr) const + { + MWBase::Environment::get().getSoundManager()->playSound (getUpSoundId(ptr), 1.0, 1.0); + + return boost::shared_ptr(new MWWorld::ActionEquip(ptr)); + } } diff --git a/apps/openmw/mwclass/weapon.hpp b/apps/openmw/mwclass/weapon.hpp index 9f9a3c4c85..92d703b4ae 100644 --- a/apps/openmw/mwclass/weapon.hpp +++ b/apps/openmw/mwclass/weapon.hpp @@ -61,6 +61,11 @@ namespace MWClass virtual std::string getEnchantment (const MWWorld::Ptr& ptr) const; ///< @return the enchantment ID if the object is enchanted, otherwise an empty string + + virtual boost::shared_ptr use (const MWWorld::Ptr& ptr) + const; + ///< Generate action for using via inventory menu + }; } diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 7160fa4f8c..9773867ec4 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -147,73 +147,32 @@ namespace MWGui { MWWorld::Ptr ptr = *mDragAndDrop->mDraggedWidget->getUserData(); - // can the object be equipped? - std::pair, bool> slots = MWWorld::Class::get(ptr).getEquipmentSlots(ptr); - if (slots.first.empty()) - { - // can't be equipped, try to use instead - boost::shared_ptr action = MWWorld::Class::get(ptr).use(ptr); - - action->execute(); - - /// \todo scripts - - // this is necessary for books/scrolls: if they are already in the player's inventory, - // the "Take" button should not be visible. - // NOTE: the take button is "reset" when the window opens, so we can safely do the following - // without screwing up future book windows - if (mDragAndDrop->mWasInInventory) - { - mWindowManager.getBookWindow()->setTakeButtonShow(false); - mWindowManager.getScrollWindow()->setTakeButtonShow(false); - } - } - else + if (mDragAndDrop->mDraggedFrom != this) { + // add item to the player's inventory MWWorld::InventoryStore& invStore = static_cast(MWWorld::Class::get(mContainer).getContainerStore(mContainer)); - MWWorld::ContainerStoreIterator it = invStore.begin(); - if (mDragAndDrop->mDraggedFrom != this) - { - // add item to the player's inventory - int origCount = ptr.getRefData().getCount(); - ptr.getRefData().setCount(origCount - mDragAndDrop->mDraggedCount); - it = invStore.add(ptr); - (*it).getRefData().setCount(mDragAndDrop->mDraggedCount); - } - else - { - // retrieve iterator to the item - for (; it != invStore.end(); ++it) - { - if (*it == ptr) - { - break; - } - } - } + int origCount = ptr.getRefData().getCount(); + ptr.getRefData().setCount(origCount - mDragAndDrop->mDraggedCount); + it = invStore.add(ptr); + (*it).getRefData().setCount(mDragAndDrop->mDraggedCount); + } - assert(it != invStore.end()); + /// \todo scripts - // equip the item in the first free slot - for (std::vector::const_iterator slot=slots.first.begin(); - slot!=slots.first.end(); ++slot) - { - // if all slots are occupied, replace the last slot - if (slot == --slots.first.end()) - { - invStore.equip(*slot, it); - break; - } + boost::shared_ptr action = MWWorld::Class::get(ptr).use(ptr); + + action->execute(); - if (invStore.getSlot(*slot) == invStore.end()) - { - // slot is not occupied - invStore.equip(*slot, it); - break; - } - } + // this is necessary for books/scrolls: if they are already in the player's inventory, + // the "Take" button should not be visible. + // NOTE: the take button is "reset" when the window opens, so we can safely do the following + // without screwing up future book windows + if (mDragAndDrop->mWasInInventory) + { + mWindowManager.getBookWindow()->setTakeButtonShow(false); + mWindowManager.getScrollWindow()->setTakeButtonShow(false); } mDragAndDrop->mIsOnDragAndDrop = false; diff --git a/apps/openmw/mwworld/actionequip.cpp b/apps/openmw/mwworld/actionequip.cpp new file mode 100644 index 0000000000..f3bb256fd8 --- /dev/null +++ b/apps/openmw/mwworld/actionequip.cpp @@ -0,0 +1,54 @@ +#include "actionequip.hpp" + +#include "../mwbase/environment.hpp" +#include "../mwworld/world.hpp" +#include "../mwworld/inventorystore.hpp" +#include "../mwworld/player.hpp" + +namespace MWWorld +{ + ActionEquip::ActionEquip (const MWWorld::Ptr& object) : mObject (object) + { + } + + void ActionEquip::execute () + { + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + MWWorld::InventoryStore& invStore = static_cast(MWWorld::Class::get(player).getContainerStore(player)); + + // slots that this item can be equipped in + std::pair, bool> slots = MWWorld::Class::get(mObject).getEquipmentSlots(mObject); + + // retrieve ContainerStoreIterator to the item + MWWorld::ContainerStoreIterator it = invStore.begin(); + for (; it != invStore.end(); ++it) + { + if (*it == mObject) + { + break; + } + } + + assert(it != invStore.end()); + + // equip the item in the first free slot + for (std::vector::const_iterator slot=slots.first.begin(); + slot!=slots.first.end(); ++slot) + { + // if all slots are occupied, replace the last slot + if (slot == --slots.first.end()) + { + invStore.equip(*slot, it); + break; + } + + if (invStore.getSlot(*slot) == invStore.end()) + { + // slot is not occupied + invStore.equip(*slot, it); + break; + } + } + } +} + diff --git a/apps/openmw/mwworld/actionequip.hpp b/apps/openmw/mwworld/actionequip.hpp new file mode 100644 index 0000000000..6cf3640f8b --- /dev/null +++ b/apps/openmw/mwworld/actionequip.hpp @@ -0,0 +1,21 @@ +#ifndef GAME_MWWORLD_ACTIONEQUIP_H +#define GAME_MWWORLD_ACTIONEQUIP_H + +#include "action.hpp" +#include "ptr.hpp" + +namespace MWWorld +{ + class ActionEquip : public Action + { + Ptr mObject; + + public: + /// @param item to equip + ActionEquip (const Ptr& object); + + virtual void execute (); + }; +} + +#endif From 4b5d6ce311f7c31461951ebb7675344931eb30f7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 16 May 2012 17:22:25 +0200 Subject: [PATCH 175/325] allow stacking gold --- apps/openmw/mwclass/misc.cpp | 18 +++++++++++----- apps/openmw/mwworld/containerstore.cpp | 29 ++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwclass/misc.cpp b/apps/openmw/mwclass/misc.cpp index 936dc4558d..d8e0553b9e 100644 --- a/apps/openmw/mwclass/misc.cpp +++ b/apps/openmw/mwclass/misc.cpp @@ -1,6 +1,8 @@ #include "misc.hpp" +#include + #include #include @@ -142,12 +144,18 @@ namespace MWClass const ESMS::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); int count = ptr.getRefData().getCount(); - // gold has count both as reference count and as value, multiply them together to get real count - bool isGold = (ref->base->name == store.gameSettings.search("sGold")->str); - if (isGold) - count *= ref->base->data.value; - info.caption = ref->base->name + MWGui::ToolTips::getCountString(count); + bool isGold = (ref->base->name == store.gameSettings.search("sGold")->str); + if (isGold && count == 1) + count = ref->base->data.value; + + std::string countString; + if (!isGold) + countString = MWGui::ToolTips::getCountString(count); + else // gold displays its count also if it's 1. + countString = " (" + boost::lexical_cast(count) + ")"; + + info.caption = ref->base->name + countString; info.icon = ref->base->icon; if (ref->ref.soul != "") diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index eca7206030..9b5afea740 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -7,6 +7,9 @@ #include +#include "../mwbase/environment.hpp" +#include "../mwworld/world.hpp" + #include "manualref.hpp" #include "refdata.hpp" #include "class.hpp" @@ -62,6 +65,32 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::add (const Ptr& ptr) { int type = getType(ptr); + // gold needs special treatment because it uses several different meshes + if (MWWorld::Class::get(ptr).getName(ptr) == MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sGold")->str) + { + ESMS::LiveCellRef *gold = + ptr.get(); + + int goldValue = (ptr.getRefData().getCount() == 1) ? gold->base->data.value : ptr.getRefData().getCount(); + + for (MWWorld::ContainerStoreIterator iter (begin(type)); iter!=end(); ++iter) + { + if (MWWorld::Class::get(*iter).getName(*iter) == MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sGold")->str) + { + ESMS::LiveCellRef *ref = + iter->get(); + + if (iter->getRefData().getCount() == 1) + iter->getRefData().setCount(ref->base->data.value + goldValue); + else + iter->getRefData().setCount(iter->getRefData().getCount() + goldValue); + + flagAsModified(); + return iter; + } + } + } + // determine whether to stack or not for (MWWorld::ContainerStoreIterator iter (begin(type)); iter!=end(); ++iter) { From 6d34e61dbd2d34a25d7194ea5507048747d7ea38 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 16 May 2012 19:18:50 +0200 Subject: [PATCH 176/325] don't stack gold if it has a script (not used in MW, but some mods might) --- apps/openmw/mwworld/containerstore.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index 9b5afea740..5dfc9a1777 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -75,7 +75,8 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::add (const Ptr& ptr) for (MWWorld::ContainerStoreIterator iter (begin(type)); iter!=end(); ++iter) { - if (MWWorld::Class::get(*iter).getName(*iter) == MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sGold")->str) + if (MWWorld::Class::get(*iter).getName(*iter) == MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sGold")->str + && MWWorld::Class::get(*iter).getScript(*iter) == "" && MWWorld::Class::get(ptr).getScript(ptr) == "") { ESMS::LiveCellRef *ref = iter->get(); @@ -89,6 +90,10 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::add (const Ptr& ptr) return iter; } } + + // if we get here, no already existing gold was found in the container + // we still need special handling because gold in a container should always have the real gold value as reference count. + ptr.getRefData().setCount(goldValue); } // determine whether to stack or not From f73d3ad33fa79fd99ce49ce549a98e313de48f4b Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 16 May 2012 21:27:02 +0200 Subject: [PATCH 177/325] fix to the "drop object on ground" feature. still crashes for gold. --- apps/openmw/mwworld/scene.cpp | 91 ++++++++++++++++++++++++++++------- apps/openmw/mwworld/world.cpp | 24 ++++++++- 2 files changed, 96 insertions(+), 19 deletions(-) diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 1d4f078d5a..311f8770bb 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -328,41 +328,96 @@ namespace MWWorld void Scene::insertObject(MWWorld::Ptr ptr, Ptr::CellStore* cell) { - ptr.mCell = cell; - - mRendering.addObject(ptr); - MWWorld::Class::get(ptr).insertObject(ptr, *mPhysics); - MWWorld::Class::get(ptr).enable(ptr); - std::string type = ptr.getTypeName(); + MWWorld::Ptr newPtr; + // insert into the correct CellRefList if (type == typeid(ESM::Potion).name()) - cell->potions.list.push_back( *ptr.get() ); + { + ESMS::LiveCellRef* ref = ptr.get(); + newPtr = MWWorld::Ptr(ref, cell); + cell->potions.list.push_back( *ref ); + } else if (type == typeid(ESM::Apparatus).name()) - cell->appas.list.push_back( *ptr.get() ); + { + ESMS::LiveCellRef* ref = ptr.get(); + newPtr = MWWorld::Ptr(ref, cell); + cell->appas.list.push_back( *ref ); + } else if (type == typeid(ESM::Armor).name()) - cell->armors.list.push_back( *ptr.get() ); + { + ESMS::LiveCellRef* ref = ptr.get(); + newPtr = MWWorld::Ptr(ref, cell); + cell->armors.list.push_back( *ref ); + } else if (type == typeid(ESM::Book).name()) - cell->books.list.push_back( *ptr.get() ); + { + ESMS::LiveCellRef* ref = ptr.get(); + newPtr = MWWorld::Ptr(ref, cell); + cell->books.list.push_back( *ref ); + } else if (type == typeid(ESM::Clothing).name()) - cell->clothes.list.push_back( *ptr.get() ); + { + ESMS::LiveCellRef* ref = ptr.get(); + newPtr = MWWorld::Ptr(ref, cell); + cell->clothes.list.push_back( *ref ); + } else if (type == typeid(ESM::Ingredient).name()) - cell->ingreds.list.push_back( *ptr.get() ); + { + ESMS::LiveCellRef* ref = ptr.get(); + newPtr = MWWorld::Ptr(ref, cell); + cell->ingreds.list.push_back( *ref ); + } else if (type == typeid(ESM::Light).name()) - cell->lights.list.push_back( *ptr.get() ); + { + ESMS::LiveCellRef* ref = ptr.get(); + newPtr = MWWorld::Ptr(ref, cell); + cell->lights.list.push_back( *ref ); + } else if (type == typeid(ESM::Tool).name()) - cell->lockpicks.list.push_back( *ptr.get() ); + { + ESMS::LiveCellRef* ref = ptr.get(); + newPtr = MWWorld::Ptr(ref, cell); + cell->lockpicks.list.push_back( *ref ); + } else if (type == typeid(ESM::Repair).name()) - cell->repairs.list.push_back( *ptr.get() ); + { + ESMS::LiveCellRef* ref = ptr.get(); + newPtr = MWWorld::Ptr(ref, cell); + cell->repairs.list.push_back( *ref ); + } else if (type == typeid(ESM::Probe).name()) - cell->probes.list.push_back( *ptr.get() ); + { + ESMS::LiveCellRef* ref = ptr.get(); + newPtr = MWWorld::Ptr(ref, cell); + cell->probes.list.push_back( *ref ); + } else if (type == typeid(ESM::Weapon).name()) - cell->weapons.list.push_back( *ptr.get() ); + { + ESMS::LiveCellRef* ref = ptr.get(); + newPtr = MWWorld::Ptr(ref, cell); + cell->weapons.list.push_back( *ref ); + } else if (type == typeid(ESM::Miscellaneous).name()) - cell->miscItems.list.push_back( *ptr.get() ); + { + ESMS::LiveCellRef* ref = ptr.get(); + cell->miscItems.list.push_back( *ref ); + newPtr = MWWorld::Ptr(&cell->miscItems.list.back(), cell); + } else throw std::runtime_error("Trying to insert object of unhandled type"); + + + + newPtr.getRefData().setCount(ptr.getRefData().getCount()); + ptr.getRefData().setCount(0); + newPtr.getRefData().enable(); + + mRendering.addObject(newPtr); + MWWorld::Class::get(newPtr).insertObject(newPtr, *mPhysics); + MWWorld::Class::get(newPtr).enable(newPtr); + } } diff --git a/apps/openmw/mwworld/world.cpp b/apps/openmw/mwworld/world.cpp index 973407b0c6..0672d5f3b2 100644 --- a/apps/openmw/mwworld/world.cpp +++ b/apps/openmw/mwworld/world.cpp @@ -21,7 +21,7 @@ #include "class.hpp" #include "player.hpp" #include "weather.hpp" - +#include "manualref.hpp" #include "refdata.hpp" #include "globals.hpp" #include "cellfunctors.hpp" @@ -982,6 +982,28 @@ namespace MWWorld else cell = getPlayer().getPlayer().getCell(); + // if this is gold, we need to fetch the correct mesh depending on the amount of gold. + if (MWWorld::Class::get(object).getName(object) == getStore().gameSettings.search("sGold")->str) + { + int goldAmount = object.getRefData().getCount(); + + std::string base = "Gold_001"; + if (goldAmount >= 5) + base = "Gold_005"; + else if (goldAmount >= 10) + base = "Gold_010"; + else if (goldAmount >= 25) + base = "Gold_025"; + else if (goldAmount >= 100) + base = "Gold_100"; + + std::cout << "using " << base << std::endl; + MWWorld::ManualRef newRef (getStore(), base); + object = newRef.getPtr(); + object.getRefData().setCount(goldAmount); + object.mCell = cell; + } + ESM::Position& pos = object.getRefData().getPosition(); pos.pos[0] = result.second[0]; pos.pos[1] = -result.second[2]; From 5875ce51286fca173550d8ddea8c880ecac7710f Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 16 May 2012 22:13:56 +0200 Subject: [PATCH 178/325] select the correct gold base object (still crashing) --- apps/openmw/mwworld/world.cpp | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwworld/world.cpp b/apps/openmw/mwworld/world.cpp index 0672d5f3b2..2f8deeff99 100644 --- a/apps/openmw/mwworld/world.cpp +++ b/apps/openmw/mwworld/world.cpp @@ -988,20 +988,19 @@ namespace MWWorld int goldAmount = object.getRefData().getCount(); std::string base = "Gold_001"; - if (goldAmount >= 5) - base = "Gold_005"; - else if (goldAmount >= 10) - base = "Gold_010"; + if (goldAmount >= 100) + base = "Gold_100"; else if (goldAmount >= 25) base = "Gold_025"; - else if (goldAmount >= 100) - base = "Gold_100"; + else if (goldAmount >= 10) + base = "Gold_010"; + else if (goldAmount >= 5) + base = "Gold_005"; std::cout << "using " << base << std::endl; MWWorld::ManualRef newRef (getStore(), base); object = newRef.getPtr(); object.getRefData().setCount(goldAmount); - object.mCell = cell; } ESM::Position& pos = object.getRefData().getPosition(); From 178ad876d74acc405026e604c780f391f56bcbcc Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 16 May 2012 22:17:13 +0200 Subject: [PATCH 179/325] fix for objects other than Miscellaneous. --- apps/openmw/mwworld/scene.cpp | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 311f8770bb..8fa7658c6c 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -336,68 +336,68 @@ namespace MWWorld if (type == typeid(ESM::Potion).name()) { ESMS::LiveCellRef* ref = ptr.get(); - newPtr = MWWorld::Ptr(ref, cell); cell->potions.list.push_back( *ref ); + newPtr = MWWorld::Ptr(&cell->potions.list.back(), cell); } else if (type == typeid(ESM::Apparatus).name()) { ESMS::LiveCellRef* ref = ptr.get(); - newPtr = MWWorld::Ptr(ref, cell); cell->appas.list.push_back( *ref ); + newPtr = MWWorld::Ptr(&cell->appas.list.back(), cell); } else if (type == typeid(ESM::Armor).name()) { ESMS::LiveCellRef* ref = ptr.get(); - newPtr = MWWorld::Ptr(ref, cell); cell->armors.list.push_back( *ref ); + newPtr = MWWorld::Ptr(&cell->armors.list.back(), cell); } else if (type == typeid(ESM::Book).name()) { ESMS::LiveCellRef* ref = ptr.get(); - newPtr = MWWorld::Ptr(ref, cell); cell->books.list.push_back( *ref ); + newPtr = MWWorld::Ptr(&cell->books.list.back(), cell); } else if (type == typeid(ESM::Clothing).name()) { ESMS::LiveCellRef* ref = ptr.get(); - newPtr = MWWorld::Ptr(ref, cell); cell->clothes.list.push_back( *ref ); + newPtr = MWWorld::Ptr(&cell->clothes.list.back(), cell); } else if (type == typeid(ESM::Ingredient).name()) { ESMS::LiveCellRef* ref = ptr.get(); - newPtr = MWWorld::Ptr(ref, cell); cell->ingreds.list.push_back( *ref ); + newPtr = MWWorld::Ptr(&cell->ingreds.list.back(), cell); } else if (type == typeid(ESM::Light).name()) { ESMS::LiveCellRef* ref = ptr.get(); - newPtr = MWWorld::Ptr(ref, cell); cell->lights.list.push_back( *ref ); + newPtr = MWWorld::Ptr(&cell->lights.list.back(), cell); } else if (type == typeid(ESM::Tool).name()) { ESMS::LiveCellRef* ref = ptr.get(); - newPtr = MWWorld::Ptr(ref, cell); cell->lockpicks.list.push_back( *ref ); + newPtr = MWWorld::Ptr(&cell->lockpicks.list.back(), cell); } else if (type == typeid(ESM::Repair).name()) { ESMS::LiveCellRef* ref = ptr.get(); - newPtr = MWWorld::Ptr(ref, cell); cell->repairs.list.push_back( *ref ); + newPtr = MWWorld::Ptr(&cell->repairs.list.back(), cell); } else if (type == typeid(ESM::Probe).name()) { ESMS::LiveCellRef* ref = ptr.get(); - newPtr = MWWorld::Ptr(ref, cell); cell->probes.list.push_back( *ref ); + newPtr = MWWorld::Ptr(&cell->probes.list.back(), cell); } else if (type == typeid(ESM::Weapon).name()) { ESMS::LiveCellRef* ref = ptr.get(); - newPtr = MWWorld::Ptr(ref, cell); cell->weapons.list.push_back( *ref ); + newPtr = MWWorld::Ptr(&cell->weapons.list.back(), cell); } else if (type == typeid(ESM::Miscellaneous).name()) { From fca9f1fc5f29de49e4767656b61e819d0f9da941 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 16 May 2012 22:56:54 +0200 Subject: [PATCH 180/325] gold dropping works without crash, but the code needs clean up. --- apps/openmw/mwworld/scene.cpp | 43 ++++++++++++++++++++++++++++++++--- apps/openmw/mwworld/world.cpp | 21 ----------------- 2 files changed, 40 insertions(+), 24 deletions(-) diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 8fa7658c6c..af7e21d7f5 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -9,6 +9,9 @@ #include "../mwgui/window_manager.hpp" +#include "../mwworld/world.hpp" /// FIXME +#include "../mwworld/manualref.hpp" /// FIXME + #include "ptr.hpp" #include "player.hpp" #include "class.hpp" @@ -326,6 +329,8 @@ namespace MWWorld insertCellRefList(mRendering, cell.weapons, cell, *mPhysics); } + + /// \todo this whole code needs major clean up, and doesn't belong in this class. void Scene::insertObject(MWWorld::Ptr ptr, Ptr::CellStore* cell) { std::string type = ptr.getTypeName(); @@ -401,9 +406,41 @@ namespace MWWorld } else if (type == typeid(ESM::Miscellaneous).name()) { - ESMS::LiveCellRef* ref = ptr.get(); - cell->miscItems.list.push_back( *ref ); - newPtr = MWWorld::Ptr(&cell->miscItems.list.back(), cell); + + // if this is gold, we need to fetch the correct mesh depending on the amount of gold. + if (MWWorld::Class::get(ptr).getName(ptr) == MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sGold")->str) + { + int goldAmount = ptr.getRefData().getCount(); + + std::string base = "Gold_001"; + if (goldAmount >= 100) + base = "Gold_100"; + else if (goldAmount >= 25) + base = "Gold_025"; + else if (goldAmount >= 10) + base = "Gold_010"; + else if (goldAmount >= 5) + base = "Gold_005"; + + MWWorld::ManualRef newRef (MWBase::Environment::get().getWorld()->getStore(), base); + + ESMS::LiveCellRef* ref = newRef.getPtr().get(); + + cell->miscItems.list.push_back( *ref ); + newPtr = MWWorld::Ptr(&cell->miscItems.list.back(), cell); + + ESM::Position& p = newPtr.getRefData().getPosition(); + p.pos[0] = ptr.getRefData().getPosition().pos[0]; + p.pos[1] = ptr.getRefData().getPosition().pos[1]; + p.pos[2] = ptr.getRefData().getPosition().pos[2]; + } + else + { + ESMS::LiveCellRef* ref = ptr.get(); + + cell->miscItems.list.push_back( *ref ); + newPtr = MWWorld::Ptr(&cell->miscItems.list.back(), cell); + } } else throw std::runtime_error("Trying to insert object of unhandled type"); diff --git a/apps/openmw/mwworld/world.cpp b/apps/openmw/mwworld/world.cpp index 2f8deeff99..b324ee1a0d 100644 --- a/apps/openmw/mwworld/world.cpp +++ b/apps/openmw/mwworld/world.cpp @@ -982,27 +982,6 @@ namespace MWWorld else cell = getPlayer().getPlayer().getCell(); - // if this is gold, we need to fetch the correct mesh depending on the amount of gold. - if (MWWorld::Class::get(object).getName(object) == getStore().gameSettings.search("sGold")->str) - { - int goldAmount = object.getRefData().getCount(); - - std::string base = "Gold_001"; - if (goldAmount >= 100) - base = "Gold_100"; - else if (goldAmount >= 25) - base = "Gold_025"; - else if (goldAmount >= 10) - base = "Gold_010"; - else if (goldAmount >= 5) - base = "Gold_005"; - - std::cout << "using " << base << std::endl; - MWWorld::ManualRef newRef (getStore(), base); - object = newRef.getPtr(); - object.getRefData().setCount(goldAmount); - } - ESM::Position& pos = object.getRefData().getPosition(); pos.pos[0] = result.second[0]; pos.pos[1] = -result.second[2]; From c5185cf2e4f750845594986e0ee87edf74148e22 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 17 May 2012 12:09:53 +0200 Subject: [PATCH 181/325] drop item on avatar from external container bugfix --- apps/openmw/mwgui/container.cpp | 2 -- apps/openmw/mwgui/container.hpp | 6 ------ apps/openmw/mwgui/inventorywindow.cpp | 3 ++- 3 files changed, 2 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 8bb3976da6..3656a89190 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -136,8 +136,6 @@ void ContainerBase::onSelectedItemImpl(MyGUI::Widget* _sender, int count) static_cast(mSelectedItem->getChildAt(0)->getChildAt(0))->setCaption( getCountString(mDragAndDrop->mDraggedCount)); - mDragAndDrop->mWasInInventory = isInventory(); - drawItems(); MWBase::Environment::get().getWindowManager()->setDragDrop(true); diff --git a/apps/openmw/mwgui/container.hpp b/apps/openmw/mwgui/container.hpp index 174f18f9a5..fe4ffc285c 100644 --- a/apps/openmw/mwgui/container.hpp +++ b/apps/openmw/mwgui/container.hpp @@ -36,17 +36,11 @@ namespace MWGui class DragAndDrop { public: - DragAndDrop() : - mWasInInventory(false) - { - } - bool mIsOnDragAndDrop; MyGUI::Widget* mDraggedWidget; MyGUI::Widget* mDragAndDropWidget; ContainerBase* mDraggedFrom; int mDraggedCount; - bool mWasInInventory; // was the item in inventory before it was dragged }; class ContainerBase diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 9773867ec4..4f16152ea9 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -157,6 +157,7 @@ namespace MWGui ptr.getRefData().setCount(origCount - mDragAndDrop->mDraggedCount); it = invStore.add(ptr); (*it).getRefData().setCount(mDragAndDrop->mDraggedCount); + ptr = *it; } /// \todo scripts @@ -169,7 +170,7 @@ namespace MWGui // the "Take" button should not be visible. // NOTE: the take button is "reset" when the window opens, so we can safely do the following // without screwing up future book windows - if (mDragAndDrop->mWasInInventory) + if (mDragAndDrop->mDraggedFrom == this) { mWindowManager.getBookWindow()->setTakeButtonShow(false); mWindowManager.getScrollWindow()->setTakeButtonShow(false); From 8cc49ae2b9a0976a8b88ace36c9710010bbb873b Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 17 May 2012 12:55:48 +0200 Subject: [PATCH 182/325] xml files update (layout tweak, added double quotation marks to font) --- files/mygui/openmw.font.xml | 1 + files/mygui/openmw_container_window_layout.xml | 6 +++--- files/mygui/openmw_inventory_window_layout.xml | 5 +++-- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/files/mygui/openmw.font.xml b/files/mygui/openmw.font.xml index 252499a5f1..73d491e04e 100644 --- a/files/mygui/openmw.font.xml +++ b/files/mygui/openmw.font.xml @@ -13,6 +13,7 @@ + diff --git a/files/mygui/openmw_container_window_layout.xml b/files/mygui/openmw_container_window_layout.xml index 7b14f5b580..cb66fadc1f 100644 --- a/files/mygui/openmw_container_window_layout.xml +++ b/files/mygui/openmw_container_window_layout.xml @@ -5,9 +5,9 @@ - - - + + + diff --git a/files/mygui/openmw_inventory_window_layout.xml b/files/mygui/openmw_inventory_window_layout.xml index cd6e1469e4..4d63b03c2a 100644 --- a/files/mygui/openmw_inventory_window_layout.xml +++ b/files/mygui/openmw_inventory_window_layout.xml @@ -27,8 +27,9 @@ - - + + + From 630241c8e2c95c6c0ab01ea681e3cb6c796653ca Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 17 May 2012 13:12:38 +0200 Subject: [PATCH 183/325] load the AIDT (AI data) for creatures in the ESM loader, which also contains the Services enum. --- apps/openmw/mwgui/dialogue.cpp | 2 ++ apps/openmw/mwgui/list.cpp | 7 ------- apps/openmw/mwgui/list.hpp | 2 +- components/esm/loadcrea.cpp | 12 +++++++++--- components/esm/loadcrea.hpp | 12 ++++++++++++ 5 files changed, 24 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 45163017a6..1116eb272f 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -145,6 +145,7 @@ void DialogueWindow::setKeywords(std::list keyWords) { topicsList->addItem(*it); } + topicsList->adjustSize(); } void DialogueWindow::removeKeyword(std::string keyWord) @@ -154,6 +155,7 @@ void DialogueWindow::removeKeyword(std::string keyWord) topicsList->removeItem(keyWord); pTopicsText.erase(keyWord); } + topicsList->adjustSize(); } void addColorInString(std::string& str, const std::string& keyword,std::string color1, std::string color2) diff --git a/apps/openmw/mwgui/list.cpp b/apps/openmw/mwgui/list.cpp index d66cc6f89b..33f5a6fd1b 100644 --- a/apps/openmw/mwgui/list.cpp +++ b/apps/openmw/mwgui/list.cpp @@ -28,8 +28,6 @@ void MWList::initialiseOverride() void MWList::addItem(const std::string& name) { mItems.push_back(name); - - redraw(); } void MWList::adjustSize() @@ -67,7 +65,6 @@ void MWList::redraw(bool scrollbarShown) mItemHeight += height + spacing; } mScrollView->setCanvasSize(mClient->getSize().width + (_scrollBarWidth-scrollBarWidth), std::max(mItemHeight, mClient->getSize().height)); - mScrollView->setViewOffset(MyGUI::IntPoint(0,0)); if (!scrollbarShown && mItemHeight > mClient->getSize().height) redraw(true); @@ -93,15 +90,11 @@ void MWList::removeItem(const std::string& name) { assert( std::find(mItems.begin(), mItems.end(), name) != mItems.end() ); mItems.erase( std::find(mItems.begin(), mItems.end(), name) ); - - redraw(); } void MWList::clear() { mItems.clear(); - - redraw(); } void MWList::onMouseWheel(MyGUI::Widget* _sender, int _rel) diff --git a/apps/openmw/mwgui/list.hpp b/apps/openmw/mwgui/list.hpp index a2e9afcd1e..76ca5257fa 100644 --- a/apps/openmw/mwgui/list.hpp +++ b/apps/openmw/mwgui/list.hpp @@ -26,7 +26,7 @@ namespace MWGui EventHandle_String eventItemSelected; /** - * Call after the size of the list changed + * Call after the size of the list changed, or items were inserted/removed */ void adjustSize(); diff --git a/components/esm/loadcrea.cpp b/components/esm/loadcrea.cpp index 651d9a3181..8af3526a0f 100644 --- a/components/esm/loadcrea.cpp +++ b/components/esm/loadcrea.cpp @@ -19,9 +19,15 @@ void Creature::load(ESMReader &esm, const std::string& id) inventory.load(esm); - // More subrecords: + if (esm.isNextSub("AIDT")) + { + esm.getHExact(&AI, sizeof(AI)); + hasAI = true; + } + else + hasAI = false; - // AIDT - data (12 bytes, unknown) + // More subrecords: // AI_W - wander (14 bytes, i don't understand it) // short distance // byte duration @@ -33,8 +39,8 @@ void Creature::load(ESMReader &esm, const std::string& id) // AI_F - follow? // AI_E - escort? // AI_A - activate? - esm.skipRecord(); + } } diff --git a/components/esm/loadcrea.hpp b/components/esm/loadcrea.hpp index 3c334ebbd4..c3c5b181e0 100644 --- a/components/esm/loadcrea.hpp +++ b/components/esm/loadcrea.hpp @@ -51,6 +51,15 @@ struct Creature int gold; }; // 96 bytes + struct AIDTstruct + { + // These are probabilities + char hello, u1, fight, flee, alarm, u2, u3, u4; + // The last u's might be the skills that this NPC can train you + // in? + int services; // See the NPC::Services enum + }; // 12 bytes + NPDTstruct data; int flags; @@ -61,6 +70,9 @@ struct Creature // Defined in loadcont.hpp InventoryList inventory; + bool hasAI; + AIDTstruct AI; + std::string mId; void load(ESMReader &esm, const std::string& id); From 1fddbf9a4034fc83717e05608c9c5d3a1becd3b8 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 17 May 2012 13:15:31 +0200 Subject: [PATCH 184/325] Issue #256: moved dynamic stats update from MechanicsManager to Actors --- apps/openmw/mwmechanics/actors.cpp | 19 +++++++++++++++++++ apps/openmw/mwmechanics/mechanicsmanager.cpp | 17 ----------------- 2 files changed, 19 insertions(+), 17 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 849ab8ea4c..d7e879b229 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -8,11 +8,30 @@ #include "../mwworld/class.hpp" #include "../mwworld/inventorystore.hpp" +#include "creaturestats.hpp" + namespace MWMechanics { void Actors::updateActor (const MWWorld::Ptr& ptr, float duration) { + MWMechanics::CreatureStats& creatureStats = MWWorld::Class::get (ptr).getCreatureStats (ptr); + // calculate dynamic stats + int strength = creatureStats.mAttributes[0].getBase(); + int intelligence = creatureStats.mAttributes[1].getBase(); + int willpower = creatureStats.mAttributes[2].getBase(); + int agility = creatureStats.mAttributes[3].getBase(); + int endurance = creatureStats.mAttributes[5].getBase(); + + double magickaFactor = creatureStats.mMagicEffects.get (EffectKey (84)).mMagnitude*0.1 + 0.5; + + creatureStats.mDynamic[0].setBase (static_cast (0.5 * (strength + endurance))); + creatureStats.mDynamic[1].setBase (static_cast (intelligence + + magickaFactor * intelligence)); + creatureStats.mDynamic[2].setBase (strength+willpower+agility+endurance); + + for (int i=0; i<3; ++i) + creatureStats.mDynamic[i].setCurrent (creatureStats.mDynamic[i].getModified()); } void Actors::updateNpc (const MWWorld::Ptr& ptr, float duration, bool paused) diff --git a/apps/openmw/mwmechanics/mechanicsmanager.cpp b/apps/openmw/mwmechanics/mechanicsmanager.cpp index 8bc408be6f..073604b015 100644 --- a/apps/openmw/mwmechanics/mechanicsmanager.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanager.cpp @@ -141,23 +141,6 @@ namespace MWMechanics // magic effects adjustMagicEffects (ptr); - - // calculate dynamic stats - int strength = creatureStats.mAttributes[0].getBase(); - int intelligence = creatureStats.mAttributes[1].getBase(); - int willpower = creatureStats.mAttributes[2].getBase(); - int agility = creatureStats.mAttributes[3].getBase(); - int endurance = creatureStats.mAttributes[5].getBase(); - - double magickaFactor = creatureStats.mMagicEffects.get (EffectKey (84)).mMagnitude*0.1 + 0.5; - - creatureStats.mDynamic[0].setBase (static_cast (0.5 * (strength + endurance))); - creatureStats.mDynamic[1].setBase (static_cast (intelligence + - magickaFactor * intelligence)); - creatureStats.mDynamic[2].setBase (strength+willpower+agility+endurance); - - for (int i=0; i<3; ++i) - creatureStats.mDynamic[i].setCurrent (creatureStats.mDynamic[i].getModified()); } void MechanicsManager::adjustMagicEffects (MWWorld::Ptr& creature) From e56ff9283dfa6849ebb9caeb6758065ff39a5cc6 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 17 May 2012 13:21:49 +0200 Subject: [PATCH 185/325] Issue #256: moved magic effects update from MechanicsManager to Actors --- apps/openmw/mwmechanics/actors.cpp | 20 +++++++++++++++++++- apps/openmw/mwmechanics/actors.hpp | 2 ++ apps/openmw/mwmechanics/mechanicsmanager.cpp | 18 ------------------ apps/openmw/mwmechanics/mechanicsmanager.hpp | 2 -- 4 files changed, 21 insertions(+), 21 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index d7e879b229..b0bb1e3ef9 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -14,7 +14,10 @@ namespace MWMechanics { void Actors::updateActor (const MWWorld::Ptr& ptr, float duration) { - MWMechanics::CreatureStats& creatureStats = MWWorld::Class::get (ptr).getCreatureStats (ptr); + // magic effects + adjustMagicEffects (ptr); + + CreatureStats& creatureStats = MWWorld::Class::get (ptr).getCreatureStats (ptr); // calculate dynamic stats int strength = creatureStats.mAttributes[0].getBase(); @@ -41,6 +44,21 @@ namespace MWMechanics MWWorld::Class::get (ptr).getNpcStats (ptr)); } + void Actors::adjustMagicEffects (const MWWorld::Ptr& creature) + { + CreatureStats& creatureStats = MWWorld::Class::get (creature).getCreatureStats (creature); + + MagicEffects now = creatureStats.mSpells.getMagicEffects(); + + /// \todo add effects from active spells and equipment + + MagicEffects diff = MagicEffects::diff (creatureStats.mMagicEffects, now); + + creatureStats.mMagicEffects = now; + + // TODO apply diff to other stats + } + Actors::Actors() : mDuration (0) {} void Actors::addActor (const MWWorld::Ptr& ptr) diff --git a/apps/openmw/mwmechanics/actors.hpp b/apps/openmw/mwmechanics/actors.hpp index ae93fb52ee..37a00deecc 100644 --- a/apps/openmw/mwmechanics/actors.hpp +++ b/apps/openmw/mwmechanics/actors.hpp @@ -23,6 +23,8 @@ namespace MWMechanics void updateNpc (const MWWorld::Ptr& ptr, float duration, bool paused); + void adjustMagicEffects (const MWWorld::Ptr& creature); + public: Actors(); diff --git a/apps/openmw/mwmechanics/mechanicsmanager.cpp b/apps/openmw/mwmechanics/mechanicsmanager.cpp index 073604b015..66a850b051 100644 --- a/apps/openmw/mwmechanics/mechanicsmanager.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanager.cpp @@ -138,26 +138,8 @@ namespace MWMechanics } } } - - // magic effects - adjustMagicEffects (ptr); } - void MechanicsManager::adjustMagicEffects (MWWorld::Ptr& creature) - { - MWMechanics::CreatureStats& creatureStats = - MWWorld::Class::get (creature).getCreatureStats (creature); - - MagicEffects now = creatureStats.mSpells.getMagicEffects(); - - /// \todo add effects from active spells and equipment - - MagicEffects diff = MagicEffects::diff (creatureStats.mMagicEffects, now); - - creatureStats.mMagicEffects = now; - - // TODO apply diff to other stats - } MechanicsManager::MechanicsManager() : mUpdatePlayer (true), mClassSelected (false), diff --git a/apps/openmw/mwmechanics/mechanicsmanager.hpp b/apps/openmw/mwmechanics/mechanicsmanager.hpp index a26fb98cd9..62bb4cf7e2 100644 --- a/apps/openmw/mwmechanics/mechanicsmanager.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanager.hpp @@ -31,8 +31,6 @@ namespace MWMechanics ///< build player according to stored class/race/birthsign information. Will /// default to the values of the ESM::NPC object, if no explicit information is given. - void adjustMagicEffects (MWWorld::Ptr& creature); - public: MechanicsManager (); From 0c1d06d9f767b3860886478d61beb18f4da8fb63 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 17 May 2012 13:36:25 +0200 Subject: [PATCH 186/325] added some trade window stuff, which does nothing yet. --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwgui/inventorywindow.hpp | 18 +--------- apps/openmw/mwgui/tradewindow.cpp | 10 ++++++ apps/openmw/mwgui/tradewindow.hpp | 41 ++++++++++++++++++++++ apps/openmw/mwgui/window_manager.hpp | 2 ++ files/mygui/openmw_trade_window_layout.xml | 24 +++++++++++++ 6 files changed, 79 insertions(+), 18 deletions(-) create mode 100644 apps/openmw/mwgui/tradewindow.cpp create mode 100644 apps/openmw/mwgui/tradewindow.hpp create mode 100644 files/mygui/openmw_trade_window_layout.xml diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index c105f28b12..9e5aeb6845 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -26,7 +26,7 @@ add_openmw_dir (mwgui text_input widgets race class birth review window_manager console dialogue dialogue_history window_base stats_window messagebox journalwindow charactercreation map_window window_pinnable_base cursorreplace tooltips scrollwindow bookwindow list - formatting itemwidget inventorywindow container hud countdialog + formatting itemwidget inventorywindow container hud countdialog tradewindow ) add_openmw_dir (mwdialogue diff --git a/apps/openmw/mwgui/inventorywindow.hpp b/apps/openmw/mwgui/inventorywindow.hpp index ae0d809867..07aeeeafd9 100644 --- a/apps/openmw/mwgui/inventorywindow.hpp +++ b/apps/openmw/mwgui/inventorywindow.hpp @@ -4,23 +4,6 @@ #include "container.hpp" #include "window_pinnable_base.hpp" -namespace MWWorld -{ - class Environment; -} - -namespace MyGUI -{ - class Gui; - class Widget; -} - -namespace MWGui -{ - class WindowManager; -} - - namespace MWGui { class InventoryWindow : public ContainerBase, public WindowPinnableBase @@ -60,4 +43,5 @@ namespace MWGui virtual void _unequipItem(MWWorld::Ptr item); }; } + #endif // Inventory_H diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp new file mode 100644 index 0000000000..45a82eecba --- /dev/null +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -0,0 +1,10 @@ +#include "tradewindow.hpp" + +namespace MWGui +{ + TradeWindow::TradeWindow(WindowManager& parWindowManager) : + WindowBase("openmw_trade_window_layout.xml", parWindowManager), + ContainerBase(NULL) // no drag&drop + { + } +} diff --git a/apps/openmw/mwgui/tradewindow.hpp b/apps/openmw/mwgui/tradewindow.hpp new file mode 100644 index 0000000000..f04f83c0d0 --- /dev/null +++ b/apps/openmw/mwgui/tradewindow.hpp @@ -0,0 +1,41 @@ +#ifndef MWGUI_TRADEWINDOW_H +#define MWGUI_TRADEWINDOW_H + +#include "container.hpp" +#include "window_base.hpp" + +namespace MyGUI +{ + class Gui; + class Widget; +} + +namespace MWGui +{ + class WindowManager; +} + + +namespace MWGui +{ + class TradeWindow : public ContainerBase, public WindowBase + { + public: + TradeWindow(WindowManager& parWindowManager); + + //virtual void Update(); + //virtual void notifyContentChanged(); + + protected: + MyGUI::Button* mFilterAll; + MyGUI::Button* mFilterWeapon; + MyGUI::Button* mFilterApparel; + MyGUI::Button* mFilterMagic; + MyGUI::Button* mFilterMisc; + + void onWindowResize(MyGUI::Window* _sender); + void onFilterChanged(MyGUI::Widget* _sender); + }; +} + +#endif diff --git a/apps/openmw/mwgui/window_manager.hpp b/apps/openmw/mwgui/window_manager.hpp index 3f5df5789f..8c9eec16d4 100644 --- a/apps/openmw/mwgui/window_manager.hpp +++ b/apps/openmw/mwgui/window_manager.hpp @@ -72,6 +72,7 @@ namespace MWGui class DialogueWindow; class MessageBoxManager; class CountDialog; + class TradeWindow; struct ClassPoint { @@ -226,6 +227,7 @@ namespace MWGui ScrollWindow* mScrollWindow; BookWindow* mBookWindow; CountDialog* mCountDialog; + TradeWindow* mTradeWindow; CharacterCreation* mCharGen; diff --git a/files/mygui/openmw_trade_window_layout.xml b/files/mygui/openmw_trade_window_layout.xml new file mode 100644 index 0000000000..e5c45cdd0b --- /dev/null +++ b/files/mygui/openmw_trade_window_layout.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + From 66abfd17abd7719a7f5eae985e869802b0652604 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 17 May 2012 14:13:35 +0200 Subject: [PATCH 187/325] check the container's "Organic" flag before trying to place items inside. --- apps/openmw/mwgui/container.cpp | 18 +++++++++++++++--- apps/openmw/mwgui/hud.cpp | 5 +++++ apps/openmw/mwgui/hud.hpp | 1 + 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 3656a89190..978e10fc4b 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -143,7 +143,7 @@ void ContainerBase::onSelectedItemImpl(MyGUI::Widget* _sender, int count) void ContainerBase::onContainerClicked(MyGUI::Widget* _sender) { - if(mDragAndDrop->mIsOnDragAndDrop) //drop widget here + if(mDragAndDrop->mIsOnDragAndDrop) //drop item here { MWWorld::Ptr object = *mDragAndDrop->mDraggedWidget->getUserData(); MWWorld::ContainerStore& containerStore = MWWorld::Class::get(mContainer).getContainerStore(mContainer); @@ -152,6 +152,20 @@ void ContainerBase::onContainerClicked(MyGUI::Widget* _sender) { assert(object.getContainerStore() && "Item is not in a container!"); + // check the container's Organic flag (if this is a container). container with Organic flag doesn't allow putting items inside + if (mContainer.getTypeName() == typeid(ESM::Container).name()) + { + ESMS::LiveCellRef* ref = mContainer.get(); + if (ref->base->flags & ESM::Container::Organic) + { + // user notification + MWBase::Environment::get().getWindowManager()-> + messageBox(MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sContentsMessage2")->str, std::vector()); + return; + } + } + + int origCount = object.getRefData().getCount(); // check that we don't exceed the allowed weight (only for containers, not for inventory) if (!isInventory()) @@ -159,7 +173,6 @@ void ContainerBase::onContainerClicked(MyGUI::Widget* _sender) float capacity = MWWorld::Class::get(mContainer).getCapacity(mContainer); // try adding the item, and if weight is exceeded, just remove it again. - int origCount = object.getRefData().getCount(); object.getRefData().setCount(mDragAndDrop->mDraggedCount); MWWorld::ContainerStoreIterator it = containerStore.add(object); @@ -181,7 +194,6 @@ void ContainerBase::onContainerClicked(MyGUI::Widget* _sender) } else { - int origCount = object.getRefData().getCount(); object.getRefData().setCount (mDragAndDrop->mDraggedCount); containerStore.add(object); object.getRefData().setCount (origCount - mDragAndDrop->mDraggedCount); diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index c15801da4d..395ca79c5d 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -92,6 +92,7 @@ HUD::HUD(int width, int height, int fpsLevel, DragAndDrop* dragAndDrop) mMainWidget->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onWorldClicked); mMainWidget->eventMouseMove += MyGUI::newDelegate(this, &HUD::onWorldMouseOver); + mMainWidget->eventMouseLostFocus += MyGUI::newDelegate(this, &HUD::onWorldMouseLostFocus); } void HUD::setFpsLevel(int level) @@ -321,3 +322,7 @@ void HUD::onWorldMouseOver(MyGUI::Widget* _sender, int x, int y) } } +void HUD::onWorldMouseLostFocus(MyGUI::Widget* _sender, MyGUI::Widget* _new) +{ + MyGUI::PointerManager::getInstance().setPointer("arrow"); +} diff --git a/apps/openmw/mwgui/hud.hpp b/apps/openmw/mwgui/hud.hpp index cccfb0541c..d588113dd1 100644 --- a/apps/openmw/mwgui/hud.hpp +++ b/apps/openmw/mwgui/hud.hpp @@ -53,5 +53,6 @@ namespace MWGui void onWorldClicked(MyGUI::Widget* _sender); void onWorldMouseOver(MyGUI::Widget* _sender, int x, int y); + void onWorldMouseLostFocus(MyGUI::Widget* _sender, MyGUI::Widget* _new); }; } From 0dc5e5919b11906d69fde2ec9a7a253f15c8900d Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 17 May 2012 14:54:03 +0200 Subject: [PATCH 188/325] show the Barter entry in the dialogue gui for npcs/creatures that buy/sell stuff. doesn't work for the Creeper for some reason, but Mudcrab Merchant works. --- apps/openmw/mwdialogue/dialoguemanager.cpp | 30 +++++++++++++++++ apps/openmw/mwgui/dialogue.cpp | 13 +++++++- apps/openmw/mwgui/dialogue.hpp | 7 ++++ apps/openmw/mwgui/list.cpp | 39 ++++++++++++++++------ apps/openmw/mwgui/list.hpp | 3 +- 5 files changed, 79 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwdialogue/dialoguemanager.cpp b/apps/openmw/mwdialogue/dialoguemanager.cpp index 7baf589c44..496cc4f7f8 100644 --- a/apps/openmw/mwdialogue/dialoguemanager.cpp +++ b/apps/openmw/mwdialogue/dialoguemanager.cpp @@ -767,6 +767,36 @@ namespace MWDialogue } } + // check the available services of this actor + int services = 0; + if (mActor.getTypeName() == typeid(ESM::NPC).name()) + { + ESMS::LiveCellRef* ref = mActor.get(); + if (ref->base->hasAI) + services = ref->base->AI.services; + } + else if (mActor.getTypeName() == typeid(ESM::Creature).name()) + { + ESMS::LiveCellRef* ref = mActor.get(); + if (ref->base->hasAI) + services = ref->base->AI.services; + } + + if (services & ESM::NPC::Weapon + || services & ESM::NPC::Armor + || services & ESM::NPC::Clothing + || services & ESM::NPC::Books + || services & ESM::NPC::Ingredients + || services & ESM::NPC::Picks + || services & ESM::NPC::Probes + || services & ESM::NPC::Lights + || services & ESM::NPC::Apparatus + || services & ESM::NPC::RepairItem + || services & ESM::NPC::Misc) + win->setShowTrade(true); + else + win->setShowTrade(false); + // sort again, because the previous sort was case-sensitive keywordList.sort(stringCompareNoCase); win->setKeywords(keywordList); diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 1116eb272f..3f6ec03769 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -40,6 +40,7 @@ std::string::size_type find_str_ci(const std::string& str, const std::string& su DialogueWindow::DialogueWindow(WindowManager& parWindowManager) : WindowBase("openmw_dialogue_window_layout.xml", parWindowManager) , mEnabled(true) + , mShowTrade(false) { // Centre dialog center(); @@ -141,6 +142,15 @@ void DialogueWindow::startDialogue(std::string npcName) void DialogueWindow::setKeywords(std::list keyWords) { topicsList->clear(); + + bool anyService = mShowTrade; + + if (mShowTrade) + topicsList->addItem(MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sBarter")->str); + + if (anyService) + topicsList->addSeparator(); + for(std::list::iterator it = keyWords.begin(); it != keyWords.end(); it++) { topicsList->addItem(*it); @@ -194,7 +204,8 @@ std::string DialogueWindow::parseText(std::string text) for(unsigned int i = 0;igetItemCount();i++) { std::string keyWord = topicsList->getItemNameAt(i); - addColorInString(text,keyWord,"#686EBA","#B29154"); + if (keyWord != "") + addColorInString(text,keyWord,"#686EBA","#B29154"); } return text; } diff --git a/apps/openmw/mwgui/dialogue.hpp b/apps/openmw/mwgui/dialogue.hpp index a29e737997..225ef37a4f 100644 --- a/apps/openmw/mwgui/dialogue.hpp +++ b/apps/openmw/mwgui/dialogue.hpp @@ -47,6 +47,10 @@ namespace MWGui void askQuestion(std::string question); void goodbye(); + // various service button visibilities, depending if the npc/creature talked to has these services + // make sure to call these before setKeywords() + void setShowTrade(bool show) { mShowTrade = show; } + protected: void onSelectTopic(std::string topic); void onByeClicked(MyGUI::Widget* _sender); @@ -61,6 +65,9 @@ namespace MWGui */ std::string parseText(std::string text); + // various service button visibilities, depending if the npc/creature talked to has these services + bool mShowTrade; + bool mEnabled; DialogueHistory* history; diff --git a/apps/openmw/mwgui/list.cpp b/apps/openmw/mwgui/list.cpp index 33f5a6fd1b..661fb2e683 100644 --- a/apps/openmw/mwgui/list.cpp +++ b/apps/openmw/mwgui/list.cpp @@ -30,6 +30,11 @@ void MWList::addItem(const std::string& name) mItems.push_back(name); } +void MWList::addSeparator() +{ + mItems.push_back(""); +} + void MWList::adjustSize() { redraw(); @@ -50,19 +55,31 @@ void MWList::redraw(bool scrollbarShown) for (std::vector::const_iterator it=mItems.begin(); it!=mItems.end(); ++it) { - MyGUI::Button* button = mScrollView->createWidget( - "MW_ListLine", MyGUI::IntCoord(0, mItemHeight, mScrollView->getSize().width - scrollBarWidth - 2, 24), - MyGUI::Align::Left | MyGUI::Align::Top, getName() + "_item_" + (*it)); - button->setCaption((*it)); - button->getSubWidgetText()->setWordWrap(true); - button->getSubWidgetText()->setTextAlign(MyGUI::Align::Left); - button->eventMouseWheel += MyGUI::newDelegate(this, &MWList::onMouseWheel); - button->eventMouseButtonClick += MyGUI::newDelegate(this, &MWList::onItemSelected); + if (*it != "") + { + MyGUI::Button* button = mScrollView->createWidget( + "MW_ListLine", MyGUI::IntCoord(0, mItemHeight, mScrollView->getSize().width - scrollBarWidth - 2, 24), + MyGUI::Align::Left | MyGUI::Align::Top, getName() + "_item_" + (*it)); + button->setCaption((*it)); + button->getSubWidgetText()->setWordWrap(true); + button->getSubWidgetText()->setTextAlign(MyGUI::Align::Left); + button->eventMouseWheel += MyGUI::newDelegate(this, &MWList::onMouseWheel); + button->eventMouseButtonClick += MyGUI::newDelegate(this, &MWList::onItemSelected); - int height = button->getTextSize().height; - button->setSize(MyGUI::IntSize(button->getSize().width, height)); + int height = button->getTextSize().height; + button->setSize(MyGUI::IntSize(button->getSize().width, height)); - mItemHeight += height + spacing; + mItemHeight += height + spacing; + } + else + { + MyGUI::ImageBox* separator = mScrollView->createWidget("MW_HLine", + MyGUI::IntCoord(2, mItemHeight, mScrollView->getWidth()-4, 18), + MyGUI::Align::Left | MyGUI::Align::Top | MyGUI::Align::HStretch); + separator->setNeedMouseFocus(false); + + mItemHeight += 18 + spacing; + } } mScrollView->setCanvasSize(mClient->getSize().width + (_scrollBarWidth-scrollBarWidth), std::max(mItemHeight, mClient->getSize().height)); diff --git a/apps/openmw/mwgui/list.hpp b/apps/openmw/mwgui/list.hpp index 76ca5257fa..2b765c2e11 100644 --- a/apps/openmw/mwgui/list.hpp +++ b/apps/openmw/mwgui/list.hpp @@ -31,10 +31,11 @@ namespace MWGui void adjustSize(); void addItem(const std::string& name); + void addSeparator(); ///< add a seperator between the current and the next item. void removeItem(const std::string& name); bool hasItem(const std::string& name); unsigned int getItemCount(); - std::string getItemNameAt(unsigned int at); + std::string getItemNameAt(unsigned int at); ///< \attention if there are separators, this method will return "" at the place where the separator is void clear(); protected: From 6f87493df664996c7d4b07ba6b708dec45afad76 Mon Sep 17 00:00:00 2001 From: gugus Date: Thu, 17 May 2012 15:46:38 +0200 Subject: [PATCH 189/325] fix collision bug i think. It disable collision for quiet a lot of objects (maybe a little to much) --- components/nifbullet/bullet_nif_loader.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/components/nifbullet/bullet_nif_loader.cpp b/components/nifbullet/bullet_nif_loader.cpp index e9aa626dbe..30cb4562d0 100644 --- a/components/nifbullet/bullet_nif_loader.cpp +++ b/components/nifbullet/bullet_nif_loader.cpp @@ -139,6 +139,8 @@ void ManualBulletShapeLoader::loadResource(Ogre::Resource *resource) handleNode(node,0,Ogre::Matrix3::IDENTITY,Ogre::Vector3::ZERO,1,hasCollisionNode,false,true); } + cShape->collide = hasCollisionNode&&cShape->collide; + struct TriangleMeshShape : public btBvhTriangleMeshShape { TriangleMeshShape(btStridingMeshInterface* meshInterface, bool useQuantizedAabbCompression) From 09ec1da0f6c02cdc5bc5ae3fc8707939525651b3 Mon Sep 17 00:00:00 2001 From: gugus Date: Thu, 17 May 2012 16:12:55 +0200 Subject: [PATCH 190/325] fix the latest commit: objects activation works again. --- libs/openengine/bullet/physic.cpp | 41 +++++++++++++++++-------------- 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index 42853d8cfa..d30d5e9f13 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -22,7 +22,8 @@ namespace Physic COL_NOTHING = 0, //collide = shape->collide; return body; + } void PhysicEngine::addRigidBody(RigidBody* body) { - if(body->collide) + if(body) { - dynamicsWorld->addRigidBody(body,COL_WORLD,COL_WORLD|COL_ACTOR_INTERNAL|COL_ACTOR_EXTERNAL); - } - else - { - dynamicsWorld->addRigidBody(body,COL_WORLD,COL_NOTHING); - } - body->setActivationState(DISABLE_DEACTIVATION); - RigidBody* oldBody = RigidBodyMap[body->mName]; - if (oldBody != NULL) - { - dynamicsWorld->removeRigidBody(oldBody); - delete oldBody; - } + if(body->collide) + { + dynamicsWorld->addRigidBody(body,COL_WORLD,COL_WORLD|COL_ACTOR_INTERNAL|COL_ACTOR_EXTERNAL); + } + else + { + dynamicsWorld->addRigidBody(body,COL_RAYCASTING,COL_RAYCASTING|COL_WORLD); + } + body->setActivationState(DISABLE_DEACTIVATION); + RigidBody* oldBody = RigidBodyMap[body->mName]; + if (oldBody != NULL) + { + dynamicsWorld->removeRigidBody(oldBody); + delete oldBody; + } - RigidBodyMap[body->mName] = body; + RigidBodyMap[body->mName] = body; + } } void PhysicEngine::removeRigidBody(std::string name) @@ -460,7 +465,7 @@ namespace Physic float d1 = 10000.; btCollisionWorld::ClosestRayResultCallback resultCallback1(from, to); - resultCallback1.m_collisionFilterMask = COL_WORLD; + resultCallback1.m_collisionFilterMask = COL_WORLD|COL_RAYCASTING; dynamicsWorld->rayTest(from, to, resultCallback1); if (resultCallback1.hasHit()) { @@ -489,7 +494,7 @@ namespace Physic std::vector< std::pair > PhysicEngine::rayTest2(btVector3& from, btVector3& to) { MyRayResultCallback resultCallback1; - resultCallback1.m_collisionFilterMask = COL_WORLD; + resultCallback1.m_collisionFilterMask = COL_WORLD|COL_RAYCASTING; dynamicsWorld->rayTest(from, to, resultCallback1); std::vector< std::pair > results = resultCallback1.results; From 6b74fec8ed4def2da942b57e6f836af94f369890 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 17 May 2012 17:13:41 +0200 Subject: [PATCH 191/325] don't do a half finished cell change, when trying to switch to an interior cell that does not exist --- apps/openmw/mwworld/scene.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 6f9f3ed3ed..caaef52649 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -251,6 +251,9 @@ namespace MWWorld void Scene::changeToInteriorCell (const std::string& cellName, const ESM::Position& position) { std::cout << "Changing to interior\n"; + + Ptr::CellStore *cell = mWorld->getInterior(cellName); + // remove active CellStoreCollection::iterator active = mActiveCells.begin(); @@ -261,11 +264,9 @@ namespace MWWorld // Load cell. std::cout << "cellName:" << cellName << std::endl; - Ptr::CellStore *cell = mWorld->getInterior(cellName); loadCell (cell); - // adjust player mCurrentCell = cell; playerCellChange (cell, position); From 5da4da820e41df0d9fde8ef585188460db58140a Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 17 May 2012 17:15:44 +0200 Subject: [PATCH 192/325] beginnings of trade window layout. --- apps/openmw/mwdialogue/dialoguemanager.cpp | 2 +- apps/openmw/mwgui/dialogue.cpp | 35 +++++++++++++++------- apps/openmw/mwgui/dialogue.hpp | 6 +++- apps/openmw/mwgui/tradewindow.cpp | 5 ++++ apps/openmw/mwgui/tradewindow.hpp | 4 +++ apps/openmw/mwgui/window_manager.cpp | 4 +++ apps/openmw/mwgui/window_manager.hpp | 1 + files/mygui/CMakeLists.txt | 1 + 8 files changed, 45 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwdialogue/dialoguemanager.cpp b/apps/openmw/mwdialogue/dialoguemanager.cpp index 496cc4f7f8..2c4de7be19 100644 --- a/apps/openmw/mwdialogue/dialoguemanager.cpp +++ b/apps/openmw/mwdialogue/dialoguemanager.cpp @@ -637,7 +637,7 @@ namespace MWDialogue //initialise the GUI MWBase::Environment::get().getInputManager()->setGuiMode(MWGui::GM_Dialogue); MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow(); - win->startDialogue(MWWorld::Class::get (actor).getName (actor)); + win->startDialogue(actor, MWWorld::Class::get (actor).getName (actor)); //setup the list of topics known by the actor. Topics who are also on the knownTopics list will be added to the GUI updateTopics(); diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 3f6ec03769..953657565f 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -1,11 +1,4 @@ #include "dialogue.hpp" -#include "dialogue_history.hpp" -#include "window_manager.hpp" -#include "widgets.hpp" -#include "list.hpp" -#include "components/esm_store/store.hpp" -#include "../mwbase/environment.hpp" -#include "../mwdialogue/dialoguemanager.hpp" #include #include @@ -14,6 +7,17 @@ #include #include +#include + +#include "../mwbase/environment.hpp" +#include "../mwdialogue/dialoguemanager.hpp" + +#include "dialogue_history.hpp" +#include "window_manager.hpp" +#include "widgets.hpp" +#include "list.hpp" +#include "tradewindow.hpp" + using namespace MWGui; using namespace Widgets; @@ -59,9 +63,7 @@ DialogueWindow::DialogueWindow(WindowManager& parWindowManager) //Topics list getWidget(topicsList, "TopicsList"); - //topicsList->eventListSelectAccept += MyGUI::newDelegate(this, &DialogueWindow::onSelectTopic); topicsList->eventItemSelected += MyGUI::newDelegate(this, &DialogueWindow::onSelectTopic); - //topicsList->eventListChangePosition += MyGUI::newDelegate(this, &DialogueWindow::onSelectTopic); MyGUI::ButtonPtr byeButton; getWidget(byeButton, "ByeButton"); @@ -117,6 +119,9 @@ void DialogueWindow::open() history->eraseText(0,history->getTextLength()); updateOptions(); setVisible(true); + + // hide all sub-dialogues of the dialog window (trade window, persuasion, etc) + mWindowManager.getTradeWindow()->setVisible(false); } void DialogueWindow::onByeClicked(MyGUI::Widget* _sender) @@ -128,12 +133,20 @@ void DialogueWindow::onSelectTopic(std::string topic) { if (!mEnabled) return; - MWBase::Environment::get().getDialogueManager()->keywordSelected(lower_string(topic)); + if (topic == MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sBarter")->str) + { + /// \todo check if the player is allowed to trade with this actor (e.g. faction rank high enough)? + mWindowManager.getTradeWindow()->startTrade(mActor); + } + + else + MWBase::Environment::get().getDialogueManager()->keywordSelected(lower_string(topic)); } -void DialogueWindow::startDialogue(std::string npcName) +void DialogueWindow::startDialogue(MWWorld::Ptr actor, std::string npcName) { mEnabled = true; + mActor = actor; topicsList->setEnabled(true); static_cast(mMainWidget)->setCaption(npcName); adjustWindowCaption(); diff --git a/apps/openmw/mwgui/dialogue.hpp b/apps/openmw/mwgui/dialogue.hpp index 225ef37a4f..7f69f972c7 100644 --- a/apps/openmw/mwgui/dialogue.hpp +++ b/apps/openmw/mwgui/dialogue.hpp @@ -4,6 +4,8 @@ #include "window_base.hpp" #include +#include "../mwworld/ptr.hpp" + namespace MWGui { class WindowManager; @@ -38,7 +40,7 @@ namespace MWGui */ EventHandle_Void eventBye; - void startDialogue(std::string npcName); + void startDialogue(MWWorld::Ptr actor, std::string npcName); void stopDialogue(); void setKeywords(std::list keyWord); void removeKeyword(std::string keyWord); @@ -70,6 +72,8 @@ namespace MWGui bool mEnabled; + MWWorld::Ptr mActor; // actor being talked to + DialogueHistory* history; Widgets::MWList* topicsList; MyGUI::ProgressPtr pDispositionBar; diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index 45a82eecba..cd38aa731a 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -7,4 +7,9 @@ namespace MWGui ContainerBase(NULL) // no drag&drop { } + + void TradeWindow::startTrade(MWWorld::Ptr actor) + { + ContainerBase::openContainer(actor); + } } diff --git a/apps/openmw/mwgui/tradewindow.hpp b/apps/openmw/mwgui/tradewindow.hpp index f04f83c0d0..5fc5b98b64 100644 --- a/apps/openmw/mwgui/tradewindow.hpp +++ b/apps/openmw/mwgui/tradewindow.hpp @@ -4,6 +4,8 @@ #include "container.hpp" #include "window_base.hpp" +#include "../mwworld/ptr.hpp" + namespace MyGUI { class Gui; @@ -23,6 +25,8 @@ namespace MWGui public: TradeWindow(WindowManager& parWindowManager); + void startTrade(MWWorld::Ptr actor); + //virtual void Update(); //virtual void notifyContentChanged(); diff --git a/apps/openmw/mwgui/window_manager.cpp b/apps/openmw/mwgui/window_manager.cpp index 5c005835c8..245b364c94 100644 --- a/apps/openmw/mwgui/window_manager.cpp +++ b/apps/openmw/mwgui/window_manager.cpp @@ -15,6 +15,7 @@ #include "hud.hpp" #include "mainmenu.hpp" #include "countdialog.hpp" +#include "tradewindow.hpp" #include "../mwmechanics/mechanicsmanager.hpp" #include "../mwinput/inputmanager.hpp" @@ -48,6 +49,7 @@ WindowManager::WindowManager( , mBookWindow(NULL) , mScrollWindow(NULL) , mCountDialog(NULL) + , mTradeWindow(NULL) , mCharGen(NULL) , playerClass() , playerName() @@ -114,6 +116,7 @@ WindowManager::WindowManager( mScrollWindow = new ScrollWindow(*this); mBookWindow = new BookWindow(*this); mCountDialog = new CountDialog(*this); + mTradeWindow = new TradeWindow(*this); // The HUD is always on hud->setVisible(true); @@ -153,6 +156,7 @@ WindowManager::~WindowManager() delete mDragAndDrop; delete mBookWindow; delete mScrollWindow; + delete mTradeWindow; cleanupGarbage(); } diff --git a/apps/openmw/mwgui/window_manager.hpp b/apps/openmw/mwgui/window_manager.hpp index 8c9eec16d4..52869ff55a 100644 --- a/apps/openmw/mwgui/window_manager.hpp +++ b/apps/openmw/mwgui/window_manager.hpp @@ -136,6 +136,7 @@ namespace MWGui MWGui::BookWindow* getBookWindow() {return mBookWindow;} MWGui::ScrollWindow* getScrollWindow() {return mScrollWindow;} MWGui::CountDialog* getCountDialog() {return mCountDialog;} + MWGui::TradeWindow* getTradeWindow() {return mTradeWindow;} MyGUI::Gui* getGui() const { return gui; } diff --git a/files/mygui/CMakeLists.txt b/files/mygui/CMakeLists.txt index 2ee823d2ae..cacfb7c5a3 100644 --- a/files/mygui/CMakeLists.txt +++ b/files/mygui/CMakeLists.txt @@ -56,6 +56,7 @@ configure_file("${SDIR}/openmw_scroll_layout.xml" "${DDIR}/openmw_scroll_layout. configure_file("${SDIR}/openmw_scroll_skin.xml" "${DDIR}/openmw_scroll_skin.xml" COPYONLY) configure_file("${SDIR}/openmw_book_layout.xml" "${DDIR}/openmw_book_layout.xml" COPYONLY) configure_file("${SDIR}/openmw_count_window_layout.xml" "${DDIR}/openmw_count_window_layout.xml" COPYONLY) +configure_file("${SDIR}/openmw_trade_window_layout.xml" "${DDIR}/openmw_trade_window_layout.xml" COPYONLY) configure_file("${SDIR}/atlas1.cfg" "${DDIR}/atlas1.cfg" COPYONLY) configure_file("${SDIR}/smallbars.png" "${DDIR}/smallbars.png" COPYONLY) configure_file("${SDIR}/transparent.png" "${DDIR}/transparent.png" COPYONLY) From ae77e7b0d84a0fa92e9a13f558d6ca0bf901efe0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 17 May 2012 18:11:34 +0200 Subject: [PATCH 193/325] don't try to retrieve land data from non-predefined cells. --- apps/openmw/mwworld/scene.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index caaef52649..e4236b2f7f 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -82,7 +82,11 @@ namespace MWWorld } if (!((*iter)->cell->data.flags & ESM::Cell::Interior)) - mPhysics->removeHeightField( (*iter)->cell->data.gridX, (*iter)->cell->data.gridY ); + { + ESM::Land* land = mWorld->getStore().lands.search((*iter)->cell->data.gridX,(*iter)->cell->data.gridY); + if (land) + mPhysics->removeHeightField( (*iter)->cell->data.gridX, (*iter)->cell->data.gridY ); + } } mRendering.removeCell(*iter); @@ -118,9 +122,10 @@ namespace MWWorld if (!(cell->cell->data.flags & ESM::Cell::Interior)) { ESM::Land* land = mWorld->getStore().lands.search(cell->cell->data.gridX,cell->cell->data.gridY); - mPhysics->addHeightField (land->landData->heights, - cell->cell->data.gridX, cell->cell->data.gridY, - 0, ( worldsize/(verts-1) ), verts); + if (land) + mPhysics->addHeightField (land->landData->heights, + cell->cell->data.gridX, cell->cell->data.gridY, + 0, ( worldsize/(verts-1) ), verts); } mRendering.configureAmbient(*cell); From 0afda15ce9f0e564abceef4773e724625d80fc40 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 17 May 2012 18:14:33 +0200 Subject: [PATCH 194/325] fix for cells that have no region. --- apps/openmw/mwgui/window_manager.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/window_manager.cpp b/apps/openmw/mwgui/window_manager.cpp index dfac55beb9..610f1b2f25 100644 --- a/apps/openmw/mwgui/window_manager.cpp +++ b/apps/openmw/mwgui/window_manager.cpp @@ -447,7 +447,8 @@ void WindowManager::changeCell(MWWorld::Ptr::CellStore* cell) else { const ESM::Region* region = MWBase::Environment::get().getWorld()->getStore().regions.search(cell->cell->region); - name = region->name; + if (region) + name = region->name; } map->setCellName( name ); From 375c198ebd9d350dd3d137c3faf8af7382e3e032 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 17 May 2012 18:21:05 +0200 Subject: [PATCH 195/325] WeatherManager: fix for cells that have no region. --- apps/openmw/mwworld/weather.cpp | 73 +++++++++++++++++---------------- 1 file changed, 38 insertions(+), 35 deletions(-) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index bcbb96eecf..316463f539 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -499,51 +499,54 @@ void WeatherManager::update(float duration) mCurrentRegion = regionstr; mWeatherUpdateTime = WeatherGlobals::mWeatherUpdateTime*3600; - std::string weather; + std::string weather = "clear"; if (mRegionOverrides.find(regionstr) != mRegionOverrides.end()) weather = mRegionOverrides[regionstr]; else { // get weather probabilities for the current region - const ESM::Region *region = MWBase::Environment::get().getWorld()->getStore().regions.find (regionstr); + const ESM::Region *region = MWBase::Environment::get().getWorld()->getStore().regions.search (regionstr); - float clear = region->data.clear/255.f; - float cloudy = region->data.cloudy/255.f; - float foggy = region->data.foggy/255.f; - float overcast = region->data.overcast/255.f; - float rain = region->data.rain/255.f; - float thunder = region->data.thunder/255.f; - float ash = region->data.ash/255.f; - float blight = region->data.blight/255.f; - //float snow = region->data.a/255.f; - //float blizzard = region->data.b/255.f; + if (region != 0) + { + float clear = region->data.clear/255.f; + float cloudy = region->data.cloudy/255.f; + float foggy = region->data.foggy/255.f; + float overcast = region->data.overcast/255.f; + float rain = region->data.rain/255.f; + float thunder = region->data.thunder/255.f; + float ash = region->data.ash/255.f; + float blight = region->data.blight/255.f; + //float snow = region->data.a/255.f; + //float blizzard = region->data.b/255.f; - // re-scale to 100 percent - const float total = clear+cloudy+foggy+overcast+rain+thunder+ash+blight;//+snow+blizzard; + // re-scale to 100 percent + const float total = clear+cloudy+foggy+overcast+rain+thunder+ash+blight;//+snow+blizzard; - float random = ((rand()%100)/100.f) * total; + float random = ((rand()%100)/100.f) * total; - //if (random >= snow+blight+ash+thunder+rain+overcast+foggy+cloudy+clear) - // weather = "blizzard"; - //else if (random >= blight+ash+thunder+rain+overcast+foggy+cloudy+clear) - // weather = "snow"; - /*else*/ if (random >= ash+thunder+rain+overcast+foggy+cloudy+clear) - weather = "blight"; - else if (random >= thunder+rain+overcast+foggy+cloudy+clear) - weather = "ashstorm"; - else if (random >= rain+overcast+foggy+cloudy+clear) - weather = "thunderstorm"; - else if (random >= overcast+foggy+cloudy+clear) - weather = "rain"; - else if (random >= foggy+cloudy+clear) - weather = "overcast"; - else if (random >= cloudy+clear) - weather = "foggy"; - else if (random >= clear) - weather = "cloudy"; - else - weather = "clear"; + //if (random >= snow+blight+ash+thunder+rain+overcast+foggy+cloudy+clear) + // weather = "blizzard"; + //else if (random >= blight+ash+thunder+rain+overcast+foggy+cloudy+clear) + // weather = "snow"; + /*else*/ if (random >= ash+thunder+rain+overcast+foggy+cloudy+clear) + weather = "blight"; + else if (random >= thunder+rain+overcast+foggy+cloudy+clear) + weather = "ashstorm"; + else if (random >= rain+overcast+foggy+cloudy+clear) + weather = "thunderstorm"; + else if (random >= overcast+foggy+cloudy+clear) + weather = "rain"; + else if (random >= foggy+cloudy+clear) + weather = "overcast"; + else if (random >= cloudy+clear) + weather = "foggy"; + else if (random >= clear) + weather = "cloudy"; + else + weather = "clear"; + } } setWeather(weather, false); From 4213b4370ff87a7986df41eabd7e9757325b8d88 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 17 May 2012 19:53:04 +0200 Subject: [PATCH 196/325] trade window shows up and shows the vendor's inventory items. --- apps/openmw/mwgui/container.cpp | 53 ++++++++-------- apps/openmw/mwgui/inventorywindow.cpp | 7 --- apps/openmw/mwgui/tradewindow.cpp | 72 ++++++++++++++++++++++ apps/openmw/mwgui/window_manager.cpp | 2 +- files/mygui/openmw_trade_window_layout.xml | 21 ++++--- 5 files changed, 115 insertions(+), 40 deletions(-) diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 978e10fc4b..eb02c5826b 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -88,31 +88,34 @@ ContainerBase::~ContainerBase() void ContainerBase::onSelectedItem(MyGUI::Widget* _sender) { - if(!mDragAndDrop->mIsOnDragAndDrop) + if (mDragAndDrop) { - mSelectedItem = _sender; - - MWWorld::Ptr object = (*_sender->getUserData()); - int count = object.getRefData().getCount(); - - if (MyGUI::InputManager::getInstance().isShiftPressed() || count == 1) + if(!mDragAndDrop->mIsOnDragAndDrop) { - onSelectedItemImpl(_sender, count); - } - else if (MyGUI::InputManager::getInstance().isControlPressed()) - { - onSelectedItemImpl(_sender, 1); + mSelectedItem = _sender; + + MWWorld::Ptr object = (*_sender->getUserData()); + int count = object.getRefData().getCount(); + + if (MyGUI::InputManager::getInstance().isShiftPressed() || count == 1) + { + onSelectedItemImpl(_sender, count); + } + else if (MyGUI::InputManager::getInstance().isControlPressed()) + { + onSelectedItemImpl(_sender, 1); + } + else + { + CountDialog* dialog = MWBase::Environment::get().getWindowManager()->getCountDialog(); + dialog->open(MWWorld::Class::get(object).getName(object), count); + dialog->eventOkClicked.clear(); + dialog->eventOkClicked += MyGUI::newDelegate(this, &ContainerBase::onSelectedItemImpl); + } } else - { - CountDialog* dialog = MWBase::Environment::get().getWindowManager()->getCountDialog(); - dialog->open(MWWorld::Class::get(object).getName(object), count); - dialog->eventOkClicked.clear(); - dialog->eventOkClicked += MyGUI::newDelegate(this, &ContainerBase::onSelectedItemImpl); - } + onContainerClicked(mContainerWidget); } - else - onContainerClicked(mContainerWidget); } void ContainerBase::onSelectedItemImpl(MyGUI::Widget* _sender, int count) @@ -143,6 +146,8 @@ void ContainerBase::onSelectedItemImpl(MyGUI::Widget* _sender, int count) void ContainerBase::onContainerClicked(MyGUI::Widget* _sender) { + if (mDragAndDrop == NULL) return; + if(mDragAndDrop->mIsOnDragAndDrop) //drop item here { MWWorld::Ptr object = *mDragAndDrop->mDraggedWidget->getUserData(); @@ -323,7 +328,7 @@ void ContainerBase::drawItems() const MWWorld::Ptr* iter = &((*it).first); int displayCount = iter->getRefData().getCount(); - if (mDragAndDrop->mIsOnDragAndDrop && *iter == *mDragAndDrop->mDraggedWidget->getUserData()) + if (mDragAndDrop != NULL && mDragAndDrop->mIsOnDragAndDrop && *iter == *mDragAndDrop->mDraggedWidget->getUserData()) { displayCount -= mDragAndDrop->mDraggedCount; } @@ -402,7 +407,7 @@ std::string ContainerBase::getCountString(const int count) void ContainerBase::Update() { - if(mDragAndDrop->mIsOnDragAndDrop) + if(mDragAndDrop != NULL && mDragAndDrop->mIsOnDragAndDrop) { if(mDragAndDrop->mDraggedWidget) mDragAndDrop->mDraggedWidget->setPosition(MyGUI::InputManager::getInstance().getMousePosition()); @@ -462,7 +467,7 @@ void ContainerWindow::open(MWWorld::Ptr container) void ContainerWindow::onCloseButtonClicked(MyGUI::Widget* _sender) { - if(!mDragAndDrop->mIsOnDragAndDrop) + if(mDragAndDrop == NULL || !mDragAndDrop->mIsOnDragAndDrop) { MWBase::Environment::get().getWindowManager()->setGuiMode(GM_Game); setVisible(false); @@ -471,7 +476,7 @@ void ContainerWindow::onCloseButtonClicked(MyGUI::Widget* _sender) void ContainerWindow::onTakeAllButtonClicked(MyGUI::Widget* _sender) { - if(!mDragAndDrop->mIsOnDragAndDrop) + if(mDragAndDrop == NULL || !mDragAndDrop->mIsOnDragAndDrop) { // transfer everything into the player's inventory MWWorld::ContainerStore& containerStore = MWWorld::Class::get(mContainer).getContainerStore(mContainer); diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 4f16152ea9..92c0553f69 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -16,13 +16,6 @@ #include "../mwbase/environment.hpp" #include "../mwworld/manualref.hpp" -#include "../mwscript/scriptmanager.hpp" -#include "../mwscript/compilercontext.hpp" -#include "../mwscript/interpretercontext.hpp" -#include "../mwscript/extensions.hpp" -#include "../mwscript/globalscripts.hpp" - - #include "window_manager.hpp" #include "widgets.hpp" #include "bookwindow.hpp" diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index cd38aa731a..09557b196e 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -1,15 +1,87 @@ #include "tradewindow.hpp" +#include "../mwbase/environment.hpp" +#include "../mwworld/world.hpp" + namespace MWGui { TradeWindow::TradeWindow(WindowManager& parWindowManager) : WindowBase("openmw_trade_window_layout.xml", parWindowManager), ContainerBase(NULL) // no drag&drop { + getWidget(mFilterAll, "AllButton"); + getWidget(mFilterWeapon, "WeaponButton"); + getWidget(mFilterApparel, "ApparelButton"); + getWidget(mFilterMagic, "MagicButton"); + getWidget(mFilterMisc, "MiscButton"); + + MyGUI::ScrollView* itemView; + MyGUI::Widget* containerWidget; + getWidget(containerWidget, "Items"); + getWidget(itemView, "ItemView"); + setWidgets(containerWidget, itemView); + + mFilterAll->setCaption (MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sAllTab")->str); + mFilterWeapon->setCaption (MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sWeaponTab")->str); + mFilterApparel->setCaption (MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sApparelTab")->str); + mFilterMagic->setCaption (MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sMagicTab")->str); + mFilterMisc->setCaption (MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sMiscTab")->str); + + // adjust size of buttons to fit text + int curX = 0; + mFilterAll->setSize( mFilterAll->getTextSize().width + 24, mFilterAll->getSize().height ); + curX += mFilterAll->getTextSize().width + 24 + 4; + + mFilterWeapon->setPosition(curX, mFilterWeapon->getPosition().top); + mFilterWeapon->setSize( mFilterWeapon->getTextSize().width + 24, mFilterWeapon->getSize().height ); + curX += mFilterWeapon->getTextSize().width + 24 + 4; + + mFilterApparel->setPosition(curX, mFilterApparel->getPosition().top); + mFilterApparel->setSize( mFilterApparel->getTextSize().width + 24, mFilterApparel->getSize().height ); + curX += mFilterApparel->getTextSize().width + 24 + 4; + + mFilterMagic->setPosition(curX, mFilterMagic->getPosition().top); + mFilterMagic->setSize( mFilterMagic->getTextSize().width + 24, mFilterMagic->getSize().height ); + curX += mFilterMagic->getTextSize().width + 24 + 4; + + mFilterMisc->setPosition(curX, mFilterMisc->getPosition().top); + mFilterMisc->setSize( mFilterMisc->getTextSize().width + 24, mFilterMisc->getSize().height ); + + mFilterAll->eventMouseButtonClick += MyGUI::newDelegate(this, &TradeWindow::onFilterChanged); + mFilterWeapon->eventMouseButtonClick += MyGUI::newDelegate(this, &TradeWindow::onFilterChanged); + mFilterApparel->eventMouseButtonClick += MyGUI::newDelegate(this, &TradeWindow::onFilterChanged); + mFilterMagic->eventMouseButtonClick += MyGUI::newDelegate(this, &TradeWindow::onFilterChanged); + mFilterMisc->eventMouseButtonClick += MyGUI::newDelegate(this, &TradeWindow::onFilterChanged); + + mFilterAll->setStateSelected(true); } void TradeWindow::startTrade(MWWorld::Ptr actor) { ContainerBase::openContainer(actor); + + setVisible(true); + } + + void TradeWindow::onFilterChanged(MyGUI::Widget* _sender) + { + if (_sender == mFilterAll) + setFilter(ContainerBase::Filter_All); + else if (_sender == mFilterWeapon) + setFilter(ContainerBase::Filter_Weapon); + else if (_sender == mFilterApparel) + setFilter(ContainerBase::Filter_Apparel); + else if (_sender == mFilterMagic) + setFilter(ContainerBase::Filter_Magic); + else if (_sender == mFilterMisc) + setFilter(ContainerBase::Filter_Misc); + + mFilterAll->setStateSelected(false); + mFilterWeapon->setStateSelected(false); + mFilterApparel->setStateSelected(false); + mFilterMagic->setStateSelected(false); + mFilterMisc->setStateSelected(false); + + static_cast(_sender)->setStateSelected(true); } } diff --git a/apps/openmw/mwgui/window_manager.cpp b/apps/openmw/mwgui/window_manager.cpp index f6e48a28ad..1593c6b199 100644 --- a/apps/openmw/mwgui/window_manager.cpp +++ b/apps/openmw/mwgui/window_manager.cpp @@ -108,6 +108,7 @@ WindowManager::WindowManager( console = new Console(w,h, extensions); mJournal = new JournalWindow(*this); mMessageBoxManager = new MessageBoxManager(this); + mTradeWindow = new TradeWindow(*this); mDialogueWindow = new DialogueWindow(*this); mContainerWindow = new ContainerWindow(*this,mDragAndDrop); mInventoryWindow = new InventoryWindow(*this,mDragAndDrop); @@ -116,7 +117,6 @@ WindowManager::WindowManager( mScrollWindow = new ScrollWindow(*this); mBookWindow = new BookWindow(*this); mCountDialog = new CountDialog(*this); - mTradeWindow = new TradeWindow(*this); // The HUD is always on hud->setVisible(true); diff --git a/files/mygui/openmw_trade_window_layout.xml b/files/mygui/openmw_trade_window_layout.xml index e5c45cdd0b..15d313c4da 100644 --- a/files/mygui/openmw_trade_window_layout.xml +++ b/files/mygui/openmw_trade_window_layout.xml @@ -2,16 +2,10 @@ - - - - - - - + - + @@ -19,6 +13,17 @@ + + + + + + + + + + + From c9aa0ca1f42300c73155f618bab8deb52bd5cd95 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 17 May 2012 19:54:09 +0200 Subject: [PATCH 197/325] don't create terrain if there is no land data, also fixes a water disappearing issue and a sound exception if cells with no region --- apps/openmw/mwrender/renderingmanager.cpp | 7 +++- apps/openmw/mwrender/terrain.cpp | 49 +++++++++-------------- apps/openmw/mwsound/soundmanager.cpp | 5 ++- 3 files changed, 29 insertions(+), 32 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index a95a179c6c..18d512ac8d 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -11,6 +11,7 @@ #include "../mwworld/world.hpp" // these includes can be removed once the static-hack is gone #include "../mwworld/ptr.hpp" +#include "../mwbase/environment.hpp" #include #include @@ -229,7 +230,10 @@ void RenderingManager::update (float duration){ mWater->update(); } void RenderingManager::waterAdded (MWWorld::Ptr::CellStore *store){ - if(store->cell->data.flags & store->cell->HasWater){ + if(store->cell->data.flags & store->cell->HasWater + || ((!(store->cell->data.flags & ESM::Cell::Interior)) + && !MWBase::Environment::get().getWorld()->getStore().lands.search(store->cell->data.gridX,store->cell->data.gridY) )) // always use water, if the cell does not have land. + { if(mWater == 0) mWater = new MWRender::Water(mRendering.getCamera(), mSkyManager, store->cell); else @@ -238,7 +242,6 @@ void RenderingManager::waterAdded (MWWorld::Ptr::CellStore *store){ } else removeWater(); - } void RenderingManager::setWaterHeight(const float height) diff --git a/apps/openmw/mwrender/terrain.cpp b/apps/openmw/mwrender/terrain.cpp index 90d853f752..56eff4a9ae 100644 --- a/apps/openmw/mwrender/terrain.cpp +++ b/apps/openmw/mwrender/terrain.cpp @@ -110,12 +110,12 @@ namespace MWRender const int cellY = store->cell->getGridY(); ESM::Land* land = MWBase::Environment::get().getWorld()->getStore().lands.search(cellX, cellY); - if ( land != NULL ) + if (land == NULL) // no land data means we're not going to create any terrain. + return; + + if (!land->dataLoaded) { - if (!land->dataLoaded) - { - land->loadData(); - } + land->loadData(); } //split the cell terrain into four segments @@ -138,25 +138,18 @@ namespace MWRender mLandSize*mLandSize, MEMCATEGORY_GEOMETRY); - if ( land != NULL ) + //copy the height data row by row + for ( int terrainCopyY = 0; terrainCopyY < mLandSize; terrainCopyY++ ) { - //copy the height data row by row - for ( int terrainCopyY = 0; terrainCopyY < mLandSize; terrainCopyY++ ) - { - //the offset of the current segment - const size_t yOffset = y * (mLandSize-1) * ESM::Land::LAND_SIZE + - //offset of the row - terrainCopyY * ESM::Land::LAND_SIZE; - const size_t xOffset = x * (mLandSize-1); + //the offset of the current segment + const size_t yOffset = y * (mLandSize-1) * ESM::Land::LAND_SIZE + + //offset of the row + terrainCopyY * ESM::Land::LAND_SIZE; + const size_t xOffset = x * (mLandSize-1); - memcpy(&terrainData.inputFloat[terrainCopyY*mLandSize], - &land->landData->heights[yOffset + xOffset], - mLandSize*sizeof(float)); - } - } - else - { - memset(terrainData.inputFloat, 0, mLandSize*mLandSize*sizeof(float)); + memcpy(&terrainData.inputFloat[terrainCopyY*mLandSize], + &land->landData->heights[yOffset + xOffset], + mLandSize*sizeof(float)); } std::map indexes; @@ -179,7 +172,7 @@ namespace MWRender terrain->setVisibilityFlags(RV_Terrain); terrain->setRenderQueueGroup(RQG_Main); - if ( land && land->landData->usingColours ) + if ( land->landData->usingColours ) { // disable or enable global colour map (depends on available vertex colours) mActiveProfile->setGlobalColourMapEnabled(true); @@ -196,10 +189,6 @@ namespace MWRender //mat = terrain->_getCompositeMapMaterial(); //mat->getTechnique(0)->getPass(0)->getTextureUnitState(1)->setTextureName( vertex->getName() ); } - else - { - mActiveProfile->setGlobalColourMapEnabled(false); - } } } } @@ -215,8 +204,10 @@ namespace MWRender { for ( int y = 0; y < 2; y++ ) { - mTerrainGroup.unloadTerrain(store->cell->getGridX() * 2 + x, - store->cell->getGridY() * 2 + y); + int terrainX = store->cell->getGridX() * 2 + x; + int terrainY = store->cell->getGridY() * 2 + y; + if (mTerrainGroup.getTerrain(terrainX, terrainY) != NULL) + mTerrainGroup.unloadTerrain(terrainX, terrainY); } } } diff --git a/apps/openmw/mwsound/soundmanager.cpp b/apps/openmw/mwsound/soundmanager.cpp index 9eefc7a28d..8deab3c046 100644 --- a/apps/openmw/mwsound/soundmanager.cpp +++ b/apps/openmw/mwsound/soundmanager.cpp @@ -433,7 +433,10 @@ namespace MWSound total = 0; } - const ESM::Region *regn = MWBase::Environment::get().getWorld()->getStore().regions.find(regionName); + const ESM::Region *regn = MWBase::Environment::get().getWorld()->getStore().regions.search(regionName); + if (regn == NULL) + return; + std::vector::const_iterator soundIter; if(total == 0) { From 6ae642aa069efabd7eb3d643e9906eb5ffa4d8ec Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 17 May 2012 21:15:48 +0200 Subject: [PATCH 198/325] complete trade window layout --- apps/openmw/mwgui/container.cpp | 2 - apps/openmw/mwgui/dialogue.cpp | 2 + apps/openmw/mwgui/tradewindow.cpp | 77 +++++++++++++++++++--- apps/openmw/mwgui/tradewindow.hpp | 15 +++++ apps/openmw/mwgui/window_manager.cpp | 6 ++ apps/openmw/mwgui/window_manager.hpp | 3 +- files/mygui/openmw_trade_window_layout.xml | 36 ++++++++-- 7 files changed, 122 insertions(+), 19 deletions(-) diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index eb02c5826b..078a5e370a 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -470,7 +470,6 @@ void ContainerWindow::onCloseButtonClicked(MyGUI::Widget* _sender) if(mDragAndDrop == NULL || !mDragAndDrop->mIsOnDragAndDrop) { MWBase::Environment::get().getWindowManager()->setGuiMode(GM_Game); - setVisible(false); } } @@ -502,6 +501,5 @@ void ContainerWindow::onTakeAllButtonClicked(MyGUI::Widget* _sender) containerStore.clear(); MWBase::Environment::get().getWindowManager()->setGuiMode(GM_Game); - setVisible(false); } } diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 953657565f..e8db4b6d15 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -17,6 +17,7 @@ #include "widgets.hpp" #include "list.hpp" #include "tradewindow.hpp" +#include "inventorywindow.hpp" using namespace MWGui; using namespace Widgets; @@ -137,6 +138,7 @@ void DialogueWindow::onSelectTopic(std::string topic) { /// \todo check if the player is allowed to trade with this actor (e.g. faction rank high enough)? mWindowManager.getTradeWindow()->startTrade(mActor); + mWindowManager.setGuiMode(GM_Barter); } else diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index 09557b196e..31e0722aab 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -3,24 +3,49 @@ #include "../mwbase/environment.hpp" #include "../mwworld/world.hpp" +#include "window_manager.hpp" + namespace MWGui { TradeWindow::TradeWindow(WindowManager& parWindowManager) : WindowBase("openmw_trade_window_layout.xml", parWindowManager), ContainerBase(NULL) // no drag&drop { - getWidget(mFilterAll, "AllButton"); - getWidget(mFilterWeapon, "WeaponButton"); - getWidget(mFilterApparel, "ApparelButton"); - getWidget(mFilterMagic, "MagicButton"); - getWidget(mFilterMisc, "MiscButton"); - MyGUI::ScrollView* itemView; MyGUI::Widget* containerWidget; getWidget(containerWidget, "Items"); getWidget(itemView, "ItemView"); setWidgets(containerWidget, itemView); + getWidget(mFilterAll, "AllButton"); + getWidget(mFilterWeapon, "WeaponButton"); + getWidget(mFilterApparel, "ApparelButton"); + getWidget(mFilterMagic, "MagicButton"); + getWidget(mFilterMisc, "MiscButton"); + + getWidget(mMaxSaleButton, "MaxSaleButton"); + getWidget(mCancelButton, "CancelButton"); + getWidget(mOfferButton, "OfferButton"); + getWidget(mPlayerGold, "PlayerGold"); + getWidget(mMerchantGold, "MerchantGold"); + getWidget(mIncreaseButton, "IncreaseButton"); + getWidget(mDecreaseButton, "DecreaseButton"); + getWidget(mTotalBalance, "TotalBalance"); + getWidget(mTotalBalanceLabel, "TotalBalanceLabel"); + getWidget(mBottomPane, "BottomPane"); + + // this GMST doesn't seem to get retrieved - even though i can clearly see it in the CS !??!? + mMaxSaleButton->setCaption(mWindowManager.getGameSettingString("sMaxSale", "Max. Sale")); + + mCancelButton->setCaption(MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sCancel")->str); + mOfferButton->setCaption(MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sOffer")->str); +/* + mTotalBalanceLabel->setCaption(MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sTotalCost")->str); + mTotalBalanceLabel->setCaption(MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sTotalSold")->str); + mPlayerGold->setCaption(MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sYourGold")->str); + mMerchantGold->setCaption(MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sSellerGold")->str); + +*/ mFilterAll->setCaption (MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sAllTab")->str); mFilterWeapon->setCaption (MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sWeaponTab")->str); mFilterApparel->setCaption (MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sApparelTab")->str); @@ -47,20 +72,42 @@ namespace MWGui mFilterMisc->setPosition(curX, mFilterMisc->getPosition().top); mFilterMisc->setSize( mFilterMisc->getTextSize().width + 24, mFilterMisc->getSize().height ); + mFilterAll->setStateSelected(true); + mFilterAll->eventMouseButtonClick += MyGUI::newDelegate(this, &TradeWindow::onFilterChanged); mFilterWeapon->eventMouseButtonClick += MyGUI::newDelegate(this, &TradeWindow::onFilterChanged); mFilterApparel->eventMouseButtonClick += MyGUI::newDelegate(this, &TradeWindow::onFilterChanged); mFilterMagic->eventMouseButtonClick += MyGUI::newDelegate(this, &TradeWindow::onFilterChanged); mFilterMisc->eventMouseButtonClick += MyGUI::newDelegate(this, &TradeWindow::onFilterChanged); - mFilterAll->setStateSelected(true); + mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &TradeWindow::onCancelButtonClicked); + mOfferButton->eventMouseButtonClick += MyGUI::newDelegate(this, &TradeWindow::onOfferButtonClicked); + + mMaxSaleButton->setSize(MyGUI::IntSize(mMaxSaleButton->getTextSize().width + 24, mMaxSaleButton->getHeight())); + + int cancelButtonWidth = mCancelButton->getTextSize().width + 24; + mCancelButton->setCoord(mBottomPane->getWidth()-cancelButtonWidth, + mCancelButton->getTop(), + cancelButtonWidth, + mCancelButton->getHeight()); + + int offerButtonWidth = mOfferButton->getTextSize().width + 24; + mOfferButton->setCoord(mBottomPane->getWidth()-cancelButtonWidth-offerButtonWidth-8, + mOfferButton->getTop(), + offerButtonWidth, + mOfferButton->getHeight()); + + setCoord(400, 0, 400, 300); + + static_cast(mMainWidget)->eventWindowChangeCoord += MyGUI::newDelegate(this, &TradeWindow::onWindowResize); } void TradeWindow::startTrade(MWWorld::Ptr actor) { ContainerBase::openContainer(actor); - setVisible(true); + setTitle(MWWorld::Class::get(actor).getName(actor)); + adjustWindowCaption(); } void TradeWindow::onFilterChanged(MyGUI::Widget* _sender) @@ -84,4 +131,18 @@ namespace MWGui static_cast(_sender)->setStateSelected(true); } + + void TradeWindow::onWindowResize(MyGUI::Window* _sender) + { + drawItems(); + } + + void TradeWindow::onOfferButtonClicked(MyGUI::Widget* _sender) + { + } + + void TradeWindow::onCancelButtonClicked(MyGUI::Widget* _sender) + { + mWindowManager.setGuiMode(GM_Game); + } } diff --git a/apps/openmw/mwgui/tradewindow.hpp b/apps/openmw/mwgui/tradewindow.hpp index 5fc5b98b64..1f937d06ec 100644 --- a/apps/openmw/mwgui/tradewindow.hpp +++ b/apps/openmw/mwgui/tradewindow.hpp @@ -37,8 +37,23 @@ namespace MWGui MyGUI::Button* mFilterMagic; MyGUI::Button* mFilterMisc; + MyGUI::Button* mIncreaseButton; + MyGUI::Button* mDecreaseButton; + MyGUI::TextBox* mTotalBalanceLabel; + MyGUI::TextBox* mTotalBalance; + + MyGUI::Widget* mBottomPane; + + MyGUI::Button* mMaxSaleButton; + MyGUI::Button* mCancelButton; + MyGUI::Button* mOfferButton; + MyGUI::TextBox* mPlayerGold; + MyGUI::TextBox* mMerchantGold; + void onWindowResize(MyGUI::Window* _sender); void onFilterChanged(MyGUI::Widget* _sender); + void onOfferButtonClicked(MyGUI::Widget* _sender); + void onCancelButtonClicked(MyGUI::Widget* _sender); }; } diff --git a/apps/openmw/mwgui/window_manager.cpp b/apps/openmw/mwgui/window_manager.cpp index 1593c6b199..e970de2e6c 100644 --- a/apps/openmw/mwgui/window_manager.cpp +++ b/apps/openmw/mwgui/window_manager.cpp @@ -215,6 +215,7 @@ void WindowManager::updateVisible() mInventoryWindow->setVisible(false); mScrollWindow->setVisible(false); mBookWindow->setVisible(false); + mTradeWindow->setVisible(false); // Mouse is visible whenever we're not in game mode MyGUI::PointerManager::getInstance().setVisible(isGuiMode()); @@ -273,6 +274,11 @@ void WindowManager::updateVisible() case GM_Dialogue: mDialogueWindow->open(); break; + case GM_Barter: + mInventoryWindow->setVisible(true); + mInventoryWindow->openInventory(); + mTradeWindow->setVisible(true); + break; case GM_InterMessageBox: if(!mMessageBoxManager->isInteractiveMessageBox()) { setGuiMode(GM_Game); diff --git a/apps/openmw/mwgui/window_manager.hpp b/apps/openmw/mwgui/window_manager.hpp index 52869ff55a..82c494191a 100644 --- a/apps/openmw/mwgui/window_manager.hpp +++ b/apps/openmw/mwgui/window_manager.hpp @@ -130,9 +130,8 @@ namespace MWGui } MWGui::DialogueWindow* getDialogueWindow() {return mDialogueWindow;} - MWGui::ContainerWindow* getContainerWindow() {return mContainerWindow;} - + MWGui::InventoryWindow* getInventoryWindow() {return mInventoryWindow;} MWGui::BookWindow* getBookWindow() {return mBookWindow;} MWGui::ScrollWindow* getScrollWindow() {return mScrollWindow;} MWGui::CountDialog* getCountDialog() {return mCountDialog;} diff --git a/files/mygui/openmw_trade_window_layout.xml b/files/mygui/openmw_trade_window_layout.xml index 15d313c4da..076924322d 100644 --- a/files/mygui/openmw_trade_window_layout.xml +++ b/files/mygui/openmw_trade_window_layout.xml @@ -1,11 +1,11 @@ - + - + @@ -14,14 +14,36 @@ - - - + + + + - - + + + + + + + + + + + + + + + + + + + + + + + From 41efea4c1d637b61e3f6be6757d2ae5478f5fcf1 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 17 May 2012 21:56:16 +0200 Subject: [PATCH 199/325] in the trade window, don't show items that the merchant has equipped. --- apps/openmw/mwgui/container.cpp | 9 ++-- apps/openmw/mwgui/container.hpp | 3 ++ apps/openmw/mwgui/inventorywindow.cpp | 19 ++++++-- apps/openmw/mwgui/inventorywindow.hpp | 2 + apps/openmw/mwgui/tradewindow.cpp | 52 +++++++++++++++++++--- apps/openmw/mwgui/tradewindow.hpp | 8 ++++ apps/openmw/mwgui/window_manager.cpp | 2 +- files/mygui/openmw_trade_window_layout.xml | 4 +- 8 files changed, 85 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 078a5e370a..6f8ca4730a 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -300,10 +300,13 @@ void ContainerBase::drawItems() equippedItems.erase(found); } // and add the items that are left (= have the correct category) - for (std::vector::const_iterator it=equippedItems.begin(); - it != equippedItems.end(); ++it) + if (!ignoreEquippedItems()) { - items.push_back( std::make_pair(*it, ItemState_Equipped) ); + for (std::vector::const_iterator it=equippedItems.begin(); + it != equippedItems.end(); ++it) + { + items.push_back( std::make_pair(*it, ItemState_Equipped) ); + } } // now add the regular items diff --git a/apps/openmw/mwgui/container.hpp b/apps/openmw/mwgui/container.hpp index fe4ffc285c..956382f23d 100644 --- a/apps/openmw/mwgui/container.hpp +++ b/apps/openmw/mwgui/container.hpp @@ -98,6 +98,9 @@ namespace MWGui virtual bool isInventory() { return false; } virtual std::vector getEquippedItems() { return std::vector(); } virtual void _unequipItem(MWWorld::Ptr item) { ; } + + // to be reimplemented by TradeWindow + virtual bool ignoreEquippedItems() { return false; } }; class ContainerWindow : public ContainerBase, public WindowBase diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 92c0553f69..ebba395ff1 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -84,13 +84,13 @@ namespace MWGui mFilterAll->setStateSelected(true); setCoord(0, 342, 600, 258); + + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + openContainer(player); } void InventoryWindow::openInventory() { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); - openContainer(player); - onWindowResize(static_cast(mMainWidget)); updateEncumbranceBar(); @@ -232,4 +232,17 @@ namespace MWGui ContainerBase::Update(); } + + int InventoryWindow::getPlayerGold() + { + MWWorld::InventoryStore& invStore = static_cast(MWWorld::Class::get(mContainer).getContainerStore(mContainer)); + + for (MWWorld::ContainerStoreIterator it = invStore.begin(); + it != invStore.end(); ++it) + { + if (MWWorld::Class::get(*it).getName(*it) == MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sGold")->str) + return it->getRefData().getCount(); + } + return 0; + } } diff --git a/apps/openmw/mwgui/inventorywindow.hpp b/apps/openmw/mwgui/inventorywindow.hpp index 07aeeeafd9..e53402bbd0 100644 --- a/apps/openmw/mwgui/inventorywindow.hpp +++ b/apps/openmw/mwgui/inventorywindow.hpp @@ -16,6 +16,8 @@ namespace MWGui virtual void Update(); virtual void notifyContentChanged(); + int getPlayerGold(); + protected: MyGUI::Widget* mAvatar; MyGUI::TextBox* mArmorRating; diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index 31e0722aab..8348b60667 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -1,15 +1,20 @@ #include "tradewindow.hpp" +#include + #include "../mwbase/environment.hpp" #include "../mwworld/world.hpp" +#include "../mwworld/inventorystore.hpp" #include "window_manager.hpp" +#include "inventorywindow.hpp" namespace MWGui { TradeWindow::TradeWindow(WindowManager& parWindowManager) : - WindowBase("openmw_trade_window_layout.xml", parWindowManager), - ContainerBase(NULL) // no drag&drop + WindowBase("openmw_trade_window_layout.xml", parWindowManager) + , ContainerBase(NULL) // no drag&drop + , mCurrentBalance(0) { MyGUI::ScrollView* itemView; MyGUI::Widget* containerWidget; @@ -40,9 +45,6 @@ namespace MWGui mCancelButton->setCaption(MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sCancel")->str); mOfferButton->setCaption(MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sOffer")->str); /* - mTotalBalanceLabel->setCaption(MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sTotalCost")->str); - mTotalBalanceLabel->setCaption(MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sTotalSold")->str); - mPlayerGold->setCaption(MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sYourGold")->str); mMerchantGold->setCaption(MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sSellerGold")->str); */ @@ -108,6 +110,10 @@ namespace MWGui setTitle(MWWorld::Class::get(actor).getName(actor)); adjustWindowCaption(); + + mCurrentBalance = 0; + + updateLabels(); } void TradeWindow::onFilterChanged(MyGUI::Widget* _sender) @@ -145,4 +151,40 @@ namespace MWGui { mWindowManager.setGuiMode(GM_Game); } + + void TradeWindow::updateLabels() + { + mPlayerGold->setCaption(MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sYourGold")->str + + " " + boost::lexical_cast(mWindowManager.getInventoryWindow()->getPlayerGold())); + + if (mCurrentBalance > 0) + { + mTotalBalanceLabel->setCaption(MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sTotalSold")->str); + mTotalBalance->setCaption(boost::lexical_cast(mCurrentBalance)); + } + else + { + mTotalBalanceLabel->setCaption(MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sTotalCost")->str); + mTotalBalance->setCaption(boost::lexical_cast(-mCurrentBalance)); + } + } + + + std::vector TradeWindow::getEquippedItems() + { + MWWorld::InventoryStore& invStore = static_cast(MWWorld::Class::get(mContainer).getContainerStore(mContainer)); + + std::vector items; + + for (int slot=0; slot < MWWorld::InventoryStore::Slots; ++slot) + { + MWWorld::ContainerStoreIterator it = invStore.getSlot(slot); + if (it != invStore.end()) + { + items.push_back(*it); + } + } + + return items; + } } diff --git a/apps/openmw/mwgui/tradewindow.hpp b/apps/openmw/mwgui/tradewindow.hpp index 1f937d06ec..dd28fcb8b4 100644 --- a/apps/openmw/mwgui/tradewindow.hpp +++ b/apps/openmw/mwgui/tradewindow.hpp @@ -50,10 +50,18 @@ namespace MWGui MyGUI::TextBox* mPlayerGold; MyGUI::TextBox* mMerchantGold; + int mCurrentBalance; + void onWindowResize(MyGUI::Window* _sender); void onFilterChanged(MyGUI::Widget* _sender); void onOfferButtonClicked(MyGUI::Widget* _sender); void onCancelButtonClicked(MyGUI::Widget* _sender); + + // don't show items that the NPC has equipped in his trade-window. + virtual bool ignoreEquippedItems() { return true; } + virtual std::vector getEquippedItems(); + + void updateLabels(); }; } diff --git a/apps/openmw/mwgui/window_manager.cpp b/apps/openmw/mwgui/window_manager.cpp index e970de2e6c..e12fb851e0 100644 --- a/apps/openmw/mwgui/window_manager.cpp +++ b/apps/openmw/mwgui/window_manager.cpp @@ -108,10 +108,10 @@ WindowManager::WindowManager( console = new Console(w,h, extensions); mJournal = new JournalWindow(*this); mMessageBoxManager = new MessageBoxManager(this); + mInventoryWindow = new InventoryWindow(*this,mDragAndDrop); mTradeWindow = new TradeWindow(*this); mDialogueWindow = new DialogueWindow(*this); mContainerWindow = new ContainerWindow(*this,mDragAndDrop); - mInventoryWindow = new InventoryWindow(*this,mDragAndDrop); hud = new HUD(w,h, showFPSLevel, mDragAndDrop); mToolTips = new ToolTips(this); mScrollWindow = new ScrollWindow(*this); diff --git a/files/mygui/openmw_trade_window_layout.xml b/files/mygui/openmw_trade_window_layout.xml index 076924322d..b6a93e6973 100644 --- a/files/mygui/openmw_trade_window_layout.xml +++ b/files/mygui/openmw_trade_window_layout.xml @@ -22,10 +22,10 @@ - + - + From 9a3fd96a0cc8a86ae31add0539778a586800fba6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 17 May 2012 22:24:47 +0200 Subject: [PATCH 200/325] display the merchant gold. --- apps/openmw/mwgui/tradewindow.cpp | 43 +++++++++++++++++++++++++++---- 1 file changed, 38 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index 8348b60667..c6b677d8b0 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -44,10 +44,7 @@ namespace MWGui mCancelButton->setCaption(MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sCancel")->str); mOfferButton->setCaption(MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sOffer")->str); -/* - mMerchantGold->setCaption(MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sSellerGold")->str); -*/ mFilterAll->setCaption (MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sAllTab")->str); mFilterWeapon->setCaption (MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sWeaponTab")->str); mFilterApparel->setCaption (MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sApparelTab")->str); @@ -167,15 +164,51 @@ namespace MWGui mTotalBalanceLabel->setCaption(MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sTotalCost")->str); mTotalBalance->setCaption(boost::lexical_cast(-mCurrentBalance)); } - } + // retrieve merchant gold + int gold = 0; + MWWorld::InventoryStore& invStore = static_cast(MWWorld::Class::get(mContainer).getContainerStore(mContainer)); + for (MWWorld::ContainerStoreIterator it = invStore.begin(); + it != invStore.end(); ++it) + { + if (MWWorld::Class::get(*it).getName(*it) == MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sGold")->str) + gold = it->getRefData().getCount(); + } + + int merchantgold; + if (mContainer.getTypeName() == typeid(ESM::NPC).name()) + { + ESMS::LiveCellRef* ref = mContainer.get(); + if (ref->base->npdt52.gold == -10) + merchantgold = ref->base->npdt12.gold; + else + merchantgold = ref->base->npdt52.gold; + } + else // ESM::Creature + { + ESMS::LiveCellRef* ref = mContainer.get(); + merchantgold = ref->base->data.gold; + } + gold += merchantgold; + + mMerchantGold->setCaption(MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sSellerGold")->str + + " " + boost::lexical_cast(gold)); + } std::vector TradeWindow::getEquippedItems() { - MWWorld::InventoryStore& invStore = static_cast(MWWorld::Class::get(mContainer).getContainerStore(mContainer)); + std::vector items; + if (mContainer.getTypeName() == typeid(ESM::Creature).name()) + { + // creatures don't have equipment slots. + return items; + } + + MWWorld::InventoryStore& invStore = static_cast(MWWorld::Class::get(mContainer).getContainerStore(mContainer)); + for (int slot=0; slot < MWWorld::InventoryStore::Slots; ++slot) { MWWorld::ContainerStoreIterator it = invStore.getSlot(slot); From 3cacc8feec26ef71d117d53a098b73e571c6f685 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 17 May 2012 23:22:41 +0200 Subject: [PATCH 201/325] add re-stocking items to containers (though restocking isn't implemented) --- apps/openmw/mwworld/containerstore.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index 5dfc9a1777..b32bcd5d96 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -150,7 +150,7 @@ void MWWorld::ContainerStore::fill (const ESM::InventoryList& items, const ESMS: continue; } - ref.getPtr().getRefData().setCount (iter->count); + ref.getPtr().getRefData().setCount (std::abs(iter->count)); /// \todo implement item restocking (indicated by negative count) add (ref.getPtr()); } From 52e5e14654ed786776d595538bc21335f1c4464a Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 17 May 2012 23:42:09 +0200 Subject: [PATCH 202/325] use GMST sDefaultCellname for the map window when cell has no region or name. --- apps/openmw/mwgui/window_manager.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/openmw/mwgui/window_manager.cpp b/apps/openmw/mwgui/window_manager.cpp index 610f1b2f25..2200448e63 100644 --- a/apps/openmw/mwgui/window_manager.cpp +++ b/apps/openmw/mwgui/window_manager.cpp @@ -449,6 +449,8 @@ void WindowManager::changeCell(MWWorld::Ptr::CellStore* cell) const ESM::Region* region = MWBase::Environment::get().getWorld()->getStore().regions.search(cell->cell->region); if (region) name = region->name; + else + name = getGameSettingString("sDefaultCellname", "Wilderness"); } map->setCellName( name ); From adf055029219ec9525820b9996cdafa4d376d73e Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 May 2012 00:14:31 +0200 Subject: [PATCH 203/325] fixed a wrong label. --- apps/openmw/mwgui/tradewindow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index c6b677d8b0..97c66b9dcf 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -43,7 +43,7 @@ namespace MWGui mMaxSaleButton->setCaption(mWindowManager.getGameSettingString("sMaxSale", "Max. Sale")); mCancelButton->setCaption(MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sCancel")->str); - mOfferButton->setCaption(MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sOffer")->str); + mOfferButton->setCaption(MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sBarterDialog8")->str); mFilterAll->setCaption (MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sAllTab")->str); mFilterWeapon->setCaption (MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sWeaponTab")->str); From e1997b7f04396cc55bbb50132a945b0560d43b13 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 18 May 2012 13:17:35 +0200 Subject: [PATCH 204/325] Issue #256: added MagicEffects::add overload for EffectLists --- apps/openmw/mwmechanics/magiceffects.cpp | 19 +++++++++++++++++++ apps/openmw/mwmechanics/magiceffects.hpp | 3 +++ apps/openmw/mwmechanics/spells.cpp | 8 +------- 3 files changed, 23 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwmechanics/magiceffects.cpp b/apps/openmw/mwmechanics/magiceffects.cpp index 1c73bf1b15..52811084f4 100644 --- a/apps/openmw/mwmechanics/magiceffects.cpp +++ b/apps/openmw/mwmechanics/magiceffects.cpp @@ -1,6 +1,8 @@ #include "magiceffects.hpp" +#include + #include #include @@ -66,6 +68,23 @@ namespace MWMechanics } } + void MagicEffects::add (const ESM::EffectList& list) + { + for (std::vector::const_iterator iter (list.list.begin()); iter!=list.list.end(); + ++iter) + { + EffectParam param; + + if (iter->magnMin>=iter->magnMax) + param.mMagnitude = iter->magnMin; + else + param.mMagnitude = static_cast ( + (iter->magnMax-iter->magnMin+1)*(std::rand() / RAND_MAX) + iter->magnMin); + + add (*iter, param); + } + } + EffectParam MagicEffects::get (const EffectKey& key) const { Collection::const_iterator iter = mCollection.find (key); diff --git a/apps/openmw/mwmechanics/magiceffects.hpp b/apps/openmw/mwmechanics/magiceffects.hpp index 3d36ea813d..d47101d458 100644 --- a/apps/openmw/mwmechanics/magiceffects.hpp +++ b/apps/openmw/mwmechanics/magiceffects.hpp @@ -6,6 +6,7 @@ namespace ESM { struct ENAMstruct; + struct EffectList; } namespace MWMechanics @@ -66,6 +67,8 @@ namespace MWMechanics void add (const EffectKey& key, const EffectParam& param); + void add (const ESM::EffectList& list); + EffectParam get (const EffectKey& key) const; ///< This function can safely be used for keys that are not present. diff --git a/apps/openmw/mwmechanics/spells.cpp b/apps/openmw/mwmechanics/spells.cpp index a53c75dc22..af43cdfb55 100644 --- a/apps/openmw/mwmechanics/spells.cpp +++ b/apps/openmw/mwmechanics/spells.cpp @@ -13,13 +13,7 @@ namespace MWMechanics { void Spells::addSpell (const ESM::Spell *spell, MagicEffects& effects) const { - for (std::vector::const_iterator iter = spell->effects.list.begin(); - iter!=spell->effects.list.end(); ++iter) - { - EffectParam param; - param.mMagnitude = iter->magnMax; /// \todo calculate magnitude - effects.add (EffectKey (*iter), param); - } + effects.add (spell->effects); } Spells::TIterator Spells::begin() const From 79055e281d882ee68ba2d2ef2abef65120254ed4 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 18 May 2012 13:54:07 +0200 Subject: [PATCH 205/325] Issue #256: Force update after building the player character --- apps/openmw/mwmechanics/actors.cpp | 3 --- apps/openmw/mwmechanics/actors.hpp | 7 +++++-- apps/openmw/mwmechanics/mechanicsmanager.cpp | 6 ++++++ 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index b0bb1e3ef9..c527a645cd 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -32,9 +32,6 @@ namespace MWMechanics creatureStats.mDynamic[1].setBase (static_cast (intelligence + magickaFactor * intelligence)); creatureStats.mDynamic[2].setBase (strength+willpower+agility+endurance); - - for (int i=0; i<3; ++i) - creatureStats.mDynamic[i].setCurrent (creatureStats.mDynamic[i].getModified()); } void Actors::updateNpc (const MWWorld::Ptr& ptr, float duration, bool paused) diff --git a/apps/openmw/mwmechanics/actors.hpp b/apps/openmw/mwmechanics/actors.hpp index 37a00deecc..30e73ccf75 100644 --- a/apps/openmw/mwmechanics/actors.hpp +++ b/apps/openmw/mwmechanics/actors.hpp @@ -19,8 +19,6 @@ namespace MWMechanics std::set mActors; float mDuration; - void updateActor (const MWWorld::Ptr& ptr, float duration); - void updateNpc (const MWWorld::Ptr& ptr, float duration, bool paused); void adjustMagicEffects (const MWWorld::Ptr& creature); @@ -41,6 +39,11 @@ namespace MWMechanics void update (std::vector >& movement, float duration, bool paused); ///< Update actor stats and store desired velocity vectors in \a movement + + void updateActor (const MWWorld::Ptr& ptr, float duration); + ///< This function is normally called automatically during the update process, but it can + /// also be called explicitly at any time to force an update. + }; } diff --git a/apps/openmw/mwmechanics/mechanicsmanager.cpp b/apps/openmw/mwmechanics/mechanicsmanager.cpp index 66a850b051..0c48d88944 100644 --- a/apps/openmw/mwmechanics/mechanicsmanager.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanager.cpp @@ -138,6 +138,12 @@ namespace MWMechanics } } } + + // forced update and current value adjustments + mActors.updateActor (ptr, 0); + + for (int i=0; i<3; ++i) + creatureStats.mDynamic[i].setCurrent (creatureStats.mDynamic[i].getModified()); } From 5236bcb557923406edf234dbb3c4bb3a3d39f46e Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 18 May 2012 15:12:11 +0200 Subject: [PATCH 206/325] Issue #256: added operator+= for MagicEffects --- apps/openmw/mwmechanics/magiceffects.cpp | 24 ++++++++++++++++++++++++ apps/openmw/mwmechanics/magiceffects.hpp | 2 ++ 2 files changed, 26 insertions(+) diff --git a/apps/openmw/mwmechanics/magiceffects.cpp b/apps/openmw/mwmechanics/magiceffects.cpp index 52811084f4..41d898ca8d 100644 --- a/apps/openmw/mwmechanics/magiceffects.cpp +++ b/apps/openmw/mwmechanics/magiceffects.cpp @@ -85,6 +85,30 @@ namespace MWMechanics } } + MagicEffects& MagicEffects::operator+= (const MagicEffects& effects) + { + if (this==&effects) + { + MagicEffects temp (effects); + *this += temp; + return *this; + } + + for (Collection::const_iterator iter (effects.Begin()); iter!=effects.End(); ++iter) + { + Collection::iterator result = mCollection.find (iter->first); + + if (result!=mCollection.end()) + { + result->second.mMagnitude += iter->second.mMagnitude; + } + else + mCollection.insert (*iter); + } + + return *this; + } + EffectParam MagicEffects::get (const EffectKey& key) const { Collection::const_iterator iter = mCollection.find (key); diff --git a/apps/openmw/mwmechanics/magiceffects.hpp b/apps/openmw/mwmechanics/magiceffects.hpp index d47101d458..26f78ec8a2 100644 --- a/apps/openmw/mwmechanics/magiceffects.hpp +++ b/apps/openmw/mwmechanics/magiceffects.hpp @@ -69,6 +69,8 @@ namespace MWMechanics void add (const ESM::EffectList& list); + MagicEffects& operator+= (const MagicEffects& effects); + EffectParam get (const EffectKey& key) const; ///< This function can safely be used for keys that are not present. From 40c58c1bb79da8794862ff7f93806f4ff16d5ce6 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 18 May 2012 15:26:08 +0200 Subject: [PATCH 207/325] Issue #256: fixed a capitalisation mistake --- apps/openmw/mwmechanics/magiceffects.cpp | 11 +++++------ apps/openmw/mwmechanics/magiceffects.hpp | 4 ++-- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwmechanics/magiceffects.cpp b/apps/openmw/mwmechanics/magiceffects.cpp index 41d898ca8d..97c2ec8c83 100644 --- a/apps/openmw/mwmechanics/magiceffects.cpp +++ b/apps/openmw/mwmechanics/magiceffects.cpp @@ -94,7 +94,7 @@ namespace MWMechanics return *this; } - for (Collection::const_iterator iter (effects.Begin()); iter!=effects.End(); ++iter) + for (Collection::const_iterator iter (effects.begin()); iter!=effects.end(); ++iter) { Collection::iterator result = mCollection.find (iter->first); @@ -128,11 +128,11 @@ namespace MWMechanics MagicEffects result; // adding/changing - for (Collection::const_iterator iter (now.Begin()); iter!=now.End(); ++iter) + for (Collection::const_iterator iter (now.begin()); iter!=now.end(); ++iter) { Collection::const_iterator other = prev.mCollection.find (iter->first); - if (other==prev.End()) + if (other==prev.end()) { // adding result.add (iter->first, iter->second); @@ -145,17 +145,16 @@ namespace MWMechanics } // removing - for (Collection::const_iterator iter (prev.Begin()); iter!=prev.End(); ++iter) + for (Collection::const_iterator iter (prev.begin()); iter!=prev.end(); ++iter) { Collection::const_iterator other = now.mCollection.find (iter->first); - if (other==prev.End()) + if (other==prev.end()) { result.add (iter->first, EffectParam() - iter->second); } } return result; - } } diff --git a/apps/openmw/mwmechanics/magiceffects.hpp b/apps/openmw/mwmechanics/magiceffects.hpp index 26f78ec8a2..2f61d7eeb4 100644 --- a/apps/openmw/mwmechanics/magiceffects.hpp +++ b/apps/openmw/mwmechanics/magiceffects.hpp @@ -61,9 +61,9 @@ namespace MWMechanics public: - Collection::const_iterator Begin() const { return mCollection.begin(); } + Collection::const_iterator begin() const { return mCollection.begin(); } - Collection::const_iterator End() const { return mCollection.end(); } + Collection::const_iterator end() const { return mCollection.end(); } void add (const EffectKey& key, const EffectParam& param); From 372efaafd718a4f878d6d96ad273d39be8580835 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 18 May 2012 15:27:41 +0200 Subject: [PATCH 208/325] Issue #256: changed implementation of MagicEffects::operator+= --- apps/openmw/mwmechanics/magiceffects.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/apps/openmw/mwmechanics/magiceffects.cpp b/apps/openmw/mwmechanics/magiceffects.cpp index 97c2ec8c83..f71e070d21 100644 --- a/apps/openmw/mwmechanics/magiceffects.cpp +++ b/apps/openmw/mwmechanics/magiceffects.cpp @@ -99,9 +99,7 @@ namespace MWMechanics Collection::iterator result = mCollection.find (iter->first); if (result!=mCollection.end()) - { - result->second.mMagnitude += iter->second.mMagnitude; - } + result->second += iter->second; else mCollection.insert (*iter); } From 124ea7761214497f8be57309f046f2333c94b415 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 18 May 2012 15:48:55 +0200 Subject: [PATCH 209/325] Issue #256: consider equipped items when calculating magic effects --- apps/openmw/mwmechanics/actors.cpp | 8 ++++- apps/openmw/mwworld/containerstore.hpp | 2 +- apps/openmw/mwworld/inventorystore.cpp | 42 ++++++++++++++++++++++++-- apps/openmw/mwworld/inventorystore.hpp | 14 +++++++++ 4 files changed, 62 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index c527a645cd..cd2dbaddfd 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -47,7 +47,13 @@ namespace MWMechanics MagicEffects now = creatureStats.mSpells.getMagicEffects(); - /// \todo add effects from active spells and equipment + if (creature.getTypeName()==typeid (ESM::NPC).name()) + { + MWWorld::InventoryStore& store = MWWorld::Class::get (creature).getInventoryStore (creature); + now += store.getMagicEffects(); + } + + /// \todo add effects from active spells MagicEffects diff = MagicEffects::diff (creatureStats.mMagicEffects, now); diff --git a/apps/openmw/mwworld/containerstore.hpp b/apps/openmw/mwworld/containerstore.hpp index 3cb3f3bdc5..f677e0dcbb 100644 --- a/apps/openmw/mwworld/containerstore.hpp +++ b/apps/openmw/mwworld/containerstore.hpp @@ -90,7 +90,7 @@ namespace MWWorld void clear(); ///< Empty container. - void flagAsModified(); + virtual void flagAsModified(); ///< \attention This function is internal to the world model and should not be called from /// outside. diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index 3e535793c0..6981aea02c 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -4,6 +4,12 @@ #include #include +#include + +#include "../mwbase/environment.hpp" + +#include "../mwworld/world.hpp" + #include "../mwmechanics/npcstats.hpp" #include "class.hpp" @@ -32,13 +38,13 @@ void MWWorld::InventoryStore::initSlots (TSlots& slots) slots.push_back (end()); } -MWWorld::InventoryStore::InventoryStore() +MWWorld::InventoryStore::InventoryStore() : mMagicEffectsUpToDate (false) { initSlots (mSlots); } MWWorld::InventoryStore::InventoryStore (const InventoryStore& store) -: ContainerStore (store) +: ContainerStore (store), mMagicEffectsUpToDate (false) { copySlots (store); } @@ -201,6 +207,38 @@ void MWWorld::InventoryStore::autoEquip (const MWMechanics::NpcStats& stats) } } +const MWMechanics::MagicEffects& MWWorld::InventoryStore::getMagicEffects() +{ + if (!mMagicEffectsUpToDate) + { + mMagicEffects = MWMechanics::MagicEffects(); + + for (TSlots::const_iterator iter (mSlots.begin()); iter!=mSlots.end(); ++iter) + if (*iter!=end()) + { + std::string enchantmentId = MWWorld::Class::get (**iter).getEnchantment (**iter); + + if (!enchantmentId.empty()) + { + const ESM::Enchantment& enchantment = + *MWBase::Environment::get().getWorld()->getStore().enchants.find (enchantmentId); + + if (enchantment.data.type==ESM::Enchantment::ConstantEffect) + mMagicEffects.add (enchantment.effects); + } + } + + mMagicEffectsUpToDate = true; + } + + return mMagicEffects; +} + +void MWWorld::InventoryStore::flagAsModified() +{ + mMagicEffectsUpToDate = false; +} + bool MWWorld::InventoryStore::stacks(const Ptr& ptr1, const Ptr& ptr2) { bool canStack = MWWorld::ContainerStore::stacks(ptr1, ptr2); diff --git a/apps/openmw/mwworld/inventorystore.hpp b/apps/openmw/mwworld/inventorystore.hpp index 05fc651ee7..dcfb21f30f 100644 --- a/apps/openmw/mwworld/inventorystore.hpp +++ b/apps/openmw/mwworld/inventorystore.hpp @@ -3,6 +3,8 @@ #include "containerstore.hpp" +#include "../mwmechanics/magiceffects.hpp" + namespace MWMechanics { struct NpcStats; @@ -41,6 +43,9 @@ namespace MWWorld private: + mutable MWMechanics::MagicEffects mMagicEffects; + mutable bool mMagicEffectsUpToDate; + typedef std::vector TSlots; mutable TSlots mSlots; @@ -65,6 +70,15 @@ namespace MWWorld void autoEquip (const MWMechanics::NpcStats& stats); ///< Auto equip items according to stats and item value. + const MWMechanics::MagicEffects& getMagicEffects(); + ///< Return magic effects from worn items. + /// + /// \todo make this const again, after the constness of Ptrs and iterators has been addressed. + + virtual void flagAsModified(); + ///< \attention This function is internal to the world model and should not be called from + /// outside. + protected: virtual bool stacks (const Ptr& ptr1, const Ptr& ptr2); From e2400ca7b2949f0238a24d5ebe7bd657b2f362f7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 May 2012 15:51:33 +0200 Subject: [PATCH 210/325] only show items in the trade window that the NPC actually trades (services enum) --- apps/openmw/mwgui/container.cpp | 5 ++- apps/openmw/mwgui/container.hpp | 3 +- apps/openmw/mwgui/tradewindow.cpp | 59 +++++++++++++++++++++++++++++-- apps/openmw/mwgui/tradewindow.hpp | 4 +++ 4 files changed, 66 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 6f8ca4730a..9ff4b8d4a2 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -309,11 +309,14 @@ void ContainerBase::drawItems() } } + std::vector ignoreItems = itemsToIgnore(); + // now add the regular items std::vector regularItems; for (MWWorld::ContainerStoreIterator iter (containerStore.begin(categories)); iter!=containerStore.end(); ++iter) { - if (std::find(equippedItems.begin(), equippedItems.end(), *iter) == equippedItems.end()) + if (std::find(equippedItems.begin(), equippedItems.end(), *iter) == equippedItems.end() + && std::find(ignoreItems.begin(), ignoreItems.end(), *iter) == ignoreItems.end()) regularItems.push_back(*iter); } diff --git a/apps/openmw/mwgui/container.hpp b/apps/openmw/mwgui/container.hpp index 956382f23d..563b22bc30 100644 --- a/apps/openmw/mwgui/container.hpp +++ b/apps/openmw/mwgui/container.hpp @@ -94,13 +94,12 @@ namespace MWGui std::string getCountString(const int count); - // to be reimplemented by InventoryWindow virtual bool isInventory() { return false; } virtual std::vector getEquippedItems() { return std::vector(); } virtual void _unequipItem(MWWorld::Ptr item) { ; } - // to be reimplemented by TradeWindow virtual bool ignoreEquippedItems() { return false; } + virtual std::vector itemsToIgnore() { return std::vector(); } }; class ContainerWindow : public ContainerBase, public WindowBase diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index 97c66b9dcf..e5fc477640 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -197,8 +197,6 @@ namespace MWGui std::vector TradeWindow::getEquippedItems() { - - std::vector items; if (mContainer.getTypeName() == typeid(ESM::Creature).name()) @@ -220,4 +218,61 @@ namespace MWGui return items; } + + bool TradeWindow::npcAcceptsItem(MWWorld::Ptr item) + { + int services = 0; + if (mContainer.getTypeName() == typeid(ESM::NPC).name()) + { + ESMS::LiveCellRef* ref = mContainer.get(); + if (ref->base->hasAI) + services = ref->base->AI.services; + } + else if (mContainer.getTypeName() == typeid(ESM::Creature).name()) + { + ESMS::LiveCellRef* ref = mContainer.get(); + if (ref->base->hasAI) + services = ref->base->AI.services; + } + + if (item.getTypeName() == typeid(ESM::Weapon).name()) + return services & ESM::NPC::Weapon; + else if (item.getTypeName() == typeid(ESM::Armor).name()) + return services & ESM::NPC::Armor; + else if (item.getTypeName() == typeid(ESM::Clothing).name()) + return services & ESM::NPC::Clothing; + else if (item.getTypeName() == typeid(ESM::Book).name()) + return services & ESM::NPC::Books; + else if (item.getTypeName() == typeid(ESM::Ingredient).name()) + return services & ESM::NPC::Ingredients; + else if (item.getTypeName() == typeid(ESM::Tool).name()) + return services & ESM::NPC::Picks; + else if (item.getTypeName() == typeid(ESM::Probe).name()) + return services & ESM::NPC::Probes; + else if (item.getTypeName() == typeid(ESM::Light).name()) + return services & ESM::NPC::Lights; + else if (item.getTypeName() == typeid(ESM::Apparatus).name()) + return services & ESM::NPC::Apparatus; + else if (item.getTypeName() == typeid(ESM::Repair).name()) + return services & ESM::NPC::RepairItem; + else if (item.getTypeName() == typeid(ESM::Miscellaneous).name()) + return services & ESM::NPC::Misc; + + return false; + } + + std::vector TradeWindow::itemsToIgnore() + { + std::vector items; + MWWorld::InventoryStore& invStore = static_cast(MWWorld::Class::get(mContainer).getContainerStore(mContainer)); + + for (MWWorld::ContainerStoreIterator it = invStore.begin(); + it != invStore.end(); ++it) + { + if (!npcAcceptsItem(*it)) + items.push_back(*it); + } + + return items; + } } diff --git a/apps/openmw/mwgui/tradewindow.hpp b/apps/openmw/mwgui/tradewindow.hpp index dd28fcb8b4..5e762cbe54 100644 --- a/apps/openmw/mwgui/tradewindow.hpp +++ b/apps/openmw/mwgui/tradewindow.hpp @@ -30,6 +30,8 @@ namespace MWGui //virtual void Update(); //virtual void notifyContentChanged(); + bool npcAcceptsItem(MWWorld::Ptr item); + protected: MyGUI::Button* mFilterAll; MyGUI::Button* mFilterWeapon; @@ -61,6 +63,8 @@ namespace MWGui virtual bool ignoreEquippedItems() { return true; } virtual std::vector getEquippedItems(); + virtual std::vector itemsToIgnore(); + void updateLabels(); }; } From 50a8eb05d96d975f702a4d3cfced0a0b37929acb Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 May 2012 17:27:55 +0200 Subject: [PATCH 211/325] transfering items between player and merchant works and shows a red frame for bought/sold items. --- apps/openmw/mwgui/container.cpp | 162 ++++++++++++++++++++++++-- apps/openmw/mwgui/container.hpp | 22 +++- apps/openmw/mwgui/dialogue.cpp | 8 +- apps/openmw/mwgui/inventorywindow.cpp | 10 ++ apps/openmw/mwgui/inventorywindow.hpp | 6 + apps/openmw/mwgui/map_window.cpp | 3 +- apps/openmw/mwgui/stats_window.cpp | 3 +- apps/openmw/mwgui/tradewindow.cpp | 10 +- apps/openmw/mwgui/tradewindow.hpp | 3 + 9 files changed, 201 insertions(+), 26 deletions(-) diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 9ff4b8d4a2..e51e22ecdb 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -21,6 +21,8 @@ #include "window_manager.hpp" #include "widgets.hpp" #include "countdialog.hpp" +#include "tradewindow.hpp" +#include "inventorywindow.hpp" using namespace MWGui; using namespace Widgets; @@ -88,37 +90,120 @@ ContainerBase::~ContainerBase() void ContainerBase::onSelectedItem(MyGUI::Widget* _sender) { - if (mDragAndDrop) + mSelectedItem = _sender; + + if (mDragAndDrop && !isTrading()) { if(!mDragAndDrop->mIsOnDragAndDrop) { - mSelectedItem = _sender; - MWWorld::Ptr object = (*_sender->getUserData()); int count = object.getRefData().getCount(); if (MyGUI::InputManager::getInstance().isShiftPressed() || count == 1) { - onSelectedItemImpl(_sender, count); + startDragItem(_sender, count); } else if (MyGUI::InputManager::getInstance().isControlPressed()) { - onSelectedItemImpl(_sender, 1); + startDragItem(_sender, 1); } else { CountDialog* dialog = MWBase::Environment::get().getWindowManager()->getCountDialog(); dialog->open(MWWorld::Class::get(object).getName(object), count); dialog->eventOkClicked.clear(); - dialog->eventOkClicked += MyGUI::newDelegate(this, &ContainerBase::onSelectedItemImpl); + dialog->eventOkClicked += MyGUI::newDelegate(this, &ContainerBase::startDragItem); } } else onContainerClicked(mContainerWidget); } + else + { + MWWorld::Ptr object = (*_sender->getUserData()); + int count = object.getRefData().getCount(); + + if (std::find(mBoughtItems.begin(), mBoughtItems.end(), object) != mBoughtItems.end()) + { + if (MyGUI::InputManager::getInstance().isShiftPressed() || count == 1) + { + sellAlreadyBoughtItem(NULL, count); + } + else if (MyGUI::InputManager::getInstance().isControlPressed()) + { + sellAlreadyBoughtItem(NULL, 1); + } + else + { + CountDialog* dialog = MWBase::Environment::get().getWindowManager()->getCountDialog(); + dialog->open(MWWorld::Class::get(object).getName(object), count); + dialog->eventOkClicked.clear(); + dialog->eventOkClicked += MyGUI::newDelegate(this, &ContainerBase::sellAlreadyBoughtItem); + } + } + else + { + if (MyGUI::InputManager::getInstance().isShiftPressed() || count == 1) + { + sellItem(NULL, count); + } + else if (MyGUI::InputManager::getInstance().isControlPressed()) + { + sellItem(NULL, 1); + } + else + { + CountDialog* dialog = MWBase::Environment::get().getWindowManager()->getCountDialog(); + dialog->open(MWWorld::Class::get(object).getName(object), count); + dialog->eventOkClicked.clear(); + dialog->eventOkClicked += MyGUI::newDelegate(this, &ContainerBase::sellItem); + } + } + } } -void ContainerBase::onSelectedItemImpl(MyGUI::Widget* _sender, int count) +void ContainerBase::sellAlreadyBoughtItem(MyGUI::Widget* _sender, int count) +{ + MWWorld::Ptr object = *mSelectedItem->getUserData(); + assert( std::find(mBoughtItems.begin(), mBoughtItems.end(), object) != mBoughtItems.end() ); + + if (count == object.getRefData().getCount()) + mBoughtItems.erase( std::find(mBoughtItems.begin(), mBoughtItems.end(), object) ); + + if (isInventory()) + { + MWBase::Environment::get().getWindowManager()->getTradeWindow()->readdBarteredItem(*mSelectedItem->getUserData(), count); + MWBase::Environment::get().getWindowManager()->getTradeWindow()->drawItems(); + } + else + { + MWBase::Environment::get().getWindowManager()->getInventoryWindow()->readdBarteredItem(*mSelectedItem->getUserData(), count); + MWBase::Environment::get().getWindowManager()->getInventoryWindow()->drawItems(); + } + + drawItems(); +} + +void ContainerBase::sellItem(MyGUI::Widget* _sender, int count) +{ + MWWorld::Ptr newPtr; + if (isInventory()) + { + newPtr = MWBase::Environment::get().getWindowManager()->getTradeWindow()->addBarteredItem(*mSelectedItem->getUserData(), count); + mSoldItems.push_back(newPtr); + MWBase::Environment::get().getWindowManager()->getTradeWindow()->drawItems(); + } + else + { + newPtr = MWBase::Environment::get().getWindowManager()->getInventoryWindow()->addBarteredItem(*mSelectedItem->getUserData(), count); + mSoldItems.push_back(newPtr); + MWBase::Environment::get().getWindowManager()->getInventoryWindow()->drawItems(); + } + + drawItems(); +} + +void ContainerBase::startDragItem(MyGUI::Widget* _sender, int count) { mDragAndDrop->mIsOnDragAndDrop = true; mSelectedItem->detachFromWidget(); @@ -281,6 +366,14 @@ void ContainerBase::drawItems() std::vector equippedItems = getEquippedItems(); + // add bartered items (always at the beginning) + std::sort(mBoughtItems.begin(), mBoughtItems.end(), sortItems); + for (std::vector::iterator it=mBoughtItems.begin(); + it != mBoughtItems.end(); ++it) + { + items.push_back( std::make_pair(*it, ItemState_Barter) ); + } + // filter out the equipped items of categories we don't want std::vector unwantedItems = equippedItems; for (MWWorld::ContainerStoreIterator iter (containerStore.begin(categories)); iter!=containerStore.end(); ++iter) @@ -316,7 +409,8 @@ void ContainerBase::drawItems() for (MWWorld::ContainerStoreIterator iter (containerStore.begin(categories)); iter!=containerStore.end(); ++iter) { if (std::find(equippedItems.begin(), equippedItems.end(), *iter) == equippedItems.end() - && std::find(ignoreItems.begin(), ignoreItems.end(), *iter) == ignoreItems.end()) + && std::find(ignoreItems.begin(), ignoreItems.end(), *iter) == ignoreItems.end() + && std::find(mBoughtItems.begin(), mBoughtItems.end(), *iter) == mBoughtItems.end()) regularItems.push_back(*iter); } @@ -338,7 +432,7 @@ void ContainerBase::drawItems() { displayCount -= mDragAndDrop->mDraggedCount; } - if(displayCount > 0 && !(onlyMagic && MWWorld::Class::get(*iter).getEnchantment(*iter) == "" && iter->getTypeName() != typeid(ESM::Potion).name())) + if(displayCount > 0 && !(onlyMagic && it->second != ItemState_Barter && MWWorld::Class::get(*iter).getEnchantment(*iter) == "" && iter->getTypeName() != typeid(ESM::Potion).name())) { std::string path = std::string("icons\\"); path+=MWWorld::Class::get(*iter).getInventoryIcon(*iter); @@ -361,10 +455,17 @@ void ContainerBase::drawItems() { backgroundTex += "_equip"; } + else if (it->second == ItemState_Barter) + { + backgroundTex += "_barter"; + } backgroundTex += ".dds"; backgroundWidget->setImageTexture(backgroundTex); - backgroundWidget->setProperty("ImageCoord", "0 0 42 42"); + if (it->second == ItemState_Barter && !isMagic) + backgroundWidget->setProperty("ImageCoord", "2 2 42 42"); + else + backgroundWidget->setProperty("ImageCoord", "0 0 42 42"); backgroundWidget->eventMouseButtonClick += MyGUI::newDelegate(this, &ContainerBase::onSelectedItem); backgroundWidget->eventMouseWheel += MyGUI::newDelegate(this, &ContainerBase::onMouseWheel); @@ -421,6 +522,47 @@ void ContainerBase::Update() } } +MWWorld::Ptr ContainerBase::readdBarteredItem(MWWorld::Ptr item, int count) +{ + MWWorld::ContainerStore& containerStore = MWWorld::Class::get(mContainer).getContainerStore(mContainer); + + int origCount = item.getRefData().getCount(); + item.getRefData().setCount(count); + MWWorld::ContainerStoreIterator it = containerStore.add(item); + item.getRefData().setCount(origCount - count); + + if (origCount - count == 0) + mSoldItems.erase( std::find(mSoldItems.begin(), mSoldItems.end(), item) ); + + return *it; +} + +MWWorld::Ptr ContainerBase::addBarteredItem(MWWorld::Ptr item, int count) +{ + MWWorld::ContainerStore& containerStore = MWWorld::Class::get(mContainer).getContainerStore(mContainer); + + int origCount = item.getRefData().getCount(); + item.getRefData().setCount(count); + MWWorld::ContainerStoreIterator it = containerStore.add(item); + item.getRefData().setCount(origCount - count); + + mBoughtItems.push_back(*it); + return *it; +} + +void ContainerBase::removeBarteredItem(MWWorld::Ptr item, int count) +{ + MWWorld::ContainerStore& containerStore = MWWorld::Class::get(mContainer).getContainerStore(mContainer); + + for (MWWorld::ContainerStoreIterator it(containerStore.begin()); it != containerStore.end(); ++it) + { + if (*it == item) + { + item.getRefData().setCount(item.getRefData().getCount() - count); + } + } +} + // ------------------------------------------------------------------------------------------------ ContainerWindow::ContainerWindow(WindowManager& parWindowManager,DragAndDrop* dragAndDrop) diff --git a/apps/openmw/mwgui/container.hpp b/apps/openmw/mwgui/container.hpp index 563b22bc30..43a04ae707 100644 --- a/apps/openmw/mwgui/container.hpp +++ b/apps/openmw/mwgui/container.hpp @@ -62,13 +62,15 @@ namespace MWGui { ItemState_Normal = 0x01, ItemState_Equipped = 0x02, - - // unimplemented ItemState_Barter = 0x03 }; void setWidgets(MyGUI::Widget* containerWidget, MyGUI::ScrollView* itemView); ///< only call once + MWWorld::Ptr addBarteredItem(MWWorld::Ptr item, int count); + MWWorld::Ptr readdBarteredItem(MWWorld::Ptr item, int count); + void removeBarteredItem(MWWorld::Ptr item, int count); + void openContainer(MWWorld::Ptr container); void setFilter(Filter filter); ///< set category filter virtual void Update(); @@ -87,17 +89,31 @@ namespace MWGui Filter mFilter; + std::vector mBoughtItems; + std::vector mSoldItems; + void onSelectedItem(MyGUI::Widget* _sender); - void onSelectedItemImpl(MyGUI::Widget* _sender, int count); void onContainerClicked(MyGUI::Widget* _sender); void onMouseWheel(MyGUI::Widget* _sender, int _rel); + /// start dragging an item (drag & drop) + void startDragItem(MyGUI::Widget* _sender, int count); + + /// sell an item from this container + void sellItem(MyGUI::Widget* _sender, int count); + + /// sell an item from this container, that was previously just bought + void sellAlreadyBoughtItem(MyGUI::Widget* _sender, int count); + std::string getCountString(const int count); + virtual bool isTradeWindow() { return false; } virtual bool isInventory() { return false; } virtual std::vector getEquippedItems() { return std::vector(); } virtual void _unequipItem(MWWorld::Ptr item) { ; } + virtual bool isTrading() { return false; } + virtual bool ignoreEquippedItems() { return false; } virtual std::vector itemsToIgnore() { return std::vector(); } }; diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index e8db4b6d15..9f5e252fd0 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -120,9 +120,6 @@ void DialogueWindow::open() history->eraseText(0,history->getTextLength()); updateOptions(); setVisible(true); - - // hide all sub-dialogues of the dialog window (trade window, persuasion, etc) - mWindowManager.getTradeWindow()->setVisible(false); } void DialogueWindow::onByeClicked(MyGUI::Widget* _sender) @@ -137,8 +134,8 @@ void DialogueWindow::onSelectTopic(std::string topic) if (topic == MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sBarter")->str) { /// \todo check if the player is allowed to trade with this actor (e.g. faction rank high enough)? - mWindowManager.getTradeWindow()->startTrade(mActor); mWindowManager.setGuiMode(GM_Barter); + mWindowManager.getTradeWindow()->startTrade(mActor); } else @@ -150,8 +147,7 @@ void DialogueWindow::startDialogue(MWWorld::Ptr actor, std::string npcName) mEnabled = true; mActor = actor; topicsList->setEnabled(true); - static_cast(mMainWidget)->setCaption(npcName); - adjustWindowCaption(); + setTitle(npcName); } void DialogueWindow::setKeywords(std::list keyWords) diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index ebba395ff1..856ff1896e 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -27,6 +27,7 @@ namespace MWGui InventoryWindow::InventoryWindow(WindowManager& parWindowManager,DragAndDrop* dragAndDrop) : ContainerBase(dragAndDrop) , WindowPinnableBase("openmw_inventory_window_layout.xml", parWindowManager) + , mTrading(false) { static_cast(mMainWidget)->eventWindowChangeCoord += MyGUI::newDelegate(this, &InventoryWindow::onWindowResize); @@ -94,6 +95,8 @@ namespace MWGui onWindowResize(static_cast(mMainWidget)); updateEncumbranceBar(); + + mTrading = false; } void InventoryWindow::onWindowResize(MyGUI::Window* _sender) @@ -245,4 +248,11 @@ namespace MWGui } return 0; } + + void InventoryWindow::startTrade() + { + mTrading = true; + mBoughtItems.clear(); + mSoldItems.clear(); + } } diff --git a/apps/openmw/mwgui/inventorywindow.hpp b/apps/openmw/mwgui/inventorywindow.hpp index e53402bbd0..e544b788ad 100644 --- a/apps/openmw/mwgui/inventorywindow.hpp +++ b/apps/openmw/mwgui/inventorywindow.hpp @@ -13,6 +13,9 @@ namespace MWGui void openInventory(); + /// start trading, disables item drag&drop + void startTrade(); + virtual void Update(); virtual void notifyContentChanged(); @@ -33,6 +36,8 @@ namespace MWGui MyGUI::Button* mFilterMagic; MyGUI::Button* mFilterMisc; + bool mTrading; + void onWindowResize(MyGUI::Window* _sender); void onFilterChanged(MyGUI::Widget* _sender); void onAvatarClicked(MyGUI::Widget* _sender); @@ -40,6 +45,7 @@ namespace MWGui void updateEncumbranceBar(); + virtual bool isTrading() { return mTrading; } virtual bool isInventory() { return true; } virtual std::vector getEquippedItems(); virtual void _unequipItem(MWWorld::Ptr item); diff --git a/apps/openmw/mwgui/map_window.cpp b/apps/openmw/mwgui/map_window.cpp index d3541f774a..9000d2fcbf 100644 --- a/apps/openmw/mwgui/map_window.cpp +++ b/apps/openmw/mwgui/map_window.cpp @@ -121,8 +121,7 @@ MapWindow::MapWindow(WindowManager& parWindowManager) : void MapWindow::setCellName(const std::string& cellName) { - static_cast(mMainWidget)->setCaption(cellName); - adjustWindowCaption(); + setTitle(cellName); } void MapWindow::setPlayerPos(const float x, const float y) diff --git a/apps/openmw/mwgui/stats_window.cpp b/apps/openmw/mwgui/stats_window.cpp index 1866682226..43099e9369 100644 --- a/apps/openmw/mwgui/stats_window.cpp +++ b/apps/openmw/mwgui/stats_window.cpp @@ -128,8 +128,7 @@ void StatsWindow::setBar(const std::string& name, const std::string& tname, int void StatsWindow::setPlayerName(const std::string& playerName) { - static_cast(mMainWidget)->setCaption(playerName); - adjustWindowCaption(); + setTitle(playerName); } void StatsWindow::setValue (const std::string& id, const MWMechanics::Stat& value) diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index e5fc477640..9f491242bd 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -103,13 +103,17 @@ namespace MWGui void TradeWindow::startTrade(MWWorld::Ptr actor) { - ContainerBase::openContainer(actor); - setTitle(MWWorld::Class::get(actor).getName(actor)); - adjustWindowCaption(); mCurrentBalance = 0; + mWindowManager.getInventoryWindow()->startTrade(); + + mBoughtItems.clear(); + mSoldItems.clear(); + + ContainerBase::openContainer(actor); + updateLabels(); } diff --git a/apps/openmw/mwgui/tradewindow.hpp b/apps/openmw/mwgui/tradewindow.hpp index 5e762cbe54..5ab2d0d790 100644 --- a/apps/openmw/mwgui/tradewindow.hpp +++ b/apps/openmw/mwgui/tradewindow.hpp @@ -63,6 +63,9 @@ namespace MWGui virtual bool ignoreEquippedItems() { return true; } virtual std::vector getEquippedItems(); + virtual bool isTrading() { return true; } + virtual bool isTradeWindow() { return true; } + virtual std::vector itemsToIgnore(); void updateLabels(); From 342a244e31a5a59713cc0b58ee17d8152761db42 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 May 2012 17:36:20 +0200 Subject: [PATCH 212/325] NPC now doesn't buy items of types that he shouldn't accept. --- apps/openmw/mwgui/container.cpp | 12 ++++++++++++ apps/openmw/mwgui/inventorywindow.cpp | 9 +++++---- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index e51e22ecdb..7d9fd43636 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -123,6 +123,18 @@ void ContainerBase::onSelectedItem(MyGUI::Widget* _sender) MWWorld::Ptr object = (*_sender->getUserData()); int count = object.getRefData().getCount(); + if (isInventory()) + { + // the player is trying to sell an item, check if the merchant accepts it + if (!MWBase::Environment::get().getWindowManager()->getTradeWindow()->npcAcceptsItem(object)) + { + // user notification "i don't buy this item" + MWBase::Environment::get().getWindowManager()-> + messageBox(MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sBarterDialog4")->str, std::vector()); + return; + } + } + if (std::find(mBoughtItems.begin(), mBoughtItems.end(), object) != mBoughtItems.end()) { if (MyGUI::InputManager::getInstance().isShiftPressed() || count == 1) diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 856ff1896e..e08a2ba4f5 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -92,11 +92,14 @@ namespace MWGui void InventoryWindow::openInventory() { - onWindowResize(static_cast(mMainWidget)); - updateEncumbranceBar(); mTrading = false; + + mBoughtItems.clear(); + mSoldItems.clear(); + + onWindowResize(static_cast(mMainWidget)); } void InventoryWindow::onWindowResize(MyGUI::Window* _sender) @@ -252,7 +255,5 @@ namespace MWGui void InventoryWindow::startTrade() { mTrading = true; - mBoughtItems.clear(); - mSoldItems.clear(); } } From fb47681fbd61310037f29ca0095cda55615e451e Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 May 2012 17:58:33 +0200 Subject: [PATCH 213/325] fix a bug, some cleanup --- apps/openmw/mwgui/container.cpp | 33 ++++++++++++--------------- apps/openmw/mwgui/container.hpp | 3 --- apps/openmw/mwgui/countdialog.cpp | 5 ++-- apps/openmw/mwgui/countdialog.hpp | 2 +- apps/openmw/mwgui/hud.cpp | 1 - apps/openmw/mwgui/inventorywindow.cpp | 8 +------ apps/openmw/mwgui/inventorywindow.hpp | 3 +-- apps/openmw/mwgui/tradewindow.hpp | 3 --- apps/openmw/mwgui/window_manager.cpp | 12 +++++++--- 9 files changed, 30 insertions(+), 40 deletions(-) diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 7d9fd43636..d0fd06a702 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -109,8 +109,9 @@ void ContainerBase::onSelectedItem(MyGUI::Widget* _sender) } else { + std::string message = MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sTake")->str; CountDialog* dialog = MWBase::Environment::get().getWindowManager()->getCountDialog(); - dialog->open(MWWorld::Class::get(object).getName(object), count); + dialog->open(MWWorld::Class::get(object).getName(object), message, count); dialog->eventOkClicked.clear(); dialog->eventOkClicked += MyGUI::newDelegate(this, &ContainerBase::startDragItem); } @@ -135,6 +136,10 @@ void ContainerBase::onSelectedItem(MyGUI::Widget* _sender) } } + bool buying = isTradeWindow(); // buying or selling? + std::string message = buying ? MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sQuanityMenuMessage02")->str + : MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sQuanityMenuMessage01")->str; + if (std::find(mBoughtItems.begin(), mBoughtItems.end(), object) != mBoughtItems.end()) { if (MyGUI::InputManager::getInstance().isShiftPressed() || count == 1) @@ -148,7 +153,7 @@ void ContainerBase::onSelectedItem(MyGUI::Widget* _sender) else { CountDialog* dialog = MWBase::Environment::get().getWindowManager()->getCountDialog(); - dialog->open(MWWorld::Class::get(object).getName(object), count); + dialog->open(MWWorld::Class::get(object).getName(object), message, count); dialog->eventOkClicked.clear(); dialog->eventOkClicked += MyGUI::newDelegate(this, &ContainerBase::sellAlreadyBoughtItem); } @@ -166,7 +171,7 @@ void ContainerBase::onSelectedItem(MyGUI::Widget* _sender) else { CountDialog* dialog = MWBase::Environment::get().getWindowManager()->getCountDialog(); - dialog->open(MWWorld::Class::get(object).getName(object), count); + dialog->open(MWWorld::Class::get(object).getName(object), message, count); dialog->eventOkClicked.clear(); dialog->eventOkClicked += MyGUI::newDelegate(this, &ContainerBase::sellItem); } @@ -202,13 +207,15 @@ void ContainerBase::sellItem(MyGUI::Widget* _sender, int count) if (isInventory()) { newPtr = MWBase::Environment::get().getWindowManager()->getTradeWindow()->addBarteredItem(*mSelectedItem->getUserData(), count); - mSoldItems.push_back(newPtr); + if (std::find(mSoldItems.begin(), mSoldItems.end(), newPtr) == mSoldItems.end()) + mSoldItems.push_back(newPtr); MWBase::Environment::get().getWindowManager()->getTradeWindow()->drawItems(); } else { newPtr = MWBase::Environment::get().getWindowManager()->getInventoryWindow()->addBarteredItem(*mSelectedItem->getUserData(), count); - mSoldItems.push_back(newPtr); + if (std::find(mSoldItems.begin(), mSoldItems.end(), newPtr) == mSoldItems.end()) + mSoldItems.push_back(newPtr); MWBase::Environment::get().getWindowManager()->getInventoryWindow()->drawItems(); } @@ -510,8 +517,6 @@ void ContainerBase::drawItems() MyGUI::IntSize size = MyGUI::IntSize(std::max(mItemView->getSize().width, x+42), mItemView->getSize().height); mItemView->setCanvasSize(size); mContainerWidget->setSize(size); - - notifyContentChanged(); } std::string ContainerBase::getCountString(const int count) @@ -524,16 +529,6 @@ std::string ContainerBase::getCountString(const int count) return boost::lexical_cast(count); } -void ContainerBase::Update() -{ - if(mDragAndDrop != NULL && mDragAndDrop->mIsOnDragAndDrop) - { - if(mDragAndDrop->mDraggedWidget) - mDragAndDrop->mDraggedWidget->setPosition(MyGUI::InputManager::getInstance().getMousePosition()); - else mDragAndDrop->mIsOnDragAndDrop = false; //If this happens, there is a bug. - } -} - MWWorld::Ptr ContainerBase::readdBarteredItem(MWWorld::Ptr item, int count) { MWWorld::ContainerStore& containerStore = MWWorld::Class::get(mContainer).getContainerStore(mContainer); @@ -558,7 +553,9 @@ MWWorld::Ptr ContainerBase::addBarteredItem(MWWorld::Ptr item, int count) MWWorld::ContainerStoreIterator it = containerStore.add(item); item.getRefData().setCount(origCount - count); - mBoughtItems.push_back(*it); + if (std::find(mBoughtItems.begin(), mBoughtItems.end(), *it) == mBoughtItems.end()) + mBoughtItems.push_back(*it); + return *it; } diff --git a/apps/openmw/mwgui/container.hpp b/apps/openmw/mwgui/container.hpp index 43a04ae707..58d4548ee3 100644 --- a/apps/openmw/mwgui/container.hpp +++ b/apps/openmw/mwgui/container.hpp @@ -73,11 +73,8 @@ namespace MWGui void openContainer(MWWorld::Ptr container); void setFilter(Filter filter); ///< set category filter - virtual void Update(); void drawItems(); - virtual void notifyContentChanged() { } - protected: MyGUI::ScrollView* mItemView; MyGUI::Widget* mContainerWidget; diff --git a/apps/openmw/mwgui/countdialog.cpp b/apps/openmw/mwgui/countdialog.cpp index dc7e75e0ea..16e3f9aab3 100644 --- a/apps/openmw/mwgui/countdialog.cpp +++ b/apps/openmw/mwgui/countdialog.cpp @@ -19,7 +19,6 @@ namespace MWGui mOkButton->setCaption(MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sOk")->str); mCancelButton->setCaption(MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sCancel")->str); - mLabelText->setCaption(MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sTake")->str); mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &CountDialog::onCancelButtonClicked); mOkButton->eventMouseButtonClick += MyGUI::newDelegate(this, &CountDialog::onOkButtonClicked); @@ -27,10 +26,12 @@ namespace MWGui mSlider->eventScrollChangePosition += MyGUI::newDelegate(this, &CountDialog::onSliderMoved); } - void CountDialog::open(const std::string& item, const int maxCount) + void CountDialog::open(const std::string& item, const std::string& message, const int maxCount) { setVisible(true); + mLabelText->setCaption(message); + MyGUI::IntSize viewSize = MyGUI::RenderManager::getInstance().getViewSize(); mSlider->setScrollRange(maxCount); diff --git a/apps/openmw/mwgui/countdialog.hpp b/apps/openmw/mwgui/countdialog.hpp index b6c836c9dc..aac17b846d 100644 --- a/apps/openmw/mwgui/countdialog.hpp +++ b/apps/openmw/mwgui/countdialog.hpp @@ -9,7 +9,7 @@ namespace MWGui { public: CountDialog(WindowManager& parWindowManager); - void open(const std::string& item, const int maxCount); + void open(const std::string& item, const std::string& message, const int maxCount); typedef MyGUI::delegates::CMultiDelegate2 EventHandle_WidgetInt; diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index 395ca79c5d..34d5ece98b 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -285,7 +285,6 @@ void HUD::onWorldClicked(MyGUI::Widget* _sender) // remove object from the container it was coming from object.getRefData().setCount(origCount - mDragAndDrop->mDraggedCount); - mDragAndDrop->mDraggedFrom->notifyContentChanged(); mDragAndDrop->mIsOnDragAndDrop = false; MyGUI::Gui::getInstance().destroyWidget(mDragAndDrop->mDraggedWidget); diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index e08a2ba4f5..ca629d51d0 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -228,15 +228,9 @@ namespace MWGui mEncumbranceText->setCaption( boost::lexical_cast(int(encumbrance)) + "/" + boost::lexical_cast(int(capacity)) ); } - void InventoryWindow::notifyContentChanged() - { - } - - void InventoryWindow::Update() + void InventoryWindow::update() { updateEncumbranceBar(); - - ContainerBase::Update(); } int InventoryWindow::getPlayerGold() diff --git a/apps/openmw/mwgui/inventorywindow.hpp b/apps/openmw/mwgui/inventorywindow.hpp index e544b788ad..59aaf7859a 100644 --- a/apps/openmw/mwgui/inventorywindow.hpp +++ b/apps/openmw/mwgui/inventorywindow.hpp @@ -16,8 +16,7 @@ namespace MWGui /// start trading, disables item drag&drop void startTrade(); - virtual void Update(); - virtual void notifyContentChanged(); + void update(); int getPlayerGold(); diff --git a/apps/openmw/mwgui/tradewindow.hpp b/apps/openmw/mwgui/tradewindow.hpp index 5ab2d0d790..b96abc7e2f 100644 --- a/apps/openmw/mwgui/tradewindow.hpp +++ b/apps/openmw/mwgui/tradewindow.hpp @@ -27,9 +27,6 @@ namespace MWGui void startTrade(MWWorld::Ptr actor); - //virtual void Update(); - //virtual void notifyContentChanged(); - bool npcAcceptsItem(MWWorld::Ptr item); protected: diff --git a/apps/openmw/mwgui/window_manager.cpp b/apps/openmw/mwgui/window_manager.cpp index e12fb851e0..abbdcbcc1b 100644 --- a/apps/openmw/mwgui/window_manager.cpp +++ b/apps/openmw/mwgui/window_manager.cpp @@ -97,7 +97,7 @@ WindowManager::WindowManager( MyGUI::Widget* dragAndDropWidget = gui->createWidgetT("Widget","",0,0,w,h,MyGUI::Align::Default,"DragAndDrop","DragAndDropWidget"); dragAndDropWidget->setVisible(false); - DragAndDrop* mDragAndDrop = new DragAndDrop(); + mDragAndDrop = new DragAndDrop(); mDragAndDrop->mIsOnDragAndDrop = false; mDragAndDrop->mDraggedWidget = 0; mDragAndDrop->mDragAndDropWidget = dragAndDropWidget; @@ -468,9 +468,15 @@ void WindowManager::onDialogueWindowBye() void WindowManager::onFrame (float frameDuration) { mMessageBoxManager->onFrame(frameDuration); - mInventoryWindow->Update(); - mContainerWindow->Update(); mToolTips->onFrame(frameDuration); + + if (mDragAndDrop->mIsOnDragAndDrop) + { + assert(mDragAndDrop->mDraggedWidget); + mDragAndDrop->mDraggedWidget->setPosition(MyGUI::InputManager::getInstance().getMousePosition()); + } + + mInventoryWindow->update(); } const ESMS::ESMStore& WindowManager::getStore() const From db49e2c04668744a9d3372a7b7c4c67972a009b2 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 May 2012 20:53:24 +0200 Subject: [PATCH 214/325] bought/sold items now use a separate ContainerStore, this fixes a stacking issue among other things --- apps/openmw/mwgui/container.cpp | 76 +++++++++++++-------------- apps/openmw/mwgui/container.hpp | 14 +++-- apps/openmw/mwgui/inventorywindow.cpp | 1 - apps/openmw/mwgui/tradewindow.cpp | 23 ++++---- 4 files changed, 56 insertions(+), 58 deletions(-) diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index d0fd06a702..14a500b690 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -182,19 +182,15 @@ void ContainerBase::onSelectedItem(MyGUI::Widget* _sender) void ContainerBase::sellAlreadyBoughtItem(MyGUI::Widget* _sender, int count) { MWWorld::Ptr object = *mSelectedItem->getUserData(); - assert( std::find(mBoughtItems.begin(), mBoughtItems.end(), object) != mBoughtItems.end() ); - - if (count == object.getRefData().getCount()) - mBoughtItems.erase( std::find(mBoughtItems.begin(), mBoughtItems.end(), object) ); if (isInventory()) { - MWBase::Environment::get().getWindowManager()->getTradeWindow()->readdBarteredItem(*mSelectedItem->getUserData(), count); + MWBase::Environment::get().getWindowManager()->getTradeWindow()->addItem(object, count); MWBase::Environment::get().getWindowManager()->getTradeWindow()->drawItems(); } else { - MWBase::Environment::get().getWindowManager()->getInventoryWindow()->readdBarteredItem(*mSelectedItem->getUserData(), count); + MWBase::Environment::get().getWindowManager()->getInventoryWindow()->addItem(object, count); MWBase::Environment::get().getWindowManager()->getInventoryWindow()->drawItems(); } @@ -203,19 +199,14 @@ void ContainerBase::sellAlreadyBoughtItem(MyGUI::Widget* _sender, int count) void ContainerBase::sellItem(MyGUI::Widget* _sender, int count) { - MWWorld::Ptr newPtr; if (isInventory()) { - newPtr = MWBase::Environment::get().getWindowManager()->getTradeWindow()->addBarteredItem(*mSelectedItem->getUserData(), count); - if (std::find(mSoldItems.begin(), mSoldItems.end(), newPtr) == mSoldItems.end()) - mSoldItems.push_back(newPtr); + MWBase::Environment::get().getWindowManager()->getTradeWindow()->addBarteredItem(*mSelectedItem->getUserData(), count); MWBase::Environment::get().getWindowManager()->getTradeWindow()->drawItems(); } else { - newPtr = MWBase::Environment::get().getWindowManager()->getInventoryWindow()->addBarteredItem(*mSelectedItem->getUserData(), count); - if (std::find(mSoldItems.begin(), mSoldItems.end(), newPtr) == mSoldItems.end()) - mSoldItems.push_back(newPtr); + MWBase::Environment::get().getWindowManager()->getInventoryWindow()->addBarteredItem(*mSelectedItem->getUserData(), count); MWBase::Environment::get().getWindowManager()->getInventoryWindow()->drawItems(); } @@ -385,10 +376,16 @@ void ContainerBase::drawItems() std::vector equippedItems = getEquippedItems(); - // add bartered items (always at the beginning) - std::sort(mBoughtItems.begin(), mBoughtItems.end(), sortItems); - for (std::vector::iterator it=mBoughtItems.begin(); - it != mBoughtItems.end(); ++it) + // add bought items (always at the beginning) + std::vector boughtItems; + for (MWWorld::ContainerStoreIterator it (mBoughtItems.begin()); it!=mBoughtItems.end(); ++it) + { + boughtItems.push_back(*it); + } + std::sort(boughtItems.begin(), boughtItems.end(), sortItems); + + for (std::vector::iterator it=boughtItems.begin(); + it != boughtItems.end(); ++it) { items.push_back( std::make_pair(*it, ItemState_Barter) ); } @@ -529,49 +526,50 @@ std::string ContainerBase::getCountString(const int count) return boost::lexical_cast(count); } -MWWorld::Ptr ContainerBase::readdBarteredItem(MWWorld::Ptr item, int count) +void ContainerBase::addBarteredItem(MWWorld::Ptr item, int count) { - MWWorld::ContainerStore& containerStore = MWWorld::Class::get(mContainer).getContainerStore(mContainer); - int origCount = item.getRefData().getCount(); item.getRefData().setCount(count); - MWWorld::ContainerStoreIterator it = containerStore.add(item); + MWWorld::ContainerStoreIterator it = mBoughtItems.add(item); item.getRefData().setCount(origCount - count); - - if (origCount - count == 0) - mSoldItems.erase( std::find(mSoldItems.begin(), mSoldItems.end(), item) ); - - return *it; } -MWWorld::Ptr ContainerBase::addBarteredItem(MWWorld::Ptr item, int count) +void ContainerBase::addItem(MWWorld::Ptr item, int count) { MWWorld::ContainerStore& containerStore = MWWorld::Class::get(mContainer).getContainerStore(mContainer); - int origCount = item.getRefData().getCount(); + int origCount = item.getRefData().getCount(); + item.getRefData().setCount(count); MWWorld::ContainerStoreIterator it = containerStore.add(item); + item.getRefData().setCount(origCount - count); - - if (std::find(mBoughtItems.begin(), mBoughtItems.end(), *it) == mBoughtItems.end()) - mBoughtItems.push_back(*it); - - return *it; } -void ContainerBase::removeBarteredItem(MWWorld::Ptr item, int count) +void ContainerBase::transferBoughtItems() { MWWorld::ContainerStore& containerStore = MWWorld::Class::get(mContainer).getContainerStore(mContainer); - for (MWWorld::ContainerStoreIterator it(containerStore.begin()); it != containerStore.end(); ++it) + for (MWWorld::ContainerStoreIterator it(mBoughtItems.begin()); it != mBoughtItems.end(); ++it) { - if (*it == item) - { - item.getRefData().setCount(item.getRefData().getCount() - count); - } + containerStore.add(*it); } } +void ContainerBase::returnBoughtItems(MWWorld::ContainerStore& store) +{ + for (MWWorld::ContainerStoreIterator it(mBoughtItems.begin()); it != mBoughtItems.end(); ++it) + { + store.add(*it); + } +} + +MWWorld::ContainerStore& ContainerBase::getContainerStore() +{ + MWWorld::ContainerStore& store = MWWorld::Class::get(mContainer).getContainerStore(mContainer); + return store; +} + // ------------------------------------------------------------------------------------------------ ContainerWindow::ContainerWindow(WindowManager& parWindowManager,DragAndDrop* dragAndDrop) diff --git a/apps/openmw/mwgui/container.hpp b/apps/openmw/mwgui/container.hpp index 58d4548ee3..d300f4497c 100644 --- a/apps/openmw/mwgui/container.hpp +++ b/apps/openmw/mwgui/container.hpp @@ -67,9 +67,13 @@ namespace MWGui void setWidgets(MyGUI::Widget* containerWidget, MyGUI::ScrollView* itemView); ///< only call once - MWWorld::Ptr addBarteredItem(MWWorld::Ptr item, int count); - MWWorld::Ptr readdBarteredItem(MWWorld::Ptr item, int count); - void removeBarteredItem(MWWorld::Ptr item, int count); + void addBarteredItem(MWWorld::Ptr item, int count); + void addItem(MWWorld::Ptr item, int count); + + void transferBoughtItems(); ///< transfer bought items into the inventory + void returnBoughtItems(MWWorld::ContainerStore& store); ///< return bought items into the specified ContainerStore + + MWWorld::ContainerStore& getContainerStore(); void openContainer(MWWorld::Ptr container); void setFilter(Filter filter); ///< set category filter @@ -86,8 +90,8 @@ namespace MWGui Filter mFilter; - std::vector mBoughtItems; - std::vector mSoldItems; + // bought items are put in a separate ContainerStore so that they don't stack with other (not bought) items. + MWWorld::ContainerStore mBoughtItems; void onSelectedItem(MyGUI::Widget* _sender); void onContainerClicked(MyGUI::Widget* _sender); diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index ca629d51d0..8bc9661e49 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -97,7 +97,6 @@ namespace MWGui mTrading = false; mBoughtItems.clear(); - mSoldItems.clear(); onWindowResize(static_cast(mMainWidget)); } diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index 9f491242bd..fb70e00457 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -110,7 +110,6 @@ namespace MWGui mWindowManager.getInventoryWindow()->startTrade(); mBoughtItems.clear(); - mSoldItems.clear(); ContainerBase::openContainer(actor); @@ -146,10 +145,19 @@ namespace MWGui void TradeWindow::onOfferButtonClicked(MyGUI::Widget* _sender) { + transferBoughtItems(); + mWindowManager.getInventoryWindow()->transferBoughtItems(); + + mWindowManager.setGuiMode(GM_Game); } void TradeWindow::onCancelButtonClicked(MyGUI::Widget* _sender) { + // i give you back your stuff! + returnBoughtItems(mWindowManager.getInventoryWindow()->getContainerStore()); + // now gimme back my stuff! + mWindowManager.getInventoryWindow()->returnBoughtItems(MWWorld::Class::get(mContainer).getContainerStore(mContainer)); + mWindowManager.setGuiMode(GM_Game); } @@ -169,16 +177,6 @@ namespace MWGui mTotalBalance->setCaption(boost::lexical_cast(-mCurrentBalance)); } - // retrieve merchant gold - int gold = 0; - MWWorld::InventoryStore& invStore = static_cast(MWWorld::Class::get(mContainer).getContainerStore(mContainer)); - for (MWWorld::ContainerStoreIterator it = invStore.begin(); - it != invStore.end(); ++it) - { - if (MWWorld::Class::get(*it).getName(*it) == MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sGold")->str) - gold = it->getRefData().getCount(); - } - int merchantgold; if (mContainer.getTypeName() == typeid(ESM::NPC).name()) { @@ -193,10 +191,9 @@ namespace MWGui ESMS::LiveCellRef* ref = mContainer.get(); merchantgold = ref->base->data.gold; } - gold += merchantgold; mMerchantGold->setCaption(MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sSellerGold")->str - + " " + boost::lexical_cast(gold)); + + " " + boost::lexical_cast(merchantgold)); } std::vector TradeWindow::getEquippedItems() From a4343bfa18212591f3ebf25b97d5b40d4fce685e Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 18 May 2012 22:04:22 +0200 Subject: [PATCH 215/325] Issue #256: added TimeStamp class --- apps/openmw/CMakeLists.txt | 1 + apps/openmw/mwworld/timestamp.cpp | 108 ++++++++++++++++++++++++++++++ apps/openmw/mwworld/timestamp.hpp | 44 ++++++++++++ 3 files changed, 153 insertions(+) create mode 100644 apps/openmw/mwworld/timestamp.cpp create mode 100644 apps/openmw/mwworld/timestamp.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index d7c229cf9f..7e5dcc1e2e 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -48,6 +48,7 @@ add_openmw_dir (mwworld refdata world physicssystem scene globals class action nullaction actionteleport containerstore actiontalk actiontake manualref player cellfunctors cells localscripts customdata weather inventorystore ptr actionread + timestamp ) add_openmw_dir (mwclass diff --git a/apps/openmw/mwworld/timestamp.cpp b/apps/openmw/mwworld/timestamp.cpp new file mode 100644 index 0000000000..e2f3d6c634 --- /dev/null +++ b/apps/openmw/mwworld/timestamp.cpp @@ -0,0 +1,108 @@ + +#include "timestamp.hpp" + +#include + +#include + +namespace MWWorld +{ + TimeStamp::TimeStamp (float hour, int day) + : mHour (hour), mDay (day) + { + if (hour<0 || hour>=24 || day<0) + throw std::runtime_error ("invalid time stamp"); + } + + float TimeStamp::getHour() const + { + return mHour; + } + + int TimeStamp::getDay() const + { + return mDay; + } + + TimeStamp& TimeStamp::operator+= (double hours) + { + if (hours<0) + throw std::runtime_error ("can't move time stamp backwards in time"); + + hours += mHour; + + mHour = static_cast (std::fmod (hours, 24)); + + mDay += hours / 24; + + return *this; + } + + bool operator== (const TimeStamp& left, const TimeStamp& right) + { + return left.getHour()==right.getHour() && left.getDay()==right.getDay(); + } + + bool operator!= (const TimeStamp& left, const TimeStamp& right) + { + return !(left==right); + } + + bool operator< (const TimeStamp& left, const TimeStamp& right) + { + if (left.getDay()right.getDay()) + return false; + + return left.getHour() (const TimeStamp& left, const TimeStamp& right) + { + return !(left<=right); + } + + bool operator>= (const TimeStamp& left, const TimeStamp& right) + { + return !(left=0 + + float getHour() const; + + int getDay() const; + + TimeStamp& operator+= (double hours); + ///< \param hours >=0 + }; + + bool operator== (const TimeStamp& left, const TimeStamp& right); + bool operator!= (const TimeStamp& left, const TimeStamp& right); + + bool operator< (const TimeStamp& left, const TimeStamp& right); + bool operator<= (const TimeStamp& left, const TimeStamp& right); + + bool operator> (const TimeStamp& left, const TimeStamp& right); + bool operator>= (const TimeStamp& left, const TimeStamp& right); + + TimeStamp operator+ (const TimeStamp& stamp, double hours); + TimeStamp operator+ (double hours, const TimeStamp& stamp); + + double operator- (const TimeStamp& left, const TimeStamp& right); + ///< Returns the difference between \a left and \a right in in-game hours. +} + +#endif From c004f5d570bc387b3c7b8910254b295a7f360391 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 May 2012 22:06:25 +0200 Subject: [PATCH 216/325] adjust the "total cost"/"total sold" value when trading items, added some checks with respective user notifications --- apps/openmw/mwgui/container.cpp | 10 +++- apps/openmw/mwgui/container.hpp | 1 + apps/openmw/mwgui/tradewindow.cpp | 76 ++++++++++++++++++++++++++ apps/openmw/mwgui/tradewindow.hpp | 3 + apps/openmw/mwworld/containerstore.hpp | 2 +- 5 files changed, 89 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 14a500b690..710e30b744 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -186,11 +186,13 @@ void ContainerBase::sellAlreadyBoughtItem(MyGUI::Widget* _sender, int count) if (isInventory()) { MWBase::Environment::get().getWindowManager()->getTradeWindow()->addItem(object, count); + MWBase::Environment::get().getWindowManager()->getTradeWindow()->buyFromNpc(object, count); MWBase::Environment::get().getWindowManager()->getTradeWindow()->drawItems(); } else { MWBase::Environment::get().getWindowManager()->getInventoryWindow()->addItem(object, count); + MWBase::Environment::get().getWindowManager()->getTradeWindow()->sellToNpc(object, count); MWBase::Environment::get().getWindowManager()->getInventoryWindow()->drawItems(); } @@ -199,14 +201,18 @@ void ContainerBase::sellAlreadyBoughtItem(MyGUI::Widget* _sender, int count) void ContainerBase::sellItem(MyGUI::Widget* _sender, int count) { + MWWorld::Ptr object = *mSelectedItem->getUserData(); + if (isInventory()) { - MWBase::Environment::get().getWindowManager()->getTradeWindow()->addBarteredItem(*mSelectedItem->getUserData(), count); + MWBase::Environment::get().getWindowManager()->getTradeWindow()->addBarteredItem(object, count); + MWBase::Environment::get().getWindowManager()->getTradeWindow()->buyFromNpc(object, count); MWBase::Environment::get().getWindowManager()->getTradeWindow()->drawItems(); } else { - MWBase::Environment::get().getWindowManager()->getInventoryWindow()->addBarteredItem(*mSelectedItem->getUserData(), count); + MWBase::Environment::get().getWindowManager()->getInventoryWindow()->addBarteredItem(object, count); + MWBase::Environment::get().getWindowManager()->getTradeWindow()->sellToNpc(object, count); MWBase::Environment::get().getWindowManager()->getInventoryWindow()->drawItems(); } diff --git a/apps/openmw/mwgui/container.hpp b/apps/openmw/mwgui/container.hpp index d300f4497c..66cac82ce6 100644 --- a/apps/openmw/mwgui/container.hpp +++ b/apps/openmw/mwgui/container.hpp @@ -74,6 +74,7 @@ namespace MWGui void returnBoughtItems(MWWorld::ContainerStore& store); ///< return bought items into the specified ContainerStore MWWorld::ContainerStore& getContainerStore(); + MWWorld::ContainerStore& getBoughtItems() { return mBoughtItems; } void openContainer(MWWorld::Ptr container); void setFilter(Filter filter); ///< set category filter diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index fb70e00457..06e91d787b 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -145,6 +145,64 @@ namespace MWGui void TradeWindow::onOfferButtonClicked(MyGUI::Widget* _sender) { + // were there any items traded at all? + MWWorld::ContainerStore& playerBought = mWindowManager.getInventoryWindow()->getBoughtItems(); + MWWorld::ContainerStore& merchantBought = getBoughtItems(); + + bool traded=false; + for (MWWorld::ContainerStoreIterator it = playerBought.begin(); + it != playerBought.end(); ++it) + { + if (it->getRefData().getCount() > 0) + traded = true; + } + for (MWWorld::ContainerStoreIterator it = merchantBought.begin(); + it != merchantBought.end(); ++it) + { + if (it->getRefData().getCount() > 0) + traded = true; + } + if (!traded) + { + // user notification + MWBase::Environment::get().getWindowManager()-> + messageBox(MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sBarterDialog11")->str, std::vector()); + return; + } + + // check if the player can afford this + if (mCurrentBalance < 0 && mWindowManager.getInventoryWindow()->getPlayerGold() < std::abs(mCurrentBalance)) + { + // user notification + MWBase::Environment::get().getWindowManager()-> + messageBox(MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sBarterDialog1")->str, std::vector()); + return; + } + + // check if the merchant can afford this + int merchantgold; + if (mContainer.getTypeName() == typeid(ESM::NPC).name()) + { + ESMS::LiveCellRef* ref = mContainer.get(); + if (ref->base->npdt52.gold == -10) + merchantgold = ref->base->npdt12.gold; + else + merchantgold = ref->base->npdt52.gold; + } + else // ESM::Creature + { + ESMS::LiveCellRef* ref = mContainer.get(); + merchantgold = ref->base->data.gold; + } + if (mCurrentBalance > 0 && merchantgold < mCurrentBalance) + { + // user notification + MWBase::Environment::get().getWindowManager()-> + messageBox(MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sBarterDialog2")->str, std::vector()); + return; + } + + // success! make the item transfer. transferBoughtItems(); mWindowManager.getInventoryWindow()->transferBoughtItems(); @@ -276,4 +334,22 @@ namespace MWGui return items; } + + void TradeWindow::sellToNpc(MWWorld::Ptr item, int count) + { + /// \todo price adjustment depending on merchantile skill + + mCurrentBalance -= MWWorld::Class::get(item).getValue(item) * count; + + updateLabels(); + } + + void TradeWindow::buyFromNpc(MWWorld::Ptr item, int count) + { + /// \todo price adjustment depending on merchantile skill + + mCurrentBalance += MWWorld::Class::get(item).getValue(item) * count; + + updateLabels(); + } } diff --git a/apps/openmw/mwgui/tradewindow.hpp b/apps/openmw/mwgui/tradewindow.hpp index b96abc7e2f..8da96d37e7 100644 --- a/apps/openmw/mwgui/tradewindow.hpp +++ b/apps/openmw/mwgui/tradewindow.hpp @@ -27,6 +27,9 @@ namespace MWGui void startTrade(MWWorld::Ptr actor); + void sellToNpc(MWWorld::Ptr item, int count); ///< only used for adjusting the gold balance + void buyFromNpc(MWWorld::Ptr item, int count); ///< only used for adjusting the gold balance + bool npcAcceptsItem(MWWorld::Ptr item); protected: diff --git a/apps/openmw/mwworld/containerstore.hpp b/apps/openmw/mwworld/containerstore.hpp index 96c97415d3..f850b01fa6 100644 --- a/apps/openmw/mwworld/containerstore.hpp +++ b/apps/openmw/mwworld/containerstore.hpp @@ -74,7 +74,7 @@ namespace MWWorld /// \attention Do not add items to an existing stack by increasing the count instead of /// calling this function! /// - /// @return if stacking happened, return iterator to the item that was stacked against, otherwise end() iterator + /// @return if stacking happened, return iterator to the item that was stacked against, otherwise iterator to the newly inserted item. protected: ContainerStoreIterator addImpl (const Ptr& ptr); From c30b9e4bb91fa3e6fa98f072b79b000fecd13f49 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 May 2012 22:21:44 +0200 Subject: [PATCH 217/325] add/remove gold from the player at the end of the transaction. --- apps/openmw/mwgui/tradewindow.cpp | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index 06e91d787b..641ffa8338 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -5,6 +5,7 @@ #include "../mwbase/environment.hpp" #include "../mwworld/world.hpp" #include "../mwworld/inventorystore.hpp" +#include "../mwworld/manualref.hpp" #include "window_manager.hpp" #include "inventorywindow.hpp" @@ -206,6 +207,31 @@ namespace MWGui transferBoughtItems(); mWindowManager.getInventoryWindow()->transferBoughtItems(); + // add or remove gold from the player. + bool goldFound = false; + MWWorld::Ptr gold; + MWWorld::ContainerStore& playerStore = mWindowManager.getInventoryWindow()->getContainerStore(); + for (MWWorld::ContainerStoreIterator it = playerStore.begin(); + it != playerStore.end(); ++it) + { + if (MWWorld::Class::get(*it).getName(*it) == MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sGold")->str) + { + goldFound = true; + gold = *it; + } + } + if (goldFound) + { + gold.getRefData().setCount(gold.getRefData().getCount() + mCurrentBalance); + } + else + { + assert(mCurrentBalance > 0); + MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), "Gold_001"); + ref.getPtr().getRefData().setCount(mCurrentBalance); + playerStore.add(ref.getPtr()); + } + mWindowManager.setGuiMode(GM_Game); } From 498530fad7244b8fe39f96003ab676f344a99bc7 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 18 May 2012 22:24:19 +0200 Subject: [PATCH 218/325] container iterator fix --- apps/openmw/mwworld/containerstore.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index ee1b620cd7..44eb0ac708 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -228,6 +228,11 @@ MWWorld::ContainerStoreIterator::ContainerStoreIterator (int mask, ContainerStor : mType (0), mMask (mask), mContainer (container) { nextType(); + + if (mType==-1 || (**this).getRefData().getCount()) + return; + + ++*this; } void MWWorld::ContainerStoreIterator::incType() @@ -249,7 +254,7 @@ void MWWorld::ContainerStoreIterator::nextType() { incType(); - if (mType & mMask) + if ((mType & mMask) && mType>0) if (resetIterator()) break; } From f28f36f2621e9803e1a830120e31609b8994548f Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 May 2012 22:27:27 +0200 Subject: [PATCH 219/325] added sounds to trade window --- apps/openmw/mwgui/container.cpp | 6 ++++++ apps/openmw/mwgui/tradewindow.cpp | 4 ++++ 2 files changed, 10 insertions(+) diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 710e30b744..871989fab7 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -196,6 +196,9 @@ void ContainerBase::sellAlreadyBoughtItem(MyGUI::Widget* _sender, int count) MWBase::Environment::get().getWindowManager()->getInventoryWindow()->drawItems(); } + std::string sound = MWWorld::Class::get(object).getUpSoundId(object); + MWBase::Environment::get().getSoundManager()->playSound (sound, 1.0, 1.0); + drawItems(); } @@ -216,6 +219,9 @@ void ContainerBase::sellItem(MyGUI::Widget* _sender, int count) MWBase::Environment::get().getWindowManager()->getInventoryWindow()->drawItems(); } + std::string sound = MWWorld::Class::get(object).getUpSoundId(object); + MWBase::Environment::get().getSoundManager()->playSound (sound, 1.0, 1.0); + drawItems(); } diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index 641ffa8338..b1beccc268 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -6,6 +6,7 @@ #include "../mwworld/world.hpp" #include "../mwworld/inventorystore.hpp" #include "../mwworld/manualref.hpp" +#include "../mwsound/soundmanager.hpp" #include "window_manager.hpp" #include "inventorywindow.hpp" @@ -232,6 +233,9 @@ namespace MWGui playerStore.add(ref.getPtr()); } + std::string sound = "Item Gold Up"; + MWBase::Environment::get().getSoundManager()->playSound (sound, 1.0, 1.0); + mWindowManager.setGuiMode(GM_Game); } From 656b08f6209bb496bc158e7ae151b9288df57c08 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 May 2012 22:32:06 +0200 Subject: [PATCH 220/325] removed the workaround for the ContainerStore bug. --- apps/openmw/mwgui/tradewindow.cpp | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index b1beccc268..047d1da1e7 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -150,21 +150,7 @@ namespace MWGui // were there any items traded at all? MWWorld::ContainerStore& playerBought = mWindowManager.getInventoryWindow()->getBoughtItems(); MWWorld::ContainerStore& merchantBought = getBoughtItems(); - - bool traded=false; - for (MWWorld::ContainerStoreIterator it = playerBought.begin(); - it != playerBought.end(); ++it) - { - if (it->getRefData().getCount() > 0) - traded = true; - } - for (MWWorld::ContainerStoreIterator it = merchantBought.begin(); - it != merchantBought.end(); ++it) - { - if (it->getRefData().getCount() > 0) - traded = true; - } - if (!traded) + if (playerBought.begin() == playerBought.end() && merchantBought.begin() == merchantBought.end()) { // user notification MWBase::Environment::get().getWindowManager()-> From 41466fc5fc38bba602ce8c2115a078811ae97a53 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 May 2012 23:00:31 +0200 Subject: [PATCH 221/325] gold label fix, and don't allow selling gold --- apps/openmw/mwgui/container.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 871989fab7..85a399450d 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -127,7 +127,9 @@ void ContainerBase::onSelectedItem(MyGUI::Widget* _sender) if (isInventory()) { // the player is trying to sell an item, check if the merchant accepts it - if (!MWBase::Environment::get().getWindowManager()->getTradeWindow()->npcAcceptsItem(object)) + // also, don't allow selling gold (let's be better than Morrowind at this, can we?) + if (!MWBase::Environment::get().getWindowManager()->getTradeWindow()->npcAcceptsItem(object) + || MWWorld::Class::get(object).getName(object) == MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sGold")->str) { // user notification "i don't buy this item" MWBase::Environment::get().getWindowManager()-> @@ -533,7 +535,7 @@ std::string ContainerBase::getCountString(const int count) if (count == 1) return ""; if (count > 9999) - return boost::lexical_cast(count/1000.f) + "k"; + return boost::lexical_cast(int(count/1000.f)) + "k"; else return boost::lexical_cast(count); } From 1006411c0200de3259608fc70f1e1cf5df7d225b Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 19 May 2012 00:06:11 +0200 Subject: [PATCH 222/325] small fix for mygui log being spammed with errors --- apps/openmw/mwgui/container.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 85a399450d..5595825fcf 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -489,7 +489,8 @@ void ContainerBase::drawItems() { backgroundTex += "_barter"; } - backgroundTex += ".dds"; + if (backgroundTex != "") + backgroundTex += ".dds"; backgroundWidget->setImageTexture(backgroundTex); if (it->second == ItemState_Barter && !isMagic) From 9ca579ba63de52d8590692dd96dd5c57dc93c699 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 19 May 2012 00:36:01 +0200 Subject: [PATCH 223/325] slightly revamped gold stacking, now always uses the gold_001 base object to be script-friendly --- apps/openmw/mwworld/containerstore.cpp | 48 +++++++++++++++----------- 1 file changed, 28 insertions(+), 20 deletions(-) diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index ada5b444ae..b669508b25 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -5,6 +5,8 @@ #include #include +#include + #include #include "../mwbase/environment.hpp" @@ -32,6 +34,12 @@ namespace return sum; } + + bool compare_string_ci(std::string str1, std::string str2) + { + boost::algorithm::to_lower(str1); + return str1 == str2; + } } MWWorld::ContainerStore::ContainerStore() : mStateId (0), mCachedWeight (0), mWeightUpToDate (false) {} @@ -65,35 +73,35 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::add (const Ptr& ptr) { int type = getType(ptr); - // gold needs special treatment because it uses several different meshes + // gold needs special handling: when it is inserted into a container, the base object automatically becomes Gold_001 + // this ensures that gold piles of different sizes stack with each other (also, several scripts rely on Gold_001 for detecting player gold) if (MWWorld::Class::get(ptr).getName(ptr) == MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sGold")->str) { ESMS::LiveCellRef *gold = ptr.get(); - int goldValue = (ptr.getRefData().getCount() == 1) ? gold->base->data.value : ptr.getRefData().getCount(); - - for (MWWorld::ContainerStoreIterator iter (begin(type)); iter!=end(); ++iter) + if (compare_string_ci(gold->ref.refID, "gold_001") + || compare_string_ci(gold->ref.refID, "gold_005") + || compare_string_ci(gold->ref.refID, "gold_010") + || compare_string_ci(gold->ref.refID, "gold_025") + || compare_string_ci(gold->ref.refID, "gold_100")) { - if (MWWorld::Class::get(*iter).getName(*iter) == MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sGold")->str - && MWWorld::Class::get(*iter).getScript(*iter) == "" && MWWorld::Class::get(ptr).getScript(ptr) == "") + MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), "Gold_001"); + + int count = (ptr.getRefData().getCount() == 1) ? gold->base->data.value : ptr.getRefData().getCount(); + ref.getPtr().getRefData().setCount(count); + for (MWWorld::ContainerStoreIterator iter (begin(type)); iter!=end(); ++iter) { - ESMS::LiveCellRef *ref = - iter->get(); - - if (iter->getRefData().getCount() == 1) - iter->getRefData().setCount(ref->base->data.value + goldValue); - else - iter->getRefData().setCount(iter->getRefData().getCount() + goldValue); - - flagAsModified(); - return iter; + if (compare_string_ci((*iter).get()->ref.refID, "gold_001")) + { + (*iter).getRefData().setCount( (*iter).getRefData().getCount() + count); + flagAsModified(); + return iter; + } } - } - // if we get here, no already existing gold was found in the container - // we still need special handling because gold in a container should always have the real gold value as reference count. - ptr.getRefData().setCount(goldValue); + return addImpl(ref.getPtr()); + } } // determine whether to stack or not From 74ae3605e0f8eb742ebe7b4b03438b62bff57d54 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 19 May 2012 09:31:45 +0200 Subject: [PATCH 224/325] Issue #256: added getTimeStamp function to World --- apps/openmw/mwworld/world.cpp | 6 ++++++ apps/openmw/mwworld/world.hpp | 4 ++++ 2 files changed, 10 insertions(+) diff --git a/apps/openmw/mwworld/world.cpp b/apps/openmw/mwworld/world.cpp index 4adaf79183..eeda92277e 100644 --- a/apps/openmw/mwworld/world.cpp +++ b/apps/openmw/mwworld/world.cpp @@ -471,6 +471,12 @@ namespace MWWorld mRendering->skySetDate (mGlobalVariables->getInt ("day"), month); } + TimeStamp World::getTimeStamp() const + { + return TimeStamp (mGlobalVariables->getFloat ("gamehour"), + mGlobalVariables->getInt ("dayspassed")); + } + bool World::toggleSky() { if (mSky) diff --git a/apps/openmw/mwworld/world.hpp b/apps/openmw/mwworld/world.hpp index 7359f8b902..49a3cf0296 100644 --- a/apps/openmw/mwworld/world.hpp +++ b/apps/openmw/mwworld/world.hpp @@ -18,6 +18,7 @@ #include "physicssystem.hpp" #include "cells.hpp" #include "localscripts.hpp" +#include "timestamp.hpp" #include #include @@ -185,6 +186,9 @@ namespace MWWorld void setDay (int day); ///< Set in-game time day. + TimeStamp getTimeStamp() const; + ///< Return current in-game time stamp. + bool toggleSky(); ///< \return Resulting mode From ee884634b993b4c5322804b9e4265d319da1dcf4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 19 May 2012 13:19:26 +0200 Subject: [PATCH 225/325] fixed item refID handling in the dialogue manager and container script extensions. --- apps/openmw/mwdialogue/dialoguemanager.cpp | 2 +- apps/openmw/mwscript/containerextensions.cpp | 17 +++++++++++++++-- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwdialogue/dialoguemanager.cpp b/apps/openmw/mwdialogue/dialoguemanager.cpp index 7baf589c44..295a50526e 100644 --- a/apps/openmw/mwdialogue/dialoguemanager.cpp +++ b/apps/openmw/mwdialogue/dialoguemanager.cpp @@ -363,7 +363,7 @@ namespace MWDialogue int sum = 0; for (MWWorld::ContainerStoreIterator iter (store.begin()); iter!=store.end(); ++iter) - if (iter->getCellRef().refID==name) + if (toLower(iter->getCellRef().refID) == toLower(name)) sum += iter->getRefData().getCount(); if(!selectCompare(comp,sum,select.i)) return false; } diff --git a/apps/openmw/mwscript/containerextensions.cpp b/apps/openmw/mwscript/containerextensions.cpp index 3e8658bf85..b916ba72cc 100644 --- a/apps/openmw/mwscript/containerextensions.cpp +++ b/apps/openmw/mwscript/containerextensions.cpp @@ -18,6 +18,19 @@ #include "interpretercontext.hpp" #include "ref.hpp" +namespace +{ + std::string toLower (const std::string& name) + { + std::string lowerCase; + + std::transform (name.begin(), name.end(), std::back_inserter (lowerCase), + (int(*)(int)) std::tolower); + + return lowerCase; + } +} + namespace MWScript { namespace Container @@ -65,7 +78,7 @@ namespace MWScript Interpreter::Type_Integer sum = 0; for (MWWorld::ContainerStoreIterator iter (store.begin()); iter!=store.end(); ++iter) - if (iter->getCellRef().refID==item) + if (toLower(iter->getCellRef().refID) == toLower(item)) sum += iter->getRefData().getCount(); runtime.push (sum); @@ -95,7 +108,7 @@ namespace MWScript for (MWWorld::ContainerStoreIterator iter (store.begin()); iter!=store.end() && count; ++iter) { - if (iter->getCellRef().refID==item) + if (toLower(iter->getCellRef().refID) == toLower(item)) { if (iter->getRefData().getCount()<=count) { From 24ce88de2a2c871bf06ca4d7c8d30167d5afe8df Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 19 May 2012 14:19:21 +0200 Subject: [PATCH 226/325] working mygui tag replacement system for GMST strings --- apps/openmw/mwgui/stats_window.cpp | 45 +++++++++++++++----- apps/openmw/mwgui/stats_window.hpp | 12 ++++-- apps/openmw/mwgui/tradewindow.cpp | 6 --- apps/openmw/mwgui/window_manager.cpp | 48 ++++++++++++---------- apps/openmw/mwgui/window_manager.hpp | 13 +++++- files/mygui/openmw_trade_window_layout.xml | 24 +++++++---- 6 files changed, 98 insertions(+), 50 deletions(-) diff --git a/apps/openmw/mwgui/stats_window.cpp b/apps/openmw/mwgui/stats_window.cpp index 43099e9369..fac2a05f93 100644 --- a/apps/openmw/mwgui/stats_window.cpp +++ b/apps/openmw/mwgui/stats_window.cpp @@ -1,13 +1,19 @@ #include "stats_window.hpp" -#include "../mwmechanics/mechanicsmanager.hpp" -#include "window_manager.hpp" - #include #include #include + #include +#include "../mwmechanics/mechanicsmanager.hpp" +#include "../mwworld/world.hpp" +#include "../mwworld/player.hpp" +#include "../mwbase/environment.hpp" + +#include "window_manager.hpp" + + using namespace MWGui; const int StatsWindow::lineHeight = 18; @@ -24,11 +30,12 @@ StatsWindow::StatsWindow (WindowManager& parWindowManager) , skillValues() , skillWidgetMap() , factionWidgetMap() - , factions() + , mFactions() , birthSignId() , reputation(0) , bounty(0) , skillWidgets() + , mChanged(true) { setCoord(0,0,498, 342); @@ -128,7 +135,8 @@ void StatsWindow::setBar(const std::string& name, const std::string& tname, int void StatsWindow::setPlayerName(const std::string& playerName) { - setTitle(playerName); + static_cast(mMainWidget)->setCaption(playerName); + adjustWindowCaption(); } void StatsWindow::setValue (const std::string& id, const MWMechanics::Stat& value) @@ -235,9 +243,24 @@ void StatsWindow::configureSkills (const std::vector& major, const std::vec } } -void StatsWindow::setFactions (const std::vector& factions) +void StatsWindow::onFrame () { - this->factions = factions; + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + MWMechanics::NpcStats PCstats = MWWorld::Class::get(player).getNpcStats(player); + + setFactions(PCstats.mFactionRank); + + if (mChanged) + updateSkillArea(); +} + +void StatsWindow::setFactions (const FactionList& factions) +{ + if (mFactions != factions) + { + mFactions = factions; + mChanged = true; + } } void StatsWindow::setBirthSign (const std::string& signId) @@ -345,6 +368,8 @@ void StatsWindow::addSkills(const SkillList &skills, const std::string &titleId, void StatsWindow::updateSkillArea() { + mChanged = false; + for (std::vector::iterator it = skillWidgets.begin(); it != skillWidgets.end(); ++it) { MyGUI::Gui::getInstance().destroyWidget(*it); @@ -366,15 +391,15 @@ void StatsWindow::updateSkillArea() const ESMS::ESMStore &store = mWindowManager.getStore(); - if (!factions.empty()) + if (!mFactions.empty()) { // Add a line separator if there are items above if (!skillWidgets.empty()) addSeparator(coord1, coord2); addGroup(mWindowManager.getGameSettingString("sFaction", "Faction"), coord1, coord2); - FactionList::const_iterator end = factions.end(); - for (FactionList::const_iterator it = factions.begin(); it != end; ++it) + FactionList::const_iterator end = mFactions.end(); + for (FactionList::const_iterator it = mFactions.begin(); it != end; ++it) { const ESM::Faction *faction = store.factions.find(it->first); addItem(faction->name, coord1, coord2); diff --git a/apps/openmw/mwgui/stats_window.hpp b/apps/openmw/mwgui/stats_window.hpp index 08c5148ecc..ecda22ee08 100644 --- a/apps/openmw/mwgui/stats_window.hpp +++ b/apps/openmw/mwgui/stats_window.hpp @@ -18,13 +18,15 @@ namespace MWGui class StatsWindow : public WindowPinnableBase { public: - typedef std::pair Faction; - typedef std::vector FactionList; + typedef std::map FactionList; typedef std::vector SkillList; StatsWindow(WindowManager& parWindowManager); + /// automatically updates all the data in the stats window, but only if it has changed. + void onFrame(); + void setBar(const std::string& name, const std::string& tname, int val, int max); void setPlayerName(const std::string& playerName); @@ -36,7 +38,7 @@ namespace MWGui void setValue(const ESM::Skill::SkillEnum parSkill, const MWMechanics::Stat& value); void configureSkills (const SkillList& major, const SkillList& minor); - void setFactions (const std::vector& factions); + void setFactions (const FactionList& factions); void setBirthSign (const std::string &signId); void setReputation (int reputation) { this->reputation = reputation; } void setBounty (int bounty) { this->bounty = bounty; } @@ -69,11 +71,13 @@ namespace MWGui std::map > skillValues; std::map skillWidgetMap; std::map factionWidgetMap; - FactionList factions; ///< Stores a list of factions and the current rank + FactionList mFactions; ///< Stores a list of factions and the current rank std::string birthSignId; int reputation, bounty; std::vector skillWidgets; //< Skills and other information + bool mChanged; + protected: virtual void onPinToggled(); }; diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index 047d1da1e7..2dcf7c7f8f 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -47,12 +47,6 @@ namespace MWGui mCancelButton->setCaption(MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sCancel")->str); mOfferButton->setCaption(MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sBarterDialog8")->str); - mFilterAll->setCaption (MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sAllTab")->str); - mFilterWeapon->setCaption (MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sWeaponTab")->str); - mFilterApparel->setCaption (MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sApparelTab")->str); - mFilterMagic->setCaption (MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sMagicTab")->str); - mFilterMisc->setCaption (MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sMiscTab")->str); - // adjust size of buttons to fit text int curX = 0; mFilterAll->setSize( mFilterAll->getTextSize().width + 24, mFilterAll->getSize().height ); diff --git a/apps/openmw/mwgui/window_manager.cpp b/apps/openmw/mwgui/window_manager.cpp index f447c78e41..9246af1fec 100644 --- a/apps/openmw/mwgui/window_manager.cpp +++ b/apps/openmw/mwgui/window_manager.cpp @@ -40,7 +40,7 @@ WindowManager::WindowManager( , hud(NULL) , map(NULL) , menu(NULL) - , stats(NULL) + , mStatsWindow(NULL) , mToolTips(NULL) , mMessageBoxManager(NULL) , console(NULL) @@ -89,6 +89,8 @@ WindowManager::WindowManager( MyGUI::FactoryManager::getInstance().registerFactory("Widget"); MyGUI::FactoryManager::getInstance().registerFactory("Widget"); + MyGUI::LanguageManager::getInstance().eventRequestTag = MyGUI::newDelegate(this, &WindowManager::onRetrieveTag); + // Get size info from the Gui object assert(gui); int w = MyGUI::RenderManager::getInstance().getViewSize().width; @@ -104,7 +106,7 @@ WindowManager::WindowManager( menu = new MainMenu(w,h); map = new MapWindow(*this); - stats = new StatsWindow(*this); + mStatsWindow = new StatsWindow(*this); console = new Console(w,h, extensions); mJournal = new JournalWindow(*this); mMessageBoxManager = new MessageBoxManager(this); @@ -146,7 +148,7 @@ WindowManager::~WindowManager() delete hud; delete map; delete menu; - delete stats; + delete mStatsWindow; delete mJournal; delete mDialogueWindow; delete mContainerWindow; @@ -207,7 +209,7 @@ void WindowManager::updateVisible() // Start out by hiding everything except the HUD map->setVisible(false); menu->setVisible(false); - stats->setVisible(false); + mStatsWindow->setVisible(false); console->disable(); mJournal->setVisible(false); mDialogueWindow->setVisible(false); @@ -261,7 +263,7 @@ void WindowManager::updateVisible() // Show the windows we want map -> setVisible( (eff & GW_Map) != 0 ); - stats -> setVisible( (eff & GW_Stats) != 0 ); + mStatsWindow -> setVisible( (eff & GW_Stats) != 0 ); mInventoryWindow->setVisible(true); mInventoryWindow->openInventory(); break; @@ -299,7 +301,7 @@ void WindowManager::updateVisible() void WindowManager::setValue (const std::string& id, const MWMechanics::Stat& value) { - stats->setValue (id, value); + mStatsWindow->setValue (id, value); static const char *ids[] = { @@ -329,13 +331,13 @@ void WindowManager::setValue (const std::string& id, const MWMechanics::Stat& value) { - stats->setValue(parSkill, value); + mStatsWindow->setValue(parSkill, value); playerSkillValues[parSkill] = value; } void WindowManager::setValue (const std::string& id, const MWMechanics::DynamicStat& value) { - stats->setValue (id, value); + mStatsWindow->setValue (id, value); hud->setValue (id, value); if (id == "HBar") { @@ -368,7 +370,7 @@ MWMechanics::DynamicStat WindowManager::getValue(const std::string& id) void WindowManager::setValue (const std::string& id, const std::string& value) { - stats->setValue (id, value); + mStatsWindow->setValue (id, value); if (id=="name") playerName = value; else if (id=="race") @@ -377,46 +379,41 @@ void WindowManager::setValue (const std::string& id, const std::string& value) void WindowManager::setValue (const std::string& id, int value) { - stats->setValue (id, value); + mStatsWindow->setValue (id, value); } void WindowManager::setPlayerClass (const ESM::Class &class_) { playerClass = class_; - stats->setValue("class", playerClass.name); + mStatsWindow->setValue("class", playerClass.name); } void WindowManager::configureSkills (const SkillList& major, const SkillList& minor) { - stats->configureSkills (major, minor); + mStatsWindow->configureSkills (major, minor); playerMajorSkills = major; playerMinorSkills = minor; } -void WindowManager::setFactions (const FactionList& factions) -{ - stats->setFactions (factions); -} - void WindowManager::setBirthSign (const std::string &signId) { - stats->setBirthSign (signId); + mStatsWindow->setBirthSign (signId); playerBirthSignId = signId; } void WindowManager::setReputation (int reputation) { - stats->setReputation (reputation); + mStatsWindow->setReputation (reputation); } void WindowManager::setBounty (int bounty) { - stats->setBounty (bounty); + mStatsWindow->setBounty (bounty); } void WindowManager::updateSkillArea() { - stats->updateSkillArea(); + mStatsWindow->updateSkillArea(); } void WindowManager::removeDialog(OEngine::GUI::Layout*dialog) @@ -477,6 +474,8 @@ void WindowManager::onFrame (float frameDuration) } mInventoryWindow->update(); + + mStatsWindow->onFrame(); } const ESMS::ESMStore& WindowManager::getStore() const @@ -598,3 +597,10 @@ void WindowManager::setDragDrop(bool dragDrop) mToolTips->setEnabled(!dragDrop); MWBase::Environment::get().getInputManager()->setDragDrop(dragDrop); } + +void WindowManager::onRetrieveTag(const MyGUI::UString& _tag, MyGUI::UString& _result) +{ + const ESM::GameSetting *setting = MWBase::Environment::get().getWorld()->getStore().gameSettings.search(_tag); + if (setting && setting->type == ESM::VT_String) + _result = setting->str; +} diff --git a/apps/openmw/mwgui/window_manager.hpp b/apps/openmw/mwgui/window_manager.hpp index 82c494191a..cdcace85de 100644 --- a/apps/openmw/mwgui/window_manager.hpp +++ b/apps/openmw/mwgui/window_manager.hpp @@ -14,11 +14,15 @@ #include #include +#include "MyGUI_UString.h" + #include #include #include + #include "../mwmechanics/stat.hpp" #include "../mwworld/ptr.hpp" + #include "mode.hpp" namespace MyGUI @@ -157,7 +161,6 @@ namespace MWGui void setPlayerClass (const ESM::Class &class_); ///< set current class of player void configureSkills (const SkillList& major, const SkillList& minor); ///< configure skill groups, each set contains the skill ID for that group. - void setFactions (const FactionList& factions); ///< set faction and rank to display on stat window, use an empty vector to disable void setBirthSign (const std::string &signId); ///< set birth sign to display on stat window, use an empty string to disable. void setReputation (int reputation); ///< set the current reputation value void setBounty (int bounty); ///< set the current bounty value @@ -216,7 +219,7 @@ namespace MWGui MapWindow *map; MainMenu *menu; ToolTips *mToolTips; - StatsWindow *stats; + StatsWindow *mStatsWindow; MessageBoxManager *mMessageBoxManager; Console *console; JournalWindow* mJournal; @@ -270,6 +273,12 @@ namespace MWGui size_t mBatchCount; void onDialogueWindowBye(); + + /** + * Called when MyGUI tries to retrieve a tag. This usually corresponds to a GMST string, + * so this method will retrieve the GMST with the name \a _tag and place the result in \a _result + */ + void onRetrieveTag(const MyGUI::UString& _tag, MyGUI::UString& _result); }; template diff --git a/files/mygui/openmw_trade_window_layout.xml b/files/mygui/openmw_trade_window_layout.xml index b6a93e6973..8a4e004333 100644 --- a/files/mygui/openmw_trade_window_layout.xml +++ b/files/mygui/openmw_trade_window_layout.xml @@ -6,11 +6,21 @@ - - - - - + + + + + + + + + + + + + + + @@ -36,8 +46,8 @@ - - + + From 635a89c35cc17053a40ec6cec0efb804c5c4185c Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 19 May 2012 14:43:02 +0200 Subject: [PATCH 227/325] Issue #256: RNG fix --- apps/openmw/mwmechanics/magiceffects.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/magiceffects.cpp b/apps/openmw/mwmechanics/magiceffects.cpp index f71e070d21..a77e199661 100644 --- a/apps/openmw/mwmechanics/magiceffects.cpp +++ b/apps/openmw/mwmechanics/magiceffects.cpp @@ -79,7 +79,8 @@ namespace MWMechanics param.mMagnitude = iter->magnMin; else param.mMagnitude = static_cast ( - (iter->magnMax-iter->magnMin+1)*(std::rand() / RAND_MAX) + iter->magnMin); + (iter->magnMax-iter->magnMin+1)* + (static_cast (std::rand()) / RAND_MAX) + iter->magnMin); add (*iter, param); } From 7ef0ad4e39c46d514681fac994a5ccbcf8d26e72 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 19 May 2012 14:55:09 +0200 Subject: [PATCH 228/325] show faction & birthsign in the stats window --- apps/openmw/mwgui/charactercreation.cpp | 2 -- apps/openmw/mwgui/inventorywindow.cpp | 11 ++++------ apps/openmw/mwgui/inventorywindow.hpp | 2 +- apps/openmw/mwgui/stats_window.cpp | 15 +++++++++++++- apps/openmw/mwgui/stats_window.hpp | 5 +++-- apps/openmw/mwgui/window_manager.cpp | 9 +-------- apps/openmw/mwgui/window_manager.hpp | 2 -- .../mygui/openmw_inventory_window_layout.xml | 20 ++++++++++++++----- 8 files changed, 38 insertions(+), 28 deletions(-) diff --git a/apps/openmw/mwgui/charactercreation.cpp b/apps/openmw/mwgui/charactercreation.cpp index 7a86ba9ac8..afb168d321 100644 --- a/apps/openmw/mwgui/charactercreation.cpp +++ b/apps/openmw/mwgui/charactercreation.cpp @@ -173,7 +173,6 @@ void CharacterCreation::spawnDialog(const char id) mWM->removeDialog(mBirthSignDialog); mBirthSignDialog = new BirthDialog(*mWM); mBirthSignDialog->setNextButtonShow(mCreationStage >= CSE_BirthSignChosen); - mBirthSignDialog->setBirthId(mPlayerBirthSignId); mBirthSignDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onBirthSignDialogDone); mBirthSignDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onBirthSignDialogBack); mBirthSignDialog->open(); @@ -414,7 +413,6 @@ void CharacterCreation::onBirthSignDialogDone(WindowBase* parWindow) if (mBirthSignDialog) { mPlayerBirthSignId = mBirthSignDialog->getBirthId(); - mWM->setBirthSign(mPlayerBirthSignId); if (!mPlayerBirthSignId.empty()) MWBase::Environment::get().getMechanicsManager()->setPlayerBirthsign(mPlayerBirthSignId); mWM->removeDialog(mBirthSignDialog); diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 8bc9661e49..a0326debc0 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -50,12 +50,6 @@ namespace MWGui getWidget(itemView, "ItemView"); setWidgets(containerWidget, itemView); - mFilterAll->setCaption (MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sAllTab")->str); - mFilterWeapon->setCaption (MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sWeaponTab")->str); - mFilterApparel->setCaption (MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sApparelTab")->str); - mFilterMagic->setCaption (MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sMagicTab")->str); - mFilterMisc->setCaption (MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sMiscTab")->str); - // adjust size of buttons to fit text int curX = 0; mFilterAll->setSize( mFilterAll->getTextSize().width + 24, mFilterAll->getSize().height ); @@ -227,8 +221,11 @@ namespace MWGui mEncumbranceText->setCaption( boost::lexical_cast(int(encumbrance)) + "/" + boost::lexical_cast(int(capacity)) ); } - void InventoryWindow::update() + void InventoryWindow::onFrame() { + if (!mMainWidget->getVisible()) + return; + updateEncumbranceBar(); } diff --git a/apps/openmw/mwgui/inventorywindow.hpp b/apps/openmw/mwgui/inventorywindow.hpp index 59aaf7859a..fdb4438292 100644 --- a/apps/openmw/mwgui/inventorywindow.hpp +++ b/apps/openmw/mwgui/inventorywindow.hpp @@ -16,7 +16,7 @@ namespace MWGui /// start trading, disables item drag&drop void startTrade(); - void update(); + void onFrame(); int getPlayerGold(); diff --git a/apps/openmw/mwgui/stats_window.cpp b/apps/openmw/mwgui/stats_window.cpp index fac2a05f93..30d63033b1 100644 --- a/apps/openmw/mwgui/stats_window.cpp +++ b/apps/openmw/mwgui/stats_window.cpp @@ -245,11 +245,16 @@ void StatsWindow::configureSkills (const std::vector& major, const std::vec void StatsWindow::onFrame () { + if (mMainWidget->getVisible()) + return; + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); MWMechanics::NpcStats PCstats = MWWorld::Class::get(player).getNpcStats(player); setFactions(PCstats.mFactionRank); + setBirthSign(MWBase::Environment::get().getWorld()->getPlayer().getBirthsign()); + if (mChanged) updateSkillArea(); } @@ -265,7 +270,11 @@ void StatsWindow::setFactions (const FactionList& factions) void StatsWindow::setBirthSign (const std::string& signId) { - birthSignId = signId; + if (signId != birthSignId) + { + birthSignId = signId; + mChanged = true; + } } void StatsWindow::addSeparator(MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) @@ -376,6 +385,10 @@ void StatsWindow::updateSkillArea() } skillWidgets.clear(); + skillScrollerWidget->setScrollPosition(0); + onScrollChangePosition(skillScrollerWidget, 0); + clientHeight = 0; + const int valueSize = 40; MyGUI::IntCoord coord1(10, 0, skillClientWidget->getWidth() - (10 + valueSize), 18); MyGUI::IntCoord coord2(coord1.left + coord1.width, coord1.top, valueSize, coord1.height); diff --git a/apps/openmw/mwgui/stats_window.hpp b/apps/openmw/mwgui/stats_window.hpp index ecda22ee08..677b329356 100644 --- a/apps/openmw/mwgui/stats_window.hpp +++ b/apps/openmw/mwgui/stats_window.hpp @@ -38,8 +38,6 @@ namespace MWGui void setValue(const ESM::Skill::SkillEnum parSkill, const MWMechanics::Stat& value); void configureSkills (const SkillList& major, const SkillList& minor); - void setFactions (const FactionList& factions); - void setBirthSign (const std::string &signId); void setReputation (int reputation) { this->reputation = reputation; } void setBounty (int bounty) { this->bounty = bounty; } void updateSkillArea(); @@ -54,6 +52,9 @@ namespace MWGui void setupToolTips(); + void setFactions (const FactionList& factions); + void setBirthSign (const std::string &signId); + void onScrollChangePosition(MyGUI::ScrollBar* scroller, size_t pos); void onWindowResize(MyGUI::Window* window); void onMouseWheel(MyGUI::Widget* _sender, int _rel); diff --git a/apps/openmw/mwgui/window_manager.cpp b/apps/openmw/mwgui/window_manager.cpp index 9246af1fec..2cacf23467 100644 --- a/apps/openmw/mwgui/window_manager.cpp +++ b/apps/openmw/mwgui/window_manager.cpp @@ -54,7 +54,6 @@ WindowManager::WindowManager( , playerClass() , playerName() , playerRaceId() - , playerBirthSignId() , playerAttributes() , playerMajorSkills() , playerMinorSkills() @@ -395,12 +394,6 @@ void WindowManager::configureSkills (const SkillList& major, const SkillList& mi playerMinorSkills = minor; } -void WindowManager::setBirthSign (const std::string &signId) -{ - mStatsWindow->setBirthSign (signId); - playerBirthSignId = signId; -} - void WindowManager::setReputation (int reputation) { mStatsWindow->setReputation (reputation); @@ -473,7 +466,7 @@ void WindowManager::onFrame (float frameDuration) mDragAndDrop->mDraggedWidget->setPosition(MyGUI::InputManager::getInstance().getMousePosition()); } - mInventoryWindow->update(); + mInventoryWindow->onFrame(); mStatsWindow->onFrame(); } diff --git a/apps/openmw/mwgui/window_manager.hpp b/apps/openmw/mwgui/window_manager.hpp index cdcace85de..22fe973a59 100644 --- a/apps/openmw/mwgui/window_manager.hpp +++ b/apps/openmw/mwgui/window_manager.hpp @@ -161,7 +161,6 @@ namespace MWGui void setPlayerClass (const ESM::Class &class_); ///< set current class of player void configureSkills (const SkillList& major, const SkillList& minor); ///< configure skill groups, each set contains the skill ID for that group. - void setBirthSign (const std::string &signId); ///< set birth sign to display on stat window, use an empty string to disable. void setReputation (int reputation); ///< set the current reputation value void setBounty (int bounty); ///< set the current bounty value void updateSkillArea(); ///< update display of skills, factions, birth sign, reputation and bounty @@ -238,7 +237,6 @@ namespace MWGui ESM::Class playerClass; std::string playerName; std::string playerRaceId; - std::string playerBirthSignId; std::map > playerAttributes; SkillList playerMajorSkills, playerMinorSkills; std::map > playerSkillValues; diff --git a/files/mygui/openmw_inventory_window_layout.xml b/files/mygui/openmw_inventory_window_layout.xml index 4d63b03c2a..86ef65324c 100644 --- a/files/mygui/openmw_inventory_window_layout.xml +++ b/files/mygui/openmw_inventory_window_layout.xml @@ -35,11 +35,21 @@ - - - - - + + + + + + + + + + + + + + + From 9f1919a230e5d6dbb0a2cf2491569169cf2bed25 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 19 May 2012 15:01:07 +0200 Subject: [PATCH 229/325] Issue #256: added active spell management (completely untested) --- apps/openmw/CMakeLists.txt | 1 + apps/openmw/mwmechanics/activespells.cpp | 162 ++++++++++++++++++++++ apps/openmw/mwmechanics/activespells.hpp | 58 ++++++++ apps/openmw/mwmechanics/actors.cpp | 2 +- apps/openmw/mwmechanics/creaturestats.hpp | 2 + 5 files changed, 224 insertions(+), 1 deletion(-) create mode 100644 apps/openmw/mwmechanics/activespells.cpp create mode 100644 apps/openmw/mwmechanics/activespells.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 7e5dcc1e2e..ca2355346c 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -58,6 +58,7 @@ add_openmw_dir (mwclass add_openmw_dir (mwmechanics mechanicsmanager stat creaturestats magiceffects movement actors drawstate spells + activespells ) add_openmw_dir (mwbase diff --git a/apps/openmw/mwmechanics/activespells.cpp b/apps/openmw/mwmechanics/activespells.cpp new file mode 100644 index 0000000000..ced2a5c3fe --- /dev/null +++ b/apps/openmw/mwmechanics/activespells.cpp @@ -0,0 +1,162 @@ + +#include "activespells.hpp" + +#include + +#include "../mwbase/environment.hpp" + +#include "../mwworld/world.hpp" + +namespace MWMechanics +{ + void ActiveSpells::update() const + { + bool rebuild = false; + + MWWorld::TimeStamp now = MWBase::Environment::get().getWorld()->getTimeStamp(); + + if (mLastUpdate!=now) + { + TContainer::iterator iter (mSpells.begin()); + while (iter!=mSpells.end()) + if (!timeToExpire (iter)) + { + mSpells.erase (iter++); + rebuild = true; + } + else + ++iter; + + mLastUpdate = now; + } + + if (mSpellsChanged) + { + mSpellsChanged = false; + rebuild = true; + } + + if (rebuild) + { + mEffects = MagicEffects(); + + for (TIterator iter (begin()); iter!=end(); ++iter) + { + const ESM::Spell& spell = + *MWBase::Environment::get().getWorld()->getStore().spells.find (iter->first); + + const MWWorld::TimeStamp& start = iter->second.first; + float magnitude = iter->second.second; + + for (std::vector::const_iterator iter (spell.effects.list.begin()); + iter!=spell.effects.list.end(); ++iter) + { + if (iter->duration) + { + MWWorld::TimeStamp end = start; + end += static_cast (iter->duration)* + MWBase::Environment::get().getWorld()->getTimeScaleFactor()/(60*60); + + if (end>now) + { + EffectParam param; + param.mMagnitude = static_cast ( + (iter->magnMax-iter->magnMin+1)*magnitude + iter->magnMin); + mEffects.add (*iter, param); + } + } + } + } + } + } + + ActiveSpells::ActiveSpells() + : mSpellsChanged (false), mLastUpdate (MWBase::Environment::get().getWorld()->getTimeStamp()) + {} + + void ActiveSpells::addSpell (const std::string& id) + { + const ESM::Spell& spell = *MWBase::Environment::get().getWorld()->getStore().spells.find (id); + + bool found = false; + + for (std::vector::const_iterator iter (spell.effects.list.begin()); + iter!=spell.effects.list.end(); ++iter) + { + if (iter->duration) + { + found = true; + break; + } + } + + if (!found) + return; + + TContainer::iterator iter = mSpells.find (id); + + float random = static_cast (std::rand()) / RAND_MAX; + + if (iter==mSpells.end()) + mSpells.insert (std::make_pair (id, + std::make_pair (MWBase::Environment::get().getWorld()->getTimeStamp(), random))); + else + iter->second = std::make_pair (MWBase::Environment::get().getWorld()->getTimeStamp(), random); + + mSpellsChanged = true; + } + + void ActiveSpells::removeSpell (const std::string& id) + { + TContainer::iterator iter = mSpells.find (id); + + if (iter!=mSpells.end()) + { + mSpells.erase (iter); + mSpellsChanged = true; + } + } + + const MagicEffects& ActiveSpells::getMagicEffects() const + { + update(); + return mEffects; + } + + ActiveSpells::TIterator ActiveSpells::begin() const + { + update(); + return mSpells.begin(); + } + + ActiveSpells::TIterator ActiveSpells::end() const + { + update(); + return mSpells.end(); + } + + double ActiveSpells::timeToExpire (const TIterator& iterator) const + { + const ESM::Spell& spell = + *MWBase::Environment::get().getWorld()->getStore().spells.find (iterator->first); + + int duration = 0; + + for (std::vector::const_iterator iter (spell.effects.list.begin()); + iter!=spell.effects.list.end(); ++iter) + { + if (iter->duration>duration) + duration = iter->duration; + } + + double scaledDuration = duration * + MWBase::Environment::get().getWorld()->getTimeScaleFactor()/(60*60); + + double usedUp = MWBase::Environment::get().getWorld()->getTimeStamp()-iterator->second.first; + + if (usedUp>=scaledDuration) + return 0; + + return scaledDuration-usedUp; + } +} diff --git a/apps/openmw/mwmechanics/activespells.hpp b/apps/openmw/mwmechanics/activespells.hpp new file mode 100644 index 0000000000..179321c58a --- /dev/null +++ b/apps/openmw/mwmechanics/activespells.hpp @@ -0,0 +1,58 @@ +#ifndef GAME_MWMECHANICS_ACTIVESPELLS_H +#define GAME_MWMECHANICS_ACTIVESPELLS_H + +#include +#include +#include + +#include "../mwworld/timestamp.hpp" + +#include "magiceffects.hpp" + +namespace ESM +{ + struct Spell; +} + +namespace MWMechanics +{ + /// \brief Lasting spell effects + class ActiveSpells + { + public: + + typedef std::map > TContainer; + typedef TContainer::const_iterator TIterator; + + private: + + mutable TContainer mSpells; // spellId, (time of casting, relative magnitude) + mutable MagicEffects mEffects; + mutable bool mSpellsChanged; + mutable MWWorld::TimeStamp mLastUpdate; + + void update() const; + + public: + + ActiveSpells(); + + void addSpell (const std::string& id); + ///< Overwrites an existing spell with the same ID. If the spell does not have any + /// non-instant effects, it is ignored. + + void removeSpell (const std::string& id); + + const MagicEffects& getMagicEffects() const; + + TIterator begin() const; + + TIterator end() const; + + double timeToExpire (const TIterator& iterator) const; + ///< Returns time (in in-game hours) until the spell pointed to by \a iterator + /// expires. + }; +} + +#endif diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index cd2dbaddfd..5a17d50e4b 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -53,7 +53,7 @@ namespace MWMechanics now += store.getMagicEffects(); } - /// \todo add effects from active spells + now += creatureStats.mActiveSpells.getMagicEffects(); MagicEffects diff = MagicEffects::diff (creatureStats.mMagicEffects, now); diff --git a/apps/openmw/mwmechanics/creaturestats.hpp b/apps/openmw/mwmechanics/creaturestats.hpp index ab008da9e8..cc3c409da2 100644 --- a/apps/openmw/mwmechanics/creaturestats.hpp +++ b/apps/openmw/mwmechanics/creaturestats.hpp @@ -7,6 +7,7 @@ #include "stat.hpp" #include "magiceffects.hpp" #include "spells.hpp" +#include "activespells.hpp" namespace MWMechanics { @@ -16,6 +17,7 @@ namespace MWMechanics DynamicStat mDynamic[3]; // health, magicka, fatigue int mLevel; Spells mSpells; + ActiveSpells mActiveSpells; MagicEffects mMagicEffects; }; } From 7a4de0ed1d527c018bc5f565ed9d007b8a6a82bb Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 19 May 2012 15:32:32 +0200 Subject: [PATCH 230/325] changed more gui stuff to use the new tag system --- apps/openmw/mwgui/birth.cpp | 1 - apps/openmw/mwgui/class.cpp | 3 -- apps/openmw/mwgui/race.cpp | 1 - apps/openmw/mwgui/review.cpp | 5 ---- apps/openmw/mwgui/stats_window.cpp | 6 ---- apps/openmw/mwgui/tradewindow.cpp | 6 ---- files/mygui/openmw_chargen_birth_layout.xml | 2 +- files/mygui/openmw_chargen_class_layout.xml | 2 +- .../openmw_chargen_create_class_layout.xml | 2 +- ...w_chargen_generate_class_result_layout.xml | 2 +- files/mygui/openmw_chargen_race_layout.xml | 2 +- files/mygui/openmw_chargen_review_layout.xml | 30 ++++++++++++++----- .../mygui/openmw_inventory_window_layout.xml | 6 +--- files/mygui/openmw_stats_window_layout.xml | 24 +++++++++++---- files/mygui/openmw_trade_window_layout.xml | 12 ++++++-- 15 files changed, 55 insertions(+), 49 deletions(-) diff --git a/apps/openmw/mwgui/birth.cpp b/apps/openmw/mwgui/birth.cpp index cb15eaf15b..49f90d1a07 100644 --- a/apps/openmw/mwgui/birth.cpp +++ b/apps/openmw/mwgui/birth.cpp @@ -27,7 +27,6 @@ BirthDialog::BirthDialog(WindowManager& parWindowManager) MyGUI::ButtonPtr backButton; getWidget(backButton, "BackButton"); - backButton->setCaption(mWindowManager.getGameSettingString("sBack", "")); backButton->eventMouseButtonClick += MyGUI::newDelegate(this, &BirthDialog::onBackClicked); MyGUI::ButtonPtr okButton; diff --git a/apps/openmw/mwgui/class.cpp b/apps/openmw/mwgui/class.cpp index e654f7c908..3e41fa6b10 100644 --- a/apps/openmw/mwgui/class.cpp +++ b/apps/openmw/mwgui/class.cpp @@ -28,7 +28,6 @@ GenerateClassResultDialog::GenerateClassResultDialog(WindowManager& parWindowMan MyGUI::ButtonPtr backButton; getWidget(backButton, "BackButton"); - backButton->setCaption(mWindowManager.getGameSettingString("sBack", "")); backButton->eventMouseButtonClick += MyGUI::newDelegate(this, &GenerateClassResultDialog::onBackClicked); MyGUI::ButtonPtr okButton; @@ -111,7 +110,6 @@ PickClassDialog::PickClassDialog(WindowManager& parWindowManager) MyGUI::ButtonPtr backButton; getWidget(backButton, "BackButton"); backButton->eventMouseButtonClick += MyGUI::newDelegate(this, &PickClassDialog::onBackClicked); - backButton->setCaption(mWindowManager.getGameSettingString("sBack", "")); MyGUI::ButtonPtr okButton; getWidget(okButton, "OKButton"); @@ -432,7 +430,6 @@ CreateClassDialog::CreateClassDialog(WindowManager& parWindowManager) MyGUI::ButtonPtr backButton; getWidget(backButton, "BackButton"); backButton->eventMouseButtonClick += MyGUI::newDelegate(this, &CreateClassDialog::onBackClicked); - backButton->setCaption(mWindowManager.getGameSettingString("sBack", "")); MyGUI::ButtonPtr okButton; getWidget(okButton, "OKButton"); diff --git a/apps/openmw/mwgui/race.cpp b/apps/openmw/mwgui/race.cpp index 275759c9f7..f18bdb41ff 100644 --- a/apps/openmw/mwgui/race.cpp +++ b/apps/openmw/mwgui/race.cpp @@ -71,7 +71,6 @@ RaceDialog::RaceDialog(WindowManager& parWindowManager) MyGUI::ButtonPtr backButton; getWidget(backButton, "BackButton"); - backButton->setCaption(mWindowManager.getGameSettingString("sBack", "")); backButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onBackClicked); MyGUI::ButtonPtr okButton; diff --git a/apps/openmw/mwgui/review.cpp b/apps/openmw/mwgui/review.cpp index 81a87b07b6..5059efb342 100644 --- a/apps/openmw/mwgui/review.cpp +++ b/apps/openmw/mwgui/review.cpp @@ -27,25 +27,21 @@ ReviewDialog::ReviewDialog(WindowManager& parWindowManager) ButtonPtr button; getWidget(nameWidget, "NameText"); getWidget(button, "NameButton"); - button->setCaption(mWindowManager.getGameSettingString("sName", "")); adjustButtonSize(button); button->eventMouseButtonClick += MyGUI::newDelegate(this, &ReviewDialog::onNameClicked);; getWidget(raceWidget, "RaceText"); getWidget(button, "RaceButton"); - button->setCaption(mWindowManager.getGameSettingString("sRace", "")); adjustButtonSize(button); button->eventMouseButtonClick += MyGUI::newDelegate(this, &ReviewDialog::onRaceClicked);; getWidget(classWidget, "ClassText"); getWidget(button, "ClassButton"); - button->setCaption(mWindowManager.getGameSettingString("sClass", "")); adjustButtonSize(button); button->eventMouseButtonClick += MyGUI::newDelegate(this, &ReviewDialog::onClassClicked);; getWidget(birthSignWidget, "SignText"); getWidget(button, "SignButton"); - button->setCaption(mWindowManager.getGameSettingString("sBirthSign", "")); adjustButtonSize(button); button->eventMouseButtonClick += MyGUI::newDelegate(this, &ReviewDialog::onBirthSignClicked);; @@ -92,7 +88,6 @@ ReviewDialog::ReviewDialog(WindowManager& parWindowManager) MyGUI::ButtonPtr backButton; getWidget(backButton, "BackButton"); - backButton->setCaption(mWindowManager.getGameSettingString("sBack", "")); backButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ReviewDialog::onBackClicked); MyGUI::ButtonPtr okButton; diff --git a/apps/openmw/mwgui/stats_window.cpp b/apps/openmw/mwgui/stats_window.cpp index 30d63033b1..06576b42b6 100644 --- a/apps/openmw/mwgui/stats_window.cpp +++ b/apps/openmw/mwgui/stats_window.cpp @@ -49,12 +49,6 @@ StatsWindow::StatsWindow (WindowManager& parWindowManager) { "Attrib6", "sAttributeEndurance" }, { "Attrib7", "sAttributePersonality" }, { "Attrib8", "sAttributeLuck" }, - { "Health_str", "sHealth" }, - { "Magicka_str", "sMagic" }, - { "Fatigue_str", "sFatigue" }, - { "Level_str", "sLevel" }, - { "Race_str", "sRace" }, - { "Class_str", "sClass" }, { 0, 0 } }; diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index 2dcf7c7f8f..3570ea6a39 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -41,12 +41,6 @@ namespace MWGui getWidget(mTotalBalanceLabel, "TotalBalanceLabel"); getWidget(mBottomPane, "BottomPane"); - // this GMST doesn't seem to get retrieved - even though i can clearly see it in the CS !??!? - mMaxSaleButton->setCaption(mWindowManager.getGameSettingString("sMaxSale", "Max. Sale")); - - mCancelButton->setCaption(MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sCancel")->str); - mOfferButton->setCaption(MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sBarterDialog8")->str); - // adjust size of buttons to fit text int curX = 0; mFilterAll->setSize( mFilterAll->getTextSize().width + 24, mFilterAll->getSize().height ); diff --git a/files/mygui/openmw_chargen_birth_layout.xml b/files/mygui/openmw_chargen_birth_layout.xml index bce3f585dc..0599ab8638 100644 --- a/files/mygui/openmw_chargen_birth_layout.xml +++ b/files/mygui/openmw_chargen_birth_layout.xml @@ -15,7 +15,7 @@ - + diff --git a/files/mygui/openmw_chargen_class_layout.xml b/files/mygui/openmw_chargen_class_layout.xml index bf49810c80..38fa606abe 100644 --- a/files/mygui/openmw_chargen_class_layout.xml +++ b/files/mygui/openmw_chargen_class_layout.xml @@ -55,7 +55,7 @@ - + diff --git a/files/mygui/openmw_chargen_create_class_layout.xml b/files/mygui/openmw_chargen_create_class_layout.xml index 3b7d91b00c..be6a10e0c9 100644 --- a/files/mygui/openmw_chargen_create_class_layout.xml +++ b/files/mygui/openmw_chargen_create_class_layout.xml @@ -56,7 +56,7 @@ - + diff --git a/files/mygui/openmw_chargen_generate_class_result_layout.xml b/files/mygui/openmw_chargen_generate_class_result_layout.xml index 26ebe17e1f..9a6ed4f2ec 100644 --- a/files/mygui/openmw_chargen_generate_class_result_layout.xml +++ b/files/mygui/openmw_chargen_generate_class_result_layout.xml @@ -21,7 +21,7 @@ - + diff --git a/files/mygui/openmw_chargen_race_layout.xml b/files/mygui/openmw_chargen_race_layout.xml index 6887b12c5c..a9b072f5e2 100644 --- a/files/mygui/openmw_chargen_race_layout.xml +++ b/files/mygui/openmw_chargen_race_layout.xml @@ -61,7 +61,7 @@ - + diff --git a/files/mygui/openmw_chargen_review_layout.xml b/files/mygui/openmw_chargen_review_layout.xml index c713eb4772..57bb3b1246 100644 --- a/files/mygui/openmw_chargen_review_layout.xml +++ b/files/mygui/openmw_chargen_review_layout.xml @@ -5,10 +5,18 @@ - - - - + + + + + + + + + + + + @@ -17,9 +25,15 @@ - - - + + + + + + + + + @@ -42,7 +56,7 @@ - + diff --git a/files/mygui/openmw_inventory_window_layout.xml b/files/mygui/openmw_inventory_window_layout.xml index 86ef65324c..b38e15fc79 100644 --- a/files/mygui/openmw_inventory_window_layout.xml +++ b/files/mygui/openmw_inventory_window_layout.xml @@ -7,11 +7,7 @@ - - - - - + diff --git a/files/mygui/openmw_stats_window_layout.xml b/files/mygui/openmw_stats_window_layout.xml index 9406fe6bdd..8b60802272 100644 --- a/files/mygui/openmw_stats_window_layout.xml +++ b/files/mygui/openmw_stats_window_layout.xml @@ -7,9 +7,15 @@ - - - + + + + + + + + + @@ -20,9 +26,15 @@ - - - + + + + + + + + + diff --git a/files/mygui/openmw_trade_window_layout.xml b/files/mygui/openmw_trade_window_layout.xml index 8a4e004333..83d7557d95 100644 --- a/files/mygui/openmw_trade_window_layout.xml +++ b/files/mygui/openmw_trade_window_layout.xml @@ -51,9 +51,15 @@ - - - + + + + + + + + + From 4fb30544d4b101437dc0411c57cc62afd0a9cb02 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 19 May 2012 16:00:00 +0200 Subject: [PATCH 231/325] more gui files cleanup --- apps/openmw/mwgui/container.cpp | 3 --- apps/openmw/mwgui/dialogue.cpp | 1 - apps/openmw/mwgui/hud.cpp | 3 --- apps/openmw/mwgui/map_window.cpp | 5 ----- files/mygui/openmw_container_window_layout.xml | 8 ++++++-- files/mygui/openmw_dialogue_window_layout.xml | 2 +- files/mygui/openmw_hud_layout.xml | 11 +++++++---- files/mygui/openmw_map_window_layout.xml | 4 +++- files/mygui/openmw_trade_window_layout.xml | 2 +- 9 files changed, 18 insertions(+), 21 deletions(-) diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 5595825fcf..be21987ef9 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -603,9 +603,6 @@ ContainerWindow::ContainerWindow(WindowManager& parWindowManager,DragAndDrop* dr mCloseButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ContainerWindow::onCloseButtonClicked); mTakeButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ContainerWindow::onTakeAllButtonClicked); - setText("CloseButton", MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sClose")->str); - setText("TakeButton", MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sTakeAll")->str); - // adjust buttons size to fit text int closeButtonWidth = mCloseButton->getTextSize().width+24; int takeButtonWidth = mTakeButton->getTextSize().width+24; diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 9f5e252fd0..53ab98aeb0 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -69,7 +69,6 @@ DialogueWindow::DialogueWindow(WindowManager& parWindowManager) MyGUI::ButtonPtr byeButton; getWidget(byeButton, "ByeButton"); byeButton->eventMouseButtonClick += MyGUI::newDelegate(this, &DialogueWindow::onByeClicked); - byeButton->setCaption(MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sGoodbye")->str); getWidget(pDispositionBar, "Disposition"); getWidget(pDispositionText,"DispositionText"); diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index 34d5ece98b..4a65458dff 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -77,9 +77,6 @@ HUD::HUD(int width, int height, int fpsLevel, DragAndDrop* dragAndDrop) getWidget(trianglecounter, "TriangleCounter"); getWidget(batchcounter, "BatchCounter"); - compass->setImageTexture("textures\\compass.dds"); - crosshair->setImageTexture("textures\\target.dds"); - // These are just demo values, you should replace these with // real calls from outside the class later. setWeapIcon("icons\\w\\tx_knife_iron.dds"); diff --git a/apps/openmw/mwgui/map_window.cpp b/apps/openmw/mwgui/map_window.cpp index 9000d2fcbf..78ca707988 100644 --- a/apps/openmw/mwgui/map_window.cpp +++ b/apps/openmw/mwgui/map_window.cpp @@ -95,11 +95,6 @@ MapWindow::MapWindow(WindowManager& parWindowManager) : mGlobal(false) { setCoord(500,0,320,300); - setText("WorldButton", "World"); - setImage("Compass", "textures\\compass.dds"); - - // Obviously you should override this later on - setCellName("No Cell Loaded"); getWidget(mLocalMap, "LocalMap"); getWidget(mGlobalMap, "GlobalMap"); diff --git a/files/mygui/openmw_container_window_layout.xml b/files/mygui/openmw_container_window_layout.xml index cb66fadc1f..ae9b0bfdf9 100644 --- a/files/mygui/openmw_container_window_layout.xml +++ b/files/mygui/openmw_container_window_layout.xml @@ -12,8 +12,12 @@ - - + + + + + + diff --git a/files/mygui/openmw_dialogue_window_layout.xml b/files/mygui/openmw_dialogue_window_layout.xml index d45de4bd44..1271a287b6 100644 --- a/files/mygui/openmw_dialogue_window_layout.xml +++ b/files/mygui/openmw_dialogue_window_layout.xml @@ -24,7 +24,7 @@ - + diff --git a/files/mygui/openmw_hud_layout.xml b/files/mygui/openmw_hud_layout.xml index 2dafa72988..0c5ffba6a2 100644 --- a/files/mygui/openmw_hud_layout.xml +++ b/files/mygui/openmw_hud_layout.xml @@ -62,7 +62,10 @@ - + + + + @@ -85,9 +88,9 @@ - - + + + - + + + diff --git a/files/mygui/openmw_trade_window_layout.xml b/files/mygui/openmw_trade_window_layout.xml index 83d7557d95..c8a9f25234 100644 --- a/files/mygui/openmw_trade_window_layout.xml +++ b/files/mygui/openmw_trade_window_layout.xml @@ -58,7 +58,7 @@ - + From 2a4c55f1abd5cd00b62ce920bf954d66dc745fc2 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 19 May 2012 16:04:34 +0200 Subject: [PATCH 232/325] use Class::getInventoryStore instead of casting ContainerStore. --- apps/openmw/mwgui/inventorywindow.cpp | 8 ++++---- apps/openmw/mwgui/tradewindow.cpp | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index a0326debc0..49b441af31 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -142,7 +142,7 @@ namespace MWGui if (mDragAndDrop->mDraggedFrom != this) { // add item to the player's inventory - MWWorld::InventoryStore& invStore = static_cast(MWWorld::Class::get(mContainer).getContainerStore(mContainer)); + MWWorld::ContainerStore& invStore = MWWorld::Class::get(mContainer).getContainerStore(mContainer); MWWorld::ContainerStoreIterator it = invStore.begin(); int origCount = ptr.getRefData().getCount(); @@ -179,7 +179,7 @@ namespace MWGui std::vector InventoryWindow::getEquippedItems() { - MWWorld::InventoryStore& invStore = static_cast(MWWorld::Class::get(mContainer).getContainerStore(mContainer)); + MWWorld::InventoryStore& invStore = MWWorld::Class::get(mContainer).getInventoryStore(mContainer); std::vector items; @@ -197,7 +197,7 @@ namespace MWGui void InventoryWindow::_unequipItem(MWWorld::Ptr item) { - MWWorld::InventoryStore& invStore = static_cast(MWWorld::Class::get(mContainer).getContainerStore(mContainer)); + MWWorld::InventoryStore& invStore = MWWorld::Class::get(mContainer).getInventoryStore(mContainer); for (int slot=0; slot < MWWorld::InventoryStore::Slots; ++slot) { @@ -231,7 +231,7 @@ namespace MWGui int InventoryWindow::getPlayerGold() { - MWWorld::InventoryStore& invStore = static_cast(MWWorld::Class::get(mContainer).getContainerStore(mContainer)); + MWWorld::InventoryStore& invStore = MWWorld::Class::get(mContainer).getInventoryStore(mContainer); for (MWWorld::ContainerStoreIterator it = invStore.begin(); it != invStore.end(); ++it) diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index 3570ea6a39..60cc06cb86 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -268,7 +268,7 @@ namespace MWGui return items; } - MWWorld::InventoryStore& invStore = static_cast(MWWorld::Class::get(mContainer).getContainerStore(mContainer)); + MWWorld::InventoryStore& invStore = MWWorld::Class::get(mContainer).getInventoryStore(mContainer); for (int slot=0; slot < MWWorld::InventoryStore::Slots; ++slot) { @@ -327,7 +327,7 @@ namespace MWGui std::vector TradeWindow::itemsToIgnore() { std::vector items; - MWWorld::InventoryStore& invStore = static_cast(MWWorld::Class::get(mContainer).getContainerStore(mContainer)); + MWWorld::ContainerStore& invStore = MWWorld::Class::get(mContainer).getContainerStore(mContainer); for (MWWorld::ContainerStoreIterator it = invStore.begin(); it != invStore.end(); ++it) From 92d9e070fb6e2cc634f9cde03b807544457a8b37 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 19 May 2012 16:10:13 +0200 Subject: [PATCH 233/325] small tweak to getPlayerGold() method --- apps/openmw/mwgui/inventorywindow.cpp | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 49b441af31..59be6a4959 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -21,6 +21,19 @@ #include "bookwindow.hpp" #include "scrollwindow.hpp" +namespace +{ + std::string toLower (const std::string& name) + { + std::string lowerCase; + + std::transform (name.begin(), name.end(), std::back_inserter (lowerCase), + (int(*)(int)) std::tolower); + + return lowerCase; + } +} + namespace MWGui { @@ -236,7 +249,7 @@ namespace MWGui for (MWWorld::ContainerStoreIterator it = invStore.begin(); it != invStore.end(); ++it) { - if (MWWorld::Class::get(*it).getName(*it) == MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sGold")->str) + if (toLower(it->getCellRef().refID) == "gold_001") return it->getRefData().getCount(); } return 0; From 876b369ca544d8a3321fe6448329e3c089e5b6c7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 19 May 2012 16:28:10 +0200 Subject: [PATCH 234/325] minor tooltip fix --- apps/openmw/mwgui/tooltips.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 6f84345356..e986b59be9 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -298,6 +298,9 @@ IntSize ToolTips::createToolTip(const MWGui::ToolTipInfo& info) const int chargeTextWidth = chargeText->getTextSize().width + 5; const int chargeAndTextWidth = chargeWidth + chargeTextWidth; + + totalSize.width = std::max(totalSize.width, chargeAndTextWidth); + chargeText->setCoord((totalSize.width - chargeAndTextWidth)/2, coord.top+6, chargeTextWidth, 18); IntCoord chargeCoord; From be46f5a59cdb8c2c8220ea25d2b70ef5d05f8629 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 19 May 2012 17:39:24 +0200 Subject: [PATCH 235/325] various fixes --- apps/openmw/mwworld/inventorystore.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index 6981aea02c..98ab1665b4 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -44,13 +44,17 @@ MWWorld::InventoryStore::InventoryStore() : mMagicEffectsUpToDate (false) } MWWorld::InventoryStore::InventoryStore (const InventoryStore& store) -: ContainerStore (store), mMagicEffectsUpToDate (false) +: ContainerStore (store) { + mMagicEffects = store.mMagicEffects; + mMagicEffectsUpToDate = store.mMagicEffectsUpToDate; copySlots (store); } MWWorld::InventoryStore& MWWorld::InventoryStore::operator= (const InventoryStore& store) { + mMagicEffects = store.mMagicEffects; + mMagicEffectsUpToDate = store.mMagicEffectsUpToDate; ContainerStore::operator= (store); mSlots.clear(); copySlots (store); @@ -236,6 +240,7 @@ const MWMechanics::MagicEffects& MWWorld::InventoryStore::getMagicEffects() void MWWorld::InventoryStore::flagAsModified() { + ContainerStore::flagAsModified(); mMagicEffectsUpToDate = false; } From 8d52ee27dcaa8b70841eaa0f127d97afb031b565 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 20 May 2012 22:06:54 +0200 Subject: [PATCH 236/325] attribute tooltips now use a new system that allows complex tooltips to be defined entirely through layout files --- apps/openmw/mwgui/stats_window.cpp | 146 ++++++++++++++++------------- apps/openmw/mwgui/tooltips.cpp | 64 +++++++++++-- files/mygui/openmw_tooltips.xml | 20 ++++ 3 files changed, 160 insertions(+), 70 deletions(-) diff --git a/apps/openmw/mwgui/stats_window.cpp b/apps/openmw/mwgui/stats_window.cpp index 06576b42b6..480b852654 100644 --- a/apps/openmw/mwgui/stats_window.cpp +++ b/apps/openmw/mwgui/stats_window.cpp @@ -459,91 +459,109 @@ void StatsWindow::setupToolTips() const ESMS::ESMStore &store = mWindowManager.getStore(); MyGUI::Widget* widget; + /// \todo move this into the .layout file! + getWidget(widget, "Attrib1"); - widget->setUserString("ToolTipType", "ImageCaptionText"); - widget->setUserString("ToolTipCaption", store.gameSettings.find ("sAttributeStrength")->str); - widget->setUserString("ToolTipText", store.gameSettings.find ("sStrDesc")->str); - widget->setUserString("ToolTipImage", "k\\attribute_strength.dds"); + widget->setUserString("ToolTipType", "Layout"); + widget->setUserString("ToolTipLayout", "AttributeToolTip"); + widget->setUserString("Caption_AttributeName", store.gameSettings.find ("sAttributeStrength")->str); + widget->setUserString("Caption_AttributeDescription", store.gameSettings.find ("sStrDesc")->str); + widget->setUserString("ImageTexture_AttributeImage", "icons\\k\\attribute_strength.dds"); getWidget(widget, "AttribVal1"); - widget->setUserString("ToolTipType", "ImageCaptionText"); - widget->setUserString("ToolTipCaption", store.gameSettings.find ("sAttributeStrength")->str); - widget->setUserString("ToolTipText", store.gameSettings.find ("sStrDesc")->str); - widget->setUserString("ToolTipImage", "k\\attribute_strength.dds"); + widget->setUserString("ToolTipType", "Layout"); + widget->setUserString("ToolTipLayout", "AttributeToolTip"); + widget->setUserString("Caption_AttributeName", store.gameSettings.find ("sAttributeStrength")->str); + widget->setUserString("Caption_AttributeDescription", store.gameSettings.find ("sStrDesc")->str); + widget->setUserString("ImageTexture_AttributeImage", "icons\\k\\attribute_strength.dds"); getWidget(widget, "Attrib2"); - widget->setUserString("ToolTipType", "ImageCaptionText"); - widget->setUserString("ToolTipCaption", store.gameSettings.find ("sAttributeIntelligence")->str); - widget->setUserString("ToolTipText", store.gameSettings.find ("sIntDesc")->str); - widget->setUserString("ToolTipImage", "k\\attribute_int.dds"); + widget->setUserString("ToolTipType", "Layout"); + widget->setUserString("ToolTipLayout", "AttributeToolTip"); + widget->setUserString("Caption_AttributeName", store.gameSettings.find ("sAttributeIntelligence")->str); + widget->setUserString("Caption_AttributeDescription", store.gameSettings.find ("sIntDesc")->str); + widget->setUserString("ImageTexture_AttributeImage", "icons\\k\\attribute_int.dds"); getWidget(widget, "AttribVal2"); - widget->setUserString("ToolTipType", "ImageCaptionText"); - widget->setUserString("ToolTipCaption", store.gameSettings.find ("sAttributeIntelligence")->str); - widget->setUserString("ToolTipText", store.gameSettings.find ("sIntDesc")->str); - widget->setUserString("ToolTipImage", "k\\attribute_int.dds"); + widget->setUserString("ToolTipType", "Layout"); + widget->setUserString("ToolTipLayout", "AttributeToolTip"); + widget->setUserString("Caption_AttributeName", store.gameSettings.find ("sAttributeIntelligence")->str); + widget->setUserString("Caption_AttributeDescription", store.gameSettings.find ("sIntDesc")->str); + widget->setUserString("ImageTexture_AttributeImage", "icons\\k\\attribute_int.dds"); getWidget(widget, "Attrib3"); - widget->setUserString("ToolTipType", "ImageCaptionText"); - widget->setUserString("ToolTipCaption", store.gameSettings.find ("sAttributeWillpower")->str); - widget->setUserString("ToolTipText", store.gameSettings.find ("sWilDesc")->str); - widget->setUserString("ToolTipImage", "k\\attribute_wilpower.dds"); + widget->setUserString("ToolTipType", "Layout"); + widget->setUserString("ToolTipLayout", "AttributeToolTip"); + widget->setUserString("Caption_AttributeName", store.gameSettings.find ("sAttributeWillpower")->str); + widget->setUserString("Caption_AttributeDescription", store.gameSettings.find ("sWilDesc")->str); + widget->setUserString("ImageTexture_AttributeImage", "icons\\k\\attribute_wilpower.dds"); getWidget(widget, "AttribVal3"); - widget->setUserString("ToolTipType", "ImageCaptionText"); - widget->setUserString("ToolTipCaption", store.gameSettings.find ("sAttributeWillpower")->str); - widget->setUserString("ToolTipText", store.gameSettings.find ("sWilDesc")->str); - widget->setUserString("ToolTipImage", "k\\attribute_wilpower.dds"); + widget->setUserString("ToolTipType", "Layout"); + widget->setUserString("ToolTipLayout", "AttributeToolTip"); + widget->setUserString("Caption_AttributeName", store.gameSettings.find ("sAttributeWillpower")->str); + widget->setUserString("Caption_AttributeDescription", store.gameSettings.find ("sWilDesc")->str); + widget->setUserString("ImageTexture_AttributeImage", "icons\\k\\attribute_wilpower.dds"); getWidget(widget, "Attrib4"); - widget->setUserString("ToolTipType", "ImageCaptionText"); - widget->setUserString("ToolTipCaption", store.gameSettings.find ("sAttributeAgility")->str); - widget->setUserString("ToolTipText", store.gameSettings.find ("sAgiDesc")->str); - widget->setUserString("ToolTipImage", "k\\attribute_agility.dds"); + widget->setUserString("ToolTipType", "Layout"); + widget->setUserString("ToolTipLayout", "AttributeToolTip"); + widget->setUserString("Caption_AttributeName", store.gameSettings.find ("sAttributeAgility")->str); + widget->setUserString("Caption_AttributeDescription", store.gameSettings.find ("sAgiDesc")->str); + widget->setUserString("ImageTexture_AttributeImage", "icons\\k\\attribute_agility.dds"); getWidget(widget, "AttribVal4"); - widget->setUserString("ToolTipType", "ImageCaptionText"); - widget->setUserString("ToolTipCaption", store.gameSettings.find ("sAttributeAgility")->str); - widget->setUserString("ToolTipText", store.gameSettings.find ("sAgiDesc")->str); - widget->setUserString("ToolTipImage", "k\\attribute_agility.dds"); + widget->setUserString("ToolTipType", "Layout"); + widget->setUserString("ToolTipLayout", "AttributeToolTip"); + widget->setUserString("Caption_AttributeName", store.gameSettings.find ("sAttributeAgility")->str); + widget->setUserString("Caption_AttributeDescription", store.gameSettings.find ("sAgiDesc")->str); + widget->setUserString("ImageTexture_AttributeImage", "icons\\k\\attribute_agility.dds"); getWidget(widget, "Attrib5"); - widget->setUserString("ToolTipType", "ImageCaptionText"); - widget->setUserString("ToolTipCaption", store.gameSettings.find ("sAttributeSpeed")->str); - widget->setUserString("ToolTipText", store.gameSettings.find ("sSpdDesc")->str); - widget->setUserString("ToolTipImage", "k\\attribute_speed.dds"); + widget->setUserString("ToolTipType", "Layout"); + widget->setUserString("ToolTipLayout", "AttributeToolTip"); + widget->setUserString("Caption_AttributeName", store.gameSettings.find ("sAttributeSpeed")->str); + widget->setUserString("Caption_AttributeDescription", store.gameSettings.find ("sSpdDesc")->str); + widget->setUserString("ImageTexture_AttributeImage", "icons\\k\\attribute_speed.dds"); getWidget(widget, "AttribVal5"); - widget->setUserString("ToolTipType", "ImageCaptionText"); - widget->setUserString("ToolTipCaption", store.gameSettings.find ("sAttributeSpeed")->str); - widget->setUserString("ToolTipText", store.gameSettings.find ("sSpdDesc")->str); - widget->setUserString("ToolTipImage", "k\\attribute_speed.dds"); + widget->setUserString("ToolTipType", "Layout"); + widget->setUserString("ToolTipLayout", "AttributeToolTip"); + widget->setUserString("Caption_AttributeName", store.gameSettings.find ("sAttributeSpeed")->str); + widget->setUserString("Caption_AttributeDescription", store.gameSettings.find ("sSpdDesc")->str); + widget->setUserString("ImageTexture_AttributeImage", "icons\\k\\attribute_speed.dds"); getWidget(widget, "Attrib6"); - widget->setUserString("ToolTipType", "ImageCaptionText"); - widget->setUserString("ToolTipCaption", store.gameSettings.find ("sAttributeEndurance")->str); - widget->setUserString("ToolTipText", store.gameSettings.find ("sEndDesc")->str); - widget->setUserString("ToolTipImage", "k\\attribute_endurance.dds"); + widget->setUserString("ToolTipType", "Layout"); + widget->setUserString("ToolTipLayout", "AttributeToolTip"); + widget->setUserString("Caption_AttributeName", store.gameSettings.find ("sAttributeEndurance")->str); + widget->setUserString("Caption_AttributeDescription", store.gameSettings.find ("sEndDesc")->str); + widget->setUserString("ImageTexture_AttributeImage", "icons\\k\\attribute_endurance.dds"); getWidget(widget, "AttribVal6"); - widget->setUserString("ToolTipType", "ImageCaptionText"); - widget->setUserString("ToolTipCaption", store.gameSettings.find ("sAttributeEndurance")->str); - widget->setUserString("ToolTipText", store.gameSettings.find ("sEndDesc")->str); - widget->setUserString("ToolTipImage", "k\\attribute_endurance.dds"); + widget->setUserString("ToolTipType", "Layout"); + widget->setUserString("ToolTipLayout", "AttributeToolTip"); + widget->setUserString("Caption_AttributeName", store.gameSettings.find ("sAttributeEndurance")->str); + widget->setUserString("Caption_AttributeDescription", store.gameSettings.find ("sEndDesc")->str); + widget->setUserString("ImageTexture_AttributeImage", "icons\\k\\attribute_endurance.dds"); getWidget(widget, "Attrib7"); - widget->setUserString("ToolTipType", "ImageCaptionText"); - widget->setUserString("ToolTipCaption", store.gameSettings.find ("sAttributePersonality")->str); - widget->setUserString("ToolTipText", store.gameSettings.find ("sPerDesc")->str); - widget->setUserString("ToolTipImage", "k\\attribute_personality.dds"); + widget->setUserString("ToolTipType", "Layout"); + widget->setUserString("ToolTipLayout", "AttributeToolTip"); + widget->setUserString("Caption_AttributeName", store.gameSettings.find ("sAttributePersonality")->str); + widget->setUserString("Caption_AttributeDescription", store.gameSettings.find ("sPerDesc")->str); + widget->setUserString("ImageTexture_AttributeImage", "icons\\k\\attribute_personality.dds"); getWidget(widget, "AttribVal7"); - widget->setUserString("ToolTipType", "ImageCaptionText"); - widget->setUserString("ToolTipCaption", store.gameSettings.find ("sAttributePersonality")->str); - widget->setUserString("ToolTipText", store.gameSettings.find ("sPerDesc")->str); - widget->setUserString("ToolTipImage", "k\\attribute_personality.dds"); + widget->setUserString("ToolTipType", "Layout"); + widget->setUserString("ToolTipLayout", "AttributeToolTip"); + widget->setUserString("Caption_AttributeName", store.gameSettings.find ("sAttributePersonality")->str); + widget->setUserString("Caption_AttributeDescription", store.gameSettings.find ("sPerDesc")->str); + widget->setUserString("ImageTexture_AttributeImage", "icons\\k\\attribute_personality.dds"); getWidget(widget, "Attrib8"); - widget->setUserString("ToolTipType", "ImageCaptionText"); - widget->setUserString("ToolTipCaption", store.gameSettings.find ("sAttributeLuck")->str); - widget->setUserString("ToolTipText", store.gameSettings.find ("sLucDesc")->str); - widget->setUserString("ToolTipImage", "k\\attribute_luck.dds"); + widget->setUserString("ToolTipType", "Layout"); + widget->setUserString("ToolTipLayout", "AttributeToolTip"); + widget->setUserString("Caption_AttributeName", store.gameSettings.find ("sAttributeLuck")->str); + widget->setUserString("Caption_AttributeDescription", store.gameSettings.find ("sLucDesc")->str); + widget->setUserString("ImageTexture_AttributeImage", "icons\\k\\attribute_luck.dds"); getWidget(widget, "AttribVal8"); - widget->setUserString("ToolTipType", "ImageCaptionText"); - widget->setUserString("ToolTipCaption", store.gameSettings.find ("sAttributeLuck")->str); - widget->setUserString("ToolTipText", store.gameSettings.find ("sLucDesc")->str); - widget->setUserString("ToolTipImage", "k\\attribute_luck.dds"); + widget->setUserString("ToolTipType", "Layout"); + widget->setUserString("ToolTipLayout", "AttributeToolTip"); + widget->setUserString("Caption_AttributeName", store.gameSettings.find ("sAttributeLuck")->str); + widget->setUserString("Caption_AttributeDescription", store.gameSettings.find ("sLucDesc")->str); + widget->setUserString("ImageTexture_AttributeImage", "icons\\k\\attribute_luck.dds"); } diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index e986b59be9..edb93320d2 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -42,11 +42,16 @@ void ToolTips::onFrame(float frameDuration) IntCoord(0, 0, mMainWidget->getCoord().width, mMainWidget->getCoord().height), Align::Stretch, "DynamicToolTipBox"); + // start by hiding everything + for (unsigned int i=0; i < mMainWidget->getChildCount(); ++i) + { + mMainWidget->getChildAt(i)->setVisible(false); + } + const IntSize &viewSize = RenderManager::getInstance().getViewSize(); if (!mEnabled) { - mDynamicToolTipBox->setVisible(false); return; } @@ -55,7 +60,6 @@ void ToolTips::onFrame(float frameDuration) Widget* focus = InputManager::getInstance().getMouseFocusWidget(); if (focus == 0) { - mDynamicToolTipBox->setVisible(false); return; } @@ -67,7 +71,6 @@ void ToolTips::onFrame(float frameDuration) ToolTipInfo info; if (type == "") { - mDynamicToolTipBox->setVisible(false); return; } else if (type == "Text") @@ -98,6 +101,54 @@ void ToolTips::onFrame(float frameDuration) mFocusObject = *focus->getUserData(); tooltipSize = getToolTipViaPtr(false); } + else if (type == "Layout") + { + // tooltip defined in the layout + MyGUI::Widget* tooltip; + getWidget(tooltip, focus->getUserString("ToolTipLayout")); + + tooltip->setVisible(true); + tooltip->setCoord(0, 0, 300, 300); + + tooltipSize = MyGUI::IntSize(0,0); + + std::map userStrings = focus->getUserStrings(); + for (std::map::iterator it = userStrings.begin(); + it != userStrings.end(); ++it) + { + if (it->first == "ToolTipType" + || it->first == "ToolTipLayout") + continue; + + + size_t underscorePos = it->first.find("_"); + std::string propertyKey = it->first.substr(0, underscorePos); + std::string widgetName = it->first.substr(underscorePos+1, it->first.size()-(underscorePos+1)); + + MyGUI::Widget* w; + getWidget(w, widgetName); + w->setProperty(propertyKey, it->second); + } + + for (unsigned int i=0; igetChildCount(); ++i) + { + MyGUI::Widget* w = tooltip->getChildAt(i); + + if (w->isUserString("AutoResizeHorizontal")) + { + MyGUI::TextBox* text = w->castType(); + tooltipSize.width = std::max(tooltipSize.width, w->getLeft() + text->getTextSize().width + 8); + } + + if (w->isUserString("AutoResizeVertical")) + { + MyGUI::TextBox* text = w->castType(); + tooltipSize.height = std::max(tooltipSize.height, w->getTop() + text->getTextSize().height + 8); + } + } + + tooltip->setCoord(0, 0, tooltipSize.width, tooltipSize.height); + } IntPoint tooltipPosition = InputManager::getInstance().getMousePosition() + IntPoint(0, 24); @@ -112,7 +163,6 @@ void ToolTips::onFrame(float frameDuration) } setCoord(tooltipPosition.left, tooltipPosition.top, tooltipSize.width, tooltipSize.height); - mDynamicToolTipBox->setVisible(true); } else { @@ -124,9 +174,9 @@ void ToolTips::onFrame(float frameDuration) std::max(0, int(mFocusToolTipY*viewSize.height - tooltipSize.height)), tooltipSize.width, tooltipSize.height); + + mDynamicToolTipBox->setVisible(true); } - else - mDynamicToolTipBox->setVisible(false); } } @@ -186,6 +236,8 @@ void ToolTips::findImageExtension(std::string& image) IntSize ToolTips::createToolTip(const MWGui::ToolTipInfo& info) { + mDynamicToolTipBox->setVisible(true); + std::string caption = info.caption; std::string image = info.icon; int imageSize = (image != "") ? 32 : 0; diff --git a/files/mygui/openmw_tooltips.xml b/files/mygui/openmw_tooltips.xml index 2d5a5da9f2..3c6c98ea97 100644 --- a/files/mygui/openmw_tooltips.xml +++ b/files/mygui/openmw_tooltips.xml @@ -8,6 +8,26 @@ + + + + + + + + + + + + + + + + + + + + From 1c7110fbf5022a7f3025866c51ebc91a1957105b Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 20 May 2012 22:45:30 +0200 Subject: [PATCH 237/325] birthsign tooltip --- apps/openmw/mwgui/stats_window.cpp | 61 +++++++++++++++++++++++++++++- apps/openmw/mwgui/stats_window.hpp | 2 +- apps/openmw/mwgui/tooltips.cpp | 4 ++ files/mygui/openmw_text.skin.xml | 3 ++ files/mygui/openmw_tooltips.xml | 18 +++++++++ 5 files changed, 85 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwgui/stats_window.cpp b/apps/openmw/mwgui/stats_window.cpp index 480b852654..092ceaeb64 100644 --- a/apps/openmw/mwgui/stats_window.cpp +++ b/apps/openmw/mwgui/stats_window.cpp @@ -322,7 +322,7 @@ MyGUI::TextBox* StatsWindow::addValueItem(const std::string& text, const std::st return skillValueWidget; } -void StatsWindow::addItem(const std::string text, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) +MyGUI::Widget* StatsWindow::addItem(const std::string text, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) { MyGUI::TextBox* skillNameWidget; @@ -334,6 +334,8 @@ void StatsWindow::addItem(const std::string text, MyGUI::IntCoord &coord1, MyGUI coord1.top += lineHeight; coord2.top += lineHeight; + + return skillNameWidget; } void StatsWindow::addSkills(const SkillList &skills, const std::string &titleId, const std::string &titleDefault, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) @@ -422,7 +424,62 @@ void StatsWindow::updateSkillArea() addGroup(mWindowManager.getGameSettingString("sBirthSign", "Sign"), coord1, coord2); const ESM::BirthSign *sign = store.birthSigns.find(birthSignId); - addItem(sign->name, coord1, coord2); + MyGUI::Widget* w = addItem(sign->name, coord1, coord2); + w->setUserString("ToolTipType", "Layout"); + w->setUserString("ToolTipLayout", "BirthSignToolTip"); + std::string image = sign->texture; + image.replace(image.size()-3, 3, "dds"); + w->setUserString("ImageTexture_BirthSignImage", "textures\\" + image); + std::string text; + + text += sign->name; + text += "\n#BF9959" + sign->description; + + std::vector abilities, powers, spells; + + std::vector::const_iterator it = sign->powers.list.begin(); + std::vector::const_iterator end = sign->powers.list.end(); + for (; it != end; ++it) + { + const std::string &spellId = *it; + const ESM::Spell *spell = store.spells.search(spellId); + if (!spell) + continue; // Skip spells which cannot be found + ESM::Spell::SpellType type = static_cast(spell->data.type); + if (type != ESM::Spell::ST_Spell && type != ESM::Spell::ST_Ability && type != ESM::Spell::ST_Power) + continue; // We only want spell, ability and powers. + + if (type == ESM::Spell::ST_Ability) + abilities.push_back(spellId); + else if (type == ESM::Spell::ST_Power) + powers.push_back(spellId); + else if (type == ESM::Spell::ST_Spell) + spells.push_back(spellId); + } + + struct{ const std::vector &spells; std::string label; } categories[3] = { + {abilities, "sBirthsignmenu1"}, + {powers, "sPowers"}, + {spells, "sBirthsignmenu2"} + }; + + for (int category = 0; category < 3; ++category) + { + for (std::vector::const_iterator it = categories[category].spells.begin(); it != categories[category].spells.end(); ++it) + { + if (it == categories[category].spells.begin()) + { + text += std::string("\n#DDC79E") + std::string("#{") + categories[category].label + "}"; + } + + const std::string &spellId = *it; + + const ESM::Spell *spell = store.spells.search(spellId); + text += "\n#BF9959" + spell->name; + } + } + + w->setUserString("Caption_BirthSignText", text); } // Add a line separator if there are items above diff --git a/apps/openmw/mwgui/stats_window.hpp b/apps/openmw/mwgui/stats_window.hpp index 677b329356..fe7be04598 100644 --- a/apps/openmw/mwgui/stats_window.hpp +++ b/apps/openmw/mwgui/stats_window.hpp @@ -47,7 +47,7 @@ namespace MWGui void addSeparator(MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2); void addGroup(const std::string &label, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2); MyGUI::TextBox* addValueItem(const std::string& text, const std::string& tooltip, const std::string &value, const std::string& state, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2); - void addItem(const std::string text, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2); + MyGUI::Widget* addItem(const std::string text, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2); void updateScroller(); void setupToolTips(); diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index edb93320d2..47907ec945 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -139,12 +139,16 @@ void ToolTips::onFrame(float frameDuration) MyGUI::TextBox* text = w->castType(); tooltipSize.width = std::max(tooltipSize.width, w->getLeft() + text->getTextSize().width + 8); } + else + tooltipSize.width = std::max(tooltipSize.width, w->getLeft() + w->getWidth() + 8); if (w->isUserString("AutoResizeVertical")) { MyGUI::TextBox* text = w->castType(); tooltipSize.height = std::max(tooltipSize.height, w->getTop() + text->getTextSize().height + 8); } + else + tooltipSize.height = std::max(tooltipSize.height, w->getTop() + w->getHeight() + 8); } tooltip->setCoord(0, 0, tooltipSize.width, tooltipSize.height); diff --git a/files/mygui/openmw_text.skin.xml b/files/mygui/openmw_text.skin.xml index 36d97e1538..6b62f618db 100644 --- a/files/mygui/openmw_text.skin.xml +++ b/files/mygui/openmw_text.skin.xml @@ -1,6 +1,8 @@ + + @@ -15,6 +17,7 @@ + diff --git a/files/mygui/openmw_tooltips.xml b/files/mygui/openmw_tooltips.xml index 3c6c98ea97..1913095a8c 100644 --- a/files/mygui/openmw_tooltips.xml +++ b/files/mygui/openmw_tooltips.xml @@ -28,6 +28,24 @@ + + + + + + + + + + + + + + + + + + From 6518eb7794a6e4a7bbe0291c9780e81e0a5b97f2 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 20 May 2012 22:55:14 +0200 Subject: [PATCH 238/325] some cleanup --- apps/openmw/mwgui/stats_window.cpp | 10 ++++++---- apps/openmw/mwgui/tooltips.cpp | 25 ++----------------------- files/mygui/openmw_tooltips.xml | 13 +++++++++++++ 3 files changed, 21 insertions(+), 27 deletions(-) diff --git a/apps/openmw/mwgui/stats_window.cpp b/apps/openmw/mwgui/stats_window.cpp index 092ceaeb64..33d9f02c88 100644 --- a/apps/openmw/mwgui/stats_window.cpp +++ b/apps/openmw/mwgui/stats_window.cpp @@ -302,13 +302,15 @@ MyGUI::TextBox* StatsWindow::addValueItem(const std::string& text, const std::st skillNameWidget = skillClientWidget->createWidget("SandText", coord1, MyGUI::Align::Left | MyGUI::Align::Top | MyGUI::Align::HStretch); skillNameWidget->setCaption(text); - skillNameWidget->setUserString("ToolTipType", "Text"); - skillNameWidget->setUserString("ToolTipText", tooltip); + skillNameWidget->setUserString("ToolTipType", "Layout"); + skillNameWidget->setUserString("ToolTipLayout", "TextToolTip"); + skillNameWidget->setUserString("Caption_Text", tooltip); skillNameWidget->eventMouseWheel += MyGUI::newDelegate(this, &StatsWindow::onMouseWheel); skillValueWidget = skillClientWidget->createWidget("SandTextRight", coord2, MyGUI::Align::Right | MyGUI::Align::Top); - skillValueWidget->setUserString("ToolTipType", "Text"); - skillValueWidget->setUserString("ToolTipText", tooltip); + skillNameWidget->setUserString("ToolTipType", "Layout"); + skillNameWidget->setUserString("ToolTipLayout", "TextToolTip"); + skillNameWidget->setUserString("Caption_Text", tooltip); skillValueWidget->setCaption(value); skillValueWidget->_setWidgetState(state); skillValueWidget->eventMouseWheel += MyGUI::newDelegate(this, &StatsWindow::onMouseWheel); diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 47907ec945..df06bd93ed 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -72,29 +72,6 @@ void ToolTips::onFrame(float frameDuration) if (type == "") { return; - } - else if (type == "Text") - { - info.text = text; - tooltipSize = createToolTip(info); - } - else if (type == "CaptionText") - { - std::string caption = focus->getUserString("ToolTipCaption"); - info.caption = caption; - info.text = text; - tooltipSize = createToolTip(info); - } - else if (type == "ImageCaptionText") - { - std::string caption = focus->getUserString("ToolTipCaption"); - std::string image = focus->getUserString("ToolTipImage"); - std::string sizeString = focus->getUserString("ToolTipImageSize"); - - info.text = text; - info.caption = caption; - info.icon = image; - tooltipSize = createToolTip(info); } else if (type == "ItemPtr") { @@ -153,6 +130,8 @@ void ToolTips::onFrame(float frameDuration) tooltip->setCoord(0, 0, tooltipSize.width, tooltipSize.height); } + else + throw std::runtime_error ("unknown tooltip type"); IntPoint tooltipPosition = InputManager::getInstance().getMousePosition() + IntPoint(0, 24); diff --git a/files/mygui/openmw_tooltips.xml b/files/mygui/openmw_tooltips.xml index 1913095a8c..4149916640 100644 --- a/files/mygui/openmw_tooltips.xml +++ b/files/mygui/openmw_tooltips.xml @@ -8,6 +8,19 @@ + + + + + + + + + + + + + From 8ce472742485c586a04635714bf4205741fdd6cf Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 21 May 2012 01:58:11 +0200 Subject: [PATCH 239/325] skill tooltips --- apps/openmw/mwgui/stats_window.cpp | 48 +++++++++++++++++++++++------- apps/openmw/mwgui/stats_window.hpp | 2 +- apps/openmw/mwgui/tooltips.cpp | 14 ++++++--- components/esm/loadskil.cpp | 29 ++++++++++++++++++ components/esm/loadskil.hpp | 1 + files/mygui/openmw_tooltips.xml | 37 +++++++++++++++++++++++ 6 files changed, 116 insertions(+), 15 deletions(-) diff --git a/apps/openmw/mwgui/stats_window.cpp b/apps/openmw/mwgui/stats_window.cpp index 33d9f02c88..fbc439b238 100644 --- a/apps/openmw/mwgui/stats_window.cpp +++ b/apps/openmw/mwgui/stats_window.cpp @@ -296,21 +296,15 @@ void StatsWindow::addGroup(const std::string &label, MyGUI::IntCoord &coord1, My coord2.top += lineHeight; } -MyGUI::TextBox* StatsWindow::addValueItem(const std::string& text, const std::string& tooltip, const std::string &value, const std::string& state, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) +MyGUI::TextBox* StatsWindow::addValueItem(const std::string& text, const std::string &value, const std::string& state, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) { MyGUI::TextBox *skillNameWidget, *skillValueWidget; skillNameWidget = skillClientWidget->createWidget("SandText", coord1, MyGUI::Align::Left | MyGUI::Align::Top | MyGUI::Align::HStretch); skillNameWidget->setCaption(text); - skillNameWidget->setUserString("ToolTipType", "Layout"); - skillNameWidget->setUserString("ToolTipLayout", "TextToolTip"); - skillNameWidget->setUserString("Caption_Text", tooltip); skillNameWidget->eventMouseWheel += MyGUI::newDelegate(this, &StatsWindow::onMouseWheel); skillValueWidget = skillClientWidget->createWidget("SandTextRight", coord2, MyGUI::Align::Right | MyGUI::Align::Top); - skillNameWidget->setUserString("ToolTipType", "Layout"); - skillNameWidget->setUserString("ToolTipLayout", "TextToolTip"); - skillNameWidget->setUserString("Caption_Text", tooltip); skillValueWidget->setCaption(value); skillValueWidget->_setWidgetState(state); skillValueWidget->eventMouseWheel += MyGUI::newDelegate(this, &StatsWindow::onMouseWheel); @@ -362,13 +356,34 @@ void StatsWindow::addSkills(const SkillList &skills, const std::string &titleId, float base = stat.getBase(); float modified = stat.getModified(); + const ESM::Skill* skill = mWindowManager.getStore().skills.search(skillId); + assert(skill); + + std::string icon = "icons\\k\\" + ESM::Skill::sIconNames[skillId]; + + const ESM::Attribute* attr = mWindowManager.getStore().attributes.search(skill->data.attribute); + assert(attr); + std::string state = "normal"; if (modified > base) state = "increased"; else if (modified < base) state = "decreased"; - MyGUI::TextBox* widget = addValueItem(mWindowManager.getGameSettingString(skillNameId, skillNameId), "", + MyGUI::TextBox* widget = addValueItem(mWindowManager.getGameSettingString(skillNameId, skillNameId), boost::lexical_cast(static_cast(modified)), state, coord1, coord2); + + for (int i=0; i<2; ++i) + { + skillWidgets[skillWidgets.size()-1-i]->setUserString("ToolTipType", "Layout"); + skillWidgets[skillWidgets.size()-1-i]->setUserString("ToolTipLayout", "SkillToolTip"); + skillWidgets[skillWidgets.size()-1-i]->setUserString("Caption_SkillName", "#{"+skillNameId+"}"); + skillWidgets[skillWidgets.size()-1-i]->setUserString("Caption_SkillDescription", skill->description); + skillWidgets[skillWidgets.size()-1-i]->setUserString("Caption_SkillAttribute", "#{sGoverningAttribute}: #{" + attr->name + "}"); + skillWidgets[skillWidgets.size()-1-i]->setUserString("ImageTexture_SkillImage", icon); + skillWidgets[skillWidgets.size()-1-i]->setUserString("Caption_SkillProgressText", "0/100"); + skillWidgets[skillWidgets.size()-1-i]->setUserString("Range_SkillProgress", "100"); + } + skillWidgetMap[skillId] = widget; } } @@ -489,12 +504,25 @@ void StatsWindow::updateSkillArea() addSeparator(coord1, coord2); addValueItem(mWindowManager.getGameSettingString("sReputation", "Reputation"), - mWindowManager.getGameSettingString("sSkillsMenuReputationHelp", ""), boost::lexical_cast(static_cast(reputation)), "normal", coord1, coord2); + + for (int i=0; i<2; ++i) + { + skillWidgets[skillWidgets.size()-1-i]->setUserString("ToolTipType", "Layout"); + skillWidgets[skillWidgets.size()-1-i]->setUserString("ToolTipLayout", "TextToolTip"); + skillWidgets[skillWidgets.size()-1-i]->setUserString("Caption_Text", "#{sSkillsMenuReputationHelp}"); + } + addValueItem(mWindowManager.getGameSettingString("sBounty", "Bounty"), - mWindowManager.getGameSettingString("sCrimeHelp", ""), boost::lexical_cast(static_cast(bounty)), "normal", coord1, coord2); + for (int i=0; i<2; ++i) + { + skillWidgets[skillWidgets.size()-1-i]->setUserString("ToolTipType", "Layout"); + skillWidgets[skillWidgets.size()-1-i]->setUserString("ToolTipLayout", "TextToolTip"); + skillWidgets[skillWidgets.size()-1-i]->setUserString("Caption_Text", "#{sCrimeHelp}"); + } + clientHeight = coord1.top; updateScroller(); } diff --git a/apps/openmw/mwgui/stats_window.hpp b/apps/openmw/mwgui/stats_window.hpp index fe7be04598..50a83bb29e 100644 --- a/apps/openmw/mwgui/stats_window.hpp +++ b/apps/openmw/mwgui/stats_window.hpp @@ -46,7 +46,7 @@ namespace MWGui void addSkills(const SkillList &skills, const std::string &titleId, const std::string &titleDefault, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2); void addSeparator(MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2); void addGroup(const std::string &label, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2); - MyGUI::TextBox* addValueItem(const std::string& text, const std::string& tooltip, const std::string &value, const std::string& state, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2); + MyGUI::TextBox* addValueItem(const std::string& text, const std::string &value, const std::string& state, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2); MyGUI::Widget* addItem(const std::string text, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2); void updateScroller(); diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index df06bd93ed..52ba391a6f 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -87,7 +87,7 @@ void ToolTips::onFrame(float frameDuration) tooltip->setVisible(true); tooltip->setCoord(0, 0, 300, 300); - tooltipSize = MyGUI::IntSize(0,0); + tooltipSize = MyGUI::IntSize(0, tooltip->getSize().height); std::map userStrings = focus->getUserStrings(); for (std::map::iterator it = userStrings.begin(); @@ -122,10 +122,16 @@ void ToolTips::onFrame(float frameDuration) if (w->isUserString("AutoResizeVertical")) { MyGUI::TextBox* text = w->castType(); - tooltipSize.height = std::max(tooltipSize.height, w->getTop() + text->getTextSize().height + 8); + int height = text->getTextSize().height; + if (height > w->getHeight()) + { + tooltipSize += MyGUI::IntSize(0, height - w->getHeight()); + } + if (height < w->getHeight()) + { + tooltipSize -= MyGUI::IntSize(0, w->getHeight() - height); + } } - else - tooltipSize.height = std::max(tooltipSize.height, w->getTop() + w->getHeight() + 8); } tooltip->setCoord(0, 0, tooltipSize.width, tooltipSize.height); diff --git a/components/esm/loadskil.cpp b/components/esm/loadskil.cpp index aa7103efcb..52869f4404 100644 --- a/components/esm/loadskil.cpp +++ b/components/esm/loadskil.cpp @@ -31,6 +31,35 @@ namespace ESM "sSkillSpeechcraft", "sSkillHandtohand", }; + const std::string Skill::sIconNames[Length] = { + "combat_block.dds", + "combat_armor.dds", + "combat_mediumarmor.dds", + "combat_heavyarmor.dds", + "combat_blunt.dds", + "combat_longblade.dds", + "combat_axe.dds", + "combat_spear.dds", + "combat_athletics.dds", + "magic_enchant.dds", + "magic_destruction.dds", + "magic_alteration.dds", + "magic_illusion.dds", + "magic_conjuration.dds", + "magic_mysticism.dds", + "magic_restoration.dds", + "magic_alchemy.dds", + "magic_unarmored.dds", + "stealth_security.dds", + "stealth_sneak.dds", + "stealth_acrobatics.dds", + "stealth_lightarmor.dds", + "stealth_shortblade.dds", + "stealth_marksman.dds", + "stealth_mercantile.dds", + "stealth_speechcraft.dds", + "stealth_handtohand.dds", + }; const boost::array Skill::skillIds = {{ Block, Armorer, diff --git a/components/esm/loadskil.hpp b/components/esm/loadskil.hpp index 836f702051..f56ec2fcb9 100644 --- a/components/esm/loadskil.hpp +++ b/components/esm/loadskil.hpp @@ -64,6 +64,7 @@ struct Skill Length }; static const std::string sSkillNameIds[Length]; + static const std::string sIconNames[Length]; static const boost::array skillIds; void load(ESMReader &esm); diff --git a/files/mygui/openmw_tooltips.xml b/files/mygui/openmw_tooltips.xml index 4149916640..af4d267751 100644 --- a/files/mygui/openmw_tooltips.xml +++ b/files/mygui/openmw_tooltips.xml @@ -41,6 +41,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 4a009fc2bbe625b33de6c9635a831163afc3aa8a Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 21 May 2012 02:58:06 +0200 Subject: [PATCH 240/325] faction tooltip (doesn't handle player having max. rank) --- apps/openmw/mwgui/stats_window.cpp | 44 ++++++++++++++++++++++++++++-- 1 file changed, 42 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/stats_window.cpp b/apps/openmw/mwgui/stats_window.cpp index fbc439b238..de12559ca3 100644 --- a/apps/openmw/mwgui/stats_window.cpp +++ b/apps/openmw/mwgui/stats_window.cpp @@ -428,8 +428,48 @@ void StatsWindow::updateSkillArea() for (FactionList::const_iterator it = mFactions.begin(); it != end; ++it) { const ESM::Faction *faction = store.factions.find(it->first); - addItem(faction->name, coord1, coord2); - // TODO: Faction rank should be placed in tooltip + MyGUI::Widget* w = addItem(faction->name, coord1, coord2); + + std::string text; + + text += std::string("#DDC79E") + faction->name; + text += std::string("\n#BF9959") + faction->ranks[it->second]; + + if (it->second < 10) + { + // player doesn't have max rank yet + text += std::string("\n\n#DDC79E#{sNextRank} ") + faction->ranks[it->second+1]; + + ESM::RankData rankData = faction->data.rankData[it->second+1]; + const ESM::Attribute* attr1 = mWindowManager.getStore().attributes.search(faction->data.attribute1); + const ESM::Attribute* attr2 = mWindowManager.getStore().attributes.search(faction->data.attribute2); + assert(attr1 && attr2); + + text += "\n#BF9959#{" + attr1->name + "}: " + boost::lexical_cast(rankData.attribute1) + + ", #{" + attr2->name + "}: " + boost::lexical_cast(rankData.attribute2); + + text += "\n\n#DDC79E#{sFavoriteSkills}"; + text += "\n#BF9959"; + for (int i=0; i<6; ++i) + { + const ESM::Skill* skill = mWindowManager.getStore().skills.search(faction->data.skillID[i]); + assert(skill); + text += "#{"+ESM::Skill::sSkillNameIds[faction->data.skillID[i]]+"}"; + if (i<5) + text += ", "; + } + + text += "\n"; + + if (rankData.skill1 > 0) + text += "\n#{sNeedOneSkill} " + boost::lexical_cast(rankData.skill1); + if (rankData.skill2 > 0) + text += "\n#{sNeedTwoSkills} " + boost::lexical_cast(rankData.skill2); + } + + w->setUserString("ToolTipType", "Layout"); + w->setUserString("ToolTipLayout", "TextToolTip"); + w->setUserString("Caption_Text", text); } } From 76d71f86bcab17a547c8515d7b40acb7b2a0f43a Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 21 May 2012 03:10:55 +0200 Subject: [PATCH 241/325] fixed a faction case folding issue --- apps/openmw/mwclass/npc.cpp | 8 ++++++-- apps/openmw/mwdialogue/dialoguemanager.cpp | 6 +++--- apps/openmw/mwmechanics/npcstats.hpp | 1 + apps/openmw/mwscript/statsextensions.cpp | 6 ++++++ 4 files changed, 16 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index db0a6460ce..e7f6cc5270 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -3,6 +3,8 @@ #include +#include + #include #include @@ -56,13 +58,15 @@ namespace MWClass // NPC stats if (!ref->base->faction.empty()) { + std::string faction = ref->base->faction; + boost::algorithm::to_lower(faction); if(ref->base->npdt52.gold != -10) { - data->mNpcStats.mFactionRank[ref->base->faction] = (int)ref->base->npdt52.rank; + data->mNpcStats.mFactionRank[faction] = (int)ref->base->npdt52.rank; } else { - data->mNpcStats.mFactionRank[ref->base->faction] = (int)ref->base->npdt12.rank; + data->mNpcStats.mFactionRank[faction] = (int)ref->base->npdt12.rank; } } diff --git a/apps/openmw/mwdialogue/dialoguemanager.cpp b/apps/openmw/mwdialogue/dialoguemanager.cpp index 2c4de7be19..dbd826127c 100644 --- a/apps/openmw/mwdialogue/dialoguemanager.cpp +++ b/apps/openmw/mwdialogue/dialoguemanager.cpp @@ -206,7 +206,7 @@ namespace MWDialogue if(!NPCstats.mFactionRank.empty()) { std::string NPCFaction = NPCstats.mFactionRank.begin()->first; - if(PCstats.mFactionRank.find(NPCFaction) != PCstats.mFactionRank.end()) sameFaction = 1; + if(PCstats.mFactionRank.find(toLower(NPCFaction)) != PCstats.mFactionRank.end()) sameFaction = 1; } if(!selectCompare(comp,sameFaction,select.i)) return false; } @@ -525,7 +525,7 @@ namespace MWDialogue //MWWorld::Class npcClass = MWWorld::Class::get(actor); MWMechanics::NpcStats stats = MWWorld::Class::get(actor).getNpcStats(actor); - std::map::iterator it = stats.mFactionRank.find(info.npcFaction); + std::map::iterator it = stats.mFactionRank.find(toLower(info.npcFaction)); if(it!=stats.mFactionRank.end()) { //check rank @@ -542,7 +542,7 @@ namespace MWDialogue if(!info.pcFaction.empty()) { MWMechanics::NpcStats stats = MWWorld::Class::get(MWBase::Environment::get().getWorld()->getPlayer().getPlayer()).getNpcStats(MWBase::Environment::get().getWorld()->getPlayer().getPlayer()); - std::map::iterator it = stats.mFactionRank.find(info.pcFaction); + std::map::iterator it = stats.mFactionRank.find(toLower(info.pcFaction)); if(it!=stats.mFactionRank.end()) { //check rank diff --git a/apps/openmw/mwmechanics/npcstats.hpp b/apps/openmw/mwmechanics/npcstats.hpp index feac5d4d3c..972863b728 100644 --- a/apps/openmw/mwmechanics/npcstats.hpp +++ b/apps/openmw/mwmechanics/npcstats.hpp @@ -20,6 +20,7 @@ namespace MWMechanics { // NPCs other than the player can only have one faction. But for the sake of consistency // we use the same data structure for the PC and the NPCs. + /// \note the faction key must be in lowercase std::map mFactionRank; Stat mSkill[27]; diff --git a/apps/openmw/mwscript/statsextensions.cpp b/apps/openmw/mwscript/statsextensions.cpp index cad52e5930..d235192817 100644 --- a/apps/openmw/mwscript/statsextensions.cpp +++ b/apps/openmw/mwscript/statsextensions.cpp @@ -1,6 +1,8 @@ #include "statsextensions.hpp" +#include + #include #include @@ -362,6 +364,7 @@ namespace MWScript factionID = runtime.getStringLiteral (runtime[0].mInteger); runtime.pop(); } + boost::algorithm::to_lower(factionID); if(factionID != "") { MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); @@ -390,6 +393,7 @@ namespace MWScript factionID = runtime.getStringLiteral (runtime[0].mInteger); runtime.pop(); } + boost::algorithm::to_lower(factionID); if(factionID != "") { MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); @@ -422,6 +426,7 @@ namespace MWScript factionID = runtime.getStringLiteral (runtime[0].mInteger); runtime.pop(); } + boost::algorithm::to_lower(factionID); if(factionID != "") { MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); @@ -459,6 +464,7 @@ namespace MWScript factionID = MWWorld::Class::get(ptr).getNpcStats(ptr).mFactionRank.begin()->first; } } + boost::algorithm::to_lower(factionID); MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); if(factionID!="") { From 1079bb26778afcf454b7aa0f01e0edee6574e53b Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 21 May 2012 05:14:07 +0200 Subject: [PATCH 242/325] finished tooltips for everything in the stats window, some gui refactoring --- apps/openmw/mwgui/hud.cpp | 18 ++--- apps/openmw/mwgui/hud.hpp | 1 - apps/openmw/mwgui/stats_window.cpp | 52 +++++++++++++ apps/openmw/mwgui/tooltips.cpp | 12 ++- files/mygui/openmw_hud_layout.xml | 30 ++++++-- files/mygui/openmw_stats_window_layout.xml | 88 ++++++++++++++++++---- files/mygui/openmw_tooltips.xml | 79 ++++++++++++++++++- 7 files changed, 242 insertions(+), 38 deletions(-) diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index 4a65458dff..892bd6c7aa 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -129,16 +129,6 @@ void HUD::setBatchCount(size_t count) batchcounter->setCaption(boost::lexical_cast(count)); } -void HUD::setStats(int h, int hmax, int m, int mmax, int s, int smax) -{ - health->setProgressRange(hmax); - health->setProgressPosition(h); - magicka->setProgressRange(mmax); - magicka->setProgressPosition(m); - stamina->setProgressRange(smax); - stamina->setProgressPosition(s); -} - void HUD::setWeapIcon(const char *str) { weapImage->setImageTexture(str); @@ -176,19 +166,27 @@ void HUD::setValue(const std::string& id, const MWMechanics::DynamicStat& v for (int i=0; ids[i]; ++i) if (ids[i]==id) { + MyGUI::Widget* w; + std::string valStr = boost::lexical_cast(value.getCurrent()) + "/" + boost::lexical_cast(value.getModified()); switch (i) { case 0: health->setProgressRange (value.getModified()); health->setProgressPosition (value.getCurrent()); + getWidget(w, "HealthFrame"); + w->setUserString("Caption_HealthDescription", "#{sHealthDesc}\n" + valStr); break; case 1: magicka->setProgressRange (value.getModified()); magicka->setProgressPosition (value.getCurrent()); + getWidget(w, "MagickaFrame"); + w->setUserString("Caption_HealthDescription", "#{sIntDesc}\n" + valStr); break; case 2: stamina->setProgressRange (value.getModified()); stamina->setProgressPosition (value.getCurrent()); + getWidget(w, "FatigueFrame"); + w->setUserString("Caption_HealthDescription", "#{sFatDesc}\n" + valStr); break; } } diff --git a/apps/openmw/mwgui/hud.hpp b/apps/openmw/mwgui/hud.hpp index d588113dd1..81f64ee504 100644 --- a/apps/openmw/mwgui/hud.hpp +++ b/apps/openmw/mwgui/hud.hpp @@ -12,7 +12,6 @@ namespace MWGui { public: HUD(int width, int height, int fpsLevel, DragAndDrop* dragAndDrop); - void setStats(int h, int hmax, int m, int mmax, int s, int smax); void setWeapIcon(const char *str); void setSpellIcon(const char *str); void setWeapStatus(int s, int smax); diff --git a/apps/openmw/mwgui/stats_window.cpp b/apps/openmw/mwgui/stats_window.cpp index de12559ca3..eba51c26fd 100644 --- a/apps/openmw/mwgui/stats_window.cpp +++ b/apps/openmw/mwgui/stats_window.cpp @@ -172,11 +172,32 @@ void StatsWindow::setValue (const std::string& id, const MWMechanics::DynamicSta }; for (int i=0; ids[i]; ++i) + { if (ids[i]==id) { std::string id (ids[i]); setBar (id, id + "T", value.getCurrent(), value.getModified()); + + // health, magicka, fatigue tooltip + MyGUI::Widget* w; + std::string valStr = boost::lexical_cast(value.getCurrent()) + "/" + boost::lexical_cast(value.getModified()); + if (i==0) + { + getWidget(w, "Health"); + w->setUserString("Caption_HealthDescription", "#{sHealthDesc}\n" + valStr); + } + else if (i==1) + { + getWidget(w, "Magicka"); + w->setUserString("Caption_HealthDescription", "#{sIntDesc}\n" + valStr); + } + else if (i==2) + { + getWidget(w, "Fatigue"); + w->setUserString("Caption_HealthDescription", "#{sFatDesc}\n" + valStr); + } } + } } void StatsWindow::setValue (const std::string& id, const std::string& value) @@ -417,6 +438,37 @@ void StatsWindow::updateSkillArea() const ESMS::ESMStore &store = mWindowManager.getStore(); + // race tooltip + const ESM::Race* playerRace = store.races.find (MWBase::Environment::get().getWorld()->getPlayer().getRace()); + MyGUI::Widget* raceWidget; + getWidget(raceWidget, "RaceText"); + raceWidget->setUserString("Caption_CenteredCaption", playerRace->name); + raceWidget->setUserString("Caption_CenteredCaptionText", playerRace->description); + getWidget(raceWidget, "Race_str"); + raceWidget->setUserString("Caption_CenteredCaption", playerRace->name); + raceWidget->setUserString("Caption_CenteredCaptionText", playerRace->description); + + // class tooltip + MyGUI::Widget* classWidget; + const ESM::Class& playerClass = MWBase::Environment::get().getWorld()->getPlayer().getClass(); + int spec = playerClass.data.specialization; + std::string specStr; + if (spec == 0) + specStr = "#{sSpecializationCombat}"; + else if (spec == 1) + specStr = "#{sSpecializationMagic}"; + else if (spec == 2) + specStr = "#{sSpecializationStealth}"; + + getWidget(classWidget, "ClassText"); + classWidget->setUserString("Caption_ClassName", playerClass.name); + classWidget->setUserString("Caption_ClassDescription", playerClass.description); + classWidget->setUserString("Caption_ClassSpecialisation", "#{sSpecialization}: " + specStr); + getWidget(classWidget, "Class_str"); + classWidget->setUserString("Caption_ClassName", playerClass.name); + classWidget->setUserString("Caption_ClassDescription", playerClass.description); + classWidget->setUserString("Caption_ClassSpecialisation", "#{sSpecialization}: " + specStr); + if (!mFactions.empty()) { // Add a line separator if there are items above diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 52ba391a6f..3ade598baa 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -85,9 +85,14 @@ void ToolTips::onFrame(float frameDuration) getWidget(tooltip, focus->getUserString("ToolTipLayout")); tooltip->setVisible(true); - tooltip->setCoord(0, 0, 300, 300); + if (!tooltip->isUserString("DontResize")) + { + tooltip->setCoord(0, 0, 450, 300); // this is the maximum width of the tooltip before it starts word-wrapping - tooltipSize = MyGUI::IntSize(0, tooltip->getSize().height); + tooltipSize = MyGUI::IntSize(0, tooltip->getSize().height); + } + else + tooltipSize = tooltip->getSize(); std::map userStrings = focus->getUserStrings(); for (std::map::iterator it = userStrings.begin(); @@ -116,7 +121,7 @@ void ToolTips::onFrame(float frameDuration) MyGUI::TextBox* text = w->castType(); tooltipSize.width = std::max(tooltipSize.width, w->getLeft() + text->getTextSize().width + 8); } - else + else if (!tooltip->isUserString("DontResize")) tooltipSize.width = std::max(tooltipSize.width, w->getLeft() + w->getWidth() + 8); if (w->isUserString("AutoResizeVertical")) @@ -133,7 +138,6 @@ void ToolTips::onFrame(float frameDuration) } } } - tooltip->setCoord(0, 0, tooltipSize.width, tooltipSize.height); } else diff --git a/files/mygui/openmw_hud_layout.xml b/files/mygui/openmw_hud_layout.xml index 0c5ffba6a2..0aabc3e3ee 100644 --- a/files/mygui/openmw_hud_layout.xml +++ b/files/mygui/openmw_hud_layout.xml @@ -3,12 +3,30 @@ - - - + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/mygui/openmw_stats_window_layout.xml b/files/mygui/openmw_stats_window_layout.xml index 8b60802272..4729e3bca8 100644 --- a/files/mygui/openmw_stats_window_layout.xml +++ b/files/mygui/openmw_stats_window_layout.xml @@ -7,37 +7,95 @@ - - + + + + + + + + + + + + + + + + - - + + + + + + + + + + + + + + + + + + + + - - + + + + + + + + + + + + + + + + + + + - - - - - - + + + + + + + + + + + + + + + + + + - - - diff --git a/files/mygui/openmw_tooltips.xml b/files/mygui/openmw_tooltips.xml index af4d267751..a1673d3462 100644 --- a/files/mygui/openmw_tooltips.xml +++ b/files/mygui/openmw_tooltips.xml @@ -21,6 +21,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -78,6 +134,27 @@ + + + + + + + + + + + + + + + + + + + + + @@ -88,8 +165,6 @@ - - From 40c52c5d09eb9e16c2bdc371e4bfb26ac8a91793 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 21 May 2012 05:19:20 +0200 Subject: [PATCH 243/325] max faction rank crashfix --- apps/openmw/mwgui/stats_window.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/stats_window.cpp b/apps/openmw/mwgui/stats_window.cpp index eba51c26fd..1dd82cf6ab 100644 --- a/apps/openmw/mwgui/stats_window.cpp +++ b/apps/openmw/mwgui/stats_window.cpp @@ -487,7 +487,7 @@ void StatsWindow::updateSkillArea() text += std::string("#DDC79E") + faction->name; text += std::string("\n#BF9959") + faction->ranks[it->second]; - if (it->second < 10) + if (it->second < 9) { // player doesn't have max rank yet text += std::string("\n\n#DDC79E#{sNextRank} ") + faction->ranks[it->second+1]; From b2d207130d88d17f4b944b44c9e9609092bcf778 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 21 May 2012 08:14:22 +0200 Subject: [PATCH 244/325] vastly improved look of the GUI, skin background textures now use tiling instead of stretching --- files/mygui/openmw_box.skin.xml | 32 ++++++++--- files/mygui/openmw_button.skin.xml | 32 ++++++++--- files/mygui/openmw_hud_box.skin.xml | 36 ++++++++++--- files/mygui/openmw_list.skin.xml | 25 +++++++-- files/mygui/openmw_windows.skin.xml | 82 ++++++++++++++++++++--------- 5 files changed, 156 insertions(+), 51 deletions(-) diff --git a/files/mygui/openmw_box.skin.xml b/files/mygui/openmw_box.skin.xml index c1952794c1..2a54edd60b 100644 --- a/files/mygui/openmw_box.skin.xml +++ b/files/mygui/openmw_box.skin.xml @@ -6,23 +6,39 @@ as around the sections of the stats window, or around popup info windows --> - - + + + + + + - - + + + + + + - - + + + + + + - - + + + + + + diff --git a/files/mygui/openmw_button.skin.xml b/files/mygui/openmw_button.skin.xml index 9efcf776f8..491b3f47b7 100644 --- a/files/mygui/openmw_button.skin.xml +++ b/files/mygui/openmw_button.skin.xml @@ -3,23 +3,39 @@ - - + + + + + + - - + + + + + + - - + + + + + + - - + + + + + + diff --git a/files/mygui/openmw_hud_box.skin.xml b/files/mygui/openmw_hud_box.skin.xml index bf1b0056a0..86b63fcf6e 100644 --- a/files/mygui/openmw_hud_box.skin.xml +++ b/files/mygui/openmw_hud_box.skin.xml @@ -3,18 +3,38 @@ - - + + + + + + - - + + + + + + + - - + + + + + + + - - + + + + + + + + diff --git a/files/mygui/openmw_list.skin.xml b/files/mygui/openmw_list.skin.xml index 213e8470f5..e1fbc49b63 100644 --- a/files/mygui/openmw_list.skin.xml +++ b/files/mygui/openmw_list.skin.xml @@ -6,13 +6,32 @@ - - + + + + + + + + + + + + + + + + + + + + + @@ -144,7 +163,7 @@ - + diff --git a/files/mygui/openmw_windows.skin.xml b/files/mygui/openmw_windows.skin.xml index 7c194ea5d0..b379f84ced 100644 --- a/files/mygui/openmw_windows.skin.xml +++ b/files/mygui/openmw_windows.skin.xml @@ -17,14 +17,22 @@ - - + + + + + + - - + + + + + + @@ -66,29 +74,45 @@ - - + + + + + + - - + + + + + + - - + + + + + + - - + + + + + + @@ -120,20 +144,32 @@ - - + + + + + + - - + + + + + + - - + + + + + + @@ -171,12 +207,8 @@ - - - - - - + + @@ -218,6 +250,7 @@ + @@ -294,6 +327,7 @@ + From 789dfe1c8865e24f1b398735521f3d48e83e0631 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 21 May 2012 09:50:02 +0200 Subject: [PATCH 245/325] fix a bug with water reflection plane height --- apps/openmw/mwrender/water.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index c81f23f548..840b94e41e 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -155,10 +155,10 @@ void Water::changeCell(const ESM::Cell* cell) { mTop = cell->water; + setHeight(mTop); + if(!(cell->data.flags & cell->Interior)) mWaterNode->setPosition(getSceneNodeCoordinates(cell->data.gridX, cell->data.gridY)); - else - setHeight(mTop); } void Water::setHeight(const float height) From 5f6e8224f44ef47e69f71fd363532a1733755c5b Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 21 May 2012 10:48:25 +0200 Subject: [PATCH 246/325] skill progress --- apps/openmw/mwgui/stats_window.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/stats_window.cpp b/apps/openmw/mwgui/stats_window.cpp index 1dd82cf6ab..cdf6a58718 100644 --- a/apps/openmw/mwgui/stats_window.cpp +++ b/apps/openmw/mwgui/stats_window.cpp @@ -376,6 +376,7 @@ void StatsWindow::addSkills(const SkillList &skills, const std::string &titleId, const MWMechanics::Stat &stat = skillValues.find(skillId)->second; float base = stat.getBase(); float modified = stat.getModified(); + int progressPercent = (modified - float(static_cast(modified))) * 100; const ESM::Skill* skill = mWindowManager.getStore().skills.search(skillId); assert(skill); @@ -401,8 +402,9 @@ void StatsWindow::addSkills(const SkillList &skills, const std::string &titleId, skillWidgets[skillWidgets.size()-1-i]->setUserString("Caption_SkillDescription", skill->description); skillWidgets[skillWidgets.size()-1-i]->setUserString("Caption_SkillAttribute", "#{sGoverningAttribute}: #{" + attr->name + "}"); skillWidgets[skillWidgets.size()-1-i]->setUserString("ImageTexture_SkillImage", icon); - skillWidgets[skillWidgets.size()-1-i]->setUserString("Caption_SkillProgressText", "0/100"); + skillWidgets[skillWidgets.size()-1-i]->setUserString("Caption_SkillProgressText", boost::lexical_cast(progressPercent)+"/100"); skillWidgets[skillWidgets.size()-1-i]->setUserString("Range_SkillProgress", "100"); + skillWidgets[skillWidgets.size()-1-i]->setUserString("RangePosition_SkillProgress", boost::lexical_cast(progressPercent)); } skillWidgetMap[skillId] = widget; From 157dd81524cd83c820d640f25e6439aa16bbec7c Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 21 May 2012 10:57:49 +0200 Subject: [PATCH 247/325] removed script instruction, will be in the settings window later --- apps/openmw/mwscript/docs/vmformat.txt | 1 - apps/openmw/mwscript/miscextensions.cpp | 18 ------------------ 2 files changed, 19 deletions(-) diff --git a/apps/openmw/mwscript/docs/vmformat.txt b/apps/openmw/mwscript/docs/vmformat.txt index 06e9a0ca73..de7248c0c2 100644 --- a/apps/openmw/mwscript/docs/vmformat.txt +++ b/apps/openmw/mwscript/docs/vmformat.txt @@ -146,5 +146,4 @@ op 0x200014f: ForceGreeting op 0x2000150: ForceGreeting, explicit reference op 0x2000151: ToggleFullHelp op 0x2000152: Goodbye -op 0x2000153: ToggleCompositors opcodes 0x2000154-0x3ffffff unused diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index 1467b0aeb4..fe1a642fd6 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -194,22 +194,6 @@ namespace MWScript } }; - class OpToggleCompositors : public Interpreter::Opcode0 - { - public: - - virtual void execute (Interpreter::Runtime& runtime) - { - InterpreterContext& context = - static_cast (runtime.getContext()); - - bool enabled = MWBase::Environment::get().getWorld()->toggleRenderMode(MWWorld::World::Render_Compositors); - - context.report (enabled ? - "Compositors -> On" : "Compositors -> Off"); - } - }; - const int opcodeXBox = 0x200000c; const int opcodeOnActivate = 0x200000d; const int opcodeActivate = 0x2000075; @@ -224,7 +208,6 @@ namespace MWScript const int opcodeFadeTo = 0x200013e; const int opcodeToggleWater = 0x2000144; const int opcodeTogglePathgrid = 0x2000146; - const int opcodeToggleCompositors = 0x2000153; void registerExtensions (Compiler::Extensions& extensions) { @@ -246,7 +229,6 @@ namespace MWScript extensions.registerInstruction ("twa", "", opcodeToggleWater); extensions.registerInstruction ("togglepathgrid", "", opcodeTogglePathgrid); extensions.registerInstruction ("tpg", "", opcodeTogglePathgrid); - extensions.registerInstruction ("togglecompositors", "", opcodeToggleCompositors); } void installOpcodes (Interpreter::Interpreter& interpreter) From bda90b77bcbd89c7348b88af504315892755a211 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 21 May 2012 10:59:06 +0200 Subject: [PATCH 248/325] oops, forgot something --- apps/openmw/mwscript/miscextensions.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index fe1a642fd6..4ba523937c 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -247,7 +247,6 @@ namespace MWScript interpreter.installSegment5 (opcodeFadeTo, new OpFadeTo); interpreter.installSegment5 (opcodeTogglePathgrid, new OpTogglePathgrid); interpreter.installSegment5 (opcodeToggleWater, new OpToggleWater); - interpreter.installSegment5 (opcodeToggleCompositors, new OpToggleCompositors); } } } From 3673cd2531743e8ece156644c842eec9af46a5c9 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 21 May 2012 12:41:15 +0200 Subject: [PATCH 249/325] increased version number --- CMakeLists.txt | 2 +- readme.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 668fcd83aa..e11ad0c0ab 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,7 +15,7 @@ include (OpenMWMacros) # Version set (OPENMW_VERSION_MAJOR 0) -set (OPENMW_VERSION_MINOR 14) +set (OPENMW_VERSION_MINOR 15) set (OPENMW_VERSION_RELEASE 0) set (OPENMW_VERSION "${OPENMW_VERSION_MAJOR}.${OPENMW_VERSION_MINOR}.${OPENMW_VERSION_RELEASE}") diff --git a/readme.txt b/readme.txt index 53f4a4c59e..08e937010b 100644 --- a/readme.txt +++ b/readme.txt @@ -3,7 +3,7 @@ OpenMW: A reimplementation of The Elder Scrolls III: Morrowind OpenMW is an attempt at recreating the engine for the popular role-playing game Morrowind by Bethesda Softworks. You need to own and install the original game for OpenMW to work. -Version: 0.14.0 +Version: 0.15.0 License: GPL (see GPL3.txt for more information) Website: http://www.openmw.org From 7aad0cc069daa098edb63461b7937d57b7d45a0f Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 21 May 2012 12:44:57 +0200 Subject: [PATCH 250/325] updated readme file --- readme.txt | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/readme.txt b/readme.txt index 08e937010b..a8a312e625 100644 --- a/readme.txt +++ b/readme.txt @@ -132,6 +132,31 @@ Thanks to Kevin Ryan for kindly providing us with the icon used for the Data Fil CHANGELOG +0.15.0 + +Bug #5: Physics reimplementation (fixes various issues) +Bug #258: Resizing arrow's background is not transparent +Bug #268: Widening the stats window in X direction causes layout problems +Bug #269: Topic pane in dialgoue window is too small for some longer topics +Bug #271: Dialog choices are sorted incorrectly +Bug #281: The single quote character is not rendered on dialog windows +Bug #285: Terrain not handled properly in cells that are not predefined +Bug #289: Dialogue filter isn't doing case smashing/folding for item IDs +Feature #15: Collision with Terrain +Feature #17: Inventory-, Container- and Trade-Windows +Feature #44: Floating Labels above Focussed Objects +Feature #80: Tooltips +Feature #90: Book and Scroll Windows +Feature #156: Item Stacking in Containers +Feature #213: Pulsating lights +Feature #218: Feather & Burden +Feature #256: Implement magic effect bookkeeping +Feature #259: Add missing information to Stats window +Feature #260: Correct case for dialogue topics +Feature #280: GUI texture atlasing +Feature #291: Ability to use GMST strings from GUI layout files +Task #255: Make MWWorld::Environment into a singleton + 0.14.0 Bug #1: Meshes rendered with wrong orientation From b494533bb2c343fca3083fce34482ecd83f16631 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 21 May 2012 12:54:23 +0200 Subject: [PATCH 251/325] another change to the readme file --- readme.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/readme.txt b/readme.txt index a8a312e625..513474dd64 100644 --- a/readme.txt +++ b/readme.txt @@ -146,6 +146,7 @@ Feature #15: Collision with Terrain Feature #17: Inventory-, Container- and Trade-Windows Feature #44: Floating Labels above Focussed Objects Feature #80: Tooltips +Feature #83: Barter Dialogue Feature #90: Book and Scroll Windows Feature #156: Item Stacking in Containers Feature #213: Pulsating lights From 343bbaf0fd9a5cce41d8a027b22f65b6e5567f3e Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 22 May 2012 03:36:03 +0200 Subject: [PATCH 252/325] integrated video settings in the settings file, the launcher is now useless --- apps/openmw/engine.cpp | 34 ++-- components/files/configurationmanager.cpp | 7 - components/files/configurationmanager.hpp | 2 - files/settings-default.cfg | 23 +++ libs/openengine/ogre/renderer.cpp | 129 ++++++------ libs/openengine/ogre/renderer.hpp | 233 +++++++++++----------- 6 files changed, 216 insertions(+), 212 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 85b0557b1a..a180849ff1 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -268,15 +268,6 @@ void OMW::Engine::go() mOgre = new OEngine::Render::OgreRenderer; - //we need to ensure the path to the configuration exists before creating an - //instance of ogre root so that Ogre doesn't raise an exception when trying to - //access it - const boost::filesystem::path configPath = mCfgMgr.getOgreConfigPath().parent_path(); - if ( !boost::filesystem::exists(configPath) ) - { - boost::filesystem::create_directories(configPath); - } - // Create the settings manager and load default settings file Settings::Manager settings; const std::string localdefault = mCfgMgr.getLocalPath().string() + "/settings-default.cfg"; @@ -308,10 +299,20 @@ void OMW::Engine::go() else if (boost::filesystem::exists(mCfgMgr.getGlobalPath().string() + "/transparency-overrides.cfg")) nifOverrides.loadTransparencyOverrides(mCfgMgr.getGlobalPath().string() + "/transparency-overrides.cfg"); - mOgre->configure(!boost::filesystem::is_regular_file(mCfgMgr.getOgreConfigPath()), - mCfgMgr.getOgreConfigPath().string(), + std::string renderSystem = settings.getString("render system", "Video"); + if (renderSystem == "") + { +#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32 + renderSystem = "Direct3D9 Rendering Subsystem"; +#else + renderSystem = "OpenGL Rendering Subsystem"; +#endif + } + mOgre->configure( mCfgMgr.getLogPath().string(), - mCfgMgr.getPluginsConfigPath().string(), false); + mCfgMgr.getPluginsConfigPath().string(), + renderSystem, + false); // This has to be added BEFORE MyGUI is initialized, as it needs // to find core.xml here. @@ -325,7 +326,14 @@ void OMW::Engine::go() addZipResource(mResDir / "mygui" / "Obliviontt.zip"); // Create the window - mOgre->createWindow("OpenMW"); + OEngine::Render::WindowSettings windowSettings; + windowSettings.fullscreen = settings.getBool("fullscreen", "Video"); + windowSettings.window_x = settings.getInt("resolution x", "Video"); + windowSettings.window_y = settings.getInt("resolution y", "Video"); + windowSettings.vsync = settings.getBool("vsync", "Video"); + std::string aa = settings.getString("antialiasing", "Video"); + windowSettings.fsaa = (aa.substr(0, 4) == "MSAA") ? aa.substr(5, aa.size()-5) : "0"; + mOgre->createWindow("OpenMW", windowSettings); loadBSA(); diff --git a/components/files/configurationmanager.cpp b/components/files/configurationmanager.cpp index d5f322ebd4..150a4fcd88 100644 --- a/components/files/configurationmanager.cpp +++ b/components/files/configurationmanager.cpp @@ -15,7 +15,6 @@ namespace Files { static const char* const openmwCfgFile = "openmw.cfg"; -static const char* const ogreCfgFile = "ogre.cfg"; static const char* const pluginsCfgFile = "plugins.cfg"; const char* const mwToken = "?mw?"; @@ -39,7 +38,6 @@ ConfigurationManager::ConfigurationManager() } } - mOgreCfgPath = mFixedPath.getUserPath() / ogreCfgFile; mLogPath = mFixedPath.getUserPath(); } @@ -164,11 +162,6 @@ const boost::filesystem::path& ConfigurationManager::getInstallPath() const return mFixedPath.getInstallPath(); } -const boost::filesystem::path& ConfigurationManager::getOgreConfigPath() const -{ - return mOgreCfgPath; -} - const boost::filesystem::path& ConfigurationManager::getPluginsConfigPath() const { return mPluginsCfgPath; diff --git a/components/files/configurationmanager.hpp b/components/files/configurationmanager.hpp index 7fb3793c64..af9d02b912 100644 --- a/components/files/configurationmanager.hpp +++ b/components/files/configurationmanager.hpp @@ -41,7 +41,6 @@ struct ConfigurationManager const boost::filesystem::path& getLocalDataPath() const; const boost::filesystem::path& getInstallPath() const; - const boost::filesystem::path& getOgreConfigPath() const; const boost::filesystem::path& getPluginsConfigPath() const; const boost::filesystem::path& getLogPath() const; @@ -59,7 +58,6 @@ struct ConfigurationManager FixedPathType mFixedPath; - boost::filesystem::path mOgreCfgPath; boost::filesystem::path mPluginsCfgPath; boost::filesystem::path mLogPath; diff --git a/files/settings-default.cfg b/files/settings-default.cfg index e4a0c020a5..81df50fb6f 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -1,6 +1,29 @@ # WARNING: Editing this file might have no effect, as these # settings are overwritten by your user settings file. +[Video] +resolution x = 800 +resolution y = 600 + +fullscreen = false + +# Render system +# blank means default +# Valid values: +# OpenGL Rendering Subsystem +# Direct3D9 Rendering Subsystem +render system = + +# Valid values: +# none +# MSAA 2 +# MSAA 4 +# MSAA 8 +# MSAA 16 +antialiasing = none + +vsync = false + [General] # Camera field of view field of view = 55 diff --git a/libs/openengine/ogre/renderer.cpp b/libs/openengine/ogre/renderer.cpp index 4ded3343f5..4c8a10c3f4 100644 --- a/libs/openengine/ogre/renderer.cpp +++ b/libs/openengine/ogre/renderer.cpp @@ -13,17 +13,17 @@ using namespace OEngine::Render; void OgreRenderer::cleanup() { - if (mFader) - delete mFader; - - if(mRoot) - delete mRoot; - mRoot = NULL; + if (mFader) + delete mFader; + + if(mRoot) + delete mRoot; + mRoot = NULL; } void OgreRenderer::start() { - mRoot->startRendering(); + mRoot->startRendering(); } bool OgreRenderer::loadPlugins() @@ -53,96 +53,79 @@ bool OgreRenderer::loadPlugins() void OgreRenderer::update(float dt) { - mFader->update(dt); + mFader->update(dt); } void OgreRenderer::screenshot(const std::string &file) { - mWindow->writeContentsToFile(file); + mWindow->writeContentsToFile(file); } float OgreRenderer::getFPS() { - return mWindow->getLastFPS(); + return mWindow->getLastFPS(); } -bool OgreRenderer::configure(bool showConfig, - const std::string &cfgPath, - const std::string &logPath, - const std::string &pluginCfg, - bool _logging) +void OgreRenderer::configure(const std::string &logPath, + const std::string &pluginCfg, + const std::string& renderSystem, + bool _logging) { - // Set up logging first - new LogManager; - Log *log = LogManager::getSingleton().createLog(logPath + std::string("Ogre.log")); - logging = _logging; + // Set up logging first + new LogManager; + Log *log = LogManager::getSingleton().createLog(logPath + std::string("Ogre.log")); + logging = _logging; - if(logging) - // Full log detail - log->setLogDetail(LL_BOREME); - else - // Disable logging - log->setDebugOutputEnabled(false); + if(logging) + // Full log detail + log->setLogDetail(LL_BOREME); + else + // Disable logging + log->setDebugOutputEnabled(false); -#if defined(ENABLE_PLUGIN_GL) || defined(ENABLE_PLUGIN_Direct3D9) || defined(ENABLE_PLUGIN_CgProgramManager) || defined(ENABLE_PLUGIN_OctreeSceneManager) || defined(ENABLE_PLUGIN_ParticleFX) - mRoot = new Root("", cfgPath, ""); - loadPlugins(); -#else - mRoot = new Root(pluginCfg, cfgPath, ""); -#endif + #if defined(ENABLE_PLUGIN_GL) || defined(ENABLE_PLUGIN_Direct3D9) || defined(ENABLE_PLUGIN_CgProgramManager) || defined(ENABLE_PLUGIN_OctreeSceneManager) || defined(ENABLE_PLUGIN_ParticleFX) + mRoot = new Root("", "", ""); + loadPlugins(); + #else + mRoot = new Root(pluginCfg, "", ""); + #endif - // Show the configuration dialog and initialise the system, if the - // showConfig parameter is specified. The settings are stored in - // ogre.cfg. If showConfig is false, the settings are assumed to - // already exist in ogre.cfg. - int result; - if(showConfig) - result = mRoot->showConfigDialog(); - else - result = mRoot->restoreConfig(); - - return !result; + RenderSystem* rs = mRoot->getRenderSystemByName(renderSystem); + if (rs == 0) + throw std::runtime_error ("RenderSystem with name " + renderSystem + " not found, make sure the plugins are loaded"); + mRoot->setRenderSystem(rs); } -bool OgreRenderer::configure(bool showConfig, - const std::string &cfgPath, - const std::string &pluginCfg, - bool _logging) +void OgreRenderer::createWindow(const std::string &title, const WindowSettings& settings) { - return configure(showConfig, cfgPath, cfgPath, pluginCfg, _logging); -} + assert(mRoot); + mRoot->initialise(false); -bool OgreRenderer::configure(bool showConfig, - const std::string &pluginCfg, - bool _logging) -{ - return configure(showConfig, "", pluginCfg, _logging); -} + NameValuePairList params; + params.insert(std::make_pair("title", title)); + params.insert(std::make_pair("FSAA", settings.fsaa)); + params.insert(std::make_pair("vsync", settings.vsync ? "true" : "false")); -void OgreRenderer::createWindow(const std::string &title) -{ - assert(mRoot); - // Initialize OGRE window - mWindow = mRoot->initialise(true, title, ""); + mWindow = mRoot->createRenderWindow(title, settings.window_x, settings.window_y, settings.fullscreen, ¶ms); } void OgreRenderer::createScene(const std::string camName, float fov, float nearClip) { - assert(mRoot); - assert(mWindow); - // Get the SceneManager, in this case a generic one - mScene = mRoot->createSceneManager(ST_GENERIC); + assert(mRoot); + assert(mWindow); + // Get the SceneManager, in this case a generic one + mScene = mRoot->createSceneManager(ST_GENERIC); - // Create the camera - mCamera = mScene->createCamera(camName); - mCamera->setNearClipDistance(nearClip); - mCamera->setFOVy(Degree(fov)); + // Create the camera + mCamera = mScene->createCamera(camName); + mCamera->setNearClipDistance(nearClip); + mCamera->setFOVy(Degree(fov)); - // Create one viewport, entire window - mView = mWindow->addViewport(mCamera); + // Create one viewport, entire window + mView = mWindow->addViewport(mCamera); - // Alter the camera aspect ratio to match the viewport - mCamera->setAspectRatio(Real(mView->getActualWidth()) / Real(mView->getActualHeight())); - - mFader = new Fader(); + // Alter the camera aspect ratio to match the viewport + mCamera->setAspectRatio(Real(mView->getActualWidth()) / Real(mView->getActualHeight())); + + mFader = new Fader(); } diff --git a/libs/openengine/ogre/renderer.hpp b/libs/openengine/ogre/renderer.hpp index 179515aa92..7dc539e27e 100644 --- a/libs/openengine/ogre/renderer.hpp +++ b/libs/openengine/ogre/renderer.hpp @@ -33,124 +33,123 @@ namespace Ogre class Viewport; } -namespace OEngine { -namespace Render +namespace OEngine { - class Fader; - class OgreRenderer - { - Ogre::Root *mRoot; - Ogre::RenderWindow *mWindow; - Ogre::SceneManager *mScene; - Ogre::Camera *mCamera; - Ogre::Viewport *mView; -#ifdef ENABLE_PLUGIN_CgProgramManager - Ogre::CgPlugin* mCgPlugin; -#endif -#ifdef ENABLE_PLUGIN_OctreeSceneManager - Ogre::OctreePlugin* mOctreePlugin; -#endif -#ifdef ENABLE_PLUGIN_ParticleFX - Ogre::ParticleFXPlugin* mParticleFXPlugin; -#endif -#ifdef ENABLE_PLUGIN_GL - Ogre::GLPlugin* mGLPlugin; -#endif -#ifdef ENABLE_PLUGIN_Direct3D9 - Ogre::D3D9Plugin* mD3D9Plugin; -#endif - Fader* mFader; - bool logging; - - public: - OgreRenderer() - : mRoot(NULL) - , mWindow(NULL) - , mScene(NULL) - , mCamera(NULL) - , mView(NULL) -#ifdef ENABLE_PLUGIN_CgProgramManager - , mCgPlugin(NULL) -#endif -#ifdef ENABLE_PLUGIN_OctreeSceneManager - , mOctreePlugin(NULL) -#endif -#ifdef ENABLE_PLUGIN_ParticleFX - , mParticleFXPlugin(NULL) -#endif -#ifdef ENABLE_PLUGIN_GL - , mGLPlugin(NULL) -#endif -#ifdef ENABLE_PLUGIN_Direct3D9 - , mD3D9Plugin(NULL) -#endif - , mFader(NULL) - , logging(false) + namespace Render { + struct WindowSettings + { + bool vsync; + bool fullscreen; + int window_x, window_y; + std::string fsaa; + }; + + class Fader; + class OgreRenderer + { + Ogre::Root *mRoot; + Ogre::RenderWindow *mWindow; + Ogre::SceneManager *mScene; + Ogre::Camera *mCamera; + Ogre::Viewport *mView; + #ifdef ENABLE_PLUGIN_CgProgramManager + Ogre::CgPlugin* mCgPlugin; + #endif + #ifdef ENABLE_PLUGIN_OctreeSceneManager + Ogre::OctreePlugin* mOctreePlugin; + #endif + #ifdef ENABLE_PLUGIN_ParticleFX + Ogre::ParticleFXPlugin* mParticleFXPlugin; + #endif + #ifdef ENABLE_PLUGIN_GL + Ogre::GLPlugin* mGLPlugin; + #endif + #ifdef ENABLE_PLUGIN_Direct3D9 + Ogre::D3D9Plugin* mD3D9Plugin; + #endif + Fader* mFader; + bool logging; + + public: + OgreRenderer() + : mRoot(NULL) + , mWindow(NULL) + , mScene(NULL) + , mCamera(NULL) + , mView(NULL) + #ifdef ENABLE_PLUGIN_CgProgramManager + , mCgPlugin(NULL) + #endif + #ifdef ENABLE_PLUGIN_OctreeSceneManager + , mOctreePlugin(NULL) + #endif + #ifdef ENABLE_PLUGIN_ParticleFX + , mParticleFXPlugin(NULL) + #endif + #ifdef ENABLE_PLUGIN_GL + , mGLPlugin(NULL) + #endif + #ifdef ENABLE_PLUGIN_Direct3D9 + , mD3D9Plugin(NULL) + #endif + , mFader(NULL) + , logging(false) + { + } + + ~OgreRenderer() { cleanup(); } + + /** Configure the renderer. This will load configuration files and + set up the Root and logging classes. */ + void configure( + const std::string &logPath, // Path to directory where to store log files + const std::string &pluginCfg, // plugin.cfg file + const std::string &renderSystem, + bool _logging); // Enable or disable logging + + /// Create a window with the given title + void createWindow(const std::string &title, const WindowSettings& settings); + + /// Set up the scene manager, camera and viewport + void createScene(const std::string camName="Camera",// Camera name + float fov=55, // Field of view angle + float nearClip=5 // Near clip distance + ); + + /// Kill the renderer. + void cleanup(); + + /// Start the main rendering loop + void start(); + + bool loadPlugins(); + + void update(float dt); + + /// Write a screenshot to file + void screenshot(const std::string &file); + + float getFPS(); + + /// Get the Root + Ogre::Root *getRoot() { return mRoot; } + + /// Get the rendering window + Ogre::RenderWindow *getWindow() { return mWindow; } + + /// Get the scene manager + Ogre::SceneManager *getScene() { return mScene; } + + /// Get the screen colour fader + Fader *getFader() { return mFader; } + + /// Camera + Ogre::Camera *getCamera() { return mCamera; } + + /// Viewport + Ogre::Viewport *getViewport() { return mView; } + }; } - - ~OgreRenderer() { cleanup(); } - - /** Configure the renderer. This will load configuration files and - set up the Root and logging classes. */ - bool configure(bool showConfig, // Show config dialog box? - const std::string &cfgPath, // Path to directory where to store config files - const std::string &logPath, // Path to directory where to store log files - const std::string &pluginCfg, // plugin.cfg file - bool _logging); // Enable or disable logging - - bool configure(bool showConfig, // Show config dialog box? - const std::string &cfgPath, // Path to directory where to store config files - const std::string &pluginCfg, // plugin.cfg file - bool _logging); // Enable or disable logging - - /** Configure the renderer. This will load configuration files and - set up the Root and logging classes. */ - bool configure(bool showConfig, // Show config dialog box? - const std::string &pluginCfg, // plugin.cfg file - bool _logging); // Enable or disable logging - - /// Create a window with the given title - void createWindow(const std::string &title); - - /// Set up the scene manager, camera and viewport - void createScene(const std::string camName="Camera",// Camera name - float fov=55, // Field of view angle - float nearClip=5 // Near clip distance - ); - - /// Kill the renderer. - void cleanup(); - - /// Start the main rendering loop - void start(); - - bool loadPlugins(); - - void update(float dt); - - /// Write a screenshot to file - void screenshot(const std::string &file); - - float getFPS(); - - /// Get the Root - Ogre::Root *getRoot() { return mRoot; } - - /// Get the rendering window - Ogre::RenderWindow *getWindow() { return mWindow; } - - /// Get the scene manager - Ogre::SceneManager *getScene() { return mScene; } - - /// Get the screen colour fader - Fader *getFader() { return mFader; } - - /// Camera - Ogre::Camera *getCamera() { return mCamera; } - - /// Viewport - Ogre::Viewport *getViewport() { return mView; } - }; -}} +} #endif From 355268dae11d77556571f97452e8a4bdcb55f16e Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 22 May 2012 19:36:50 +0200 Subject: [PATCH 253/325] make the launcher build and run again, but it doesn't change settings --- apps/launcher/graphicspage.cpp | 35 ++++++---------------------------- 1 file changed, 6 insertions(+), 29 deletions(-) diff --git a/apps/launcher/graphicspage.cpp b/apps/launcher/graphicspage.cpp index 95b38d53ea..8a26ec4441 100644 --- a/apps/launcher/graphicspage.cpp +++ b/apps/launcher/graphicspage.cpp @@ -150,9 +150,6 @@ void GraphicsPage::createPages() void GraphicsPage::setupConfig() { - QString ogreCfg = mCfgMgr.getOgreConfigPath().string().c_str(); - QFile file(ogreCfg); - mOgreConfig = new QSettings(ogreCfg, QSettings::IniFormat); } void GraphicsPage::setupOgre() @@ -164,32 +161,12 @@ void GraphicsPage::setupOgre() Ogre::LogManager* logMgr = OGRE_NEW Ogre::LogManager; logMgr->createLog((mCfgMgr.getLogPath().string() + "/launcherOgre.log"), true, false, false); - QString ogreCfg = QString::fromStdString(mCfgMgr.getOgreConfigPath().string()); - file.setFileName(ogreCfg); - - //we need to check that the path to the configuration file exists before we - //try and create an instance of Ogre::Root otherwise Ogre raises an exception - QDir configDir = QFileInfo(file).dir(); - if ( !configDir.exists() && !configDir.mkpath(configDir.path()) ) - { - QMessageBox msgBox; - msgBox.setWindowTitle("Error creating config file"); - msgBox.setIcon(QMessageBox::Critical); - msgBox.setStandardButtons(QMessageBox::Ok); - msgBox.setText(QString(tr("
Failed to create the configuration file

\ - Make sure you have write access to
%1

")).arg(configDir.path())); - msgBox.exec(); - - qApp->exit(1); - return; - } - try { #if defined(ENABLE_PLUGIN_GL) || defined(ENABLE_PLUGIN_Direct3D9) - mOgre = new Ogre::Root("", file.fileName().toStdString(), "./launcherOgre.log"); + mOgre = new Ogre::Root("", "", "./launcherOgre.log"); #else - mOgre = new Ogre::Root(pluginCfg.toStdString(), file.fileName().toStdString(), "./launcherOgre.log"); + mOgre = new Ogre::Root(pluginCfg.toStdString(), "", "./launcherOgre.log"); #endif } catch(Ogre::Exception &ex) @@ -227,13 +204,13 @@ void GraphicsPage::setupOgre() mSelectedRenderSystem = *r; mRendererComboBox->addItem((*r)->getName().c_str()); } - +/* int index = mRendererComboBox->findText(mOgreConfig->value("Render System").toString()); if ( index != -1) { mRendererComboBox->setCurrentIndex(index); } - +*/ // Create separate rendersystems QString openGLName = mRendererComboBox->itemText(mRendererComboBox->findText(QString("OpenGL"), Qt::MatchStartsWith)); QString direct3DName = mRendererComboBox->itemText(mRendererComboBox->findText(QString("Direct3D"), Qt::MatchStartsWith)); @@ -460,11 +437,11 @@ void GraphicsPage::writeConfig() QString GraphicsPage::getConfigValue(const QString &key, Ogre::RenderSystem *renderer) { QString result; - +/* mOgreConfig->beginGroup(renderer->getName().c_str()); result = mOgreConfig->value(key).toString(); mOgreConfig->endGroup(); - +*/ return result; } From ad46049ee078bc9fde6ef92eaf45fd366e8e60dd Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 22 May 2012 20:37:18 +0200 Subject: [PATCH 254/325] got the launcher working with the new settings system. --- apps/launcher/graphicspage.cpp | 375 ++++++--------------------------- apps/launcher/graphicspage.hpp | 26 +-- apps/launcher/maindialog.cpp | 27 +++ apps/launcher/maindialog.hpp | 2 + 4 files changed, 102 insertions(+), 328 deletions(-) diff --git a/apps/launcher/graphicspage.cpp b/apps/launcher/graphicspage.cpp index 8a26ec4441..2cd8006aea 100644 --- a/apps/launcher/graphicspage.cpp +++ b/apps/launcher/graphicspage.cpp @@ -1,7 +1,11 @@ +#include "graphicspage.hpp" + #include -#include "graphicspage.hpp" +#include + #include +#include GraphicsPage::GraphicsPage(Files::ConfigurationManager &cfg, QWidget *parent) : QWidget(parent) @@ -17,12 +21,9 @@ GraphicsPage::GraphicsPage(Files::ConfigurationManager &cfg, QWidget *parent) renderSystemLayout->addWidget(rendererLabel, 0, 0, 1, 1); renderSystemLayout->addWidget(mRendererComboBox, 0, 1, 1, 1); - mRendererStackedWidget = new QStackedWidget(rendererGroup); - QVBoxLayout *rendererGroupLayout = new QVBoxLayout(rendererGroup); rendererGroupLayout->addLayout(renderSystemLayout); - rendererGroupLayout->addWidget(mRendererStackedWidget); // Display QGroupBox *displayGroup = new QGroupBox(tr("Display"), this); @@ -52,100 +53,29 @@ GraphicsPage::GraphicsPage(Files::ConfigurationManager &cfg, QWidget *parent) void GraphicsPage::createPages() { - // OpenGL rendering settings - QWidget *mOGLRendererPage = new QWidget(); + QWidget *main = new QWidget(); + QGridLayout *grid = new QGridLayout(main); - QLabel *OGLRTTLabel = new QLabel(tr("Preferred RTT Mode:"), mOGLRendererPage); - mOGLRTTComboBox = new QComboBox(mOGLRendererPage); + mVSyncCheckBox = new QCheckBox(tr("Vertical Sync"), main); + grid->addWidget(mVSyncCheckBox, 0, 0, 1, 1); - QLabel *OGLAntiAliasingLabel = new QLabel(tr("Antialiasing:"), mOGLRendererPage); - mOGLAntiAliasingComboBox = new QComboBox(mOGLRendererPage); + mFullScreenCheckBox = new QCheckBox(tr("Full Screen"), main); + grid->addWidget(mFullScreenCheckBox, 1, 0, 1, 1); + + QLabel *antiAliasingLabel = new QLabel(tr("Antialiasing:"), main); + mAntiAliasingComboBox = new QComboBox(main); + grid->addWidget(antiAliasingLabel, 2, 0, 1, 1); + grid->addWidget(mAntiAliasingComboBox, 2, 1, 1, 1); + + QLabel *resolutionLabel = new QLabel(tr("Resolution:"), main); + mResolutionComboBox = new QComboBox(main); + grid->addWidget(resolutionLabel, 3, 0, 1, 1); + grid->addWidget(mResolutionComboBox, 3, 1, 1, 1); - QGridLayout *OGLRendererLayout = new QGridLayout(mOGLRendererPage); QSpacerItem *vSpacer1 = new QSpacerItem(20, 10, QSizePolicy::Minimum, QSizePolicy::Expanding); + grid->addItem(vSpacer1, 4, 0, 1, 1); - OGLRendererLayout->addWidget(OGLRTTLabel, 0, 0, 1, 1); - OGLRendererLayout->addWidget(mOGLRTTComboBox, 0, 1, 1, 1); - OGLRendererLayout->addWidget(OGLAntiAliasingLabel, 1, 0, 1, 1); - OGLRendererLayout->addWidget(mOGLAntiAliasingComboBox, 1, 1, 1, 1); - OGLRendererLayout->addItem(vSpacer1, 2, 1, 1, 1); - - // OpenGL display settings - QWidget *mOGLDisplayPage = new QWidget(); - - QLabel *OGLResolutionLabel = new QLabel(tr("Resolution:"), mOGLDisplayPage); - mOGLResolutionComboBox = new QComboBox(mOGLDisplayPage); - - QLabel *OGLFrequencyLabel = new QLabel(tr("Display Frequency:"), mOGLDisplayPage); - mOGLFrequencyComboBox = new QComboBox(mOGLDisplayPage); - - mOGLVSyncCheckBox = new QCheckBox(tr("Vertical Sync"), mOGLDisplayPage); - mOGLFullScreenCheckBox = new QCheckBox(tr("Full Screen"), mOGLDisplayPage); - - QGridLayout *OGLDisplayLayout = new QGridLayout(mOGLDisplayPage); - QSpacerItem *vSpacer2 = new QSpacerItem(20, 10, QSizePolicy::Minimum, QSizePolicy::Minimum); - - OGLDisplayLayout->addWidget(OGLResolutionLabel, 0, 0, 1, 1); - OGLDisplayLayout->addWidget(mOGLResolutionComboBox, 0, 1, 1, 1); - OGLDisplayLayout->addWidget(OGLFrequencyLabel, 1, 0, 1, 1); - OGLDisplayLayout->addWidget(mOGLFrequencyComboBox, 1, 1, 1, 1); - - OGLDisplayLayout->addItem(vSpacer2, 2, 1, 1, 1); - OGLDisplayLayout->addWidget(mOGLVSyncCheckBox, 3, 0, 1, 1); - OGLDisplayLayout->addWidget(mOGLFullScreenCheckBox, 6, 0, 1, 1); - - // Direct3D rendering settings - QWidget *mD3DRendererPage = new QWidget(); - - QLabel *D3DRenderDeviceLabel = new QLabel(tr("Rendering Device:"), mD3DRendererPage); - mD3DRenderDeviceComboBox = new QComboBox(mD3DRendererPage); - - QLabel *D3DAntiAliasingLabel = new QLabel(tr("Antialiasing:"), mD3DRendererPage); - mD3DAntiAliasingComboBox = new QComboBox(mD3DRendererPage); - - QLabel *D3DFloatingPointLabel = new QLabel(tr("Floating-point Mode:"), mD3DRendererPage); - mD3DFloatingPointComboBox = new QComboBox(mD3DRendererPage); - - mD3DNvPerfCheckBox = new QCheckBox(tr("Allow NVPerfHUD"), mD3DRendererPage); - - QGridLayout *D3DRendererLayout = new QGridLayout(mD3DRendererPage); - QSpacerItem *vSpacer3 = new QSpacerItem(20, 10, QSizePolicy::Minimum, QSizePolicy::Minimum); - QSpacerItem *vSpacer4 = new QSpacerItem(20, 10, QSizePolicy::Minimum, QSizePolicy::Expanding); - - D3DRendererLayout->addWidget(D3DRenderDeviceLabel, 0, 0, 1, 1); - D3DRendererLayout->addWidget(mD3DRenderDeviceComboBox, 0, 1, 1, 1); - D3DRendererLayout->addWidget(D3DAntiAliasingLabel, 1, 0, 1, 1); - D3DRendererLayout->addWidget(mD3DAntiAliasingComboBox, 1, 1, 1, 1); - D3DRendererLayout->addWidget(D3DFloatingPointLabel, 2, 0, 1, 1); - D3DRendererLayout->addWidget(mD3DFloatingPointComboBox, 2, 1, 1, 1); - D3DRendererLayout->addItem(vSpacer3, 3, 1, 1, 1); - D3DRendererLayout->addWidget(mD3DNvPerfCheckBox, 4, 0, 1, 1); - D3DRendererLayout->addItem(vSpacer4, 5, 1, 1, 1); - - // Direct3D display settings - QWidget *mD3DDisplayPage = new QWidget(); - - QLabel *D3DResolutionLabel = new QLabel(tr("Resolution:"), mD3DDisplayPage); - mD3DResolutionComboBox = new QComboBox(mD3DDisplayPage); - - mD3DVSyncCheckBox = new QCheckBox(tr("Vertical Sync"), mD3DDisplayPage); - mD3DFullScreenCheckBox = new QCheckBox(tr("Full Screen"), mD3DDisplayPage); - - QGridLayout *mD3DDisplayLayout = new QGridLayout(mD3DDisplayPage); - QSpacerItem *vSpacer5 = new QSpacerItem(20, 10, QSizePolicy::Minimum, QSizePolicy::Minimum); - - mD3DDisplayLayout->addWidget(D3DResolutionLabel, 0, 0, 1, 1); - mD3DDisplayLayout->addWidget(mD3DResolutionComboBox, 0, 1, 1, 1); - mD3DDisplayLayout->addItem(vSpacer5, 1, 1, 1, 1); - mD3DDisplayLayout->addWidget(mD3DVSyncCheckBox, 2, 0, 1, 1); - mD3DDisplayLayout->addWidget(mD3DFullScreenCheckBox, 5, 0, 1, 1); - - // Add the created pages - mRendererStackedWidget->addWidget(mOGLRendererPage); - mRendererStackedWidget->addWidget(mD3DRendererPage); - - mDisplayStackedWidget->addWidget(mOGLDisplayPage); - mDisplayStackedWidget->addWidget(mD3DDisplayPage); + mDisplayStackedWidget->addWidget(main); } void GraphicsPage::setupConfig() @@ -204,13 +134,21 @@ void GraphicsPage::setupOgre() mSelectedRenderSystem = *r; mRendererComboBox->addItem((*r)->getName().c_str()); } -/* - int index = mRendererComboBox->findText(mOgreConfig->value("Render System").toString()); + + int index = mRendererComboBox->findText(QString::fromStdString(Settings::Manager::getString("render system", "Video"))); if ( index != -1) { mRendererComboBox->setCurrentIndex(index); } -*/ + else + { +#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32 + mRendererComboBox->setCurrentIndex(mRendererComboBox->findText("Direct3D9 Rendering Subsystem")); +#else + mRendererComboBox->setCurrentIndex(mRendererComboBox->findText("OpenGL Rendering Subsystem")); +#endif + } + // Create separate rendersystems QString openGLName = mRendererComboBox->itemText(mRendererComboBox->findText(QString("OpenGL"), Qt::MatchStartsWith)); QString direct3DName = mRendererComboBox->itemText(mRendererComboBox->findText(QString("Direct3D"), Qt::MatchStartsWith)); @@ -232,217 +170,44 @@ void GraphicsPage::setupOgre() } // Now fill the GUI elements - // OpenGL - if (mOpenGLRenderSystem) { - mOGLRTTComboBox->addItems(getAvailableOptions(QString("RTT Preferred Mode"), mOpenGLRenderSystem)); - mOGLAntiAliasingComboBox->addItems(getAvailableOptions(QString("FSAA"), mOpenGLRenderSystem)); - mOGLResolutionComboBox->addItems(getAvailableOptions(QString("Video Mode"), mOpenGLRenderSystem)); - mOGLFrequencyComboBox->addItems(getAvailableOptions(QString("Display Frequency"), mOpenGLRenderSystem)); - } - - // Direct3D - if (mDirect3DRenderSystem) { - mD3DRenderDeviceComboBox->addItems(getAvailableOptions(QString("Rendering Device"), mDirect3DRenderSystem)); - mD3DAntiAliasingComboBox->addItems(getAvailableOptions(QString("FSAA"), mDirect3DRenderSystem)); - mD3DFloatingPointComboBox->addItems(getAvailableOptions(QString("Floating-point mode"), mDirect3DRenderSystem)); - mD3DResolutionComboBox->addItems(getAvailableOptions(QString("Video Mode"), mDirect3DRenderSystem)); - } + mAntiAliasingComboBox->clear(); + mResolutionComboBox->clear(); + mAntiAliasingComboBox->addItems(getAvailableOptions(QString("FSAA"), mSelectedRenderSystem)); + mResolutionComboBox->addItems(getAvailableOptions(QString("Video Mode"), mSelectedRenderSystem)); } void GraphicsPage::readConfig() { - // Read the config file settings - if (mOpenGLRenderSystem) { + if (Settings::Manager::getBool("vsync", "Video")) + mVSyncCheckBox->setCheckState(Qt::Checked); - int index = mOGLRTTComboBox->findText(getConfigValue("RTT Preferred Mode", mOpenGLRenderSystem)); - if ( index != -1) { - mOGLRTTComboBox->setCurrentIndex(index); - } + if (Settings::Manager::getBool("fullscreen", "Video")) + mFullScreenCheckBox->setCheckState(Qt::Checked); - index = mOGLAntiAliasingComboBox->findText(getConfigValue("FSAA", mOpenGLRenderSystem)); - if ( index != -1){ - mOGLAntiAliasingComboBox->setCurrentIndex(index); - } + int aaIndex = mAntiAliasingComboBox->findText(QString::fromStdString(Settings::Manager::getString("antialiasing", "Video"))); + if (aaIndex != -1) + mAntiAliasingComboBox->setCurrentIndex(aaIndex); - index = mOGLResolutionComboBox->findText(getConfigValue("Video Mode", mOpenGLRenderSystem)); - if ( index != -1) { - mOGLResolutionComboBox->setCurrentIndex(index); - } - - index = mOGLFrequencyComboBox->findText(getConfigValue("Display Frequency", mOpenGLRenderSystem)); - if ( index != -1) { - mOGLFrequencyComboBox->setCurrentIndex(index); - } - - // Now we do the same for the checkboxes - if (getConfigValue("VSync", mOpenGLRenderSystem) == QLatin1String("Yes")) { - mOGLVSyncCheckBox->setCheckState(Qt::Checked); - } - - if (getConfigValue("Full Screen", mOpenGLRenderSystem) == QLatin1String("Yes")) { - mOGLFullScreenCheckBox->setCheckState(Qt::Checked); - } - } - - if (mDirect3DRenderSystem) { - - int index = mD3DRenderDeviceComboBox->findText(getConfigValue("Rendering Device", mDirect3DRenderSystem)); - if ( index != -1) { - mD3DRenderDeviceComboBox->setCurrentIndex(index); - } - - index = mD3DAntiAliasingComboBox->findText(getConfigValue("FSAA", mDirect3DRenderSystem)); - if ( index != -1) { - mD3DAntiAliasingComboBox->setCurrentIndex(index); - } - - index = mD3DFloatingPointComboBox->findText(getConfigValue("Floating-point mode", mDirect3DRenderSystem)); - if ( index != -1) { - mD3DFloatingPointComboBox->setCurrentIndex(index); - } - - index = mD3DResolutionComboBox->findText(getConfigValue("Video Mode", mDirect3DRenderSystem)); - if ( index != -1) { - mD3DResolutionComboBox->setCurrentIndex(index); - } - - if (getConfigValue("Allow NVPerfHUD", mDirect3DRenderSystem) == QLatin1String("Yes")) { - mD3DNvPerfCheckBox->setCheckState(Qt::Checked); - } - - if (getConfigValue("VSync", mDirect3DRenderSystem) == QLatin1String("Yes")) { - mD3DVSyncCheckBox->setCheckState(Qt::Checked); - } - - if (getConfigValue("Full Screen", mDirect3DRenderSystem) == QLatin1String("Yes")) { - mD3DFullScreenCheckBox->setCheckState(Qt::Checked); - } - } + std::string resolution = boost::lexical_cast(Settings::Manager::getInt("resolution x", "Video")) + + " x " + boost::lexical_cast(Settings::Manager::getInt("resolution y", "Video")); + int resIndex = mResolutionComboBox->findText(QString::fromStdString(resolution)); + if (resIndex != -1) + mResolutionComboBox->setCurrentIndex(resIndex); } void GraphicsPage::writeConfig() { - mOgre->setRenderSystem(mSelectedRenderSystem); + Settings::Manager::setBool("vsync", "Video", mVSyncCheckBox->checkState()); + Settings::Manager::setBool("fullscreen", "Video", mFullScreenCheckBox->checkState()); + Settings::Manager::setString("antialiasing", "Video", mAntiAliasingComboBox->currentText().toStdString()); - if (mDirect3DRenderSystem) { - // Nvidia Performance HUD - if (mD3DNvPerfCheckBox->checkState() == Qt::Checked) { - mDirect3DRenderSystem->setConfigOption("Allow NVPerfHUD", "Yes"); - } else { - mDirect3DRenderSystem->setConfigOption("Allow NVPerfHUD", "No"); - } - - // Antialiasing - mDirect3DRenderSystem->setConfigOption("FSAA", mD3DAntiAliasingComboBox->currentText().toStdString()); - - // Full screen - if (mD3DFullScreenCheckBox->checkState() == Qt::Checked) { - mDirect3DRenderSystem->setConfigOption("Full Screen", "Yes"); - } else { - mDirect3DRenderSystem->setConfigOption("Full Screen", "No"); - } - - // Rendering device - mDirect3DRenderSystem->setConfigOption("Rendering Device", mD3DRenderDeviceComboBox->currentText().toStdString()); - - // VSync - if (mD3DVSyncCheckBox->checkState() == Qt::Checked) { - mDirect3DRenderSystem->setConfigOption("VSync", "Yes"); - } else { - mDirect3DRenderSystem->setConfigOption("VSync", "No"); - } - - // Resolution - mDirect3DRenderSystem->setConfigOption("Video Mode", mD3DResolutionComboBox->currentText().toStdString()); - } - - if (mOpenGLRenderSystem) { - // Display Frequency - mOpenGLRenderSystem->setConfigOption("Display Frequency", mOGLFrequencyComboBox->currentText().toStdString()); - - // Antialiasing - mOpenGLRenderSystem->setConfigOption("FSAA", mOGLAntiAliasingComboBox->currentText().toStdString()); - - // Full screen - if (mOGLFullScreenCheckBox->checkState() == Qt::Checked) { - mOpenGLRenderSystem->setConfigOption("Full Screen", "Yes"); - } else { - mOpenGLRenderSystem->setConfigOption("Full Screen", "No"); - } - - // RTT mode - mOpenGLRenderSystem->setConfigOption("RTT Preferred Mode", mOGLRTTComboBox->currentText().toStdString()); - - // VSync - if (mOGLVSyncCheckBox->checkState() == Qt::Checked) { - mOpenGLRenderSystem->setConfigOption("VSync", "Yes"); - } else { - mOpenGLRenderSystem->setConfigOption("VSync", "No"); - } - - // Resolution - mOpenGLRenderSystem->setConfigOption("Video Mode", mOGLResolutionComboBox->currentText().toStdString()); - } - - // Now we validate the options - QString ogreError = QString::fromStdString(mSelectedRenderSystem->validateConfigOptions()); - - if (!ogreError.isEmpty()) { - QMessageBox msgBox; - msgBox.setWindowTitle("Error validating Ogre configuration"); - msgBox.setIcon(QMessageBox::Critical); - msgBox.setStandardButtons(QMessageBox::Ok); - msgBox.setText(tr("
A problem occured while validating the graphics options

\ - The graphics options could not be saved.

\ - Press \"Show Details...\" for more information.
")); - msgBox.setDetailedText(ogreError); - msgBox.exec(); - - Ogre::LogManager::getSingletonPtr()->logMessage( "Caught exception in validateConfigOptions"); - - qCritical("Error validating configuration"); - - qApp->exit(1); - return; - } - - // Write the settings to the config file - - - try - { - mOgre->saveConfig(); - } - catch(Ogre::Exception &ex) - { - QString ogreError = QString::fromStdString(ex.getFullDescription().c_str()); - QMessageBox msgBox; - msgBox.setWindowTitle("Error writing Ogre configuration file"); - msgBox.setIcon(QMessageBox::Critical); - msgBox.setStandardButtons(QMessageBox::Ok); - msgBox.setText(tr("
Could not write the graphics configuration

\ - Please make sure you have the right permissions and try again.

\ - Press \"Show Details...\" for more information.
")); - msgBox.setDetailedText(ogreError); - msgBox.exec(); - - qCritical("Error saving Ogre configuration, the error reported was:\n %s", qPrintable(ogreError)); - - qApp->exit(1); - return; - } - -} - -QString GraphicsPage::getConfigValue(const QString &key, Ogre::RenderSystem *renderer) -{ - QString result; -/* - mOgreConfig->beginGroup(renderer->getName().c_str()); - result = mOgreConfig->value(key).toString(); - mOgreConfig->endGroup(); -*/ - return result; + std::string resolution = mResolutionComboBox->currentText().toStdString(); + // parse resolution x and y from a string like "800 x 600" + size_t xPos = resolution.find("x"); + int resX = boost::lexical_cast(resolution.substr(0, xPos-1)); + int resY = boost::lexical_cast(resolution.substr(xPos+2, resolution.size()-(xPos+2))); + Settings::Manager::setInt("resolution x", "Video", resX); + Settings::Manager::setInt("resolution y", "Video", resY); } QStringList GraphicsPage::getAvailableOptions(const QString &key, Ogre::RenderSystem *renderer) @@ -461,7 +226,9 @@ QStringList GraphicsPage::getAvailableOptions(const QString &key, Ogre::RenderSy { if (strcmp (key.toStdString().c_str(), i->first.c_str()) == 0) - result << QString::fromStdString((*opt_it).c_str()).simplified(); + { + result << ((key == "FSAA") ? QString("MSAA ") : QString("")) + QString::fromStdString((*opt_it).c_str()).simplified(); + } } } @@ -471,15 +238,11 @@ QStringList GraphicsPage::getAvailableOptions(const QString &key, Ogre::RenderSy void GraphicsPage::rendererChanged(const QString &renderer) { - if (renderer.contains("Direct3D")) { - mRendererStackedWidget->setCurrentIndex(1); - mDisplayStackedWidget->setCurrentIndex(1); - } - - if (renderer.contains("OpenGL")) { - mRendererStackedWidget->setCurrentIndex(0); - mDisplayStackedWidget->setCurrentIndex(0); - } - mSelectedRenderSystem = mOgre->getRenderSystemByName(renderer.toStdString()); + + mAntiAliasingComboBox->clear(); + mResolutionComboBox->clear(); + + mAntiAliasingComboBox->addItems(getAvailableOptions(QString("FSAA"), mSelectedRenderSystem)); + mResolutionComboBox->addItems(getAvailableOptions(QString("Video Mode"), mSelectedRenderSystem)); } diff --git a/apps/launcher/graphicspage.hpp b/apps/launcher/graphicspage.hpp index 6a91a0628e..1b0c6f388c 100644 --- a/apps/launcher/graphicspage.hpp +++ b/apps/launcher/graphicspage.hpp @@ -49,33 +49,15 @@ private: QComboBox *mRendererComboBox; - QStackedWidget *mRendererStackedWidget; QStackedWidget *mDisplayStackedWidget; - // OpenGL - QComboBox *mOGLRTTComboBox; - QComboBox *mOGLAntiAliasingComboBox; - QComboBox *mOGLResolutionComboBox; - QComboBox *mOGLFrequencyComboBox; - - QCheckBox *mOGLVSyncCheckBox; - QCheckBox *mOGLFullScreenCheckBox; - - // Direct3D - QComboBox *mD3DRenderDeviceComboBox; - QComboBox *mD3DAntiAliasingComboBox; - QComboBox *mD3DFloatingPointComboBox; - QComboBox *mD3DResolutionComboBox; - - QCheckBox *mD3DNvPerfCheckBox; - QCheckBox *mD3DVSyncCheckBox; - QCheckBox *mD3DFullScreenCheckBox; - - QSettings *mOgreConfig; + QComboBox *mAntiAliasingComboBox; + QComboBox *mResolutionComboBox; + QCheckBox *mVSyncCheckBox; + QCheckBox *mFullScreenCheckBox; Files::ConfigurationManager &mCfgMgr; - QString getConfigValue(const QString &key, Ogre::RenderSystem *renderer); QStringList getAvailableOptions(const QString &key, Ogre::RenderSystem *renderer); void createPages(); diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index 8bb618dd66..d404fed8e7 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -7,6 +7,28 @@ MainDialog::MainDialog() { + // Create the settings manager and load default settings file + const std::string localdefault = mCfgMgr.getLocalPath().string() + "/settings-default.cfg"; + const std::string globaldefault = mCfgMgr.getGlobalPath().string() + "/settings-default.cfg"; + + // prefer local + if (boost::filesystem::exists(localdefault)) + mSettings.loadDefault(localdefault); + else if (boost::filesystem::exists(globaldefault)) + mSettings.loadDefault(globaldefault); + else + throw std::runtime_error ("No default settings file found! Make sure the file \"settings-default.cfg\" was properly installed."); + + // load user settings if they exist, otherwise just load the default settings as user settings + const std::string settingspath = mCfgMgr.getUserPath().string() + "/settings.cfg"; + if (boost::filesystem::exists(settingspath)) + mSettings.loadUser(settingspath); + else if (boost::filesystem::exists(localdefault)) + mSettings.loadUser(localdefault); + else if (boost::filesystem::exists(globaldefault)) + mSettings.loadUser(globaldefault); + + mIconWidget = new QListWidget; mIconWidget->setObjectName("IconWidget"); mIconWidget->setViewMode(QListView::IconMode); @@ -178,6 +200,11 @@ void MainDialog::closeEvent(QCloseEvent *event) // Now write all config files mDataFilesPage->writeConfig(); mGraphicsPage->writeConfig(); + + // Save user settings + const std::string settingspath = mCfgMgr.getUserPath().string() + "/settings.cfg"; + mSettings.saveUser(settingspath); + event->accept(); } diff --git a/apps/launcher/maindialog.hpp b/apps/launcher/maindialog.hpp index d6d0e9974e..0065aa8c47 100644 --- a/apps/launcher/maindialog.hpp +++ b/apps/launcher/maindialog.hpp @@ -4,6 +4,7 @@ #include #include +#include class QListWidget; class QListWidgetItem; @@ -41,6 +42,7 @@ private: DataFilesPage *mDataFilesPage; Files::ConfigurationManager mCfgMgr; + Settings::Manager mSettings; }; #endif From b25d62a7e2ad30cf41ee9f19110ebcfb4f328334 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 22 May 2012 20:52:38 +0200 Subject: [PATCH 255/325] rename antialiasing mode "MSAA 0" to "none" to avoid confusion. --- apps/launcher/graphicspage.cpp | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/apps/launcher/graphicspage.cpp b/apps/launcher/graphicspage.cpp index 2cd8006aea..e156e4fbc2 100644 --- a/apps/launcher/graphicspage.cpp +++ b/apps/launcher/graphicspage.cpp @@ -222,14 +222,17 @@ QStringList GraphicsPage::getAvailableOptions(const QString &key, Ogre::RenderSy 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(); - } - } + if (strcmp (key.toStdString().c_str(), i->first.c_str()) == 0) + { + if (key == "FSAA" && *opt_it == "0") + result << QString("none"); + else + result << ((key == "FSAA") ? QString("MSAA ") : QString("")) + QString::fromStdString((*opt_it).c_str()).simplified(); + } + } } From 313294c52297753aed1c168d61b553dc7d5615ef Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 22 May 2012 21:40:42 +0200 Subject: [PATCH 256/325] settings window (hotkey F2) which does nothing. Yay! --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwgui/mode.hpp | 1 + apps/openmw/mwgui/settingswindow.cpp | 25 ++++++++++++++++++ apps/openmw/mwgui/settingswindow.hpp | 26 +++++++++++++++++++ apps/openmw/mwgui/window_manager.cpp | 9 ++++++- apps/openmw/mwgui/window_manager.hpp | 2 ++ apps/openmw/mwinput/inputmanager.cpp | 15 +++++++++++ files/mygui/CMakeLists.txt | 1 + files/mygui/openmw_settings_window_layout.xml | 14 ++++++++++ 9 files changed, 93 insertions(+), 2 deletions(-) create mode 100644 apps/openmw/mwgui/settingswindow.cpp create mode 100644 apps/openmw/mwgui/settingswindow.hpp create mode 100644 files/mygui/openmw_settings_window_layout.xml diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index c08c91c02e..fd2fdf5754 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -27,7 +27,7 @@ add_openmw_dir (mwgui text_input widgets race class birth review window_manager console dialogue dialogue_history window_base stats_window messagebox journalwindow charactercreation map_window window_pinnable_base cursorreplace tooltips scrollwindow bookwindow list - formatting itemwidget inventorywindow container hud countdialog tradewindow + formatting itemwidget inventorywindow container hud countdialog tradewindow settingswindow ) add_openmw_dir (mwdialogue diff --git a/apps/openmw/mwgui/mode.hpp b/apps/openmw/mwgui/mode.hpp index 775fe4a030..ad54ed1dfd 100644 --- a/apps/openmw/mwgui/mode.hpp +++ b/apps/openmw/mwgui/mode.hpp @@ -6,6 +6,7 @@ namespace MWGui enum GuiMode { GM_Game, // Game mode, only HUD + GM_Settings, // Settings window GM_Inventory, // Inventory mode GM_Container, GM_MainMenu, // Main menu mode diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp new file mode 100644 index 0000000000..3641a63a40 --- /dev/null +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -0,0 +1,25 @@ +#include "settingswindow.hpp" + +#include "window_manager.hpp" + +namespace MWGui +{ + SettingsWindow::SettingsWindow(WindowManager& parWindowManager) : + WindowBase("openmw_settings_window_layout.xml", parWindowManager) + { + getWidget(mOkButton, "OkButton"); + + mOkButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onOkButtonClicked); + + center(); + + int okSize = mOkButton->getTextSize().width + 24; + mOkButton->setCoord(mMainWidget->getWidth()-16-okSize, mOkButton->getTop(), + okSize, mOkButton->getHeight()); + } + + void SettingsWindow::onOkButtonClicked(MyGUI::Widget* _sender) + { + mWindowManager.setGuiMode(GM_Game); + } +} diff --git a/apps/openmw/mwgui/settingswindow.hpp b/apps/openmw/mwgui/settingswindow.hpp new file mode 100644 index 0000000000..e37c00f7ee --- /dev/null +++ b/apps/openmw/mwgui/settingswindow.hpp @@ -0,0 +1,26 @@ +#ifndef MWGUI_SETTINGS_H +#define MWGUI_SETTINGS_H + +#include "window_base.hpp" + +namespace MWGui +{ + class WindowManager; +} + +namespace MWGui +{ + class SettingsWindow : public WindowBase + { + public: + SettingsWindow(WindowManager& parWindowManager); + + protected: + MyGUI::Button* mOkButton; + + void onOkButtonClicked(MyGUI::Widget* _sender); + }; +} + +#endif + diff --git a/apps/openmw/mwgui/window_manager.cpp b/apps/openmw/mwgui/window_manager.cpp index 2cacf23467..4bb34cf244 100644 --- a/apps/openmw/mwgui/window_manager.cpp +++ b/apps/openmw/mwgui/window_manager.cpp @@ -16,6 +16,7 @@ #include "mainmenu.hpp" #include "countdialog.hpp" #include "tradewindow.hpp" +#include "settingswindow.hpp" #include "../mwmechanics/mechanicsmanager.hpp" #include "../mwinput/inputmanager.hpp" @@ -45,11 +46,12 @@ WindowManager::WindowManager( , mMessageBoxManager(NULL) , console(NULL) , mJournal(NULL) - , mDialogueWindow(nullptr) + , mDialogueWindow(NULL) , mBookWindow(NULL) , mScrollWindow(NULL) , mCountDialog(NULL) , mTradeWindow(NULL) + , mSettingsWindow(NULL) , mCharGen(NULL) , playerClass() , playerName() @@ -118,6 +120,7 @@ WindowManager::WindowManager( mScrollWindow = new ScrollWindow(*this); mBookWindow = new BookWindow(*this); mCountDialog = new CountDialog(*this); + mSettingsWindow = new SettingsWindow(*this); // The HUD is always on hud->setVisible(true); @@ -217,6 +220,7 @@ void WindowManager::updateVisible() mScrollWindow->setVisible(false); mBookWindow->setVisible(false); mTradeWindow->setVisible(false); + mSettingsWindow->setVisible(false); // Mouse is visible whenever we're not in game mode MyGUI::PointerManager::getInstance().setVisible(isGuiMode()); @@ -233,6 +237,9 @@ void WindowManager::updateVisible() case GM_MainMenu: menu->setVisible(true); break; + case GM_Settings: + mSettingsWindow->setVisible(true); + break; case GM_Console: console->enable(); break; diff --git a/apps/openmw/mwgui/window_manager.hpp b/apps/openmw/mwgui/window_manager.hpp index 22fe973a59..aab3070358 100644 --- a/apps/openmw/mwgui/window_manager.hpp +++ b/apps/openmw/mwgui/window_manager.hpp @@ -77,6 +77,7 @@ namespace MWGui class MessageBoxManager; class CountDialog; class TradeWindow; + class SettingsWindow; struct ClassPoint { @@ -230,6 +231,7 @@ namespace MWGui BookWindow* mBookWindow; CountDialog* mCountDialog; TradeWindow* mTradeWindow; + SettingsWindow* mSettingsWindow; CharacterCreation* mCharGen; diff --git a/apps/openmw/mwinput/inputmanager.cpp b/apps/openmw/mwinput/inputmanager.cpp index 8f8f1e1ee2..8fd6a9c6b1 100644 --- a/apps/openmw/mwinput/inputmanager.cpp +++ b/apps/openmw/mwinput/inputmanager.cpp @@ -71,6 +71,8 @@ namespace MWInput A_ToggleFps, // Toggle FPS display (this is temporary) + A_Settings, // Temporary hotkey + A_LAST // Marker for the last item }; @@ -140,6 +142,16 @@ namespace MWInput windows.messageBox ("Screenshot saved", empty); } + void showSettings() + { + if (mDragDrop) + return; + + MWGui::GuiMode mode = windows.getMode(); + if (mode != MWGui::GM_Settings) + setGuiMode(MWGui::GM_Settings); + } + /* toggleInventory() is called when the user presses the button to toggle the inventory screen. */ void toggleInventory() { @@ -261,6 +273,8 @@ namespace MWInput "Ready hands"); disp->funcs.bind(A_ToggleFps, boost::bind(&InputImpl::toggleFps, this), "Toggle FPS display"); + disp->funcs.bind(A_Settings, boost::bind(&InputImpl::showSettings, this), + "Show settings window"); // Add the exit listener ogre.getRoot()->addFrameListener(&exit); @@ -308,6 +322,7 @@ namespace MWInput disp->bind(A_ToggleWeapon,KC_F); disp->bind(A_ToggleSpell,KC_R); disp->bind(A_ToggleFps, KC_F10); + disp->bind(A_Settings, KC_F2); // Key bindings for polled keys // NOTE: These keys are constantly being polled. Only add keys that must be checked each frame. diff --git a/files/mygui/CMakeLists.txt b/files/mygui/CMakeLists.txt index cacfb7c5a3..9f43f2d890 100644 --- a/files/mygui/CMakeLists.txt +++ b/files/mygui/CMakeLists.txt @@ -57,6 +57,7 @@ configure_file("${SDIR}/openmw_scroll_skin.xml" "${DDIR}/openmw_scroll_skin.xml" configure_file("${SDIR}/openmw_book_layout.xml" "${DDIR}/openmw_book_layout.xml" COPYONLY) configure_file("${SDIR}/openmw_count_window_layout.xml" "${DDIR}/openmw_count_window_layout.xml" COPYONLY) configure_file("${SDIR}/openmw_trade_window_layout.xml" "${DDIR}/openmw_trade_window_layout.xml" COPYONLY) +configure_file("${SDIR}/openmw_settings_window_layout.xml" "${DDIR}/openmw_settings_window_layout.xml" COPYONLY) configure_file("${SDIR}/atlas1.cfg" "${DDIR}/atlas1.cfg" COPYONLY) configure_file("${SDIR}/smallbars.png" "${DDIR}/smallbars.png" COPYONLY) configure_file("${SDIR}/transparent.png" "${DDIR}/transparent.png" COPYONLY) diff --git a/files/mygui/openmw_settings_window_layout.xml b/files/mygui/openmw_settings_window_layout.xml new file mode 100644 index 0000000000..eaf9191bc0 --- /dev/null +++ b/files/mygui/openmw_settings_window_layout.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + From 972c035e97dc0aac9b714685628f3910b5ddc546 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 22 May 2012 23:35:05 +0200 Subject: [PATCH 257/325] TabControl skin, settings window categories --- files/mygui/openmw_resources.xml | 15 +++++++++++++++ files/mygui/openmw_settings_window_layout.xml | 16 +++++++++++++++- 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/files/mygui/openmw_resources.xml b/files/mygui/openmw_resources.xml index 4c509ae13d..b47de005d4 100644 --- a/files/mygui/openmw_resources.xml +++ b/files/mygui/openmw_resources.xml @@ -113,6 +113,8 @@
+ + @@ -124,4 +126,17 @@ + + + + + + + + + + + + + diff --git a/files/mygui/openmw_settings_window_layout.xml b/files/mygui/openmw_settings_window_layout.xml index eaf9191bc0..387a8587e4 100644 --- a/files/mygui/openmw_settings_window_layout.xml +++ b/files/mygui/openmw_settings_window_layout.xml @@ -3,7 +3,21 @@ - + + + + + + + + + + + + + + + From 656a8f1be9fd3cf181de8140ba343778851e49c3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 23 May 2012 01:32:36 +0200 Subject: [PATCH 258/325] working menu transparency slider --- apps/openmw/mwgui/settingswindow.cpp | 38 ++++++++++++++++ apps/openmw/mwgui/settingswindow.hpp | 4 ++ apps/openmw/mwrender/renderingmanager.cpp | 24 ++++++++++ apps/openmw/mwrender/renderingmanager.hpp | 6 +++ apps/openmw/mwworld/world.cpp | 5 ++ apps/openmw/mwworld/world.hpp | 3 ++ files/mygui/CMakeLists.txt | 1 - files/mygui/openmw_list.skin.xml | 23 ++++++++++ files/mygui/openmw_resources.xml | 2 +- files/mygui/openmw_settings_window_layout.xml | 43 ++++++++++++++++-- files/mygui/transparent.png | Bin 150 -> 0 bytes files/settings-default.cfg | 4 ++ libs/openengine/ogre/renderer.cpp | 15 ++++++ libs/openengine/ogre/renderer.hpp | 4 ++ 14 files changed, 166 insertions(+), 6 deletions(-) delete mode 100644 files/mygui/transparent.png diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index 3641a63a40..af909ea8ca 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -1,5 +1,13 @@ #include "settingswindow.hpp" +#include +#include + +#include + +#include "../mwbase/environment.hpp" +#include "../mwworld/world.hpp" + #include "window_manager.hpp" namespace MWGui @@ -8,18 +16,48 @@ namespace MWGui WindowBase("openmw_settings_window_layout.xml", parWindowManager) { getWidget(mOkButton, "OkButton"); + getWidget(mResolutionList, "ResolutionList"); + getWidget(mMenuTransparencySlider, "MenuTransparencySlider"); + getWidget(mViewDistanceSlider, "ViewDistanceSlider"); mOkButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onOkButtonClicked); + mMenuTransparencySlider->eventScrollChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onSliderChangePosition); + mViewDistanceSlider->eventScrollChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onSliderChangePosition); center(); int okSize = mOkButton->getTextSize().width + 24; mOkButton->setCoord(mMainWidget->getWidth()-16-okSize, mOkButton->getTop(), okSize, mOkButton->getHeight()); + + // fill resolution list + Ogre::RenderSystem* rs = Ogre::Root::getSingleton().getRenderSystem(); + const Ogre::StringVector& videoModes = rs->getConfigOptions()["Video Mode"].possibleValues; + for (Ogre::StringVector::const_iterator it=videoModes.begin(); + it!=videoModes.end(); ++it) + { + mResolutionList->addItem(*it); + } + + // read settings + int menu_transparency = (mMenuTransparencySlider->getScrollRange()-1) * Settings::Manager::getFloat("menu transparency", "GUI"); + mMenuTransparencySlider->setScrollPosition(menu_transparency); + onSliderChangePosition(mMenuTransparencySlider, menu_transparency); } void SettingsWindow::onOkButtonClicked(MyGUI::Widget* _sender) { mWindowManager.setGuiMode(GM_Game); } + + void SettingsWindow::onSliderChangePosition(MyGUI::ScrollBar* scroller, size_t pos) + { + float val = pos / float(scroller->getScrollRange()-1); + if (scroller == mMenuTransparencySlider) + { + Settings::Manager::setFloat("menu transparency", "GUI", val); + } + + MWBase::Environment::get().getWorld()->processChangedSettings(Settings::Manager::apply()); + } } diff --git a/apps/openmw/mwgui/settingswindow.hpp b/apps/openmw/mwgui/settingswindow.hpp index e37c00f7ee..597f8dec16 100644 --- a/apps/openmw/mwgui/settingswindow.hpp +++ b/apps/openmw/mwgui/settingswindow.hpp @@ -17,8 +17,12 @@ namespace MWGui protected: MyGUI::Button* mOkButton; + MyGUI::ListBox* mResolutionList; + MyGUI::ScrollBar* mMenuTransparencySlider; + MyGUI::ScrollBar* mViewDistanceSlider; void onOkButtonClicked(MyGUI::Widget* _sender); + void onSliderChangePosition(MyGUI::ScrollBar* scroller, size_t pos); }; } diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 6d0b1b21c5..86c1f752c2 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -114,6 +114,8 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const mDebugging = new Debugging(mMwRoot, engine); mLocalMap = new MWRender::LocalMap(&mRendering, this); + + setMenuTransparency(Settings::Manager::getFloat("menu transparency", "GUI")); } RenderingManager::~RenderingManager () @@ -563,4 +565,26 @@ Compositors* RenderingManager::getCompositors() return mCompositors; } +void RenderingManager::processChangedSettings(const Settings::CategorySettingVector& settings) +{ + for (Settings::CategorySettingVector::const_iterator it=settings.begin(); + it != settings.end(); ++it) + { + if (it->second == "menu transparency" && it->first == "GUI") + { + setMenuTransparency(Settings::Manager::getFloat("menu transparency", "GUI")); + } + } +} + +void RenderingManager::setMenuTransparency(float val) +{ + Ogre::TexturePtr tex = Ogre::TextureManager::getSingleton().getByName("transparent.png"); + std::vector buffer; + buffer.resize(1); + buffer[0] = (int(255*val) << 24); + memcpy(tex->getBuffer()->lock(Ogre::HardwareBuffer::HBL_DISCARD), &buffer[0], 1*4); + tex->getBuffer()->unlock(); +} + } // namespace diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 5ef43a2e28..edee193f36 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -13,6 +13,8 @@ #include #include +#include + #include #include @@ -157,10 +159,14 @@ class RenderingManager: private RenderingInterface { ///< transform the specified bounding box (in world coordinates) into screen coordinates. /// @return packed vector4 (min_x, min_y, max_x, max_y) + void processChangedSettings(const Settings::CategorySettingVector& settings); + private: void setAmbientMode(); + void setMenuTransparency(float val); + bool mSunEnabled; SkyManager* mSkyManager; diff --git a/apps/openmw/mwworld/world.cpp b/apps/openmw/mwworld/world.cpp index c0107d9afe..772dc71cb3 100644 --- a/apps/openmw/mwworld/world.cpp +++ b/apps/openmw/mwworld/world.cpp @@ -1024,4 +1024,9 @@ namespace MWWorld mWorldScene->insertObject(object, cell); } + + void World::processChangedSettings(const Settings::CategorySettingVector& settings) + { + mRendering->processChangedSettings(settings); + } } diff --git a/apps/openmw/mwworld/world.hpp b/apps/openmw/mwworld/world.hpp index 1b0ad7fd82..e8391773b1 100644 --- a/apps/openmw/mwworld/world.hpp +++ b/apps/openmw/mwworld/world.hpp @@ -7,6 +7,7 @@ #include #include +#include #include "../mwrender/debugging.hpp" #include "../mwrender/renderingmanager.hpp" @@ -279,6 +280,8 @@ namespace MWWorld bool canPlaceObject(float cursorX, float cursorY); ///< @return true if it is possible to place on object at specified cursor location + + void processChangedSettings(const Settings::CategorySettingVector& settings); }; } diff --git a/files/mygui/CMakeLists.txt b/files/mygui/CMakeLists.txt index 9f43f2d890..90a0c1fceb 100644 --- a/files/mygui/CMakeLists.txt +++ b/files/mygui/CMakeLists.txt @@ -60,7 +60,6 @@ configure_file("${SDIR}/openmw_trade_window_layout.xml" "${DDIR}/openmw_trade_wi configure_file("${SDIR}/openmw_settings_window_layout.xml" "${DDIR}/openmw_settings_window_layout.xml" COPYONLY) configure_file("${SDIR}/atlas1.cfg" "${DDIR}/atlas1.cfg" COPYONLY) configure_file("${SDIR}/smallbars.png" "${DDIR}/smallbars.png" COPYONLY) -configure_file("${SDIR}/transparent.png" "${DDIR}/transparent.png" COPYONLY) configure_file("${SDIR}/EBGaramond-Regular.ttf" "${DDIR}/EBGaramond-Regular.ttf" COPYONLY) configure_file("${SDIR}/Obliviontt.zip" "${DDIR}/Obliviontt.zip" COPYONLY) configure_file("${SDIR}/VeraMono.ttf" "${DDIR}/VeraMono.ttf" COPYONLY) diff --git a/files/mygui/openmw_list.skin.xml b/files/mygui/openmw_list.skin.xml index e1fbc49b63..64435451ad 100644 --- a/files/mygui/openmw_list.skin.xml +++ b/files/mygui/openmw_list.skin.xml @@ -151,6 +151,28 @@ + + + + + + + + + + + + + + + + + + + + + + @@ -170,6 +192,7 @@ + diff --git a/files/mygui/openmw_resources.xml b/files/mygui/openmw_resources.xml index b47de005d4..e96aeb918e 100644 --- a/files/mygui/openmw_resources.xml +++ b/files/mygui/openmw_resources.xml @@ -130,7 +130,7 @@ - + diff --git a/files/mygui/openmw_settings_window_layout.xml b/files/mygui/openmw_settings_window_layout.xml index 387a8587e4..9c6716ff0b 100644 --- a/files/mygui/openmw_settings_window_layout.xml +++ b/files/mygui/openmw_settings_window_layout.xml @@ -6,17 +6,52 @@ - + + + + + + + + + + + + + + + + - + - + - + + + + + + + + + + + + + + + + + + + + + diff --git a/files/mygui/transparent.png b/files/mygui/transparent.png deleted file mode 100644 index 32d2ed1975611dbfc9baf5550b92118fee2d73b8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 150 zcmeAS@N?(olHy`uVBq!ia0vp^93afW1|*O0@9PFqjKx9jP7LeL$-D$|*pj^6T^Rm@ z;DWu&Cj&(|3p^r=85p>QL70(Y)*K0-AbW|YuPggaCRPzfaZ{P!_CO&qPZ!4!iOb0; m2?-I$8rTgC1sD!HGcs&^z_3mHan=i<3I @@ -107,6 +110,18 @@ void OgreRenderer::createWindow(const std::string &title, const WindowSettings& params.insert(std::make_pair("vsync", settings.vsync ? "true" : "false")); mWindow = mRoot->createRenderWindow(title, settings.window_x, settings.window_y, settings.fullscreen, ¶ms); + + // create the semi-transparent black background texture used by the GUI. + // has to be created in code with TU_DYNAMIC_WRITE_ONLY_DISCARDABLE param + // so that it can be modified at runtime. + mTransparentBGTexture = Ogre::TextureManager::getSingleton().createManual( + "transparent.png", + Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, + Ogre::TEX_TYPE_2D, + 1, 1, + 0, + Ogre::PF_A8R8G8B8, + Ogre::TU_DYNAMIC_WRITE_ONLY_DISCARDABLE); } void OgreRenderer::createScene(const std::string camName, float fov, float nearClip) diff --git a/libs/openengine/ogre/renderer.hpp b/libs/openengine/ogre/renderer.hpp index 7dc539e27e..50fe640151 100644 --- a/libs/openengine/ogre/renderer.hpp +++ b/libs/openengine/ogre/renderer.hpp @@ -24,6 +24,8 @@ # include "OgreD3D9Plugin.h" #endif +#include "OgreTexture.h" + namespace Ogre { class Root; @@ -71,6 +73,8 @@ namespace OEngine Fader* mFader; bool logging; + Ogre::TexturePtr mTransparentBGTexture; + public: OgreRenderer() : mRoot(NULL) From 689cf7ce054554354a08c49dedabc51fb98f7dd6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 23 May 2012 05:28:25 +0200 Subject: [PATCH 259/325] ConfirmationDialog --- apps/openmw/CMakeLists.txt | 1 + apps/openmw/mwgui/confirmationdialog.cpp | 68 ++++++++++++++++++ apps/openmw/mwgui/confirmationdialog.hpp | 34 +++++++++ apps/openmw/mwgui/countdialog.cpp | 3 - apps/openmw/mwgui/settingswindow.cpp | 69 ++++++++++++++++++- apps/openmw/mwgui/settingswindow.hpp | 4 ++ apps/openmw/mwgui/window_manager.cpp | 5 ++ apps/openmw/mwgui/window_manager.hpp | 3 + components/settings/settings.cpp | 4 ++ files/mygui/CMakeLists.txt | 1 + .../openmw_confirmation_dialog_layout.xml | 25 +++++++ files/mygui/openmw_count_window_layout.xml | 8 ++- files/mygui/openmw_settings_window_layout.xml | 5 +- 13 files changed, 222 insertions(+), 8 deletions(-) create mode 100644 apps/openmw/mwgui/confirmationdialog.cpp create mode 100644 apps/openmw/mwgui/confirmationdialog.hpp create mode 100644 files/mygui/openmw_confirmation_dialog_layout.xml diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index fd2fdf5754..a3c147b946 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -28,6 +28,7 @@ add_openmw_dir (mwgui dialogue_history window_base stats_window messagebox journalwindow charactercreation map_window window_pinnable_base cursorreplace tooltips scrollwindow bookwindow list formatting itemwidget inventorywindow container hud countdialog tradewindow settingswindow + confirmationdialog ) add_openmw_dir (mwdialogue diff --git a/apps/openmw/mwgui/confirmationdialog.cpp b/apps/openmw/mwgui/confirmationdialog.cpp new file mode 100644 index 0000000000..a54bdb1d8d --- /dev/null +++ b/apps/openmw/mwgui/confirmationdialog.cpp @@ -0,0 +1,68 @@ +#include "confirmationdialog.hpp" + +#include + +#include "../mwbase/environment.hpp" +#include "../mwworld/world.hpp" + +namespace MWGui +{ + ConfirmationDialog::ConfirmationDialog(WindowManager& parWindowManager) : + WindowBase("openmw_confirmation_dialog_layout.xml", parWindowManager) + { + getWidget(mMessage, "Message"); + getWidget(mOkButton, "OkButton"); + getWidget(mCancelButton, "CancelButton"); + + mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ConfirmationDialog::onCancelButtonClicked); + mOkButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ConfirmationDialog::onOkButtonClicked); + } + + void ConfirmationDialog::open(const std::string& message) + { + setVisible(true); + + mMessage->setCaptionWithReplacing(message); + + int height = mMessage->getTextSize().height + 72; + + mMainWidget->setSize(mMainWidget->getWidth(), height); + + mMessage->setSize(mMessage->getWidth(), mMessage->getTextSize().height+24); + + center(); + + // make other gui elements inaccessible while this dialog is open + MyGUI::InputManager::getInstance().addWidgetModal(mMainWidget); + + int okButtonWidth = mOkButton->getTextSize().width + 24; + mOkButton->setCoord(mMainWidget->getWidth() - 30 - okButtonWidth, + mOkButton->getTop(), + okButtonWidth, + mOkButton->getHeight()); + + int cancelButtonWidth = mCancelButton->getTextSize().width + 24; + mCancelButton->setCoord(mMainWidget->getWidth() - 30 - okButtonWidth - cancelButtonWidth - 8, + mCancelButton->getTop(), + cancelButtonWidth, + mCancelButton->getHeight()); + } + + void ConfirmationDialog::onCancelButtonClicked(MyGUI::Widget* _sender) + { + close(); + } + + void ConfirmationDialog::onOkButtonClicked(MyGUI::Widget* _sender) + { + eventOkClicked(); + + close(); + } + + void ConfirmationDialog::close() + { + setVisible(false); + MyGUI::InputManager::getInstance().removeWidgetModal(mMainWidget); + } +} diff --git a/apps/openmw/mwgui/confirmationdialog.hpp b/apps/openmw/mwgui/confirmationdialog.hpp new file mode 100644 index 0000000000..a20034171b --- /dev/null +++ b/apps/openmw/mwgui/confirmationdialog.hpp @@ -0,0 +1,34 @@ +#ifndef MWGUI_CONFIRMATIONDIALOG_H +#define MWGUI_CONFIRMATIONDIALOG_H + +#include "window_base.hpp" + +namespace MWGui +{ + class ConfirmationDialog : public WindowBase + { + public: + ConfirmationDialog(WindowManager& parWindowManager); + void open(const std::string& message); + + typedef MyGUI::delegates::CMultiDelegate0 EventHandle_Void; + + /** Event : Ok button was clicked.\n + signature : void method()\n + */ + EventHandle_Void eventOkClicked; + + private: + MyGUI::EditBox* mMessage; + MyGUI::Button* mOkButton; + MyGUI::Button* mCancelButton; + + void onCancelButtonClicked(MyGUI::Widget* _sender); + void onOkButtonClicked(MyGUI::Widget* _sender); + + void close(); + }; + +} + +#endif diff --git a/apps/openmw/mwgui/countdialog.cpp b/apps/openmw/mwgui/countdialog.cpp index 16e3f9aab3..e0a9bb9082 100644 --- a/apps/openmw/mwgui/countdialog.cpp +++ b/apps/openmw/mwgui/countdialog.cpp @@ -17,9 +17,6 @@ namespace MWGui getWidget(mOkButton, "OkButton"); getWidget(mCancelButton, "CancelButton"); - mOkButton->setCaption(MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sOk")->str); - mCancelButton->setCaption(MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sCancel")->str); - mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &CountDialog::onCancelButtonClicked); mOkButton->eventMouseButtonClick += MyGUI::newDelegate(this, &CountDialog::onOkButtonClicked); mItemEdit->eventEditTextChange += MyGUI::newDelegate(this, &CountDialog::onEditTextChange); diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index af909ea8ca..6eaf31ce96 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -2,6 +2,9 @@ #include #include +#include + +#include #include @@ -9,6 +12,7 @@ #include "../mwworld/world.hpp" #include "window_manager.hpp" +#include "confirmationdialog.hpp" namespace MWGui { @@ -19,10 +23,13 @@ namespace MWGui getWidget(mResolutionList, "ResolutionList"); getWidget(mMenuTransparencySlider, "MenuTransparencySlider"); getWidget(mViewDistanceSlider, "ViewDistanceSlider"); + getWidget(mFullscreenButton, "FullscreenButton"); mOkButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onOkButtonClicked); + mFullscreenButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onButtonToggled); mMenuTransparencySlider->eventScrollChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onSliderChangePosition); mViewDistanceSlider->eventScrollChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onSliderChangePosition); + mResolutionList->eventListChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onResolutionSelected); center(); @@ -42,7 +49,15 @@ namespace MWGui // read settings int menu_transparency = (mMenuTransparencySlider->getScrollRange()-1) * Settings::Manager::getFloat("menu transparency", "GUI"); mMenuTransparencySlider->setScrollPosition(menu_transparency); - onSliderChangePosition(mMenuTransparencySlider, menu_transparency); + + float val = (Settings::Manager::getFloat("max viewing distance", "Viewing distance")-2000)/(5600-2000); + int viewdist = (mViewDistanceSlider->getScrollRange()-1) * val; + mViewDistanceSlider->setScrollPosition(viewdist); + + std::string on = mWindowManager.getGameSettingString("sOn", "On"); + std::string off = mWindowManager.getGameSettingString("sOff", "On"); + + mFullscreenButton->setCaption(Settings::Manager::getBool("fullscreen", "Video") ? on : off); } void SettingsWindow::onOkButtonClicked(MyGUI::Widget* _sender) @@ -50,6 +65,54 @@ namespace MWGui mWindowManager.setGuiMode(GM_Game); } + void SettingsWindow::onResolutionSelected(MyGUI::ListBox* _sender, size_t index) + { + if (index == MyGUI::ITEM_NONE) + return; + + ConfirmationDialog* dialog = mWindowManager.getConfirmationDialog(); + dialog->open("#{sNotifyMessage67}"); + dialog->eventOkClicked.clear(); + dialog->eventOkClicked += MyGUI::newDelegate(this, &SettingsWindow::onResolutionAccept); + } + + void SettingsWindow::onResolutionAccept() + { + std::string resStr = mResolutionList->getItemNameAt(mResolutionList->getIndexSelected()); + size_t xPos = resStr.find("x"); + std::string resXStr = resStr.substr(0, xPos-1); + Ogre::StringUtil::trim(resXStr); + std::string resYStr = resStr.substr(xPos+2, resStr.size()-(xPos+2)); + Ogre::StringUtil::trim(resYStr); + int resX = boost::lexical_cast(resXStr); + int resY = boost::lexical_cast(resYStr); + + Settings::Manager::setInt("resolution x", "Video", resX); + Settings::Manager::setInt("resolution y", "Video", resY); + + MWBase::Environment::get().getWorld()->processChangedSettings(Settings::Manager::apply()); + } + + void SettingsWindow::onButtonToggled(MyGUI::Widget* _sender) + { + std::string on = mWindowManager.getGameSettingString("sOn", "On"); + std::string off = mWindowManager.getGameSettingString("sOff", "On"); + bool newState; + if (_sender->castType()->getCaption() == on) + { + _sender->castType()->setCaption(off); + newState = false; + } + else + { + _sender->castType()->setCaption(on); + newState = true; + } + + if (_sender == mFullscreenButton) + Settings::Manager::setBool("fullscreen", "Video", newState); + } + void SettingsWindow::onSliderChangePosition(MyGUI::ScrollBar* scroller, size_t pos) { float val = pos / float(scroller->getScrollRange()-1); @@ -57,6 +120,10 @@ namespace MWGui { Settings::Manager::setFloat("menu transparency", "GUI", val); } + else if (scroller == mViewDistanceSlider) + { + Settings::Manager::setFloat("max viewing distance", "Viewing distance", (1-val) * 2000 + val * 5600); + } MWBase::Environment::get().getWorld()->processChangedSettings(Settings::Manager::apply()); } diff --git a/apps/openmw/mwgui/settingswindow.hpp b/apps/openmw/mwgui/settingswindow.hpp index 597f8dec16..785b0c9b14 100644 --- a/apps/openmw/mwgui/settingswindow.hpp +++ b/apps/openmw/mwgui/settingswindow.hpp @@ -18,11 +18,15 @@ namespace MWGui protected: MyGUI::Button* mOkButton; MyGUI::ListBox* mResolutionList; + MyGUI::Button* mFullscreenButton; MyGUI::ScrollBar* mMenuTransparencySlider; MyGUI::ScrollBar* mViewDistanceSlider; void onOkButtonClicked(MyGUI::Widget* _sender); void onSliderChangePosition(MyGUI::ScrollBar* scroller, size_t pos); + void onButtonToggled(MyGUI::Widget* _sender); + void onResolutionSelected(MyGUI::ListBox* _sender, size_t index); + void onResolutionAccept(); }; } diff --git a/apps/openmw/mwgui/window_manager.cpp b/apps/openmw/mwgui/window_manager.cpp index 4bb34cf244..09ea6543a7 100644 --- a/apps/openmw/mwgui/window_manager.cpp +++ b/apps/openmw/mwgui/window_manager.cpp @@ -17,6 +17,7 @@ #include "countdialog.hpp" #include "tradewindow.hpp" #include "settingswindow.hpp" +#include "confirmationdialog.hpp" #include "../mwmechanics/mechanicsmanager.hpp" #include "../mwinput/inputmanager.hpp" @@ -52,6 +53,7 @@ WindowManager::WindowManager( , mCountDialog(NULL) , mTradeWindow(NULL) , mSettingsWindow(NULL) + , mConfirmationDialog(NULL) , mCharGen(NULL) , playerClass() , playerName() @@ -121,6 +123,7 @@ WindowManager::WindowManager( mBookWindow = new BookWindow(*this); mCountDialog = new CountDialog(*this); mSettingsWindow = new SettingsWindow(*this); + mConfirmationDialog = new ConfirmationDialog(*this); // The HUD is always on hud->setVisible(true); @@ -161,6 +164,8 @@ WindowManager::~WindowManager() delete mBookWindow; delete mScrollWindow; delete mTradeWindow; + delete mSettingsWindow; + delete mConfirmationDialog; cleanupGarbage(); } diff --git a/apps/openmw/mwgui/window_manager.hpp b/apps/openmw/mwgui/window_manager.hpp index aab3070358..9ccc42b1e9 100644 --- a/apps/openmw/mwgui/window_manager.hpp +++ b/apps/openmw/mwgui/window_manager.hpp @@ -78,6 +78,7 @@ namespace MWGui class CountDialog; class TradeWindow; class SettingsWindow; + class ConfirmationDialog; struct ClassPoint { @@ -140,6 +141,7 @@ namespace MWGui MWGui::BookWindow* getBookWindow() {return mBookWindow;} MWGui::ScrollWindow* getScrollWindow() {return mScrollWindow;} MWGui::CountDialog* getCountDialog() {return mCountDialog;} + MWGui::ConfirmationDialog* getConfirmationDialog() {return mConfirmationDialog;} MWGui::TradeWindow* getTradeWindow() {return mTradeWindow;} MyGUI::Gui* getGui() const { return gui; } @@ -232,6 +234,7 @@ namespace MWGui CountDialog* mCountDialog; TradeWindow* mTradeWindow; SettingsWindow* mSettingsWindow; + ConfirmationDialog* mConfirmationDialog; CharacterCreation* mCharGen; diff --git a/components/settings/settings.cpp b/components/settings/settings.cpp index 28201eda2a..9b941e2534 100644 --- a/components/settings/settings.cpp +++ b/components/settings/settings.cpp @@ -131,7 +131,11 @@ void Manager::setString (const std::string& setting, const std::string& category } } else + { + if (mDefaultFile.getSetting(setting, category) != value) + mChangedSettings.push_back(std::make_pair(category, setting)); mNewSettings[s] = value; + } } } diff --git a/files/mygui/CMakeLists.txt b/files/mygui/CMakeLists.txt index 90a0c1fceb..89ebd8f948 100644 --- a/files/mygui/CMakeLists.txt +++ b/files/mygui/CMakeLists.txt @@ -58,6 +58,7 @@ configure_file("${SDIR}/openmw_book_layout.xml" "${DDIR}/openmw_book_layout.xml" configure_file("${SDIR}/openmw_count_window_layout.xml" "${DDIR}/openmw_count_window_layout.xml" COPYONLY) configure_file("${SDIR}/openmw_trade_window_layout.xml" "${DDIR}/openmw_trade_window_layout.xml" COPYONLY) configure_file("${SDIR}/openmw_settings_window_layout.xml" "${DDIR}/openmw_settings_window_layout.xml" COPYONLY) +configure_file("${SDIR}/openmw_confirmation_dialog_layout.xml" "${DDIR}/openmw_confirmation_dialog_layout.xml" COPYONLY) configure_file("${SDIR}/atlas1.cfg" "${DDIR}/atlas1.cfg" COPYONLY) configure_file("${SDIR}/smallbars.png" "${DDIR}/smallbars.png" COPYONLY) configure_file("${SDIR}/EBGaramond-Regular.ttf" "${DDIR}/EBGaramond-Regular.ttf" COPYONLY) diff --git a/files/mygui/openmw_confirmation_dialog_layout.xml b/files/mygui/openmw_confirmation_dialog_layout.xml new file mode 100644 index 0000000000..7b8bd2a1fd --- /dev/null +++ b/files/mygui/openmw_confirmation_dialog_layout.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/mygui/openmw_count_window_layout.xml b/files/mygui/openmw_count_window_layout.xml index 38ba7644f6..ae6635dff3 100644 --- a/files/mygui/openmw_count_window_layout.xml +++ b/files/mygui/openmw_count_window_layout.xml @@ -20,8 +20,12 @@ - - + + + + + + diff --git a/files/mygui/openmw_settings_window_layout.xml b/files/mygui/openmw_settings_window_layout.xml index 9c6716ff0b..2fa332d9a8 100644 --- a/files/mygui/openmw_settings_window_layout.xml +++ b/files/mygui/openmw_settings_window_layout.xml @@ -34,9 +34,10 @@ - - + + + From 7ebbc099b37024d4aee29da8f2ac4b4483efc6b2 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 23 May 2012 12:23:35 +0200 Subject: [PATCH 260/325] allow stacking gui modes --- apps/openmw/engine.cpp | 8 +- apps/openmw/mwdialogue/dialoguemanager.cpp | 4 +- apps/openmw/mwgui/bookwindow.cpp | 9 +- apps/openmw/mwgui/charactercreation.cpp | 118 ++++++++++++++------- apps/openmw/mwgui/charactercreation.hpp | 1 - apps/openmw/mwgui/container.cpp | 4 +- apps/openmw/mwgui/dialogue.cpp | 16 ++- apps/openmw/mwgui/dialogue.hpp | 2 - apps/openmw/mwgui/messagebox.cpp | 1 - apps/openmw/mwgui/mode.hpp | 1 - apps/openmw/mwgui/scrollwindow.cpp | 9 +- apps/openmw/mwgui/tradewindow.cpp | 4 +- apps/openmw/mwgui/window_manager.cpp | 69 ++++++------ apps/openmw/mwgui/window_manager.hpp | 24 ++--- apps/openmw/mwinput/inputmanager.cpp | 73 ++++++------- apps/openmw/mwinput/inputmanager.hpp | 4 +- apps/openmw/mwscript/guiextensions.cpp | 2 +- apps/openmw/mwworld/actionopen.cpp | 2 +- apps/openmw/mwworld/actionread.cpp | 4 +- 19 files changed, 194 insertions(+), 161 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 85b0557b1a..412050ff21 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -105,7 +105,7 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt) // frame. // passing of time - if (MWBase::Environment::get().getWindowManager()->getMode()==MWGui::GM_Game) + if (!MWBase::Environment::get().getWindowManager()->isGuiMode()) MWBase::Environment::get().getWorld()->advanceTime ( mEnvironment.getFrameDuration()*MWBase::Environment::get().getWorld()->getTimeScaleFactor()/3600); @@ -116,9 +116,9 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt) // update actors std::vector > movement; MWBase::Environment::get().getMechanicsManager()->update (movement, mEnvironment.getFrameDuration(), - MWBase::Environment::get().getWindowManager()->getMode()!=MWGui::GM_Game); + MWBase::Environment::get().getWindowManager()->isGuiMode()); - if (MWBase::Environment::get().getWindowManager()->getMode()==MWGui::GM_Game) + if (!MWBase::Environment::get().getWindowManager()->isGuiMode()) MWBase::Environment::get().getWorld()->doPhysics (movement, mEnvironment.getFrameDuration()); // update world @@ -413,7 +413,7 @@ void OMW::Engine::go() void OMW::Engine::activate() { - if (MWBase::Environment::get().getWindowManager()->getMode()!=MWGui::GM_Game) + if (MWBase::Environment::get().getWindowManager()->isGuiMode()) return; std::string handle = MWBase::Environment::get().getWorld()->getFacedHandle(); diff --git a/apps/openmw/mwdialogue/dialoguemanager.cpp b/apps/openmw/mwdialogue/dialoguemanager.cpp index af589469e7..716f472a0e 100644 --- a/apps/openmw/mwdialogue/dialoguemanager.cpp +++ b/apps/openmw/mwdialogue/dialoguemanager.cpp @@ -635,7 +635,7 @@ namespace MWDialogue actorKnownTopics.clear(); //initialise the GUI - MWBase::Environment::get().getInputManager()->setGuiMode(MWGui::GM_Dialogue); + MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Dialogue); MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow(); win->startDialogue(actor, MWWorld::Class::get (actor).getName (actor)); @@ -843,7 +843,7 @@ namespace MWDialogue void DialogueManager::goodbyeSelected() { - MWBase::Environment::get().getInputManager()->setGuiMode(MWGui::GM_Game); + MWBase::Environment::get().getWindowManager()->popGuiMode(); } void DialogueManager::questionAnswered(std::string answere) diff --git a/apps/openmw/mwgui/bookwindow.cpp b/apps/openmw/mwgui/bookwindow.cpp index c6411175d1..f1873b5508 100644 --- a/apps/openmw/mwgui/bookwindow.cpp +++ b/apps/openmw/mwgui/bookwindow.cpp @@ -1,13 +1,14 @@ #include "bookwindow.hpp" -#include "formatting.hpp" +#include #include "../mwbase/environment.hpp" #include "../mwinput/inputmanager.hpp" #include "../mwsound/soundmanager.hpp" #include "../mwworld/actiontake.hpp" -#include +#include "formatting.hpp" +#include "window_manager.hpp" using namespace MWGui; @@ -91,7 +92,7 @@ void BookWindow::onCloseButtonClicked (MyGUI::Widget* _sender) // no 3d sounds because the object could be in a container. MWBase::Environment::get().getSoundManager()->playSound ("book close", 1.0, 1.0); - MWBase::Environment::get().getInputManager()->setGuiMode(MWGui::GM_Game); + mWindowManager.popGuiMode(); } void BookWindow::onTakeButtonClicked (MyGUI::Widget* _sender) @@ -101,7 +102,7 @@ void BookWindow::onTakeButtonClicked (MyGUI::Widget* _sender) MWWorld::ActionTake take(mBook); take.execute(); - MWBase::Environment::get().getInputManager()->setGuiMode (GM_Game); + mWindowManager.popGuiMode(); } void BookWindow::onNextPageButtonClicked (MyGUI::Widget* _sender) diff --git a/apps/openmw/mwgui/charactercreation.cpp b/apps/openmw/mwgui/charactercreation.cpp index afb168d321..691fd4a917 100644 --- a/apps/openmw/mwgui/charactercreation.cpp +++ b/apps/openmw/mwgui/charactercreation.cpp @@ -110,7 +110,6 @@ using namespace MWGui; CharacterCreation::CharacterCreation(WindowManager* _wm) : mNameDialog(0) , mRaceDialog(0) - , mDialogueWindow(0) , mClassChoiceDialog(0) , mGenerateClassQuestionDialog(0) , mGenerateClassResultDialog(0) @@ -253,7 +252,7 @@ void CharacterCreation::onReviewDialogDone(WindowBase* parWindow) if (mReviewDialog) mWM->removeDialog(mReviewDialog); - mWM->setGuiMode(GM_Game); + mWM->popGuiMode(); } void CharacterCreation::onReviewDialogBack() @@ -261,7 +260,7 @@ void CharacterCreation::onReviewDialogBack() if (mReviewDialog) mWM->removeDialog(mReviewDialog); - mWM->setGuiMode(GM_Birth); + mWM->pushGuiMode(GM_Birth); } void CharacterCreation::onReviewActivateDialog(int parDialog) @@ -270,19 +269,21 @@ void CharacterCreation::onReviewActivateDialog(int parDialog) mWM->removeDialog(mReviewDialog); mCreationStage = CSE_ReviewNext; + mWM->popGuiMode(); + switch(parDialog) { case ReviewDialog::NAME_DIALOG: - mWM->setGuiMode(GM_Name); + mWM->pushGuiMode(GM_Name); break; case ReviewDialog::RACE_DIALOG: - mWM->setGuiMode(GM_Race); + mWM->pushGuiMode(GM_Race); break; case ReviewDialog::CLASS_DIALOG: - mWM->setGuiMode(GM_Class); + mWM->pushGuiMode(GM_Class); break; case ReviewDialog::BIRTHSIGN_DIALOG: - mWM->setGuiMode(GM_Birth); + mWM->pushGuiMode(GM_Birth); }; } @@ -304,13 +305,19 @@ void CharacterCreation::onPickClassDialogDone(WindowBase* parWindow) //TODO This bit gets repeated a few times; wrap it in a function if (mCreationStage == CSE_ReviewNext) - mWM->setGuiMode(GM_Review); + { + mWM->popGuiMode(); + mWM->pushGuiMode(GM_Review); + } else if (mCreationStage >= CSE_ClassChosen) - mWM->setGuiMode(GM_Birth); + { + mWM->popGuiMode(); + mWM->pushGuiMode(GM_Birth); + } else { mCreationStage = CSE_ClassChosen; - mWM->setGuiMode(GM_Game); + mWM->popGuiMode(); } } @@ -324,7 +331,8 @@ void CharacterCreation::onPickClassDialogBack() mWM->removeDialog(mPickClassDialog); } - mWM->setGuiMode(GM_Class); + mWM->popGuiMode(); + mWM->pushGuiMode(GM_Class); } void CharacterCreation::onClassChoice(int _index) @@ -334,19 +342,21 @@ void CharacterCreation::onClassChoice(int _index) mWM->removeDialog(mClassChoiceDialog); } + mWM->popGuiMode(); + switch(_index) { case ClassChoiceDialog::Class_Generate: - mWM->setGuiMode(GM_ClassGenerate); + mWM->pushGuiMode(GM_ClassGenerate); break; case ClassChoiceDialog::Class_Pick: - mWM->setGuiMode(GM_ClassPick); + mWM->pushGuiMode(GM_ClassPick); break; case ClassChoiceDialog::Class_Create: - mWM->setGuiMode(GM_ClassCreate); + mWM->pushGuiMode(GM_ClassCreate); break; case ClassChoiceDialog::Class_Back: - mWM->setGuiMode(GM_Race); + mWM->pushGuiMode(GM_Race); break; }; @@ -363,13 +373,19 @@ void CharacterCreation::onNameDialogDone(WindowBase* parWindow) } if (mCreationStage == CSE_ReviewNext) - mWM->setGuiMode(GM_Review); + { + mWM->popGuiMode(); + mWM->pushGuiMode(GM_Review); + } else if (mCreationStage >= CSE_NameChosen) - mWM->setGuiMode(GM_Race); + { + mWM->popGuiMode(); + mWM->pushGuiMode(GM_Race); + } else { mCreationStage = CSE_NameChosen; - mWM->setGuiMode(GM_Game); + mWM->popGuiMode(); } } @@ -383,7 +399,8 @@ void CharacterCreation::onRaceDialogBack() mWM->removeDialog(mRaceDialog); } - mWM->setGuiMode(GM_Name); + mWM->popGuiMode(); + mWM->pushGuiMode(GM_Name); } void CharacterCreation::onRaceDialogDone(WindowBase* parWindow) @@ -398,13 +415,19 @@ void CharacterCreation::onRaceDialogDone(WindowBase* parWindow) } if (mCreationStage == CSE_ReviewNext) - mWM->setGuiMode(GM_Review); - else if(mCreationStage >= CSE_RaceChosen) - mWM->setGuiMode(GM_Class); + { + mWM->popGuiMode(); + mWM->pushGuiMode(GM_Review); + } + else if (mCreationStage >= CSE_NameChosen) + { + mWM->popGuiMode(); + mWM->pushGuiMode(GM_Class); + } else { - mCreationStage = CSE_RaceChosen; - mWM->setGuiMode(GM_Game); + mCreationStage = CSE_NameChosen; + mWM->popGuiMode(); } } @@ -419,11 +442,14 @@ void CharacterCreation::onBirthSignDialogDone(WindowBase* parWindow) } if (mCreationStage >= CSE_BirthSignChosen) - mWM->setGuiMode(GM_Review); + { + mWM->popGuiMode(); + mWM->pushGuiMode(GM_Review); + } else { mCreationStage = CSE_BirthSignChosen; - mWM->setGuiMode(GM_Game); + mWM->popGuiMode(); } } @@ -435,7 +461,8 @@ void CharacterCreation::onBirthSignDialogBack() mWM->removeDialog(mBirthSignDialog); } - mWM->setGuiMode(GM_Class); + mWM->popGuiMode(); + mWM->pushGuiMode(GM_Class); } void CharacterCreation::onCreateClassDialogDone(WindowBase* parWindow) @@ -470,13 +497,19 @@ void CharacterCreation::onCreateClassDialogDone(WindowBase* parWindow) } if (mCreationStage == CSE_ReviewNext) - mWM->setGuiMode(GM_Review); + { + mWM->popGuiMode(); + mWM->pushGuiMode(GM_Review); + } else if (mCreationStage >= CSE_ClassChosen) - mWM->setGuiMode(GM_Birth); + { + mWM->popGuiMode(); + mWM->pushGuiMode(GM_Birth); + } else { mCreationStage = CSE_ClassChosen; - mWM->setGuiMode(GM_Game); + mWM->popGuiMode(); } } @@ -485,7 +518,8 @@ void CharacterCreation::onCreateClassDialogBack() if (mCreateClassDialog) mWM->removeDialog(mCreateClassDialog); - mWM->setGuiMode(GM_Class); + mWM->popGuiMode(); + mWM->pushGuiMode(GM_Class); } void CharacterCreation::onClassQuestionChosen(int _index) @@ -496,7 +530,8 @@ void CharacterCreation::onClassQuestionChosen(int _index) mWM->removeDialog(mGenerateClassQuestionDialog); if (_index < 0 || _index >= 3) { - mWM->setGuiMode(GM_Class); + mWM->popGuiMode(); + mWM->pushGuiMode(GM_Class); return; } @@ -581,7 +616,8 @@ void CharacterCreation::showClassQuestionDialog() if (mGenerateClassStep > sGenerateClassSteps.size()) { - mWM->setGuiMode(GM_Class); + mWM->popGuiMode(); + mWM->pushGuiMode(GM_Class); return; } @@ -610,7 +646,8 @@ void CharacterCreation::onGenerateClassBack() mWM->removeDialog(mGenerateClassResultDialog); MWBase::Environment::get().getMechanicsManager()->setPlayerClass(mGenerateClass); - mWM->setGuiMode(GM_Class); + mWM->popGuiMode(); + mWM->pushGuiMode(GM_Class); } void CharacterCreation::onGenerateClassDone(WindowBase* parWindow) @@ -620,13 +657,19 @@ void CharacterCreation::onGenerateClassDone(WindowBase* parWindow) MWBase::Environment::get().getMechanicsManager()->setPlayerClass(mGenerateClass); if (mCreationStage == CSE_ReviewNext) - mWM->setGuiMode(GM_Review); + { + mWM->popGuiMode(); + mWM->pushGuiMode(GM_Review); + } else if (mCreationStage >= CSE_ClassChosen) - mWM->setGuiMode(GM_Birth); + { + mWM->popGuiMode(); + mWM->pushGuiMode(GM_Birth); + } else { mCreationStage = CSE_ClassChosen; - mWM->setGuiMode(GM_Game); + mWM->popGuiMode(); } } @@ -634,7 +677,6 @@ CharacterCreation::~CharacterCreation() { delete mNameDialog; delete mRaceDialog; - delete mDialogueWindow; delete mClassChoiceDialog; delete mGenerateClassQuestionDialog; delete mGenerateClassResultDialog; diff --git a/apps/openmw/mwgui/charactercreation.hpp b/apps/openmw/mwgui/charactercreation.hpp index 222754cdc3..dfb07853e3 100644 --- a/apps/openmw/mwgui/charactercreation.hpp +++ b/apps/openmw/mwgui/charactercreation.hpp @@ -46,7 +46,6 @@ namespace MWGui //Dialogs TextInputDialog* mNameDialog; RaceDialog* mRaceDialog; - DialogueWindow* mDialogueWindow; ClassChoiceDialog* mClassChoiceDialog; InfoBoxDialog* mGenerateClassQuestionDialog; GenerateClassResultDialog* mGenerateClassResultDialog; diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index be21987ef9..8ac876c078 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -636,7 +636,7 @@ void ContainerWindow::onCloseButtonClicked(MyGUI::Widget* _sender) { if(mDragAndDrop == NULL || !mDragAndDrop->mIsOnDragAndDrop) { - MWBase::Environment::get().getWindowManager()->setGuiMode(GM_Game); + MWBase::Environment::get().getWindowManager()->popGuiMode(); } } @@ -667,6 +667,6 @@ void ContainerWindow::onTakeAllButtonClicked(MyGUI::Widget* _sender) containerStore.clear(); - MWBase::Environment::get().getWindowManager()->setGuiMode(GM_Game); + MWBase::Environment::get().getWindowManager()->popGuiMode(); } } diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 53ab98aeb0..8a68ff6663 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -112,15 +112,6 @@ void DialogueWindow::onMouseWheel(MyGUI::Widget* _sender, int _rel) history->setVScrollPosition(history->getVScrollPosition() - _rel*0.3); } -void DialogueWindow::open() -{ - topicsList->clear(); - pTopicsText.clear(); - history->eraseText(0,history->getTextLength()); - updateOptions(); - setVisible(true); -} - void DialogueWindow::onByeClicked(MyGUI::Widget* _sender) { MWBase::Environment::get().getDialogueManager()->goodbyeSelected(); @@ -133,7 +124,7 @@ void DialogueWindow::onSelectTopic(std::string topic) if (topic == MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sBarter")->str) { /// \todo check if the player is allowed to trade with this actor (e.g. faction rank high enough)? - mWindowManager.setGuiMode(GM_Barter); + mWindowManager.pushGuiMode(GM_Barter); mWindowManager.getTradeWindow()->startTrade(mActor); } @@ -147,6 +138,11 @@ void DialogueWindow::startDialogue(MWWorld::Ptr actor, std::string npcName) mActor = actor; topicsList->setEnabled(true); setTitle(npcName); + + topicsList->clear(); + pTopicsText.clear(); + history->eraseText(0,history->getTextLength()); + updateOptions(); } void DialogueWindow::setKeywords(std::list keyWords) diff --git a/apps/openmw/mwgui/dialogue.hpp b/apps/openmw/mwgui/dialogue.hpp index 7f69f972c7..d3106ad381 100644 --- a/apps/openmw/mwgui/dialogue.hpp +++ b/apps/openmw/mwgui/dialogue.hpp @@ -30,8 +30,6 @@ namespace MWGui public: DialogueWindow(WindowManager& parWindowManager); - void open(); - // Events typedef MyGUI::delegates::CMultiDelegate0 EventHandle_Void; diff --git a/apps/openmw/mwgui/messagebox.cpp b/apps/openmw/mwgui/messagebox.cpp index a6b9025ce4..9a06714780 100644 --- a/apps/openmw/mwgui/messagebox.cpp +++ b/apps/openmw/mwgui/messagebox.cpp @@ -58,7 +58,6 @@ void MessageBoxManager::onFrame (float frameDuration) if(mInterMessageBoxe != NULL && mInterMessageBoxe->mMarkedToDelete) { delete mInterMessageBoxe; mInterMessageBoxe = NULL; - mWindowManager->setNextMode(GM_Game); } } diff --git a/apps/openmw/mwgui/mode.hpp b/apps/openmw/mwgui/mode.hpp index 775fe4a030..d465aa0c5b 100644 --- a/apps/openmw/mwgui/mode.hpp +++ b/apps/openmw/mwgui/mode.hpp @@ -5,7 +5,6 @@ namespace MWGui { enum GuiMode { - GM_Game, // Game mode, only HUD GM_Inventory, // Inventory mode GM_Container, GM_MainMenu, // Main menu mode diff --git a/apps/openmw/mwgui/scrollwindow.cpp b/apps/openmw/mwgui/scrollwindow.cpp index 877864cfed..f4d45fc265 100644 --- a/apps/openmw/mwgui/scrollwindow.cpp +++ b/apps/openmw/mwgui/scrollwindow.cpp @@ -1,12 +1,13 @@ #include "scrollwindow.hpp" -#include "formatting.hpp" - #include "../mwbase/environment.hpp" #include "../mwinput/inputmanager.hpp" #include "../mwworld/actiontake.hpp" #include "../mwsound/soundmanager.hpp" +#include "formatting.hpp" +#include "window_manager.hpp" + using namespace MWGui; ScrollWindow::ScrollWindow (WindowManager& parWindowManager) : @@ -55,7 +56,7 @@ void ScrollWindow::onCloseButtonClicked (MyGUI::Widget* _sender) { MWBase::Environment::get().getSoundManager()->playSound ("scroll", 1.0, 1.0); - MWBase::Environment::get().getInputManager()->setGuiMode (GM_Game); + mWindowManager.popGuiMode(); } void ScrollWindow::onTakeButtonClicked (MyGUI::Widget* _sender) @@ -65,5 +66,5 @@ void ScrollWindow::onTakeButtonClicked (MyGUI::Widget* _sender) MWWorld::ActionTake take(mScroll); take.execute(); - MWBase::Environment::get().getInputManager()->setGuiMode (GM_Game); + mWindowManager.popGuiMode(); } diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index 60cc06cb86..311ea6c957 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -210,7 +210,7 @@ namespace MWGui std::string sound = "Item Gold Up"; MWBase::Environment::get().getSoundManager()->playSound (sound, 1.0, 1.0); - mWindowManager.setGuiMode(GM_Game); + mWindowManager.popGuiMode(); } void TradeWindow::onCancelButtonClicked(MyGUI::Widget* _sender) @@ -220,7 +220,7 @@ namespace MWGui // now gimme back my stuff! mWindowManager.getInventoryWindow()->returnBoughtItems(MWWorld::Class::get(mContainer).getContainerStore(mContainer)); - mWindowManager.setGuiMode(GM_Game); + mWindowManager.popGuiMode(); } void TradeWindow::updateLabels() diff --git a/apps/openmw/mwgui/window_manager.cpp b/apps/openmw/mwgui/window_manager.cpp index 2cacf23467..1233231687 100644 --- a/apps/openmw/mwgui/window_manager.cpp +++ b/apps/openmw/mwgui/window_manager.cpp @@ -62,9 +62,6 @@ WindowManager::WindowManager( , playerMagicka() , playerFatigue() , gui(NULL) - , mode(GM_Game) - , nextMode(GM_Game) - , needModeChange(false) , garbageDialogs() , shown(GW_ALL) , allowed(newGame ? GW_None : GW_ALL) @@ -178,12 +175,6 @@ void WindowManager::cleanupGarbage() void WindowManager::update() { cleanupGarbage(); - if (needModeChange) - { - needModeChange = false; - MWBase::Environment::get().getInputManager()->setGuiMode(nextMode); - nextMode = GM_Game; - } if (showFPSLevel > 0) { hud->setFPS(mFPS); @@ -192,17 +183,6 @@ void WindowManager::update() } } -void WindowManager::setNextMode(GuiMode newMode) -{ - nextMode = newMode; - needModeChange = true; -} - -void WindowManager::setGuiMode(GuiMode newMode) -{ - MWBase::Environment::get().getInputManager()->setGuiMode(newMode); -} - void WindowManager::updateVisible() { // Start out by hiding everything except the HUD @@ -221,15 +201,20 @@ void WindowManager::updateVisible() // Mouse is visible whenever we're not in game mode MyGUI::PointerManager::getInstance().setVisible(isGuiMode()); - if (mode == GM_Game) + bool gameMode = !isGuiMode(); + + if (gameMode) mToolTips->enterGameMode(); else mToolTips->enterGuiMode(); + // If in game mode, don't show anything. + if (gameMode) + return; + + GuiMode mode = mGuiModes.back(); + switch(mode) { - case GM_Game: - // If in game mode, don't show anything. - break; case GM_MainMenu: menu->setVisible(true); break; @@ -273,7 +258,7 @@ void WindowManager::updateVisible() mInventoryWindow->openInventory(); break; case GM_Dialogue: - mDialogueWindow->open(); + mDialogueWindow->setVisible(true); break; case GM_Barter: mInventoryWindow->setVisible(true); @@ -281,9 +266,6 @@ void WindowManager::updateVisible() mTradeWindow->setVisible(true); break; case GM_InterMessageBox: - if(!mMessageBoxManager->isInteractiveMessageBox()) { - setGuiMode(GM_Game); - } break; case GM_Journal: mJournal->setVisible(true); @@ -291,9 +273,6 @@ void WindowManager::updateVisible() break; default: // Unsupported mode, switch back to game - // Note: The call will eventually end up this method again but - // will stop at the check if mode is GM_Game. - setGuiMode(GM_Game); break; } } @@ -427,7 +406,7 @@ void WindowManager::messageBox (const std::string& message, const std::vectorcreateInteractiveMessageBox(message, buttons); - setGuiMode(GM_InterMessageBox); + pushGuiMode(GM_InterMessageBox); } } @@ -452,7 +431,7 @@ void WindowManager::onDialogueWindowBye() //removeDialog(dialogueWindow); mDialogueWindow->setVisible(false); } - setGuiMode(GM_Game); + popGuiMode(); } void WindowManager::onFrame (float frameDuration) @@ -597,3 +576,27 @@ void WindowManager::onRetrieveTag(const MyGUI::UString& _tag, MyGUI::UString& _r if (setting && setting->type == ESM::VT_String) _result = setting->str; } + +void WindowManager::pushGuiMode(GuiMode mode) +{ + if (mode==GM_Inventory && allowed==GW_None) + return; + + mGuiModes.push_back(mode); + + bool gameMode = !isGuiMode(); + MWBase::Environment::get().getInputManager()->changeInputMode(!gameMode); + + updateVisible(); +} + +void WindowManager::popGuiMode() +{ + if (mGuiModes.size()) + mGuiModes.pop_back(); + + bool gameMode = !isGuiMode(); + MWBase::Environment::get().getInputManager()->changeInputMode(!gameMode); + + updateVisible(); +} diff --git a/apps/openmw/mwgui/window_manager.hpp b/apps/openmw/mwgui/window_manager.hpp index 22fe973a59..d519d2e493 100644 --- a/apps/openmw/mwgui/window_manager.hpp +++ b/apps/openmw/mwgui/window_manager.hpp @@ -96,8 +96,6 @@ namespace MWGui WindowManager(const Compiler::Extensions& extensions, int fpsLevel, bool newGame, OEngine::Render::OgreRenderer *mOgre, const std::string logpath); virtual ~WindowManager(); - void setGuiMode(GuiMode newMode); - /** * Should be called each frame to update windows/gui elements. * This could mean updating sizes of gui elements or opening @@ -105,19 +103,17 @@ namespace MWGui */ void update(); - void setMode(GuiMode newMode) + void pushGuiMode(GuiMode mode); + void popGuiMode(); + + GuiMode getMode() const { - if (newMode==GM_Inventory && allowed==GW_None) - return; - - mode = newMode; - updateVisible(); + if (mGuiModes.empty()) + throw std::runtime_error ("getMode() called, but there is no active mode"); + return mGuiModes.back(); } - void setNextMode(GuiMode newMode); - GuiMode getMode() const { return mode; } - - bool isGuiMode() const { return getMode() != GM_Game; } // Everything that is not game mode is considered "gui mode" + bool isGuiMode() const { return !mGuiModes.empty(); } // Disallow all inventory mode windows void disallowAll() @@ -244,9 +240,7 @@ namespace MWGui MyGUI::Gui *gui; // Gui - GuiMode mode; // Current gui mode - GuiMode nextMode; // Next mode to activate in update() - bool needModeChange; //Whether a mode change is needed in update() [will use nextMode] + std::vector mGuiModes; std::vector garbageDialogs; void cleanupGarbage(); diff --git a/apps/openmw/mwinput/inputmanager.cpp b/apps/openmw/mwinput/inputmanager.cpp index 8f8f1e1ee2..c074731d8e 100644 --- a/apps/openmw/mwinput/inputmanager.cpp +++ b/apps/openmw/mwinput/inputmanager.cpp @@ -143,20 +143,20 @@ namespace MWInput /* toggleInventory() is called when the user presses the button to toggle the inventory screen. */ void toggleInventory() { - using namespace MWGui; + using namespace MWGui; - if (mDragDrop) - return; + if (mDragDrop) + return; - GuiMode mode = windows.getMode(); + bool gameMode = !windows.isGuiMode(); - // Toggle between game mode and inventory mode - if(mode == GM_Game) - setGuiMode(GM_Inventory); - else if(mode == GM_Inventory) - setGuiMode(GM_Game); + // Toggle between game mode and inventory mode + if(gameMode) + windows.pushGuiMode(GM_Inventory); + else if(windows.getMode() == GM_Inventory) + windows.popGuiMode(); - // .. but don't touch any other mode. + // .. but don't touch any other mode. } // Toggle console @@ -167,28 +167,33 @@ namespace MWInput if (mDragDrop) return; - GuiMode mode = windows.getMode(); + bool gameMode = !windows.isGuiMode(); // Switch to console mode no matter what mode we are currently // in, except of course if we are already in console mode - if(mode == GM_Console) - setGuiMode(GM_Game); - else setGuiMode(GM_Console); + if (!gameMode) + { + if (windows.getMode() == GM_Console) + windows.popGuiMode(); + else + windows.pushGuiMode(GM_Console); + } + else + windows.pushGuiMode(GM_Console); } void toggleJournal() { - using namespace MWGui; + using namespace MWGui; - GuiMode mode = windows.getMode(); + // Toggle between game mode and journal mode + bool gameMode = !windows.isGuiMode(); - // Toggle between game mode and journal mode - if(mode == GM_Game) - setGuiMode(GM_Journal); - else if(mode == GM_Journal) - setGuiMode(GM_Game); - - // .. but don't touch any other mode. + if(gameMode) + windows.pushGuiMode(GM_Journal); + else if(windows.getMode() == GM_Journal) + windows.popGuiMode(); + // .. but don't touch any other mode. } void activate() @@ -282,8 +287,7 @@ namespace MWInput lst->add(guiEvents,Event::EV_ALL); } - // Start out in game mode - setGuiMode(MWGui::GM_Game); + changeInputMode(false); /********************************** Key binding section @@ -348,6 +352,7 @@ namespace MWInput windows.update(); // Disable movement in Gui mode + if (windows.isGuiMode()) return; // Configure player movement according to keyboard input. Actual movement will @@ -388,14 +393,10 @@ namespace MWInput // Switch between gui modes. Besides controlling the Gui windows // this also makes sure input is directed to the right place - void setGuiMode(MWGui::GuiMode mode) + void changeInputMode(bool guiMode) { - // Tell the GUI what to show (this also takes care of the mouse - // pointer) - windows.setMode(mode); - // Are we in GUI mode now? - if(windows.isGuiMode()) + if(guiMode) { // Disable mouse look mouse->setCamera(NULL); @@ -431,11 +432,6 @@ namespace MWInput delete impl; } - void MWInputManager::setGuiMode(MWGui::GuiMode mode) - { - impl->setGuiMode(mode); - } - void MWInputManager::update() { impl->update(); @@ -445,4 +441,9 @@ namespace MWInput { impl->setDragDrop(dragDrop); } + + void MWInputManager::changeInputMode(bool guiMode) + { + impl->changeInputMode(guiMode); + } } diff --git a/apps/openmw/mwinput/inputmanager.hpp b/apps/openmw/mwinput/inputmanager.hpp index 158d05f0ee..b8d98ed566 100644 --- a/apps/openmw/mwinput/inputmanager.hpp +++ b/apps/openmw/mwinput/inputmanager.hpp @@ -50,9 +50,9 @@ namespace MWInput void update(); - void setDragDrop(bool dragDrop); + void changeInputMode(bool guiMode); - void setGuiMode(MWGui::GuiMode mode); + void setDragDrop(bool dragDrop); }; } #endif diff --git a/apps/openmw/mwscript/guiextensions.cpp b/apps/openmw/mwscript/guiextensions.cpp index c4d9e9fabb..b267cc6e49 100644 --- a/apps/openmw/mwscript/guiextensions.cpp +++ b/apps/openmw/mwscript/guiextensions.cpp @@ -44,7 +44,7 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime) { - MWBase::Environment::get().getInputManager()->setGuiMode(mDialogue); + MWBase::Environment::get().getWindowManager()->pushGuiMode(mDialogue); } }; diff --git a/apps/openmw/mwworld/actionopen.cpp b/apps/openmw/mwworld/actionopen.cpp index e450585e63..e2c8ec5cf1 100644 --- a/apps/openmw/mwworld/actionopen.cpp +++ b/apps/openmw/mwworld/actionopen.cpp @@ -16,7 +16,7 @@ namespace MWWorld void ActionOpen::execute () { - MWBase::Environment::get().getWindowManager()->setGuiMode(MWGui::GM_Container); + MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Container); MWBase::Environment::get().getWindowManager()->getContainerWindow()->open(mContainer); } } diff --git a/apps/openmw/mwworld/actionread.cpp b/apps/openmw/mwworld/actionread.cpp index 0d37e06f58..34e95cbd07 100644 --- a/apps/openmw/mwworld/actionread.cpp +++ b/apps/openmw/mwworld/actionread.cpp @@ -18,12 +18,12 @@ namespace MWWorld if (ref->base->data.isScroll) { - MWBase::Environment::get().getWindowManager()->setGuiMode(MWGui::GM_Scroll); + MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Scroll); MWBase::Environment::get().getWindowManager()->getScrollWindow()->open(mObject); } else { - MWBase::Environment::get().getWindowManager()->setGuiMode(MWGui::GM_Book); + MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Book); MWBase::Environment::get().getWindowManager()->getBookWindow()->open(mObject); } } From a1907e7b88ceff1bfc54ace08b498d55a12c9cb0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 24 May 2012 03:48:02 +0200 Subject: [PATCH 261/325] cleaning up mwgui/widgets part 1 --- apps/openmw/mwgui/widgets.hpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/apps/openmw/mwgui/widgets.hpp b/apps/openmw/mwgui/widgets.hpp index 74da7fc933..6e230e2c63 100644 --- a/apps/openmw/mwgui/widgets.hpp +++ b/apps/openmw/mwgui/widgets.hpp @@ -23,6 +23,18 @@ namespace MWGui { void fixTexturePath(std::string &path); + struct SpellEffectParams + { + bool mHasTarget; // potion effects for example have no target (target is always the player) + bool mIsConstant; // constant effect means that duration will not be displayed + std::string effectID; + + // note that the ESM::MagicEffect (retrieved through effectID) might already store skill and attribute, + // in that case the ESM::MagicEffect skill/attribute is preferred. this is just here for ingredients which + // have them defined elsewhere. + signed char skill, attribute; + }; + class MYGUI_EXPORT MWSkill : public Widget { MYGUI_RTTI_DERIVED( MWSkill ); From cb35f4d208d4760634b10aa28c341d3fd71ac9ed Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 24 May 2012 03:50:02 +0200 Subject: [PATCH 262/325] some unrelated gui cleanup --- apps/openmw/mwgui/map_window.cpp | 6 +- apps/openmw/mwgui/stats_window.cpp | 115 -------------------- apps/openmw/mwgui/stats_window.hpp | 2 - apps/openmw/mwgui/window_manager.cpp | 2 + files/mygui/openmw_stats_window_layout.xml | 120 ++++++++++++++++++--- 5 files changed, 109 insertions(+), 136 deletions(-) diff --git a/apps/openmw/mwgui/map_window.cpp b/apps/openmw/mwgui/map_window.cpp index 78ca707988..a44571d0a6 100644 --- a/apps/openmw/mwgui/map_window.cpp +++ b/apps/openmw/mwgui/map_window.cpp @@ -102,7 +102,7 @@ MapWindow::MapWindow(WindowManager& parWindowManager) : getWidget(mButton, "WorldButton"); mButton->eventMouseButtonClick += MyGUI::newDelegate(this, &MapWindow::onWorldButtonClicked); - mButton->setCaption(mWindowManager.getGameSettingString("sWorld", "")); + mButton->setCaptionWithReplacing("#{sWorld}"); int width = mButton->getTextSize().width + 24; mButton->setCoord(mMainWidget->getSize().width - width - 22, mMainWidget->getSize().height - 64, width, 22); @@ -172,8 +172,8 @@ void MapWindow::onWorldButtonClicked(MyGUI::Widget* _sender) mGlobalMap->setVisible(mGlobal); mLocalMap->setVisible(!mGlobal); - mButton->setCaption( mGlobal ? mWindowManager.getGameSettingString("sWorld", "") : - mWindowManager.getGameSettingString("sLocal", "")); + mButton->setCaptionWithReplacing( mGlobal ? "#{sLocal}" : + "#{sWorld}"); int width = mButton->getTextSize().width + 24; mButton->setCoord(mMainWidget->getSize().width - width - 22, mMainWidget->getSize().height - 64, width, 22); } diff --git a/apps/openmw/mwgui/stats_window.cpp b/apps/openmw/mwgui/stats_window.cpp index cdf6a58718..54d9d7d4e3 100644 --- a/apps/openmw/mwgui/stats_window.cpp +++ b/apps/openmw/mwgui/stats_window.cpp @@ -77,8 +77,6 @@ StatsWindow::StatsWindow (WindowManager& parWindowManager) MyGUI::WindowPtr t = static_cast(mMainWidget); t->eventWindowChangeCoord += MyGUI::newDelegate(this, &StatsWindow::onWindowResize); - - setupToolTips(); } void StatsWindow::onScrollChangePosition(MyGUI::ScrollBar* scroller, size_t pos) @@ -633,116 +631,3 @@ void StatsWindow::onPinToggled() { mWindowManager.setHMSVisibility(!mPinned); } - -void StatsWindow::setupToolTips() -{ - - const ESMS::ESMStore &store = mWindowManager.getStore(); - MyGUI::Widget* widget; - - /// \todo move this into the .layout file! - - getWidget(widget, "Attrib1"); - widget->setUserString("ToolTipType", "Layout"); - widget->setUserString("ToolTipLayout", "AttributeToolTip"); - widget->setUserString("Caption_AttributeName", store.gameSettings.find ("sAttributeStrength")->str); - widget->setUserString("Caption_AttributeDescription", store.gameSettings.find ("sStrDesc")->str); - widget->setUserString("ImageTexture_AttributeImage", "icons\\k\\attribute_strength.dds"); - getWidget(widget, "AttribVal1"); - widget->setUserString("ToolTipType", "Layout"); - widget->setUserString("ToolTipLayout", "AttributeToolTip"); - widget->setUserString("Caption_AttributeName", store.gameSettings.find ("sAttributeStrength")->str); - widget->setUserString("Caption_AttributeDescription", store.gameSettings.find ("sStrDesc")->str); - widget->setUserString("ImageTexture_AttributeImage", "icons\\k\\attribute_strength.dds"); - - getWidget(widget, "Attrib2"); - widget->setUserString("ToolTipType", "Layout"); - widget->setUserString("ToolTipLayout", "AttributeToolTip"); - widget->setUserString("Caption_AttributeName", store.gameSettings.find ("sAttributeIntelligence")->str); - widget->setUserString("Caption_AttributeDescription", store.gameSettings.find ("sIntDesc")->str); - widget->setUserString("ImageTexture_AttributeImage", "icons\\k\\attribute_int.dds"); - getWidget(widget, "AttribVal2"); - widget->setUserString("ToolTipType", "Layout"); - widget->setUserString("ToolTipLayout", "AttributeToolTip"); - widget->setUserString("Caption_AttributeName", store.gameSettings.find ("sAttributeIntelligence")->str); - widget->setUserString("Caption_AttributeDescription", store.gameSettings.find ("sIntDesc")->str); - widget->setUserString("ImageTexture_AttributeImage", "icons\\k\\attribute_int.dds"); - - getWidget(widget, "Attrib3"); - widget->setUserString("ToolTipType", "Layout"); - widget->setUserString("ToolTipLayout", "AttributeToolTip"); - widget->setUserString("Caption_AttributeName", store.gameSettings.find ("sAttributeWillpower")->str); - widget->setUserString("Caption_AttributeDescription", store.gameSettings.find ("sWilDesc")->str); - widget->setUserString("ImageTexture_AttributeImage", "icons\\k\\attribute_wilpower.dds"); - getWidget(widget, "AttribVal3"); - widget->setUserString("ToolTipType", "Layout"); - widget->setUserString("ToolTipLayout", "AttributeToolTip"); - widget->setUserString("Caption_AttributeName", store.gameSettings.find ("sAttributeWillpower")->str); - widget->setUserString("Caption_AttributeDescription", store.gameSettings.find ("sWilDesc")->str); - widget->setUserString("ImageTexture_AttributeImage", "icons\\k\\attribute_wilpower.dds"); - - getWidget(widget, "Attrib4"); - widget->setUserString("ToolTipType", "Layout"); - widget->setUserString("ToolTipLayout", "AttributeToolTip"); - widget->setUserString("Caption_AttributeName", store.gameSettings.find ("sAttributeAgility")->str); - widget->setUserString("Caption_AttributeDescription", store.gameSettings.find ("sAgiDesc")->str); - widget->setUserString("ImageTexture_AttributeImage", "icons\\k\\attribute_agility.dds"); - getWidget(widget, "AttribVal4"); - widget->setUserString("ToolTipType", "Layout"); - widget->setUserString("ToolTipLayout", "AttributeToolTip"); - widget->setUserString("Caption_AttributeName", store.gameSettings.find ("sAttributeAgility")->str); - widget->setUserString("Caption_AttributeDescription", store.gameSettings.find ("sAgiDesc")->str); - widget->setUserString("ImageTexture_AttributeImage", "icons\\k\\attribute_agility.dds"); - - getWidget(widget, "Attrib5"); - widget->setUserString("ToolTipType", "Layout"); - widget->setUserString("ToolTipLayout", "AttributeToolTip"); - widget->setUserString("Caption_AttributeName", store.gameSettings.find ("sAttributeSpeed")->str); - widget->setUserString("Caption_AttributeDescription", store.gameSettings.find ("sSpdDesc")->str); - widget->setUserString("ImageTexture_AttributeImage", "icons\\k\\attribute_speed.dds"); - getWidget(widget, "AttribVal5"); - widget->setUserString("ToolTipType", "Layout"); - widget->setUserString("ToolTipLayout", "AttributeToolTip"); - widget->setUserString("Caption_AttributeName", store.gameSettings.find ("sAttributeSpeed")->str); - widget->setUserString("Caption_AttributeDescription", store.gameSettings.find ("sSpdDesc")->str); - widget->setUserString("ImageTexture_AttributeImage", "icons\\k\\attribute_speed.dds"); - - getWidget(widget, "Attrib6"); - widget->setUserString("ToolTipType", "Layout"); - widget->setUserString("ToolTipLayout", "AttributeToolTip"); - widget->setUserString("Caption_AttributeName", store.gameSettings.find ("sAttributeEndurance")->str); - widget->setUserString("Caption_AttributeDescription", store.gameSettings.find ("sEndDesc")->str); - widget->setUserString("ImageTexture_AttributeImage", "icons\\k\\attribute_endurance.dds"); - getWidget(widget, "AttribVal6"); - widget->setUserString("ToolTipType", "Layout"); - widget->setUserString("ToolTipLayout", "AttributeToolTip"); - widget->setUserString("Caption_AttributeName", store.gameSettings.find ("sAttributeEndurance")->str); - widget->setUserString("Caption_AttributeDescription", store.gameSettings.find ("sEndDesc")->str); - widget->setUserString("ImageTexture_AttributeImage", "icons\\k\\attribute_endurance.dds"); - - getWidget(widget, "Attrib7"); - widget->setUserString("ToolTipType", "Layout"); - widget->setUserString("ToolTipLayout", "AttributeToolTip"); - widget->setUserString("Caption_AttributeName", store.gameSettings.find ("sAttributePersonality")->str); - widget->setUserString("Caption_AttributeDescription", store.gameSettings.find ("sPerDesc")->str); - widget->setUserString("ImageTexture_AttributeImage", "icons\\k\\attribute_personality.dds"); - getWidget(widget, "AttribVal7"); - widget->setUserString("ToolTipType", "Layout"); - widget->setUserString("ToolTipLayout", "AttributeToolTip"); - widget->setUserString("Caption_AttributeName", store.gameSettings.find ("sAttributePersonality")->str); - widget->setUserString("Caption_AttributeDescription", store.gameSettings.find ("sPerDesc")->str); - widget->setUserString("ImageTexture_AttributeImage", "icons\\k\\attribute_personality.dds"); - - getWidget(widget, "Attrib8"); - widget->setUserString("ToolTipType", "Layout"); - widget->setUserString("ToolTipLayout", "AttributeToolTip"); - widget->setUserString("Caption_AttributeName", store.gameSettings.find ("sAttributeLuck")->str); - widget->setUserString("Caption_AttributeDescription", store.gameSettings.find ("sLucDesc")->str); - widget->setUserString("ImageTexture_AttributeImage", "icons\\k\\attribute_luck.dds"); - getWidget(widget, "AttribVal8"); - widget->setUserString("ToolTipType", "Layout"); - widget->setUserString("ToolTipLayout", "AttributeToolTip"); - widget->setUserString("Caption_AttributeName", store.gameSettings.find ("sAttributeLuck")->str); - widget->setUserString("Caption_AttributeDescription", store.gameSettings.find ("sLucDesc")->str); - widget->setUserString("ImageTexture_AttributeImage", "icons\\k\\attribute_luck.dds"); -} diff --git a/apps/openmw/mwgui/stats_window.hpp b/apps/openmw/mwgui/stats_window.hpp index 50a83bb29e..bbd9165859 100644 --- a/apps/openmw/mwgui/stats_window.hpp +++ b/apps/openmw/mwgui/stats_window.hpp @@ -50,8 +50,6 @@ namespace MWGui MyGUI::Widget* addItem(const std::string text, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2); void updateScroller(); - void setupToolTips(); - void setFactions (const FactionList& factions); void setBirthSign (const std::string &signId); diff --git a/apps/openmw/mwgui/window_manager.cpp b/apps/openmw/mwgui/window_manager.cpp index 09ea6543a7..6be7125097 100644 --- a/apps/openmw/mwgui/window_manager.cpp +++ b/apps/openmw/mwgui/window_manager.cpp @@ -608,4 +608,6 @@ void WindowManager::onRetrieveTag(const MyGUI::UString& _tag, MyGUI::UString& _r const ESM::GameSetting *setting = MWBase::Environment::get().getWorld()->getStore().gameSettings.search(_tag); if (setting && setting->type == ESM::VT_String) _result = setting->str; + else + _result = _tag; } diff --git a/files/mygui/openmw_stats_window_layout.xml b/files/mygui/openmw_stats_window_layout.xml index 4729e3bca8..81d70f7042 100644 --- a/files/mygui/openmw_stats_window_layout.xml +++ b/files/mygui/openmw_stats_window_layout.xml @@ -99,29 +99,117 @@ - - + + + + + + + + + + + + + - - + + + + + + + + + + + + + - - + + + + + + + + + + + + + - - + + + + + + + + + + + + + - - + + + + + + + + + + + + + - - + + + + + + + + + + + + + - - + + + + + + + + + + + + + - - + + + + + + + + + + + + + From 9b94edd561d27a69ba137c89f225ed49cbd5bf2f Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 24 May 2012 04:34:53 +0200 Subject: [PATCH 263/325] audio tab with volume sliders --- apps/openmw/mwgui/settingswindow.cpp | 44 ++++++++++++++++--- apps/openmw/mwgui/settingswindow.hpp | 9 ++++ apps/openmw/mwsound/soundmanager.cpp | 16 +++++-- apps/openmw/mwsound/soundmanager.hpp | 8 ++++ files/mygui/openmw_settings_window_layout.xml | 43 ++++++++++++++++-- files/settings-default.cfg | 4 +- 6 files changed, 109 insertions(+), 15 deletions(-) diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index 6eaf31ce96..d8e1072e33 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -24,6 +24,11 @@ namespace MWGui getWidget(mMenuTransparencySlider, "MenuTransparencySlider"); getWidget(mViewDistanceSlider, "ViewDistanceSlider"); getWidget(mFullscreenButton, "FullscreenButton"); + getWidget(mMasterVolumeSlider, "MasterVolume"); + getWidget(mVoiceVolumeSlider, "VoiceVolume"); + getWidget(mEffectsVolumeSlider, "EffectsVolume"); + getWidget(mFootstepsVolumeSlider, "FootstepsVolume"); + getWidget(mMusicVolumeSlider, "MusicVolume"); mOkButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onOkButtonClicked); mFullscreenButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onButtonToggled); @@ -31,6 +36,12 @@ namespace MWGui mViewDistanceSlider->eventScrollChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onSliderChangePosition); mResolutionList->eventListChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onResolutionSelected); + mMasterVolumeSlider->eventScrollChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onSliderChangePosition); + mVoiceVolumeSlider->eventScrollChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onSliderChangePosition); + mEffectsVolumeSlider->eventScrollChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onSliderChangePosition); + mFootstepsVolumeSlider->eventScrollChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onSliderChangePosition); + mMusicVolumeSlider->eventScrollChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onSliderChangePosition); + center(); int okSize = mOkButton->getTextSize().width + 24; @@ -54,6 +65,12 @@ namespace MWGui int viewdist = (mViewDistanceSlider->getScrollRange()-1) * val; mViewDistanceSlider->setScrollPosition(viewdist); + mMasterVolumeSlider->setScrollPosition(Settings::Manager::getFloat("master volume", "Sound") * (mMasterVolumeSlider->getScrollRange()-1)); + mMusicVolumeSlider->setScrollPosition(Settings::Manager::getFloat("music volume", "Sound") * (mMusicVolumeSlider->getScrollRange()-1)); + mEffectsVolumeSlider->setScrollPosition(Settings::Manager::getFloat("sfx volume", "Sound") * (mEffectsVolumeSlider->getScrollRange()-1)); + mFootstepsVolumeSlider->setScrollPosition(Settings::Manager::getFloat("footsteps volume", "Sound") * (mFootstepsVolumeSlider->getScrollRange()-1)); + mVoiceVolumeSlider->setScrollPosition(Settings::Manager::getFloat("voice volume", "Sound") * (mVoiceVolumeSlider->getScrollRange()-1)); + std::string on = mWindowManager.getGameSettingString("sOn", "On"); std::string off = mWindowManager.getGameSettingString("sOff", "On"); @@ -90,7 +107,7 @@ namespace MWGui Settings::Manager::setInt("resolution x", "Video", resX); Settings::Manager::setInt("resolution y", "Video", resY); - MWBase::Environment::get().getWorld()->processChangedSettings(Settings::Manager::apply()); + apply(); } void SettingsWindow::onButtonToggled(MyGUI::Widget* _sender) @@ -117,14 +134,27 @@ namespace MWGui { float val = pos / float(scroller->getScrollRange()-1); if (scroller == mMenuTransparencySlider) - { Settings::Manager::setFloat("menu transparency", "GUI", val); - } else if (scroller == mViewDistanceSlider) - { - Settings::Manager::setFloat("max viewing distance", "Viewing distance", (1-val) * 2000 + val * 5600); - } + Settings::Manager::setFloat("max viewing distance", "Viewing distance", (1-val) * 2000 + val * 5600); + else if (scroller == mMasterVolumeSlider) + Settings::Manager::setFloat("master volume", "Sound", val); + else if (scroller == mVoiceVolumeSlider) + Settings::Manager::setFloat("voice volume", "Sound", val); + else if (scroller == mEffectsVolumeSlider) + Settings::Manager::setFloat("sfx volume", "Sound", val); + else if (scroller == mFootstepsVolumeSlider) + Settings::Manager::setFloat("footsteps volume", "Sound", val); + else if (scroller == mMusicVolumeSlider) + Settings::Manager::setFloat("music volume", "Sound", val); - MWBase::Environment::get().getWorld()->processChangedSettings(Settings::Manager::apply()); + apply(); + } + + void SettingsWindow::apply() + { + const Settings::CategorySettingVector changed = Settings::Manager::apply(); + MWBase::Environment::get().getWorld()->processChangedSettings(changed); + MWBase::Environment::get().getWorld()->processChangedSettings(changed); } } diff --git a/apps/openmw/mwgui/settingswindow.hpp b/apps/openmw/mwgui/settingswindow.hpp index 785b0c9b14..62acc56490 100644 --- a/apps/openmw/mwgui/settingswindow.hpp +++ b/apps/openmw/mwgui/settingswindow.hpp @@ -22,11 +22,20 @@ namespace MWGui MyGUI::ScrollBar* mMenuTransparencySlider; MyGUI::ScrollBar* mViewDistanceSlider; + // audio + MyGUI::ScrollBar* mMasterVolumeSlider; + MyGUI::ScrollBar* mVoiceVolumeSlider; + MyGUI::ScrollBar* mEffectsVolumeSlider; + MyGUI::ScrollBar* mFootstepsVolumeSlider; + MyGUI::ScrollBar* mMusicVolumeSlider; + void onOkButtonClicked(MyGUI::Widget* _sender); void onSliderChangePosition(MyGUI::ScrollBar* scroller, size_t pos); void onButtonToggled(MyGUI::Widget* _sender); void onResolutionSelected(MyGUI::ListBox* _sender, size_t index); void onResolutionAccept(); + + void apply(); }; } diff --git a/apps/openmw/mwsound/soundmanager.cpp b/apps/openmw/mwsound/soundmanager.cpp index 8deab3c046..11576e22a2 100644 --- a/apps/openmw/mwsound/soundmanager.cpp +++ b/apps/openmw/mwsound/soundmanager.cpp @@ -7,7 +7,6 @@ #include #include -#include #include "../mwbase/environment.hpp" @@ -53,6 +52,8 @@ namespace MWSound , mMasterVolume(1.0f) , mSFXVolume(1.0f) , mMusicVolume(1.0f) + , mFootstepsVolume(1.0f) + , mVoiceVolume(1.0f) { if(!useSound) return; @@ -210,7 +211,7 @@ namespace MWSound try { // The range values are not tested - float basevol = mMasterVolume * mSFXVolume; + float basevol = mMasterVolume * mVoiceVolume; std::string filePath = "Sound/"+filename; const ESM::Position &pos = ptr.getCellRef().pos; const Ogre::Vector3 objpos(pos.pos[0], pos.pos[1], pos.pos[2]); @@ -234,7 +235,7 @@ namespace MWSound return; try { - float basevol = mMasterVolume * mSFXVolume; + float basevol = mMasterVolume * mVoiceVolume; std::string filePath = "Sound/"+filename; SoundPtr sound = mOutput->playSound(filePath, basevol, 1.0f, Play_Normal); @@ -527,6 +528,15 @@ namespace MWSound } + void SoundManager::processChangedSettings(const Settings::CategorySettingVector& settings) + { + mMasterVolume = Settings::Manager::getFloat("master volume", "Sound"); + mMusicVolume = Settings::Manager::getFloat("music volume", "Sound"); + mSFXVolume = Settings::Manager::getFloat("sfx volume", "Sound"); + mFootstepsVolume = Settings::Manager::getFloat("footsteps volume", "Sound"); + mVoiceVolume = Settings::Manager::getFloat("voice volume", "Sound"); + } + // Default readAll implementation, for decoders that can't do anything // better void Sound_Decoder::readAll(std::vector &output) diff --git a/apps/openmw/mwsound/soundmanager.hpp b/apps/openmw/mwsound/soundmanager.hpp index e1816cd1f3..562b2af002 100644 --- a/apps/openmw/mwsound/soundmanager.hpp +++ b/apps/openmw/mwsound/soundmanager.hpp @@ -7,6 +7,8 @@ #include +#include + #include "../mwworld/ptr.hpp" @@ -52,6 +54,10 @@ namespace MWSound float mMasterVolume; float mSFXVolume; float mMusicVolume; + float mVoiceVolume; + + // not implemented + float mFootstepsVolume; boost::shared_ptr mMusic; std::string mCurrentPlaylist; @@ -78,6 +84,8 @@ namespace MWSound SoundManager(bool useSound); ~SoundManager(); + void processChangedSettings(const Settings::CategorySettingVector& settings); + void stopMusic(); ///< Stops music if it's playing diff --git a/files/mygui/openmw_settings_window_layout.xml b/files/mygui/openmw_settings_window_layout.xml index 2fa332d9a8..dc1cbfa9e3 100644 --- a/files/mygui/openmw_settings_window_layout.xml +++ b/files/mygui/openmw_settings_window_layout.xml @@ -9,23 +9,58 @@ - + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/settings-default.cfg b/files/settings-default.cfg index ab0b75ff2d..a6623656ca 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -131,7 +131,9 @@ underwater effect = true # Device name. Blank means default device = -# Volumes. Sfx and music volumes are both affected by the master volume +# Volumes. master volume affects all other volumes. master volume = 1.0 sfx volume = 1.0 music volume = 0.4 +footsteps volume = 0.6 +voice volume = 1.0 From 189b044392b6fc94464d3450ca73754b38abb1ef Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 24 May 2012 04:37:41 +0200 Subject: [PATCH 264/325] small correction --- apps/openmw/mwsound/soundmanager.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/openmw/mwsound/soundmanager.cpp b/apps/openmw/mwsound/soundmanager.cpp index 11576e22a2..b6f4296aa5 100644 --- a/apps/openmw/mwsound/soundmanager.cpp +++ b/apps/openmw/mwsound/soundmanager.cpp @@ -64,6 +64,10 @@ namespace MWSound mSFXVolume = std::min(std::max(mSFXVolume, 0.0f), 1.0f); mMusicVolume = Settings::Manager::getFloat("music volume", "Sound"); mMusicVolume = std::min(std::max(mMusicVolume, 0.0f), 1.0f); + mVoiceVolume = Settings::Manager::getFloat("voice volume", "Sound"); + mVoiceVolume = std::min(std::max(mMusicVolume, 0.0f), 1.0f); + mFootstepsVolume = Settings::Manager::getFloat("footsteps volume", "Sound"); + mFootstepsVolume = std::min(std::max(mMusicVolume, 0.0f), 1.0f); std::cout << "Sound output: " << SOUND_OUT << std::endl; std::cout << "Sound decoder: " << SOUND_IN << std::endl; From cbe89f7e32eede6ea7773a5d606066329b01344b Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 24 May 2012 08:56:45 +0200 Subject: [PATCH 265/325] copy&paste mistake --- apps/openmw/mwsound/soundmanager.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwsound/soundmanager.cpp b/apps/openmw/mwsound/soundmanager.cpp index b6f4296aa5..27294ae773 100644 --- a/apps/openmw/mwsound/soundmanager.cpp +++ b/apps/openmw/mwsound/soundmanager.cpp @@ -65,9 +65,9 @@ namespace MWSound mMusicVolume = Settings::Manager::getFloat("music volume", "Sound"); mMusicVolume = std::min(std::max(mMusicVolume, 0.0f), 1.0f); mVoiceVolume = Settings::Manager::getFloat("voice volume", "Sound"); - mVoiceVolume = std::min(std::max(mMusicVolume, 0.0f), 1.0f); + mVoiceVolume = std::min(std::max(mVoiceVolume, 0.0f), 1.0f); mFootstepsVolume = Settings::Manager::getFloat("footsteps volume", "Sound"); - mFootstepsVolume = std::min(std::max(mMusicVolume, 0.0f), 1.0f); + mFootstepsVolume = std::min(std::max(mFootstepsVolume, 0.0f), 1.0f); std::cout << "Sound output: " << SOUND_OUT << std::endl; std::cout << "Sound decoder: " << SOUND_IN << std::endl; From 6ea7bdb224c07a6965482610508d02c6f78c9b89 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 24 May 2012 11:50:48 +0200 Subject: [PATCH 266/325] vsync & fps buttons, sound volume apply fix --- apps/openmw/mwgui/settingswindow.cpp | 42 ++++++++++++-- apps/openmw/mwgui/settingswindow.hpp | 8 ++- apps/openmw/mwgui/window_manager.cpp | 13 ++--- apps/openmw/mwgui/window_manager.hpp | 6 +- apps/openmw/mwinput/inputmanager.cpp | 10 ---- files/mygui/openmw_settings_window_layout.xml | 58 +++++++++++++------ 6 files changed, 92 insertions(+), 45 deletions(-) diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index d8e1072e33..ce7f0d0e2f 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -10,10 +10,24 @@ #include "../mwbase/environment.hpp" #include "../mwworld/world.hpp" +#include "../mwsound/soundmanager.hpp" #include "window_manager.hpp" #include "confirmationdialog.hpp" +namespace +{ + std::string fpsLevelToStr(int level) + { + if (level == 0) + return "#{sOff}"; + else if (level == 1) + return "Basic"; + else + return "Detailed"; + } +} + namespace MWGui { SettingsWindow::SettingsWindow(WindowManager& parWindowManager) : @@ -24,6 +38,8 @@ namespace MWGui getWidget(mMenuTransparencySlider, "MenuTransparencySlider"); getWidget(mViewDistanceSlider, "ViewDistanceSlider"); getWidget(mFullscreenButton, "FullscreenButton"); + getWidget(mVSyncButton, "VSyncButton"); + getWidget(mFPSButton, "FPSButton"); getWidget(mMasterVolumeSlider, "MasterVolume"); getWidget(mVoiceVolumeSlider, "VoiceVolume"); getWidget(mEffectsVolumeSlider, "EffectsVolume"); @@ -32,6 +48,8 @@ namespace MWGui mOkButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onOkButtonClicked); mFullscreenButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onButtonToggled); + mVSyncButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onButtonToggled); + mFPSButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onFpsToggled); mMenuTransparencySlider->eventScrollChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onSliderChangePosition); mViewDistanceSlider->eventScrollChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onSliderChangePosition); mResolutionList->eventListChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onResolutionSelected); @@ -71,10 +89,9 @@ namespace MWGui mFootstepsVolumeSlider->setScrollPosition(Settings::Manager::getFloat("footsteps volume", "Sound") * (mFootstepsVolumeSlider->getScrollRange()-1)); mVoiceVolumeSlider->setScrollPosition(Settings::Manager::getFloat("voice volume", "Sound") * (mVoiceVolumeSlider->getScrollRange()-1)); - std::string on = mWindowManager.getGameSettingString("sOn", "On"); - std::string off = mWindowManager.getGameSettingString("sOff", "On"); - - mFullscreenButton->setCaption(Settings::Manager::getBool("fullscreen", "Video") ? on : off); + mFullscreenButton->setCaptionWithReplacing(Settings::Manager::getBool("fullscreen", "Video") ? "#{sOn}" : "#{sOff}"); + mVSyncButton->setCaptionWithReplacing(Settings::Manager::getBool("vsync", "Video") ? "#{sOn}": "#{sOff}"); + mFPSButton->setCaptionWithReplacing(fpsLevelToStr(Settings::Manager::getInt("fps", "HUD"))); } void SettingsWindow::onOkButtonClicked(MyGUI::Widget* _sender) @@ -128,6 +145,20 @@ namespace MWGui if (_sender == mFullscreenButton) Settings::Manager::setBool("fullscreen", "Video", newState); + else if (_sender == mVSyncButton) + { + Settings::Manager::setBool("vsync", "Video", newState); + MWBase::Environment::get().getWindowManager()-> + messageBox("VSync will be applied after a restart", std::vector()); + } + } + + void SettingsWindow::onFpsToggled(MyGUI::Widget* _sender) + { + int newLevel = (Settings::Manager::getInt("fps", "HUD") + 1) % 3; + Settings::Manager::setInt("fps", "HUD", newLevel); + mFPSButton->setCaptionWithReplacing(fpsLevelToStr(newLevel)); + apply(); } void SettingsWindow::onSliderChangePosition(MyGUI::ScrollBar* scroller, size_t pos) @@ -155,6 +186,7 @@ namespace MWGui { const Settings::CategorySettingVector changed = Settings::Manager::apply(); MWBase::Environment::get().getWorld()->processChangedSettings(changed); - MWBase::Environment::get().getWorld()->processChangedSettings(changed); + MWBase::Environment::get().getSoundManager()->processChangedSettings(changed); + MWBase::Environment::get().getWindowManager()->processChangedSettings(changed); } } diff --git a/apps/openmw/mwgui/settingswindow.hpp b/apps/openmw/mwgui/settingswindow.hpp index 62acc56490..79af039945 100644 --- a/apps/openmw/mwgui/settingswindow.hpp +++ b/apps/openmw/mwgui/settingswindow.hpp @@ -17,9 +17,14 @@ namespace MWGui protected: MyGUI::Button* mOkButton; + + MyGUI::ScrollBar* mMenuTransparencySlider; + + // graphics MyGUI::ListBox* mResolutionList; MyGUI::Button* mFullscreenButton; - MyGUI::ScrollBar* mMenuTransparencySlider; + MyGUI::Button* mVSyncButton; + MyGUI::Button* mFPSButton; MyGUI::ScrollBar* mViewDistanceSlider; // audio @@ -30,6 +35,7 @@ namespace MWGui MyGUI::ScrollBar* mMusicVolumeSlider; void onOkButtonClicked(MyGUI::Widget* _sender); + void onFpsToggled(MyGUI::Widget* _sender); void onSliderChangePosition(MyGUI::ScrollBar* scroller, size_t pos); void onButtonToggled(MyGUI::Widget* _sender); void onResolutionSelected(MyGUI::ListBox* _sender, size_t index); diff --git a/apps/openmw/mwgui/window_manager.cpp b/apps/openmw/mwgui/window_manager.cpp index 6be7125097..b71edc718b 100644 --- a/apps/openmw/mwgui/window_manager.cpp +++ b/apps/openmw/mwgui/window_manager.cpp @@ -554,14 +554,6 @@ void WindowManager::toggleFogOfWar() hud->toggleFogOfWar(); } -int WindowManager::toggleFps() -{ - showFPSLevel = (showFPSLevel+1)%3; - hud->setFpsLevel(showFPSLevel); - Settings::Manager::setInt("fps", "HUD", showFPSLevel); - return showFPSLevel; -} - void WindowManager::setFocusObject(const MWWorld::Ptr& focus) { mToolTips->setFocusObject(focus); @@ -611,3 +603,8 @@ void WindowManager::onRetrieveTag(const MyGUI::UString& _tag, MyGUI::UString& _r else _result = _tag; } + +void WindowManager::processChangedSettings(const Settings::CategorySettingVector& changed) +{ + hud->setFpsLevel(Settings::Manager::getInt("fps", "HUD")); +} diff --git a/apps/openmw/mwgui/window_manager.hpp b/apps/openmw/mwgui/window_manager.hpp index 9ccc42b1e9..f585ac3bae 100644 --- a/apps/openmw/mwgui/window_manager.hpp +++ b/apps/openmw/mwgui/window_manager.hpp @@ -17,6 +17,7 @@ #include "MyGUI_UString.h" #include +#include #include #include @@ -182,9 +183,6 @@ namespace MWGui void toggleFullHelp(); ///< show extra info in item tooltips (owner, script) bool getFullHelp() const; - int toggleFps(); - ///< toggle fps display @return resulting fps level - void setInteriorMapTexture(const int x, const int y); ///< set the index of the map texture that should be used (for interiors) @@ -215,6 +213,8 @@ namespace MWGui const ESMS::ESMStore& getStore() const; + void processChangedSettings(const Settings::CategorySettingVector& changed); + private: OEngine::GUI::MyGUIManager *mGuiManager; HUD *hud; diff --git a/apps/openmw/mwinput/inputmanager.cpp b/apps/openmw/mwinput/inputmanager.cpp index 8fd6a9c6b1..3ae1daadf8 100644 --- a/apps/openmw/mwinput/inputmanager.cpp +++ b/apps/openmw/mwinput/inputmanager.cpp @@ -69,8 +69,6 @@ namespace MWInput A_ToggleWeapon, A_ToggleSpell, - A_ToggleFps, // Toggle FPS display (this is temporary) - A_Settings, // Temporary hotkey A_LAST // Marker for the last item @@ -95,11 +93,6 @@ namespace MWInput /* InputImpl Methods */ - void toggleFps() - { - windows.toggleFps(); - } - void toggleSpell() { if (windows.isGuiMode()) return; @@ -271,8 +264,6 @@ namespace MWInput "Draw Weapon"); disp->funcs.bind(A_ToggleSpell,boost::bind(&InputImpl::toggleSpell,this), "Ready hands"); - disp->funcs.bind(A_ToggleFps, boost::bind(&InputImpl::toggleFps, this), - "Toggle FPS display"); disp->funcs.bind(A_Settings, boost::bind(&InputImpl::showSettings, this), "Show settings window"); // Add the exit listener @@ -321,7 +312,6 @@ namespace MWInput disp->bind(A_ToggleWalk, KC_C); disp->bind(A_ToggleWeapon,KC_F); disp->bind(A_ToggleSpell,KC_R); - disp->bind(A_ToggleFps, KC_F10); disp->bind(A_Settings, KC_F2); // Key bindings for polled keys diff --git a/files/mygui/openmw_settings_window_layout.xml b/files/mygui/openmw_settings_window_layout.xml index dc1cbfa9e3..9b5826765f 100644 --- a/files/mygui/openmw_settings_window_layout.xml +++ b/files/mygui/openmw_settings_window_layout.xml @@ -68,25 +68,47 @@ - - - - - + + - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 57d834b14bcea471c335cf2581a0bb2c900ff33f Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 24 May 2012 12:05:43 +0200 Subject: [PATCH 267/325] fixed an issue with interactive messagebox --- apps/openmw/mwgui/messagebox.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwgui/messagebox.cpp b/apps/openmw/mwgui/messagebox.cpp index 9a06714780..9df80476ec 100644 --- a/apps/openmw/mwgui/messagebox.cpp +++ b/apps/openmw/mwgui/messagebox.cpp @@ -58,6 +58,7 @@ void MessageBoxManager::onFrame (float frameDuration) if(mInterMessageBoxe != NULL && mInterMessageBoxe->mMarkedToDelete) { delete mInterMessageBoxe; mInterMessageBoxe = NULL; + mWindowManager->popGuiMode(); } } From c0ee382c7211e027a22608cbf5194e4d7008bd5d Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 24 May 2012 13:21:52 +0200 Subject: [PATCH 268/325] Issue #176: made actor deregistration more robust --- apps/openmw/mwmechanics/actors.cpp | 5 ++++- apps/openmw/mwmechanics/actors.hpp | 2 ++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 5a17d50e4b..8f8fd68710 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -71,7 +71,10 @@ namespace MWMechanics void Actors::removeActor (const MWWorld::Ptr& ptr) { - mActors.erase (ptr); + std::set::iterator iter = mActors.find (ptr); + + if (iter!=mActors.end()) + mActors.erase (iter); } void Actors::dropActors (const MWWorld::Ptr::CellStore *cellStore) diff --git a/apps/openmw/mwmechanics/actors.hpp b/apps/openmw/mwmechanics/actors.hpp index 30e73ccf75..1be29463f0 100644 --- a/apps/openmw/mwmechanics/actors.hpp +++ b/apps/openmw/mwmechanics/actors.hpp @@ -32,6 +32,8 @@ namespace MWMechanics void removeActor (const MWWorld::Ptr& ptr); ///< Deregister an actor for stats management + /// + /// \note Ignored, if \a ptr is not a registered actor. void dropActors (const MWWorld::Ptr::CellStore *cellStore); ///< Deregister all actors in the given cell. From 684208dfc9eb457c20bd7c473e0a5c5993db5458 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 24 May 2012 13:26:07 +0200 Subject: [PATCH 269/325] Issue #176: when deleting objects, don't go through disable to remove actors from the mechanics manager --- apps/openmw/mwworld/world.cpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwworld/world.cpp b/apps/openmw/mwworld/world.cpp index c0107d9afe..6d42560d21 100644 --- a/apps/openmw/mwworld/world.cpp +++ b/apps/openmw/mwworld/world.cpp @@ -553,16 +553,17 @@ namespace MWWorld { ptr.getRefData().setCount (0); + if (mWorldScene->getActiveCells().find (ptr.getCell())!=mWorldScene->getActiveCells().end()) + { + MWBase::Environment::get().getMechanicsManager()->removeActor (ptr); - if (mWorldScene->getActiveCells().find (ptr.getCell())!=mWorldScene->getActiveCells().end()){ -// Class::get (ptr).disable (ptr, mEnvironment); /// \todo this line needs to be removed - MWBase::Environment::get().getSoundManager()->stopSound3D (ptr); + MWBase::Environment::get().getSoundManager()->stopSound3D (ptr); - mPhysics->removeObject (ptr.getRefData().getHandle()); - mRendering->removeObject(ptr); + mPhysics->removeObject (ptr.getRefData().getHandle()); + mRendering->removeObject(ptr); - mLocalScripts.remove (ptr); - } + mLocalScripts.remove (ptr); + } } } From 05fd8f0211967781ce0848c82d8138e3eb749eee Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 24 May 2012 05:30:22 -0700 Subject: [PATCH 270/325] Update the actual sounds and music volume when settings change --- apps/openmw/mwsound/soundmanager.cpp | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/apps/openmw/mwsound/soundmanager.cpp b/apps/openmw/mwsound/soundmanager.cpp index 27294ae773..ff618ac334 100644 --- a/apps/openmw/mwsound/soundmanager.cpp +++ b/apps/openmw/mwsound/soundmanager.cpp @@ -539,6 +539,30 @@ namespace MWSound mSFXVolume = Settings::Manager::getFloat("sfx volume", "Sound"); mFootstepsVolume = Settings::Manager::getFloat("footsteps volume", "Sound"); mVoiceVolume = Settings::Manager::getFloat("voice volume", "Sound"); + + SoundMap::iterator snditer = mActiveSounds.begin(); + while(snditer != mActiveSounds.end()) + { + if(snditer->second.second != "_say_sound") + { + float basevol = mMasterVolume * mSFXVolume; + float min, max; + lookup(snditer->second.second, basevol, min, max); + snditer->first->mBaseVolume = basevol; + } + else + { + float basevol = mMasterVolume * mVoiceVolume; + snditer->first->mBaseVolume = basevol; + } + snditer->first->update(); + snditer++; + } + if(mMusic) + { + mMusic->mBaseVolume = mMasterVolume * mMusicVolume; + mMusic->update(); + } } // Default readAll implementation, for decoders that can't do anything From a3a22e9096c1f055e20014690c359694c4033e59 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 24 May 2012 14:47:57 +0200 Subject: [PATCH 271/325] ingredient tooltip shows possible effects --- apps/openmw/mwclass/ingredient.cpp | 13 ++ apps/openmw/mwclass/potion.cpp | 2 +- apps/openmw/mwgui/tooltips.cpp | 6 +- apps/openmw/mwgui/tooltips.hpp | 9 +- apps/openmw/mwgui/widgets.cpp | 195 ++++++++++++++++++----------- apps/openmw/mwgui/widgets.hpp | 56 ++++++--- 6 files changed, 178 insertions(+), 103 deletions(-) diff --git a/apps/openmw/mwclass/ingredient.cpp b/apps/openmw/mwclass/ingredient.cpp index c0186da37a..0c7fa7e698 100644 --- a/apps/openmw/mwclass/ingredient.cpp +++ b/apps/openmw/mwclass/ingredient.cpp @@ -135,6 +135,19 @@ namespace MWClass text += MWGui::ToolTips::getMiscString(ref->base->script, "Script"); } + MWGui::Widgets::SpellEffectList list; + for (int i=0; i<4; ++i) + { + if (ref->base->data.effectID[i] < 0) + continue; + MWGui::Widgets::SpellEffectParams params; + params.mEffectID = ref->base->data.effectID[i]; + params.mAttribute = ref->base->data.attributes[i]; + params.mSkill = ref->base->data.skills[i]; + list.push_back(params); + } + info.effects = list; + info.text = text; return info; diff --git a/apps/openmw/mwclass/potion.cpp b/apps/openmw/mwclass/potion.cpp index ffc8386396..157af01f55 100644 --- a/apps/openmw/mwclass/potion.cpp +++ b/apps/openmw/mwclass/potion.cpp @@ -132,7 +132,7 @@ namespace MWClass text += "\n" + store.gameSettings.search("sWeight")->str + ": " + MWGui::ToolTips::toString(ref->base->data.weight); text += MWGui::ToolTips::getValueString(ref->base->data.value, store.gameSettings.search("sValue")->str); - info.effects = &ref->base->effects; + info.effects = MWGui::Widgets::MWEffectList::effectListFromESM(&ref->base->effects); if (MWBase::Environment::get().getWindowManager()->getFullHelp()) { text += MWGui::ToolTips::getMiscString(ref->ref.owner, "Owner"); diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 3ade598baa..c61aa56a39 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -285,7 +285,7 @@ IntSize ToolTips::createToolTip(const MWGui::ToolTipInfo& info) IntSize totalSize = IntSize( std::max(textSize.width, captionSize.width + ((image != "") ? imageCaptionHPadding : 0)), ((text != "") ? textSize.height + imageCaptionVPadding : 0) + captionHeight ); - if (info.effects != 0) + if (!info.effects.empty()) { Widget* effectArea = mDynamicToolTipBox->createWidget("", IntCoord(0, totalSize.height, 300, 300-totalSize.height), @@ -305,7 +305,7 @@ IntSize ToolTips::createToolTip(const MWGui::ToolTipInfo& info) effectsWidget->setEffectList(info.effects); std::vector effectItems; - effectsWidget->createEffectWidgets(effectItems, effectArea, coord, true, Widgets::MWEffectList::EF_Potion); + effectsWidget->createEffectWidgets(effectItems, effectArea, coord, true, Widgets::MWEffectList::EF_NoTarget); totalSize.height += coord.top-6; totalSize.width = std::max(totalSize.width, coord.width); } @@ -321,7 +321,7 @@ IntSize ToolTips::createToolTip(const MWGui::ToolTipInfo& info) Widgets::MWEffectListPtr enchantWidget = enchantArea->createWidget ("MW_StatName", coord, Align::Default, "ToolTipEnchantWidget"); enchantWidget->setWindowManager(mWindowManager); - enchantWidget->setEffectList(&enchant->effects); + enchantWidget->setEffectList(Widgets::MWEffectList::effectListFromESM(&enchant->effects)); std::vector enchantEffectItems; int flag = (enchant->data.type == ESM::Enchantment::ConstantEffect) ? Widgets::MWEffectList::EF_Constant : 0; diff --git a/apps/openmw/mwgui/tooltips.hpp b/apps/openmw/mwgui/tooltips.hpp index 4be0baff9d..6d4a205d1a 100644 --- a/apps/openmw/mwgui/tooltips.hpp +++ b/apps/openmw/mwgui/tooltips.hpp @@ -5,6 +5,8 @@ #include #include "../mwworld/ptr.hpp" +#include "widgets.hpp" + namespace MWGui { class WindowManager; @@ -13,11 +15,6 @@ namespace MWGui struct ToolTipInfo { public: - ToolTipInfo() : - effects(0) - { - }; - std::string caption; std::string text; std::string icon; @@ -26,7 +23,7 @@ namespace MWGui std::string enchant; // effects (for potions, ingredients) - const ESM::EffectList* effects; + Widgets::SpellEffectList effects; }; class ToolTips : public OEngine::GUI::Layout diff --git a/apps/openmw/mwgui/widgets.cpp b/apps/openmw/mwgui/widgets.cpp index 0422bb0e23..2fd40b7c22 100644 --- a/apps/openmw/mwgui/widgets.cpp +++ b/apps/openmw/mwgui/widgets.cpp @@ -234,8 +234,17 @@ void MWSpell::createEffectWidgets(std::vector &effects, MyGUI: { effect = creator->createWidget("MW_EffectImage", coord, MyGUI::Align::Default); effect->setWindowManager(mWindowManager); - effect->setFlags(flags); - effect->setSpellEffect(*it); + SpellEffectParams params; + params.mEffectID = it->effectID; + params.mSkill = it->skill; + params.mAttribute = it->attribute; + params.mDuration = it->duration; + params.mMagnMin = it->magnMin; + params.mMagnMax = it->magnMax; + params.mRange = it->range; + params.mIsConstant = (flags & MWEffectList::EF_Constant); + params.mNoTarget = (flags & MWEffectList::EF_NoTarget); + effect->setSpellEffect(params); effects.push_back(effect); coord.top += effect->getHeight(); coord.width = std::max(coord.width, effect->getRequestedWidth()); @@ -274,7 +283,7 @@ MWEffectList::MWEffectList() { } -void MWEffectList::setEffectList(const ESM::EffectList* list) +void MWEffectList::setEffectList(const SpellEffectList& list) { mEffectList = list; updateWidgets(); @@ -283,25 +292,26 @@ void MWEffectList::setEffectList(const ESM::EffectList* list) void MWEffectList::createEffectWidgets(std::vector &effects, MyGUI::WidgetPtr creator, MyGUI::IntCoord &coord, bool center, int flags) { // We don't know the width of all the elements beforehand, so we do it in - // 2 steps: first, create all widgets and check their width + // 2 steps: first, create all widgets and check their width.... MWSpellEffectPtr effect = nullptr; - std::vector::const_iterator end = mEffectList->list.end(); int maxwidth = coord.width; - for (std::vector::const_iterator it = mEffectList->list.begin(); it != end; ++it) + + for (SpellEffectList::iterator it=mEffectList.begin(); + it != mEffectList.end(); ++it) { effect = creator->createWidget("MW_EffectImage", coord, MyGUI::Align::Default); effect->setWindowManager(mWindowManager); - effect->setFlags(flags); + it->mIsConstant = (flags & EF_Constant); + it->mNoTarget = (flags & EF_NoTarget); effect->setSpellEffect(*it); effects.push_back(effect); - if (effect->getRequestedWidth() > maxwidth) maxwidth = effect->getRequestedWidth(); coord.top += effect->getHeight(); } - // then adjust the size for all widgets + // ... then adjust the size for all widgets for (std::vector::iterator it = effects.begin(); it != effects.end(); ++it) { effect = static_cast(*it); @@ -334,6 +344,25 @@ MWEffectList::~MWEffectList() { } +SpellEffectList MWEffectList::effectListFromESM(const ESM::EffectList* effects) +{ + SpellEffectList result; + std::vector::const_iterator end = effects->list.end(); + for (std::vector::const_iterator it = effects->list.begin(); it != end; ++it) + { + SpellEffectParams params; + params.mEffectID = it->effectID; + params.mSkill = it->skill; + params.mAttribute = it->attribute; + params.mDuration = it->duration; + params.mMagnMin = it->magnMin; + params.mMagnMax = it->magnMax; + params.mRange = it->range; + result.push_back(params); + } + return result; +} + /* MWSpellEffect */ MWSpellEffect::MWSpellEffect() @@ -341,13 +370,12 @@ MWSpellEffect::MWSpellEffect() , imageWidget(nullptr) , textWidget(nullptr) , mRequestedWidth(0) - , mFlags(0) { } -void MWSpellEffect::setSpellEffect(SpellEffectValue value) +void MWSpellEffect::setSpellEffect(const SpellEffectParams& params) { - effect = value; + mEffectParams = params; updateWidgets(); } @@ -357,74 +385,71 @@ void MWSpellEffect::updateWidgets() return; const ESMS::ESMStore &store = mWindowManager->getStore(); - const ESM::MagicEffect *magicEffect = store.magicEffects.search(effect.effectID); + const ESM::MagicEffect *magicEffect = store.magicEffects.search(mEffectParams.mEffectID); + if (!magicEffect) + return; if (textWidget) { - if (magicEffect) + std::string pt = mWindowManager->getGameSettingString("spoint", ""); + std::string pts = mWindowManager->getGameSettingString("spoints", ""); + std::string to = " " + mWindowManager->getGameSettingString("sTo", "") + " "; + std::string sec = " " + mWindowManager->getGameSettingString("ssecond", ""); + std::string secs = " " + mWindowManager->getGameSettingString("sseconds", ""); + + std::string effectIDStr = effectIDToString(mEffectParams.mEffectID); + std::string spellLine = mWindowManager->getGameSettingString(effectIDStr, ""); + if (effectInvolvesSkill(effectIDStr) && mEffectParams.mSkill >= 0 && mEffectParams.mSkill < ESM::Skill::Length) { - std::string pt = mWindowManager->getGameSettingString("spoint", ""); - std::string pts = mWindowManager->getGameSettingString("spoints", ""); - std::string to = " " + mWindowManager->getGameSettingString("sTo", "") + " "; - std::string sec = " " + mWindowManager->getGameSettingString("ssecond", ""); - std::string secs = " " + mWindowManager->getGameSettingString("sseconds", ""); - - std::string effectIDStr = effectIDToString(effect.effectID); - std::string spellLine = mWindowManager->getGameSettingString(effectIDStr, ""); - if (effect.skill >= 0 && effect.skill < ESM::Skill::Length) - { - spellLine += " " + mWindowManager->getGameSettingString(ESM::Skill::sSkillNameIds[effect.skill], ""); - } - if (effect.attribute >= 0 && effect.attribute < 8) - { - static const char *attributes[8] = { - "sAttributeStrength", - "sAttributeIntelligence", - "sAttributeWillpower", - "sAttributeAgility", - "sAttributeSpeed", - "sAttributeEndurance", - "sAttributePersonality", - "sAttributeLuck" - }; - spellLine += " " + mWindowManager->getGameSettingString(attributes[effect.attribute], ""); - } - - if ((effect.magnMin >= 0 || effect.magnMax >= 0) && effectHasMagnitude(effectIDStr)) - { - if (effect.magnMin == effect.magnMax) - spellLine += " " + boost::lexical_cast(effect.magnMin) + " " + ((effect.magnMin == 1) ? pt : pts); - else - { - spellLine += " " + boost::lexical_cast(effect.magnMin) + to + boost::lexical_cast(effect.magnMax) + " " + pts; - } - } - - // constant effects have no duration and no target - if (!(mFlags & MWEffectList::EF_Constant)) - { - if (effect.duration >= 0 && effectHasDuration(effectIDStr)) - { - spellLine += " " + mWindowManager->getGameSettingString("sfor", "") + " " + boost::lexical_cast(effect.duration) + ((effect.duration == 1) ? sec : secs); - } - - // potions have no target - if (!(mFlags & MWEffectList::EF_Potion)) - { - std::string on = mWindowManager->getGameSettingString("sonword", ""); - if (effect.range == ESM::RT_Self) - spellLine += " " + on + " " + mWindowManager->getGameSettingString("sRangeSelf", ""); - else if (effect.range == ESM::RT_Touch) - spellLine += " " + on + " " + mWindowManager->getGameSettingString("sRangeTouch", ""); - else if (effect.range == ESM::RT_Target) - spellLine += " " + on + " " + mWindowManager->getGameSettingString("sRangeTarget", ""); - } - } - - static_cast(textWidget)->setCaption(spellLine); - mRequestedWidth = textWidget->getTextSize().width + 24; + spellLine += " " + mWindowManager->getGameSettingString(ESM::Skill::sSkillNameIds[mEffectParams.mSkill], ""); } - else - static_cast(textWidget)->setCaption(""); + if (effectInvolvesAttribute(effectIDStr) && mEffectParams.mAttribute >= 0 && mEffectParams.mAttribute < 8) + { + static const char *attributes[8] = { + "sAttributeStrength", + "sAttributeIntelligence", + "sAttributeWillpower", + "sAttributeAgility", + "sAttributeSpeed", + "sAttributeEndurance", + "sAttributePersonality", + "sAttributeLuck" + }; + spellLine += " " + mWindowManager->getGameSettingString(attributes[mEffectParams.mAttribute], ""); + } + + if ((mEffectParams.mMagnMin >= 0 || mEffectParams.mMagnMax >= 0) && effectHasMagnitude(effectIDStr)) + { + if (mEffectParams.mMagnMin == mEffectParams.mMagnMax) + spellLine += " " + boost::lexical_cast(mEffectParams.mMagnMin) + " " + ((mEffectParams.mMagnMin == 1) ? pt : pts); + else + { + spellLine += " " + boost::lexical_cast(mEffectParams.mMagnMin) + to + boost::lexical_cast(mEffectParams.mMagnMax) + " " + pts; + } + } + + // constant effects have no duration and no target + if (!mEffectParams.mIsConstant) + { + if (mEffectParams.mDuration >= 0 && effectHasDuration(effectIDStr)) + { + spellLine += " " + mWindowManager->getGameSettingString("sfor", "") + " " + boost::lexical_cast(mEffectParams.mDuration) + ((mEffectParams.mDuration == 1) ? sec : secs); + } + + // potions have no target + if (!mEffectParams.mNoTarget) + { + std::string on = mWindowManager->getGameSettingString("sonword", ""); + if (mEffectParams.mRange == ESM::RT_Self) + spellLine += " " + on + " " + mWindowManager->getGameSettingString("sRangeSelf", ""); + else if (mEffectParams.mRange == ESM::RT_Touch) + spellLine += " " + on + " " + mWindowManager->getGameSettingString("sRangeTouch", ""); + else if (mEffectParams.mRange == ESM::RT_Target) + spellLine += " " + on + " " + mWindowManager->getGameSettingString("sRangeTarget", ""); + } + } + + static_cast(textWidget)->setCaption(spellLine); + mRequestedWidth = textWidget->getTextSize().width + 24; } if (imageWidget) { @@ -677,6 +702,24 @@ bool MWSpellEffect::effectHasMagnitude(const std::string& effect) return (std::find(effectsWithoutMagnitude.begin(), effectsWithoutMagnitude.end(), effect) == effectsWithoutMagnitude.end()); } +bool MWSpellEffect::effectInvolvesAttribute (const std::string& effect) +{ + return (effect == "sEffectRestoreAttribute" + || effect == "sEffectAbsorbAttribute" + || effect == "sEffectDrainAttribute" + || effect == "sEffectFortifyAttribute" + || effect == "sEffectDamageAttribute"); +} + +bool MWSpellEffect::effectInvolvesSkill (const std::string& effect) +{ + return (effect == "sEffectRestoreSkill" + || effect == "sEffectAbsorbSkill" + || effect == "sEffectDrainSkill" + || effect == "sEffectFortifySkill" + || effect == "sEffectDamageSkill"); +} + MWSpellEffect::~MWSpellEffect() { } diff --git a/apps/openmw/mwgui/widgets.hpp b/apps/openmw/mwgui/widgets.hpp index 6e230e2c63..54a278f1c2 100644 --- a/apps/openmw/mwgui/widgets.hpp +++ b/apps/openmw/mwgui/widgets.hpp @@ -21,20 +21,40 @@ namespace MWGui namespace Widgets { + class MWEffectList; + void fixTexturePath(std::string &path); struct SpellEffectParams { - bool mHasTarget; // potion effects for example have no target (target is always the player) - bool mIsConstant; // constant effect means that duration will not be displayed - std::string effectID; + SpellEffectParams() + : mMagnMin(-1) + , mMagnMax(-1) + , mRange(-1) + , mDuration(-1) + , mSkill(-1) + , mAttribute(-1) + , mEffectID(-1) + , mNoTarget(false) + , mIsConstant(false) + { + } - // note that the ESM::MagicEffect (retrieved through effectID) might already store skill and attribute, - // in that case the ESM::MagicEffect skill/attribute is preferred. this is just here for ingredients which - // have them defined elsewhere. - signed char skill, attribute; + bool mNoTarget; // potion effects for example have no target (target is always the player) + bool mIsConstant; // constant effect means that duration will not be displayed + + // value of -1 here means the effect is unknown to the player + short mEffectID; + + // value of -1 here means there is no skill/attribute + signed char mSkill, mAttribute; + + // value of -1 here means the value is unavailable + int mMagnMin, mMagnMax, mRange, mDuration; }; + typedef std::vector SpellEffectList; + class MYGUI_EXPORT MWSkill : public Widget { MYGUI_RTTI_DERIVED( MWSkill ); @@ -120,6 +140,9 @@ namespace MWGui }; typedef MWAttribute* MWAttributePtr; + /** + * @todo remove this class and use MWEffectList instead + */ class MWSpellEffect; class MYGUI_EXPORT MWSpell : public Widget { @@ -167,12 +190,14 @@ namespace MWGui enum EffectFlags { - EF_Potion = 0x01, // potions have no target (target is always the player) + EF_NoTarget = 0x01, // potions have no target (target is always the player) EF_Constant = 0x02 // constant effect means that duration will not be displayed }; void setWindowManager(WindowManager* parWindowManager) { mWindowManager = parWindowManager; } - void setEffectList(const ESM::EffectList* list); + void setEffectList(const SpellEffectList& list); + + static SpellEffectList effectListFromESM(const ESM::EffectList* effects); /** * @param vector to store the created effect widgets @@ -192,7 +217,7 @@ namespace MWGui void updateWidgets(); WindowManager* mWindowManager; - const ESM::EffectList* mEffectList; + SpellEffectList mEffectList; }; typedef MWEffectList* MWEffectListPtr; @@ -205,14 +230,13 @@ namespace MWGui typedef ESM::ENAMstruct SpellEffectValue; void setWindowManager(WindowManager* parWindowManager) { mWindowManager = parWindowManager; } - void setSpellEffect(SpellEffectValue value); - void setFlags(int flags) { mFlags = flags; } + void setSpellEffect(const SpellEffectParams& params); std::string effectIDToString(const short effectID); bool effectHasMagnitude (const std::string& effect); bool effectHasDuration (const std::string& effect); - - const SpellEffectValue &getSpellEffect() const { return effect; } + bool effectInvolvesAttribute (const std::string& effect); + bool effectInvolvesSkill (const std::string& effect); int getRequestedWidth() const { return mRequestedWidth; } @@ -226,8 +250,7 @@ namespace MWGui void updateWidgets(); WindowManager* mWindowManager; - SpellEffectValue effect; - int mFlags; + SpellEffectParams mEffectParams; MyGUI::ImageBox* imageWidget; MyGUI::TextBox* textWidget; int mRequestedWidth; @@ -259,7 +282,6 @@ namespace MWGui MyGUI::TextBox* barTextWidget; }; typedef MWDynamicStat* MWDynamicStatPtr; - } } From c2b818373e075af0c3b8be49e9caacfa4e78d871 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 24 May 2012 15:11:45 +0200 Subject: [PATCH 272/325] adjust tooltip skin, now is never transparent --- apps/openmw/mwgui/tooltips.cpp | 8 +++---- files/mygui/openmw_hud_box.skin.xml | 37 +++++++++++++++++++++++++++++ files/mygui/openmw_tooltips.xml | 18 +++++++------- 3 files changed, 50 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 3ade598baa..49e68bd86d 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -37,10 +37,10 @@ void ToolTips::setEnabled(bool enabled) void ToolTips::onFrame(float frameDuration) { - MyGUI::Gui::getInstance().destroyWidget(mDynamicToolTipBox); - mDynamicToolTipBox = mMainWidget->createWidget("HUD_Box", - IntCoord(0, 0, mMainWidget->getCoord().width, mMainWidget->getCoord().height), - Align::Stretch, "DynamicToolTipBox"); + while (mDynamicToolTipBox->getChildCount()) + { + MyGUI::Gui::getInstance().destroyWidget(mDynamicToolTipBox->getChildAt(0)); + } // start by hiding everything for (unsigned int i=0; i < mMainWidget->getChildCount(); ++i) diff --git a/files/mygui/openmw_hud_box.skin.xml b/files/mygui/openmw_hud_box.skin.xml index 86b63fcf6e..ce231e5bb9 100644 --- a/files/mygui/openmw_hud_box.skin.xml +++ b/files/mygui/openmw_hud_box.skin.xml @@ -38,4 +38,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/mygui/openmw_tooltips.xml b/files/mygui/openmw_tooltips.xml index a1673d3462..262fd2020a 100644 --- a/files/mygui/openmw_tooltips.xml +++ b/files/mygui/openmw_tooltips.xml @@ -4,12 +4,12 @@ - + - + @@ -22,7 +22,7 @@ - + @@ -40,7 +40,7 @@ - + @@ -63,7 +63,7 @@ - + @@ -78,7 +78,7 @@ - + @@ -98,7 +98,7 @@ - + @@ -135,7 +135,7 @@ - + @@ -156,7 +156,7 @@ - + From 09c870ad68d79424eb089ab50c4cda569805a4af Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 25 May 2012 12:58:28 +0200 Subject: [PATCH 273/325] first alchemy window layout (not pretty) --- apps/openmw/mwgui/alchemywindow.cpp | 27 +++++++ apps/openmw/mwgui/alchemywindow.hpp | 7 ++ files/mygui/openmw_alchemy_window_layout.xml | 80 ++++++++++++++++++++ 3 files changed, 114 insertions(+) diff --git a/apps/openmw/mwgui/alchemywindow.cpp b/apps/openmw/mwgui/alchemywindow.cpp index 570a1f6d47..90326c3d79 100644 --- a/apps/openmw/mwgui/alchemywindow.cpp +++ b/apps/openmw/mwgui/alchemywindow.cpp @@ -1,10 +1,37 @@ #include "alchemywindow.hpp" +#include "window_manager.hpp" + namespace MWGui { AlchemyWindow::AlchemyWindow(WindowManager& parWindowManager) : WindowBase("openmw_alchemy_window_layout.xml", parWindowManager) { + getWidget(mCreateButton, "CreateButton"); + getWidget(mCancelButton, "CancelButton"); + + + MyGUI::Widget* buttonBox = mCancelButton->getParent(); + int cancelButtonWidth = mCancelButton->getTextSize().width + 24; + mCancelButton->setCoord(buttonBox->getWidth() - cancelButtonWidth, + mCancelButton->getTop(), cancelButtonWidth, mCancelButton->getHeight()); + int createButtonWidth = mCreateButton->getTextSize().width + 24; + mCreateButton->setCoord(buttonBox->getWidth() - createButtonWidth - cancelButtonWidth - 4, + mCreateButton->getTop(), createButtonWidth, mCreateButton->getHeight()); + + mCreateButton->eventMouseButtonClick += MyGUI::newDelegate(this, &AlchemyWindow::onCreateButtonClicked); + mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &AlchemyWindow::onCancelButtonClicked); + center(); } + + void AlchemyWindow::onCancelButtonClicked(MyGUI::Widget* _sender) + { + mWindowManager.popGuiMode(); + mWindowManager.popGuiMode(); + } + + void AlchemyWindow::onCreateButtonClicked(MyGUI::Widget* _sender) + { + } } diff --git a/apps/openmw/mwgui/alchemywindow.hpp b/apps/openmw/mwgui/alchemywindow.hpp index 37e50413b9..d43bb6d334 100644 --- a/apps/openmw/mwgui/alchemywindow.hpp +++ b/apps/openmw/mwgui/alchemywindow.hpp @@ -9,6 +9,13 @@ namespace MWGui { public: AlchemyWindow(WindowManager& parWindowManager); + + protected: + MyGUI::Button* mCreateButton; + MyGUI::Button* mCancelButton; + + void onCancelButtonClicked(MyGUI::Widget* _sender); + void onCreateButtonClicked(MyGUI::Widget* _sender); }; } diff --git a/files/mygui/openmw_alchemy_window_layout.xml b/files/mygui/openmw_alchemy_window_layout.xml index c6c4b1caa6..22511f0134 100644 --- a/files/mygui/openmw_alchemy_window_layout.xml +++ b/files/mygui/openmw_alchemy_window_layout.xml @@ -3,6 +3,86 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 6eb15f7680be9c48409cc5c0eeb1e7e413fe6b1d Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 25 May 2012 15:24:33 +0200 Subject: [PATCH 274/325] auto-select the alchemy tools with highest quality --- apps/openmw/mwgui/alchemywindow.cpp | 173 ++++++++++++++++++++++++++ apps/openmw/mwgui/alchemywindow.hpp | 21 +++- apps/openmw/mwgui/container.cpp | 10 +- apps/openmw/mwgui/container.hpp | 6 +- apps/openmw/mwgui/inventorywindow.cpp | 2 +- apps/openmw/mwgui/inventorywindow.hpp | 2 +- apps/openmw/mwgui/window_base.cpp | 9 ++ apps/openmw/mwgui/window_base.hpp | 1 + apps/openmw/mwgui/window_manager.cpp | 3 - 9 files changed, 218 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwgui/alchemywindow.cpp b/apps/openmw/mwgui/alchemywindow.cpp index 90326c3d79..60ad123a54 100644 --- a/apps/openmw/mwgui/alchemywindow.cpp +++ b/apps/openmw/mwgui/alchemywindow.cpp @@ -1,15 +1,46 @@ #include "alchemywindow.hpp" +#include "../mwbase/environment.hpp" +#include "../mwworld/world.hpp" +#include "../mwworld/player.hpp" +#include "../mwworld/containerstore.hpp" + #include "window_manager.hpp" +namespace +{ + std::string getIconPath(MWWorld::Ptr ptr) + { + std::string path = std::string("icons\\"); + path += MWWorld::Class::get(ptr).getInventoryIcon(ptr); + int pos = path.rfind("."); + path.erase(pos); + path.append(".dds"); + return path; + } +} + namespace MWGui { AlchemyWindow::AlchemyWindow(WindowManager& parWindowManager) : WindowBase("openmw_alchemy_window_layout.xml", parWindowManager) + , ContainerBase(0) { getWidget(mCreateButton, "CreateButton"); getWidget(mCancelButton, "CancelButton"); + getWidget(mIngredient1, "Ingredient1"); + getWidget(mIngredient2, "Ingredient2"); + getWidget(mIngredient3, "Ingredient3"); + getWidget(mIngredient4, "Ingredient4"); + getWidget(mApparatus1, "Apparatus1"); + getWidget(mApparatus2, "Apparatus2"); + getWidget(mApparatus3, "Apparatus3"); + getWidget(mApparatus4, "Apparatus4"); + mIngredient1->eventMouseButtonClick += MyGUI::newDelegate(this, &AlchemyWindow::onIngredientSelected); + mIngredient2->eventMouseButtonClick += MyGUI::newDelegate(this, &AlchemyWindow::onIngredientSelected); + mIngredient3->eventMouseButtonClick += MyGUI::newDelegate(this, &AlchemyWindow::onIngredientSelected); + mIngredient4->eventMouseButtonClick += MyGUI::newDelegate(this, &AlchemyWindow::onIngredientSelected); MyGUI::Widget* buttonBox = mCancelButton->getParent(); int cancelButtonWidth = mCancelButton->getTextSize().width + 24; @@ -22,6 +53,12 @@ namespace MWGui mCreateButton->eventMouseButtonClick += MyGUI::newDelegate(this, &AlchemyWindow::onCreateButtonClicked); mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &AlchemyWindow::onCancelButtonClicked); + MyGUI::ScrollView* itemView; + MyGUI::Widget* containerWidget; + getWidget(containerWidget, "Items"); + getWidget(itemView, "ItemView"); + setWidgets(containerWidget, itemView); + center(); } @@ -34,4 +71,140 @@ namespace MWGui void AlchemyWindow::onCreateButtonClicked(MyGUI::Widget* _sender) { } + + void AlchemyWindow::open() + { + openContainer(MWBase::Environment::get().getWorld()->getPlayer().getPlayer()); + setFilter(ContainerBase::Filter_Ingredients); + + // pick the best available apparatus + MWWorld::ContainerStore& store = MWWorld::Class::get(mContainer).getContainerStore(mContainer); + + MWWorld::Ptr bestAlbemic; + MWWorld::Ptr bestMortarPestle; + MWWorld::Ptr bestCalcinator; + MWWorld::Ptr bestRetort; + + for (MWWorld::ContainerStoreIterator it(store.begin(MWWorld::ContainerStore::Type_Apparatus)); + it != store.end(); ++it) + { + ESMS::LiveCellRef* ref = it->get(); + if (ref->base->data.type == ESM::Apparatus::Albemic + && (bestAlbemic.isEmpty() || ref->base->data.quality > bestAlbemic.get()->base->data.quality)) + bestAlbemic = *it; + else if (ref->base->data.type == ESM::Apparatus::MortarPestle + && (bestMortarPestle.isEmpty() || ref->base->data.quality > bestMortarPestle.get()->base->data.quality)) + bestMortarPestle = *it; + else if (ref->base->data.type == ESM::Apparatus::Calcinator + && (bestCalcinator.isEmpty() || ref->base->data.quality > bestCalcinator.get()->base->data.quality)) + bestCalcinator = *it; + else if (ref->base->data.type == ESM::Apparatus::Retort + && (bestRetort.isEmpty() || ref->base->data.quality > bestRetort.get()->base->data.quality)) + bestRetort = *it; + } + + if (!bestMortarPestle.isEmpty()) + { + mApparatus1->setUserString("ToolTipType", "ItemPtr"); + mApparatus1->setUserData(bestMortarPestle); + mApparatus1->setImageTexture(getIconPath(bestMortarPestle)); + } + if (!bestAlbemic.isEmpty()) + { + mApparatus2->setUserString("ToolTipType", "ItemPtr"); + mApparatus2->setUserData(bestAlbemic); + mApparatus2->setImageTexture(getIconPath(bestAlbemic)); + } + if (!bestCalcinator.isEmpty()) + { + mApparatus3->setUserString("ToolTipType", "ItemPtr"); + mApparatus3->setUserData(bestCalcinator); + mApparatus3->setImageTexture(getIconPath(bestCalcinator)); + } + if (!bestRetort.isEmpty()) + { + mApparatus4->setUserString("ToolTipType", "ItemPtr"); + mApparatus4->setUserData(bestRetort); + mApparatus4->setImageTexture(getIconPath(bestRetort)); + } + } + + void AlchemyWindow::onIngredientSelected(MyGUI::Widget* _sender) + { + _sender->clearUserStrings(); + static_cast(_sender)->setImageTexture(""); + if (_sender->getChildCount()) + MyGUI::Gui::getInstance().destroyWidget(_sender->getChildAt(0)); + drawItems(); + update(); + } + + void AlchemyWindow::onSelectedItemImpl(MWWorld::Ptr item) + { + MyGUI::ImageBox* add = NULL; + + if (!mIngredient1->isUserString("ToolTipType")) + add = mIngredient1; + if (add == NULL && !mIngredient2->isUserString("ToolTipType")) + add = mIngredient2; + if (add == NULL && !mIngredient3->isUserString("ToolTipType")) + add = mIngredient3; + if (add == NULL && !mIngredient4->isUserString("ToolTipType")) + add = mIngredient4; + + if (add != NULL) + { + add->setUserString("ToolTipType", "ItemPtr"); + add->setUserData(item); + add->setImageTexture(getIconPath(item)); + drawItems(); + update(); + } + } + + std::vector AlchemyWindow::itemsToIgnore() + { + std::vector ignore; + // don't show ingredients that are currently selected in the "available ingredients" box. + if (mIngredient1->isUserString("ToolTipType")) + ignore.push_back(*mIngredient1->getUserData()); + if (mIngredient2->isUserString("ToolTipType")) + ignore.push_back(*mIngredient2->getUserData()); + if (mIngredient3->isUserString("ToolTipType")) + ignore.push_back(*mIngredient3->getUserData()); + if (mIngredient4->isUserString("ToolTipType")) + ignore.push_back(*mIngredient4->getUserData()); + + return ignore; + } + + void AlchemyWindow::update() + { + // update ingredient count labels + for (int i=0; i<4; ++i) + { + MyGUI::ImageBox* ingredient; + if (i==0) + ingredient = mIngredient1; + else if (i==1) + ingredient = mIngredient2; + else if (i==2) + ingredient = mIngredient3; + else if (i==3) + ingredient = mIngredient4; + + if (!ingredient->isUserString("ToolTipType")) + continue; + + if (ingredient->getChildCount()) + MyGUI::Gui::getInstance().destroyWidget(ingredient->getChildAt(0)); + + MyGUI::TextBox* text = ingredient->createWidget("SandBrightText", MyGUI::IntCoord(0, 14, 32, 18), MyGUI::Align::Default, std::string("Label")); + text->setTextAlign(MyGUI::Align::Right); + text->setNeedMouseFocus(false); + text->setTextShadow(true); + text->setTextShadowColour(MyGUI::Colour(0,0,0)); + text->setCaption(getCountString(ingredient->getUserData()->getRefData().getCount())); + } + } } diff --git a/apps/openmw/mwgui/alchemywindow.hpp b/apps/openmw/mwgui/alchemywindow.hpp index d43bb6d334..365ad96420 100644 --- a/apps/openmw/mwgui/alchemywindow.hpp +++ b/apps/openmw/mwgui/alchemywindow.hpp @@ -2,20 +2,39 @@ #define MWGUI_ALCHEMY_H #include "window_base.hpp" +#include "container.hpp" namespace MWGui { - class AlchemyWindow : public WindowBase + class AlchemyWindow : public WindowBase, public ContainerBase { public: AlchemyWindow(WindowManager& parWindowManager); + virtual void open(); + protected: MyGUI::Button* mCreateButton; MyGUI::Button* mCancelButton; + MyGUI::ImageBox* mIngredient1; + MyGUI::ImageBox* mIngredient2; + MyGUI::ImageBox* mIngredient3; + MyGUI::ImageBox* mIngredient4; + + MyGUI::ImageBox* mApparatus1; + MyGUI::ImageBox* mApparatus2; + MyGUI::ImageBox* mApparatus3; + MyGUI::ImageBox* mApparatus4; + void onCancelButtonClicked(MyGUI::Widget* _sender); void onCreateButtonClicked(MyGUI::Widget* _sender); + void onIngredientSelected(MyGUI::Widget* _sender); + + virtual void onSelectedItemImpl(MWWorld::Ptr item); + virtual std::vector itemsToIgnore(); + + void update(); }; } diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 8ac876c078..6aabeb2c6b 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -119,7 +119,7 @@ void ContainerBase::onSelectedItem(MyGUI::Widget* _sender) else onContainerClicked(mContainerWidget); } - else + else if (isTrading()) { MWWorld::Ptr object = (*_sender->getUserData()); int count = object.getRefData().getCount(); @@ -179,6 +179,10 @@ void ContainerBase::onSelectedItem(MyGUI::Widget* _sender) } } } + else + { + onSelectedItemImpl(*_sender->getUserData()); + } } void ContainerBase::sellAlreadyBoughtItem(MyGUI::Widget* _sender, int count) @@ -383,6 +387,8 @@ void ContainerBase::drawItems() + MWWorld::ContainerStore::Type_Lockpick + MWWorld::ContainerStore::Type_Light + MWWorld::ContainerStore::Type_Apparatus; } + else if (mFilter == Filter_Ingredients) + categories = MWWorld::ContainerStore::Type_Ingredient; /// \todo performance improvement: don't create/destroy all the widgets everytime the container window changes size, only reposition them @@ -514,6 +520,7 @@ void ContainerBase::drawItems() text->setNeedMouseFocus(false); text->setTextShadow(true); text->setTextShadowColour(MyGUI::Colour(0,0,0)); + text->setCaption(getCountString(displayCount)); y += 42; if (y > maxHeight) @@ -522,7 +529,6 @@ void ContainerBase::drawItems() y = 0; } - text->setCaption(getCountString(displayCount)); } } diff --git a/apps/openmw/mwgui/container.hpp b/apps/openmw/mwgui/container.hpp index 66cac82ce6..26e78149ae 100644 --- a/apps/openmw/mwgui/container.hpp +++ b/apps/openmw/mwgui/container.hpp @@ -55,7 +55,9 @@ namespace MWGui Filter_Weapon = 0x02, Filter_Apparel = 0x03, Filter_Magic = 0x04, - Filter_Misc = 0x05 + Filter_Misc = 0x05, + + Filter_Ingredients = 0x06 }; enum ItemState @@ -116,6 +118,8 @@ namespace MWGui virtual bool isTrading() { return false; } + virtual void onSelectedItemImpl(MWWorld::Ptr item) { ; } + virtual bool ignoreEquippedItems() { return false; } virtual std::vector itemsToIgnore() { return std::vector(); } }; diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 59be6a4959..04a30b69bf 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -97,7 +97,7 @@ namespace MWGui openContainer(player); } - void InventoryWindow::openInventory() + void InventoryWindow::open() { updateEncumbranceBar(); diff --git a/apps/openmw/mwgui/inventorywindow.hpp b/apps/openmw/mwgui/inventorywindow.hpp index fdb4438292..86f7ee3c7b 100644 --- a/apps/openmw/mwgui/inventorywindow.hpp +++ b/apps/openmw/mwgui/inventorywindow.hpp @@ -11,7 +11,7 @@ namespace MWGui public: InventoryWindow(WindowManager& parWindowManager,DragAndDrop* dragAndDrop); - void openInventory(); + virtual void open(); /// start trading, disables item drag&drop void startTrade(); diff --git a/apps/openmw/mwgui/window_base.cpp b/apps/openmw/mwgui/window_base.cpp index 1eb126a74c..45206214b8 100644 --- a/apps/openmw/mwgui/window_base.cpp +++ b/apps/openmw/mwgui/window_base.cpp @@ -13,6 +13,15 @@ void WindowBase::open() { } +void WindowBase::setVisible(bool visible) +{ + bool wasVisible = mMainWidget->getVisible(); + mMainWidget->setVisible(visible); + + if (!wasVisible && visible) + open(); +} + void WindowBase::center() { // Centre dialog diff --git a/apps/openmw/mwgui/window_base.hpp b/apps/openmw/mwgui/window_base.hpp index 99ddbe9181..9cfdbe2612 100644 --- a/apps/openmw/mwgui/window_base.hpp +++ b/apps/openmw/mwgui/window_base.hpp @@ -16,6 +16,7 @@ namespace MWGui typedef MyGUI::delegates::CMultiDelegate1 EventHandle_WindowBase; virtual void open(); + virtual void setVisible(bool visible); // calls open() if visible is true and was false before void center(); /** Event : Dialog finished, OK button clicked.\n diff --git a/apps/openmw/mwgui/window_manager.cpp b/apps/openmw/mwgui/window_manager.cpp index a29dd96a64..96469d105f 100644 --- a/apps/openmw/mwgui/window_manager.cpp +++ b/apps/openmw/mwgui/window_manager.cpp @@ -269,20 +269,17 @@ void WindowManager::updateVisible() map -> setVisible( (eff & GW_Map) != 0 ); mStatsWindow -> setVisible( (eff & GW_Stats) != 0 ); mInventoryWindow->setVisible(true); - mInventoryWindow->openInventory(); break; } case GM_Container: mContainerWindow->setVisible(true); mInventoryWindow->setVisible(true); - mInventoryWindow->openInventory(); break; case GM_Dialogue: mDialogueWindow->setVisible(true); break; case GM_Barter: mInventoryWindow->setVisible(true); - mInventoryWindow->openInventory(); mTradeWindow->setVisible(true); break; case GM_InterMessageBox: From 1df1b521a4d06edd482f18a36b4410b13d2c9021 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 25 May 2012 16:20:57 +0200 Subject: [PATCH 275/325] show the list of potion effects --- apps/openmw/mwgui/alchemywindow.cpp | 107 ++++++++++++++++++- apps/openmw/mwgui/alchemywindow.hpp | 4 + apps/openmw/mwgui/widgets.hpp | 7 ++ files/mygui/openmw_alchemy_window_layout.xml | 2 +- 4 files changed, 118 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/alchemywindow.cpp b/apps/openmw/mwgui/alchemywindow.cpp index 60ad123a54..c9548e05db 100644 --- a/apps/openmw/mwgui/alchemywindow.cpp +++ b/apps/openmw/mwgui/alchemywindow.cpp @@ -4,6 +4,7 @@ #include "../mwworld/world.hpp" #include "../mwworld/player.hpp" #include "../mwworld/containerstore.hpp" +#include "../mwsound/soundmanager.hpp" #include "window_manager.hpp" @@ -36,6 +37,7 @@ namespace MWGui getWidget(mApparatus2, "Apparatus2"); getWidget(mApparatus3, "Apparatus3"); getWidget(mApparatus4, "Apparatus4"); + getWidget(mEffectsBox, "CreatedEffects"); mIngredient1->eventMouseButtonClick += MyGUI::newDelegate(this, &AlchemyWindow::onIngredientSelected); mIngredient2->eventMouseButtonClick += MyGUI::newDelegate(this, &AlchemyWindow::onIngredientSelected); @@ -143,6 +145,41 @@ namespace MWGui { MyGUI::ImageBox* add = NULL; + // don't allow to add an ingredient that is already added + // (which could happen if two similiar ingredients don't stack because of script / owner) + bool alreadyAdded = false; + std::string name = MWWorld::Class::get(item).getName(item); + if (mIngredient1->isUserString("ToolTipType")) + { + MWWorld::Ptr item2 = *mIngredient1->getUserData(); + std::string name2 = MWWorld::Class::get(item2).getName(item2); + if (name == name2) + alreadyAdded = true; + } + if (mIngredient2->isUserString("ToolTipType")) + { + MWWorld::Ptr item2 = *mIngredient2->getUserData(); + std::string name2 = MWWorld::Class::get(item2).getName(item2); + if (name == name2) + alreadyAdded = true; + } + if (mIngredient3->isUserString("ToolTipType")) + { + MWWorld::Ptr item2 = *mIngredient3->getUserData(); + std::string name2 = MWWorld::Class::get(item2).getName(item2); + if (name == name2) + alreadyAdded = true; + } + if (mIngredient4->isUserString("ToolTipType")) + { + MWWorld::Ptr item2 = *mIngredient4->getUserData(); + std::string name2 = MWWorld::Class::get(item2).getName(item2); + if (name == name2) + alreadyAdded = true; + } + if (alreadyAdded) + return; + if (!mIngredient1->isUserString("ToolTipType")) add = mIngredient1; if (add == NULL && !mIngredient2->isUserString("ToolTipType")) @@ -159,6 +196,9 @@ namespace MWGui add->setImageTexture(getIconPath(item)); drawItems(); update(); + + std::string sound = MWWorld::Class::get(item).getUpSoundId(item); + MWBase::Environment::get().getSoundManager()->playSound (sound, 1.0, 1.0); } } @@ -180,7 +220,8 @@ namespace MWGui void AlchemyWindow::update() { - // update ingredient count labels + Widgets::SpellEffectList effects; + for (int i=0; i<4; ++i) { MyGUI::ImageBox* ingredient; @@ -196,6 +237,20 @@ namespace MWGui if (!ingredient->isUserString("ToolTipType")) continue; + // add the effects of this ingredient to list of effects + ESMS::LiveCellRef* ref = ingredient->getUserData()->get(); + for (int i=0; i<4; ++i) + { + if (ref->base->data.effectID[i] < 0) + continue; + MWGui::Widgets::SpellEffectParams params; + params.mEffectID = ref->base->data.effectID[i]; + params.mAttribute = ref->base->data.attributes[i]; + params.mSkill = ref->base->data.skills[i]; + effects.push_back(params); + } + + // update ingredient count labels if (ingredient->getChildCount()) MyGUI::Gui::getInstance().destroyWidget(ingredient->getChildAt(0)); @@ -206,5 +261,55 @@ namespace MWGui text->setTextShadowColour(MyGUI::Colour(0,0,0)); text->setCaption(getCountString(ingredient->getUserData()->getRefData().getCount())); } + + // now remove effects that are only present once + Widgets::SpellEffectList::iterator it = effects.begin(); + while (it != effects.end()) + { + Widgets::SpellEffectList::iterator next = it; + ++next; + bool found = false; + for (; next != effects.end(); ++next) + { + if (*next == *it) + found = true; + } + + if (!found) + it = effects.erase(it); + else + ++it; + } + + // now remove duplicates + Widgets::SpellEffectList old = effects; + effects.clear(); + for (Widgets::SpellEffectList::iterator it = old.begin(); + it != old.end(); ++it) + { + bool found = false; + for (Widgets::SpellEffectList::iterator it2 = effects.begin(); + it2 != effects.end(); ++it2) + { + if (*it2 == *it) + found = true; + } + if (!found) + effects.push_back(*it); + } + mEffects = effects; + + while (mEffectsBox->getChildCount()) + MyGUI::Gui::getInstance().destroyWidget(mEffectsBox->getChildAt(0)); + + MyGUI::IntCoord coord(0, 0, mEffectsBox->getWidth(), 24); + Widgets::MWEffectListPtr effectsWidget = mEffectsBox->createWidget + ("MW_StatName", coord, Align::Left | Align::Top); + effectsWidget->setWindowManager(&mWindowManager); + effectsWidget->setEffectList(effects); + + std::vector effectItems; + effectsWidget->createEffectWidgets(effectItems, mEffectsBox, coord, false, 0); + effectsWidget->setCoord(coord); } } diff --git a/apps/openmw/mwgui/alchemywindow.hpp b/apps/openmw/mwgui/alchemywindow.hpp index 365ad96420..17f363e92c 100644 --- a/apps/openmw/mwgui/alchemywindow.hpp +++ b/apps/openmw/mwgui/alchemywindow.hpp @@ -27,6 +27,10 @@ namespace MWGui MyGUI::ImageBox* mApparatus3; MyGUI::ImageBox* mApparatus4; + MyGUI::Widget* mEffectsBox; + + Widgets::SpellEffectList mEffects; // effects of created potion + void onCancelButtonClicked(MyGUI::Widget* _sender); void onCreateButtonClicked(MyGUI::Widget* _sender); void onIngredientSelected(MyGUI::Widget* _sender); diff --git a/apps/openmw/mwgui/widgets.hpp b/apps/openmw/mwgui/widgets.hpp index 54a278f1c2..c66bf5dd0e 100644 --- a/apps/openmw/mwgui/widgets.hpp +++ b/apps/openmw/mwgui/widgets.hpp @@ -51,6 +51,13 @@ namespace MWGui // value of -1 here means the value is unavailable int mMagnMin, mMagnMax, mRange, mDuration; + + bool operator==(const SpellEffectParams& other) const + { + return (other.mEffectID == mEffectID + && other.mSkill == mSkill + && other.mAttribute == mAttribute); + } }; typedef std::vector SpellEffectList; diff --git a/files/mygui/openmw_alchemy_window_layout.xml b/files/mygui/openmw_alchemy_window_layout.xml index 22511f0134..8eb5e12656 100644 --- a/files/mygui/openmw_alchemy_window_layout.xml +++ b/files/mygui/openmw_alchemy_window_layout.xml @@ -72,7 +72,7 @@ - + From 63b3b82657fb5a3c4d3782eaf3848ffd32c4258a Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 25 May 2012 16:23:49 +0200 Subject: [PATCH 276/325] don't allow more than 4 potion effects --- apps/openmw/mwgui/alchemywindow.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/alchemywindow.cpp b/apps/openmw/mwgui/alchemywindow.cpp index c9548e05db..bd2f05289c 100644 --- a/apps/openmw/mwgui/alchemywindow.cpp +++ b/apps/openmw/mwgui/alchemywindow.cpp @@ -281,9 +281,10 @@ namespace MWGui ++it; } - // now remove duplicates + // now remove duplicates, and don't allow more than 4 effects Widgets::SpellEffectList old = effects; effects.clear(); + int i=0; for (Widgets::SpellEffectList::iterator it = old.begin(); it != old.end(); ++it) { @@ -294,8 +295,11 @@ namespace MWGui if (*it2 == *it) found = true; } - if (!found) + if (!found && i<4) + { + ++i; effects.push_back(*it); + } } mEffects = effects; From 36885b2e4004bff3610b08ee283828b4d081b2fa Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 25 May 2012 17:04:33 +0200 Subject: [PATCH 277/325] Issue #176: removed enable/disable functions from Creature, Npc and Light --- apps/openmw/mwclass/creature.cpp | 9 --------- apps/openmw/mwclass/creature.hpp | 6 ------ apps/openmw/mwclass/light.cpp | 6 ------ apps/openmw/mwclass/light.hpp | 5 ----- apps/openmw/mwclass/npc.cpp | 29 ++++++----------------------- apps/openmw/mwclass/npc.hpp | 6 ------ 6 files changed, 6 insertions(+), 55 deletions(-) diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 653fabd089..e33fd322a7 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -81,24 +81,15 @@ namespace MWClass ESMS::LiveCellRef *ref = ptr.get(); - const std::string &model = ref->base->model; assert (ref->base != NULL); if(!model.empty()){ physics.insertActorPhysics(ptr, "meshes\\" + model); } - } - void Creature::enable (const MWWorld::Ptr& ptr) const - { MWBase::Environment::get().getMechanicsManager()->addActor (ptr); } - void Creature::disable (const MWWorld::Ptr& ptr) const - { - MWBase::Environment::get().getMechanicsManager()->removeActor (ptr); - } - std::string Creature::getName (const MWWorld::Ptr& ptr) const { ESMS::LiveCellRef *ref = diff --git a/apps/openmw/mwclass/creature.hpp b/apps/openmw/mwclass/creature.hpp index 9d94915795..237f54e82f 100644 --- a/apps/openmw/mwclass/creature.hpp +++ b/apps/openmw/mwclass/creature.hpp @@ -22,12 +22,6 @@ namespace MWClass virtual void insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const; - virtual void enable (const MWWorld::Ptr& ptr) const; - ///< Enable reference; only does the non-rendering part - - virtual void disable (const MWWorld::Ptr& ptr) const; - ///< Enable reference; only does the non-rendering part - virtual std::string getName (const MWWorld::Ptr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); /// can return an empty string. diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index d9af2e73f3..12ae517efd 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -55,12 +55,6 @@ namespace MWClass if(!model.empty()){ physics.insertObjectPhysics(ptr, "meshes\\" + model); } - } - - void Light::enable (const MWWorld::Ptr& ptr) const - { - ESMS::LiveCellRef *ref = - ptr.get(); if (!ref->base->sound.empty()) { diff --git a/apps/openmw/mwclass/light.hpp b/apps/openmw/mwclass/light.hpp index 4f21a0f8e1..cd963d8429 100644 --- a/apps/openmw/mwclass/light.hpp +++ b/apps/openmw/mwclass/light.hpp @@ -14,11 +14,6 @@ namespace MWClass virtual void insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const; - virtual void enable (const MWWorld::Ptr& ptr) const; - ///< Enable reference; only does the non-rendering part - /// \attention This is not the same as the script instruction with the same name. References - /// should only be enabled while in an active cell. - virtual std::string getName (const MWWorld::Ptr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); /// can return an empty string. diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index e7f6cc5270..4c964c7007 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -110,44 +110,27 @@ namespace MWClass void Npc::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const { - - renderingInterface.getActors().insertNPC(ptr, getInventoryStore(ptr)); - } void Npc::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const { - - ESMS::LiveCellRef *ref = ptr.get(); - assert (ref->base != NULL); - std::string headID = ref->base->head; - std::string bodyRaceID = headID.substr(0, headID.find_last_of("head_") - 4); - bool beast = bodyRaceID == "b_n_khajiit_m_" || bodyRaceID == "b_n_khajiit_f_" || bodyRaceID == "b_n_argonian_m_" || bodyRaceID == "b_n_argonian_f_"; - + std::string headID = ref->base->head; + std::string bodyRaceID = headID.substr(0, headID.find_last_of("head_") - 4); + bool beast = bodyRaceID == "b_n_khajiit_m_" || bodyRaceID == "b_n_khajiit_f_" || bodyRaceID == "b_n_argonian_m_" || bodyRaceID == "b_n_argonian_f_"; std::string smodel = "meshes\\base_anim.nif"; - if(beast) - smodel = "meshes\\base_animkna.nif"; - physics.insertActorPhysics(ptr, smodel); + if(beast) + smodel = "meshes\\base_animkna.nif"; + physics.insertActorPhysics(ptr, smodel); - - } - - void Npc::enable (const MWWorld::Ptr& ptr) const - { MWBase::Environment::get().getMechanicsManager()->addActor (ptr); } - void Npc::disable (const MWWorld::Ptr& ptr) const - { - MWBase::Environment::get().getMechanicsManager()->removeActor (ptr); - } - std::string Npc::getName (const MWWorld::Ptr& ptr) const { ESMS::LiveCellRef *ref = diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index ef154bad41..4cb733977e 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -19,12 +19,6 @@ namespace MWClass virtual void insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const; - virtual void enable (const MWWorld::Ptr& ptr) const; - ///< Enable reference; only does the non-rendering part - - virtual void disable (const MWWorld::Ptr& ptr) const; - ///< Enable reference; only does the non-rendering part - virtual std::string getName (const MWWorld::Ptr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); /// can return an empty string. From 0131c53005e01fc2e5ab6b1ed3264e5dfe8a9b74 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 25 May 2012 17:28:27 +0200 Subject: [PATCH 278/325] Issue #176: removed enable/disable functions from MWWorld::Class --- apps/openmw/mwworld/class.cpp | 10 ---------- apps/openmw/mwworld/class.hpp | 10 ---------- apps/openmw/mwworld/scene.cpp | 15 +++++++++++++-- apps/openmw/mwworld/scene.hpp | 6 ++++++ apps/openmw/mwworld/world.cpp | 29 +++++++---------------------- 5 files changed, 26 insertions(+), 44 deletions(-) diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 15bc405cef..fe39406fe1 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -32,16 +32,6 @@ namespace MWWorld } - void Class::enable (const Ptr& ptr) const - { - - } - - void Class::disable (const Ptr& ptr) const - { - - } - MWMechanics::CreatureStats& Class::getCreatureStats (const Ptr& ptr) const { throw std::runtime_error ("class does not have creature stats"); diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index a8f2aba177..46781d5160 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -68,16 +68,6 @@ namespace MWWorld virtual void insertObject(const Ptr& ptr, MWWorld::PhysicsSystem& physics) const; ///< Add reference into a cell for rendering (default implementation: don't render anything). - virtual void enable (const Ptr& ptr) const; - ///< Enable reference; only does the non-rendering part (default implementation: ignore) - /// \attention This is not the same as the script instruction with the same name. References - /// should only be enabled while in an active cell. - - virtual void disable (const Ptr& ptr) const; - ///< Enable reference; only does the non-rendering part (default implementation: ignore) - /// \attention This is not the same as the script instruction with the same name. References - /// should only be enabled while in an active cell. - virtual std::string getName (const Ptr& ptr) const = 0; ///< \return name (the one that is to be presented to the user; not the internal one); /// can return an empty string. diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 94f0c69a95..47238ee719 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -41,7 +41,6 @@ namespace { rendering.addObject(ptr); class_.insertObject(ptr, physics); - class_.enable (ptr); } catch (const std::exception& e) { @@ -459,8 +458,20 @@ namespace MWWorld mRendering.addObject(newPtr); MWWorld::Class::get(newPtr).insertObject(newPtr, *mPhysics); - MWWorld::Class::get(newPtr).enable(newPtr); } + void Scene::addObjectToScene (const Ptr& ptr) + { + mRendering.addObject (ptr); + MWWorld::Class::get (ptr).insertObject (ptr, *mPhysics); + } + + void Scene::removeObjectFromScene (const Ptr& ptr) + { + MWBase::Environment::get().getMechanicsManager()->removeActor (ptr); + MWBase::Environment::get().getSoundManager()->stopSound3D (ptr); + mPhysics->removeObject (ptr.getRefData().getHandle()); + mRendering.removeObject (ptr); + } } diff --git a/apps/openmw/mwworld/scene.hpp b/apps/openmw/mwworld/scene.hpp index 857ee50d1e..906580ff4f 100644 --- a/apps/openmw/mwworld/scene.hpp +++ b/apps/openmw/mwworld/scene.hpp @@ -105,6 +105,12 @@ namespace MWWorld void insertObject(MWWorld::Ptr object, Ptr::CellStore* cell); void update (float duration); + + void addObjectToScene (const Ptr& ptr); + ///< Add an object that already exists in the world model to the scene. + + void removeObjectFromScene (const Ptr& ptr); + ///< Remove an object from the scene, but not from the world model. }; } diff --git a/apps/openmw/mwworld/world.cpp b/apps/openmw/mwworld/world.cpp index 6d42560d21..8f3d6c838f 100644 --- a/apps/openmw/mwworld/world.cpp +++ b/apps/openmw/mwworld/world.cpp @@ -357,12 +357,8 @@ namespace MWWorld { reference.getRefData().enable(); - - //render->enable (reference.getRefData().getHandle()); - if(mWorldScene->getActiveCells().find (reference.getCell()) != mWorldScene->getActiveCells().end()) - Class::get (reference).enable (reference); - - + if(mWorldScene->getActiveCells().find (reference.getCell()) != mWorldScene->getActiveCells().end() && reference.getRefData().getCount()) + mWorldScene->addObjectToScene (reference); } } @@ -372,14 +368,8 @@ namespace MWWorld { reference.getRefData().disable(); - - //render->disable (reference.getRefData().getHandle()); - if(mWorldScene->getActiveCells().find (reference.getCell())!=mWorldScene->getActiveCells().end()){ - Class::get (reference).disable (reference); - MWBase::Environment::get().getSoundManager()->stopSound3D (reference); - } - - + if(mWorldScene->getActiveCells().find (reference.getCell())!=mWorldScene->getActiveCells().end() && reference.getRefData().getCount()) + mWorldScene->removeObjectFromScene (reference); } } @@ -553,15 +543,10 @@ namespace MWWorld { ptr.getRefData().setCount (0); - if (mWorldScene->getActiveCells().find (ptr.getCell())!=mWorldScene->getActiveCells().end()) + if (mWorldScene->getActiveCells().find (ptr.getCell())!=mWorldScene->getActiveCells().end() && + ptr.getRefData().isEnabled()) { - MWBase::Environment::get().getMechanicsManager()->removeActor (ptr); - - MWBase::Environment::get().getSoundManager()->stopSound3D (ptr); - - mPhysics->removeObject (ptr.getRefData().getHandle()); - mRendering->removeObject(ptr); - + mWorldScene->removeObjectFromScene (ptr); mLocalScripts.remove (ptr); } } From 6fe53aa3205fa438895c76b7cab5f74e68e97f3b Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 25 May 2012 17:55:00 +0200 Subject: [PATCH 279/325] Issue #277: containers in cells were not filled up on cell load when the cell was preloaded before --- apps/openmw/mwworld/cells.cpp | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwworld/cells.cpp b/apps/openmw/mwworld/cells.cpp index 8c657a5c83..b6d3e38ce7 100644 --- a/apps/openmw/mwworld/cells.cpp +++ b/apps/openmw/mwworld/cells.cpp @@ -78,8 +78,6 @@ MWWorld::Ptr::CellStore *MWWorld::Cells::getExterior (int x, int y) std::map, Ptr::CellStore>::iterator result = mExteriors.find (std::make_pair (x, y)); - bool fill = false; - if (result==mExteriors.end()) { const ESM::Cell *cell = mStore.cells.searchExt (x, y); @@ -100,15 +98,13 @@ MWWorld::Ptr::CellStore *MWWorld::Cells::getExterior (int x, int y) result = mExteriors.insert (std::make_pair ( std::make_pair (x, y), Ptr::CellStore (cell))).first; - - fill = true; } if (result->second.mState!=Ptr::CellStore::State_Loaded) + { result->second.load (mStore, mReader); - - if (fill) fillContainers (result->second); + } return &result->second; } @@ -117,22 +113,18 @@ MWWorld::Ptr::CellStore *MWWorld::Cells::getInterior (const std::string& name) { std::map::iterator result = mInteriors.find (name); - bool fill = false; - if (result==mInteriors.end()) { const ESM::Cell *cell = mStore.cells.findInt (name); result = mInteriors.insert (std::make_pair (name, Ptr::CellStore (cell))).first; - - fill = true; } if (result->second.mState!=Ptr::CellStore::State_Loaded) + { result->second.load (mStore, mReader); - - if (fill) fillContainers (result->second); + } return &result->second; } From 750259973e13824836963753ef509fa36a76cd71 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 25 May 2012 18:00:13 +0200 Subject: [PATCH 280/325] potion creating works, most of the values are bogus --- apps/openmw/mwgui/alchemywindow.cpp | 161 ++++++++++++++++++++++- apps/openmw/mwgui/alchemywindow.hpp | 4 + apps/openmw/mwgui/messagebox.cpp | 2 +- files/mygui/openmw_layers.xml | 1 + files/mygui/openmw_messagebox_layout.xml | 2 +- 5 files changed, 163 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwgui/alchemywindow.cpp b/apps/openmw/mwgui/alchemywindow.cpp index bd2f05289c..4fdd6588f7 100644 --- a/apps/openmw/mwgui/alchemywindow.cpp +++ b/apps/openmw/mwgui/alchemywindow.cpp @@ -1,8 +1,11 @@ #include "alchemywindow.hpp" +#include + #include "../mwbase/environment.hpp" #include "../mwworld/world.hpp" #include "../mwworld/player.hpp" +#include "../mwworld/manualref.hpp" #include "../mwworld/containerstore.hpp" #include "../mwsound/soundmanager.hpp" @@ -38,6 +41,7 @@ namespace MWGui getWidget(mApparatus3, "Apparatus3"); getWidget(mApparatus4, "Apparatus4"); getWidget(mEffectsBox, "CreatedEffects"); + getWidget(mNameEdit, "NameEdit"); mIngredient1->eventMouseButtonClick += MyGUI::newDelegate(this, &AlchemyWindow::onIngredientSelected); mIngredient2->eventMouseButtonClick += MyGUI::newDelegate(this, &AlchemyWindow::onIngredientSelected); @@ -72,6 +76,145 @@ namespace MWGui void AlchemyWindow::onCreateButtonClicked(MyGUI::Widget* _sender) { + // check if mortar & pestle is available (always needed) + /// \todo check albemic, calcinator, retort (sometimes needed) + if (!mApparatus1->isUserString("ToolTipType")) + { + mWindowManager.messageBox("#{sNotifyMessage45}", std::vector()); + return; + } + + // make sure 2 or more ingredients were selected + int numIngreds = 0; + if (mIngredient1->isUserString("ToolTipType")) + ++numIngreds; + if (mIngredient2->isUserString("ToolTipType")) + ++numIngreds; + if (mIngredient3->isUserString("ToolTipType")) + ++numIngreds; + if (mIngredient4->isUserString("ToolTipType")) + ++numIngreds; + if (numIngreds < 2) + { + mWindowManager.messageBox("#{sNotifyMessage6a}", std::vector()); + return; + } + + // make sure a name was entered + std::string name = mNameEdit->getCaption(); + boost::algorithm::trim(name); + if (name == "") + { + mWindowManager.messageBox("#{sNotifyMessage37}", std::vector()); + return; + } + + // if there are no created effects, the potion will always fail (but the ingredients won't be destroyed) + if (mEffects.empty()) + { + mWindowManager.messageBox("#{sNotifyMessage8}", std::vector()); + MWBase::Environment::get().getSoundManager()->playSound("potion fail", 1.f, 1.f); + return; + } + + if (rand() % 2 == 0) /// \todo + { + ESM::Potion newPotion; + newPotion.name = mNameEdit->getCaption(); + ESM::EffectList effects; + for (unsigned int i=0; i<4; ++i) + { + if (mEffects.size() >= i+1) + { + ESM::ENAMstruct effect; + effect.effectID = mEffects[i].mEffectID; + effect.range = ESM::RT_Self; + effect.skill = mEffects[i].mSkill; + effect.attribute = mEffects[i].mAttribute; + effect.magnMin = 1; /// \todo + effect.magnMax = 10; /// \todo + effect.duration = 60; /// \todo + effects.list.push_back(effect); + } + } + + // UESP Wiki / Morrowind:Alchemy + // "The weight of a potion is an average of the weight of the ingredients, rounded down." + // note by scrawl: not rounding down here, I can't imagine a created potion to + // have 0 weight when using ingredients with 0.1 weight respectively + float weight = 0; + if (mIngredient1->isUserString("ToolTipType")) + weight += mIngredient1->getUserData()->get()->base->data.weight; + if (mIngredient2->isUserString("ToolTipType")) + weight += mIngredient2->getUserData()->get()->base->data.weight; + if (mIngredient3->isUserString("ToolTipType")) + weight += mIngredient3->getUserData()->get()->base->data.weight; + if (mIngredient4->isUserString("ToolTipType")) + weight += mIngredient4->getUserData()->get()->base->data.weight; + newPotion.data.weight = weight / float(numIngreds); + + newPotion.data.value = 100; /// \todo + newPotion.effects = effects; + // pick a random mesh and icon + std::vector names; + /// \todo is the mesh/icon dependent on alchemy skill? + names.push_back("standard"); + names.push_back("bargain"); + names.push_back("cheap"); + names.push_back("fresh"); + names.push_back("exclusive"); + names.push_back("quality"); + int random = rand() % names.size(); + newPotion.model = "m\\misc_potion_" + names[random ] + "_01.nif"; + newPotion.icon = "m\\tx_potion_" + names[random ] + "_01.dds"; + std::pair result = MWBase::Environment::get().getWorld()->createRecord(newPotion); + + // create a reference and add it to player inventory + MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), result.first); + MWWorld::ContainerStore& store = MWWorld::Class::get(mContainer).getContainerStore(mContainer); + ref.getPtr().getRefData().setCount(1); + store.add(ref.getPtr()); + + mWindowManager.messageBox("#{sPotionSuccess}", std::vector()); + MWBase::Environment::get().getSoundManager()->playSound("potion success", 1.f, 1.f); + } + else + { + // potion failed + mWindowManager.messageBox("#{sNotifyMessage8}", std::vector()); + MWBase::Environment::get().getSoundManager()->playSound("potion fail", 1.f, 1.f); + } + + // reduce count of the ingredients + if (mIngredient1->isUserString("ToolTipType")) + { + MWWorld::Ptr ingred = *mIngredient1->getUserData(); + ingred.getRefData().setCount(ingred.getRefData().getCount()-1); + if (ingred.getRefData().getCount() == 0) + removeIngredient(mIngredient1); + } + if (mIngredient2->isUserString("ToolTipType")) + { + MWWorld::Ptr ingred = *mIngredient2->getUserData(); + ingred.getRefData().setCount(ingred.getRefData().getCount()-1); + if (ingred.getRefData().getCount() == 0) + removeIngredient(mIngredient2); + } + if (mIngredient3->isUserString("ToolTipType")) + { + MWWorld::Ptr ingred = *mIngredient3->getUserData(); + ingred.getRefData().setCount(ingred.getRefData().getCount()-1); + if (ingred.getRefData().getCount() == 0) + removeIngredient(mIngredient3); + } + if (mIngredient4->isUserString("ToolTipType")) + { + MWWorld::Ptr ingred = *mIngredient4->getUserData(); + ingred.getRefData().setCount(ingred.getRefData().getCount()-1); + if (ingred.getRefData().getCount() == 0) + removeIngredient(mIngredient4); + } + update(); } void AlchemyWindow::open() @@ -133,10 +276,7 @@ namespace MWGui void AlchemyWindow::onIngredientSelected(MyGUI::Widget* _sender) { - _sender->clearUserStrings(); - static_cast(_sender)->setImageTexture(""); - if (_sender->getChildCount()) - MyGUI::Gui::getInstance().destroyWidget(_sender->getChildAt(0)); + removeIngredient(_sender); drawItems(); update(); } @@ -292,7 +432,10 @@ namespace MWGui for (Widgets::SpellEffectList::iterator it2 = effects.begin(); it2 != effects.end(); ++it2) { - if (*it2 == *it) + // MW considers all "foritfy attribute" effects as the same effect. See the + // "Can't create multi-state boost potions" discussion on http://www.uesp.net/wiki/Morrowind_talk:Alchemy + // thus, we are only checking effectID here and not attribute or skill + if (it2->mEffectID == it->mEffectID) found = true; } if (!found && i<4) @@ -316,4 +459,12 @@ namespace MWGui effectsWidget->createEffectWidgets(effectItems, mEffectsBox, coord, false, 0); effectsWidget->setCoord(coord); } + + void AlchemyWindow::removeIngredient(MyGUI::Widget* ingredient) + { + ingredient->clearUserStrings(); + static_cast(ingredient)->setImageTexture(""); + if (ingredient->getChildCount()) + MyGUI::Gui::getInstance().destroyWidget(ingredient->getChildAt(0)); + } } diff --git a/apps/openmw/mwgui/alchemywindow.hpp b/apps/openmw/mwgui/alchemywindow.hpp index 17f363e92c..e75597bcd2 100644 --- a/apps/openmw/mwgui/alchemywindow.hpp +++ b/apps/openmw/mwgui/alchemywindow.hpp @@ -29,6 +29,8 @@ namespace MWGui MyGUI::Widget* mEffectsBox; + MyGUI::EditBox* mNameEdit; + Widgets::SpellEffectList mEffects; // effects of created potion void onCancelButtonClicked(MyGUI::Widget* _sender); @@ -38,6 +40,8 @@ namespace MWGui virtual void onSelectedItemImpl(MWWorld::Ptr item); virtual std::vector itemsToIgnore(); + void removeIngredient(MyGUI::Widget* ingredient); + void update(); }; } diff --git a/apps/openmw/mwgui/messagebox.cpp b/apps/openmw/mwgui/messagebox.cpp index 9df80476ec..0bb7d3c1cf 100644 --- a/apps/openmw/mwgui/messagebox.cpp +++ b/apps/openmw/mwgui/messagebox.cpp @@ -161,7 +161,7 @@ MessageBox::MessageBox(MessageBoxManager& parMessageBoxManager, const std::strin getWidget(mMessageWidget, "message"); mMessageWidget->setOverflowToTheLeft(true); - mMessageWidget->addText(cMessage); + mMessageWidget->setCaptionWithReplacing(cMessage); MyGUI::IntSize size; size.width = mFixedWidth; diff --git a/files/mygui/openmw_layers.xml b/files/mygui/openmw_layers.xml index a5044fb78e..56f800ea34 100644 --- a/files/mygui/openmw_layers.xml +++ b/files/mygui/openmw_layers.xml @@ -7,6 +7,7 @@ + diff --git a/files/mygui/openmw_messagebox_layout.xml b/files/mygui/openmw_messagebox_layout.xml index c99c00a49e..c5a7464ef6 100644 --- a/files/mygui/openmw_messagebox_layout.xml +++ b/files/mygui/openmw_messagebox_layout.xml @@ -4,7 +4,7 @@ - + From c7010623fb419f928fb369b5e93cbcfe39c0e0c8 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 25 May 2012 18:45:17 +0200 Subject: [PATCH 281/325] Issue #294: disallowed inventory prevents Talk, Open and Take actions --- apps/openmw/mwgui/window_manager.hpp | 5 +++++ apps/openmw/mwworld/actionopen.cpp | 3 +++ apps/openmw/mwworld/actiontake.cpp | 4 ++++ apps/openmw/mwworld/actiontalk.cpp | 5 ++++- 4 files changed, 16 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/window_manager.hpp b/apps/openmw/mwgui/window_manager.hpp index c698047fe2..f565c15fac 100644 --- a/apps/openmw/mwgui/window_manager.hpp +++ b/apps/openmw/mwgui/window_manager.hpp @@ -133,6 +133,11 @@ namespace MWGui updateVisible(); } + bool isAllowed(GuiWindow wnd) + { + return allowed & wnd; + } + MWGui::DialogueWindow* getDialogueWindow() {return mDialogueWindow;} MWGui::ContainerWindow* getContainerWindow() {return mContainerWindow;} MWGui::InventoryWindow* getInventoryWindow() {return mInventoryWindow;} diff --git a/apps/openmw/mwworld/actionopen.cpp b/apps/openmw/mwworld/actionopen.cpp index e2c8ec5cf1..dd36487dc9 100644 --- a/apps/openmw/mwworld/actionopen.cpp +++ b/apps/openmw/mwworld/actionopen.cpp @@ -16,6 +16,9 @@ namespace MWWorld void ActionOpen::execute () { + if (!MWBase::Environment::get().getWindowManager()->isAllowed(MWGui::GW_Inventory)) + return; + MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Container); MWBase::Environment::get().getWindowManager()->getContainerWindow()->open(mContainer); } diff --git a/apps/openmw/mwworld/actiontake.cpp b/apps/openmw/mwworld/actiontake.cpp index 384cb3ffe1..9cff42812b 100644 --- a/apps/openmw/mwworld/actiontake.cpp +++ b/apps/openmw/mwworld/actiontake.cpp @@ -2,6 +2,7 @@ #include "actiontake.hpp" #include "../mwbase/environment.hpp" +#include "../mwgui/window_manager.hpp" #include "class.hpp" #include "world.hpp" @@ -13,6 +14,9 @@ namespace MWWorld void ActionTake::execute() { + if (!MWBase::Environment::get().getWindowManager()->isAllowed(MWGui::GW_Inventory)) + return; + // insert into player's inventory MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPtr ("player", true); diff --git a/apps/openmw/mwworld/actiontalk.cpp b/apps/openmw/mwworld/actiontalk.cpp index b33b788323..b3b6316533 100644 --- a/apps/openmw/mwworld/actiontalk.cpp +++ b/apps/openmw/mwworld/actiontalk.cpp @@ -2,7 +2,7 @@ #include "actiontalk.hpp" #include "../mwbase/environment.hpp" - +#include "../mwgui/window_manager.hpp" #include "../mwdialogue/dialoguemanager.hpp" namespace MWWorld @@ -11,6 +11,9 @@ namespace MWWorld void ActionTalk::execute() { + if (!MWBase::Environment::get().getWindowManager()->isAllowed(MWGui::GW_Inventory)) + return; + MWBase::Environment::get().getDialogueManager()->startDialogue (mActor); } } From 3cba884f59488609172de97e062a175e186a6351 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 26 May 2012 05:46:46 +0200 Subject: [PATCH 282/325] Issue #294: show/hide HUD elements based on allowed windows --- apps/openmw/mwgui/window_manager.cpp | 10 ++++++++-- apps/openmw/mwgui/window_manager.hpp | 3 --- apps/openmw/mwgui/window_pinnable_base.hpp | 1 + 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwgui/window_manager.cpp b/apps/openmw/mwgui/window_manager.cpp index 96469d105f..745ef16d47 100644 --- a/apps/openmw/mwgui/window_manager.cpp +++ b/apps/openmw/mwgui/window_manager.cpp @@ -222,6 +222,11 @@ void WindowManager::updateVisible() else mToolTips->enterGuiMode(); + setMinimapVisibility((allowed & GW_Map) && !map->pinned()); + setWeaponVisibility((allowed & GW_Inventory) && !mInventoryWindow->pinned()); + setSpellVisibility((allowed & GW_Magic)); /// \todo add pin state when spells window is implemented + setHMSVisibility((allowed & GW_Stats) && !mStatsWindow->pinned()); + // If in game mode, don't show anything. if (gameMode) return; @@ -560,12 +565,13 @@ bool WindowManager::getFullHelp() const void WindowManager::setWeaponVisibility(bool visible) { - hud->weapBox->setVisible(visible); + hud->setBottomLeftVisibility(hud->health->getVisible(), visible, hud->spellBox->getVisible()); } void WindowManager::setSpellVisibility(bool visible) { - hud->spellBox->setVisible(visible); + hud->setBottomLeftVisibility(hud->health->getVisible(), hud->weapBox->getVisible(), visible); + hud->setBottomRightVisibility(visible, hud->minimapBox->getVisible()); } void WindowManager::setMouseVisible(bool visible) diff --git a/apps/openmw/mwgui/window_manager.hpp b/apps/openmw/mwgui/window_manager.hpp index f565c15fac..e2fbd3e1ee 100644 --- a/apps/openmw/mwgui/window_manager.hpp +++ b/apps/openmw/mwgui/window_manager.hpp @@ -263,9 +263,6 @@ namespace MWGui the start of the game, when windows are enabled one by one through script commands. You can manipulate this through using allow() and disableAll(). - - The setting should also affect visibility of certain HUD - elements, but this is not done yet. */ GuiWindow allowed; diff --git a/apps/openmw/mwgui/window_pinnable_base.hpp b/apps/openmw/mwgui/window_pinnable_base.hpp index 8ef38c3867..86bc3b85c8 100644 --- a/apps/openmw/mwgui/window_pinnable_base.hpp +++ b/apps/openmw/mwgui/window_pinnable_base.hpp @@ -12,6 +12,7 @@ namespace MWGui public: WindowPinnableBase(const std::string& parLayout, WindowManager& parWindowManager); void setVisible(bool b); + bool pinned() { return mPinned; } private: void onWindowButtonPressed(MyGUI::Window* sender, const std::string& eventName); From 313a8e55b7cea30dd4061fc507ee8606eff534b1 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 26 May 2012 21:09:21 +0200 Subject: [PATCH 283/325] - Issue #296: Clicking on HUD elements shows/hides the respective window - Slightly redesigned the map window and minimap, the player arrow now isn't cut off at cell borders anymore --- apps/openmw/mwgui/hud.cpp | 64 ++++++------- apps/openmw/mwgui/hud.hpp | 6 +- apps/openmw/mwgui/map_window.cpp | 109 +++++++++++++++-------- apps/openmw/mwgui/map_window.hpp | 12 ++- apps/openmw/mwgui/window_manager.cpp | 6 +- apps/openmw/mwgui/window_manager.hpp | 6 ++ files/mygui/openmw_hud_layout.xml | 76 +++++----------- files/mygui/openmw_map_window_layout.xml | 42 +-------- 8 files changed, 154 insertions(+), 167 deletions(-) diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index 892bd6c7aa..a3036cec4f 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -48,25 +48,38 @@ HUD::HUD(int width, int height, int fpsLevel, DragAndDrop* dragAndDrop) getWidget(health, "Health"); getWidget(magicka, "Magicka"); getWidget(stamina, "Stamina"); + hmsBaseLeft = health->getLeft(); + MyGUI::Widget *healthFrame, *magickaFrame, *fatigueFrame; + getWidget(healthFrame, "HealthFrame"); + getWidget(magickaFrame, "MagickaFrame"); + getWidget(fatigueFrame, "FatigueFrame"); + healthFrame->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onHMSClicked); + magickaFrame->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onHMSClicked); + fatigueFrame->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onHMSClicked); + // Item and spell images and status bars getWidget(weapBox, "WeapBox"); getWidget(weapImage, "WeapImage"); getWidget(weapStatus, "WeapStatus"); weapBoxBaseLeft = weapBox->getLeft(); + weapBox->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onWeaponClicked); getWidget(spellBox, "SpellBox"); getWidget(spellImage, "SpellImage"); getWidget(spellStatus, "SpellStatus"); spellBoxBaseLeft = spellBox->getLeft(); + spellBox->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onMagicClicked); getWidget(effectBox, "EffectBox"); getWidget(effect1, "Effect1"); effectBoxBaseRight = effectBox->getRight(); + effectBox->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onMagicClicked); getWidget(minimapBox, "MiniMapBox"); minimapBoxBaseRight = minimapBox->getRight(); + minimapBox->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onMapClicked); getWidget(minimap, "MiniMap"); getWidget(compass, "Compass"); @@ -85,7 +98,7 @@ HUD::HUD(int width, int height, int fpsLevel, DragAndDrop* dragAndDrop) setSpellStatus(65, 100); setEffect("icons\\s\\tx_s_chameleon.dds"); - LocalMapBase::init(minimap, this); + LocalMapBase::init(minimap, compass, this); mMainWidget->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onWorldClicked); mMainWidget->eventMouseMove += MyGUI::newDelegate(this, &HUD::onWorldMouseOver); @@ -192,35 +205,6 @@ void HUD::setValue(const std::string& id, const MWMechanics::DynamicStat& v } } -void HUD::setPlayerDir(const float x, const float y) -{ - if (!minimapBox->getVisible() || (x == mLastPositionX && y == mLastPositionY)) return; - - MyGUI::ISubWidget* main = compass->getSubWidgetMain(); - MyGUI::RotatingSkin* rotatingSubskin = main->castType(); - rotatingSubskin->setCenter(MyGUI::IntPoint(16,16)); - float angle = std::atan2(x,y); - rotatingSubskin->setAngle(angle); - mLastPositionX = x; - mLastPositionY = y; -} - -void HUD::setPlayerPos(const float x, const float y) -{ - if (!minimapBox->getVisible() || (x == mLastDirectionX && y == mLastDirectionY)) return; - - MyGUI::IntSize size = minimap->getCanvasSize(); - MyGUI::IntPoint middle = MyGUI::IntPoint((1/3.f + x/3.f)*size.width,(1/3.f + y/3.f)*size.height); - MyGUI::IntCoord viewsize = minimap->getCoord(); - MyGUI::IntPoint pos(0.5*viewsize.width - middle.left, 0.5*viewsize.height - middle.top); - - minimap->setViewOffset(pos); - compass->setPosition(MyGUI::IntPoint(x*512-16, y*512-16)); - - mLastDirectionX = x; - mLastDirectionY = y; -} - void HUD::setBottomLeftVisibility(bool hmsVisible, bool weapVisible, bool spellVisible) { int weapDx = 0, spellDx = 0; @@ -320,3 +304,23 @@ void HUD::onWorldMouseLostFocus(MyGUI::Widget* _sender, MyGUI::Widget* _new) { MyGUI::PointerManager::getInstance().setPointer("arrow"); } + +void HUD::onHMSClicked(MyGUI::Widget* _sender) +{ + MWBase::Environment::get().getWindowManager()->toggleVisible(GW_Stats); +} + +void HUD::onMapClicked(MyGUI::Widget* _sender) +{ + MWBase::Environment::get().getWindowManager()->toggleVisible(GW_Map); +} + +void HUD::onWeaponClicked(MyGUI::Widget* _sender) +{ + MWBase::Environment::get().getWindowManager()->toggleVisible(GW_Inventory); +} + +void HUD::onMagicClicked(MyGUI::Widget* _sender) +{ + MWBase::Environment::get().getWindowManager()->toggleVisible(GW_Magic); +} diff --git a/apps/openmw/mwgui/hud.hpp b/apps/openmw/mwgui/hud.hpp index 81f64ee504..9248933515 100644 --- a/apps/openmw/mwgui/hud.hpp +++ b/apps/openmw/mwgui/hud.hpp @@ -21,8 +21,6 @@ namespace MWGui void setFPS(float fps); void setTriangleCount(size_t count); void setBatchCount(size_t count); - void setPlayerDir(const float x, const float y); - void setPlayerPos(const float x, const float y); void setBottomLeftVisibility(bool hmsVisible, bool weapVisible, bool spellVisible); void setBottomRightVisibility(bool effectBoxVisible, bool minimapVisible); void setFpsLevel(const int level); @@ -53,5 +51,9 @@ namespace MWGui void onWorldClicked(MyGUI::Widget* _sender); void onWorldMouseOver(MyGUI::Widget* _sender, int x, int y); void onWorldMouseLostFocus(MyGUI::Widget* _sender, MyGUI::Widget* _new); + void onHMSClicked(MyGUI::Widget* _sender); + void onWeaponClicked(MyGUI::Widget* _sender); + void onMagicClicked(MyGUI::Widget* _sender); + void onMapClicked(MyGUI::Widget* _sender); }; } diff --git a/apps/openmw/mwgui/map_window.cpp b/apps/openmw/mwgui/map_window.cpp index a44571d0a6..a51b66e2bf 100644 --- a/apps/openmw/mwgui/map_window.cpp +++ b/apps/openmw/mwgui/map_window.cpp @@ -11,6 +11,7 @@ LocalMapBase::LocalMapBase() , mInterior(false) , mFogOfWar(true) , mLocalMap(NULL) + , mMapDragAndDrop(false) , mPrefix() , mChanged(true) , mLayout(NULL) @@ -18,13 +19,41 @@ LocalMapBase::LocalMapBase() , mLastPositionY(0.0f) , mLastDirectionX(0.0f) , mLastDirectionY(0.0f) + , mCompass(NULL) { } -void LocalMapBase::init(MyGUI::ScrollView* widget, OEngine::GUI::Layout* layout) +void LocalMapBase::init(MyGUI::ScrollView* widget, MyGUI::ImageBox* compass, OEngine::GUI::Layout* layout, bool mapDragAndDrop) { mLocalMap = widget; mLayout = layout; + mMapDragAndDrop = mapDragAndDrop; + mCompass = compass; + + // create 3x3 map widgets, 512x512 each, holding a 1024x1024 texture each + const int widgetSize = 512; + for (int mx=0; mx<3; ++mx) + { + for (int my=0; my<3; ++my) + { + MyGUI::ImageBox* map = mLocalMap->createWidget("ImageBox", + MyGUI::IntCoord(mx*widgetSize, my*widgetSize, widgetSize, widgetSize), + MyGUI::Align::Top | MyGUI::Align::Left, "Map_" + boost::lexical_cast(mx) + "_" + boost::lexical_cast(my)); + + MyGUI::ImageBox* fog = map->createWidget("ImageBox", + MyGUI::IntCoord(0, 0, widgetSize, widgetSize), + MyGUI::Align::Top | MyGUI::Align::Left, "Map_" + boost::lexical_cast(mx) + "_" + boost::lexical_cast(my) + "_fog"); + + if (!mMapDragAndDrop) + { + map->setNeedMouseFocus(false); + fog->setNeedMouseFocus(false); + } + + mMapWidgets.push_back(map); + mFogWidgets.push_back(fog); + } + } } void LocalMapBase::setCellPrefix(const std::string& prefix) @@ -47,10 +76,10 @@ void LocalMapBase::applyFogOfWar() { std::string name = "Map_" + boost::lexical_cast(mx) + "_" + boost::lexical_cast(my); + std::string image = mPrefix+"_"+ boost::lexical_cast(mCurX + (mx-1)) + "_" + boost::lexical_cast(mCurY + (mInterior ? (my-1) : -1*(my-1))); - MyGUI::ImageBox* fog; - mLayout->getWidget(fog, name+"_fog"); + MyGUI::ImageBox* fog = mFogWidgets[my + 3*mx]; fog->setImageTexture(mFogOfWar ? ((MyGUI::RenderManager::getInstance().getTexture(image+"_fog") != 0) ? image+"_fog" : "black.png" ) @@ -66,14 +95,13 @@ void LocalMapBase::setActiveCell(const int x, const int y, bool interior) { for (int my=0; my<3; ++my) { - std::string name = "Map_" + boost::lexical_cast(mx) + "_" - + boost::lexical_cast(my); - std::string image = mPrefix+"_"+ boost::lexical_cast(x + (mx-1)) + "_" + boost::lexical_cast(y + (interior ? (my-1) : -1*(my-1))); - MyGUI::ImageBox* box; - mLayout->getWidget(box, name); + std::string name = "Map_" + boost::lexical_cast(mx) + "_" + + boost::lexical_cast(my); + + MyGUI::ImageBox* box = mMapWidgets[my + 3*mx]; if (MyGUI::RenderManager::getInstance().getTexture(image) != 0) box->setImageTexture(image); @@ -86,6 +114,42 @@ void LocalMapBase::setActiveCell(const int x, const int y, bool interior) mCurY = y; mChanged = false; applyFogOfWar(); + + // set the compass texture again, because MyGUI determines sorting of ImageBox widgets + // based on the last setImageTexture call + std::string tex = "textures\\compass.dds"; + mCompass->setImageTexture(""); + mCompass->setImageTexture(tex); +} + + +void LocalMapBase::setPlayerPos(const float x, const float y) +{ + if (x == mLastPositionX && y == mLastPositionY) + return; + MyGUI::IntSize size = mLocalMap->getCanvasSize(); + MyGUI::IntPoint middle = MyGUI::IntPoint((1/3.f + x/3.f)*size.width,(1/3.f + y/3.f)*size.height); + MyGUI::IntCoord viewsize = mLocalMap->getCoord(); + MyGUI::IntPoint pos(0.5*viewsize.width - middle.left, 0.5*viewsize.height - middle.top); + mLocalMap->setViewOffset(pos); + + mCompass->setPosition(MyGUI::IntPoint(512+x*512-16, 512+y*512-16)); + mLastPositionX = x; + mLastPositionY = y; +} + +void LocalMapBase::setPlayerDir(const float x, const float y) +{ + if (x == mLastDirectionX && y == mLastDirectionY) + return; + MyGUI::ISubWidget* main = mCompass->getSubWidgetMain(); + MyGUI::RotatingSkin* rotatingSubskin = main->castType(); + rotatingSubskin->setCenter(MyGUI::IntPoint(16,16)); + float angle = std::atan2(x,y); + rotatingSubskin->setAngle(angle); + + mLastDirectionX = x; + mLastDirectionY = y; } // ------------------------------------------------------------------------------------------ @@ -111,7 +175,7 @@ MapWindow::MapWindow(WindowManager& parWindowManager) : eventbox->eventMouseDrag += MyGUI::newDelegate(this, &MapWindow::onMouseDrag); eventbox->eventMouseButtonPressed += MyGUI::newDelegate(this, &MapWindow::onDragStart); - LocalMapBase::init(mLocalMap, this); + LocalMapBase::init(mLocalMap, mPlayerArrow, this); } void MapWindow::setCellName(const std::string& cellName) @@ -119,33 +183,6 @@ void MapWindow::setCellName(const std::string& cellName) setTitle(cellName); } -void MapWindow::setPlayerPos(const float x, const float y) -{ - if (mGlobal || !mVisible || (x == mLastPositionX && y == mLastPositionY)) return; - MyGUI::IntSize size = mLocalMap->getCanvasSize(); - MyGUI::IntPoint middle = MyGUI::IntPoint((1/3.f + x/3.f)*size.width,(1/3.f + y/3.f)*size.height); - MyGUI::IntCoord viewsize = mLocalMap->getCoord(); - MyGUI::IntPoint pos(0.5*viewsize.width - middle.left, 0.5*viewsize.height - middle.top); - mLocalMap->setViewOffset(pos); - - mPlayerArrow->setPosition(MyGUI::IntPoint(x*512-16, y*512-16)); - mLastPositionX = x; - mLastPositionY = y; -} - -void MapWindow::setPlayerDir(const float x, const float y) -{ - if (!mVisible || (x == mLastDirectionX && y == mLastDirectionY)) return; - MyGUI::ISubWidget* main = mPlayerArrow->getSubWidgetMain(); - MyGUI::RotatingSkin* rotatingSubskin = main->castType(); - rotatingSubskin->setCenter(MyGUI::IntPoint(16,16)); - float angle = std::atan2(x,y); - rotatingSubskin->setAngle(angle); - - mLastDirectionX = x; - mLastDirectionY = y; -} - void MapWindow::onDragStart(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id) { if (_id!=MyGUI::MouseButton::Left) return; diff --git a/apps/openmw/mwgui/map_window.hpp b/apps/openmw/mwgui/map_window.hpp index e7318f4e45..8d3392b827 100644 --- a/apps/openmw/mwgui/map_window.hpp +++ b/apps/openmw/mwgui/map_window.hpp @@ -9,10 +9,12 @@ namespace MWGui { public: LocalMapBase(); - void init(MyGUI::ScrollView* widget, OEngine::GUI::Layout* layout); + void init(MyGUI::ScrollView* widget, MyGUI::ImageBox* compass, OEngine::GUI::Layout* layout, bool mapDragAndDrop=false); void setCellPrefix(const std::string& prefix); void setActiveCell(const int x, const int y, bool interior=false); + void setPlayerDir(const float x, const float y); + void setPlayerPos(const float x, const float y); void toggleFogOfWar(); @@ -20,14 +22,20 @@ namespace MWGui int mCurX, mCurY; bool mInterior; MyGUI::ScrollView* mLocalMap; + MyGUI::ImageBox* mCompass; std::string mPrefix; bool mChanged; bool mFogOfWar; + std::vector mMapWidgets; + std::vector mFogWidgets; + void applyFogOfWar(); OEngine::GUI::Layout* mLayout; + bool mMapDragAndDrop; + float mLastPositionX; float mLastPositionY; float mLastDirectionX; @@ -40,8 +48,6 @@ namespace MWGui MapWindow(WindowManager& parWindowManager); virtual ~MapWindow(){} - void setPlayerPos(const float x, const float y); - void setPlayerDir(const float x, const float y); void setCellName(const std::string& cellName); private: diff --git a/apps/openmw/mwgui/window_manager.cpp b/apps/openmw/mwgui/window_manager.cpp index 745ef16d47..088e9c61ee 100644 --- a/apps/openmw/mwgui/window_manager.cpp +++ b/apps/openmw/mwgui/window_manager.cpp @@ -271,9 +271,9 @@ void WindowManager::updateVisible() int eff = shown & allowed; // Show the windows we want - map -> setVisible( (eff & GW_Map) != 0 ); - mStatsWindow -> setVisible( (eff & GW_Stats) != 0 ); - mInventoryWindow->setVisible(true); + map -> setVisible( (eff & GW_Map) ); + mStatsWindow -> setVisible( (eff & GW_Stats) ); + mInventoryWindow->setVisible( (eff & GW_Inventory)); break; } case GM_Container: diff --git a/apps/openmw/mwgui/window_manager.hpp b/apps/openmw/mwgui/window_manager.hpp index e2fbd3e1ee..df32547fcd 100644 --- a/apps/openmw/mwgui/window_manager.hpp +++ b/apps/openmw/mwgui/window_manager.hpp @@ -119,6 +119,12 @@ namespace MWGui bool isGuiMode() const { return !mGuiModes.empty(); } + void toggleVisible(GuiWindow wnd) + { + shown = (shown & wnd) ? (GuiWindow) (shown & ~wnd) : (GuiWindow) (shown | wnd); + updateVisible(); + } + // Disallow all inventory mode windows void disallowAll() { diff --git a/files/mygui/openmw_hud_layout.xml b/files/mygui/openmw_hud_layout.xml index 0aabc3e3ee..26c31793cf 100644 --- a/files/mygui/openmw_hud_layout.xml +++ b/files/mygui/openmw_hud_layout.xml @@ -29,79 +29,49 @@ - + - + + + + + + + - - + - + + + + + - - - + + + - - - - - - + + + - - - - - - - - - - - - - - - - - - + + - - - - - - - - - - - - - - - - diff --git a/files/mygui/openmw_map_window_layout.xml b/files/mygui/openmw_map_window_layout.xml index e0ae5bd881..63fd03b140 100644 --- a/files/mygui/openmw_map_window_layout.xml +++ b/files/mygui/openmw_map_window_layout.xml @@ -11,46 +11,8 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + From 63213b36bfdf162fe9fd3edaec8a2a9716c7c672 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 26 May 2012 23:06:15 +0200 Subject: [PATCH 284/325] Show a label on the HUD with the cell name when it changes (visible for a few seconds) - like Morrowind --- apps/openmw/mwgui/hud.cpp | 23 +++++++++++++++++++++++ apps/openmw/mwgui/hud.hpp | 8 ++++++++ apps/openmw/mwgui/window_manager.cpp | 4 ++++ files/mygui/openmw_hud_layout.xml | 8 ++++++++ 4 files changed, 43 insertions(+) diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index a3036cec4f..d3d7696b4a 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -41,6 +41,8 @@ HUD::HUD(int width, int height, int fpsLevel, DragAndDrop* dragAndDrop) , effectBoxBaseRight(0) , minimapBoxBaseRight(0) , mDragAndDrop(dragAndDrop) + , mCellNameTimer(0.0f) + , mCellNameBox(NULL) { setCoord(0,0, width, height); @@ -83,6 +85,8 @@ HUD::HUD(int width, int height, int fpsLevel, DragAndDrop* dragAndDrop) getWidget(minimap, "MiniMap"); getWidget(compass, "Compass"); + getWidget(mCellNameBox, "CellName"); + getWidget(crosshair, "Crosshair"); setFpsLevel(fpsLevel); @@ -324,3 +328,22 @@ void HUD::onMagicClicked(MyGUI::Widget* _sender) { MWBase::Environment::get().getWindowManager()->toggleVisible(GW_Magic); } + +void HUD::setCellName(const std::string& cellName) +{ + if (mCellName != cellName) + { + mCellNameTimer = 5.0f; + mCellName = cellName; + + mCellNameBox->setCaption(mCellName); + mCellNameBox->setVisible(true); + } +} + +void HUD::onFrame(float dt) +{ + mCellNameTimer -= dt; + if (mCellNameTimer < 0) + mCellNameBox->setVisible(false); +} diff --git a/apps/openmw/mwgui/hud.hpp b/apps/openmw/mwgui/hud.hpp index 9248933515..f7131a39c6 100644 --- a/apps/openmw/mwgui/hud.hpp +++ b/apps/openmw/mwgui/hud.hpp @@ -25,6 +25,10 @@ namespace MWGui void setBottomRightVisibility(bool effectBoxVisible, bool minimapVisible); void setFpsLevel(const int level); + void onFrame(float dt); + + void setCellName(const std::string& cellName); + MyGUI::ProgressPtr health, magicka, stamina; MyGUI::Widget *weapBox, *spellBox; MyGUI::ImageBox *weapImage, *spellImage; @@ -34,6 +38,7 @@ namespace MWGui MyGUI::ScrollView* minimap; MyGUI::ImageBox* compass; MyGUI::ImageBox* crosshair; + MyGUI::TextBox* mCellNameBox; MyGUI::WidgetPtr fpsbox; MyGUI::TextBox* fpscounter; @@ -48,6 +53,9 @@ namespace MWGui DragAndDrop* mDragAndDrop; + std::string mCellName; + float mCellNameTimer; + void onWorldClicked(MyGUI::Widget* _sender); void onWorldMouseOver(MyGUI::Widget* _sender, int x, int y); void onWorldMouseLostFocus(MyGUI::Widget* _sender, MyGUI::Widget* _new); diff --git a/apps/openmw/mwgui/window_manager.cpp b/apps/openmw/mwgui/window_manager.cpp index 088e9c61ee..acd0b089f5 100644 --- a/apps/openmw/mwgui/window_manager.cpp +++ b/apps/openmw/mwgui/window_manager.cpp @@ -470,6 +470,8 @@ void WindowManager::onFrame (float frameDuration) mInventoryWindow->onFrame(); mStatsWindow->onFrame(); + + hud->onFrame(frameDuration); } const ESMS::ESMStore& WindowManager::getStore() const @@ -494,6 +496,7 @@ void WindowManager::changeCell(MWWorld::Ptr::CellStore* cell) } map->setCellName( name ); + hud->setCellName( name ); map->setCellPrefix("Cell"); hud->setCellPrefix("Cell"); @@ -503,6 +506,7 @@ void WindowManager::changeCell(MWWorld::Ptr::CellStore* cell) else { map->setCellName( cell->cell->name ); + hud->setCellName( cell->cell->name ); map->setCellPrefix( cell->cell->name ); hud->setCellPrefix( cell->cell->name ); } diff --git a/files/mygui/openmw_hud_layout.xml b/files/mygui/openmw_hud_layout.xml index 26c31793cf..d0026bf251 100644 --- a/files/mygui/openmw_hud_layout.xml +++ b/files/mygui/openmw_hud_layout.xml @@ -59,6 +59,14 @@ name="Effect1"/> + + + + + + + + From a7e6a142f972ad102443f1eb0d4bff9ace4c59b6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 27 May 2012 00:39:33 +0200 Subject: [PATCH 285/325] blend fog of war into adjacent cells --- apps/openmw/mwrender/localmap.cpp | 71 +++++++++++++++++++++---------- 1 file changed, 49 insertions(+), 22 deletions(-) diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index ea89024433..55cb45fdcc 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -307,19 +307,19 @@ void LocalMap::updatePlayer (const Ogre::Vector3& position, const Ogre::Quaterni // convert from world coordinates to texture UV coordinates float u,v; - std::string texName; + std::string texBaseName; if (!mInterior) { u = std::abs((pos.x - (sSize*x))/sSize); v = 1-std::abs((pos.y + (sSize*y))/sSize); - texName = "Cell_"+coordStr(x,y); + texBaseName = "Cell_"; } else { u = (pos.x - min.x - sSize*x)/sSize; v = (pos.y - min.y - sSize*y)/sSize; - texName = mInteriorName + "_" + coordStr(x,y); + texBaseName = mInteriorName + "_"; } MWBase::Environment::get().getWindowManager()->setPlayerPos(u, v); @@ -327,30 +327,57 @@ void LocalMap::updatePlayer (const Ogre::Vector3& position, const Ogre::Quaterni // explore radius (squared) const float sqrExploreRadius = 0.01 * sFogOfWarResolution*sFogOfWarResolution; + const float exploreRadius = 0.1 * sFogOfWarResolution; // explore radius from 0 to sFogOfWarResolution + const float exploreRadiusUV = exploreRadius / sFogOfWarResolution; // explore radius from 0 to 1 (UV space) - // get the appropriate fog of war texture - TexturePtr tex = TextureManager::getSingleton().getByName(texName+"_fog"); - if (!tex.isNull()) + int intExtMult = mInterior ? 1 : -1; // interior and exterior have reversed Y coordinates (interior: top to bottom) + + // change the affected fog of war textures (in a 3x3 grid around the player) + for (int mx = -1; mx<2; ++mx) { - // get its buffer - if (mBuffers.find(texName) == mBuffers.end()) return; - int i=0; - for (int texV = 0; texV> 24); - alpha = std::min( alpha, (uint8) (std::max(0.f, std::min(1.f, (sqrDist/sqrExploreRadius)))*255) ); - mBuffers[texName][i] = (uint32) (alpha << 24); - ++i; + // is this texture affected at all? + bool affected = false; + if (mx == 0 && my == 0) // the player is always in the center of the 3x3 grid + affected = true; + else + { + bool affectsX = (mx > 0)? (u + exploreRadiusUV > 1) : (u - exploreRadiusUV < 0); + bool affectsY = (my > 0)? (v + exploreRadiusUV > 1) : (v - exploreRadiusUV < 0); + affected = (affectsX && (my == 0)) || (affectsY && mx == 0) || (affectsX && affectsY); + } + + if (!affected) + continue; + + std::string texName = texBaseName + coordStr(x+mx,y+my*intExtMult); + + TexturePtr tex = TextureManager::getSingleton().getByName(texName+"_fog"); + if (!tex.isNull()) + { + // get its buffer + if (mBuffers.find(texName) == mBuffers.end()) return; + int i=0; + for (int texV = 0; texV> 24); + alpha = std::min( alpha, (uint8) (std::max(0.f, std::min(1.f, (sqrDist/sqrExploreRadius)))*255) ); + mBuffers[texName][i] = (uint32) (alpha << 24); + + ++i; + } + } + + // copy to the texture + memcpy(tex->getBuffer()->lock(HardwareBuffer::HBL_DISCARD), &mBuffers[texName][0], sFogOfWarResolution*sFogOfWarResolution*4); + tex->getBuffer()->unlock(); } } - - // copy to the texture - memcpy(tex->getBuffer()->lock(HardwareBuffer::HBL_DISCARD), &mBuffers[texName][0], sFogOfWarResolution*sFogOfWarResolution*4); - tex->getBuffer()->unlock(); } } From f1d3978897b0e89f6f8f70128494c847d434d09c Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 27 May 2012 01:14:33 +0200 Subject: [PATCH 286/325] Issue #290: Auto-Close MW-reference related GUI windows --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwgui/alchemywindow.cpp | 4 +-- apps/openmw/mwgui/alchemywindow.hpp | 2 ++ apps/openmw/mwgui/container.cpp | 27 ++++++++++-------- apps/openmw/mwgui/container.hpp | 16 +++++------ apps/openmw/mwgui/dialogue.cpp | 9 ++++-- apps/openmw/mwgui/dialogue.hpp | 7 +++-- apps/openmw/mwgui/inventorywindow.cpp | 8 +++--- apps/openmw/mwgui/inventorywindow.hpp | 2 ++ apps/openmw/mwgui/referenceinterface.cpp | 28 +++++++++++++++++++ apps/openmw/mwgui/referenceinterface.hpp | 29 ++++++++++++++++++++ apps/openmw/mwgui/tradewindow.cpp | 35 ++++++++++++++---------- apps/openmw/mwgui/tradewindow.hpp | 2 ++ apps/openmw/mwgui/window_manager.cpp | 18 ++++++++++++ apps/openmw/mwgui/window_manager.hpp | 1 + 15 files changed, 145 insertions(+), 45 deletions(-) create mode 100644 apps/openmw/mwgui/referenceinterface.cpp create mode 100644 apps/openmw/mwgui/referenceinterface.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index ac38827146..edbeab0a1a 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -28,7 +28,7 @@ add_openmw_dir (mwgui dialogue_history window_base stats_window messagebox journalwindow charactercreation map_window window_pinnable_base cursorreplace tooltips scrollwindow bookwindow list formatting inventorywindow container hud countdialog tradewindow settingswindow - confirmationdialog alchemywindow + confirmationdialog alchemywindow referenceinterface ) add_openmw_dir (mwdialogue diff --git a/apps/openmw/mwgui/alchemywindow.cpp b/apps/openmw/mwgui/alchemywindow.cpp index 4fdd6588f7..50d2095241 100644 --- a/apps/openmw/mwgui/alchemywindow.cpp +++ b/apps/openmw/mwgui/alchemywindow.cpp @@ -171,7 +171,7 @@ namespace MWGui // create a reference and add it to player inventory MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), result.first); - MWWorld::ContainerStore& store = MWWorld::Class::get(mContainer).getContainerStore(mContainer); + MWWorld::ContainerStore& store = MWWorld::Class::get(mPtr).getContainerStore(mPtr); ref.getPtr().getRefData().setCount(1); store.add(ref.getPtr()); @@ -223,7 +223,7 @@ namespace MWGui setFilter(ContainerBase::Filter_Ingredients); // pick the best available apparatus - MWWorld::ContainerStore& store = MWWorld::Class::get(mContainer).getContainerStore(mContainer); + MWWorld::ContainerStore& store = MWWorld::Class::get(mPtr).getContainerStore(mPtr); MWWorld::Ptr bestAlbemic; MWWorld::Ptr bestMortarPestle; diff --git a/apps/openmw/mwgui/alchemywindow.hpp b/apps/openmw/mwgui/alchemywindow.hpp index e75597bcd2..c01a18e413 100644 --- a/apps/openmw/mwgui/alchemywindow.hpp +++ b/apps/openmw/mwgui/alchemywindow.hpp @@ -42,6 +42,8 @@ namespace MWGui void removeIngredient(MyGUI::Widget* ingredient); + virtual void onReferenceUnavailable() { ; } + void update(); }; } diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 6aabeb2c6b..1cfbc1b2b0 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -264,16 +264,16 @@ void ContainerBase::onContainerClicked(MyGUI::Widget* _sender) if(mDragAndDrop->mIsOnDragAndDrop) //drop item here { MWWorld::Ptr object = *mDragAndDrop->mDraggedWidget->getUserData(); - MWWorld::ContainerStore& containerStore = MWWorld::Class::get(mContainer).getContainerStore(mContainer); + MWWorld::ContainerStore& containerStore = MWWorld::Class::get(mPtr).getContainerStore(mPtr); if (mDragAndDrop->mDraggedFrom != this) { assert(object.getContainerStore() && "Item is not in a container!"); // check the container's Organic flag (if this is a container). container with Organic flag doesn't allow putting items inside - if (mContainer.getTypeName() == typeid(ESM::Container).name()) + if (mPtr.getTypeName() == typeid(ESM::Container).name()) { - ESMS::LiveCellRef* ref = mContainer.get(); + ESMS::LiveCellRef* ref = mPtr.get(); if (ref->base->flags & ESM::Container::Organic) { // user notification @@ -288,13 +288,13 @@ void ContainerBase::onContainerClicked(MyGUI::Widget* _sender) // check that we don't exceed the allowed weight (only for containers, not for inventory) if (!isInventory()) { - float capacity = MWWorld::Class::get(mContainer).getCapacity(mContainer); + float capacity = MWWorld::Class::get(mPtr).getCapacity(mPtr); // try adding the item, and if weight is exceeded, just remove it again. object.getRefData().setCount(mDragAndDrop->mDraggedCount); MWWorld::ContainerStoreIterator it = containerStore.add(object); - float curWeight = MWWorld::Class::get(mContainer).getEncumbrance(mContainer); + float curWeight = MWWorld::Class::get(mPtr).getEncumbrance(mPtr); if (curWeight > capacity) { it->getRefData().setCount(0); @@ -346,7 +346,7 @@ void ContainerBase::setFilter(ContainerBase::Filter filter) void ContainerBase::openContainer(MWWorld::Ptr container) { - mContainer = container; + mPtr = container; drawItems(); } @@ -356,7 +356,7 @@ void ContainerBase::drawItems() { MyGUI::Gui::getInstance().destroyWidget(mContainerWidget->getChildAt(0)); } - MWWorld::ContainerStore& containerStore = MWWorld::Class::get(mContainer).getContainerStore(mContainer); + MWWorld::ContainerStore& containerStore = MWWorld::Class::get(mPtr).getContainerStore(mPtr); int x = 0; int y = 0; @@ -557,7 +557,7 @@ void ContainerBase::addBarteredItem(MWWorld::Ptr item, int count) void ContainerBase::addItem(MWWorld::Ptr item, int count) { - MWWorld::ContainerStore& containerStore = MWWorld::Class::get(mContainer).getContainerStore(mContainer); + MWWorld::ContainerStore& containerStore = MWWorld::Class::get(mPtr).getContainerStore(mPtr); int origCount = item.getRefData().getCount(); @@ -569,7 +569,7 @@ void ContainerBase::addItem(MWWorld::Ptr item, int count) void ContainerBase::transferBoughtItems() { - MWWorld::ContainerStore& containerStore = MWWorld::Class::get(mContainer).getContainerStore(mContainer); + MWWorld::ContainerStore& containerStore = MWWorld::Class::get(mPtr).getContainerStore(mPtr); for (MWWorld::ContainerStoreIterator it(mBoughtItems.begin()); it != mBoughtItems.end(); ++it) { @@ -587,7 +587,7 @@ void ContainerBase::returnBoughtItems(MWWorld::ContainerStore& store) MWWorld::ContainerStore& ContainerBase::getContainerStore() { - MWWorld::ContainerStore& store = MWWorld::Class::get(mContainer).getContainerStore(mContainer); + MWWorld::ContainerStore& store = MWWorld::Class::get(mPtr).getContainerStore(mPtr); return store; } @@ -651,7 +651,7 @@ void ContainerWindow::onTakeAllButtonClicked(MyGUI::Widget* _sender) if(mDragAndDrop == NULL || !mDragAndDrop->mIsOnDragAndDrop) { // transfer everything into the player's inventory - MWWorld::ContainerStore& containerStore = MWWorld::Class::get(mContainer).getContainerStore(mContainer); + MWWorld::ContainerStore& containerStore = MWWorld::Class::get(mPtr).getContainerStore(mPtr); MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); MWWorld::ContainerStore& playerStore = MWWorld::Class::get(player).getContainerStore(player); @@ -676,3 +676,8 @@ void ContainerWindow::onTakeAllButtonClicked(MyGUI::Widget* _sender) MWBase::Environment::get().getWindowManager()->popGuiMode(); } } + +void ContainerWindow::onReferenceUnavailable() +{ + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Container); +} diff --git a/apps/openmw/mwgui/container.hpp b/apps/openmw/mwgui/container.hpp index 26e78149ae..5cd8167c24 100644 --- a/apps/openmw/mwgui/container.hpp +++ b/apps/openmw/mwgui/container.hpp @@ -2,15 +2,14 @@ #define MGUI_CONTAINER_H #include -#include "../mwclass/container.hpp" -#include -#include -#include -#include + #include "window_base.hpp" +#include "referenceinterface.hpp" + +#include "../mwclass/container.hpp" #include "../mwworld/ptr.hpp" #include "../mwworld/containerstore.hpp" -#include + namespace MWWorld { @@ -43,7 +42,7 @@ namespace MWGui int mDraggedCount; }; - class ContainerBase + class ContainerBase : public ReferenceInterface { public: ContainerBase(DragAndDrop* dragAndDrop); @@ -89,7 +88,6 @@ namespace MWGui MyGUI::Widget* mSelectedItem; DragAndDrop* mDragAndDrop; - MWWorld::Ptr mContainer; Filter mFilter; @@ -140,6 +138,8 @@ namespace MWGui void onWindowResize(MyGUI::Window* window); void onCloseButtonClicked(MyGUI::Widget* _sender); void onTakeAllButtonClicked(MyGUI::Widget* _sender); + + virtual void onReferenceUnavailable(); }; } #endif // CONTAINER_H diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 8a68ff6663..ce687424c0 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -125,7 +125,7 @@ void DialogueWindow::onSelectTopic(std::string topic) { /// \todo check if the player is allowed to trade with this actor (e.g. faction rank high enough)? mWindowManager.pushGuiMode(GM_Barter); - mWindowManager.getTradeWindow()->startTrade(mActor); + mWindowManager.getTradeWindow()->startTrade(mPtr); } else @@ -135,7 +135,7 @@ void DialogueWindow::onSelectTopic(std::string topic) void DialogueWindow::startDialogue(MWWorld::Ptr actor, std::string npcName) { mEnabled = true; - mActor = actor; + mPtr = actor; topicsList->setEnabled(true); setTitle(npcName); @@ -260,3 +260,8 @@ void DialogueWindow::goodbye() topicsList->setEnabled(false); mEnabled = false; } + +void DialogueWindow::onReferenceUnavailable() +{ + mWindowManager.removeGuiMode(GM_Dialogue); +} diff --git a/apps/openmw/mwgui/dialogue.hpp b/apps/openmw/mwgui/dialogue.hpp index d3106ad381..8e9aba0030 100644 --- a/apps/openmw/mwgui/dialogue.hpp +++ b/apps/openmw/mwgui/dialogue.hpp @@ -2,6 +2,7 @@ #define MWGUI_DIALOGE_H #include "window_base.hpp" +#include "referenceinterface.hpp" #include #include "../mwworld/ptr.hpp" @@ -25,7 +26,7 @@ namespace MWGui { class DialogueHistory; - class DialogueWindow: public WindowBase + class DialogueWindow: public WindowBase, public ReferenceInterface { public: DialogueWindow(WindowManager& parWindowManager); @@ -58,6 +59,8 @@ namespace MWGui void onMouseWheel(MyGUI::Widget* _sender, int _rel); void onWindowResize(MyGUI::Window* _sender); + virtual void onReferenceUnavailable(); + private: void updateOptions(); /** @@ -70,8 +73,6 @@ namespace MWGui bool mEnabled; - MWWorld::Ptr mActor; // actor being talked to - DialogueHistory* history; Widgets::MWList* topicsList; MyGUI::ProgressPtr pDispositionBar; diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 04a30b69bf..2b224ab2cc 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -155,7 +155,7 @@ namespace MWGui if (mDragAndDrop->mDraggedFrom != this) { // add item to the player's inventory - MWWorld::ContainerStore& invStore = MWWorld::Class::get(mContainer).getContainerStore(mContainer); + MWWorld::ContainerStore& invStore = MWWorld::Class::get(mPtr).getContainerStore(mPtr); MWWorld::ContainerStoreIterator it = invStore.begin(); int origCount = ptr.getRefData().getCount(); @@ -192,7 +192,7 @@ namespace MWGui std::vector InventoryWindow::getEquippedItems() { - MWWorld::InventoryStore& invStore = MWWorld::Class::get(mContainer).getInventoryStore(mContainer); + MWWorld::InventoryStore& invStore = MWWorld::Class::get(mPtr).getInventoryStore(mPtr); std::vector items; @@ -210,7 +210,7 @@ namespace MWGui void InventoryWindow::_unequipItem(MWWorld::Ptr item) { - MWWorld::InventoryStore& invStore = MWWorld::Class::get(mContainer).getInventoryStore(mContainer); + MWWorld::InventoryStore& invStore = MWWorld::Class::get(mPtr).getInventoryStore(mPtr); for (int slot=0; slot < MWWorld::InventoryStore::Slots; ++slot) { @@ -244,7 +244,7 @@ namespace MWGui int InventoryWindow::getPlayerGold() { - MWWorld::InventoryStore& invStore = MWWorld::Class::get(mContainer).getInventoryStore(mContainer); + MWWorld::InventoryStore& invStore = MWWorld::Class::get(mPtr).getInventoryStore(mPtr); for (MWWorld::ContainerStoreIterator it = invStore.begin(); it != invStore.end(); ++it) diff --git a/apps/openmw/mwgui/inventorywindow.hpp b/apps/openmw/mwgui/inventorywindow.hpp index 86f7ee3c7b..ecff75f101 100644 --- a/apps/openmw/mwgui/inventorywindow.hpp +++ b/apps/openmw/mwgui/inventorywindow.hpp @@ -48,6 +48,8 @@ namespace MWGui virtual bool isInventory() { return true; } virtual std::vector getEquippedItems(); virtual void _unequipItem(MWWorld::Ptr item); + + virtual void onReferenceUnavailable() { ; } }; } diff --git a/apps/openmw/mwgui/referenceinterface.cpp b/apps/openmw/mwgui/referenceinterface.cpp new file mode 100644 index 0000000000..c6e710952f --- /dev/null +++ b/apps/openmw/mwgui/referenceinterface.cpp @@ -0,0 +1,28 @@ +#include "referenceinterface.hpp" + +#include "../mwworld/player.hpp" +#include "../mwworld/world.hpp" +#include "../mwbase/environment.hpp" + +namespace MWGui +{ + ReferenceInterface::ReferenceInterface() + : mCurrentPlayerCell(NULL) + { + } + + void ReferenceInterface::checkReferenceAvailable() + { + if (mPtr.isEmpty()) + return; + + MWWorld::Ptr::CellStore* playerCell = MWBase::Environment::get().getWorld()->getPlayer().getPlayer().getCell(); + + // check if player has changed cell, or count of the reference has become 0 + if ((playerCell != mCurrentPlayerCell && mCurrentPlayerCell != NULL) + || mPtr.getRefData().getCount() == 0) + onReferenceUnavailable(); + + mCurrentPlayerCell = playerCell; + } +} diff --git a/apps/openmw/mwgui/referenceinterface.hpp b/apps/openmw/mwgui/referenceinterface.hpp new file mode 100644 index 0000000000..40844b2388 --- /dev/null +++ b/apps/openmw/mwgui/referenceinterface.hpp @@ -0,0 +1,29 @@ +#ifndef MWGUI_REFERENCEINTERFACE_H +#define MWGUI_REFERENCEINTERFACE_H + +#include "../mwworld/ptr.hpp" + +namespace MWGui +{ + /// \brief this class is intended for GUI interfaces that access an MW-Reference + /// for example dialogue window accesses an NPC, or Container window accesses a Container + /// these classes have to be automatically closed if the reference becomes unavailable + /// make sure that checkReferenceAvailable() is called every frame and that onReferenceUnavailable() has been overridden + class ReferenceInterface + { + public: + ReferenceInterface(); + + void checkReferenceAvailable(); ///< closes the window, if the MW-reference has become unavailable + + protected: + virtual void onReferenceUnavailable() = 0; ///< called when reference has become unavailable + + MWWorld::Ptr mPtr; + + private: + MWWorld::Ptr::CellStore* mCurrentPlayerCell; + }; +} + +#endif diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index 311ea6c957..0a12a82a08 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -157,9 +157,9 @@ namespace MWGui // check if the merchant can afford this int merchantgold; - if (mContainer.getTypeName() == typeid(ESM::NPC).name()) + if (mPtr.getTypeName() == typeid(ESM::NPC).name()) { - ESMS::LiveCellRef* ref = mContainer.get(); + ESMS::LiveCellRef* ref = mPtr.get(); if (ref->base->npdt52.gold == -10) merchantgold = ref->base->npdt12.gold; else @@ -167,7 +167,7 @@ namespace MWGui } else // ESM::Creature { - ESMS::LiveCellRef* ref = mContainer.get(); + ESMS::LiveCellRef* ref = mPtr.get(); merchantgold = ref->base->data.gold; } if (mCurrentBalance > 0 && merchantgold < mCurrentBalance) @@ -218,7 +218,7 @@ namespace MWGui // i give you back your stuff! returnBoughtItems(mWindowManager.getInventoryWindow()->getContainerStore()); // now gimme back my stuff! - mWindowManager.getInventoryWindow()->returnBoughtItems(MWWorld::Class::get(mContainer).getContainerStore(mContainer)); + mWindowManager.getInventoryWindow()->returnBoughtItems(MWWorld::Class::get(mPtr).getContainerStore(mPtr)); mWindowManager.popGuiMode(); } @@ -240,9 +240,9 @@ namespace MWGui } int merchantgold; - if (mContainer.getTypeName() == typeid(ESM::NPC).name()) + if (mPtr.getTypeName() == typeid(ESM::NPC).name()) { - ESMS::LiveCellRef* ref = mContainer.get(); + ESMS::LiveCellRef* ref = mPtr.get(); if (ref->base->npdt52.gold == -10) merchantgold = ref->base->npdt12.gold; else @@ -250,7 +250,7 @@ namespace MWGui } else // ESM::Creature { - ESMS::LiveCellRef* ref = mContainer.get(); + ESMS::LiveCellRef* ref = mPtr.get(); merchantgold = ref->base->data.gold; } @@ -262,13 +262,13 @@ namespace MWGui { std::vector items; - if (mContainer.getTypeName() == typeid(ESM::Creature).name()) + if (mPtr.getTypeName() == typeid(ESM::Creature).name()) { // creatures don't have equipment slots. return items; } - MWWorld::InventoryStore& invStore = MWWorld::Class::get(mContainer).getInventoryStore(mContainer); + MWWorld::InventoryStore& invStore = MWWorld::Class::get(mPtr).getInventoryStore(mPtr); for (int slot=0; slot < MWWorld::InventoryStore::Slots; ++slot) { @@ -285,15 +285,15 @@ namespace MWGui bool TradeWindow::npcAcceptsItem(MWWorld::Ptr item) { int services = 0; - if (mContainer.getTypeName() == typeid(ESM::NPC).name()) + if (mPtr.getTypeName() == typeid(ESM::NPC).name()) { - ESMS::LiveCellRef* ref = mContainer.get(); + ESMS::LiveCellRef* ref = mPtr.get(); if (ref->base->hasAI) services = ref->base->AI.services; } - else if (mContainer.getTypeName() == typeid(ESM::Creature).name()) + else if (mPtr.getTypeName() == typeid(ESM::Creature).name()) { - ESMS::LiveCellRef* ref = mContainer.get(); + ESMS::LiveCellRef* ref = mPtr.get(); if (ref->base->hasAI) services = ref->base->AI.services; } @@ -327,7 +327,7 @@ namespace MWGui std::vector TradeWindow::itemsToIgnore() { std::vector items; - MWWorld::ContainerStore& invStore = MWWorld::Class::get(mContainer).getContainerStore(mContainer); + MWWorld::ContainerStore& invStore = MWWorld::Class::get(mPtr).getContainerStore(mPtr); for (MWWorld::ContainerStoreIterator it = invStore.begin(); it != invStore.end(); ++it) @@ -356,4 +356,11 @@ namespace MWGui updateLabels(); } + + void TradeWindow::onReferenceUnavailable() + { + // remove both Trade and Dialogue (since you always trade with the NPC/creature that you have previously talked to) + mWindowManager.removeGuiMode(GM_Barter); + mWindowManager.removeGuiMode(GM_Dialogue); + } } diff --git a/apps/openmw/mwgui/tradewindow.hpp b/apps/openmw/mwgui/tradewindow.hpp index 8da96d37e7..b391fd8fa2 100644 --- a/apps/openmw/mwgui/tradewindow.hpp +++ b/apps/openmw/mwgui/tradewindow.hpp @@ -69,6 +69,8 @@ namespace MWGui virtual std::vector itemsToIgnore(); void updateLabels(); + + virtual void onReferenceUnavailable(); }; } diff --git a/apps/openmw/mwgui/window_manager.cpp b/apps/openmw/mwgui/window_manager.cpp index acd0b089f5..a6d236136c 100644 --- a/apps/openmw/mwgui/window_manager.cpp +++ b/apps/openmw/mwgui/window_manager.cpp @@ -472,6 +472,10 @@ void WindowManager::onFrame (float frameDuration) mStatsWindow->onFrame(); hud->onFrame(frameDuration); + + mDialogueWindow->checkReferenceAvailable(); + mTradeWindow->checkReferenceAvailable(); + mContainerWindow->checkReferenceAvailable(); } const ESMS::ESMStore& WindowManager::getStore() const @@ -626,3 +630,17 @@ void WindowManager::popGuiMode() updateVisible(); } + +void WindowManager::removeGuiMode(GuiMode mode) +{ + std::vector::iterator it = mGuiModes.begin(); + while (it != mGuiModes.end()) + { + if (*it == mode) + it = mGuiModes.erase(it); + else + ++it; + } + + updateVisible(); +} diff --git a/apps/openmw/mwgui/window_manager.hpp b/apps/openmw/mwgui/window_manager.hpp index df32547fcd..7082cc0bc7 100644 --- a/apps/openmw/mwgui/window_manager.hpp +++ b/apps/openmw/mwgui/window_manager.hpp @@ -109,6 +109,7 @@ namespace MWGui void pushGuiMode(GuiMode mode); void popGuiMode(); + void removeGuiMode(GuiMode mode); ///< can be anywhere in the stack GuiMode getMode() const { From 10cfe0f5bc37d08356dccb3a4d08589facda131e Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 27 May 2012 06:39:10 +0200 Subject: [PATCH 287/325] Issue #295: Class creation dialogs tooltips; plus tons of other improvements --- apps/openmw/mwgui/class.cpp | 129 +++++++++++-- apps/openmw/mwgui/class.hpp | 8 + apps/openmw/mwgui/race.cpp | 15 +- apps/openmw/mwgui/review.cpp | 52 ++++- apps/openmw/mwgui/review.hpp | 2 + apps/openmw/mwgui/stats_window.cpp | 79 +------- apps/openmw/mwgui/tooltips.cpp | 181 ++++++++++++++++++ apps/openmw/mwgui/tooltips.hpp | 9 + apps/openmw/mwgui/widgets.cpp | 4 +- components/esm/attr.cpp | 11 ++ components/esm/attr.hpp | 1 + files/mygui/openmw_chargen_class_layout.xml | 16 +- .../openmw_chargen_create_class_layout.xml | 14 +- ...w_chargen_generate_class_result_layout.xml | 4 +- files/mygui/openmw_chargen_race_layout.xml | 8 +- files/mygui/openmw_chargen_review_layout.xml | 75 +++++++- ...w_chargen_select_specialization_layout.xml | 6 +- files/mygui/openmw_infobox_layout.xml | 2 +- files/mygui/openmw_resources.xml | 29 +++ files/mygui/openmw_text.skin.xml | 41 ++-- files/mygui/openmw_tooltips.xml | 25 +++ 21 files changed, 565 insertions(+), 146 deletions(-) diff --git a/apps/openmw/mwgui/class.cpp b/apps/openmw/mwgui/class.cpp index 3e41fa6b10..d3d261ab02 100644 --- a/apps/openmw/mwgui/class.cpp +++ b/apps/openmw/mwgui/class.cpp @@ -1,6 +1,4 @@ #include "class.hpp" -#include "window_manager.hpp" -#include "components/esm_store/store.hpp" #include #include @@ -8,6 +6,11 @@ #include #include +#include + +#include "window_manager.hpp" +#include "tooltips.hpp" + #undef min #undef max @@ -79,17 +82,13 @@ PickClassDialog::PickClassDialog(WindowManager& parWindowManager) // Centre dialog center(); - setText("SpecializationT", mWindowManager.getGameSettingString("sChooseClassMenu1", "Specialization")); getWidget(specializationName, "SpecializationName"); - setText("FavoriteAttributesT", mWindowManager.getGameSettingString("sChooseClassMenu2", "Favorite Attributes:")); getWidget(favoriteAttribute[0], "FavoriteAttribute0"); getWidget(favoriteAttribute[1], "FavoriteAttribute1"); favoriteAttribute[0]->setWindowManager(&mWindowManager); favoriteAttribute[1]->setWindowManager(&mWindowManager); - setText("MajorSkillT", mWindowManager.getGameSettingString("sChooseClassMenu3", "Major Skills:")); - setText("MinorSkillT", mWindowManager.getGameSettingString("sChooseClassMenu4", "Minor Skills:")); for(int i = 0; i < 5; i++) { char theIndex = '0'+i; @@ -231,15 +230,21 @@ void PickClassDialog::updateStats() "sSpecializationMagic", "sSpecializationStealth" }; - specializationName->setCaption(mWindowManager.getGameSettingString(specIds[specialization], specIds[specialization])); + std::string specName = mWindowManager.getGameSettingString(specIds[specialization], specIds[specialization]); + specializationName->setCaption(specName); + ToolTips::createSpecializationToolTip(specializationName, specName, specialization); favoriteAttribute[0]->setAttributeId(klass->data.attribute[0]); favoriteAttribute[1]->setAttributeId(klass->data.attribute[1]); + ToolTips::createAttributeToolTip(favoriteAttribute[0], favoriteAttribute[0]->getAttributeId()); + ToolTips::createAttributeToolTip(favoriteAttribute[1], favoriteAttribute[1]->getAttributeId()); for (int i = 0; i < 5; ++i) { majorSkill[i]->setSkillNumber(klass->data.skills[i][0]); minorSkill[i]->setSkillNumber(klass->data.skills[i][1]); + ToolTips::createSkillToolTip(majorSkill[i], klass->data.skills[i][0]); + ToolTips::createSkillToolTip(minorSkill[i], klass->data.skills[i][1]); } classImage->setImageTexture(std::string("textures\\levelup\\") + currentClassId + ".dds"); @@ -387,7 +392,6 @@ CreateClassDialog::CreateClassDialog(WindowManager& parWindowManager) setText("SpecializationT", mWindowManager.getGameSettingString("sChooseClassMenu1", "Specialization")); getWidget(specializationName, "SpecializationName"); - specializationName->setCaption(mWindowManager.getGameSettingString(ESM::Class::gmstSpecializationIds[ESM::Class::Combat], "")); specializationName->eventMouseButtonClick += MyGUI::newDelegate(this, &CreateClassDialog::onSpecializationClicked); setText("FavoriteAttributesT", mWindowManager.getGameSettingString("sChooseClassMenu2", "Favorite Attributes:")); @@ -451,6 +455,9 @@ CreateClassDialog::CreateClassDialog(WindowManager& parWindowManager) minorSkill[2]->setSkillId(ESM::Skill::Spear); minorSkill[3]->setSkillId(ESM::Skill::Athletics); minorSkill[4]->setSkillId(ESM::Skill::Enchant); + + setSpecialization(0); + update(); } CreateClassDialog::~CreateClassDialog() @@ -461,6 +468,18 @@ CreateClassDialog::~CreateClassDialog() delete descDialog; } +void CreateClassDialog::update() +{ + for (int i = 0; i < 5; ++i) + { + ToolTips::createSkillToolTip(majorSkill[i], majorSkill[i]->getSkillId()); + ToolTips::createSkillToolTip(minorSkill[i], minorSkill[i]->getSkillId()); + } + + ToolTips::createAttributeToolTip(favoriteAttribute0, favoriteAttribute0->getAttributeId()); + ToolTips::createAttributeToolTip(favoriteAttribute1, favoriteAttribute1->getAttributeId()); +} + std::string CreateClassDialog::getName() const { return editName->getOnlyText(); @@ -539,14 +558,25 @@ void CreateClassDialog::open() void CreateClassDialog::onDialogCancel() { if (specDialog) - specDialog->setVisible(false); + { + mWindowManager.removeDialog(specDialog); + specDialog = 0; + } if (attribDialog) - attribDialog->setVisible(false); + { + mWindowManager.removeDialog(attribDialog); + attribDialog = 0; + } if (skillDialog) - skillDialog->setVisible(false); + { + mWindowManager.removeDialog(skillDialog); + skillDialog = 0; + } if (descDialog) - descDialog->setVisible(false); - // TODO: Delete dialogs here + { + mWindowManager.removeDialog(descDialog); + descDialog = 0; + } } void CreateClassDialog::onSpecializationClicked(MyGUI::WidgetPtr _sender) @@ -562,8 +592,23 @@ void CreateClassDialog::onSpecializationClicked(MyGUI::WidgetPtr _sender) void CreateClassDialog::onSpecializationSelected() { specializationId = specDialog->getSpecializationId(); - specializationName->setCaption(mWindowManager.getGameSettingString(ESM::Class::gmstSpecializationIds[specializationId], "")); - specDialog->setVisible(false); + setSpecialization(specializationId); + + mWindowManager.removeDialog(specDialog); + specDialog = 0; +} + +void CreateClassDialog::setSpecialization(int id) +{ + specializationId = (ESM::Class::Specialization) id; + static const char *specIds[3] = { + "sSpecializationCombat", + "sSpecializationMagic", + "sSpecializationStealth" + }; + std::string specName = mWindowManager.getGameSettingString(specIds[specializationId], specIds[specializationId]); + specializationName->setCaption(specName); + ToolTips::createSpecializationToolTip(specializationName, specName, specializationId); } void CreateClassDialog::onAttributeClicked(Widgets::MWAttributePtr _sender) @@ -592,7 +637,10 @@ void CreateClassDialog::onAttributeSelected() favoriteAttribute0->setAttributeId(favoriteAttribute1->getAttributeId()); } attribute->setAttributeId(id); - attribDialog->setVisible(false); + mWindowManager.removeDialog(attribDialog); + attribDialog = 0; + + update(); } void CreateClassDialog::onSkillClicked(Widgets::MWSkillPtr _sender) @@ -625,7 +673,9 @@ void CreateClassDialog::onSkillSelected() } skill->setSkillId(skillDialog->getSkillId()); - skillDialog->setVisible(false); + mWindowManager.removeDialog(skillDialog); + skillDialog = 0; + update(); } void CreateClassDialog::onDescriptionClicked(MyGUI::Widget* _sender) @@ -640,6 +690,7 @@ void CreateClassDialog::onDescriptionEntered(WindowBase* parWindow) { description = descDialog->getTextInput(); mWindowManager.removeDialog(descDialog); + descDialog = 0; } void CreateClassDialog::onOkClicked(MyGUI::Widget* _sender) @@ -665,20 +716,35 @@ SelectSpecializationDialog::SelectSpecializationDialog(WindowManager& parWindowM getWidget(specialization0, "Specialization0"); getWidget(specialization1, "Specialization1"); getWidget(specialization2, "Specialization2"); - specialization0->setCaption(mWindowManager.getGameSettingString(ESM::Class::gmstSpecializationIds[ESM::Class::Combat], "")); + std::string combat = mWindowManager.getGameSettingString(ESM::Class::gmstSpecializationIds[ESM::Class::Combat], ""); + std::string magic = mWindowManager.getGameSettingString(ESM::Class::gmstSpecializationIds[ESM::Class::Magic], ""); + std::string stealth = mWindowManager.getGameSettingString(ESM::Class::gmstSpecializationIds[ESM::Class::Stealth], ""); + + specialization0->setCaption(combat); specialization0->eventMouseButtonClick += MyGUI::newDelegate(this, &SelectSpecializationDialog::onSpecializationClicked); - specialization1->setCaption(mWindowManager.getGameSettingString(ESM::Class::gmstSpecializationIds[ESM::Class::Magic], "")); + specialization1->setCaption(magic); specialization1->eventMouseButtonClick += MyGUI::newDelegate(this, &SelectSpecializationDialog::onSpecializationClicked); - specialization2->setCaption(mWindowManager.getGameSettingString(ESM::Class::gmstSpecializationIds[ESM::Class::Stealth], "")); + specialization2->setCaption(stealth); specialization2->eventMouseButtonClick += MyGUI::newDelegate(this, &SelectSpecializationDialog::onSpecializationClicked); specializationId = ESM::Class::Combat; + ToolTips::createSpecializationToolTip(specialization0, combat, ESM::Class::Combat); + ToolTips::createSpecializationToolTip(specialization1, magic, ESM::Class::Magic); + ToolTips::createSpecializationToolTip(specialization2, stealth, ESM::Class::Stealth); + MyGUI::ButtonPtr cancelButton; getWidget(cancelButton, "CancelButton"); cancelButton->setCaption(mWindowManager.getGameSettingString("sCancel", "")); cancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SelectSpecializationDialog::onCancelClicked); int buttonWidth = cancelButton->getTextSize().width + 24; cancelButton->setCoord(216 - buttonWidth, 90, buttonWidth, 21); + + MyGUI::InputManager::getInstance().addWidgetModal(mMainWidget); +} + +SelectSpecializationDialog::~SelectSpecializationDialog() +{ + MyGUI::InputManager::getInstance().removeWidgetModal(mMainWidget); } // widget controls @@ -721,6 +787,7 @@ SelectAttributeDialog::SelectAttributeDialog(WindowManager& parWindowManager) attribute->setWindowManager(&parWindowManager); attribute->setAttributeId(ESM::Attribute::attributeIds[i]); attribute->eventClicked += MyGUI::newDelegate(this, &SelectAttributeDialog::onAttributeClicked); + ToolTips::createAttributeToolTip(attribute, attribute->getAttributeId()); } MyGUI::ButtonPtr cancelButton; @@ -729,6 +796,13 @@ SelectAttributeDialog::SelectAttributeDialog(WindowManager& parWindowManager) cancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SelectAttributeDialog::onCancelClicked); int buttonWidth = cancelButton->getTextSize().width + 24; cancelButton->setCoord(186 - buttonWidth, 180, buttonWidth, 21); + + MyGUI::InputManager::getInstance().addWidgetModal(mMainWidget); +} + +SelectAttributeDialog::~SelectAttributeDialog() +{ + MyGUI::InputManager::getInstance().removeWidgetModal(mMainWidget); } // widget controls @@ -810,6 +884,7 @@ SelectSkillDialog::SelectSkillDialog(WindowManager& parWindowManager) skills[spec][i].widget->setWindowManager(&mWindowManager); skills[spec][i].widget->setSkillId(skills[spec][i].skillId); skills[spec][i].widget->eventClicked += MyGUI::newDelegate(this, &SelectSkillDialog::onSkillClicked); + ToolTips::createSkillToolTip(skills[spec][i].widget, skills[spec][i].widget->getSkillId()); } } @@ -819,6 +894,13 @@ SelectSkillDialog::SelectSkillDialog(WindowManager& parWindowManager) cancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SelectSkillDialog::onCancelClicked); int buttonWidth = cancelButton->getTextSize().width + 24; cancelButton->setCoord(447 - buttonWidth, 218, buttonWidth, 21); + + MyGUI::InputManager::getInstance().addWidgetModal(mMainWidget); +} + +SelectSkillDialog::~SelectSkillDialog() +{ + MyGUI::InputManager::getInstance().removeWidgetModal(mMainWidget); } // widget controls @@ -853,6 +935,13 @@ DescriptionDialog::DescriptionDialog(WindowManager& parWindowManager) // Make sure the edit box has focus MyGUI::InputManager::getInstance().setKeyFocusWidget(textEdit); + + MyGUI::InputManager::getInstance().addWidgetModal(mMainWidget); +} + +DescriptionDialog::~DescriptionDialog() +{ + MyGUI::InputManager::getInstance().removeWidgetModal(mMainWidget); } // widget controls diff --git a/apps/openmw/mwgui/class.hpp b/apps/openmw/mwgui/class.hpp index 6f0138aa4d..868052800d 100644 --- a/apps/openmw/mwgui/class.hpp +++ b/apps/openmw/mwgui/class.hpp @@ -139,6 +139,7 @@ namespace MWGui { public: SelectSpecializationDialog(WindowManager& parWindowManager); + ~SelectSpecializationDialog(); ESM::Class::Specialization getSpecializationId() const { return specializationId; } @@ -169,6 +170,7 @@ namespace MWGui { public: SelectAttributeDialog(WindowManager& parWindowManager); + ~SelectAttributeDialog(); ESM::Attribute::AttributeID getAttributeId() const { return attributeId; } Widgets::MWAttributePtr getAffectedWidget() const { return affectedWidget; } @@ -201,6 +203,7 @@ namespace MWGui { public: SelectSkillDialog(WindowManager& parWindowManager); + ~SelectSkillDialog(); ESM::Skill::SkillEnum getSkillId() const { return skillId; } Widgets::MWSkillPtr getAffectedWidget() const { return affectedWidget; } @@ -236,6 +239,7 @@ namespace MWGui { public: DescriptionDialog(WindowManager& parWindowManager); + ~DescriptionDialog(); std::string getTextInput() const { return textEdit ? textEdit->getOnlyText() : ""; } void setTextInput(const std::string &text) { if (textEdit) textEdit->setOnlyText(text); } @@ -285,6 +289,10 @@ namespace MWGui void onDescriptionEntered(WindowBase* parWindow); void onDialogCancel(); + void setSpecialization(int id); + + void update(); + private: MyGUI::EditPtr editName; MyGUI::TextBox* specializationName; diff --git a/apps/openmw/mwgui/race.cpp b/apps/openmw/mwgui/race.cpp index f18bdb41ff..dea365ac23 100644 --- a/apps/openmw/mwgui/race.cpp +++ b/apps/openmw/mwgui/race.cpp @@ -1,7 +1,4 @@ #include "race.hpp" -#include "window_manager.hpp" -#include "widgets.hpp" -#include "components/esm_store/store.hpp" #include #include @@ -10,6 +7,12 @@ #include #include +#include + +#include "window_manager.hpp" +#include "widgets.hpp" +#include "tooltips.hpp" + using namespace MWGui; using namespace Widgets; @@ -51,7 +54,7 @@ RaceDialog::RaceDialog(WindowManager& parWindowManager) prevButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onSelectPreviousFace); nextButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onSelectNextFace); - setText("HairChoiceT", mWindowManager.getGameSettingString("sRaceMenu3", "Change Hair")); + setText("HairChoiceT", mWindowManager.getGameSettingString("sRaceMenu4", "Change Hair")); getWidget(prevButton, "PrevHairButton"); getWidget(nextButton, "NextHairButton"); prevButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onSelectPreviousHair); @@ -255,6 +258,8 @@ void RaceDialog::updateSkills() skillWidget->setWindowManager(&mWindowManager); skillWidget->setSkillNumber(skillId); skillWidget->setSkillValue(MWSkill::SkillValue(race->data.bonus[i].bonus)); + ToolTips::createSkillToolTip(skillWidget, skillId); + skillItems.push_back(skillWidget); @@ -288,6 +293,8 @@ void RaceDialog::updateSpellPowers() spellPowerWidget = spellPowerList->createWidget("MW_StatName", coord, MyGUI::Align::Default, std::string("SpellPower") + boost::lexical_cast(i)); spellPowerWidget->setWindowManager(&mWindowManager); spellPowerWidget->setSpellId(spellpower); + spellPowerWidget->setUserString("ToolTipType", "Spell"); + spellPowerWidget->setUserString("Spell", spellpower); spellPowerItems.push_back(spellPowerWidget); diff --git a/apps/openmw/mwgui/review.cpp b/apps/openmw/mwgui/review.cpp index 5059efb342..be537e854e 100644 --- a/apps/openmw/mwgui/review.cpp +++ b/apps/openmw/mwgui/review.cpp @@ -1,12 +1,15 @@ #include "review.hpp" -#include "window_manager.hpp" -#include "widgets.hpp" -#include "components/esm_store/store.hpp" + +#include #include #include -#include +#include + +#include "window_manager.hpp" +#include "widgets.hpp" +#include "tooltips.hpp" #undef min #undef max @@ -74,7 +77,7 @@ ReviewDialog::ReviewDialog(WindowManager& parWindowManager) getWidget(skillAreaWidget, "Skills"); getWidget(skillClientWidget, "SkillClient"); getWidget(skillScrollerWidget, "SkillScroller"); - + skillClientWidget->eventMouseWheel += MyGUI::newDelegate(this, &ReviewDialog::onMouseWheel); skillScrollerWidget->eventScrollChangePosition += MyGUI::newDelegate(this, &ReviewDialog::onScrollChangePosition); updateScroller(); @@ -137,13 +140,17 @@ void ReviewDialog::setRace(const std::string &raceId_) raceId = raceId_; const ESM::Race *race = mWindowManager.getStore().races.search(raceId); if (race) + { + ToolTips::createRaceToolTip(raceWidget, race); raceWidget->setCaption(race->name); + } } void ReviewDialog::setClass(const ESM::Class& class_) { klass = class_; classWidget->setCaption(klass.name); + ToolTips::createClassToolTip(classWidget, klass); } void ReviewDialog::setBirthSign(const std::string& signId) @@ -151,22 +158,31 @@ void ReviewDialog::setBirthSign(const std::string& signId) birthSignId = signId; const ESM::BirthSign *sign = mWindowManager.getStore().birthSigns.search(birthSignId); if (sign) + { birthSignWidget->setCaption(sign->name); + ToolTips::createBirthsignToolTip(birthSignWidget, birthSignId); + } } void ReviewDialog::setHealth(const MWMechanics::DynamicStat& value) { health->setValue(value.getCurrent(), value.getModified()); + std::string valStr = boost::lexical_cast(value.getCurrent()) + "/" + boost::lexical_cast(value.getModified()); + health->setUserString("Caption_HealthDescription", "#{sHealthDesc}\n" + valStr); } void ReviewDialog::setMagicka(const MWMechanics::DynamicStat& value) { magicka->setValue(value.getCurrent(), value.getModified()); + std::string valStr = boost::lexical_cast(value.getCurrent()) + "/" + boost::lexical_cast(value.getModified()); + magicka->setUserString("Caption_HealthDescription", "#{sIntDesc}\n" + valStr); } void ReviewDialog::setFatigue(const MWMechanics::DynamicStat& value) { fatigue->setValue(value.getCurrent(), value.getModified()); + std::string valStr = boost::lexical_cast(value.getCurrent()) + "/" + boost::lexical_cast(value.getModified()); + fatigue->setUserString("Caption_HealthDescription", "#{sFatDesc}\n" + valStr); } void ReviewDialog::setAttribute(ESM::Attribute::AttributeID attributeId, const MWMechanics::Stat& value) @@ -219,6 +235,8 @@ void ReviewDialog::configureSkills(const std::vector& major, const std::vec void ReviewDialog::addSeparator(MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) { MyGUI::ImageBox* separator = skillClientWidget->createWidget("MW_HLine", MyGUI::IntCoord(10, coord1.top, coord1.width + coord2.width - 4, 18), MyGUI::Align::Default); + separator->eventMouseWheel += MyGUI::newDelegate(this, &ReviewDialog::onMouseWheel); + skillWidgets.push_back(separator); coord1.top += separator->getHeight(); @@ -228,6 +246,7 @@ void ReviewDialog::addSeparator(MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2 void ReviewDialog::addGroup(const std::string &label, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) { MyGUI::TextBox* groupWidget = skillClientWidget->createWidget("SandBrightText", MyGUI::IntCoord(0, coord1.top, coord1.width + coord2.width, coord1.height), MyGUI::Align::Default); + groupWidget->eventMouseWheel += MyGUI::newDelegate(this, &ReviewDialog::onMouseWheel); groupWidget->setCaption(label); skillWidgets.push_back(groupWidget); @@ -242,10 +261,12 @@ MyGUI::TextBox* ReviewDialog::addValueItem(const std::string text, const std::st skillNameWidget = skillClientWidget->createWidget("SandText", coord1, MyGUI::Align::Default); skillNameWidget->setCaption(text); + skillNameWidget->eventMouseWheel += MyGUI::newDelegate(this, &ReviewDialog::onMouseWheel); skillValueWidget = skillClientWidget->createWidget("SandTextRight", coord2, MyGUI::Align::Top | MyGUI::Align::Right); skillValueWidget->setCaption(value); skillValueWidget->_setWidgetState(state); + skillValueWidget->eventMouseWheel += MyGUI::newDelegate(this, &ReviewDialog::onMouseWheel); skillWidgets.push_back(skillNameWidget); skillWidgets.push_back(skillValueWidget); @@ -262,6 +283,7 @@ void ReviewDialog::addItem(const std::string text, MyGUI::IntCoord &coord1, MyGU skillNameWidget = skillClientWidget->createWidget("SandText", coord1 + MyGUI::IntSize(coord2.width, 0), MyGUI::Align::Default); skillNameWidget->setCaption(text); + skillNameWidget->eventMouseWheel += MyGUI::newDelegate(this, &ReviewDialog::onMouseWheel); skillWidgets.push_back(skillNameWidget); @@ -297,6 +319,12 @@ void ReviewDialog::addSkills(const SkillList &skills, const std::string &titleId else if (modified < base) state = "decreased"; MyGUI::TextBox* widget = addValueItem(mWindowManager.getGameSettingString(skillNameId, skillNameId), boost::lexical_cast(static_cast(modified)), state, coord1, coord2); + + for (int i=0; i<2; ++i) + { + ToolTips::createSkillToolTip(skillWidgets[skillWidgets.size()-1-i], skillId); + } + skillWidgetMap[skillId] = widget; } } @@ -330,6 +358,8 @@ void ReviewDialog::updateScroller() { skillScrollerWidget->setScrollRange(std::max(clientHeight - skillClientWidget->getHeight(), 0)); skillScrollerWidget->setScrollPage(std::max(skillClientWidget->getHeight() - lineHeight, 0)); + if (clientHeight != 0) + skillScrollerWidget->setTrackSize( (skillAreaWidget->getHeight() / float(clientHeight)) * skillScrollerWidget->getLineSize() ); } // widget controls @@ -363,3 +393,15 @@ void ReviewDialog::onBirthSignClicked(MyGUI::Widget* _sender) { eventActivateDialog(BIRTHSIGN_DIALOG); } + +void ReviewDialog::onMouseWheel(MyGUI::Widget* _sender, int _rel) +{ + if (skillScrollerWidget->getScrollPosition() - _rel*0.3 < 0) + skillScrollerWidget->setScrollPosition(0); + else if (skillScrollerWidget->getScrollPosition() - _rel*0.3 > skillScrollerWidget->getScrollRange()-1) + skillScrollerWidget->setScrollPosition(skillScrollerWidget->getScrollRange()-1); + else + skillScrollerWidget->setScrollPosition(skillScrollerWidget->getScrollPosition() - _rel*0.3); + + onScrollChangePosition(skillScrollerWidget, skillScrollerWidget->getScrollPosition()); +} diff --git a/apps/openmw/mwgui/review.hpp b/apps/openmw/mwgui/review.hpp index 76ca5a2d76..bae4dc4592 100644 --- a/apps/openmw/mwgui/review.hpp +++ b/apps/openmw/mwgui/review.hpp @@ -68,6 +68,8 @@ namespace MWGui void onClassClicked(MyGUI::Widget* _sender); void onBirthSignClicked(MyGUI::Widget* _sender); + void onMouseWheel(MyGUI::Widget* _sender, int _rel); + private: void addSkills(const SkillList &skills, const std::string &titleId, const std::string &titleDefault, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2); void addSeparator(MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2); diff --git a/apps/openmw/mwgui/stats_window.cpp b/apps/openmw/mwgui/stats_window.cpp index 54d9d7d4e3..061800bf0c 100644 --- a/apps/openmw/mwgui/stats_window.cpp +++ b/apps/openmw/mwgui/stats_window.cpp @@ -12,6 +12,7 @@ #include "../mwbase/environment.hpp" #include "window_manager.hpp" +#include "tooltips.hpp" using namespace MWGui; @@ -442,32 +443,17 @@ void StatsWindow::updateSkillArea() const ESM::Race* playerRace = store.races.find (MWBase::Environment::get().getWorld()->getPlayer().getRace()); MyGUI::Widget* raceWidget; getWidget(raceWidget, "RaceText"); - raceWidget->setUserString("Caption_CenteredCaption", playerRace->name); - raceWidget->setUserString("Caption_CenteredCaptionText", playerRace->description); + ToolTips::createRaceToolTip(raceWidget, playerRace); getWidget(raceWidget, "Race_str"); - raceWidget->setUserString("Caption_CenteredCaption", playerRace->name); - raceWidget->setUserString("Caption_CenteredCaptionText", playerRace->description); + ToolTips::createRaceToolTip(raceWidget, playerRace); // class tooltip MyGUI::Widget* classWidget; const ESM::Class& playerClass = MWBase::Environment::get().getWorld()->getPlayer().getClass(); - int spec = playerClass.data.specialization; - std::string specStr; - if (spec == 0) - specStr = "#{sSpecializationCombat}"; - else if (spec == 1) - specStr = "#{sSpecializationMagic}"; - else if (spec == 2) - specStr = "#{sSpecializationStealth}"; - getWidget(classWidget, "ClassText"); - classWidget->setUserString("Caption_ClassName", playerClass.name); - classWidget->setUserString("Caption_ClassDescription", playerClass.description); - classWidget->setUserString("Caption_ClassSpecialisation", "#{sSpecialization}: " + specStr); + ToolTips::createClassToolTip(classWidget, playerClass); getWidget(classWidget, "Class_str"); - classWidget->setUserString("Caption_ClassName", playerClass.name); - classWidget->setUserString("Caption_ClassDescription", playerClass.description); - classWidget->setUserString("Caption_ClassSpecialisation", "#{sSpecialization}: " + specStr); + ToolTips::createClassToolTip(classWidget, playerClass); if (!mFactions.empty()) { @@ -534,61 +520,8 @@ void StatsWindow::updateSkillArea() addGroup(mWindowManager.getGameSettingString("sBirthSign", "Sign"), coord1, coord2); const ESM::BirthSign *sign = store.birthSigns.find(birthSignId); MyGUI::Widget* w = addItem(sign->name, coord1, coord2); - w->setUserString("ToolTipType", "Layout"); - w->setUserString("ToolTipLayout", "BirthSignToolTip"); - std::string image = sign->texture; - image.replace(image.size()-3, 3, "dds"); - w->setUserString("ImageTexture_BirthSignImage", "textures\\" + image); - std::string text; - text += sign->name; - text += "\n#BF9959" + sign->description; - - std::vector abilities, powers, spells; - - std::vector::const_iterator it = sign->powers.list.begin(); - std::vector::const_iterator end = sign->powers.list.end(); - for (; it != end; ++it) - { - const std::string &spellId = *it; - const ESM::Spell *spell = store.spells.search(spellId); - if (!spell) - continue; // Skip spells which cannot be found - ESM::Spell::SpellType type = static_cast(spell->data.type); - if (type != ESM::Spell::ST_Spell && type != ESM::Spell::ST_Ability && type != ESM::Spell::ST_Power) - continue; // We only want spell, ability and powers. - - if (type == ESM::Spell::ST_Ability) - abilities.push_back(spellId); - else if (type == ESM::Spell::ST_Power) - powers.push_back(spellId); - else if (type == ESM::Spell::ST_Spell) - spells.push_back(spellId); - } - - struct{ const std::vector &spells; std::string label; } categories[3] = { - {abilities, "sBirthsignmenu1"}, - {powers, "sPowers"}, - {spells, "sBirthsignmenu2"} - }; - - for (int category = 0; category < 3; ++category) - { - for (std::vector::const_iterator it = categories[category].spells.begin(); it != categories[category].spells.end(); ++it) - { - if (it == categories[category].spells.begin()) - { - text += std::string("\n#DDC79E") + std::string("#{") + categories[category].label + "}"; - } - - const std::string &spellId = *it; - - const ESM::Spell *spell = store.spells.search(spellId); - text += "\n#BF9959" + spell->name; - } - } - - w->setUserString("Caption_BirthSignText", text); + ToolTips::createBirthsignToolTip(w, birthSignId); } // Add a line separator if there are items above diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index e21c886468..c6d8e2c8cc 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -65,6 +65,17 @@ void ToolTips::onFrame(float frameDuration) IntSize tooltipSize; + // try to go 1 level up until there is a widget that has tooltip + // this is necessary because some skin elements are actually separate widgets + int i=0; + while (!focus->isUserString("ToolTipType")) + { + focus = focus->getParent(); + if (!focus) + return; + ++i; + } + std::string type = focus->getUserString("ToolTipType"); std::string text = focus->getUserString("ToolTipText"); @@ -78,6 +89,29 @@ void ToolTips::onFrame(float frameDuration) mFocusObject = *focus->getUserData(); tooltipSize = getToolTipViaPtr(false); } + else if (type == "Spell") + { + ToolTipInfo info; + const ESM::Spell *spell = MWBase::Environment::get().getWorld()->getStore().spells.find(focus->getUserString("Spell")); + info.caption = spell->name; + Widgets::SpellEffectList effects; + std::vector::const_iterator end = spell->effects.list.end(); + for (std::vector::const_iterator it = spell->effects.list.begin(); it != end; ++it) + { + Widgets::SpellEffectParams params; + params.mEffectID = it->effectID; + params.mSkill = it->skill; + params.mAttribute = it->attribute; + params.mDuration = it->duration; + params.mMagnMin = it->magnMin; + params.mMagnMax = it->magnMax; + params.mRange = it->range; + params.mIsConstant = (spell->data.type == ESM::Spell::ST_Ability); + effects.push_back(params); + } + info.effects = effects; + tooltipSize = createToolTip(info); + } else if (type == "Layout") { // tooltip defined in the layout @@ -440,3 +474,150 @@ void ToolTips::setFocusObjectScreenCoords(float min_x, float min_y, float max_x, mFocusToolTipX = (min_x + max_x) / 2; mFocusToolTipY = min_y; } + +void ToolTips::createSkillToolTip(MyGUI::Widget* widget, int skillId) +{ + if (skillId == -1) + return; + + const std::string &skillNameId = ESMS::Skill::sSkillNameIds[skillId]; + const ESM::Skill* skill = MWBase::Environment::get().getWorld()->getStore().skills.search(skillId); + assert(skill); + const ESM::Attribute* attr = MWBase::Environment::get().getWorld()->getStore().attributes.search(skill->data.attribute); + assert(attr); + std::string icon = "icons\\k\\" + ESM::Skill::sIconNames[skillId]; + + widget->setUserString("ToolTipType", "Layout"); + widget->setUserString("ToolTipLayout", "SkillNoProgressToolTip"); + widget->setUserString("Caption_SkillNoProgressName", "#{"+skillNameId+"}"); + widget->setUserString("Caption_SkillNoProgressDescription", skill->description); + widget->setUserString("Caption_SkillNoProgressAttribute", "#{sGoverningAttribute}: #{" + attr->name + "}"); + widget->setUserString("ImageTexture_SkillNoProgressImage", icon); + widget->setUserString("ToolTipLayout", "SkillNoProgressToolTip"); + widget->setUserString("ToolTipLayout", "SkillNoProgressToolTip"); +} + +void ToolTips::createAttributeToolTip(MyGUI::Widget* widget, int attributeId) +{ + if (attributeId == -1) + return; + + const ESM::Attribute* attr = MWBase::Environment::get().getWorld()->getStore().attributes.search(attributeId); + assert(attr); + std::string icon = ESM::Attribute::attributeIcons[attributeId]; + std::string name = ESM::Attribute::gmstAttributeIds[attributeId]; + std::string desc = ESM::Attribute::gmstAttributeDescIds[attributeId]; + + widget->setUserString("ToolTipType", "Layout"); + widget->setUserString("ToolTipLayout", "AttributeToolTip"); + widget->setUserString("Caption_AttributeName", "#{"+name+"}"); + widget->setUserString("Caption_AttributeDescription", "#{"+desc+"}"); + widget->setUserString("ImageTexture_AttributeImage", icon); +} + +void ToolTips::createSpecializationToolTip(MyGUI::Widget* widget, const std::string& name, int specId) +{ + widget->setUserString("Caption_CenteredCaption", name); + std::string specText; + // get all skills of this specialisation + std::map skills = MWBase::Environment::get().getWorld()->getStore().skills.list; + for (std::map::const_iterator it = skills.begin(); + it != skills.end(); ++it) + { + if (it->second.data.specialization == specId) + specText += std::string("\n#{") + ESM::Skill::sSkillNameIds[it->second.index] + "}"; + } + widget->setUserString("Caption_CenteredCaptionText", specText); + widget->setUserString("ToolTipLayout", "TextWithCenteredCaptionToolTip"); + widget->setUserString("ToolTipType", "Layout"); +} + +void ToolTips::createBirthsignToolTip(MyGUI::Widget* widget, const std::string& birthsignId) +{ + const ESM::BirthSign *sign = MWBase::Environment::get().getWorld()->getStore().birthSigns.find(birthsignId); + + widget->setUserString("ToolTipType", "Layout"); + widget->setUserString("ToolTipLayout", "BirthSignToolTip"); + std::string image = sign->texture; + image.replace(image.size()-3, 3, "dds"); + widget->setUserString("ImageTexture_BirthSignImage", "textures\\" + image); + std::string text; + + text += sign->name; + text += "\n#BF9959" + sign->description; + + std::vector abilities, powers, spells; + + std::vector::const_iterator it = sign->powers.list.begin(); + std::vector::const_iterator end = sign->powers.list.end(); + for (; it != end; ++it) + { + const std::string &spellId = *it; + const ESM::Spell *spell = MWBase::Environment::get().getWorld()->getStore().spells.search(spellId); + if (!spell) + continue; // Skip spells which cannot be found + ESM::Spell::SpellType type = static_cast(spell->data.type); + if (type != ESM::Spell::ST_Spell && type != ESM::Spell::ST_Ability && type != ESM::Spell::ST_Power) + continue; // We only want spell, ability and powers. + + if (type == ESM::Spell::ST_Ability) + abilities.push_back(spellId); + else if (type == ESM::Spell::ST_Power) + powers.push_back(spellId); + else if (type == ESM::Spell::ST_Spell) + spells.push_back(spellId); + } + + struct{ const std::vector &spells; std::string label; } categories[3] = { + {abilities, "sBirthsignmenu1"}, + {powers, "sPowers"}, + {spells, "sBirthsignmenu2"} + }; + + for (int category = 0; category < 3; ++category) + { + for (std::vector::const_iterator it = categories[category].spells.begin(); it != categories[category].spells.end(); ++it) + { + if (it == categories[category].spells.begin()) + { + text += std::string("\n#DDC79E") + std::string("#{") + categories[category].label + "}"; + } + + const std::string &spellId = *it; + + const ESM::Spell *spell = MWBase::Environment::get().getWorld()->getStore().spells.search(spellId); + text += "\n#BF9959" + spell->name; + } + } + + widget->setUserString("Caption_BirthSignText", text); +} + +void ToolTips::createRaceToolTip(MyGUI::Widget* widget, const ESM::Race* playerRace) +{ + widget->setUserString("Caption_CenteredCaption", playerRace->name); + widget->setUserString("Caption_CenteredCaptionText", playerRace->description); + widget->setUserString("ToolTipType", "Layout"); + widget->setUserString("ToolTipLayout", "TextWithCenteredCaptionToolTip"); +} + +void ToolTips::createClassToolTip(MyGUI::Widget* widget, const ESM::Class& playerClass) +{ + if (playerClass.name == "") + return; + + int spec = playerClass.data.specialization; + std::string specStr; + if (spec == 0) + specStr = "#{sSpecializationCombat}"; + else if (spec == 1) + specStr = "#{sSpecializationMagic}"; + else if (spec == 2) + specStr = "#{sSpecializationStealth}"; + + widget->setUserString("Caption_ClassName", playerClass.name); + widget->setUserString("Caption_ClassDescription", playerClass.description); + widget->setUserString("Caption_ClassSpecialisation", "#{sSpecialization}: " + specStr); + widget->setUserString("ToolTipType", "Layout"); + widget->setUserString("ToolTipLayout", "ClassToolTip"); +} diff --git a/apps/openmw/mwgui/tooltips.hpp b/apps/openmw/mwgui/tooltips.hpp index 6d4a205d1a..1925a4f148 100644 --- a/apps/openmw/mwgui/tooltips.hpp +++ b/apps/openmw/mwgui/tooltips.hpp @@ -57,6 +57,15 @@ namespace MWGui static std::string getCountString(const int value); ///< @return blank string if count is 1, or else " (value)" + // these do not create an actual tooltip, but they fill in the data that is required so the tooltip + // system knows what to show in case this widget is hovered + static void createSkillToolTip(MyGUI::Widget* widget, int skillId); + static void createAttributeToolTip(MyGUI::Widget* widget, int attributeId); + static void createSpecializationToolTip(MyGUI::Widget* widget, const std::string& name, int specId); + static void createBirthsignToolTip(MyGUI::Widget* widget, const std::string& birthsignId); + static void createRaceToolTip(MyGUI::Widget* widget, const ESM::Race* playerRace); + static void createClassToolTip(MyGUI::Widget* widget, const ESM::Class& playerClass); + private: MyGUI::Widget* mDynamicToolTipBox; diff --git a/apps/openmw/mwgui/widgets.cpp b/apps/openmw/mwgui/widgets.cpp index 2fd40b7c22..b850748057 100644 --- a/apps/openmw/mwgui/widgets.cpp +++ b/apps/openmw/mwgui/widgets.cpp @@ -301,8 +301,8 @@ void MWEffectList::createEffectWidgets(std::vector &effects, M { effect = creator->createWidget("MW_EffectImage", coord, MyGUI::Align::Default); effect->setWindowManager(mWindowManager); - it->mIsConstant = (flags & EF_Constant); - it->mNoTarget = (flags & EF_NoTarget); + it->mIsConstant = (flags & EF_Constant) || it->mIsConstant; + it->mNoTarget = (flags & EF_NoTarget) || it->mNoTarget; effect->setSpellEffect(*it); effects.push_back(effect); if (effect->getRequestedWidth() > maxwidth) diff --git a/components/esm/attr.cpp b/components/esm/attr.cpp index 8c410e57a0..b077ef499c 100644 --- a/components/esm/attr.cpp +++ b/components/esm/attr.cpp @@ -34,3 +34,14 @@ const std::string Attribute::gmstAttributeDescIds[Attribute::Length] = { "sPerDesc", "sLucDesc" }; + +const std::string Attribute::attributeIcons[Attribute::Length] = { + "icons\\k\\attribute_strength.dds", + "icons\\k\\attribute_int.dds", + "icons\\k\\attribute_wilpower.dds", + "icons\\k\\attribute_agility.dds", + "icons\\k\\attribute_speed.dds", + "icons\\k\\attribute_endurance.dds", + "icons\\k\\attribute_personality.dds", + "icons\\k\\attribute_luck.dds" +}; diff --git a/components/esm/attr.hpp b/components/esm/attr.hpp index 183fb9e0e0..620683dbb1 100644 --- a/components/esm/attr.hpp +++ b/components/esm/attr.hpp @@ -30,6 +30,7 @@ struct Attribute static const AttributeID attributeIds[Length]; static const std::string gmstAttributeIds[Length]; static const std::string gmstAttributeDescIds[Length]; + static const std::string attributeIcons[Length]; Attribute(AttributeID id, const std::string &name, const std::string &description) : id(id) diff --git a/files/mygui/openmw_chargen_class_layout.xml b/files/mygui/openmw_chargen_class_layout.xml index 38fa606abe..613143d542 100644 --- a/files/mygui/openmw_chargen_class_layout.xml +++ b/files/mygui/openmw_chargen_class_layout.xml @@ -14,8 +14,11 @@ - + + + + @@ -23,16 +26,19 @@ - + + + + - + @@ -42,7 +48,7 @@ - + @@ -58,7 +64,7 @@ - + diff --git a/files/mygui/openmw_chargen_create_class_layout.xml b/files/mygui/openmw_chargen_create_class_layout.xml index be6a10e0c9..dde74a6a2c 100644 --- a/files/mygui/openmw_chargen_create_class_layout.xml +++ b/files/mygui/openmw_chargen_create_class_layout.xml @@ -12,17 +12,23 @@ - + + + + - + - + + + + @@ -59,7 +65,7 @@ - + diff --git a/files/mygui/openmw_chargen_generate_class_result_layout.xml b/files/mygui/openmw_chargen_generate_class_result_layout.xml index 9a6ed4f2ec..1cef9c9ce6 100644 --- a/files/mygui/openmw_chargen_generate_class_result_layout.xml +++ b/files/mygui/openmw_chargen_generate_class_result_layout.xml @@ -9,10 +9,10 @@ - + @@ -24,7 +24,7 @@ - + diff --git a/files/mygui/openmw_chargen_race_layout.xml b/files/mygui/openmw_chargen_race_layout.xml index a9b072f5e2..df0d29f78c 100644 --- a/files/mygui/openmw_chargen_race_layout.xml +++ b/files/mygui/openmw_chargen_race_layout.xml @@ -17,27 +17,23 @@ - - - - @@ -45,15 +41,13 @@ - - + - diff --git a/files/mygui/openmw_chargen_review_layout.xml b/files/mygui/openmw_chargen_review_layout.xml index 57bb3b1246..2071cac88d 100644 --- a/files/mygui/openmw_chargen_review_layout.xml +++ b/files/mygui/openmw_chargen_review_layout.xml @@ -26,26 +26,83 @@ + + + + + + + + + - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -59,7 +116,7 @@ - + diff --git a/files/mygui/openmw_chargen_select_specialization_layout.xml b/files/mygui/openmw_chargen_select_specialization_layout.xml index 53980b1335..1b5295bc9e 100644 --- a/files/mygui/openmw_chargen_select_specialization_layout.xml +++ b/files/mygui/openmw_chargen_select_specialization_layout.xml @@ -11,13 +11,13 @@ - + - + - + diff --git a/files/mygui/openmw_infobox_layout.xml b/files/mygui/openmw_infobox_layout.xml index de10308304..89031a6162 100644 --- a/files/mygui/openmw_infobox_layout.xml +++ b/files/mygui/openmw_infobox_layout.xml @@ -4,7 +4,7 @@ - + diff --git a/files/mygui/openmw_resources.xml b/files/mygui/openmw_resources.xml index e96aeb918e..f1a8b0dfc7 100644 --- a/files/mygui/openmw_resources.xml +++ b/files/mygui/openmw_resources.xml @@ -139,4 +139,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/mygui/openmw_text.skin.xml b/files/mygui/openmw_text.skin.xml index 6b62f618db..bfa970de52 100644 --- a/files/mygui/openmw_text.skin.xml +++ b/files/mygui/openmw_text.skin.xml @@ -65,26 +65,45 @@ - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - + diff --git a/files/mygui/openmw_tooltips.xml b/files/mygui/openmw_tooltips.xml index 262fd2020a..148e98064f 100644 --- a/files/mygui/openmw_tooltips.xml +++ b/files/mygui/openmw_tooltips.xml @@ -134,6 +134,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + From f6a6684685d033554f01fb1a0187f77be5c6eee3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 27 May 2012 21:39:18 +0200 Subject: [PATCH 288/325] when the resolution changes, adjust camera aspect ratio and recreate compositors --- apps/openmw/mwrender/compositors.cpp | 15 +++++++++++ apps/openmw/mwrender/compositors.hpp | 5 ++++ apps/openmw/mwrender/renderingmanager.cpp | 32 +++++++++++++++++++++++ apps/openmw/mwrender/renderingmanager.hpp | 10 ++++++- apps/openmw/mwrender/sky.cpp | 7 +++-- apps/openmw/mwrender/sky.hpp | 2 +- apps/openmw/mwrender/water.cpp | 9 +++++-- apps/openmw/mwrender/water.hpp | 3 ++- libs/openengine/ogre/renderer.cpp | 15 +++++++++++ libs/openengine/ogre/renderer.hpp | 5 ++++ 10 files changed, 94 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwrender/compositors.cpp b/apps/openmw/mwrender/compositors.cpp index 4c9f08b72e..d786c263b1 100644 --- a/apps/openmw/mwrender/compositors.cpp +++ b/apps/openmw/mwrender/compositors.cpp @@ -26,6 +26,21 @@ void Compositors::setEnabled (const bool enabled) mEnabled = enabled; } +void Compositors::recreate() +{ + Ogre::CompositorManager::getSingleton().removeCompositorChain(mViewport); + + CompositorMap temp = mCompositors; + mCompositors.clear(); + + for (CompositorMap::iterator it=temp.begin(); + it != temp.end(); ++it) + { + addCompositor(it->first, it->second.second); + setCompositorEnabled(it->first, mEnabled && it->second.first); + } +} + void Compositors::addCompositor (const std::string& name, const int priority) { int id = 0; diff --git a/apps/openmw/mwrender/compositors.hpp b/apps/openmw/mwrender/compositors.hpp index 50b53f84aa..f249ece420 100644 --- a/apps/openmw/mwrender/compositors.hpp +++ b/apps/openmw/mwrender/compositors.hpp @@ -25,6 +25,11 @@ namespace MWRender */ void setEnabled (const bool enabled); + void setViewport(Ogre::Viewport* vp) { mViewport = vp; } + + /// recreate compositors (call this after viewport size changes) + void recreate(); + bool toggle() { setEnabled(!mEnabled); return mEnabled; } /** diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 86c1f752c2..e5ce6b0ddd 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -11,6 +11,7 @@ #include "../mwworld/world.hpp" // these includes can be removed once the static-hack is gone #include "../mwworld/ptr.hpp" +#include "../mwworld/player.hpp" #include "../mwbase/environment.hpp" #include #include @@ -30,6 +31,7 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const :mRendering(_rend), mObjects(mRendering), mActors(mRendering), mAmbientMode(0), mSunEnabled(0) { mRendering.createScene("PlayerCam", Settings::Manager::getFloat("field of view", "General"), 5); + mRendering.setWindowEventListener(this); mCompositors = new Compositors(mRendering.getViewport()); @@ -567,6 +569,7 @@ Compositors* RenderingManager::getCompositors() void RenderingManager::processChangedSettings(const Settings::CategorySettingVector& settings) { + bool changeRes = false; for (Settings::CategorySettingVector::const_iterator it=settings.begin(); it != settings.end(); ++it) { @@ -574,6 +577,24 @@ void RenderingManager::processChangedSettings(const Settings::CategorySettingVec { setMenuTransparency(Settings::Manager::getFloat("menu transparency", "GUI")); } + else if (it->second == "max viewing distance" && it->first == "Viewing distance") + { + if (!MWBase::Environment::get().getWorld()->isCellExterior() && !MWBase::Environment::get().getWorld()->isCellQuasiExterior()) + configureFog(*MWBase::Environment::get().getWorld()->getPlayer().getPlayer().getCell()); + } + else if (it->first == "Video" && ( + it->second == "resolution x" + || it->second == "resolution y" + || it->second == "fullscreen")) + changeRes = true; + } + + if (changeRes) + { + int x = Settings::Manager::getInt("resolution x", "Video"); + int y = Settings::Manager::getInt("resolution y", "Video"); + mRendering.getWindow()->resize(x, y); + mRendering.getWindow()->setFullscreen(Settings::Manager::getBool("fullscreen", "Video"), x, y); } } @@ -587,4 +608,15 @@ void RenderingManager::setMenuTransparency(float val) tex->getBuffer()->unlock(); } +void RenderingManager::windowResized(Ogre::RenderWindow* rw) +{ + mCompositors->setViewport(mRendering.recreateViewport()); + mCompositors->recreate(); + mWater->assignTextures(); +} + +void RenderingManager::windowClosed(Ogre::RenderWindow* rw) +{ +} + } // namespace diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index edee193f36..562184c62e 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -8,6 +8,8 @@ #include "../mwworld/class.hpp" +#include + #include #include #include @@ -51,7 +53,7 @@ namespace MWRender class Water; class Compositors; -class RenderingManager: private RenderingInterface { +class RenderingManager: private RenderingInterface, public Ogre::WindowEventListener { private: @@ -161,6 +163,12 @@ class RenderingManager: private RenderingInterface { void processChangedSettings(const Settings::CategorySettingVector& settings); + Ogre::Viewport* getViewport() { return mRendering.getViewport(); } + + protected: + virtual void windowResized(Ogre::RenderWindow* rw); + virtual void windowClosed(Ogre::RenderWindow* rw); + private: void setAmbientMode(); diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 72f88c6c52..19e45c189d 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -374,7 +374,7 @@ SkyManager::SkyManager (SceneNode* pMwRoot, Camera* pCamera) , mSunGlare(NULL) , mMasser(NULL) , mSecunda(NULL) - , mViewport(NULL) + , mCamera(pCamera) , mRootNode(NULL) , mSceneMgr(NULL) , mAtmosphereDay(NULL) @@ -399,9 +399,8 @@ SkyManager::SkyManager (SceneNode* pMwRoot, Camera* pCamera) , mSecundaEnabled(true) , mCreated(false) { - mViewport = pCamera->getViewport(); mSceneMgr = pMwRoot->getCreator(); - mRootNode = pCamera->getParentSceneNode()->createChildSceneNode(); + mRootNode = mCamera->getParentSceneNode()->createChildSceneNode(); mRootNode->pitch(Degree(-90)); // convert MW to ogre coordinates mRootNode->setInheritOrientation(false); } @@ -741,7 +740,7 @@ void SkyManager::update(float duration) // on how directly the player is looking at the sun Vector3 sun = mSunGlare->getPosition(); sun = Vector3(sun.x, sun.z, -sun.y); - Vector3 cam = mViewport->getCamera()->getRealDirection(); + Vector3 cam = mCamera->getRealDirection(); const Degree angle = sun.angleBetween( cam ); float val = 1- (angle.valueDegrees() / 180.f); val = (val*val*val*val)*2; diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index da89d0eb04..e11745e828 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -185,7 +185,7 @@ namespace MWRender Moon* mMasser; Moon* mSecunda; - Ogre::Viewport* mViewport; + Ogre::Camera* mCamera; Ogre::SceneNode* mRootNode; Ogre::SceneManager* mSceneMgr; diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index dda215999c..981343e919 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -10,7 +10,7 @@ namespace MWRender { Water::Water (Ogre::Camera *camera, RenderingManager* rend, const ESM::Cell* cell) : - mCamera (camera), mViewport (camera->getViewport()), mSceneManager (camera->getSceneManager()), + mCamera (camera), mSceneManager (camera->getSceneManager()), mIsUnderwater(false), mVisibilityFlags(0), mReflectionTarget(0), mActive(1), mToggled(1), mReflectionRenderActive(false), mRendering(rend) @@ -80,6 +80,8 @@ Water::Water (Ogre::Camera *camera, RenderingManager* rend, const ESM::Cell* cel mSceneManager->addRenderQueueListener(this); + assignTextures(); + // ---------------------------------------------------------------------------------------------- // ---------------------------------- reflection debug overlay ---------------------------------- @@ -262,10 +264,13 @@ void Water::createMaterial() // use technique without shaders if reflection is disabled if (mReflectionTarget == 0) mMaterial->removeTechnique(0); +} +void Water::assignTextures() +{ if (Settings::Manager::getBool("shader", "Water")) { - CompositorInstance* compositor = CompositorManager::getSingleton().getCompositorChain(mViewport)->getCompositor("gbuffer"); + CompositorInstance* compositor = CompositorManager::getSingleton().getCompositorChain(mRendering->getViewport())->getCompositor("gbuffer"); TexturePtr colorTexture = compositor->getTextureInstance("mrt_output", 0); TextureUnitState* tus = mMaterial->getTechnique(0)->getPass(0)->getTextureUnitState("refractionMap"); diff --git a/apps/openmw/mwrender/water.hpp b/apps/openmw/mwrender/water.hpp index 25631b4aff..edd217e842 100644 --- a/apps/openmw/mwrender/water.hpp +++ b/apps/openmw/mwrender/water.hpp @@ -17,7 +17,6 @@ namespace MWRender { static const int CELL_SIZE = 8192; Ogre::Camera *mCamera; Ogre::SceneManager *mSceneManager; - Ogre::Viewport *mViewport; Ogre::Plane mWaterPlane; Ogre::SceneNode *mWaterNode; @@ -65,6 +64,8 @@ namespace MWRender { void toggle(); void update(); + void assignTextures(); + void setViewportBackground(const Ogre::ColourValue& bg); void checkUnderwater(float y); diff --git a/libs/openengine/ogre/renderer.cpp b/libs/openengine/ogre/renderer.cpp index ab7920ab83..579ba3dd7c 100644 --- a/libs/openengine/ogre/renderer.cpp +++ b/libs/openengine/ogre/renderer.cpp @@ -144,3 +144,18 @@ void OgreRenderer::createScene(const std::string camName, float fov, float nearC mFader = new Fader(); } + +Ogre::Viewport* OgreRenderer::recreateViewport() +{ + mWindow->removeViewport(mView->getZOrder()); + mView = mWindow->addViewport(mCamera); + + // Alter the camera aspect ratio to match the viewport + mCamera->setAspectRatio(Real(mView->getActualWidth()) / Real(mView->getActualHeight())); + return mView; +} + +void OgreRenderer::setWindowEventListener(Ogre::WindowEventListener* listener) +{ + Ogre::WindowEventUtilities::addWindowEventListener(mWindow, listener); +} diff --git a/libs/openengine/ogre/renderer.hpp b/libs/openengine/ogre/renderer.hpp index 50fe640151..7a0fd11df6 100644 --- a/libs/openengine/ogre/renderer.hpp +++ b/libs/openengine/ogre/renderer.hpp @@ -25,6 +25,7 @@ #endif #include "OgreTexture.h" +#include namespace Ogre { @@ -104,6 +105,8 @@ namespace OEngine ~OgreRenderer() { cleanup(); } + void setWindowEventListener(Ogre::WindowEventListener* listener); + /** Configure the renderer. This will load configuration files and set up the Root and logging classes. */ void configure( @@ -153,6 +156,8 @@ namespace OEngine /// Viewport Ogre::Viewport *getViewport() { return mView; } + + Ogre::Viewport* recreateViewport(); }; } } From 8f667580bb855ae04857eda9c228888956527d87 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 27 May 2012 23:12:45 +0200 Subject: [PATCH 289/325] ogre 1.8 final release compability fixes --- apps/openmw/mwrender/terrain.cpp | 20 ++++++++++---------- apps/openmw/mwrender/terrain.hpp | 2 +- files/gbuffer/gbuffer.compositor | 17 ++++------------- 3 files changed, 15 insertions(+), 24 deletions(-) diff --git a/apps/openmw/mwrender/terrain.cpp b/apps/openmw/mwrender/terrain.cpp index 56eff4a9ae..90345cf301 100644 --- a/apps/openmw/mwrender/terrain.cpp +++ b/apps/openmw/mwrender/terrain.cpp @@ -22,30 +22,30 @@ namespace MWRender TerrainManager::TerrainManager(Ogre::SceneManager* mgr, RenderingManager* rend) : mTerrainGroup(TerrainGroup(mgr, Terrain::ALIGN_X_Z, mLandSize, mWorldSize)), mRendering(rend) { - + mTerrainGlobals = OGRE_NEW TerrainGlobalOptions(); TerrainMaterialGeneratorPtr matGen; TerrainMaterialGeneratorB* matGenP = new TerrainMaterialGeneratorB(); matGen.bind(matGenP); - mTerrainGlobals.setDefaultMaterialGenerator(matGen); + mTerrainGlobals->setDefaultMaterialGenerator(matGen); TerrainMaterialGenerator::Profile* const activeProfile = - mTerrainGlobals.getDefaultMaterialGenerator() + mTerrainGlobals->getDefaultMaterialGenerator() ->getActiveProfile(); mActiveProfile = static_cast(activeProfile); //The pixel error should be as high as possible without it being noticed //as it governs how fast mesh quality decreases. - mTerrainGlobals.setMaxPixelError(8); + mTerrainGlobals->setMaxPixelError(8); - mTerrainGlobals.setLayerBlendMapSize(32); - mTerrainGlobals.setDefaultGlobalColourMapSize(65); + mTerrainGlobals->setLayerBlendMapSize(32); + mTerrainGlobals->setDefaultGlobalColourMapSize(65); //10 (default) didn't seem to be quite enough - mTerrainGlobals.setSkirtSize(128); + mTerrainGlobals->setSkirtSize(128); //due to the sudden flick between composite and non composite textures, //this seemed the distance where it wasn't too noticeable - mTerrainGlobals.setCompositeMapDistance(mWorldSize*2); + mTerrainGlobals->setCompositeMapDistance(mWorldSize*2); mActiveProfile->setLightmapEnabled(false); mActiveProfile->setLayerSpecularMappingEnabled(false); @@ -92,14 +92,14 @@ namespace MWRender void TerrainManager::setDiffuse(const ColourValue& diffuse) { - mTerrainGlobals.setCompositeMapDiffuse(diffuse); + mTerrainGlobals->setCompositeMapDiffuse(diffuse); } //---------------------------------------------------------------------------------------------- void TerrainManager::setAmbient(const ColourValue& ambient) { - mTerrainGlobals.setCompositeMapAmbient(ambient); + mTerrainGlobals->setCompositeMapAmbient(ambient); } //---------------------------------------------------------------------------------------------- diff --git a/apps/openmw/mwrender/terrain.hpp b/apps/openmw/mwrender/terrain.hpp index c4ff053a6f..273ede0849 100644 --- a/apps/openmw/mwrender/terrain.hpp +++ b/apps/openmw/mwrender/terrain.hpp @@ -33,7 +33,7 @@ namespace MWRender{ void cellAdded(MWWorld::Ptr::CellStore* store); void cellRemoved(MWWorld::Ptr::CellStore* store); private: - Ogre::TerrainGlobalOptions mTerrainGlobals; + Ogre::TerrainGlobalOptions* mTerrainGlobals; Ogre::TerrainGroup mTerrainGroup; RenderingManager* mRendering; diff --git a/files/gbuffer/gbuffer.compositor b/files/gbuffer/gbuffer.compositor index 316003af6b..6ca35df87b 100644 --- a/files/gbuffer/gbuffer.compositor +++ b/files/gbuffer/gbuffer.compositor @@ -11,11 +11,8 @@ compositor gbuffer input none pass clear { - clear - { - // make sure to set this to the viewport background color from outside - colour_value 0 0 0 1 - } + // make sure to set this to the viewport background color from outside + colour_value 0 0 0 1 } pass render_scene { @@ -59,11 +56,8 @@ compositor gbufferFinalizer shadows off pass clear { - clear - { - buffers colour - colour_value 0 0 0 0 - } + buffers colour + colour_value 0 0 0 0 } pass render_quad { @@ -81,9 +75,6 @@ compositor gbufferFinalizer input none pass clear { - clear - { - } } pass render_quad { From 19c428e86c46ab120379f9dbfb1aceb72ac6d0ff Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 28 May 2012 02:04:00 +0200 Subject: [PATCH 290/325] delete fix --- apps/openmw/mwrender/terrain.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwrender/terrain.cpp b/apps/openmw/mwrender/terrain.cpp index 90345cf301..4dac750c7c 100644 --- a/apps/openmw/mwrender/terrain.cpp +++ b/apps/openmw/mwrender/terrain.cpp @@ -86,6 +86,7 @@ namespace MWRender TerrainManager::~TerrainManager() { + OGRE_DELETE mTerrainGlobals; } //---------------------------------------------------------------------------------------------- From 3daf1ebc3fc36dbc565279a1274a110a69963147 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 28 May 2012 05:03:50 +0200 Subject: [PATCH 291/325] small map tweak --- apps/openmw/mwrender/localmap.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index 55cb45fdcc..2442700bb5 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -326,8 +326,8 @@ void LocalMap::updatePlayer (const Ogre::Vector3& position, const Ogre::Quaterni MWBase::Environment::get().getWindowManager()->setPlayerDir(playerdirection.x, -playerdirection.z); // explore radius (squared) - const float sqrExploreRadius = 0.01 * sFogOfWarResolution*sFogOfWarResolution; - const float exploreRadius = 0.1 * sFogOfWarResolution; // explore radius from 0 to sFogOfWarResolution + const float sqrExploreRadius = (mInterior ? 0.01 : 0.09) * sFogOfWarResolution*sFogOfWarResolution; + const float exploreRadius = (mInterior ? 0.1 : 0.3) * sFogOfWarResolution; // explore radius from 0 to sFogOfWarResolution const float exploreRadiusUV = exploreRadius / sFogOfWarResolution; // explore radius from 0 to 1 (UV space) int intExtMult = mInterior ? 1 : -1; // interior and exterior have reversed Y coordinates (interior: top to bottom) @@ -364,7 +364,11 @@ void LocalMap::updatePlayer (const Ogre::Vector3& position, const Ogre::Quaterni { for (int texU = 0; texU> 24); alpha = std::min( alpha, (uint8) (std::max(0.f, std::min(1.f, (sqrDist/sqrExploreRadius)))*255) ); From 14f4f09f834b4d5f7c1d840de8b3be18ff66943e Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 28 May 2012 09:19:25 +0200 Subject: [PATCH 292/325] proper resolution switching (reposition GUI & adjust mouse clipping region) --- apps/openmw/mwgui/console.cpp | 5 +++++ apps/openmw/mwgui/console.hpp | 2 ++ apps/openmw/mwgui/hud.cpp | 5 +++++ apps/openmw/mwgui/hud.hpp | 1 + apps/openmw/mwgui/settingswindow.cpp | 5 +++++ apps/openmw/mwgui/window_base.cpp | 10 +++++++++- apps/openmw/mwgui/window_manager.cpp | 21 +++++++++++++++++++++ apps/openmw/mwinput/inputmanager.cpp | 23 ++++++++++++++++++++++- apps/openmw/mwinput/inputmanager.hpp | 4 ++++ apps/openmw/mwrender/renderingmanager.cpp | 23 +++++++++++++++++++---- libs/mangle/input/servers/ois_driver.cpp | 7 +++++++ libs/mangle/input/servers/ois_driver.hpp | 2 ++ libs/openengine/gui/events.cpp | 18 +++--------------- libs/openengine/gui/events.hpp | 2 -- libs/openengine/ogre/renderer.cpp | 6 +----- libs/openengine/ogre/renderer.hpp | 2 +- 16 files changed, 107 insertions(+), 29 deletions(-) diff --git a/apps/openmw/mwgui/console.cpp b/apps/openmw/mwgui/console.cpp index 8e15abddd6..bf80a77b2f 100644 --- a/apps/openmw/mwgui/console.cpp +++ b/apps/openmw/mwgui/console.cpp @@ -370,4 +370,9 @@ namespace MWGui /* All keywords match with the shortest. Append it to the output string and return it. */ return output.append(matches.front()); } + + void Console::onResChange(int width, int height) + { + setCoord(10,10, width-10, height/2); + } } diff --git a/apps/openmw/mwgui/console.hpp b/apps/openmw/mwgui/console.hpp index 6974d83330..1172858473 100644 --- a/apps/openmw/mwgui/console.hpp +++ b/apps/openmw/mwgui/console.hpp @@ -58,6 +58,8 @@ namespace MWGui void setFont(const std::string &fntName); + void onResChange(int width, int height); + void clearHistory(); // Print a message to the console. Messages may contain color diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index d3d7696b4a..31952e9931 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -347,3 +347,8 @@ void HUD::onFrame(float dt) if (mCellNameTimer < 0) mCellNameBox->setVisible(false); } + +void HUD::onResChange(int width, int height) +{ + setCoord(0, 0, width, height); +} diff --git a/apps/openmw/mwgui/hud.hpp b/apps/openmw/mwgui/hud.hpp index f7131a39c6..531dd70202 100644 --- a/apps/openmw/mwgui/hud.hpp +++ b/apps/openmw/mwgui/hud.hpp @@ -26,6 +26,7 @@ namespace MWGui void setFpsLevel(const int level); void onFrame(float dt); + void onResChange(int width, int height); void setCellName(const std::string& cellName); diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index 0e08152283..c8337d74c4 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -11,6 +11,7 @@ #include "../mwbase/environment.hpp" #include "../mwworld/world.hpp" #include "../mwsound/soundmanager.hpp" +#include "../mwinput/inputmanager.hpp" #include "window_manager.hpp" #include "confirmationdialog.hpp" @@ -144,7 +145,10 @@ namespace MWGui } if (_sender == mFullscreenButton) + { Settings::Manager::setBool("fullscreen", "Video", newState); + apply(); + } else if (_sender == mVSyncButton) { Settings::Manager::setBool("vsync", "Video", newState); @@ -188,5 +192,6 @@ namespace MWGui MWBase::Environment::get().getWorld()->processChangedSettings(changed); MWBase::Environment::get().getSoundManager()->processChangedSettings(changed); MWBase::Environment::get().getWindowManager()->processChangedSettings(changed); + MWBase::Environment::get().getInputManager()->processChangedSettings(changed); } } diff --git a/apps/openmw/mwgui/window_base.cpp b/apps/openmw/mwgui/window_base.cpp index 45206214b8..4330579311 100644 --- a/apps/openmw/mwgui/window_base.cpp +++ b/apps/openmw/mwgui/window_base.cpp @@ -1,6 +1,8 @@ #include "window_base.hpp" #include "window_manager.hpp" +#include + using namespace MWGui; WindowBase::WindowBase(const std::string& parLayout, WindowManager& parWindowManager) @@ -25,7 +27,13 @@ void WindowBase::setVisible(bool visible) void WindowBase::center() { // Centre dialog - MyGUI::IntSize gameWindowSize = MyGUI::RenderManager::getInstance().getViewSize(); + + // MyGUI::IntSize gameWindowSize = MyGUI::RenderManager::getInstance().getViewSize(); + // Note by scrawl: The following works more reliably in the case when the window was _just_ + // resized and MyGUI RenderManager doesn't know about the new size yet + MyGUI::IntSize gameWindowSize = MyGUI::IntSize(Settings::Manager::getInt("resolution x", "Video"), + Settings::Manager::getInt("resolution y", "Video")); + MyGUI::IntCoord coord = mMainWidget->getCoord(); coord.left = (gameWindowSize.width - coord.width)/2; coord.top = (gameWindowSize.height - coord.height)/2; diff --git a/apps/openmw/mwgui/window_manager.cpp b/apps/openmw/mwgui/window_manager.cpp index a6d236136c..891f85ca2a 100644 --- a/apps/openmw/mwgui/window_manager.cpp +++ b/apps/openmw/mwgui/window_manager.cpp @@ -605,6 +605,27 @@ void WindowManager::onRetrieveTag(const MyGUI::UString& _tag, MyGUI::UString& _r void WindowManager::processChangedSettings(const Settings::CategorySettingVector& changed) { hud->setFpsLevel(Settings::Manager::getInt("fps", "HUD")); + + bool changeRes = false; + for (Settings::CategorySettingVector::const_iterator it = changed.begin(); + it != changed.end(); ++it) + { + if (it->first == "Video" && ( + it->second == "resolution x" + || it->second == "resolution y")) + { + changeRes = true; + } + } + + if (changeRes) + { + int x = Settings::Manager::getInt("resolution x", "Video"); + int y = Settings::Manager::getInt("resolution y", "Video"); + hud->onResChange(x, y); + console->onResChange(x, y); + mSettingsWindow->center(); + } } void WindowManager::pushGuiMode(GuiMode mode) diff --git a/apps/openmw/mwinput/inputmanager.cpp b/apps/openmw/mwinput/inputmanager.cpp index 9b6a1d39bc..a2bafcbf78 100644 --- a/apps/openmw/mwinput/inputmanager.cpp +++ b/apps/openmw/mwinput/inputmanager.cpp @@ -92,7 +92,12 @@ namespace MWInput /* InputImpl Methods */ - +public: + void adjustMouseRegion(int width, int height) + { + input.adjustMouseClippingSize(width, height); + } +private: void toggleSpell() { if (windows.isGuiMode()) return; @@ -450,4 +455,20 @@ namespace MWInput { impl->changeInputMode(guiMode); } + + void MWInputManager::processChangedSettings(const Settings::CategorySettingVector& changed) + { + bool changeRes = false; + for (Settings::CategorySettingVector::const_iterator it = changed.begin(); + it != changed.end(); ++it) + { + if (it->first == "Video" && ( + it->second == "resolution x" + || it->second == "resolution y")) + changeRes = true; + } + + if (changeRes) + impl->adjustMouseRegion(Settings::Manager::getInt("resolution x", "Video"), Settings::Manager::getInt("resolution y", "Video")); + } } diff --git a/apps/openmw/mwinput/inputmanager.hpp b/apps/openmw/mwinput/inputmanager.hpp index b8d98ed566..4ef3df1371 100644 --- a/apps/openmw/mwinput/inputmanager.hpp +++ b/apps/openmw/mwinput/inputmanager.hpp @@ -3,6 +3,8 @@ #include "../mwgui/mode.hpp" +#include + namespace OEngine { namespace Render @@ -52,6 +54,8 @@ namespace MWInput void changeInputMode(bool guiMode); + void processChangedSettings(const Settings::CategorySettingVector& changed); + void setDragDrop(bool dragDrop); }; } diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index e5ce6b0ddd..46e274ff5d 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -22,6 +22,9 @@ #include "water.hpp" #include "compositors.hpp" +#include "../mwgui/window_manager.hpp" // FIXME +#include "../mwinput/inputmanager.hpp" // FIXME + using namespace MWRender; using namespace Ogre; @@ -591,9 +594,13 @@ void RenderingManager::processChangedSettings(const Settings::CategorySettingVec if (changeRes) { - int x = Settings::Manager::getInt("resolution x", "Video"); - int y = Settings::Manager::getInt("resolution y", "Video"); - mRendering.getWindow()->resize(x, y); + unsigned int x = Settings::Manager::getInt("resolution x", "Video"); + unsigned int y = Settings::Manager::getInt("resolution y", "Video"); + + if (x != mRendering.getWindow()->getWidth() || y != mRendering.getWindow()->getHeight()) + { + mRendering.getWindow()->resize(x, y); + } mRendering.getWindow()->setFullscreen(Settings::Manager::getBool("fullscreen", "Video"), x, y); } } @@ -610,9 +617,17 @@ void RenderingManager::setMenuTransparency(float val) void RenderingManager::windowResized(Ogre::RenderWindow* rw) { - mCompositors->setViewport(mRendering.recreateViewport()); + Settings::Manager::setInt("resolution x", "Video", rw->getWidth()); + Settings::Manager::setInt("resolution y", "Video", rw->getHeight()); + + + mRendering.adjustViewport(); mCompositors->recreate(); mWater->assignTextures(); + + const Settings::CategorySettingVector& changed = Settings::Manager::apply(); + MWBase::Environment::get().getInputManager()->processChangedSettings(changed); //FIXME + MWBase::Environment::get().getWindowManager()->processChangedSettings(changed); // FIXME } void RenderingManager::windowClosed(Ogre::RenderWindow* rw) diff --git a/libs/mangle/input/servers/ois_driver.cpp b/libs/mangle/input/servers/ois_driver.cpp index 2071b91ea6..acca69df4a 100644 --- a/libs/mangle/input/servers/ois_driver.cpp +++ b/libs/mangle/input/servers/ois_driver.cpp @@ -146,3 +146,10 @@ bool OISDriver::isDown(int index) // TODO: Extend to mouse buttons as well return keyboard->isKeyDown((OIS::KeyCode)index); } + +void OISDriver::adjustMouseClippingSize(int width, int height) +{ + const OIS::MouseState &ms = mouse->getMouseState(); + ms.width = width; + ms.height = height; +} diff --git a/libs/mangle/input/servers/ois_driver.hpp b/libs/mangle/input/servers/ois_driver.hpp index ba780c39e6..81633542fb 100644 --- a/libs/mangle/input/servers/ois_driver.hpp +++ b/libs/mangle/input/servers/ois_driver.hpp @@ -31,6 +31,8 @@ namespace Mangle OISDriver(Ogre::RenderWindow *window, bool exclusive=true); ~OISDriver(); + void adjustMouseClippingSize(int width, int height); + void capture(); bool isDown(int index); /// Not currently supported. diff --git a/libs/openengine/gui/events.cpp b/libs/openengine/gui/events.cpp index 3e52c6435d..a19c247c25 100644 --- a/libs/openengine/gui/events.cpp +++ b/libs/openengine/gui/events.cpp @@ -8,18 +8,9 @@ using namespace OIS; using namespace OEngine::GUI; EventInjector::EventInjector(MyGUI::Gui *g) - : gui(g), mouseX(0), mouseY(0), enabled(true) + : gui(g), enabled(true) { assert(gui); - maxX = MyGUI::RenderManager::getInstance().getViewSize().width; - maxY = MyGUI::RenderManager::getInstance().getViewSize().height; -} - -template -void setRange(X &x, X min, X max) -{ - if(x < min) x = min; - else if(x > max) x = max; } void EventInjector::event(Type type, int index, const void *p) @@ -64,11 +55,8 @@ void EventInjector::event(Type type, int index, const void *p) MyGUI::MouseButton id = MyGUI::MouseButton::Enum(index); // Update mouse position - mouseX += mouse->state.X.rel; - mouseY += mouse->state.Y.rel; - - setRange(mouseX,0,maxX); - setRange(mouseY,0,maxY); + int mouseX = mouse->state.X.abs; + int mouseY = mouse->state.Y.abs; if(type == EV_MouseDown) MyGUI::InputManager::getInstance().injectMousePress(mouseX, mouseY, id); diff --git a/libs/openengine/gui/events.hpp b/libs/openengine/gui/events.hpp index 6ca83cf753..1f506cffad 100644 --- a/libs/openengine/gui/events.hpp +++ b/libs/openengine/gui/events.hpp @@ -16,8 +16,6 @@ namespace GUI class EventInjector : public Mangle::Input::Event { MyGUI::Gui *gui; - int mouseX, mouseY; - int maxX, maxY; public: bool enabled; diff --git a/libs/openengine/ogre/renderer.cpp b/libs/openengine/ogre/renderer.cpp index 579ba3dd7c..7a01ffce71 100644 --- a/libs/openengine/ogre/renderer.cpp +++ b/libs/openengine/ogre/renderer.cpp @@ -145,14 +145,10 @@ void OgreRenderer::createScene(const std::string camName, float fov, float nearC mFader = new Fader(); } -Ogre::Viewport* OgreRenderer::recreateViewport() +void OgreRenderer::adjustViewport() { - mWindow->removeViewport(mView->getZOrder()); - mView = mWindow->addViewport(mCamera); - // Alter the camera aspect ratio to match the viewport mCamera->setAspectRatio(Real(mView->getActualWidth()) / Real(mView->getActualHeight())); - return mView; } void OgreRenderer::setWindowEventListener(Ogre::WindowEventListener* listener) diff --git a/libs/openengine/ogre/renderer.hpp b/libs/openengine/ogre/renderer.hpp index 7a0fd11df6..9d1d0122dd 100644 --- a/libs/openengine/ogre/renderer.hpp +++ b/libs/openengine/ogre/renderer.hpp @@ -157,7 +157,7 @@ namespace OEngine /// Viewport Ogre::Viewport *getViewport() { return mView; } - Ogre::Viewport* recreateViewport(); + void adjustViewport(); }; } } From 6014a900025cd45b13325c0d1f9d896e856defe5 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 28 May 2012 09:46:05 +0200 Subject: [PATCH 293/325] added tooltip delay option --- apps/openmw/mwgui/settingswindow.cpp | 6 ++++ apps/openmw/mwgui/settingswindow.hpp | 1 + apps/openmw/mwgui/tooltips.cpp | 30 +++++++++++++++++++ apps/openmw/mwgui/tooltips.hpp | 8 +++++ apps/openmw/mwgui/window_manager.cpp | 1 + files/mygui/openmw_settings_window_layout.xml | 15 ++++++++++ files/settings-default.cfg | 3 ++ 7 files changed, 64 insertions(+) diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index c8337d74c4..428e0e8622 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -37,6 +37,7 @@ namespace MWGui getWidget(mOkButton, "OkButton"); getWidget(mResolutionList, "ResolutionList"); getWidget(mMenuTransparencySlider, "MenuTransparencySlider"); + getWidget(mToolTipDelaySlider, "ToolTipDelaySlider"); getWidget(mViewDistanceSlider, "ViewDistanceSlider"); getWidget(mFullscreenButton, "FullscreenButton"); getWidget(mVSyncButton, "VSyncButton"); @@ -52,6 +53,7 @@ namespace MWGui mVSyncButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onButtonToggled); mFPSButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onFpsToggled); mMenuTransparencySlider->eventScrollChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onSliderChangePosition); + mToolTipDelaySlider->eventScrollChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onSliderChangePosition); mViewDistanceSlider->eventScrollChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onSliderChangePosition); mResolutionList->eventListChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onResolutionSelected); @@ -79,6 +81,8 @@ namespace MWGui // read settings int menu_transparency = (mMenuTransparencySlider->getScrollRange()-1) * Settings::Manager::getFloat("menu transparency", "GUI"); mMenuTransparencySlider->setScrollPosition(menu_transparency); + int tooltip_delay = (mToolTipDelaySlider->getScrollRange()-1) * Settings::Manager::getFloat("tooltip delay", "GUI"); + mToolTipDelaySlider->setScrollPosition(tooltip_delay); float val = (Settings::Manager::getFloat("max viewing distance", "Viewing distance")-2000)/(5600-2000); int viewdist = (mViewDistanceSlider->getScrollRange()-1) * val; @@ -170,6 +174,8 @@ namespace MWGui float val = pos / float(scroller->getScrollRange()-1); if (scroller == mMenuTransparencySlider) Settings::Manager::setFloat("menu transparency", "GUI", val); + else if (scroller == mToolTipDelaySlider) + Settings::Manager::setFloat("tooltip delay", "GUI", val); else if (scroller == mViewDistanceSlider) Settings::Manager::setFloat("max viewing distance", "Viewing distance", (1-val) * 2000 + val * 5600); else if (scroller == mMasterVolumeSlider) diff --git a/apps/openmw/mwgui/settingswindow.hpp b/apps/openmw/mwgui/settingswindow.hpp index 79af039945..09a93264d4 100644 --- a/apps/openmw/mwgui/settingswindow.hpp +++ b/apps/openmw/mwgui/settingswindow.hpp @@ -19,6 +19,7 @@ namespace MWGui MyGUI::Button* mOkButton; MyGUI::ScrollBar* mMenuTransparencySlider; + MyGUI::ScrollBar* mToolTipDelaySlider; // graphics MyGUI::ListBox* mResolutionList; diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index c6d8e2c8cc..bdce61a44f 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -8,6 +8,8 @@ #include +#include + using namespace MWGui; using namespace MyGUI; @@ -19,6 +21,10 @@ ToolTips::ToolTips(WindowManager* windowManager) : , mEnabled(true) , mFocusToolTipX(0.0) , mFocusToolTipY(0.0) + , mDelay(0.0) + , mRemainingDelay(0.0) + , mLastMouseX(0) + , mLastMouseY(0) { getWidget(mDynamicToolTipBox, "DynamicToolTipBox"); @@ -28,6 +34,9 @@ ToolTips::ToolTips(WindowManager* windowManager) : // even if the mouse is over the tooltip mDynamicToolTipBox->setNeedMouseFocus(false); mMainWidget->setNeedMouseFocus(false); + + mDelay = Settings::Manager::getFloat("tooltip delay", "GUI"); + mRemainingDelay = mDelay; } void ToolTips::setEnabled(bool enabled) @@ -57,6 +66,21 @@ void ToolTips::onFrame(float frameDuration) if (!mGameMode) { + const MyGUI::IntPoint& mousePos = InputManager::getInstance().getMousePosition(); + if (mousePos.left == mLastMouseX && mousePos.top == mLastMouseY) + { + mRemainingDelay -= frameDuration; + } + else + { + mRemainingDelay = mDelay; + } + mLastMouseX = mousePos.left; + mLastMouseY = mousePos.top; + + if (mRemainingDelay > 0) + return; + Widget* focus = InputManager::getInstance().getMouseFocusWidget(); if (focus == 0) { @@ -621,3 +645,9 @@ void ToolTips::createClassToolTip(MyGUI::Widget* widget, const ESM::Class& playe widget->setUserString("ToolTipType", "Layout"); widget->setUserString("ToolTipLayout", "ClassToolTip"); } + +void ToolTips::setDelay(float delay) +{ + mDelay = delay; + mRemainingDelay = mDelay; +} diff --git a/apps/openmw/mwgui/tooltips.hpp b/apps/openmw/mwgui/tooltips.hpp index 1925a4f148..036bdfaa34 100644 --- a/apps/openmw/mwgui/tooltips.hpp +++ b/apps/openmw/mwgui/tooltips.hpp @@ -41,6 +41,8 @@ namespace MWGui void toggleFullHelp(); ///< show extra info in item tooltips (owner, script) bool getFullHelp() const; + void setDelay(float delay); + void setFocusObject(const MWWorld::Ptr& focus); void setFocusObjectScreenCoords(float min_x, float min_y, float max_x, float max_y); ///< set the screen-space position of the tooltip for focused object @@ -84,6 +86,12 @@ namespace MWGui float mFocusToolTipX; float mFocusToolTipY; + float mDelay; + float mRemainingDelay; // remaining time until tooltip will show + + int mLastMouseX; + int mLastMouseY; + bool mGameMode; bool mEnabled; diff --git a/apps/openmw/mwgui/window_manager.cpp b/apps/openmw/mwgui/window_manager.cpp index 891f85ca2a..c3dc5d801c 100644 --- a/apps/openmw/mwgui/window_manager.cpp +++ b/apps/openmw/mwgui/window_manager.cpp @@ -605,6 +605,7 @@ void WindowManager::onRetrieveTag(const MyGUI::UString& _tag, MyGUI::UString& _r void WindowManager::processChangedSettings(const Settings::CategorySettingVector& changed) { hud->setFpsLevel(Settings::Manager::getInt("fps", "HUD")); + mToolTips->setDelay(Settings::Manager::getFloat("tooltip delay", "GUI")); bool changeRes = false; for (Settings::CategorySettingVector::const_iterator it = changed.begin(); diff --git a/files/mygui/openmw_settings_window_layout.xml b/files/mygui/openmw_settings_window_layout.xml index 9b5826765f..2e53c2a4a4 100644 --- a/files/mygui/openmw_settings_window_layout.xml +++ b/files/mygui/openmw_settings_window_layout.xml @@ -23,6 +23,21 @@ + + + + + + + + + + + + + + + diff --git a/files/settings-default.cfg b/files/settings-default.cfg index a6623656ca..883f32ae07 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -28,6 +28,9 @@ vsync = false # 1 is fully opaque menu transparency = 0.84 +# 0 - instantly, 1 - max. delay +tooltip delay = 0.2 + [General] # Camera field of view field of view = 55 From e1ee45a6d66f1eacfa7192d386ccfde42ef53761 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 28 May 2012 10:50:00 +0200 Subject: [PATCH 294/325] Issue #297: Make the stats review dialog show correct values for attributes/skills/health/magicka/fatigue --- apps/openmw/mwgui/charactercreation.cpp | 62 +++++++++++++++++++++++-- apps/openmw/mwgui/charactercreation.hpp | 8 ++-- apps/openmw/mwgui/class.cpp | 10 ++-- apps/openmw/mwgui/review.cpp | 3 ++ apps/openmw/mwgui/stats_window.cpp | 2 + apps/openmw/mwgui/window_manager.cpp | 4 ++ apps/openmw/mwgui/window_manager.hpp | 5 ++ 7 files changed, 81 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwgui/charactercreation.cpp b/apps/openmw/mwgui/charactercreation.cpp index 691fd4a917..cc74486465 100644 --- a/apps/openmw/mwgui/charactercreation.cpp +++ b/apps/openmw/mwgui/charactercreation.cpp @@ -122,6 +122,56 @@ CharacterCreation::CharacterCreation(WindowManager* _wm) mCreationStage = CSE_NotStarted; } +void CharacterCreation::setValue (const std::string& id, const MWMechanics::Stat& value) +{ + if (mReviewDialog) + { + static const char *ids[] = + { + "AttribVal1", "AttribVal2", "AttribVal3", "AttribVal4", "AttribVal5", + "AttribVal6", "AttribVal7", "AttribVal8", + 0 + }; + + for (int i=0; ids[i]; ++i) + { + if (ids[i]==id) + mReviewDialog->setAttribute(ESM::Attribute::AttributeID(i), value); + } + } +} + +void CharacterCreation::setValue (const std::string& id, const MWMechanics::DynamicStat& value) +{ + if (mReviewDialog) + { + if (id == "HBar") + { + mReviewDialog->setHealth (value); + } + else if (id == "MBar") + { + mReviewDialog->setMagicka (value); + } + else if (id == "FBar") + { + mReviewDialog->setFatigue (value); + } + } +} + +void CharacterCreation::setValue(const ESM::Skill::SkillEnum parSkill, const MWMechanics::Stat& value) +{ + if (mReviewDialog) + mReviewDialog->setSkillValue(parSkill, value); +} + +void CharacterCreation::configureSkills (const SkillList& major, const SkillList& minor) +{ + if (mReviewDialog) + mReviewDialog->configureSkills(major, minor); +} + void CharacterCreation::spawnDialog(const char id) { switch (id) @@ -208,20 +258,22 @@ void CharacterCreation::spawnDialog(const char id) mReviewDialog->setFatigue(mPlayerFatigue); { - std::map >::iterator end = mPlayerAttributes.end(); - for (std::map >::iterator it = mPlayerAttributes.begin(); it != end; ++it) + std::map > attributes = mWM->getPlayerAttributeValues(); + for (std::map >::iterator it = attributes.begin(); + it != attributes.end(); ++it) { mReviewDialog->setAttribute(it->first, it->second); } } { - std::map >::iterator end = mPlayerSkillValues.end(); - for (std::map >::iterator it = mPlayerSkillValues.begin(); it != end; ++it) + std::map > skills = mWM->getPlayerSkillValues(); + for (std::map >::iterator it = skills.begin(); + it != skills.end(); ++it) { mReviewDialog->setSkillValue(it->first, it->second); } - mReviewDialog->configureSkills(mPlayerMajorSkills, mPlayerMinorSkills); + mReviewDialog->configureSkills(mWM->getPlayerMajorSkills(), mWM->getPlayerMinorSkills()); } mReviewDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onReviewDialogDone); diff --git a/apps/openmw/mwgui/charactercreation.hpp b/apps/openmw/mwgui/charactercreation.hpp index dfb07853e3..02b48ffe23 100644 --- a/apps/openmw/mwgui/charactercreation.hpp +++ b/apps/openmw/mwgui/charactercreation.hpp @@ -42,6 +42,11 @@ namespace MWGui void setPlayerFatigue (const MWMechanics::DynamicStat& value); + void setValue (const std::string& id, const MWMechanics::Stat& value); + void setValue (const std::string& id, const MWMechanics::DynamicStat& value); + void setValue(const ESM::Skill::SkillEnum parSkill, const MWMechanics::Stat& value); + void configureSkills (const SkillList& major, const SkillList& minor); + private: //Dialogs TextInputDialog* mNameDialog; @@ -61,9 +66,6 @@ namespace MWGui std::string mPlayerRaceId; std::string mPlayerBirthSignId; ESM::Class mPlayerClass; - std::map > mPlayerAttributes; - SkillList mPlayerMajorSkills, mPlayerMinorSkills; - std::map > mPlayerSkillValues; MWMechanics::DynamicStat mPlayerHealth; MWMechanics::DynamicStat mPlayerMagicka; MWMechanics::DynamicStat mPlayerFatigue; diff --git a/apps/openmw/mwgui/class.cpp b/apps/openmw/mwgui/class.cpp index d3d261ab02..a7e5b86747 100644 --- a/apps/openmw/mwgui/class.cpp +++ b/apps/openmw/mwgui/class.cpp @@ -241,10 +241,10 @@ void PickClassDialog::updateStats() for (int i = 0; i < 5; ++i) { - majorSkill[i]->setSkillNumber(klass->data.skills[i][0]); - minorSkill[i]->setSkillNumber(klass->data.skills[i][1]); - ToolTips::createSkillToolTip(majorSkill[i], klass->data.skills[i][0]); - ToolTips::createSkillToolTip(minorSkill[i], klass->data.skills[i][1]); + minorSkill[i]->setSkillNumber(klass->data.skills[i][0]); + majorSkill[i]->setSkillNumber(klass->data.skills[i][1]); + ToolTips::createSkillToolTip(minorSkill[i], klass->data.skills[i][0]); + ToolTips::createSkillToolTip(majorSkill[i], klass->data.skills[i][1]); } classImage->setImageTexture(std::string("textures\\levelup\\") + currentClassId + ".dds"); @@ -518,7 +518,7 @@ std::vector CreateClassDialog::getMinorSkills() const std::vector v; for(int i=0; i < 5; i++) { - v.push_back(majorSkill[i]->getSkillId()); + v.push_back(minorSkill[i]->getSkillId()); } return v; } diff --git a/apps/openmw/mwgui/review.cpp b/apps/openmw/mwgui/review.cpp index be537e854e..67b6cc24ac 100644 --- a/apps/openmw/mwgui/review.cpp +++ b/apps/openmw/mwgui/review.cpp @@ -211,6 +211,7 @@ void ReviewDialog::setSkillValue(ESM::Skill::SkillEnum skillId, const MWMechanic widget->setCaption(text); widget->_setWidgetState(state); } + } void ReviewDialog::configureSkills(const std::vector& major, const std::vector& minor) @@ -230,6 +231,8 @@ void ReviewDialog::configureSkills(const std::vector& major, const std::vec if (skillSet.find(skill) == skillSet.end()) miscSkills.push_back(skill); } + + updateSkillArea(); } void ReviewDialog::addSeparator(MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) diff --git a/apps/openmw/mwgui/stats_window.cpp b/apps/openmw/mwgui/stats_window.cpp index 061800bf0c..75159f4dbd 100644 --- a/apps/openmw/mwgui/stats_window.cpp +++ b/apps/openmw/mwgui/stats_window.cpp @@ -255,6 +255,8 @@ void StatsWindow::configureSkills (const std::vector& major, const std::vec if (skillSet.find(skill) == skillSet.end()) miscSkills.push_back(skill); } + + updateSkillArea(); } void StatsWindow::onFrame () diff --git a/apps/openmw/mwgui/window_manager.cpp b/apps/openmw/mwgui/window_manager.cpp index c3dc5d801c..4e786978f3 100644 --- a/apps/openmw/mwgui/window_manager.cpp +++ b/apps/openmw/mwgui/window_manager.cpp @@ -302,6 +302,7 @@ void WindowManager::updateVisible() void WindowManager::setValue (const std::string& id, const MWMechanics::Stat& value) { mStatsWindow->setValue (id, value); + mCharGen->setValue(id, value); static const char *ids[] = { @@ -332,6 +333,7 @@ void WindowManager::setValue (const std::string& id, const MWMechanics::Stat& value) { mStatsWindow->setValue(parSkill, value); + mCharGen->setValue(parSkill, value); playerSkillValues[parSkill] = value; } @@ -339,6 +341,7 @@ void WindowManager::setValue (const std::string& id, const MWMechanics::DynamicS { mStatsWindow->setValue (id, value); hud->setValue (id, value); + mCharGen->setValue(id, value); if (id == "HBar") { playerHealth = value; @@ -391,6 +394,7 @@ void WindowManager::setPlayerClass (const ESM::Class &class_) void WindowManager::configureSkills (const SkillList& major, const SkillList& minor) { mStatsWindow->configureSkills (major, minor); + mCharGen->configureSkills(major, minor); playerMajorSkills = major; playerMinorSkills = minor; } diff --git a/apps/openmw/mwgui/window_manager.hpp b/apps/openmw/mwgui/window_manager.hpp index 7082cc0bc7..f3e6a436e3 100644 --- a/apps/openmw/mwgui/window_manager.hpp +++ b/apps/openmw/mwgui/window_manager.hpp @@ -211,6 +211,11 @@ namespace MWGui void onFrame (float frameDuration); + std::map > getPlayerSkillValues() { return playerSkillValues; } + std::map > getPlayerAttributeValues() { return playerAttributes; } + SkillList getPlayerMinorSkills() { return playerMinorSkills; } + SkillList getPlayerMajorSkills() { return playerMajorSkills; } + /** * Fetches a GMST string from the store, if there is no setting with the given * ID or it is not a string the default string is returned. From a54623bcd2a764e7622d282ea3a7117ab24cdfe2 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 28 May 2012 11:37:56 +0200 Subject: [PATCH 295/325] reset attributes when building player --- apps/openmw/mwmechanics/mechanicsmanager.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/apps/openmw/mwmechanics/mechanicsmanager.cpp b/apps/openmw/mwmechanics/mechanicsmanager.cpp index 0c48d88944..331074ef78 100644 --- a/apps/openmw/mwmechanics/mechanicsmanager.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanager.cpp @@ -30,6 +30,15 @@ namespace MWMechanics for (int i=0; i<27; ++i) npcStats.mSkill[i].setBase (player->npdt52.skills[i]); + creatureStats.mAttributes[0].setBase (player->npdt52.strength); + creatureStats.mAttributes[1].setBase (player->npdt52.intelligence); + creatureStats.mAttributes[2].setBase (player->npdt52.willpower); + creatureStats.mAttributes[3].setBase (player->npdt52.agility); + creatureStats.mAttributes[4].setBase (player->npdt52.speed); + creatureStats.mAttributes[5].setBase (player->npdt52.endurance); + creatureStats.mAttributes[6].setBase (player->npdt52.personality); + creatureStats.mAttributes[7].setBase (player->npdt52.luck); + // race if (mRaceSelected) { From 0a17d6d710731152d543f866d805a1eb7e58e609 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 28 May 2012 12:34:29 +0200 Subject: [PATCH 296/325] more resolution switching fixes --- apps/openmw/mwgui/confirmationdialog.cpp | 2 ++ apps/openmw/mwgui/confirmationdialog.hpp | 1 + apps/openmw/mwgui/hud.cpp | 4 ++- apps/openmw/mwgui/hud.hpp | 2 ++ apps/openmw/mwgui/settingswindow.cpp | 40 ++++++++++++++++++++++-- apps/openmw/mwgui/settingswindow.hpp | 1 + 6 files changed, 47 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwgui/confirmationdialog.cpp b/apps/openmw/mwgui/confirmationdialog.cpp index a54bdb1d8d..5e12c32964 100644 --- a/apps/openmw/mwgui/confirmationdialog.cpp +++ b/apps/openmw/mwgui/confirmationdialog.cpp @@ -50,6 +50,8 @@ namespace MWGui void ConfirmationDialog::onCancelButtonClicked(MyGUI::Widget* _sender) { + eventCancelClicked(); + close(); } diff --git a/apps/openmw/mwgui/confirmationdialog.hpp b/apps/openmw/mwgui/confirmationdialog.hpp index a20034171b..d278274a03 100644 --- a/apps/openmw/mwgui/confirmationdialog.hpp +++ b/apps/openmw/mwgui/confirmationdialog.hpp @@ -17,6 +17,7 @@ namespace MWGui signature : void method()\n */ EventHandle_Void eventOkClicked; + EventHandle_Void eventCancelClicked; private: MyGUI::EditBox* mMessage; diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index 31952e9931..7276218d6b 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -43,6 +43,7 @@ HUD::HUD(int width, int height, int fpsLevel, DragAndDrop* dragAndDrop) , mDragAndDrop(dragAndDrop) , mCellNameTimer(0.0f) , mCellNameBox(NULL) + , mMapVisible(true) { setCoord(0,0, width, height); @@ -234,6 +235,7 @@ void HUD::setBottomRightVisibility(bool effectBoxVisible, bool minimapBoxVisible if (!minimapBoxVisible) effectsDx = minimapBoxBaseRight - effectBoxBaseRight; + mMapVisible = minimapBoxVisible; minimapBox->setVisible(minimapBoxVisible); effectBox->setPosition(effectBoxBaseRight - effectBox->getWidth() + effectsDx, effectBox->getTop()); effectBox->setVisible(effectBoxVisible); @@ -337,7 +339,7 @@ void HUD::setCellName(const std::string& cellName) mCellName = cellName; mCellNameBox->setCaption(mCellName); - mCellNameBox->setVisible(true); + mCellNameBox->setVisible(mMapVisible); } } diff --git a/apps/openmw/mwgui/hud.hpp b/apps/openmw/mwgui/hud.hpp index 531dd70202..16749114c5 100644 --- a/apps/openmw/mwgui/hud.hpp +++ b/apps/openmw/mwgui/hud.hpp @@ -57,6 +57,8 @@ namespace MWGui std::string mCellName; float mCellNameTimer; + bool mMapVisible; + void onWorldClicked(MyGUI::Widget* _sender); void onWorldMouseOver(MyGUI::Widget* _sender, int x, int y); void onWorldMouseLostFocus(MyGUI::Widget* _sender, MyGUI::Widget* _new); diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index 428e0e8622..3f30516d90 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -113,6 +113,8 @@ namespace MWGui dialog->open("#{sNotifyMessage67}"); dialog->eventOkClicked.clear(); dialog->eventOkClicked += MyGUI::newDelegate(this, &SettingsWindow::onResolutionAccept); + dialog->eventCancelClicked.clear(); + dialog->eventCancelClicked += MyGUI::newDelegate(this, &SettingsWindow::onResolutionAccept); } void SettingsWindow::onResolutionAccept() @@ -130,6 +132,12 @@ namespace MWGui Settings::Manager::setInt("resolution y", "Video", resY); apply(); + mResolutionList->setIndexSelected(MyGUI::ITEM_NONE); + } + + void SettingsWindow::onResolutionCancel() + { + mResolutionList->setIndexSelected(MyGUI::ITEM_NONE); } void SettingsWindow::onButtonToggled(MyGUI::Widget* _sender) @@ -150,8 +158,36 @@ namespace MWGui if (_sender == mFullscreenButton) { - Settings::Manager::setBool("fullscreen", "Video", newState); - apply(); + // check if this resolution is supported in fullscreen + bool supported = false; + for (unsigned int i=0; igetItemCount(); ++i) + { + std::string resStr = mResolutionList->getItemNameAt(i); + size_t xPos = resStr.find("x"); + std::string resXStr = resStr.substr(0, xPos-1); + Ogre::StringUtil::trim(resXStr); + std::string resYStr = resStr.substr(xPos+2, resStr.size()-(xPos+2)); + Ogre::StringUtil::trim(resYStr); + int resX = boost::lexical_cast(resXStr); + int resY = boost::lexical_cast(resYStr); + + if (resX == Settings::Manager::getInt("resolution x", "Video") + && resY == Settings::Manager::getInt("resolution y", "Video")) + supported = true; + } + + if (!supported) + { + std::string msg = "This resolution is not supported in Fullscreen mode. Please select a resolution from the list."; + MWBase::Environment::get().getWindowManager()-> + messageBox(msg, std::vector()); + _sender->castType()->setCaption(off); + } + else + { + Settings::Manager::setBool("fullscreen", "Video", newState); + apply(); + } } else if (_sender == mVSyncButton) { diff --git a/apps/openmw/mwgui/settingswindow.hpp b/apps/openmw/mwgui/settingswindow.hpp index 09a93264d4..9079cff540 100644 --- a/apps/openmw/mwgui/settingswindow.hpp +++ b/apps/openmw/mwgui/settingswindow.hpp @@ -41,6 +41,7 @@ namespace MWGui void onButtonToggled(MyGUI::Widget* _sender); void onResolutionSelected(MyGUI::ListBox* _sender, size_t index); void onResolutionAccept(); + void onResolutionCancel(); void apply(); }; From f75266e4bae64ab53515614934a569aedb918e2f Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 29 May 2012 01:47:49 +0200 Subject: [PATCH 297/325] fixed race dialog bug --- apps/openmw/mwgui/charactercreation.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/charactercreation.cpp b/apps/openmw/mwgui/charactercreation.cpp index cc74486465..31696230cb 100644 --- a/apps/openmw/mwgui/charactercreation.cpp +++ b/apps/openmw/mwgui/charactercreation.cpp @@ -471,14 +471,14 @@ void CharacterCreation::onRaceDialogDone(WindowBase* parWindow) mWM->popGuiMode(); mWM->pushGuiMode(GM_Review); } - else if (mCreationStage >= CSE_NameChosen) + else if (mCreationStage >= CSE_RaceChosen) { mWM->popGuiMode(); mWM->pushGuiMode(GM_Class); } else { - mCreationStage = CSE_NameChosen; + mCreationStage = CSE_RaceChosen; mWM->popGuiMode(); } } From 8c7cb6909d937563247048e652946e3035a7fa8c Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 29 May 2012 01:59:16 +0200 Subject: [PATCH 298/325] addition to c7010623fb419f928fb369b5e93cbcfe39c0e0c8 : apparently talking _is_ allowed during the starting sequence, it is only disabled via scripts for certain actors --- apps/openmw/mwworld/actiontalk.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/apps/openmw/mwworld/actiontalk.cpp b/apps/openmw/mwworld/actiontalk.cpp index b3b6316533..a0f9d8c4c6 100644 --- a/apps/openmw/mwworld/actiontalk.cpp +++ b/apps/openmw/mwworld/actiontalk.cpp @@ -11,9 +11,6 @@ namespace MWWorld void ActionTalk::execute() { - if (!MWBase::Environment::get().getWindowManager()->isAllowed(MWGui::GW_Inventory)) - return; - MWBase::Environment::get().getDialogueManager()->startDialogue (mActor); } } From 6945afe95b8073b71719905fb3d7b4647c79052b Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 29 May 2012 02:57:19 +0200 Subject: [PATCH 299/325] alchemy window layout --- apps/openmw/mwgui/alchemywindow.cpp | 46 +++++++++++++++++++- files/mygui/openmw_alchemy_window_layout.xml | 40 ++++++++--------- 2 files changed, 64 insertions(+), 22 deletions(-) diff --git a/apps/openmw/mwgui/alchemywindow.cpp b/apps/openmw/mwgui/alchemywindow.cpp index 50d2095241..9c26bfabe4 100644 --- a/apps/openmw/mwgui/alchemywindow.cpp +++ b/apps/openmw/mwgui/alchemywindow.cpp @@ -128,6 +128,7 @@ namespace MWGui { ESM::ENAMstruct effect; effect.effectID = mEffects[i].mEffectID; + effect.area = 0; effect.range = ESM::RT_Self; effect.skill = mEffects[i].mSkill; effect.attribute = mEffects[i].mAttribute; @@ -167,10 +168,51 @@ namespace MWGui int random = rand() % names.size(); newPotion.model = "m\\misc_potion_" + names[random ] + "_01.nif"; newPotion.icon = "m\\tx_potion_" + names[random ] + "_01.dds"; - std::pair result = MWBase::Environment::get().getWorld()->createRecord(newPotion); + + // check if a similiar potion record exists already + bool found = false; + std::string objectId; + typedef std::map PotionMap; + PotionMap potions = MWBase::Environment::get().getWorld()->getStore().potions.list; + for (PotionMap::const_iterator it = potions.begin(); it != potions.end(); ++it) + { + if (found) break; + + if (it->second.data.value == newPotion.data.value + && it->second.data.weight == newPotion.data.weight + && it->second.name == newPotion.name + && it->second.effects.list.size() == newPotion.effects.list.size()) + { + // check effects + for (unsigned int i=0; i < it->second.effects.list.size(); ++i) + { + const ESM::ENAMstruct& a = it->second.effects.list[i]; + const ESM::ENAMstruct& b = newPotion.effects.list[i]; + if (a.effectID == b.effectID + && a.area == b.area + && a.range == b.range + && a.skill == b.skill + && a.attribute == b.attribute + && a.magnMin == b.magnMin + && a.magnMax == b.magnMax + && a.duration == b.duration) + { + found = true; + objectId = it->first; + break; + } + } + } + } + + if (!found) + { + std::pair result = MWBase::Environment::get().getWorld()->createRecord(newPotion); + objectId = result.first; + } // create a reference and add it to player inventory - MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), result.first); + MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), objectId); MWWorld::ContainerStore& store = MWWorld::Class::get(mPtr).getContainerStore(mPtr); ref.getPtr().getRefData().setCount(1); store.add(ref.getPtr()); diff --git a/files/mygui/openmw_alchemy_window_layout.xml b/files/mygui/openmw_alchemy_window_layout.xml index 8eb5e12656..2590f9db28 100644 --- a/files/mygui/openmw_alchemy_window_layout.xml +++ b/files/mygui/openmw_alchemy_window_layout.xml @@ -1,7 +1,7 @@ - + @@ -10,73 +10,73 @@ - + - + - + - + - + - + - + - + - + - + - + - + - - + + - + - + - - + + - + From 5d03e866131372be578e5898b6b1d3bf63d2c7ea Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 29 May 2012 04:54:54 +0200 Subject: [PATCH 300/325] added field of view and texture filtering to settings window --- apps/openmw/mwgui/settingswindow.cpp | 69 ++++++++++++++++++- apps/openmw/mwgui/settingswindow.hpp | 12 ++++ apps/openmw/mwrender/renderingmanager.cpp | 15 ++++ files/mygui/openmw_alchemy_window_layout.xml | 4 +- files/mygui/openmw_settings_window_layout.xml | 33 ++++++++- libs/openengine/gui/events.cpp | 19 +++-- libs/openengine/gui/events.hpp | 3 + libs/openengine/ogre/renderer.cpp | 5 ++ libs/openengine/ogre/renderer.hpp | 2 + 9 files changed, 151 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index 3f30516d90..82c8b554fd 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -27,6 +27,18 @@ namespace else return "Detailed"; } + + std::string textureFilteringToStr(const std::string& val) + { + if (val == "none") + return "None"; + else if (val == "anisotropic") + return "Anisotropic"; + else if (val == "bilinear") + return "Bilinear"; + else + return "Trilinear"; + } } namespace MWGui @@ -42,20 +54,28 @@ namespace MWGui getWidget(mFullscreenButton, "FullscreenButton"); getWidget(mVSyncButton, "VSyncButton"); getWidget(mFPSButton, "FPSButton"); + getWidget(mFOVSlider, "FOVSlider"); getWidget(mMasterVolumeSlider, "MasterVolume"); getWidget(mVoiceVolumeSlider, "VoiceVolume"); getWidget(mEffectsVolumeSlider, "EffectsVolume"); getWidget(mFootstepsVolumeSlider, "FootstepsVolume"); getWidget(mMusicVolumeSlider, "MusicVolume"); + getWidget(mAnisotropySlider, "AnisotropySlider"); + getWidget(mTextureFilteringButton, "TextureFilteringButton"); + getWidget(mAnisotropyLabel, "AnisotropyLabel"); + getWidget(mAnisotropyBox, "AnisotropyBox"); mOkButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onOkButtonClicked); mFullscreenButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onButtonToggled); + mTextureFilteringButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onTextureFilteringToggled); mVSyncButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onButtonToggled); mFPSButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onFpsToggled); mMenuTransparencySlider->eventScrollChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onSliderChangePosition); + mFOVSlider->eventScrollChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onSliderChangePosition); mToolTipDelaySlider->eventScrollChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onSliderChangePosition); mViewDistanceSlider->eventScrollChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onSliderChangePosition); mResolutionList->eventListChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onResolutionSelected); + mAnisotropySlider->eventScrollChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onSliderChangePosition); mMasterVolumeSlider->eventScrollChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onSliderChangePosition); mVoiceVolumeSlider->eventScrollChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onSliderChangePosition); @@ -84,7 +104,20 @@ namespace MWGui int tooltip_delay = (mToolTipDelaySlider->getScrollRange()-1) * Settings::Manager::getFloat("tooltip delay", "GUI"); mToolTipDelaySlider->setScrollPosition(tooltip_delay); - float val = (Settings::Manager::getFloat("max viewing distance", "Viewing distance")-2000)/(5600-2000); + float fovVal = (Settings::Manager::getFloat("field of view", "General")-sFovMin)/(sFovMax-sFovMin); + mFOVSlider->setScrollPosition(fovVal * (mFOVSlider->getScrollRange()-1)); + MyGUI::TextBox* fovText; + getWidget(fovText, "FovText"); + fovText->setCaption("Field of View (" + boost::lexical_cast(int(Settings::Manager::getFloat("field of view", "General"))) + ")"); + + float anisotropyVal = Settings::Manager::getInt("anisotropy", "General") / 16.0; + mAnisotropySlider->setScrollPosition(anisotropyVal * (mAnisotropySlider->getScrollRange()-1)); + std::string tf = Settings::Manager::getString("texture filtering", "General"); + mTextureFilteringButton->setCaption(textureFilteringToStr(tf)); + mAnisotropyLabel->setCaption("Anisotropy (" + boost::lexical_cast(Settings::Manager::getInt("anisotropy", "General")) + ")"); + mAnisotropyBox->setVisible(tf == "anisotropic"); + + float val = (Settings::Manager::getFloat("max viewing distance", "Viewing distance")-sViewDistMin)/(sViewDistMax-sViewDistMin); int viewdist = (mViewDistanceSlider->getScrollRange()-1) * val; mViewDistanceSlider->setScrollPosition(viewdist); @@ -205,6 +238,26 @@ namespace MWGui apply(); } + void SettingsWindow::onTextureFilteringToggled(MyGUI::Widget* _sender) + { + std::string current = Settings::Manager::getString("texture filtering", "General"); + std::string next; + if (current == "none") + next = "bilinear"; + else if (current == "bilinear") + next = "trilinear"; + else if (current == "trilinear") + next = "anisotropic"; + else + next = "none"; + + mTextureFilteringButton->setCaption(textureFilteringToStr(next)); + mAnisotropyBox->setVisible(next == "anisotropic"); + + Settings::Manager::setString("texture filtering", "General", next); + apply(); + } + void SettingsWindow::onSliderChangePosition(MyGUI::ScrollBar* scroller, size_t pos) { float val = pos / float(scroller->getScrollRange()-1); @@ -213,7 +266,19 @@ namespace MWGui else if (scroller == mToolTipDelaySlider) Settings::Manager::setFloat("tooltip delay", "GUI", val); else if (scroller == mViewDistanceSlider) - Settings::Manager::setFloat("max viewing distance", "Viewing distance", (1-val) * 2000 + val * 5600); + Settings::Manager::setFloat("max viewing distance", "Viewing distance", (1-val) * sViewDistMin + val * sViewDistMax); + else if (scroller == mFOVSlider) + { + MyGUI::TextBox* fovText; + getWidget(fovText, "FovText"); + fovText->setCaption("Field of View (" + boost::lexical_cast(int((1-val) * sFovMin + val * sFovMax)) + ")"); + Settings::Manager::setFloat("field of view", "General", (1-val) * sFovMin + val * sFovMax); + } + else if (scroller == mAnisotropySlider) + { + mAnisotropyLabel->setCaption("Anisotropy (" + boost::lexical_cast(int(val*16)) + ")"); + Settings::Manager::setInt("anisotropy", "General", val * 16); + } else if (scroller == mMasterVolumeSlider) Settings::Manager::setFloat("master volume", "Sound", val); else if (scroller == mVoiceVolumeSlider) diff --git a/apps/openmw/mwgui/settingswindow.hpp b/apps/openmw/mwgui/settingswindow.hpp index 9079cff540..8924375d92 100644 --- a/apps/openmw/mwgui/settingswindow.hpp +++ b/apps/openmw/mwgui/settingswindow.hpp @@ -15,6 +15,12 @@ namespace MWGui public: SettingsWindow(WindowManager& parWindowManager); + private: + static const float sFovMin = 30; + static const float sFovMax = 140; + static const float sViewDistMin = 2000; + static const float sViewDistMax = 5600; + protected: MyGUI::Button* mOkButton; @@ -27,6 +33,11 @@ namespace MWGui MyGUI::Button* mVSyncButton; MyGUI::Button* mFPSButton; MyGUI::ScrollBar* mViewDistanceSlider; + MyGUI::ScrollBar* mFOVSlider; + MyGUI::ScrollBar* mAnisotropySlider; + MyGUI::Button* mTextureFilteringButton; + MyGUI::TextBox* mAnisotropyLabel; + MyGUI::Widget* mAnisotropyBox; // audio MyGUI::ScrollBar* mMasterVolumeSlider; @@ -37,6 +48,7 @@ namespace MWGui void onOkButtonClicked(MyGUI::Widget* _sender); void onFpsToggled(MyGUI::Widget* _sender); + void onTextureFilteringToggled(MyGUI::Widget* _sender); void onSliderChangePosition(MyGUI::ScrollBar* scroller, size_t pos); void onButtonToggled(MyGUI::Widget* _sender); void onResolutionSelected(MyGUI::ListBox* _sender, size_t index); diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 46e274ff5d..89f42a5f1c 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -590,6 +590,21 @@ void RenderingManager::processChangedSettings(const Settings::CategorySettingVec || it->second == "resolution y" || it->second == "fullscreen")) changeRes = true; + else if (it->second == "field of view" && it->first == "General") + mRendering.setFov(Settings::Manager::getFloat("field of view", "General")); + else if ((it->second == "texture filtering" && it->first == "General") + || (it->second == "anisotropy" && it->first == "General")) + { + TextureFilterOptions tfo; + std::string filter = Settings::Manager::getString("texture filtering", "General"); + if (filter == "anisotropic") tfo = TFO_ANISOTROPIC; + else if (filter == "trilinear") tfo = TFO_TRILINEAR; + else if (filter == "bilinear") tfo = TFO_BILINEAR; + else if (filter == "none") tfo = TFO_NONE; + + MaterialManager::getSingleton().setDefaultTextureFiltering(tfo); + MaterialManager::getSingleton().setDefaultAnisotropy( (filter == "anisotropic") ? Settings::Manager::getInt("anisotropy", "General") : 1 ); + } } if (changeRes) diff --git a/files/mygui/openmw_alchemy_window_layout.xml b/files/mygui/openmw_alchemy_window_layout.xml index 2590f9db28..68df748b16 100644 --- a/files/mygui/openmw_alchemy_window_layout.xml +++ b/files/mygui/openmw_alchemy_window_layout.xml @@ -60,9 +60,9 @@ - + - + diff --git a/files/mygui/openmw_settings_window_layout.xml b/files/mygui/openmw_settings_window_layout.xml index 2e53c2a4a4..107e883c42 100644 --- a/files/mygui/openmw_settings_window_layout.xml +++ b/files/mygui/openmw_settings_window_layout.xml @@ -100,15 +100,44 @@ - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/libs/openengine/gui/events.cpp b/libs/openengine/gui/events.cpp index a19c247c25..bce70704b0 100644 --- a/libs/openengine/gui/events.cpp +++ b/libs/openengine/gui/events.cpp @@ -9,8 +9,13 @@ using namespace OEngine::GUI; EventInjector::EventInjector(MyGUI::Gui *g) : gui(g), enabled(true) + , mMouseX(0) + , mMouseY(0) { assert(gui); + const MyGUI::IntSize& viewSize = MyGUI::RenderManager::getInstance().getViewSize(); + mMouseX = viewSize.width/2; + mMouseY = viewSize.height/2; } void EventInjector::event(Type type, int index, const void *p) @@ -54,15 +59,19 @@ void EventInjector::event(Type type, int index, const void *p) MouseEvent *mouse = (MouseEvent*)p; MyGUI::MouseButton id = MyGUI::MouseButton::Enum(index); + const MyGUI::IntSize& viewSize = MyGUI::RenderManager::getInstance().getViewSize(); + // Update mouse position - int mouseX = mouse->state.X.abs; - int mouseY = mouse->state.Y.abs; + mMouseX += mouse->state.X.rel; + mMouseY += mouse->state.Y.rel; + mMouseX = std::max(0, std::min(mMouseX, viewSize.width)); + mMouseY = std::max(0, std::min(mMouseY, viewSize.height)); if(type == EV_MouseDown) - MyGUI::InputManager::getInstance().injectMousePress(mouseX, mouseY, id); + MyGUI::InputManager::getInstance().injectMousePress(mMouseX, mMouseY, id); else if(type == EV_MouseUp) - MyGUI::InputManager::getInstance().injectMouseRelease(mouseX, mouseY, id); + MyGUI::InputManager::getInstance().injectMouseRelease(mMouseX, mMouseY, id); else - MyGUI::InputManager::getInstance().injectMouseMove(mouseX, mouseY, mouse->state.Z.abs); + MyGUI::InputManager::getInstance().injectMouseMove(mMouseX, mMouseY, mouse->state.Z.abs); } } diff --git a/libs/openengine/gui/events.hpp b/libs/openengine/gui/events.hpp index 1f506cffad..10c5309bc3 100644 --- a/libs/openengine/gui/events.hpp +++ b/libs/openengine/gui/events.hpp @@ -17,6 +17,9 @@ namespace GUI { MyGUI::Gui *gui; + int mMouseX; + int mMouseY; + public: bool enabled; diff --git a/libs/openengine/ogre/renderer.cpp b/libs/openengine/ogre/renderer.cpp index 7a01ffce71..b525e76e38 100644 --- a/libs/openengine/ogre/renderer.cpp +++ b/libs/openengine/ogre/renderer.cpp @@ -155,3 +155,8 @@ void OgreRenderer::setWindowEventListener(Ogre::WindowEventListener* listener) { Ogre::WindowEventUtilities::addWindowEventListener(mWindow, listener); } + +void OgreRenderer::setFov(float fov) +{ + mCamera->setFOVy(Degree(fov)); +} diff --git a/libs/openengine/ogre/renderer.hpp b/libs/openengine/ogre/renderer.hpp index 9d1d0122dd..f4ea8fbc85 100644 --- a/libs/openengine/ogre/renderer.hpp +++ b/libs/openengine/ogre/renderer.hpp @@ -124,6 +124,8 @@ namespace OEngine float nearClip=5 // Near clip distance ); + void setFov(float fov); + /// Kill the renderer. void cleanup(); From 69e6bc6588256be514f9dbc054fd8795a20583c7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 29 May 2012 06:45:44 +0200 Subject: [PATCH 301/325] add water settings to settings window --- apps/openmw/mwgui/settingswindow.cpp | 38 +++++ apps/openmw/mwgui/settingswindow.hpp | 4 + apps/openmw/mwrender/compositors.cpp | 7 + apps/openmw/mwrender/compositors.hpp | 2 + apps/openmw/mwrender/renderingmanager.cpp | 52 +++++-- apps/openmw/mwrender/renderingmanager.hpp | 4 + apps/openmw/mwrender/water.cpp | 134 +++++++++++++----- apps/openmw/mwrender/water.hpp | 8 ++ files/mygui/openmw_settings_window_layout.xml | 28 ++++ files/water/water.material | 25 ++++ 10 files changed, 252 insertions(+), 50 deletions(-) diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index 82c8b554fd..67ccf9d531 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -64,9 +64,17 @@ namespace MWGui getWidget(mTextureFilteringButton, "TextureFilteringButton"); getWidget(mAnisotropyLabel, "AnisotropyLabel"); getWidget(mAnisotropyBox, "AnisotropyBox"); + getWidget(mWaterShaderButton, "WaterShaderButton"); + getWidget(mReflectObjectsButton, "ReflectObjectsButton"); + getWidget(mReflectActorsButton, "ReflectActorsButton"); + getWidget(mReflectTerrainButton, "ReflectTerrainButton"); mOkButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onOkButtonClicked); mFullscreenButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onButtonToggled); + mWaterShaderButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onButtonToggled); + mReflectObjectsButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onButtonToggled); + mReflectTerrainButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onButtonToggled); + mReflectActorsButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onButtonToggled); mTextureFilteringButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onTextureFilteringToggled); mVSyncButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onButtonToggled); mFPSButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onFpsToggled); @@ -127,6 +135,19 @@ namespace MWGui mFootstepsVolumeSlider->setScrollPosition(Settings::Manager::getFloat("footsteps volume", "Sound") * (mFootstepsVolumeSlider->getScrollRange()-1)); mVoiceVolumeSlider->setScrollPosition(Settings::Manager::getFloat("voice volume", "Sound") * (mVoiceVolumeSlider->getScrollRange()-1)); + mWaterShaderButton->setCaptionWithReplacing(Settings::Manager::getBool("shader", "Water") ? "#{sOn}" : "#{sOff}"); + mReflectObjectsButton->setCaptionWithReplacing(Settings::Manager::getBool("reflect objects", "Water") ? "#{sOn}" : "#{sOff}"); + mReflectActorsButton->setCaptionWithReplacing(Settings::Manager::getBool("reflect actors", "Water") ? "#{sOn}" : "#{sOff}"); + mReflectTerrainButton->setCaptionWithReplacing(Settings::Manager::getBool("reflect terrain", "Water") ? "#{sOn}" : "#{sOff}"); + + if (!MWRender::RenderingManager::waterShaderSupported()) + { + mWaterShaderButton->setEnabled(false); + mReflectObjectsButton->setEnabled(false); + mReflectActorsButton->setEnabled(false); + mReflectTerrainButton->setEnabled(false); + } + mFullscreenButton->setCaptionWithReplacing(Settings::Manager::getBool("fullscreen", "Video") ? "#{sOn}" : "#{sOff}"); mVSyncButton->setCaptionWithReplacing(Settings::Manager::getBool("vsync", "Video") ? "#{sOn}": "#{sOff}"); mFPSButton->setCaptionWithReplacing(fpsLevelToStr(Settings::Manager::getInt("fps", "HUD"))); @@ -228,6 +249,23 @@ namespace MWGui MWBase::Environment::get().getWindowManager()-> messageBox("VSync will be applied after a restart", std::vector()); } + else + { + if (_sender == mWaterShaderButton) + Settings::Manager::setBool("shader", "Water", newState); + else if (_sender == mReflectObjectsButton) + { + Settings::Manager::setBool("reflect misc", "Water", newState); + Settings::Manager::setBool("reflect statics", "Water", newState); + Settings::Manager::setBool("reflect statics small", "Water", newState); + } + else if (_sender == mReflectActorsButton) + Settings::Manager::setBool("reflect actors", "Water", newState); + else if (_sender == mReflectTerrainButton) + Settings::Manager::setBool("reflect terrain", "Water", newState); + + apply(); + } } void SettingsWindow::onFpsToggled(MyGUI::Widget* _sender) diff --git a/apps/openmw/mwgui/settingswindow.hpp b/apps/openmw/mwgui/settingswindow.hpp index 8924375d92..ce95edbd2e 100644 --- a/apps/openmw/mwgui/settingswindow.hpp +++ b/apps/openmw/mwgui/settingswindow.hpp @@ -38,6 +38,10 @@ namespace MWGui MyGUI::Button* mTextureFilteringButton; MyGUI::TextBox* mAnisotropyLabel; MyGUI::Widget* mAnisotropyBox; + MyGUI::Button* mWaterShaderButton; + MyGUI::Button* mReflectObjectsButton; + MyGUI::Button* mReflectActorsButton; + MyGUI::Button* mReflectTerrainButton; // audio MyGUI::ScrollBar* mMasterVolumeSlider; diff --git a/apps/openmw/mwrender/compositors.cpp b/apps/openmw/mwrender/compositors.cpp index d786c263b1..6f97269ab7 100644 --- a/apps/openmw/mwrender/compositors.cpp +++ b/apps/openmw/mwrender/compositors.cpp @@ -62,3 +62,10 @@ void Compositors::setCompositorEnabled (const std::string& name, const bool enab mCompositors[name].first = enabled; Ogre::CompositorManager::getSingleton().setCompositorEnabled (mViewport, name, enabled && mEnabled); } + +void Compositors::removeAll() +{ + Ogre::CompositorManager::getSingleton().removeCompositorChain(mViewport); + + mCompositors.clear(); +} diff --git a/apps/openmw/mwrender/compositors.hpp b/apps/openmw/mwrender/compositors.hpp index f249ece420..bbd838b8ee 100644 --- a/apps/openmw/mwrender/compositors.hpp +++ b/apps/openmw/mwrender/compositors.hpp @@ -44,6 +44,8 @@ namespace MWRender */ void addCompositor (const std::string& name, const int priority); + void removeAll (); + protected: /// maps compositor name to its "enabled" state CompositorMap mCompositors; diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 89f42a5f1c..a6f10fcd28 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -67,25 +67,13 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const // disable unsupported effects const RenderSystemCapabilities* caps = Root::getSingleton().getRenderSystem()->getCapabilities(); - if (caps->getNumMultiRenderTargets() < 2 || !Settings::Manager::getBool("shaders", "Objects")) + if (!waterShaderSupported()) Settings::Manager::setBool("shader", "Water", false); if ( !(caps->isShaderProfileSupported("fp40") || caps->isShaderProfileSupported("ps_4_0")) || !Settings::Manager::getBool("shaders", "Objects")) Settings::Manager::setBool("enabled", "Shadows", false); - // note that the order is important here - if (useMRT()) - { - mCompositors->addCompositor("gbuffer", 0); - mCompositors->setCompositorEnabled("gbuffer", true); - mCompositors->addCompositor("Underwater", 1); - mCompositors->addCompositor("gbufferFinalizer", 2); - mCompositors->setCompositorEnabled("gbufferFinalizer", true); - } - else - { - mCompositors->addCompositor("UnderwaterNoMRT", 0); - } + applyCompositors(); // Turn the entire scene (represented by the 'root' node) -90 // degrees around the x axis. This makes Z go upwards, and Y go into @@ -605,6 +593,11 @@ void RenderingManager::processChangedSettings(const Settings::CategorySettingVec MaterialManager::getSingleton().setDefaultTextureFiltering(tfo); MaterialManager::getSingleton().setDefaultAnisotropy( (filter == "anisotropic") ? Settings::Manager::getInt("anisotropy", "General") : 1 ); } + else if (it->second == "shader" && it->first == "Water") + { + applyCompositors(); + mShaderHelper->applyShaders(); + } } if (changeRes) @@ -618,6 +611,9 @@ void RenderingManager::processChangedSettings(const Settings::CategorySettingVec } mRendering.getWindow()->setFullscreen(Settings::Manager::getBool("fullscreen", "Video"), x, y); } + + if (mWater) + mWater->processChangedSettings(settings); } void RenderingManager::setMenuTransparency(float val) @@ -649,4 +645,32 @@ void RenderingManager::windowClosed(Ogre::RenderWindow* rw) { } +bool RenderingManager::waterShaderSupported() +{ + const RenderSystemCapabilities* caps = Root::getSingleton().getRenderSystem()->getCapabilities(); + if (caps->getNumMultiRenderTargets() < 2 || !Settings::Manager::getBool("shaders", "Objects")) + return false; + return true; +} + +void RenderingManager::applyCompositors() +{ + mCompositors->removeAll(); + if (useMRT()) + { + mCompositors->addCompositor("gbuffer", 0); + mCompositors->setCompositorEnabled("gbuffer", true); + mCompositors->addCompositor("Underwater", 1); + mCompositors->addCompositor("gbufferFinalizer", 2); + mCompositors->setCompositorEnabled("gbufferFinalizer", true); + } + else + { + mCompositors->addCompositor("UnderwaterNoMRT", 0); + } + + if (mWater) + mWater->assignTextures(); +} + } // namespace diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 562184c62e..642c42930c 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -165,6 +165,8 @@ class RenderingManager: private RenderingInterface, public Ogre::WindowEventList Ogre::Viewport* getViewport() { return mRendering.getViewport(); } + static bool waterShaderSupported(); + protected: virtual void windowResized(Ogre::RenderWindow* rw); virtual void windowClosed(Ogre::RenderWindow* rw); @@ -175,6 +177,8 @@ class RenderingManager: private RenderingInterface, public Ogre::WindowEventList void setMenuTransparency(float val); + void applyCompositors(); + bool mSunEnabled; SkyManager* mSkyManager; diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 981343e919..b4486a0cac 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -1,5 +1,5 @@ #include "water.hpp" -#include + #include "sky.hpp" #include "renderingmanager.hpp" #include "compositors.hpp" @@ -30,13 +30,6 @@ Water::Water (Ogre::Camera *camera, RenderingManager* rend, const ESM::Cell* cel mWater->setRenderQueueGroup(RQG_Water); mWater->setCastShadows(false); - mVisibilityFlags = RV_Terrain * Settings::Manager::getBool("reflect terrain", "Water") - + RV_Statics * Settings::Manager::getBool("reflect statics", "Water") - + RV_StaticsSmall * Settings::Manager::getBool("reflect small statics", "Water") - + RV_Actors * Settings::Manager::getBool("reflect actors", "Water") - + RV_Misc * Settings::Manager::getBool("reflect misc", "Water") - + RV_Sky; - mWaterNode = mSceneManager->getRootSceneNode()->createChildSceneNode(); mWaterNode->setPosition(0, mTop, 0); @@ -48,30 +41,9 @@ Water::Water (Ogre::Camera *camera, RenderingManager* rend, const ESM::Cell* cel } mWaterNode->attachObject(mWater); - // Create rendertarget for reflection - int rttsize = Settings::Manager::getInt("rtt size", "Water"); + applyRTT(); + applyVisibilityMask(); - TexturePtr tex; - if (Settings::Manager::getBool("shader", "Water")) - { - tex = TextureManager::getSingleton().createManual("WaterReflection", - ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, TEX_TYPE_2D, rttsize, rttsize, 0, PF_FLOAT16_RGBA, TU_RENDERTARGET); - - RenderTarget* rtt = tex->getBuffer()->getRenderTarget(); - Viewport* vp = rtt->addViewport(mReflectionCamera); - vp->setOverlaysEnabled(false); - vp->setBackgroundColour(ColourValue(0.8f, 0.9f, 1.0f)); - vp->setShadowsEnabled(false); - vp->setVisibilityMask( mVisibilityFlags ); - // use fallback techniques without shadows and without mrt (currently not implemented for sky and terrain) - //vp->setMaterialScheme("Fallback"); - rtt->addListener(this); - rtt->setActive(true); - - mReflectionTarget = rtt; - } - - mCompositorName = RenderingManager::useMRT() ? "Underwater" : "UnderwaterNoMRT"; createMaterial(); mWater->setMaterial(mMaterial); @@ -251,7 +223,15 @@ void Water::postRenderTargetUpdate(const RenderTargetEvent& evt) void Water::createMaterial() { - mMaterial = MaterialManager::getSingleton().getByName("Water"); + if (mReflectionTarget == 0) + { + mMaterial = MaterialManager::getSingleton().getByName("Water_Fallback"); + } + else + { + mMaterial = MaterialManager::getSingleton().getByName("Water"); + mMaterial->getTechnique(0)->getPass(0)->getTextureUnitState(0)->setTexture(mReflectionTexture); + } // these have to be set in code std::string textureNames[32]; @@ -259,11 +239,13 @@ void Water::createMaterial() { textureNames[i] = "textures\\water\\water" + StringConverter::toString(i, 2, '0') + ".dds"; } - mMaterial->getTechnique(1)->getPass(0)->getTextureUnitState(0)->setAnimatedTextureName(textureNames, 32, 2); - - // use technique without shaders if reflection is disabled + Ogre::Technique* tech; if (mReflectionTarget == 0) - mMaterial->removeTechnique(0); + tech = mMaterial->getTechnique(0); + else + tech = mMaterial->getTechnique(1); + + tech->getPass(0)->getTextureUnitState(0)->setAnimatedTextureName(textureNames, 32, 2); } void Water::assignTextures() @@ -320,4 +302,84 @@ void Water::update() { } +void Water::applyRTT() +{ + if (mReflectionTarget) + { + TextureManager::getSingleton().remove("WaterReflection"); + mReflectionTarget = 0; + } + + // Create rendertarget for reflection + int rttsize = Settings::Manager::getInt("rtt size", "Water"); + + if (Settings::Manager::getBool("shader", "Water")) + { + mReflectionTexture = TextureManager::getSingleton().createManual("WaterReflection", + ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, TEX_TYPE_2D, rttsize, rttsize, 0, PF_FLOAT16_RGBA, TU_RENDERTARGET); + + RenderTarget* rtt = mReflectionTexture->getBuffer()->getRenderTarget(); + Viewport* vp = rtt->addViewport(mReflectionCamera); + vp->setOverlaysEnabled(false); + vp->setBackgroundColour(ColourValue(0.8f, 0.9f, 1.0f)); + vp->setShadowsEnabled(false); + // use fallback techniques without shadows and without mrt (currently not implemented for sky and terrain) + //vp->setMaterialScheme("Fallback"); + rtt->addListener(this); + rtt->setActive(true); + + mReflectionTarget = rtt; + } + + mCompositorName = RenderingManager::useMRT() ? "Underwater" : "UnderwaterNoMRT"; +} + +void Water::applyVisibilityMask() +{ + mVisibilityFlags = RV_Terrain * Settings::Manager::getBool("reflect terrain", "Water") + + RV_Statics * Settings::Manager::getBool("reflect statics", "Water") + + RV_StaticsSmall * Settings::Manager::getBool("reflect small statics", "Water") + + RV_Actors * Settings::Manager::getBool("reflect actors", "Water") + + RV_Misc * Settings::Manager::getBool("reflect misc", "Water") + + RV_Sky; + + if (mReflectionTarget) + { + mReflectionTexture->getBuffer()->getRenderTarget()->getViewport(0)->setVisibilityMask(mVisibilityFlags); + } +} + +void Water::processChangedSettings(const Settings::CategorySettingVector& settings) +{ + bool applyRT = false; + bool applyVisMask = false; + for (Settings::CategorySettingVector::const_iterator it=settings.begin(); + it != settings.end(); ++it) + { + if ( it->first == "Water" && ( + it->second == "shader" + || it->second == "rtt size")) + applyRT = true; + + if ( it->first == "Water" && ( + it->second == "reflect actors" + || it->second == "reflect terrain" + || it->second == "reflect misc" + || it->second == "reflect small statics" + || it->second == "reflect statics")) + applyVisMask = true; + } + + if(applyRT) + { + applyRTT(); + applyVisibilityMask(); + createMaterial(); + mWater->setMaterial(mMaterial); + assignTextures(); + } + if (applyVisMask) + applyVisibilityMask(); +} + } // namespace diff --git a/apps/openmw/mwrender/water.hpp b/apps/openmw/mwrender/water.hpp index edd217e842..4d617ea472 100644 --- a/apps/openmw/mwrender/water.hpp +++ b/apps/openmw/mwrender/water.hpp @@ -3,9 +3,11 @@ #include #include +#include #include "renderconst.hpp" + namespace MWRender { class SkyManager; @@ -38,6 +40,9 @@ namespace MWRender { void renderQueueStarted (Ogre::uint8 queueGroupId, const Ogre::String &invocation, bool &skipThisInvocation); void renderQueueEnded (Ogre::uint8 queueGroupId, const Ogre::String &invocation, bool &repeatThisInvocation); + void applyRTT(); + void applyVisibilityMask(); + void updateVisible(); RenderingManager* mRendering; @@ -50,6 +55,7 @@ namespace MWRender { Ogre::Camera* mReflectionCamera; + Ogre::TexturePtr mReflectionTexture; Ogre::RenderTarget* mReflectionTarget; bool mUnderwaterEffect; @@ -68,6 +74,8 @@ namespace MWRender { void setViewportBackground(const Ogre::ColourValue& bg); + void processChangedSettings(const Settings::CategorySettingVector& settings); + void checkUnderwater(float y); void changeCell(const ESM::Cell* cell); void setHeight(const float height); diff --git a/files/mygui/openmw_settings_window_layout.xml b/files/mygui/openmw_settings_window_layout.xml index 107e883c42..7c508b1e97 100644 --- a/files/mygui/openmw_settings_window_layout.xml +++ b/files/mygui/openmw_settings_window_layout.xml @@ -153,6 +153,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/water/water.material b/files/water/water.material index 8b4ff96f56..a2a6b3e2dc 100644 --- a/files/water/water.material +++ b/files/water/water.material @@ -90,6 +90,31 @@ material Water } } } + + technique + { + scheme Fallback + pass + { + cull_hardware none + scene_blend alpha_blend + depth_write off + diffuse 0 0 0 1 + emissive 0.6 0.7 1.0 + ambient 0 0 0 + texture_unit + { + // texture names set via code + scale 0.1 0.1 + alpha_op_ex source1 src_manual src_current 0.7 + } + } + } + +} + +material Water_Fallback +{ technique { scheme Fallback From c7268233df07351dc7c06251bac1158c64fce23d Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 29 May 2012 09:02:22 +0200 Subject: [PATCH 302/325] spell window layout & opening/closing/pinning logic --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwgui/inventorywindow.cpp | 2 +- apps/openmw/mwgui/spellwindow.cpp | 20 ++++++++++++++++++++ apps/openmw/mwgui/spellwindow.hpp | 21 +++++++++++++++++++++ apps/openmw/mwgui/window_manager.cpp | 14 ++++++++++---- apps/openmw/mwgui/window_manager.hpp | 2 ++ files/mygui/CMakeLists.txt | 1 + files/mygui/openmw_spell_window_layout.xml | 19 +++++++++++++++++++ 8 files changed, 75 insertions(+), 6 deletions(-) create mode 100644 apps/openmw/mwgui/spellwindow.cpp create mode 100644 apps/openmw/mwgui/spellwindow.hpp create mode 100644 files/mygui/openmw_spell_window_layout.xml diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index edbeab0a1a..045f504a74 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -28,7 +28,7 @@ add_openmw_dir (mwgui dialogue_history window_base stats_window messagebox journalwindow charactercreation map_window window_pinnable_base cursorreplace tooltips scrollwindow bookwindow list formatting inventorywindow container hud countdialog tradewindow settingswindow - confirmationdialog alchemywindow referenceinterface + confirmationdialog alchemywindow referenceinterface spellwindow ) add_openmw_dir (mwdialogue diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 2b224ab2cc..1a715657a7 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -91,7 +91,7 @@ namespace MWGui mFilterAll->setStateSelected(true); - setCoord(0, 342, 600, 258); + setCoord(0, 342, 498, 258); MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); openContainer(player); diff --git a/apps/openmw/mwgui/spellwindow.cpp b/apps/openmw/mwgui/spellwindow.cpp new file mode 100644 index 0000000000..9c903134d9 --- /dev/null +++ b/apps/openmw/mwgui/spellwindow.cpp @@ -0,0 +1,20 @@ +#include "spellwindow.hpp" + +#include "window_manager.hpp" + +namespace MWGui +{ + SpellWindow::SpellWindow(WindowManager& parWindowManager) + : WindowPinnableBase("openmw_spell_window_layout.xml", parWindowManager) + { + getWidget(mSpellView, "SpellView"); + getWidget(mEffectBox, "EffectsBox"); + + setCoord(498, 300, 302, 300); + } + + void SpellWindow::onPinToggled() + { + mWindowManager.setSpellVisibility(!mPinned); + } +} diff --git a/apps/openmw/mwgui/spellwindow.hpp b/apps/openmw/mwgui/spellwindow.hpp new file mode 100644 index 0000000000..0450be4737 --- /dev/null +++ b/apps/openmw/mwgui/spellwindow.hpp @@ -0,0 +1,21 @@ +#ifndef MWGUI_SPELLWINDOW_H +#define MWGUI_SPELLWINDOW_H + +#include "window_pinnable_base.hpp" + +namespace MWGui +{ + class SpellWindow : public WindowPinnableBase + { + public: + SpellWindow(WindowManager& parWindowManager); + + protected: + MyGUI::ScrollView* mSpellView; + MyGUI::Widget* mEffectBox; + + virtual void onPinToggled(); + }; +} + +#endif diff --git a/apps/openmw/mwgui/window_manager.cpp b/apps/openmw/mwgui/window_manager.cpp index 4e786978f3..2db71438ab 100644 --- a/apps/openmw/mwgui/window_manager.cpp +++ b/apps/openmw/mwgui/window_manager.cpp @@ -19,6 +19,7 @@ #include "settingswindow.hpp" #include "confirmationdialog.hpp" #include "alchemywindow.hpp" +#include "spellwindow.hpp" #include "../mwmechanics/mechanicsmanager.hpp" #include "../mwinput/inputmanager.hpp" @@ -56,6 +57,7 @@ WindowManager::WindowManager( , mSettingsWindow(NULL) , mConfirmationDialog(NULL) , mAlchemyWindow(NULL) + , mSpellWindow(NULL) , mCharGen(NULL) , playerClass() , playerName() @@ -124,6 +126,7 @@ WindowManager::WindowManager( mSettingsWindow = new SettingsWindow(*this); mConfirmationDialog = new ConfirmationDialog(*this); mAlchemyWindow = new AlchemyWindow(*this); + mSpellWindow = new SpellWindow(*this); // The HUD is always on hud->setVisible(true); @@ -167,6 +170,7 @@ WindowManager::~WindowManager() delete mSettingsWindow; delete mConfirmationDialog; delete mAlchemyWindow; + delete mSpellWindow; cleanupGarbage(); } @@ -211,6 +215,7 @@ void WindowManager::updateVisible() mTradeWindow->setVisible(false); mSettingsWindow->setVisible(false); mAlchemyWindow->setVisible(false); + mSpellWindow->setVisible(false); // Mouse is visible whenever we're not in game mode MyGUI::PointerManager::getInstance().setVisible(isGuiMode()); @@ -224,7 +229,7 @@ void WindowManager::updateVisible() setMinimapVisibility((allowed & GW_Map) && !map->pinned()); setWeaponVisibility((allowed & GW_Inventory) && !mInventoryWindow->pinned()); - setSpellVisibility((allowed & GW_Magic)); /// \todo add pin state when spells window is implemented + setSpellVisibility((allowed & GW_Magic) && !mSpellWindow->pinned()); setHMSVisibility((allowed & GW_Stats) && !mStatsWindow->pinned()); // If in game mode, don't show anything. @@ -271,9 +276,10 @@ void WindowManager::updateVisible() int eff = shown & allowed; // Show the windows we want - map -> setVisible( (eff & GW_Map) ); - mStatsWindow -> setVisible( (eff & GW_Stats) ); - mInventoryWindow->setVisible( (eff & GW_Inventory)); + map -> setVisible(eff & GW_Map); + mStatsWindow -> setVisible(eff & GW_Stats); + mInventoryWindow->setVisible(eff & GW_Inventory); + mSpellWindow->setVisible(eff & GW_Magic); break; } case GM_Container: diff --git a/apps/openmw/mwgui/window_manager.hpp b/apps/openmw/mwgui/window_manager.hpp index f3e6a436e3..872f46f3d9 100644 --- a/apps/openmw/mwgui/window_manager.hpp +++ b/apps/openmw/mwgui/window_manager.hpp @@ -81,6 +81,7 @@ namespace MWGui class SettingsWindow; class ConfirmationDialog; class AlchemyWindow; + class SpellWindow; struct ClassPoint { @@ -250,6 +251,7 @@ namespace MWGui SettingsWindow* mSettingsWindow; ConfirmationDialog* mConfirmationDialog; AlchemyWindow* mAlchemyWindow; + SpellWindow* mSpellWindow; CharacterCreation* mCharGen; diff --git a/files/mygui/CMakeLists.txt b/files/mygui/CMakeLists.txt index 6b16e5f599..dad4afb466 100644 --- a/files/mygui/CMakeLists.txt +++ b/files/mygui/CMakeLists.txt @@ -60,6 +60,7 @@ configure_file("${SDIR}/openmw_trade_window_layout.xml" "${DDIR}/openmw_trade_wi configure_file("${SDIR}/openmw_settings_window_layout.xml" "${DDIR}/openmw_settings_window_layout.xml" COPYONLY) configure_file("${SDIR}/openmw_confirmation_dialog_layout.xml" "${DDIR}/openmw_confirmation_dialog_layout.xml" COPYONLY) configure_file("${SDIR}/openmw_alchemy_window_layout.xml" "${DDIR}/openmw_alchemy_window_layout.xml" COPYONLY) +configure_file("${SDIR}/openmw_spell_window_layout.xml" "${DDIR}/openmw_spell_window_layout.xml" COPYONLY) configure_file("${SDIR}/atlas1.cfg" "${DDIR}/atlas1.cfg" COPYONLY) configure_file("${SDIR}/smallbars.png" "${DDIR}/smallbars.png" COPYONLY) configure_file("${SDIR}/EBGaramond-Regular.ttf" "${DDIR}/EBGaramond-Regular.ttf" COPYONLY) diff --git a/files/mygui/openmw_spell_window_layout.xml b/files/mygui/openmw_spell_window_layout.xml new file mode 100644 index 0000000000..66a685c38d --- /dev/null +++ b/files/mygui/openmw_spell_window_layout.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + From 5412d6ed9effdc16ad3814a79c77f2a2665b9034 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 29 May 2012 10:47:48 +0200 Subject: [PATCH 303/325] fixed a typo that prevented spells from getting added --- apps/openmw/mwmechanics/spells.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/spells.cpp b/apps/openmw/mwmechanics/spells.cpp index af43cdfb55..70eb786392 100644 --- a/apps/openmw/mwmechanics/spells.cpp +++ b/apps/openmw/mwmechanics/spells.cpp @@ -28,7 +28,7 @@ namespace MWMechanics void Spells::add (const std::string& spellId) { - if (std::find (mSpells.begin(), mSpells.end(), spellId)!=mSpells.end()) + if (std::find (mSpells.begin(), mSpells.end(), spellId)==mSpells.end()) mSpells.push_back (spellId); } From 30461438f62a45abea53100687f148a4c6d53286 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 29 May 2012 12:35:03 +0200 Subject: [PATCH 304/325] still left: spell success formula --- apps/openmw/mwgui/container.cpp | 2 + apps/openmw/mwgui/container.hpp | 2 + apps/openmw/mwgui/hud.cpp | 5 +- apps/openmw/mwgui/inventorywindow.cpp | 8 + apps/openmw/mwgui/inventorywindow.hpp | 2 + apps/openmw/mwgui/spellwindow.cpp | 358 +++++++++++++++++++++ apps/openmw/mwgui/spellwindow.hpp | 13 + apps/openmw/mwgui/tooltips.cpp | 5 + apps/openmw/mwgui/window_manager.cpp | 10 +- apps/openmw/mwgui/window_manager.hpp | 1 + apps/openmw/mwworld/containerstore.cpp | 1 + apps/openmw/mwworld/inventorystore.cpp | 13 + apps/openmw/mwworld/inventorystore.hpp | 13 +- files/mygui/openmw_spell_window_layout.xml | 1 + files/mygui/openmw_text.skin.xml | 30 ++ 15 files changed, 456 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 1cfbc1b2b0..33ee8bf49d 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -535,6 +535,8 @@ void ContainerBase::drawItems() MyGUI::IntSize size = MyGUI::IntSize(std::max(mItemView->getSize().width, x+42), mItemView->getSize().height); mItemView->setCanvasSize(size); mContainerWidget->setSize(size); + + notifyContentChanged(); } std::string ContainerBase::getCountString(const int count) diff --git a/apps/openmw/mwgui/container.hpp b/apps/openmw/mwgui/container.hpp index 5cd8167c24..88e445a7bb 100644 --- a/apps/openmw/mwgui/container.hpp +++ b/apps/openmw/mwgui/container.hpp @@ -120,6 +120,8 @@ namespace MWGui virtual bool ignoreEquippedItems() { return false; } virtual std::vector itemsToIgnore() { return std::vector(); } + + virtual void notifyContentChanged() { ; } }; class ContainerWindow : public ContainerBase, public WindowBase diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index 7276218d6b..fdd1c88211 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -112,6 +112,8 @@ HUD::HUD(int width, int height, int fpsLevel, DragAndDrop* dragAndDrop) void HUD::setFpsLevel(int level) { + fpscounter = 0; + MyGUI::Widget* fps; getWidget(fps, "FPSBoxAdv"); fps->setVisible(false); @@ -134,7 +136,8 @@ void HUD::setFpsLevel(int level) void HUD::setFPS(float fps) { - fpscounter->setCaption(boost::lexical_cast((int)fps)); + if (fpscounter) + fpscounter->setCaption(boost::lexical_cast((int)fps)); } void HUD::setTriangleCount(size_t count) diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 1a715657a7..e1d4cc998a 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -20,6 +20,7 @@ #include "widgets.hpp" #include "bookwindow.hpp" #include "scrollwindow.hpp" +#include "spellwindow.hpp" namespace { @@ -259,4 +260,11 @@ namespace MWGui { mTrading = true; } + + void InventoryWindow::notifyContentChanged() + { + // update the spell window just in case new enchanted items were added to inventory + if (mWindowManager.getSpellWindow()) + mWindowManager.getSpellWindow()->updateSpells(); + } } diff --git a/apps/openmw/mwgui/inventorywindow.hpp b/apps/openmw/mwgui/inventorywindow.hpp index ecff75f101..bc4cb08ef2 100644 --- a/apps/openmw/mwgui/inventorywindow.hpp +++ b/apps/openmw/mwgui/inventorywindow.hpp @@ -50,6 +50,8 @@ namespace MWGui virtual void _unequipItem(MWWorld::Ptr item); virtual void onReferenceUnavailable() { ; } + + virtual void notifyContentChanged(); }; } diff --git a/apps/openmw/mwgui/spellwindow.cpp b/apps/openmw/mwgui/spellwindow.cpp index 9c903134d9..f761e00dbe 100644 --- a/apps/openmw/mwgui/spellwindow.cpp +++ b/apps/openmw/mwgui/spellwindow.cpp @@ -1,20 +1,378 @@ #include "spellwindow.hpp" +#include +#include + +#include "../mwworld/world.hpp" +#include "../mwworld/player.hpp" +#include "../mwworld/inventorystore.hpp" +#include "../mwbase/environment.hpp" +#include "../mwmechanics/spells.hpp" +#include "../mwmechanics/creaturestats.hpp" +#include "../mwsound/soundmanager.hpp" + #include "window_manager.hpp" +#include "inventorywindow.hpp" + +namespace +{ + bool sortSpells(const std::string& left, const std::string& right) + { + const ESM::Spell* a = MWBase::Environment::get().getWorld()->getStore().spells.find(left); + const ESM::Spell* b = MWBase::Environment::get().getWorld()->getStore().spells.find(right); + + int cmp = a->name.compare(b->name); + return cmp < 0; + } + + bool sortItems(const MWWorld::Ptr& left, const MWWorld::Ptr& right) + { + int cmp = MWWorld::Class::get(left).getName(left).compare( + MWWorld::Class::get(right).getName(right)); + return cmp < 0; + } +} namespace MWGui { SpellWindow::SpellWindow(WindowManager& parWindowManager) : WindowPinnableBase("openmw_spell_window_layout.xml", parWindowManager) + , mHeight(0) + , mWidth(0) { getWidget(mSpellView, "SpellView"); getWidget(mEffectBox, "EffectsBox"); setCoord(498, 300, 302, 300); + updateSpells(); + + mMainWidget->castType()->eventWindowChangeCoord += MyGUI::newDelegate(this, &SpellWindow::onWindowResize); } void SpellWindow::onPinToggled() { mWindowManager.setSpellVisibility(!mPinned); } + + void SpellWindow::open() + { + updateSpells(); + } + + void SpellWindow::updateSpells() + { + const int spellHeight = 18; + + mHeight = 0; + while (mSpellView->getChildCount()) + MyGUI::Gui::getInstance().destroyWidget(mSpellView->getChildAt(0)); + + // retrieve all player spells, divide them into Powers and Spells and sort them + std::vector spellList; + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + MWWorld::InventoryStore& store = MWWorld::Class::get(player).getInventoryStore(player); + MWMechanics::CreatureStats& stats = MWWorld::Class::get(player).getCreatureStats(player); + MWMechanics::Spells& spells = stats.mSpells; + + // the following code switches between selected enchanted item and selected spell (only one of these + // can be active at a time) + std::string selectedSpell = spells.getSelectedSpell(); + MWWorld::Ptr selectedItem; + if (store.getSelectedEnchantItem() != store.end()) + { + selectedSpell = ""; + selectedItem = *store.getSelectedEnchantItem(); + + bool allowSelectedItem = true; + + // if the selected item can be equipped, make sure that it actually is equipped + std::pair, bool> slots; + slots = MWWorld::Class::get(selectedItem).getEquipmentSlots(selectedItem); + if (!slots.first.empty()) + { + bool equipped = false; + for (int i=0; i < MWWorld::InventoryStore::Slots; ++i) + { + if (store.getSlot(i) != store.end() && *store.getSlot(i) == selectedItem) + { + equipped = true; + break; + } + } + + if (!equipped) + allowSelectedItem = false; + } + + if (!allowSelectedItem) + { + store.setSelectedEnchantItem(store.end()); + selectedItem = MWWorld::Ptr(); + } + } + + + + for (MWMechanics::Spells::TIterator it = spells.begin(); it != spells.end(); ++it) + { + spellList.push_back(*it); + } + + std::vector powers; + std::vector::iterator it = spellList.begin(); + while (it != spellList.end()) + { + const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().spells.find(*it); + if (spell->data.type == ESM::Spell::ST_Power) + { + powers.push_back(*it); + it = spellList.erase(it); + } + else if (spell->data.type == ESM::Spell::ST_Ability) + { + // abilities are always active and don't show in the spell window. + it = spellList.erase(it); + } + else + ++it; + } + std::sort(powers.begin(), powers.end(), sortSpells); + std::sort(spellList.begin(), spellList.end(), sortSpells); + + // retrieve player's enchanted items + std::vector items; + for (MWWorld::ContainerStoreIterator it(store.begin()); it != store.end(); ++it) + { + std::string enchantId = MWWorld::Class::get(*it).getEnchantment(*it); + if (enchantId != "") + { + // only add items with "Cast once" or "Cast on use" + const ESM::Enchantment* enchant = MWBase::Environment::get().getWorld()->getStore().enchants.find(enchantId); + int type = enchant->data.type; + if (type != ESM::Enchantment::CastOnce + && type != ESM::Enchantment::WhenUsed) + continue; + + items.push_back(*it); + } + } + std::sort(items.begin(), items.end(), sortItems); + + + int height = estimateHeight(items.size() + powers.size() + spellList.size()); + bool scrollVisible = height > mSpellView->getHeight(); + mWidth = mSpellView->getWidth() - (scrollVisible ? 18 : 0); + + // powers + addGroup("#{sPowers}", ""); + + for (std::vector::const_iterator it = powers.begin(); it != powers.end(); ++it) + { + const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().spells.find(*it); + MyGUI::Button* t = mSpellView->createWidget("SpellText", + MyGUI::IntCoord(4, mHeight, mWidth-8, spellHeight), MyGUI::Align::Left | MyGUI::Align::Top); + t->setCaption(spell->name); + t->setTextAlign(MyGUI::Align::Left); + t->setUserString("ToolTipType", "Spell"); + t->setUserString("Spell", *it); + t->eventMouseButtonClick += MyGUI::newDelegate(this, &SpellWindow::onSpellSelected); + + if (*it == selectedSpell) + t->setStateSelected(true); + + mHeight += spellHeight; + } + + // other spells + addGroup("#{sSpells}", "#{sCostChance}"); + for (std::vector::const_iterator it = spellList.begin(); it != spellList.end(); ++it) + { + const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().spells.find(*it); + MyGUI::Button* t = mSpellView->createWidget("SpellText", + MyGUI::IntCoord(4, mHeight, mWidth-8, spellHeight), MyGUI::Align::Left | MyGUI::Align::Top); + t->setCaption(spell->name); + t->setTextAlign(MyGUI::Align::Left); + t->setUserString("ToolTipType", "Spell"); + t->setUserString("Spell", *it); + t->eventMouseButtonClick += MyGUI::newDelegate(this, &SpellWindow::onSpellSelected); + + if (*it == selectedSpell) + t->setStateSelected(true); + + // cost / success chance + MyGUI::TextBox* costChance = mSpellView->createWidget("SpellText", + MyGUI::IntCoord(4, mHeight, mWidth-8, spellHeight), MyGUI::Align::Left | MyGUI::Align::Top); + std::string cost = boost::lexical_cast(spell->data.cost); + costChance->setCaption(cost + "/" + "100"); /// \todo + costChance->setTextAlign(MyGUI::Align::Right); + costChance->setNeedMouseFocus(false); + + + mHeight += spellHeight; + } + + + // enchanted items + addGroup("#{sMagicItem}", "#{sCostCharge}"); + + for (std::vector::const_iterator it = items.begin(); it != items.end(); ++it) + { + MWWorld::Ptr item = *it; + + // check if the item is currently equipped (will display in a different color) + bool equipped = false; + for (int i=0; i < MWWorld::InventoryStore::Slots; ++i) + { + if (store.getSlot(i) != store.end() && *store.getSlot(i) == item) + { + equipped = true; + break; + } + } + + MyGUI::Button* t = mSpellView->createWidget(equipped ? "SpellText" : "SpellTextUnequipped", + MyGUI::IntCoord(4, mHeight, mWidth-8, spellHeight), MyGUI::Align::Left | MyGUI::Align::Top); + t->setCaption(MWWorld::Class::get(item).getName(item)); + t->setTextAlign(MyGUI::Align::Left); + t->setUserData(item); + t->setUserString("ToolTipType", "ItemPtr"); + t->setUserString("Equipped", equipped ? "true" : "false"); + t->eventMouseButtonClick += MyGUI::newDelegate(this, &SpellWindow::onEnchantedItemSelected); + t->setStateSelected(item == selectedItem); + + // cost / charge + MyGUI::TextBox* costCharge = mSpellView->createWidget(equipped ? "SpellText" : "SpellTextUnequipped", + MyGUI::IntCoord(4, mHeight, mWidth-8, spellHeight), MyGUI::Align::Left | MyGUI::Align::Top); + + const ESM::Enchantment* enchant = MWBase::Environment::get().getWorld()->getStore().enchants.find(MWWorld::Class::get(item).getEnchantment(item)); + std::string cost = boost::lexical_cast(enchant->data.cost); + std::string charge = boost::lexical_cast(enchant->data.charge); /// \todo track current charge + costCharge->setCaption(cost + "/" + charge); + costCharge->setTextAlign(MyGUI::Align::Right); + costCharge->setNeedMouseFocus(false); + + mHeight += spellHeight; + } + + mSpellView->setCanvasSize(mSpellView->getWidth(), std::max(mSpellView->getHeight(), mHeight)); + } + + void SpellWindow::addGroup(const std::string &label, const std::string& label2) + { + if (mSpellView->getChildCount() > 0) + { + MyGUI::ImageBox* separator = mSpellView->createWidget("MW_HLine", + MyGUI::IntCoord(4, mHeight, mWidth-8, 18), + MyGUI::Align::Left | MyGUI::Align::Top); + separator->setNeedMouseFocus(false); + mHeight += 18; + } + + MyGUI::TextBox* groupWidget = mSpellView->createWidget("SandBrightText", + MyGUI::IntCoord(0, mHeight, mWidth, 24), + MyGUI::Align::Left | MyGUI::Align::Top | MyGUI::Align::HStretch); + groupWidget->setCaptionWithReplacing(label); + groupWidget->setTextAlign(MyGUI::Align::Left); + groupWidget->setNeedMouseFocus(false); + + if (label2 != "") + { + MyGUI::TextBox* groupWidget2 = mSpellView->createWidget("SandBrightText", + MyGUI::IntCoord(0, mHeight, mWidth-4, 24), + MyGUI::Align::Left | MyGUI::Align::Top); + groupWidget2->setCaptionWithReplacing(label2); + groupWidget2->setTextAlign(MyGUI::Align::Right); + groupWidget2->setNeedMouseFocus(false); + } + + mHeight += 24; + } + + void SpellWindow::onWindowResize(MyGUI::Window* _sender) + { + updateSpells(); + } + + void SpellWindow::onEnchantedItemSelected(MyGUI::Widget* _sender) + { + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + MWMechanics::CreatureStats& stats = MWWorld::Class::get(player).getCreatureStats(player); + MWWorld::InventoryStore& store = MWWorld::Class::get(player).getInventoryStore(player); + MWMechanics::Spells& spells = stats.mSpells; + MWWorld::Ptr item = *_sender->getUserData(); + + // retrieve ContainerStoreIterator to the item + MWWorld::ContainerStoreIterator it = store.begin(); + for (; it != store.end(); ++it) + { + if (*it == item) + { + break; + } + } + assert(it != store.end()); + + // equip, if it is not already equipped + if (_sender->getUserString("Equipped") == "false") + { + // sound + MWBase::Environment::get().getSoundManager()->playSound(MWWorld::Class::get(item).getUpSoundId(item), 1.0, 1.0); + + // Note: can't use Class::use here because enchanted scrolls for example would then open the scroll window instead of equipping + + /// \todo the following code is pretty much copy&paste from ActionEquip, put it in a function? + // slots that this item can be equipped in + std::pair, bool> slots = MWWorld::Class::get(item).getEquipmentSlots(item); + + + // equip the item in the first free slot + for (std::vector::const_iterator slot=slots.first.begin(); + slot!=slots.first.end(); ++slot) + { + // if all slots are occupied, replace the last slot + if (slot == --slots.first.end()) + { + store.equip(*slot, it); + break; + } + + if (store.getSlot(*slot) == store.end()) + { + // slot is not occupied + store.equip(*slot, it); + break; + } + } + /// \todo scripts? + + // since we changed equipping status, update the inventory window + mWindowManager.getInventoryWindow()->drawItems(); + } + + store.setSelectedEnchantItem(it); + spells.setSelectedSpell(""); + + updateSpells(); + } + + void SpellWindow::onSpellSelected(MyGUI::Widget* _sender) + { + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + MWMechanics::CreatureStats& stats = MWWorld::Class::get(player).getCreatureStats(player); + MWWorld::InventoryStore& store = MWWorld::Class::get(player).getInventoryStore(player); + MWMechanics::Spells& spells = stats.mSpells; + + spells.setSelectedSpell(_sender->getUserString("Spell")); + store.setSelectedEnchantItem(store.end()); + + updateSpells(); + } + + int SpellWindow::estimateHeight(int numSpells) const + { + int height = 0; + height += 24 * 3 + 18 * 2; // group headings + height += numSpells * 18; + return height; + } } diff --git a/apps/openmw/mwgui/spellwindow.hpp b/apps/openmw/mwgui/spellwindow.hpp index 0450be4737..16a1c7ff8a 100644 --- a/apps/openmw/mwgui/spellwindow.hpp +++ b/apps/openmw/mwgui/spellwindow.hpp @@ -10,11 +10,24 @@ namespace MWGui public: SpellWindow(WindowManager& parWindowManager); + void updateSpells(); + protected: MyGUI::ScrollView* mSpellView; MyGUI::Widget* mEffectBox; + int mHeight; + int mWidth; + + void addGroup(const std::string& label, const std::string& label2); + + int estimateHeight(int numSpells) const; + virtual void onPinToggled(); + void onWindowResize(MyGUI::Window* _sender); + void onEnchantedItemSelected(MyGUI::Widget* _sender); + void onSpellSelected(MyGUI::Widget* _sender); + virtual void open(); }; } diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index bdce61a44f..dc34ee86cc 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -67,6 +67,11 @@ void ToolTips::onFrame(float frameDuration) if (!mGameMode) { const MyGUI::IntPoint& mousePos = InputManager::getInstance().getMousePosition(); + const MyGUI::IntPoint& lastPressed = InputManager::getInstance().getLastPressedPosition(MyGUI::MouseButton::Left); + + if (mousePos == lastPressed) // mouseclick makes tooltip disappear + return; + if (mousePos.left == mLastMouseX && mousePos.top == mLastMouseY) { mRemainingDelay -= frameDuration; diff --git a/apps/openmw/mwgui/window_manager.cpp b/apps/openmw/mwgui/window_manager.cpp index 2db71438ab..4eaaf72a4b 100644 --- a/apps/openmw/mwgui/window_manager.cpp +++ b/apps/openmw/mwgui/window_manager.cpp @@ -191,12 +191,10 @@ void WindowManager::cleanupGarbage() void WindowManager::update() { cleanupGarbage(); - if (showFPSLevel > 0) - { - hud->setFPS(mFPS); - hud->setTriangleCount(mTriangleCount); - hud->setBatchCount(mBatchCount); - } + + hud->setFPS(mFPS); + hud->setTriangleCount(mTriangleCount); + hud->setBatchCount(mBatchCount); } void WindowManager::updateVisible() diff --git a/apps/openmw/mwgui/window_manager.hpp b/apps/openmw/mwgui/window_manager.hpp index 872f46f3d9..2a7794f702 100644 --- a/apps/openmw/mwgui/window_manager.hpp +++ b/apps/openmw/mwgui/window_manager.hpp @@ -154,6 +154,7 @@ namespace MWGui MWGui::CountDialog* getCountDialog() {return mCountDialog;} MWGui::ConfirmationDialog* getConfirmationDialog() {return mConfirmationDialog;} MWGui::TradeWindow* getTradeWindow() {return mTradeWindow;} + MWGui::SpellWindow* getSpellWindow() {return mSpellWindow;} MyGUI::Gui* getGui() const { return gui; } diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index b669508b25..3304d0e6d0 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -61,6 +61,7 @@ bool MWWorld::ContainerStore::stacks(const Ptr& ptr1, const Ptr& ptr2) /// \todo add current weapon/armor health, remaining lockpick/repair uses, current enchantment charge here as soon as they are implemented if ( ptr1.mCellRef->refID == ptr2.mCellRef->refID && MWWorld::Class::get(ptr1).getScript(ptr1) == "" // item with a script never stacks + && MWWorld::Class::get(ptr1).getEnchantment(ptr1) == "" // item with enchantment never stacks (we could revisit this later, but for now it makes selecting items in the spell window much easier) && ptr1.mCellRef->owner == ptr2.mCellRef->owner && ptr1.mCellRef->soul == ptr2.mCellRef->soul && ptr1.mCellRef->charge == ptr2.mCellRef->charge) diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index 98ab1665b4..6df73004be 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -39,15 +39,18 @@ void MWWorld::InventoryStore::initSlots (TSlots& slots) } MWWorld::InventoryStore::InventoryStore() : mMagicEffectsUpToDate (false) + , mSelectedEnchantItem(end()) { initSlots (mSlots); } MWWorld::InventoryStore::InventoryStore (const InventoryStore& store) : ContainerStore (store) + , mSelectedEnchantItem(end()) { mMagicEffects = store.mMagicEffects; mMagicEffectsUpToDate = store.mMagicEffectsUpToDate; + mSelectedEnchantItem = store.mSelectedEnchantItem; copySlots (store); } @@ -260,3 +263,13 @@ bool MWWorld::InventoryStore::stacks(const Ptr& ptr1, const Ptr& ptr2) return true; } + +void MWWorld::InventoryStore::setSelectedEnchantItem(const ContainerStoreIterator& iterator) +{ + mSelectedEnchantItem = iterator; +} + +MWWorld::ContainerStoreIterator MWWorld::InventoryStore::getSelectedEnchantItem() +{ + return mSelectedEnchantItem; +} diff --git a/apps/openmw/mwworld/inventorystore.hpp b/apps/openmw/mwworld/inventorystore.hpp index dcfb21f30f..45b3cab268 100644 --- a/apps/openmw/mwworld/inventorystore.hpp +++ b/apps/openmw/mwworld/inventorystore.hpp @@ -50,6 +50,9 @@ namespace MWWorld mutable TSlots mSlots; + // selected magic item (for using enchantments of type "Cast once" or "Cast when used") + ContainerStoreIterator mSelectedEnchantItem; + void copySlots (const InventoryStore& store); void initSlots (TSlots& slots); @@ -63,7 +66,15 @@ namespace MWWorld InventoryStore& operator= (const InventoryStore& store); void equip (int slot, const ContainerStoreIterator& iterator); - ///< \note \a iteartor can be an end-iterator + ///< \note \a iterator can be an end-iterator + + void setSelectedEnchantItem(const ContainerStoreIterator& iterator); + ///< set the selected magic item (for using enchantments of type "Cast once" or "Cast when used") + /// \note to unset the selected item, call this method with end() iterator + + ContainerStoreIterator getSelectedEnchantItem(); + ///< @return selected magic item (for using enchantments of type "Cast once" or "Cast when used") + /// \note if no item selected, return end() iterator ContainerStoreIterator getSlot (int slot); diff --git a/files/mygui/openmw_spell_window_layout.xml b/files/mygui/openmw_spell_window_layout.xml index 66a685c38d..d489f41b8a 100644 --- a/files/mygui/openmw_spell_window_layout.xml +++ b/files/mygui/openmw_spell_window_layout.xml @@ -12,6 +12,7 @@ + diff --git a/files/mygui/openmw_text.skin.xml b/files/mygui/openmw_text.skin.xml index bfa970de52..e29483e35b 100644 --- a/files/mygui/openmw_text.skin.xml +++ b/files/mygui/openmw_text.skin.xml @@ -99,6 +99,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 48ba293e88febaed2d0efaca9fac7c5f5eeaac83 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 29 May 2012 15:13:44 +0200 Subject: [PATCH 305/325] added the success formula, and spell deleting (shift+click) --- apps/openmw/mwgui/spellwindow.cpp | 83 ++++++++++++++++++++---- apps/openmw/mwgui/spellwindow.hpp | 7 +- apps/openmw/mwmechanics/spellsuccess.hpp | 83 ++++++++++++++++++++++++ 3 files changed, 160 insertions(+), 13 deletions(-) create mode 100644 apps/openmw/mwmechanics/spellsuccess.hpp diff --git a/apps/openmw/mwgui/spellwindow.cpp b/apps/openmw/mwgui/spellwindow.cpp index f761e00dbe..168578831f 100644 --- a/apps/openmw/mwgui/spellwindow.cpp +++ b/apps/openmw/mwgui/spellwindow.cpp @@ -2,6 +2,7 @@ #include #include +#include #include "../mwworld/world.hpp" #include "../mwworld/player.hpp" @@ -9,10 +10,12 @@ #include "../mwbase/environment.hpp" #include "../mwmechanics/spells.hpp" #include "../mwmechanics/creaturestats.hpp" +#include "../mwmechanics/spellsuccess.hpp" #include "../mwsound/soundmanager.hpp" #include "window_manager.hpp" #include "inventorywindow.hpp" +#include "confirmationdialog.hpp" namespace { @@ -175,6 +178,7 @@ namespace MWGui t->setTextAlign(MyGUI::Align::Left); t->setUserString("ToolTipType", "Spell"); t->setUserString("Spell", *it); + t->eventMouseWheel += MyGUI::newDelegate(this, &SpellWindow::onMouseWheel); t->eventMouseButtonClick += MyGUI::newDelegate(this, &SpellWindow::onSpellSelected); if (*it == selectedSpell) @@ -194,18 +198,19 @@ namespace MWGui t->setTextAlign(MyGUI::Align::Left); t->setUserString("ToolTipType", "Spell"); t->setUserString("Spell", *it); + t->eventMouseWheel += MyGUI::newDelegate(this, &SpellWindow::onMouseWheel); t->eventMouseButtonClick += MyGUI::newDelegate(this, &SpellWindow::onSpellSelected); - - if (*it == selectedSpell) - t->setStateSelected(true); + t->setStateSelected(*it == selectedSpell); // cost / success chance - MyGUI::TextBox* costChance = mSpellView->createWidget("SpellText", + MyGUI::Button* costChance = mSpellView->createWidget("SpellText", MyGUI::IntCoord(4, mHeight, mWidth-8, spellHeight), MyGUI::Align::Left | MyGUI::Align::Top); std::string cost = boost::lexical_cast(spell->data.cost); - costChance->setCaption(cost + "/" + "100"); /// \todo + std::string chance = boost::lexical_cast(int(MWMechanics::getSpellSuccessChance(*it, player))); + costChance->setCaption(cost + "/" + chance); costChance->setTextAlign(MyGUI::Align::Right); costChance->setNeedMouseFocus(false); + costChance->setStateSelected(*it == selectedSpell); mHeight += spellHeight; @@ -219,6 +224,8 @@ namespace MWGui { MWWorld::Ptr item = *it; + const ESM::Enchantment* enchant = MWBase::Environment::get().getWorld()->getStore().enchants.find(MWWorld::Class::get(item).getEnchantment(item)); + // check if the item is currently equipped (will display in a different color) bool equipped = false; for (int i=0; i < MWWorld::InventoryStore::Slots; ++i) @@ -238,18 +245,26 @@ namespace MWGui t->setUserString("ToolTipType", "ItemPtr"); t->setUserString("Equipped", equipped ? "true" : "false"); t->eventMouseButtonClick += MyGUI::newDelegate(this, &SpellWindow::onEnchantedItemSelected); + t->eventMouseWheel += MyGUI::newDelegate(this, &SpellWindow::onMouseWheel); t->setStateSelected(item == selectedItem); // cost / charge - MyGUI::TextBox* costCharge = mSpellView->createWidget(equipped ? "SpellText" : "SpellTextUnequipped", + MyGUI::Button* costCharge = mSpellView->createWidget(equipped ? "SpellText" : "SpellTextUnequipped", MyGUI::IntCoord(4, mHeight, mWidth-8, spellHeight), MyGUI::Align::Left | MyGUI::Align::Top); - const ESM::Enchantment* enchant = MWBase::Environment::get().getWorld()->getStore().enchants.find(MWWorld::Class::get(item).getEnchantment(item)); std::string cost = boost::lexical_cast(enchant->data.cost); std::string charge = boost::lexical_cast(enchant->data.charge); /// \todo track current charge + if (enchant->data.type != ESM::Enchantment::CastOnce) + { + // this is Morrowind behaviour + cost = "100"; + charge = "100"; + } + costCharge->setCaption(cost + "/" + charge); costCharge->setTextAlign(MyGUI::Align::Right); costCharge->setNeedMouseFocus(false); + costCharge->setStateSelected(item == selectedItem); mHeight += spellHeight; } @@ -312,8 +327,9 @@ namespace MWGui } assert(it != store.end()); - // equip, if it is not already equipped - if (_sender->getUserString("Equipped") == "false") + // equip, if it can be equipped and is not already equipped + if (_sender->getUserString("Equipped") == "false" + && !MWWorld::Class::get(item).getEquipmentSlots(item).first.empty()) { // sound MWBase::Environment::get().getSoundManager()->playSound(MWWorld::Class::get(item).getUpSoundId(item), 1.0, 1.0); @@ -324,7 +340,6 @@ namespace MWGui // slots that this item can be equipped in std::pair, bool> slots = MWWorld::Class::get(item).getEquipmentSlots(item); - // equip the item in the first free slot for (std::vector::const_iterator slot=slots.first.begin(); slot!=slots.first.end(); ++slot) @@ -362,8 +377,33 @@ namespace MWGui MWWorld::InventoryStore& store = MWWorld::Class::get(player).getInventoryStore(player); MWMechanics::Spells& spells = stats.mSpells; - spells.setSelectedSpell(_sender->getUserString("Spell")); - store.setSelectedEnchantItem(store.end()); + if (MyGUI::InputManager::getInstance().isShiftPressed()) + { + // delete spell, if allowed + const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().spells.find(_sender->getUserString("Spell")); + if (spell->data.flags & ESM::Spell::F_Always + || spell->data.type == ESM::Spell::ST_Power) + { + mWindowManager.messageBox("#{sDeleteSpellError}", std::vector()); + } + else + { + // ask for confirmation + mSpellToDelete = _sender->getUserString("Spell"); + ConfirmationDialog* dialog = mWindowManager.getConfirmationDialog(); + std::string question = mWindowManager.getGameSettingString("sQuestionDeleteSpell", "Delete %s?"); + question = boost::str(boost::format(question) % spell->name); + dialog->open(question); + dialog->eventOkClicked.clear(); + dialog->eventOkClicked += MyGUI::newDelegate(this, &SpellWindow::onDeleteSpellAccept); + dialog->eventCancelClicked.clear(); + } + } + else + { + spells.setSelectedSpell(_sender->getUserString("Spell")); + store.setSelectedEnchantItem(store.end()); + } updateSpells(); } @@ -375,4 +415,23 @@ namespace MWGui height += numSpells * 18; return height; } + + void SpellWindow::onMouseWheel(MyGUI::Widget* _sender, int _rel) + { + if (mSpellView->getViewOffset().top + _rel*0.3 > 0) + mSpellView->setViewOffset(MyGUI::IntPoint(0, 0)); + else + mSpellView->setViewOffset(MyGUI::IntPoint(0, mSpellView->getViewOffset().top + _rel*0.3)); + } + + void SpellWindow::onDeleteSpellAccept() + { + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + MWMechanics::CreatureStats& stats = MWWorld::Class::get(player).getCreatureStats(player); + MWMechanics::Spells& spells = stats.mSpells; + + spells.remove(mSpellToDelete); + + updateSpells(); + } } diff --git a/apps/openmw/mwgui/spellwindow.hpp b/apps/openmw/mwgui/spellwindow.hpp index 16a1c7ff8a..87e4783ba2 100644 --- a/apps/openmw/mwgui/spellwindow.hpp +++ b/apps/openmw/mwgui/spellwindow.hpp @@ -19,14 +19,19 @@ namespace MWGui int mHeight; int mWidth; + std::string mSpellToDelete; + void addGroup(const std::string& label, const std::string& label2); int estimateHeight(int numSpells) const; - virtual void onPinToggled(); void onWindowResize(MyGUI::Window* _sender); void onEnchantedItemSelected(MyGUI::Widget* _sender); void onSpellSelected(MyGUI::Widget* _sender); + void onMouseWheel(MyGUI::Widget* _sender, int _rel); + void onDeleteSpellAccept(); + + virtual void onPinToggled(); virtual void open(); }; } diff --git a/apps/openmw/mwmechanics/spellsuccess.hpp b/apps/openmw/mwmechanics/spellsuccess.hpp new file mode 100644 index 0000000000..532f9eb4ec --- /dev/null +++ b/apps/openmw/mwmechanics/spellsuccess.hpp @@ -0,0 +1,83 @@ +#ifndef MWMECHANICS_SPELLSUCCESS_H +#define MWMECHANICS_SPELLSUCCESS_H + +#include "../mwworld/ptr.hpp" +#include "../mwworld/world.hpp" +#include "../mwbase/environment.hpp" + +#include "npcstats.hpp" + +namespace MWMechanics +{ + // UESP wiki / Morrowind/Spells: + // Chance of success is (Spell's skill * 2 + Willpower / 5 + Luck / 10 - Spell cost - Sound magnitude) * (Current fatigue + Maximum Fatigue * 1.5) / Maximum fatigue * 2 + + /** + * @param spellId ID of spell + * @param actor calculate spell success chance for this actor (depends on actor's skills) + * @attention actor has to be an NPC and not a creature! + * @return success chance from 0 to 100 (in percent) + */ + float getSpellSuccessChance (const std::string& spellId, const MWWorld::Ptr& actor) + { + const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().spells.find(spellId); + + if (spell->data.flags & ESM::Spell::F_Always) // spells with this flag always succeed (usually birthsign spells) + return 100.0; + + NpcStats& stats = MWWorld::Class::get(actor).getNpcStats(actor); + CreatureStats& creatureStats = MWWorld::Class::get(actor).getCreatureStats(actor); + + std::map schoolSkillMap; // maps spell school to skill id + schoolSkillMap[0] = 11; // alteration + schoolSkillMap[1] = 13; // conjuration + schoolSkillMap[3] = 12; // illusion + schoolSkillMap[2] = 10; // destruction + schoolSkillMap[4] = 14; // mysticism + schoolSkillMap[5] = 15; // restoration + + // determine the spell's school + // this is always the school where the player's respective skill is the least advanced + // out of all the magic effects' schools + const std::vector& effects = spell->effects.list; + int skill = -1; + int skillLevel = -1; + for (std::vector::const_iterator it = effects.begin(); + it != effects.end(); ++it) + { + const ESM::MagicEffect* effect = MWBase::Environment::get().getWorld()->getStore().magicEffects.find(it->effectID); + int school = effect->data.school; + assert(schoolSkillMap.find(school) != schoolSkillMap.end()); + int _skillLevel = stats.mSkill[schoolSkillMap[school]].getModified(); + + if (skill == -1) + { + skill = schoolSkillMap[school]; + skillLevel = _skillLevel; + } + else if (_skillLevel < skillLevel) + { + skill = schoolSkillMap[school]; + skillLevel = _skillLevel; + } + } + + // Sound magic effect (reduces spell casting chance) + int soundMagnitude = creatureStats.mMagicEffects.get (MWMechanics::EffectKey (48)).mMagnitude; + + int willpower = creatureStats.mAttributes[ESM::Attribute::Willpower].getModified(); + int luck = creatureStats.mAttributes[ESM::Attribute::Luck].getModified(); + int currentFatigue = creatureStats.mDynamic[2].getCurrent(); + int maxFatigue = creatureStats.mDynamic[2].getModified(); + int spellCost = spell->data.cost; + + // There we go, all needed variables are there, lets go + float chance = (float(skillLevel * 2) + float(willpower)/5.0 + float(luck)/ 10.0 - spellCost - soundMagnitude) * (float(currentFatigue + maxFatigue * 1.5)) / float(maxFatigue * 2.0); + + chance = std::max(0.0f, std::min(100.0f, chance)); // clamp to 0 .. 100 + + return chance; + } +} + +#endif From 8b7baa808e719663f65e4ba08c80f416ac0e45bc Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 29 May 2012 15:36:48 +0200 Subject: [PATCH 306/325] fixed the hud icon positioning issues --- apps/openmw/mwgui/hud.cpp | 17 +++++++++++------ apps/openmw/mwgui/hud.hpp | 1 + 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index fdd1c88211..6b0cdbd5cb 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -48,11 +48,12 @@ HUD::HUD(int width, int height, int fpsLevel, DragAndDrop* dragAndDrop) setCoord(0,0, width, height); // Energy bars + getWidget(mHealthFrame, "HealthFrame"); getWidget(health, "Health"); getWidget(magicka, "Magicka"); getWidget(stamina, "Stamina"); - hmsBaseLeft = health->getLeft(); + hmsBaseLeft = mHealthFrame->getLeft(); MyGUI::Widget *healthFrame, *magickaFrame, *fatigueFrame; getWidget(healthFrame, "HealthFrame"); @@ -62,6 +63,8 @@ HUD::HUD(int width, int height, int fpsLevel, DragAndDrop* dragAndDrop) magickaFrame->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onHMSClicked); fatigueFrame->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onHMSClicked); + const MyGUI::IntSize& viewSize = MyGUI::RenderManager::getInstance().getViewSize(); + // Item and spell images and status bars getWidget(weapBox, "WeapBox"); getWidget(weapImage, "WeapImage"); @@ -77,11 +80,11 @@ HUD::HUD(int width, int height, int fpsLevel, DragAndDrop* dragAndDrop) getWidget(effectBox, "EffectBox"); getWidget(effect1, "Effect1"); - effectBoxBaseRight = effectBox->getRight(); + effectBoxBaseRight = viewSize.width - effectBox->getRight(); effectBox->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onMagicClicked); getWidget(minimapBox, "MiniMapBox"); - minimapBoxBaseRight = minimapBox->getRight(); + minimapBoxBaseRight = viewSize.width - minimapBox->getRight(); minimapBox->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onMapClicked); getWidget(minimap, "MiniMap"); getWidget(compass, "Compass"); @@ -220,7 +223,7 @@ void HUD::setBottomLeftVisibility(bool hmsVisible, bool weapVisible, bool spellV spellDx = weapDx = weapBoxBaseLeft - hmsBaseLeft; if (!weapVisible) - spellDx -= spellBoxBaseLeft - weapBoxBaseLeft; + spellDx += spellBoxBaseLeft - weapBoxBaseLeft; health->setVisible(hmsVisible); stamina->setVisible(hmsVisible); @@ -233,14 +236,16 @@ void HUD::setBottomLeftVisibility(bool hmsVisible, bool weapVisible, bool spellV void HUD::setBottomRightVisibility(bool effectBoxVisible, bool minimapBoxVisible) { + const MyGUI::IntSize& viewSize = MyGUI::RenderManager::getInstance().getViewSize(); + // effect box can have variable width -> variable left coordinate int effectsDx = 0; if (!minimapBoxVisible) - effectsDx = minimapBoxBaseRight - effectBoxBaseRight; + effectsDx = (viewSize.width - minimapBoxBaseRight) - (viewSize.width - effectBoxBaseRight); mMapVisible = minimapBoxVisible; minimapBox->setVisible(minimapBoxVisible); - effectBox->setPosition(effectBoxBaseRight - effectBox->getWidth() + effectsDx, effectBox->getTop()); + effectBox->setPosition((viewSize.width - effectBoxBaseRight) - effectBox->getWidth() + effectsDx, effectBox->getTop()); effectBox->setVisible(effectBoxVisible); } diff --git a/apps/openmw/mwgui/hud.hpp b/apps/openmw/mwgui/hud.hpp index 16749114c5..6d4bf05594 100644 --- a/apps/openmw/mwgui/hud.hpp +++ b/apps/openmw/mwgui/hud.hpp @@ -31,6 +31,7 @@ namespace MWGui void setCellName(const std::string& cellName); MyGUI::ProgressPtr health, magicka, stamina; + MyGUI::Widget* mHealthFrame; MyGUI::Widget *weapBox, *spellBox; MyGUI::ImageBox *weapImage, *spellImage; MyGUI::ProgressPtr weapStatus, spellStatus; From 298ae4f7f8c8cde5d689c3b5013854f95a183493 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 29 May 2012 18:33:01 +0200 Subject: [PATCH 307/325] HUD icons for selected weapon / selected spell / selected enchanted item --- apps/openmw/mwgui/container.cpp | 2 +- apps/openmw/mwgui/hud.cpp | 171 +++++++++++++++++++---- apps/openmw/mwgui/hud.hpp | 16 ++- apps/openmw/mwgui/inventorywindow.cpp | 18 +++ apps/openmw/mwgui/spellwindow.cpp | 17 ++- apps/openmw/mwgui/tooltips.cpp | 1 - apps/openmw/mwgui/tradewindow.cpp | 2 + apps/openmw/mwgui/window_manager.cpp | 25 ++++ apps/openmw/mwgui/window_manager.hpp | 6 + apps/openmw/mwmechanics/spellsuccess.hpp | 66 +++++---- files/mygui/openmw_hud_layout.xml | 8 ++ 11 files changed, 270 insertions(+), 62 deletions(-) diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 33ee8bf49d..bf6b4add04 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -347,7 +347,6 @@ void ContainerBase::setFilter(ContainerBase::Filter filter) void ContainerBase::openContainer(MWWorld::Ptr container) { mPtr = container; - drawItems(); } void ContainerBase::drawItems() @@ -638,6 +637,7 @@ void ContainerWindow::open(MWWorld::Ptr container) { openContainer(container); setTitle(MWWorld::Class::get(container).getName(container)); + drawItems(); } void ContainerWindow::onCloseButtonClicked(MyGUI::Widget* _sender) diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index 6b0cdbd5cb..95017579bc 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -90,6 +90,7 @@ HUD::HUD(int width, int height, int fpsLevel, DragAndDrop* dragAndDrop) getWidget(compass, "Compass"); getWidget(mCellNameBox, "CellName"); + getWidget(mWeaponSpellBox, "WeaponSpellName"); getWidget(crosshair, "Crosshair"); @@ -98,14 +99,11 @@ HUD::HUD(int width, int height, int fpsLevel, DragAndDrop* dragAndDrop) getWidget(trianglecounter, "TriangleCounter"); getWidget(batchcounter, "BatchCounter"); - // These are just demo values, you should replace these with - // real calls from outside the class later. - setWeapIcon("icons\\w\\tx_knife_iron.dds"); - setWeapStatus(90, 100); - setSpellIcon("icons\\s\\b_tx_s_rstor_health.dds"); - setSpellStatus(65, 100); setEffect("icons\\s\\tx_s_chameleon.dds"); + unsetSelectedSpell(); + unsetSelectedWeapon(); + LocalMapBase::init(minimap, compass, this); mMainWidget->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onWorldClicked); @@ -153,28 +151,6 @@ void HUD::setBatchCount(size_t count) batchcounter->setCaption(boost::lexical_cast(count)); } -void HUD::setWeapIcon(const char *str) -{ - weapImage->setImageTexture(str); -} - -void HUD::setSpellIcon(const char *str) -{ - spellImage->setImageTexture(str); -} - -void HUD::setWeapStatus(int s, int smax) -{ - weapStatus->setProgressRange(smax); - weapStatus->setProgressPosition(s); -} - -void HUD::setSpellStatus(int s, int smax) -{ - spellStatus->setProgressRange(smax); - spellStatus->setProgressPosition(s); -} - void HUD::setEffect(const char *img) { effect1->setImageTexture(img); @@ -354,11 +330,150 @@ void HUD::setCellName(const std::string& cellName) void HUD::onFrame(float dt) { mCellNameTimer -= dt; + mWeaponSpellTimer -= dt; if (mCellNameTimer < 0) mCellNameBox->setVisible(false); + if (mWeaponSpellTimer < 0) + mWeaponSpellBox->setVisible(false); } void HUD::onResChange(int width, int height) { setCoord(0, 0, width, height); } + +void HUD::setSelectedSpell(const std::string& spellId, int successChancePercent) +{ + const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().spells.find(spellId); + std::string spellName = spell->name; + if (spellName != mSpellName) + { + mWeaponSpellTimer = 5.0f; + mSpellName = spellName; + mWeaponSpellBox->setCaption(mSpellName); + mWeaponSpellBox->setVisible(true); + } + + spellStatus->setProgressRange(100); + spellStatus->setProgressPosition(successChancePercent); + + if (spellImage->getChildCount()) + MyGUI::Gui::getInstance().destroyWidget(spellImage->getChildAt(0)); + + spellBox->setUserString("ToolTipType", "Spell"); + spellBox->setUserString("Spell", spellId); + + // use the icon of the first effect + const ESM::MagicEffect* effect = MWBase::Environment::get().getWorld()->getStore().magicEffects.find(spell->effects.list.front().effectID); + std::string icon = effect->icon; + int slashPos = icon.find("\\"); + icon.insert(slashPos+1, "b_"); + icon = std::string("icons\\") + icon; + Widgets::fixTexturePath(icon); + spellImage->setImageTexture(icon); +} + +void HUD::setSelectedEnchantItem(const MWWorld::Ptr& item, int chargePercent) +{ + std::string itemName = MWWorld::Class::get(item).getName(item); + if (itemName != mSpellName) + { + mWeaponSpellTimer = 5.0f; + mSpellName = itemName; + mWeaponSpellBox->setCaption(mSpellName); + mWeaponSpellBox->setVisible(true); + } + + spellStatus->setProgressRange(100); + spellStatus->setProgressPosition(chargePercent); + + if (spellImage->getChildCount()) + MyGUI::Gui::getInstance().destroyWidget(spellImage->getChildAt(0)); + + spellBox->setUserString("ToolTipType", "ItemPtr"); + spellBox->setUserData(item); + + spellImage->setImageTexture("textures\\menu_icon_magic_mini.dds"); + MyGUI::ImageBox* itemBox = spellImage->createWidgetReal("ImageBox", MyGUI::FloatCoord(0,0,1,1) + , MyGUI::Align::Stretch); + + std::string path = std::string("icons\\"); + path+=MWWorld::Class::get(item).getInventoryIcon(item); + Widgets::fixTexturePath(path); + itemBox->setImageTexture(path); + itemBox->setNeedMouseFocus(false); +} + +void HUD::setSelectedWeapon(const MWWorld::Ptr& item, int durabilityPercent) +{ + std::string itemName = MWWorld::Class::get(item).getName(item); + if (itemName != mWeaponName) + { + mWeaponSpellTimer = 5.0f; + mWeaponName = itemName; + mWeaponSpellBox->setCaption(mWeaponName); + mWeaponSpellBox->setVisible(true); + } + + weapBox->setUserString("ToolTipType", "ItemPtr"); + weapBox->setUserData(item); + + weapStatus->setProgressRange(100); + weapStatus->setProgressPosition(durabilityPercent); + + if (weapImage->getChildCount()) + MyGUI::Gui::getInstance().destroyWidget(weapImage->getChildAt(0)); + + std::string path = std::string("icons\\"); + path+=MWWorld::Class::get(item).getInventoryIcon(item); + Widgets::fixTexturePath(path); + + if (MWWorld::Class::get(item).getEnchantment(item) != "") + { + weapImage->setImageTexture("textures\\menu_icon_magic_mini.dds"); + MyGUI::ImageBox* itemBox = weapImage->createWidgetReal("ImageBox", MyGUI::FloatCoord(0,0,1,1) + , MyGUI::Align::Stretch); + itemBox->setImageTexture(path); + itemBox->setNeedMouseFocus(false); + } + else + weapImage->setImageTexture(path); +} + +void HUD::unsetSelectedSpell() +{ + std::string spellName = "#{sNone}"; + if (spellName != mSpellName) + { + mWeaponSpellTimer = 5.0f; + mSpellName = spellName; + mWeaponSpellBox->setCaptionWithReplacing(mSpellName); + mWeaponSpellBox->setVisible(true); + } + + if (spellImage->getChildCount()) + MyGUI::Gui::getInstance().destroyWidget(spellImage->getChildAt(0)); + spellStatus->setProgressRange(100); + spellStatus->setProgressPosition(0); + spellImage->setImageTexture(""); + spellBox->clearUserStrings(); +} + +void HUD::unsetSelectedWeapon() +{ + std::string itemName = "#{sSkillHandtohand}"; + if (itemName != mWeaponName) + { + mWeaponSpellTimer = 5.0f; + mWeaponName = itemName; + mWeaponSpellBox->setCaptionWithReplacing(mWeaponName); + mWeaponSpellBox->setVisible(true); + } + + if (weapImage->getChildCount()) + MyGUI::Gui::getInstance().destroyWidget(weapImage->getChildAt(0)); + weapStatus->setProgressRange(100); + weapStatus->setProgressPosition(0); + weapImage->setImageTexture("icons\\k\\stealth_handtohand.dds"); + weapBox->clearUserStrings(); +} diff --git a/apps/openmw/mwgui/hud.hpp b/apps/openmw/mwgui/hud.hpp index 6d4bf05594..f51110637c 100644 --- a/apps/openmw/mwgui/hud.hpp +++ b/apps/openmw/mwgui/hud.hpp @@ -3,6 +3,7 @@ #include #include "../mwmechanics/stat.hpp" +#include "../mwworld/ptr.hpp" namespace MWGui { @@ -12,10 +13,6 @@ namespace MWGui { public: HUD(int width, int height, int fpsLevel, DragAndDrop* dragAndDrop); - void setWeapIcon(const char *str); - void setSpellIcon(const char *str); - void setWeapStatus(int s, int smax); - void setSpellStatus(int s, int smax); void setEffect(const char *img); void setValue (const std::string& id, const MWMechanics::DynamicStat& value); void setFPS(float fps); @@ -25,6 +22,12 @@ namespace MWGui void setBottomRightVisibility(bool effectBoxVisible, bool minimapVisible); void setFpsLevel(const int level); + void setSelectedSpell(const std::string& spellId, int successChancePercent); + void setSelectedEnchantItem(const MWWorld::Ptr& item, int chargePercent); + void setSelectedWeapon(const MWWorld::Ptr& item, int durabilityPercent); + void unsetSelectedSpell(); + void unsetSelectedWeapon(); + void onFrame(float dt); void onResChange(int width, int height); @@ -41,6 +44,7 @@ namespace MWGui MyGUI::ImageBox* compass; MyGUI::ImageBox* crosshair; MyGUI::TextBox* mCellNameBox; + MyGUI::TextBox* mWeaponSpellBox; MyGUI::WidgetPtr fpsbox; MyGUI::TextBox* fpscounter; @@ -58,6 +62,10 @@ namespace MWGui std::string mCellName; float mCellNameTimer; + std::string mWeaponName; + std::string mSpellName; + float mWeaponSpellTimer; + bool mMapVisible; void onWorldClicked(MyGUI::Widget* _sender); diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index e1d4cc998a..103f5ebf3d 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -188,6 +188,15 @@ namespace MWGui mWindowManager.setDragDrop(false); drawItems(); + + // update selected weapon icon + MWWorld::InventoryStore& invStore = MWWorld::Class::get(mPtr).getInventoryStore(mPtr); + MWWorld::ContainerStoreIterator weaponSlot = invStore.getSlot(MWWorld::InventoryStore::Slot_CarriedRight); + if (weaponSlot == invStore.end()) + mWindowManager.unsetSelectedWeapon(); + else + mWindowManager.setSelectedWeapon(*weaponSlot, 100); /// \todo track weapon durability + } } @@ -266,5 +275,14 @@ namespace MWGui // update the spell window just in case new enchanted items were added to inventory if (mWindowManager.getSpellWindow()) mWindowManager.getSpellWindow()->updateSpells(); + + // update selected weapon icon + MWWorld::InventoryStore& invStore = MWWorld::Class::get(mPtr).getInventoryStore(mPtr); + MWWorld::ContainerStoreIterator weaponSlot = invStore.getSlot(MWWorld::InventoryStore::Slot_CarriedRight); + if (weaponSlot == invStore.end()) + mWindowManager.unsetSelectedWeapon(); + else + mWindowManager.setSelectedWeapon(*weaponSlot, 100); /// \todo track weapon durability + } } diff --git a/apps/openmw/mwgui/spellwindow.cpp b/apps/openmw/mwgui/spellwindow.cpp index 168578831f..aae3d878d2 100644 --- a/apps/openmw/mwgui/spellwindow.cpp +++ b/apps/openmw/mwgui/spellwindow.cpp @@ -110,6 +110,8 @@ namespace MWGui if (!allowSelectedItem) { store.setSelectedEnchantItem(store.end()); + spells.setSelectedSpell(""); + mWindowManager.unsetSelectedSpell(); selectedItem = MWWorld::Ptr(); } } @@ -366,12 +368,14 @@ namespace MWGui store.setSelectedEnchantItem(it); spells.setSelectedSpell(""); + mWindowManager.setSelectedEnchantItem(item, 100); /// \todo track charge % updateSpells(); } void SpellWindow::onSpellSelected(MyGUI::Widget* _sender) { + std::string spellId = _sender->getUserString("Spell"); MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); MWMechanics::CreatureStats& stats = MWWorld::Class::get(player).getCreatureStats(player); MWWorld::InventoryStore& store = MWWorld::Class::get(player).getInventoryStore(player); @@ -380,7 +384,7 @@ namespace MWGui if (MyGUI::InputManager::getInstance().isShiftPressed()) { // delete spell, if allowed - const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().spells.find(_sender->getUserString("Spell")); + const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().spells.find(spellId); if (spell->data.flags & ESM::Spell::F_Always || spell->data.type == ESM::Spell::ST_Power) { @@ -389,7 +393,7 @@ namespace MWGui else { // ask for confirmation - mSpellToDelete = _sender->getUserString("Spell"); + mSpellToDelete = spellId; ConfirmationDialog* dialog = mWindowManager.getConfirmationDialog(); std::string question = mWindowManager.getGameSettingString("sQuestionDeleteSpell", "Delete %s?"); question = boost::str(boost::format(question) % spell->name); @@ -401,8 +405,9 @@ namespace MWGui } else { - spells.setSelectedSpell(_sender->getUserString("Spell")); + spells.setSelectedSpell(spellId); store.setSelectedEnchantItem(store.end()); + mWindowManager.setSelectedSpell(spellId, int(MWMechanics::getSpellSuccessChance(spellId, player))); } updateSpells(); @@ -430,6 +435,12 @@ namespace MWGui MWMechanics::CreatureStats& stats = MWWorld::Class::get(player).getCreatureStats(player); MWMechanics::Spells& spells = stats.mSpells; + if (spells.getSelectedSpell() == mSpellToDelete) + { + spells.setSelectedSpell(""); + mWindowManager.unsetSelectedSpell(); + } + spells.remove(mSpellToDelete); updateSpells(); diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index dc34ee86cc..0f68921905 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -402,7 +402,6 @@ IntSize ToolTips::createToolTip(const MWGui::ToolTipInfo& info) TextBox* chargeText = enchantArea->createWidget("SandText", IntCoord(0, 0, 10, 18), Align::Default, "ToolTipEnchantChargeText"); chargeText->setCaption(store.gameSettings.search("sCharges")->str); - chargeText->setProperty("Static", "true"); const int chargeTextWidth = chargeText->getTextSize().width + 5; const int chargeAndTextWidth = chargeWidth + chargeTextWidth; diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index 0a12a82a08..2089ed4aff 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -104,6 +104,8 @@ namespace MWGui ContainerBase::openContainer(actor); updateLabels(); + + drawItems(); } void TradeWindow::onFilterChanged(MyGUI::Widget* _sender) diff --git a/apps/openmw/mwgui/window_manager.cpp b/apps/openmw/mwgui/window_manager.cpp index 4eaaf72a4b..bd1ad46b60 100644 --- a/apps/openmw/mwgui/window_manager.cpp +++ b/apps/openmw/mwgui/window_manager.cpp @@ -674,3 +674,28 @@ void WindowManager::removeGuiMode(GuiMode mode) updateVisible(); } + +void WindowManager::setSelectedSpell(const std::string& spellId, int successChancePercent) +{ + hud->setSelectedSpell(spellId, successChancePercent); +} + +void WindowManager::setSelectedEnchantItem(const MWWorld::Ptr& item, int chargePercent) +{ + hud->setSelectedEnchantItem(item, chargePercent); +} + +void WindowManager::setSelectedWeapon(const MWWorld::Ptr& item, int durabilityPercent) +{ + hud->setSelectedWeapon(item, durabilityPercent); +} + +void WindowManager::unsetSelectedSpell() +{ + hud->unsetSelectedSpell(); +} + +void WindowManager::unsetSelectedWeapon() +{ + hud->unsetSelectedWeapon(); +} diff --git a/apps/openmw/mwgui/window_manager.hpp b/apps/openmw/mwgui/window_manager.hpp index 2a7794f702..037022b42b 100644 --- a/apps/openmw/mwgui/window_manager.hpp +++ b/apps/openmw/mwgui/window_manager.hpp @@ -204,6 +204,12 @@ namespace MWGui void setWeaponVisibility(bool visible); void setSpellVisibility(bool visible); + void setSelectedSpell(const std::string& spellId, int successChancePercent); + void setSelectedEnchantItem(const MWWorld::Ptr& item, int chargePercent); + void setSelectedWeapon(const MWWorld::Ptr& item, int durabilityPercent); + void unsetSelectedSpell(); + void unsetSelectedWeapon(); + template void removeDialog(T*& dialog); ///< Casts to OEngine::GUI::Layout and calls removeDialog, then resets pointer to nullptr. void removeDialog(OEngine::GUI::Layout* dialog); ///< Hides dialog and schedules dialog to be deleted. diff --git a/apps/openmw/mwmechanics/spellsuccess.hpp b/apps/openmw/mwmechanics/spellsuccess.hpp index 532f9eb4ec..11ac7cda76 100644 --- a/apps/openmw/mwmechanics/spellsuccess.hpp +++ b/apps/openmw/mwmechanics/spellsuccess.hpp @@ -4,30 +4,14 @@ #include "../mwworld/ptr.hpp" #include "../mwworld/world.hpp" #include "../mwbase/environment.hpp" +#include "../mwmechanics/creaturestats.hpp" #include "npcstats.hpp" namespace MWMechanics { - // UESP wiki / Morrowind/Spells: - // Chance of success is (Spell's skill * 2 + Willpower / 5 + Luck / 10 - Spell cost - Sound magnitude) * (Current fatigue + Maximum Fatigue * 1.5) / Maximum fatigue * 2 - - /** - * @param spellId ID of spell - * @param actor calculate spell success chance for this actor (depends on actor's skills) - * @attention actor has to be an NPC and not a creature! - * @return success chance from 0 to 100 (in percent) - */ - float getSpellSuccessChance (const std::string& spellId, const MWWorld::Ptr& actor) + inline int spellSchoolToSkill(int school) { - const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().spells.find(spellId); - - if (spell->data.flags & ESM::Spell::F_Always) // spells with this flag always succeed (usually birthsign spells) - return 100.0; - - NpcStats& stats = MWWorld::Class::get(actor).getNpcStats(actor); - CreatureStats& creatureStats = MWWorld::Class::get(actor).getCreatureStats(actor); - std::map schoolSkillMap; // maps spell school to skill id schoolSkillMap[0] = 11; // alteration schoolSkillMap[1] = 13; // conjuration @@ -35,33 +19,65 @@ namespace MWMechanics schoolSkillMap[2] = 10; // destruction schoolSkillMap[4] = 14; // mysticism schoolSkillMap[5] = 15; // restoration + assert(schoolSkillMap.find(school) != schoolSkillMap.end()); + return schoolSkillMap[school]; + } + + inline int getSpellSchool(const std::string& spellId, const MWWorld::Ptr& actor) + { + const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().spells.find(spellId); + NpcStats& stats = MWWorld::Class::get(actor).getNpcStats(actor); // determine the spell's school // this is always the school where the player's respective skill is the least advanced // out of all the magic effects' schools const std::vector& effects = spell->effects.list; - int skill = -1; + int school = -1; int skillLevel = -1; for (std::vector::const_iterator it = effects.begin(); it != effects.end(); ++it) { const ESM::MagicEffect* effect = MWBase::Environment::get().getWorld()->getStore().magicEffects.find(it->effectID); - int school = effect->data.school; - assert(schoolSkillMap.find(school) != schoolSkillMap.end()); - int _skillLevel = stats.mSkill[schoolSkillMap[school]].getModified(); + int _school = effect->data.school; + int _skillLevel = stats.mSkill[spellSchoolToSkill(_school)].getModified(); - if (skill == -1) + if (school == -1) { - skill = schoolSkillMap[school]; + school = _school; skillLevel = _skillLevel; } else if (_skillLevel < skillLevel) { - skill = schoolSkillMap[school]; + school = _school; skillLevel = _skillLevel; } } + return school; + } + + + // UESP wiki / Morrowind/Spells: + // Chance of success is (Spell's skill * 2 + Willpower / 5 + Luck / 10 - Spell cost - Sound magnitude) * (Current fatigue + Maximum Fatigue * 1.5) / Maximum fatigue * 2 + /** + * @param spellId ID of spell + * @param actor calculate spell success chance for this actor (depends on actor's skills) + * @attention actor has to be an NPC and not a creature! + * @return success chance from 0 to 100 (in percent) + */ + inline float getSpellSuccessChance (const std::string& spellId, const MWWorld::Ptr& actor) + { + const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().spells.find(spellId); + + if (spell->data.flags & ESM::Spell::F_Always // spells with this flag always succeed (usually birthsign spells) + || spell->data.type == ESM::Spell::ST_Power) // powers always succeed, but can be cast only once per day + return 100.0; + + NpcStats& stats = MWWorld::Class::get(actor).getNpcStats(actor); + CreatureStats& creatureStats = MWWorld::Class::get(actor).getCreatureStats(actor); + + int skillLevel = stats.mSkill[getSpellSchool(spellId, actor)].getModified(); + // Sound magic effect (reduces spell casting chance) int soundMagnitude = creatureStats.mMagicEffects.get (MWMechanics::EffectKey (48)).mMagnitude; diff --git a/files/mygui/openmw_hud_layout.xml b/files/mygui/openmw_hud_layout.xml index d0026bf251..cf353a205e 100644 --- a/files/mygui/openmw_hud_layout.xml +++ b/files/mygui/openmw_hud_layout.xml @@ -28,6 +28,14 @@ + + + + + + + + From c5a685d11fead58106c62c30acb18f74c5f84f3e Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 29 May 2012 18:59:11 +0200 Subject: [PATCH 308/325] addition to last commit: show the selected weapon/spell names as inventory/spell window caption --- apps/openmw/mwgui/hud.cpp | 20 ++++++++++++-------- apps/openmw/mwgui/hud.hpp | 2 ++ apps/openmw/mwgui/spellwindow.cpp | 1 + apps/openmw/mwgui/window_manager.cpp | 9 +++++++++ libs/openengine/gui/layout.hpp | 2 +- 5 files changed, 25 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index 95017579bc..14212c2f9d 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -44,6 +44,8 @@ HUD::HUD(int width, int height, int fpsLevel, DragAndDrop* dragAndDrop) , mCellNameTimer(0.0f) , mCellNameBox(NULL) , mMapVisible(true) + , mWeaponVisible(true) + , mSpellVisible(true) { setCoord(0,0, width, height); @@ -101,9 +103,6 @@ HUD::HUD(int width, int height, int fpsLevel, DragAndDrop* dragAndDrop) setEffect("icons\\s\\tx_s_chameleon.dds"); - unsetSelectedSpell(); - unsetSelectedWeapon(); - LocalMapBase::init(minimap, compass, this); mMainWidget->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onWorldClicked); @@ -201,6 +200,11 @@ void HUD::setBottomLeftVisibility(bool hmsVisible, bool weapVisible, bool spellV if (!weapVisible) spellDx += spellBoxBaseLeft - weapBoxBaseLeft; + mWeaponVisible = weapVisible; + mSpellVisible = spellVisible; + if (!mWeaponVisible && !mSpellVisible) + mWeaponSpellBox->setVisible(false); + health->setVisible(hmsVisible); stamina->setVisible(hmsVisible); magicka->setVisible(hmsVisible); @@ -346,7 +350,7 @@ void HUD::setSelectedSpell(const std::string& spellId, int successChancePercent) { const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().spells.find(spellId); std::string spellName = spell->name; - if (spellName != mSpellName) + if (spellName != mSpellName && mSpellVisible) { mWeaponSpellTimer = 5.0f; mSpellName = spellName; @@ -376,7 +380,7 @@ void HUD::setSelectedSpell(const std::string& spellId, int successChancePercent) void HUD::setSelectedEnchantItem(const MWWorld::Ptr& item, int chargePercent) { std::string itemName = MWWorld::Class::get(item).getName(item); - if (itemName != mSpellName) + if (itemName != mSpellName && mSpellVisible) { mWeaponSpellTimer = 5.0f; mSpellName = itemName; @@ -407,7 +411,7 @@ void HUD::setSelectedEnchantItem(const MWWorld::Ptr& item, int chargePercent) void HUD::setSelectedWeapon(const MWWorld::Ptr& item, int durabilityPercent) { std::string itemName = MWWorld::Class::get(item).getName(item); - if (itemName != mWeaponName) + if (itemName != mWeaponName && mWeaponVisible) { mWeaponSpellTimer = 5.0f; mWeaponName = itemName; @@ -443,7 +447,7 @@ void HUD::setSelectedWeapon(const MWWorld::Ptr& item, int durabilityPercent) void HUD::unsetSelectedSpell() { std::string spellName = "#{sNone}"; - if (spellName != mSpellName) + if (spellName != mSpellName && mSpellVisible) { mWeaponSpellTimer = 5.0f; mSpellName = spellName; @@ -462,7 +466,7 @@ void HUD::unsetSelectedSpell() void HUD::unsetSelectedWeapon() { std::string itemName = "#{sSkillHandtohand}"; - if (itemName != mWeaponName) + if (itemName != mWeaponName && mWeaponVisible) { mWeaponSpellTimer = 5.0f; mWeaponName = itemName; diff --git a/apps/openmw/mwgui/hud.hpp b/apps/openmw/mwgui/hud.hpp index f51110637c..47bd93eef7 100644 --- a/apps/openmw/mwgui/hud.hpp +++ b/apps/openmw/mwgui/hud.hpp @@ -67,6 +67,8 @@ namespace MWGui float mWeaponSpellTimer; bool mMapVisible; + bool mWeaponVisible; + bool mSpellVisible; void onWorldClicked(MyGUI::Widget* _sender); void onWorldMouseOver(MyGUI::Widget* _sender, int x, int y); diff --git a/apps/openmw/mwgui/spellwindow.cpp b/apps/openmw/mwgui/spellwindow.cpp index aae3d878d2..04338aa114 100644 --- a/apps/openmw/mwgui/spellwindow.cpp +++ b/apps/openmw/mwgui/spellwindow.cpp @@ -47,6 +47,7 @@ namespace MWGui getWidget(mEffectBox, "EffectsBox"); setCoord(498, 300, 302, 300); + updateSpells(); mMainWidget->castType()->eventWindowChangeCoord += MyGUI::newDelegate(this, &SpellWindow::onWindowResize); diff --git a/apps/openmw/mwgui/window_manager.cpp b/apps/openmw/mwgui/window_manager.cpp index bd1ad46b60..8ddbfe9298 100644 --- a/apps/openmw/mwgui/window_manager.cpp +++ b/apps/openmw/mwgui/window_manager.cpp @@ -144,6 +144,9 @@ WindowManager::WindowManager( playerSkillValues.insert(std::make_pair(ESM::Skill::skillIds[i], MWMechanics::Stat())); } + unsetSelectedSpell(); + unsetSelectedWeapon(); + // Set up visibility updateVisible(); } @@ -678,24 +681,30 @@ void WindowManager::removeGuiMode(GuiMode mode) void WindowManager::setSelectedSpell(const std::string& spellId, int successChancePercent) { hud->setSelectedSpell(spellId, successChancePercent); + const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().spells.find(spellId); + mSpellWindow->setTitle(spell->name); } void WindowManager::setSelectedEnchantItem(const MWWorld::Ptr& item, int chargePercent) { hud->setSelectedEnchantItem(item, chargePercent); + mSpellWindow->setTitle(MWWorld::Class::get(item).getName(item)); } void WindowManager::setSelectedWeapon(const MWWorld::Ptr& item, int durabilityPercent) { hud->setSelectedWeapon(item, durabilityPercent); + mInventoryWindow->setTitle(MWWorld::Class::get(item).getName(item)); } void WindowManager::unsetSelectedSpell() { hud->unsetSelectedSpell(); + mSpellWindow->setTitle("#{sNone}"); } void WindowManager::unsetSelectedWeapon() { hud->unsetSelectedWeapon(); + mInventoryWindow->setTitle("#{sSkillHandtohand}"); } diff --git a/libs/openengine/gui/layout.hpp b/libs/openengine/gui/layout.hpp index d9eefe0510..e6feb3d0ed 100644 --- a/libs/openengine/gui/layout.hpp +++ b/libs/openengine/gui/layout.hpp @@ -118,7 +118,7 @@ namespace GUI void setTitle(const std::string& title) { // NOTE: this assume that mMainWidget is of type Window. - static_cast(mMainWidget)->setCaption(title); + static_cast(mMainWidget)->setCaptionWithReplacing(title); adjustWindowCaption(); } From 72bb7a2d2c987e97c65e11d8f79b89e0b546bf2f Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 30 May 2012 08:04:07 +0200 Subject: [PATCH 309/325] fix a typo --- apps/openmw/mwgui/spellwindow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/spellwindow.cpp b/apps/openmw/mwgui/spellwindow.cpp index 04338aa114..502754feb0 100644 --- a/apps/openmw/mwgui/spellwindow.cpp +++ b/apps/openmw/mwgui/spellwindow.cpp @@ -257,7 +257,7 @@ namespace MWGui std::string cost = boost::lexical_cast(enchant->data.cost); std::string charge = boost::lexical_cast(enchant->data.charge); /// \todo track current charge - if (enchant->data.type != ESM::Enchantment::CastOnce) + if (enchant->data.type == ESM::Enchantment::CastOnce) { // this is Morrowind behaviour cost = "100"; From 2c90654401aff4de56c057130fb9e917c2721b86 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 30 May 2012 09:21:41 +0200 Subject: [PATCH 310/325] fix a typo that caused a crash when trying to disable an already disabled object --- apps/openmw/mwworld/refdata.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/refdata.cpp b/apps/openmw/mwworld/refdata.cpp index 528f49c33e..e1c14b907e 100644 --- a/apps/openmw/mwworld/refdata.cpp +++ b/apps/openmw/mwworld/refdata.cpp @@ -123,7 +123,7 @@ namespace MWWorld void RefData::disable() { - mEnabled = true; + mEnabled = false; } ESM::Position& RefData::getPosition() From 36d26e0681260005843ae7bdd63c366157aef310 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 30 May 2012 15:52:39 +0200 Subject: [PATCH 311/325] set the camera orientation after using teleport doors --- apps/openmw/mwrender/player.cpp | 18 ++++++++++++++++++ apps/openmw/mwrender/player.hpp | 3 +++ apps/openmw/mwworld/player.cpp | 5 +++++ apps/openmw/mwworld/player.hpp | 3 +++ apps/openmw/mwworld/scene.cpp | 5 ++++- 5 files changed, 33 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/player.cpp b/apps/openmw/mwrender/player.cpp index 7ed921218b..d6baac4b5a 100644 --- a/apps/openmw/mwrender/player.cpp +++ b/apps/openmw/mwrender/player.cpp @@ -6,4 +6,22 @@ namespace MWRender Player::Player (Ogre::Camera *camera, Ogre::SceneNode* node) : mCamera (camera), mNode (node) {} + + void Player::setRot(float x, float y, float z) + { + Ogre::SceneNode *sceneNode = mNode; + Ogre::Node* yawNode = sceneNode->getChildIterator().getNext(); + Ogre::Node* pitchNode = yawNode->getChildIterator().getNext(); + + // we are only interested in X and Y rotation + + // Rotate around X axis + Ogre::Quaternion xr(Ogre::Radian(x), Ogre::Vector3::UNIT_X); + + // Rotate around Y axis + Ogre::Quaternion yr(Ogre::Radian(-z), Ogre::Vector3::UNIT_Y); + + pitchNode->setOrientation(xr); + yawNode->setOrientation(yr); + } } diff --git a/apps/openmw/mwrender/player.hpp b/apps/openmw/mwrender/player.hpp index 4306b8a95e..406bedb0aa 100644 --- a/apps/openmw/mwrender/player.hpp +++ b/apps/openmw/mwrender/player.hpp @@ -23,6 +23,9 @@ namespace MWRender Ogre::Camera *getCamera() { return mCamera; } + /// Set where the player is looking at. Uses Morrowind (euler) angles + void setRot(float x, float y, float z); + std::string getHandle() const { return mNode->getName(); } Ogre::SceneNode* getNode() {return mNode;} }; diff --git a/apps/openmw/mwworld/player.cpp b/apps/openmw/mwworld/player.cpp index 0b1483ff8f..91b030d1c8 100644 --- a/apps/openmw/mwworld/player.cpp +++ b/apps/openmw/mwworld/player.cpp @@ -40,6 +40,11 @@ namespace MWWorld mWorld.moveObject (getPlayer(), x, y, z); } + void Player::setRot(float x, float y, float z) + { + mRenderer->setRot(x, y, z); + } + void Player::setClass (const ESM::Class& class_) { ESM::Class *new_class = new ESM::Class (class_); diff --git a/apps/openmw/mwworld/player.hpp b/apps/openmw/mwworld/player.hpp index e199f17e98..166d4cfee0 100644 --- a/apps/openmw/mwworld/player.hpp +++ b/apps/openmw/mwworld/player.hpp @@ -42,6 +42,9 @@ namespace MWWorld /// Set the player position. Uses Morrowind coordinates. void setPos(float x, float y, float z); + /// Set where the player is looking at. Uses Morrowind (euler) angles + void setRot(float x, float y, float z); + void setCell (MWWorld::Ptr::CellStore *cellStore) { mCellStore = cellStore; diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 47238ee719..a47137d257 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -145,10 +145,13 @@ namespace MWWorld bool hasWater = cell->cell->data.flags & cell->cell->HasWater; mPhysics->setCurrentWater(hasWater, cell->cell->water); if (adjustPlayerPos) + { mWorld->getPlayer().setPos (position.pos[0], position.pos[1], position.pos[2]); + mWorld->getPlayer().setRot (position.rot[0], position.rot[1], position.rot[2]); + } mWorld->getPlayer().setCell (cell); - // TODO orientation + MWBase::Environment::get().getMechanicsManager()->addActor (mWorld->getPlayer().getPlayer()); MWBase::Environment::get().getMechanicsManager()->watchActor (mWorld->getPlayer().getPlayer()); From a9a582f858ef272f048bcdcb96934ea1e1a53573 Mon Sep 17 00:00:00 2001 From: Edmondo Tommasina Date: Wed, 30 May 2012 23:18:59 +0200 Subject: [PATCH 312/325] renderer.cpp: fix std::runtime_error compile error --- libs/openengine/ogre/renderer.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libs/openengine/ogre/renderer.cpp b/libs/openengine/ogre/renderer.cpp index b525e76e38..a5eca76ed8 100644 --- a/libs/openengine/ogre/renderer.cpp +++ b/libs/openengine/ogre/renderer.cpp @@ -10,6 +10,7 @@ #include "OgreHardwarePixelBuffer.h" #include +#include using namespace Ogre; using namespace OEngine::Render; From 0ba0b2122e3ac3505d2b90a82784cd13fd3d48aa Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 2 Jun 2012 12:25:24 +0200 Subject: [PATCH 313/325] set the implicit object for script excution by clicking on it --- apps/openmw/mwgui/console.cpp | 12 +- apps/openmw/mwgui/console.hpp | 16 +- apps/openmw/mwgui/hud.cpp | 32 ++- apps/openmw/mwgui/hud.hpp | 4 + apps/openmw/mwgui/tooltips.cpp | 297 ++++++++++++++------------ apps/openmw/mwgui/window_manager.cpp | 23 ++ apps/openmw/mwgui/window_manager.hpp | 4 + apps/openmw/mwworld/physicssystem.cpp | 26 ++- apps/openmw/mwworld/physicssystem.hpp | 3 + apps/openmw/mwworld/world.cpp | 30 ++- 10 files changed, 308 insertions(+), 139 deletions(-) diff --git a/apps/openmw/mwgui/console.cpp b/apps/openmw/mwgui/console.cpp index bf80a77b2f..c9ba752e94 100644 --- a/apps/openmw/mwgui/console.cpp +++ b/apps/openmw/mwgui/console.cpp @@ -240,7 +240,7 @@ namespace MWGui { try { - ConsoleInterpreterContext interpreterContext (*this, MWWorld::Ptr()); + ConsoleInterpreterContext interpreterContext (*this, mPtr); Interpreter::Interpreter interpreter; MWScript::installOpcodes (interpreter); std::vector code; @@ -375,4 +375,14 @@ namespace MWGui { setCoord(10,10, width-10, height/2); } + + void Console::setSelectedObject(const MWWorld::Ptr& object) + { + mPtr = object; + } + + void Console::onReferenceUnavailable() + { + mPtr = MWWorld::Ptr(); + } } diff --git a/apps/openmw/mwgui/console.hpp b/apps/openmw/mwgui/console.hpp index 1172858473..eadf4aa4ea 100644 --- a/apps/openmw/mwgui/console.hpp +++ b/apps/openmw/mwgui/console.hpp @@ -16,9 +16,11 @@ #include "../mwscript/compilercontext.hpp" #include "../mwscript/interpretercontext.hpp" +#include "referenceinterface.hpp" + namespace MWGui { - class Console : private OEngine::GUI::Layout, private Compiler::ErrorHandler + class Console : private OEngine::GUI::Layout, private Compiler::ErrorHandler, public ReferenceInterface { private: @@ -39,7 +41,17 @@ namespace MWGui /// \note The list may contain duplicates (if a name is a keyword and an identifier at the same /// time). - public: + public: + + void setSelectedObject(const MWWorld::Ptr& object); + ///< Set the implicit object for script execution + + protected: + + virtual void onReferenceUnavailable(); + + + public: MyGUI::EditPtr command; MyGUI::EditPtr history; diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index 14212c2f9d..2f275cd330 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -14,6 +14,7 @@ #include "window_manager.hpp" #include "container.hpp" +#include "console.hpp" using namespace MWGui; @@ -46,6 +47,7 @@ HUD::HUD(int width, int height, int fpsLevel, DragAndDrop* dragAndDrop) , mMapVisible(true) , mWeaponVisible(true) , mSpellVisible(true) + , mWorldMouseOver(false) { setCoord(0,0, width, height); @@ -265,12 +267,39 @@ void HUD::onWorldClicked(MyGUI::Widget* _sender) MWBase::Environment::get().getWindowManager()->setDragDrop(false); } + else + { + GuiMode mode = MWBase::Environment::get().getWindowManager()->getMode(); + + if ( (mode != GM_Console) && (mode != GM_Container) && (mode != GM_Inventory) ) + return; + + std::string handle = MWBase::Environment::get().getWorld()->getFacedHandle(); + MWWorld::Ptr object; + try + { + object = MWBase::Environment::get().getWorld()->getPtrViaHandle(handle); + } + catch (std::exception& e) + { + return; + } + + if (mode == GM_Console) + MWBase::Environment::get().getWindowManager()->getConsole()->setSelectedObject(object); + else if (mode == GM_Console || GM_Inventory) + { + // pick up object + } + } } void HUD::onWorldMouseOver(MyGUI::Widget* _sender, int x, int y) { if (mDragAndDrop->mIsOnDragAndDrop) { + mWorldMouseOver = false; + MyGUI::IntSize viewSize = MyGUI::RenderManager::getInstance().getViewSize(); MyGUI::IntPoint cursorPosition = MyGUI::InputManager::getInstance().getMousePosition(); float mouseX = cursorPosition.left / float(viewSize.width); @@ -290,13 +319,14 @@ void HUD::onWorldMouseOver(MyGUI::Widget* _sender, int x, int y) else { MyGUI::PointerManager::getInstance().setPointer("arrow"); - /// \todo make it possible to pick up objects with the mouse, if inventory or container window is open + mWorldMouseOver = true; } } void HUD::onWorldMouseLostFocus(MyGUI::Widget* _sender, MyGUI::Widget* _new) { MyGUI::PointerManager::getInstance().setPointer("arrow"); + mWorldMouseOver = false; } void HUD::onHMSClicked(MyGUI::Widget* _sender) diff --git a/apps/openmw/mwgui/hud.hpp b/apps/openmw/mwgui/hud.hpp index 47bd93eef7..0bfe5c20f2 100644 --- a/apps/openmw/mwgui/hud.hpp +++ b/apps/openmw/mwgui/hud.hpp @@ -33,6 +33,8 @@ namespace MWGui void setCellName(const std::string& cellName); + bool getWorldMouseOver() { return mWorldMouseOver; } + MyGUI::ProgressPtr health, magicka, stamina; MyGUI::Widget* mHealthFrame; MyGUI::Widget *weapBox, *spellBox; @@ -70,6 +72,8 @@ namespace MWGui bool mWeaponVisible; bool mSpellVisible; + bool mWorldMouseOver; + void onWorldClicked(MyGUI::Widget* _sender); void onWorldMouseOver(MyGUI::Widget* _sender, int x, int y); void onWorldMouseLostFocus(MyGUI::Widget* _sender, MyGUI::Widget* _new); diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 0f68921905..1f614d56b3 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -67,158 +67,193 @@ void ToolTips::onFrame(float frameDuration) if (!mGameMode) { const MyGUI::IntPoint& mousePos = InputManager::getInstance().getMousePosition(); - const MyGUI::IntPoint& lastPressed = InputManager::getInstance().getLastPressedPosition(MyGUI::MouseButton::Left); - if (mousePos == lastPressed) // mouseclick makes tooltip disappear - return; - - if (mousePos.left == mLastMouseX && mousePos.top == mLastMouseY) + if (mWindowManager->getWorldMouseOver() && ((mWindowManager->getMode() == GM_Console) + || (mWindowManager->getMode() == GM_Container) + || (mWindowManager->getMode() == GM_Inventory))) { - mRemainingDelay -= frameDuration; + std::string handle = MWBase::Environment::get().getWorld()->getFacedHandle(); + try + { + mFocusObject = MWBase::Environment::get().getWorld()->getPtrViaHandle(handle); + } + catch (std::exception& e) + { + return; + } + + MyGUI::IntSize tooltipSize = getToolTipViaPtr(true); + + IntPoint tooltipPosition = InputManager::getInstance().getMousePosition() + IntPoint(0, 24); + + // make the tooltip stay completely in the viewport + if ((tooltipPosition.left + tooltipSize.width) > viewSize.width) + { + tooltipPosition.left = viewSize.width - tooltipSize.width; + } + if ((tooltipPosition.top + tooltipSize.height) > viewSize.height) + { + tooltipPosition.top = viewSize.height - tooltipSize.height; + } + + setCoord(tooltipPosition.left, tooltipPosition.top, tooltipSize.width, tooltipSize.height); } + else { - mRemainingDelay = mDelay; - } - mLastMouseX = mousePos.left; - mLastMouseY = mousePos.top; + const MyGUI::IntPoint& lastPressed = InputManager::getInstance().getLastPressedPosition(MyGUI::MouseButton::Left); - if (mRemainingDelay > 0) - return; - - Widget* focus = InputManager::getInstance().getMouseFocusWidget(); - if (focus == 0) - { - return; - } - - IntSize tooltipSize; - - // try to go 1 level up until there is a widget that has tooltip - // this is necessary because some skin elements are actually separate widgets - int i=0; - while (!focus->isUserString("ToolTipType")) - { - focus = focus->getParent(); - if (!focus) + if (mousePos == lastPressed) // mouseclick makes tooltip disappear return; - ++i; - } - std::string type = focus->getUserString("ToolTipType"); - std::string text = focus->getUserString("ToolTipText"); - - ToolTipInfo info; - if (type == "") - { - return; - } - else if (type == "ItemPtr") - { - mFocusObject = *focus->getUserData(); - tooltipSize = getToolTipViaPtr(false); - } - else if (type == "Spell") - { - ToolTipInfo info; - const ESM::Spell *spell = MWBase::Environment::get().getWorld()->getStore().spells.find(focus->getUserString("Spell")); - info.caption = spell->name; - Widgets::SpellEffectList effects; - std::vector::const_iterator end = spell->effects.list.end(); - for (std::vector::const_iterator it = spell->effects.list.begin(); it != end; ++it) + if (mousePos.left == mLastMouseX && mousePos.top == mLastMouseY) { - Widgets::SpellEffectParams params; - params.mEffectID = it->effectID; - params.mSkill = it->skill; - params.mAttribute = it->attribute; - params.mDuration = it->duration; - params.mMagnMin = it->magnMin; - params.mMagnMax = it->magnMax; - params.mRange = it->range; - params.mIsConstant = (spell->data.type == ESM::Spell::ST_Ability); - effects.push_back(params); - } - info.effects = effects; - tooltipSize = createToolTip(info); - } - else if (type == "Layout") - { - // tooltip defined in the layout - MyGUI::Widget* tooltip; - getWidget(tooltip, focus->getUserString("ToolTipLayout")); - - tooltip->setVisible(true); - if (!tooltip->isUserString("DontResize")) - { - tooltip->setCoord(0, 0, 450, 300); // this is the maximum width of the tooltip before it starts word-wrapping - - tooltipSize = MyGUI::IntSize(0, tooltip->getSize().height); + mRemainingDelay -= frameDuration; } else - tooltipSize = tooltip->getSize(); - - std::map userStrings = focus->getUserStrings(); - for (std::map::iterator it = userStrings.begin(); - it != userStrings.end(); ++it) { - if (it->first == "ToolTipType" - || it->first == "ToolTipLayout") - continue; + mRemainingDelay = mDelay; + } + mLastMouseX = mousePos.left; + mLastMouseY = mousePos.top; + if (mRemainingDelay > 0) + return; - size_t underscorePos = it->first.find("_"); - std::string propertyKey = it->first.substr(0, underscorePos); - std::string widgetName = it->first.substr(underscorePos+1, it->first.size()-(underscorePos+1)); - - MyGUI::Widget* w; - getWidget(w, widgetName); - w->setProperty(propertyKey, it->second); + Widget* focus = InputManager::getInstance().getMouseFocusWidget(); + if (focus == 0) + { + return; } - for (unsigned int i=0; igetChildCount(); ++i) + IntSize tooltipSize; + + // try to go 1 level up until there is a widget that has tooltip + // this is necessary because some skin elements are actually separate widgets + int i=0; + while (!focus->isUserString("ToolTipType")) { - MyGUI::Widget* w = tooltip->getChildAt(i); - - if (w->isUserString("AutoResizeHorizontal")) - { - MyGUI::TextBox* text = w->castType(); - tooltipSize.width = std::max(tooltipSize.width, w->getLeft() + text->getTextSize().width + 8); - } - else if (!tooltip->isUserString("DontResize")) - tooltipSize.width = std::max(tooltipSize.width, w->getLeft() + w->getWidth() + 8); - - if (w->isUserString("AutoResizeVertical")) - { - MyGUI::TextBox* text = w->castType(); - int height = text->getTextSize().height; - if (height > w->getHeight()) - { - tooltipSize += MyGUI::IntSize(0, height - w->getHeight()); - } - if (height < w->getHeight()) - { - tooltipSize -= MyGUI::IntSize(0, w->getHeight() - height); - } - } + focus = focus->getParent(); + if (!focus) + return; + ++i; } - tooltip->setCoord(0, 0, tooltipSize.width, tooltipSize.height); - } - else - throw std::runtime_error ("unknown tooltip type"); - IntPoint tooltipPosition = InputManager::getInstance().getMousePosition() + IntPoint(0, 24); + std::string type = focus->getUserString("ToolTipType"); + std::string text = focus->getUserString("ToolTipText"); - // make the tooltip stay completely in the viewport - if ((tooltipPosition.left + tooltipSize.width) > viewSize.width) - { - tooltipPosition.left = viewSize.width - tooltipSize.width; - } - if ((tooltipPosition.top + tooltipSize.height) > viewSize.height) - { - tooltipPosition.top = viewSize.height - tooltipSize.height; - } + ToolTipInfo info; + if (type == "") + { + return; + } + else if (type == "ItemPtr") + { + mFocusObject = *focus->getUserData(); + tooltipSize = getToolTipViaPtr(false); + } + else if (type == "Spell") + { + ToolTipInfo info; + const ESM::Spell *spell = MWBase::Environment::get().getWorld()->getStore().spells.find(focus->getUserString("Spell")); + info.caption = spell->name; + Widgets::SpellEffectList effects; + std::vector::const_iterator end = spell->effects.list.end(); + for (std::vector::const_iterator it = spell->effects.list.begin(); it != end; ++it) + { + Widgets::SpellEffectParams params; + params.mEffectID = it->effectID; + params.mSkill = it->skill; + params.mAttribute = it->attribute; + params.mDuration = it->duration; + params.mMagnMin = it->magnMin; + params.mMagnMax = it->magnMax; + params.mRange = it->range; + params.mIsConstant = (spell->data.type == ESM::Spell::ST_Ability); + effects.push_back(params); + } + info.effects = effects; + tooltipSize = createToolTip(info); + } + else if (type == "Layout") + { + // tooltip defined in the layout + MyGUI::Widget* tooltip; + getWidget(tooltip, focus->getUserString("ToolTipLayout")); - setCoord(tooltipPosition.left, tooltipPosition.top, tooltipSize.width, tooltipSize.height); + tooltip->setVisible(true); + if (!tooltip->isUserString("DontResize")) + { + tooltip->setCoord(0, 0, 450, 300); // this is the maximum width of the tooltip before it starts word-wrapping + + tooltipSize = MyGUI::IntSize(0, tooltip->getSize().height); + } + else + tooltipSize = tooltip->getSize(); + + std::map userStrings = focus->getUserStrings(); + for (std::map::iterator it = userStrings.begin(); + it != userStrings.end(); ++it) + { + if (it->first == "ToolTipType" + || it->first == "ToolTipLayout") + continue; + + + size_t underscorePos = it->first.find("_"); + std::string propertyKey = it->first.substr(0, underscorePos); + std::string widgetName = it->first.substr(underscorePos+1, it->first.size()-(underscorePos+1)); + + MyGUI::Widget* w; + getWidget(w, widgetName); + w->setProperty(propertyKey, it->second); + } + + for (unsigned int i=0; igetChildCount(); ++i) + { + MyGUI::Widget* w = tooltip->getChildAt(i); + + if (w->isUserString("AutoResizeHorizontal")) + { + MyGUI::TextBox* text = w->castType(); + tooltipSize.width = std::max(tooltipSize.width, w->getLeft() + text->getTextSize().width + 8); + } + else if (!tooltip->isUserString("DontResize")) + tooltipSize.width = std::max(tooltipSize.width, w->getLeft() + w->getWidth() + 8); + + if (w->isUserString("AutoResizeVertical")) + { + MyGUI::TextBox* text = w->castType(); + int height = text->getTextSize().height; + if (height > w->getHeight()) + { + tooltipSize += MyGUI::IntSize(0, height - w->getHeight()); + } + if (height < w->getHeight()) + { + tooltipSize -= MyGUI::IntSize(0, w->getHeight() - height); + } + } + } + tooltip->setCoord(0, 0, tooltipSize.width, tooltipSize.height); + } + else + throw std::runtime_error ("unknown tooltip type"); + + IntPoint tooltipPosition = InputManager::getInstance().getMousePosition() + IntPoint(0, 24); + + // make the tooltip stay completely in the viewport + if ((tooltipPosition.left + tooltipSize.width) > viewSize.width) + { + tooltipPosition.left = viewSize.width - tooltipSize.width; + } + if ((tooltipPosition.top + tooltipSize.height) > viewSize.height) + { + tooltipPosition.top = viewSize.height - tooltipSize.height; + } + + setCoord(tooltipPosition.left, tooltipPosition.top, tooltipSize.width, tooltipSize.height); + } } else { diff --git a/apps/openmw/mwgui/window_manager.cpp b/apps/openmw/mwgui/window_manager.cpp index 8ddbfe9298..5275ae19d9 100644 --- a/apps/openmw/mwgui/window_manager.cpp +++ b/apps/openmw/mwgui/window_manager.cpp @@ -487,6 +487,7 @@ void WindowManager::onFrame (float frameDuration) mDialogueWindow->checkReferenceAvailable(); mTradeWindow->checkReferenceAvailable(); mContainerWindow->checkReferenceAvailable(); + console->checkReferenceAvailable(); } const ESMS::ESMStore& WindowManager::getStore() const @@ -708,3 +709,25 @@ void WindowManager::unsetSelectedWeapon() hud->unsetSelectedWeapon(); mInventoryWindow->setTitle("#{sSkillHandtohand}"); } + +void WindowManager::getMousePosition(int &x, int &y) +{ + const MyGUI::IntPoint& pos = MyGUI::InputManager::getInstance().getMousePosition(); + x = pos.left; + y = pos.top; +} + +void WindowManager::getMousePosition(float &x, float &y) +{ + const MyGUI::IntPoint& pos = MyGUI::InputManager::getInstance().getMousePosition(); + x = pos.left; + y = pos.top; + const MyGUI::IntSize& viewSize = MyGUI::RenderManager::getInstance().getViewSize(); + x /= viewSize.width; + y /= viewSize.height; +} + +bool WindowManager::getWorldMouseOver() +{ + return hud->getWorldMouseOver(); +} diff --git a/apps/openmw/mwgui/window_manager.hpp b/apps/openmw/mwgui/window_manager.hpp index 037022b42b..19ad7702a4 100644 --- a/apps/openmw/mwgui/window_manager.hpp +++ b/apps/openmw/mwgui/window_manager.hpp @@ -155,6 +155,7 @@ namespace MWGui MWGui::ConfirmationDialog* getConfirmationDialog() {return mConfirmationDialog;} MWGui::TradeWindow* getTradeWindow() {return mTradeWindow;} MWGui::SpellWindow* getSpellWindow() {return mSpellWindow;} + MWGui::Console* getConsole() {return console;} MyGUI::Gui* getGui() const { return gui; } @@ -188,7 +189,10 @@ namespace MWGui void setFocusObjectScreenCoords(float min_x, float min_y, float max_x, float max_y); void setMouseVisible(bool visible); + void getMousePosition(int &x, int &y); + void getMousePosition(float &x, float &y); void setDragDrop(bool dragDrop); + bool getWorldMouseOver(); void toggleFogOfWar(); void toggleFullHelp(); ///< show extra info in item tooltips (owner, script) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 808c712a07..5598ff3c0b 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -66,7 +66,23 @@ namespace MWWorld return mEngine->rayTest2(from,to); } - void PhysicsSystem::setCurrentWater(bool hasWater, int waterHeight){ + + std::vector < std::pair > PhysicsSystem::getFacedObjects (float mouseX, float mouseY) + { + Ray ray = mRender.getCamera()->getCameraToViewportRay(mouseX, mouseY); + Ogre::Vector3 from = ray.getOrigin(); + Ogre::Vector3 to = ray.getPoint(500); /// \todo make this distance (ray length) configurable + + btVector3 _from, _to; + // OGRE to MW coordinates + _from = btVector3(from.x, -from.z, from.y); + _to = btVector3(to.x, -to.z, to.y); + + return mEngine->rayTest2(_from,_to); + } + + void PhysicsSystem::setCurrentWater(bool hasWater, int waterHeight) + { playerphysics->hasWater = hasWater; if(hasWater){ playerphysics->waterHeight = waterHeight; @@ -84,6 +100,14 @@ namespace MWWorld return result; } + btVector3 PhysicsSystem::getRayPoint(float extent, float mouseX, float mouseY) + { + //get a ray pointing to the center of the viewport + Ray centerRay = mRender.getCamera()->getCameraToViewportRay(mouseX, mouseY); + btVector3 result(centerRay.getPoint(500*extent).x,-centerRay.getPoint(500*extent).z,centerRay.getPoint(500*extent).y); /// \todo make this distance (ray length) configurable + return result; + } + bool PhysicsSystem::castRay(const Vector3& from, const Vector3& to) { btVector3 _from, _to; diff --git a/apps/openmw/mwworld/physicssystem.hpp b/apps/openmw/mwworld/physicssystem.hpp index 9b03d2124f..1a8bd87ae4 100644 --- a/apps/openmw/mwworld/physicssystem.hpp +++ b/apps/openmw/mwworld/physicssystem.hpp @@ -47,9 +47,12 @@ namespace MWWorld std::pair getFacedHandle (MWWorld::World& world); btVector3 getRayPoint(float extent); + btVector3 getRayPoint(float extent, float mouseX, float mouseY); std::vector < std::pair > getFacedObjects (); + std::vector < std::pair > getFacedObjects (float mouseX, float mouseY); + // cast ray, return true if it hit something bool castRay(const Ogre::Vector3& from, const Ogre::Vector3& to); diff --git a/apps/openmw/mwworld/world.cpp b/apps/openmw/mwworld/world.cpp index 6802d5cc12..e8d555689d 100644 --- a/apps/openmw/mwworld/world.cpp +++ b/apps/openmw/mwworld/world.cpp @@ -818,7 +818,15 @@ namespace MWWorld // send new query // figure out which object we want to test against - std::vector < std::pair < float, std::string > > results = mPhysics->getFacedObjects(); + std::vector < std::pair < float, std::string > > results; + if (MWBase::Environment::get().getWindowManager()->isGuiMode()) + { + float x, y; + MWBase::Environment::get().getWindowManager()->getMousePosition(x, y); + results = mPhysics->getFacedObjects(x, y); + } + else + results = mPhysics->getFacedObjects(); // ignore the player and other things we're not interested in std::vector < std::pair < float, std::string > >::iterator it = results.begin(); @@ -843,7 +851,15 @@ namespace MWWorld mFaced1Name = results.front().second; mNumFacing = 1; - btVector3 p = mPhysics->getRayPoint(results.front().first); + btVector3 p; + if (MWBase::Environment::get().getWindowManager()->isGuiMode()) + { + float x, y; + MWBase::Environment::get().getWindowManager()->getMousePosition(x, y); + p = mPhysics->getRayPoint(results.front().first, x, y); + } + else + p = mPhysics->getRayPoint(results.front().first); Ogre::Vector3 pos(p.x(), p.z(), -p.y()); Ogre::SceneNode* node = mFaced1.getRefData().getBaseNode(); @@ -860,7 +876,15 @@ namespace MWWorld mFaced2 = getPtrViaHandle(results[1].second); mNumFacing = 2; - btVector3 p = mPhysics->getRayPoint(results[1].first); + btVector3 p; + if (MWBase::Environment::get().getWindowManager()->isGuiMode()) + { + float x, y; + MWBase::Environment::get().getWindowManager()->getMousePosition(x, y); + p = mPhysics->getRayPoint(results[1].first, x, y); + } + else + p = mPhysics->getRayPoint(results[1].first); Ogre::Vector3 pos(p.x(), p.z(), -p.y()); Ogre::SceneNode* node1 = mFaced1.getRefData().getBaseNode(); Ogre::SceneNode* node2 = mFaced2.getRefData().getBaseNode(); From b886aea2989e0a5276bf637c4328372a43117377 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 2 Jun 2012 12:31:23 +0200 Subject: [PATCH 314/325] change console skin to MW_Window and set the selected object refID as window title --- apps/openmw/mwgui/console.cpp | 2 ++ files/mygui/openmw_console.skin.xml | 35 --------------------------- files/mygui/openmw_console_layout.xml | 8 +++--- 3 files changed, 6 insertions(+), 39 deletions(-) diff --git a/apps/openmw/mwgui/console.cpp b/apps/openmw/mwgui/console.cpp index c9ba752e94..25cd90eaef 100644 --- a/apps/openmw/mwgui/console.cpp +++ b/apps/openmw/mwgui/console.cpp @@ -379,10 +379,12 @@ namespace MWGui void Console::setSelectedObject(const MWWorld::Ptr& object) { mPtr = object; + setTitle("#{sConsoleTitle} (" + mPtr.getCellRef().refID + ")"); } void Console::onReferenceUnavailable() { mPtr = MWWorld::Ptr(); + setTitle("#{sConsoleTitle}"); } } diff --git a/files/mygui/openmw_console.skin.xml b/files/mygui/openmw_console.skin.xml index 598252734f..1758c728de 100644 --- a/files/mygui/openmw_console.skin.xml +++ b/files/mygui/openmw_console.skin.xml @@ -1,41 +1,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/files/mygui/openmw_console_layout.xml b/files/mygui/openmw_console_layout.xml index a2b883cdb5..732684ad12 100644 --- a/files/mygui/openmw_console_layout.xml +++ b/files/mygui/openmw_console_layout.xml @@ -1,17 +1,17 @@  - - + + - + - + From b8464d4ce50c4852a9b2375cf684582baa5f7331 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 2 Jun 2012 14:19:02 +0200 Subject: [PATCH 315/325] allow picking up objects from the gameworld with the mouse in inventory mode --- apps/openmw/mwgui/console.cpp | 9 ++-- apps/openmw/mwgui/container.cpp | 2 +- apps/openmw/mwgui/hud.cpp | 5 +- apps/openmw/mwgui/inventorywindow.cpp | 68 ++++++++++++++++++++++++--- apps/openmw/mwgui/inventorywindow.hpp | 2 + apps/openmw/mwgui/spellwindow.cpp | 10 ++++ apps/openmw/mwgui/tradewindow.cpp | 2 + apps/openmw/mwgui/window_manager.cpp | 1 + 8 files changed, 87 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwgui/console.cpp b/apps/openmw/mwgui/console.cpp index 25cd90eaef..2f8a953069 100644 --- a/apps/openmw/mwgui/console.cpp +++ b/apps/openmw/mwgui/console.cpp @@ -138,6 +138,7 @@ namespace MWGui void Console::disable() { setVisible(false); + setSelectedObject(MWWorld::Ptr()); // Remove keyboard focus from the console input whenever the // console is turned off MyGUI::InputManager::getInstance().setKeyFocusWidget(NULL); @@ -379,12 +380,14 @@ namespace MWGui void Console::setSelectedObject(const MWWorld::Ptr& object) { mPtr = object; - setTitle("#{sConsoleTitle} (" + mPtr.getCellRef().refID + ")"); + if (!mPtr.isEmpty()) + setTitle("#{sConsoleTitle} (" + mPtr.getCellRef().refID + ")"); + else + setTitle("#{sConsoleTitle}"); } void Console::onReferenceUnavailable() { - mPtr = MWWorld::Ptr(); - setTitle("#{sConsoleTitle}"); + setSelectedObject(MWWorld::Ptr()); } } diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index bf6b4add04..eb5cbc92b3 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -470,7 +470,7 @@ void ContainerBase::drawItems() if(displayCount > 0 && !(onlyMagic && it->second != ItemState_Barter && MWWorld::Class::get(*iter).getEnchantment(*iter) == "" && iter->getTypeName() != typeid(ESM::Potion).name())) { std::string path = std::string("icons\\"); - path+=MWWorld::Class::get(*iter).getInventoryIcon(*iter); + path += MWWorld::Class::get(*iter).getInventoryIcon(*iter); // background widget (for the "equipped" frame and magic item background image) bool isMagic = (MWWorld::Class::get(*iter).getEnchantment(*iter) != ""); diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index 2f275cd330..95d66eb81d 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -12,6 +12,7 @@ #include "../mwworld/world.hpp" #include "../mwworld/player.hpp" +#include "inventorywindow.hpp" #include "window_manager.hpp" #include "container.hpp" #include "console.hpp" @@ -266,6 +267,7 @@ void HUD::onWorldClicked(MyGUI::Widget* _sender) mDragAndDrop->mDraggedWidget = 0; MWBase::Environment::get().getWindowManager()->setDragDrop(false); + MWBase::Environment::get().getWindowManager()->getInventoryWindow()->drawItems(); } else { @@ -287,9 +289,10 @@ void HUD::onWorldClicked(MyGUI::Widget* _sender) if (mode == GM_Console) MWBase::Environment::get().getWindowManager()->getConsole()->setSelectedObject(object); - else if (mode == GM_Console || GM_Inventory) + else if ((mode == GM_Container) || (mode == GM_Inventory)) { // pick up object + MWBase::Environment::get().getWindowManager()->getInventoryWindow()->pickUpObject(object); } } } diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 103f5ebf3d..f75c9afdc6 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -15,6 +15,8 @@ #include "../mwworld/player.hpp" #include "../mwbase/environment.hpp" #include "../mwworld/manualref.hpp" +#include "../mwworld/actiontake.hpp" +#include "../mwsound/soundmanager.hpp" #include "window_manager.hpp" #include "widgets.hpp" @@ -276,13 +278,65 @@ namespace MWGui if (mWindowManager.getSpellWindow()) mWindowManager.getSpellWindow()->updateSpells(); - // update selected weapon icon - MWWorld::InventoryStore& invStore = MWWorld::Class::get(mPtr).getInventoryStore(mPtr); - MWWorld::ContainerStoreIterator weaponSlot = invStore.getSlot(MWWorld::InventoryStore::Slot_CarriedRight); - if (weaponSlot == invStore.end()) - mWindowManager.unsetSelectedWeapon(); - else - mWindowManager.setSelectedWeapon(*weaponSlot, 100); /// \todo track weapon durability + // update selected weapon icon + MWWorld::InventoryStore& invStore = MWWorld::Class::get(mPtr).getInventoryStore(mPtr); + MWWorld::ContainerStoreIterator weaponSlot = invStore.getSlot(MWWorld::InventoryStore::Slot_CarriedRight); + if (weaponSlot == invStore.end()) + mWindowManager.unsetSelectedWeapon(); + else + mWindowManager.setSelectedWeapon(*weaponSlot, 100); /// \todo track weapon durability + } + void InventoryWindow::pickUpObject (MWWorld::Ptr object) + { + /// \todo scripts + + // make sure the object is of a type that can be picked up + std::string type = object.getTypeName(); + if ( (type != typeid(ESM::Apparatus).name()) + && (type != typeid(ESM::Armor).name()) + && (type != typeid(ESM::Book).name()) + && (type != typeid(ESM::Clothing).name()) + && (type != typeid(ESM::Ingredient).name()) + && (type != typeid(ESM::Light).name()) + && (type != typeid(ESM::Miscellaneous).name()) + && (type != typeid(ESM::Tool).name()) + && (type != typeid(ESM::Probe).name()) + && (type != typeid(ESM::Repair).name()) + && (type != typeid(ESM::Potion).name())) + return; + + // sound + std::string sound = MWWorld::Class::get(object).getUpSoundId(object); + MWBase::Environment::get().getSoundManager()->playSound(sound, 1, 1); + + int count = object.getRefData().getCount(); + MWWorld::ActionTake action(object); + action.execute(); + mDragAndDrop->mIsOnDragAndDrop = true; + mDragAndDrop->mDraggedCount = count; + + std::string path = std::string("icons\\"); + path += MWWorld::Class::get(object).getInventoryIcon(object); + MyGUI::ImageBox* baseWidget = mContainerWidget->createWidget("ImageBox", MyGUI::IntCoord(0, 0, 42, 42), MyGUI::Align::Default); + baseWidget->detachFromWidget(); + baseWidget->attachToWidget(mDragAndDrop->mDragAndDropWidget); + baseWidget->setUserData(object); + mDragAndDrop->mDraggedWidget = baseWidget; + ImageBox* image = baseWidget->createWidget("ImageBox", MyGUI::IntCoord(5, 5, 32, 32), MyGUI::Align::Default); + int pos = path.rfind("."); + path.erase(pos); + path.append(".dds"); + image->setImageTexture(path); + image->setNeedMouseFocus(false); + + // text widget that shows item count + MyGUI::TextBox* text = image->createWidget("SandBrightText", MyGUI::IntCoord(0, 14, 32, 18), MyGUI::Align::Default, std::string("Label")); + text->setTextAlign(MyGUI::Align::Right); + text->setNeedMouseFocus(false); + text->setTextShadow(true); + text->setTextShadowColour(MyGUI::Colour(0,0,0)); + text->setCaption(getCountString(count)); + mDragAndDrop->mDraggedFrom = this; } } diff --git a/apps/openmw/mwgui/inventorywindow.hpp b/apps/openmw/mwgui/inventorywindow.hpp index bc4cb08ef2..82da3efea7 100644 --- a/apps/openmw/mwgui/inventorywindow.hpp +++ b/apps/openmw/mwgui/inventorywindow.hpp @@ -18,6 +18,8 @@ namespace MWGui void onFrame(); + void pickUpObject (MWWorld::Ptr object); + int getPlayerGold(); protected: diff --git a/apps/openmw/mwgui/spellwindow.cpp b/apps/openmw/mwgui/spellwindow.cpp index 502754feb0..d34ce68d93 100644 --- a/apps/openmw/mwgui/spellwindow.cpp +++ b/apps/openmw/mwgui/spellwindow.cpp @@ -89,6 +89,16 @@ namespace MWGui bool allowSelectedItem = true; + // make sure that the item is still in the player inventory, otherwise it can't be selected + bool found = false; + for (MWWorld::ContainerStoreIterator it(store.begin()); it != store.end(); ++it) + { + if (*it == selectedItem) + found = true; + } + if (!found) + allowSelectedItem = false; + // if the selected item can be equipped, make sure that it actually is equipped std::pair, bool> slots; slots = MWWorld::Class::get(selectedItem).getEquipmentSlots(selectedItem); diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index 2089ed4aff..47d299fdc6 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -300,6 +300,8 @@ namespace MWGui services = ref->base->AI.services; } + /// \todo what about potions, there doesn't seem to be a flag for them?? + if (item.getTypeName() == typeid(ESM::Weapon).name()) return services & ESM::NPC::Weapon; else if (item.getTypeName() == typeid(ESM::Armor).name()) diff --git a/apps/openmw/mwgui/window_manager.cpp b/apps/openmw/mwgui/window_manager.cpp index 5275ae19d9..800125f27c 100644 --- a/apps/openmw/mwgui/window_manager.cpp +++ b/apps/openmw/mwgui/window_manager.cpp @@ -638,6 +638,7 @@ void WindowManager::processChangedSettings(const Settings::CategorySettingVector hud->onResChange(x, y); console->onResChange(x, y); mSettingsWindow->center(); + mDragAndDrop->mDragAndDropWidget->setSize(MyGUI::IntSize(x, y)); } } From 8e96871acdbb6a5784e634a0f1481ea63bf1f2d4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 3 Jun 2012 18:40:10 +0200 Subject: [PATCH 316/325] remove something unused --- apps/openmw/mwgui/dialogue.cpp | 3 --- apps/openmw/mwgui/dialogue.hpp | 1 - 2 files changed, 4 deletions(-) diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index ce687424c0..17552b09dc 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -140,7 +140,6 @@ void DialogueWindow::startDialogue(MWWorld::Ptr actor, std::string npcName) setTitle(npcName); topicsList->clear(); - pTopicsText.clear(); history->eraseText(0,history->getTextLength()); updateOptions(); } @@ -169,7 +168,6 @@ void DialogueWindow::removeKeyword(std::string keyWord) if(topicsList->hasItem(keyWord)) { topicsList->removeItem(keyWord); - pTopicsText.erase(keyWord); } topicsList->adjustSize(); } @@ -245,7 +243,6 @@ void DialogueWindow::updateOptions() { //Clear the list of topics topicsList->clear(); - pTopicsText.clear(); history->eraseText(0,history->getTextLength()); pDispositionBar->setProgressRange(100); diff --git a/apps/openmw/mwgui/dialogue.hpp b/apps/openmw/mwgui/dialogue.hpp index 8e9aba0030..aa66cd5798 100644 --- a/apps/openmw/mwgui/dialogue.hpp +++ b/apps/openmw/mwgui/dialogue.hpp @@ -77,7 +77,6 @@ namespace MWGui Widgets::MWList* topicsList; MyGUI::ProgressPtr pDispositionBar; MyGUI::EditPtr pDispositionText; - std::map pTopicsText;// this map links keyword and "real" text. }; } #endif From d56defd4f4c013587ffd628d299b7bdb1196e4b0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 3 Jun 2012 21:19:48 +0200 Subject: [PATCH 317/325] set input focus to console after selecting objects in console mode --- apps/openmw/mwgui/console.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwgui/console.cpp b/apps/openmw/mwgui/console.cpp index 2f8a953069..8e6dd8019e 100644 --- a/apps/openmw/mwgui/console.cpp +++ b/apps/openmw/mwgui/console.cpp @@ -384,6 +384,7 @@ namespace MWGui setTitle("#{sConsoleTitle} (" + mPtr.getCellRef().refID + ")"); else setTitle("#{sConsoleTitle}"); + MyGUI::InputManager::getInstance().setKeyFocusWidget(command); } void Console::onReferenceUnavailable() From 1ecc6f97ed2529ae7c9b22f1fdd85dd829e7f99d Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 4 Jun 2012 20:56:13 +0200 Subject: [PATCH 318/325] alchemy effect fix --- apps/openmw/mwgui/widgets.hpp | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwgui/widgets.hpp b/apps/openmw/mwgui/widgets.hpp index c66bf5dd0e..04866b176d 100644 --- a/apps/openmw/mwgui/widgets.hpp +++ b/apps/openmw/mwgui/widgets.hpp @@ -54,9 +54,20 @@ namespace MWGui bool operator==(const SpellEffectParams& other) const { - return (other.mEffectID == mEffectID - && other.mSkill == mSkill - && other.mAttribute == mAttribute); + if (mEffectID != other.mEffectID) + return false; + + bool involvesAttribute = (mEffectID == 74 // restore attribute + || mEffectID == 85 // absorb attribute + || mEffectID == 17 // drain attribute + || mEffectID == 79 // fortify attribute + || mEffectID == 22); // damage attribute + bool involvesSkill = (mEffectID == 78 // restore skill + || mEffectID == 89 // absorb skill + || mEffectID == 21 // drain skill + || mEffectID == 83 // fortify skill + || mEffectID == 26); // damage skill + return ((other.mSkill == mSkill) || !involvesSkill) && ((other.mAttribute == mAttribute) && !involvesAttribute); } }; From ea8e3ca1c8809aa5625dc9af4b5d6e05be2b67b2 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 4 Jun 2012 21:09:51 +0200 Subject: [PATCH 319/325] fix item duplication bug when picking up object with the mouse and immediately dropping again --- apps/openmw/mwgui/inventorywindow.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index f75c9afdc6..7409aed727 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -311,17 +311,23 @@ namespace MWGui MWBase::Environment::get().getSoundManager()->playSound(sound, 1, 1); int count = object.getRefData().getCount(); - MWWorld::ActionTake action(object); - action.execute(); + + // add to player inventory + // can't use ActionTake here because we need an MWWorld::Ptr to the newly inserted object + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + MWWorld::Ptr newObject = *MWWorld::Class::get (player).getContainerStore (player).add (object); + // remove from world + MWBase::Environment::get().getWorld()->deleteObject (object); + mDragAndDrop->mIsOnDragAndDrop = true; mDragAndDrop->mDraggedCount = count; std::string path = std::string("icons\\"); - path += MWWorld::Class::get(object).getInventoryIcon(object); + path += MWWorld::Class::get(newObject).getInventoryIcon(newObject); MyGUI::ImageBox* baseWidget = mContainerWidget->createWidget("ImageBox", MyGUI::IntCoord(0, 0, 42, 42), MyGUI::Align::Default); baseWidget->detachFromWidget(); baseWidget->attachToWidget(mDragAndDrop->mDragAndDropWidget); - baseWidget->setUserData(object); + baseWidget->setUserData(newObject); mDragAndDrop->mDraggedWidget = baseWidget; ImageBox* image = baseWidget->createWidget("ImageBox", MyGUI::IntCoord(5, 5, 32, 32), MyGUI::Align::Default); int pos = path.rfind("."); From dfac5f26c3a504a20377271525af89c819b4fde8 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 4 Jun 2012 21:48:20 +0200 Subject: [PATCH 320/325] fixed some issues: - probes were not showing up in inventory category "misc" - lights, probes, lockpicks were not equippable - weapons could not be picked up --- apps/openmw/mwclass/light.cpp | 8 ++++++++ apps/openmw/mwclass/light.hpp | 4 ++++ apps/openmw/mwclass/lockpick.cpp | 8 ++++++++ apps/openmw/mwclass/lockpick.hpp | 4 ++++ apps/openmw/mwclass/probe.cpp | 8 ++++++++ apps/openmw/mwclass/probe.hpp | 4 ++++ apps/openmw/mwgui/container.cpp | 2 +- apps/openmw/mwgui/inventorywindow.cpp | 1 + 8 files changed, 38 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index 12ae517efd..1540334338 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -9,6 +9,7 @@ #include "../mwworld/ptr.hpp" #include "../mwworld/actiontake.hpp" +#include "../mwworld/actionequip.hpp" #include "../mwworld/nullaction.hpp" #include "../mwworld/inventorystore.hpp" #include "../mwworld/world.hpp" @@ -176,4 +177,11 @@ namespace MWClass return info; } + + boost::shared_ptr Light::use (const MWWorld::Ptr& ptr) const + { + MWBase::Environment::get().getSoundManager()->playSound (getUpSoundId(ptr), 1.0, 1.0); + + return boost::shared_ptr(new MWWorld::ActionEquip(ptr)); + } } diff --git a/apps/openmw/mwclass/light.hpp b/apps/openmw/mwclass/light.hpp index cd963d8429..91193dfdca 100644 --- a/apps/openmw/mwclass/light.hpp +++ b/apps/openmw/mwclass/light.hpp @@ -48,6 +48,10 @@ namespace MWClass virtual std::string getInventoryIcon (const MWWorld::Ptr& ptr) const; ///< Return name of inventory icon. + + virtual boost::shared_ptr use (const MWWorld::Ptr& ptr) + const; + ///< Generate action for using via inventory menu }; } diff --git a/apps/openmw/mwclass/lockpick.cpp b/apps/openmw/mwclass/lockpick.cpp index 5bb6776465..27e292bc0e 100644 --- a/apps/openmw/mwclass/lockpick.cpp +++ b/apps/openmw/mwclass/lockpick.cpp @@ -9,6 +9,7 @@ #include "../mwworld/ptr.hpp" #include "../mwworld/actiontake.hpp" +#include "../mwworld/actionequip.hpp" #include "../mwworld/inventorystore.hpp" #include "../mwworld/world.hpp" #include "../mwgui/window_manager.hpp" @@ -155,4 +156,11 @@ namespace MWClass return info; } + + boost::shared_ptr Lockpick::use (const MWWorld::Ptr& ptr) const + { + MWBase::Environment::get().getSoundManager()->playSound (getUpSoundId(ptr), 1.0, 1.0); + + return boost::shared_ptr(new MWWorld::ActionEquip(ptr)); + } } diff --git a/apps/openmw/mwclass/lockpick.hpp b/apps/openmw/mwclass/lockpick.hpp index b8683c5e99..26aab584c3 100644 --- a/apps/openmw/mwclass/lockpick.hpp +++ b/apps/openmw/mwclass/lockpick.hpp @@ -48,6 +48,10 @@ namespace MWClass virtual std::string getInventoryIcon (const MWWorld::Ptr& ptr) const; ///< Return name of inventory icon. + + virtual boost::shared_ptr use (const MWWorld::Ptr& ptr) + const; + ///< Generate action for using via inventory menu }; } diff --git a/apps/openmw/mwclass/probe.cpp b/apps/openmw/mwclass/probe.cpp index 1e713f0a5d..0b256d7293 100644 --- a/apps/openmw/mwclass/probe.cpp +++ b/apps/openmw/mwclass/probe.cpp @@ -9,6 +9,7 @@ #include "../mwworld/ptr.hpp" #include "../mwworld/actiontake.hpp" +#include "../mwworld/actionequip.hpp" #include "../mwworld/inventorystore.hpp" #include "../mwworld/world.hpp" #include "../mwgui/window_manager.hpp" @@ -154,4 +155,11 @@ namespace MWClass return info; } + + boost::shared_ptr Probe::use (const MWWorld::Ptr& ptr) const + { + MWBase::Environment::get().getSoundManager()->playSound (getUpSoundId(ptr), 1.0, 1.0); + + return boost::shared_ptr(new MWWorld::ActionEquip(ptr)); + } } diff --git a/apps/openmw/mwclass/probe.hpp b/apps/openmw/mwclass/probe.hpp index 5e0059e141..51b046fda2 100644 --- a/apps/openmw/mwclass/probe.hpp +++ b/apps/openmw/mwclass/probe.hpp @@ -48,6 +48,10 @@ namespace MWClass virtual std::string getInventoryIcon (const MWWorld::Ptr& ptr) const; ///< Return name of inventory icon. + + virtual boost::shared_ptr use (const MWWorld::Ptr& ptr) + const; + ///< Generate action for using via inventory menu }; } diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index eb5cbc92b3..6ba4923d95 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -384,7 +384,7 @@ void ContainerBase::drawItems() categories = MWWorld::ContainerStore::Type_Miscellaneous + MWWorld::ContainerStore::Type_Book + MWWorld::ContainerStore::Type_Ingredient + MWWorld::ContainerStore::Type_Repair + MWWorld::ContainerStore::Type_Lockpick + MWWorld::ContainerStore::Type_Light - + MWWorld::ContainerStore::Type_Apparatus; + + MWWorld::ContainerStore::Type_Apparatus + MWWorld::ContainerStore::Type_Probe; } else if (mFilter == Filter_Ingredients) categories = MWWorld::ContainerStore::Type_Ingredient; diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 7409aed727..a26a958bd0 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -303,6 +303,7 @@ namespace MWGui && (type != typeid(ESM::Tool).name()) && (type != typeid(ESM::Probe).name()) && (type != typeid(ESM::Repair).name()) + && (type != typeid(ESM::Weapon).name()) && (type != typeid(ESM::Potion).name())) return; From c85c794c869080d778b99efe14b6bdc5c4e3c359 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 6 Jun 2012 20:29:30 +0200 Subject: [PATCH 321/325] fixed some cppcheck issues --- apps/mwiniimporter/importer.cpp | 22 ++++++++++++---------- apps/openmw/mwdialogue/dialoguemanager.cpp | 2 +- apps/openmw/mwgui/charactercreation.cpp | 1 + apps/openmw/mwgui/class.cpp | 9 +++------ apps/openmw/mwgui/console.cpp | 6 +++--- apps/openmw/mwgui/container.cpp | 4 ---- apps/openmw/mwgui/dialogue.cpp | 2 +- apps/openmw/mwgui/journalwindow.cpp | 4 ++-- apps/openmw/mwgui/review.cpp | 4 ++-- apps/openmw/mwgui/review.hpp | 4 ++-- apps/openmw/mwgui/stats_window.cpp | 2 +- apps/openmw/mwgui/stats_window.hpp | 2 +- apps/openmw/mwgui/tooltips.cpp | 1 - apps/openmw/mwgui/widgets.cpp | 2 +- apps/openmw/mwgui/widgets.hpp | 2 +- apps/openmw/mwgui/window_manager.cpp | 4 ++-- apps/openmw/mwgui/window_manager.hpp | 4 ++-- apps/openmw/mwrender/debugging.cpp | 6 +++--- apps/openmw/mwrender/npcanimation.cpp | 2 +- apps/openmw/mwrender/npcanimation.hpp | 2 +- apps/openmw/mwrender/objects.hpp | 5 +++-- apps/openmw/mwrender/terrainmaterial.hpp | 2 +- apps/openmw/mwsound/sound_output.hpp | 2 +- apps/openmw/mwworld/physicssystem.cpp | 1 + apps/openmw/mwworld/player.hpp | 2 +- apps/openmw/mwworld/weather.cpp | 3 ++- components/bsa/bsa_archive.cpp | 4 ++-- components/compiler/generator.cpp | 8 ++++---- components/compiler/generator.hpp | 8 ++++---- components/esm/esm_reader.hpp | 12 ++++++------ components/files/filelibrary.cpp | 4 ++-- components/nifogre/ogre_nif_loader.cpp | 6 +++--- libs/mangle/input/servers/ois_driver.cpp | 3 +-- libs/openengine/bullet/CMotionState.cpp | 2 ++ libs/openengine/gui/manager.cpp | 2 +- libs/openengine/ogre/renderer.cpp | 11 +++++------ libs/openengine/ogre/renderer.hpp | 4 ++-- 37 files changed, 81 insertions(+), 83 deletions(-) diff --git a/apps/mwiniimporter/importer.cpp b/apps/mwiniimporter/importer.cpp index 5503a7c1a8..d396df648f 100644 --- a/apps/mwiniimporter/importer.cpp +++ b/apps/mwiniimporter/importer.cpp @@ -8,7 +8,9 @@ #include #include -MwIniImporter::MwIniImporter() { +MwIniImporter::MwIniImporter() + : mVerbose(false) +{ const char *map[][2] = { { "fps", "General:Show FPS" }, @@ -124,9 +126,9 @@ MwIniImporter::multistrmap MwIniImporter::loadCfgFile(std::string filename) { void MwIniImporter::merge(multistrmap &cfg, multistrmap &ini) { multistrmap::iterator cfgIt; multistrmap::iterator iniIt; - for(strmap::iterator it=mMergeMap.begin(); it!=mMergeMap.end(); it++) { + for(strmap::iterator it=mMergeMap.begin(); it!=mMergeMap.end(); ++it) { if((iniIt = ini.find(it->second)) != ini.end()) { - for(std::vector::iterator vc = iniIt->second.begin(); vc != iniIt->second.end(); vc++) { + for(std::vector::iterator vc = iniIt->second.begin(); vc != iniIt->second.end(); ++vc) { cfg.erase(it->first); insertMultistrmap(cfg, it->first, *vc); } @@ -139,9 +141,9 @@ void MwIniImporter::mergeFallback(multistrmap &cfg, multistrmap &ini) { multistrmap::iterator cfgIt; multistrmap::iterator iniIt; - for(std::vector::iterator it=mMergeFallback.begin(); it!=mMergeFallback.end(); it++) { + for(std::vector::iterator it=mMergeFallback.begin(); it!=mMergeFallback.end(); ++it) { if((iniIt = ini.find(*it)) != ini.end()) { - for(std::vector::iterator vc = iniIt->second.begin(); vc != iniIt->second.end(); vc++) { + for(std::vector::iterator vc = iniIt->second.begin(); vc != iniIt->second.end(); ++vc) { std::string value(*it); std::replace( value.begin(), value.end(), ' ', '_' ); std::replace( value.begin(), value.end(), ':', '_' ); @@ -176,7 +178,7 @@ void MwIniImporter::importGameFiles(multistrmap &cfg, multistrmap &ini) { break; } - for(std::vector::iterator entry = it->second.begin(); entry!=it->second.end(); entry++) { + for(std::vector::iterator entry = it->second.begin(); entry!=it->second.end(); ++entry) { std::string filetype(entry->substr(entry->length()-4, 3)); std::transform(filetype.begin(), filetype.end(), filetype.begin(), ::tolower); @@ -194,22 +196,22 @@ void MwIniImporter::importGameFiles(multistrmap &cfg, multistrmap &ini) { cfg.erase("master"); cfg.insert( std::make_pair > ("master", std::vector() ) ); - for(std::vector::iterator it=esmFiles.begin(); it!=esmFiles.end(); it++) { + for(std::vector::iterator it=esmFiles.begin(); it!=esmFiles.end(); ++it) { cfg["master"].push_back(*it); } cfg.erase("plugin"); cfg.insert( std::make_pair > ("plugin", std::vector() ) ); - for(std::vector::iterator it=espFiles.begin(); it!=espFiles.end(); it++) { + for(std::vector::iterator it=espFiles.begin(); it!=espFiles.end(); ++it) { cfg["plugin"].push_back(*it); } } void MwIniImporter::writeToFile(boost::iostreams::stream &out, multistrmap &cfg) { - for(multistrmap::iterator it=cfg.begin(); it != cfg.end(); it++) { - for(std::vector::iterator entry=it->second.begin(); entry != it->second.end(); entry++) { + for(multistrmap::iterator it=cfg.begin(); it != cfg.end(); ++it) { + for(std::vector::iterator entry=it->second.begin(); entry != it->second.end(); ++entry) { out << (it->first) << "=" << (*entry) << std::endl; } } diff --git a/apps/openmw/mwdialogue/dialoguemanager.cpp b/apps/openmw/mwdialogue/dialoguemanager.cpp index 716f472a0e..a19356d07f 100644 --- a/apps/openmw/mwdialogue/dialoguemanager.cpp +++ b/apps/openmw/mwdialogue/dialoguemanager.cpp @@ -607,7 +607,7 @@ namespace MWDialogue void DialogueManager::parseText(std::string text) { std::list::iterator it; - for(it = actorKnownTopics.begin();it != actorKnownTopics.end();it++) + for(it = actorKnownTopics.begin();it != actorKnownTopics.end();++it) { size_t pos = find_str_ci(text,*it,0); if(pos !=std::string::npos) diff --git a/apps/openmw/mwgui/charactercreation.cpp b/apps/openmw/mwgui/charactercreation.cpp index 31696230cb..3f9a94e2db 100644 --- a/apps/openmw/mwgui/charactercreation.cpp +++ b/apps/openmw/mwgui/charactercreation.cpp @@ -117,6 +117,7 @@ CharacterCreation::CharacterCreation(WindowManager* _wm) , mCreateClassDialog(0) , mBirthSignDialog(0) , mReviewDialog(0) + , mGenerateClassStep(0) , mWM(_wm) { mCreationStage = CSE_NotStarted; diff --git a/apps/openmw/mwgui/class.cpp b/apps/openmw/mwgui/class.cpp index a7e5b86747..0961f6327e 100644 --- a/apps/openmw/mwgui/class.cpp +++ b/apps/openmw/mwgui/class.cpp @@ -581,8 +581,7 @@ void CreateClassDialog::onDialogCancel() void CreateClassDialog::onSpecializationClicked(MyGUI::WidgetPtr _sender) { - if (specDialog) - delete specDialog; + delete specDialog; specDialog = new SelectSpecializationDialog(mWindowManager); specDialog->eventCancel += MyGUI::newDelegate(this, &CreateClassDialog::onDialogCancel); specDialog->eventItemSelected += MyGUI::newDelegate(this, &CreateClassDialog::onSpecializationSelected); @@ -613,8 +612,7 @@ void CreateClassDialog::setSpecialization(int id) void CreateClassDialog::onAttributeClicked(Widgets::MWAttributePtr _sender) { - if (attribDialog) - delete attribDialog; + delete attribDialog; attribDialog = new SelectAttributeDialog(mWindowManager); attribDialog->setAffectedWidget(_sender); attribDialog->eventCancel += MyGUI::newDelegate(this, &CreateClassDialog::onDialogCancel); @@ -645,8 +643,7 @@ void CreateClassDialog::onAttributeSelected() void CreateClassDialog::onSkillClicked(Widgets::MWSkillPtr _sender) { - if (skillDialog) - delete skillDialog; + delete skillDialog; skillDialog = new SelectSkillDialog(mWindowManager); skillDialog->setAffectedWidget(_sender); skillDialog->eventCancel += MyGUI::newDelegate(this, &CreateClassDialog::onDialogCancel); diff --git a/apps/openmw/mwgui/console.cpp b/apps/openmw/mwgui/console.cpp index 8e6dd8019e..8115835f40 100644 --- a/apps/openmw/mwgui/console.cpp +++ b/apps/openmw/mwgui/console.cpp @@ -268,7 +268,7 @@ namespace MWGui /* Are there quotation marks? */ if( tmp.find('"') != string::npos ) { int numquotes=0; - for(string::iterator it=tmp.begin(); it < tmp.end(); it++) { + for(string::iterator it=tmp.begin(); it < tmp.end(); ++it) { if( *it == '"' ) numquotes++; } @@ -311,7 +311,7 @@ namespace MWGui } /* Iterate through the vector. */ - for(vector::iterator it=mNames.begin(); it < mNames.end();it++) { + for(vector::iterator it=mNames.begin(); it < mNames.end();++it) { bool string_different=false; /* Is the string shorter than the input string? If yes skip it. */ @@ -359,7 +359,7 @@ namespace MWGui int i = tmp.length(); for(string::iterator iter=matches.front().begin()+tmp.length(); iter < matches.front().end(); iter++, i++) { - for(vector::iterator it=matches.begin(); it < matches.end();it++) { + for(vector::iterator it=matches.begin(); it < matches.end();++it) { if( tolower((*it)[i]) != tolower(*iter) ) { /* Append the longest match to the end of the output string*/ output.append(matches.front().substr( 0, i)); diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 6ba4923d95..6775fa6439 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -361,9 +361,6 @@ void ContainerBase::drawItems() int y = 0; int maxHeight = mItemView->getSize().height - 58; - int index = 0; - - bool onlyMagic = false; int categories; if (mFilter == Filter_All) @@ -459,7 +456,6 @@ void ContainerBase::drawItems() for (std::vector< std::pair >::const_iterator it=items.begin(); it != items.end(); ++it) { - index++; const MWWorld::Ptr* iter = &((*it).first); int displayCount = iter->getRefData().getCount(); diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 17552b09dc..79b2d68bab 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -156,7 +156,7 @@ void DialogueWindow::setKeywords(std::list keyWords) if (anyService) topicsList->addSeparator(); - for(std::list::iterator it = keyWords.begin(); it != keyWords.end(); it++) + for(std::list::iterator it = keyWords.begin(); it != keyWords.end(); ++it) { topicsList->addItem(*it); } diff --git a/apps/openmw/mwgui/journalwindow.cpp b/apps/openmw/mwgui/journalwindow.cpp index e4c38496dc..7f9000bc75 100644 --- a/apps/openmw/mwgui/journalwindow.cpp +++ b/apps/openmw/mwgui/journalwindow.cpp @@ -131,7 +131,7 @@ void MWGui::JournalWindow::open() book journal; journal.endLine = 0; - for(std::deque::const_iterator it = MWBase::Environment::get().getJournal()->begin();it!=MWBase::Environment::get().getJournal()->end();it++) + for(std::deque::const_iterator it = MWBase::Environment::get().getJournal()->begin();it!=MWBase::Environment::get().getJournal()->end();++it) { std::string a = it->getText(MWBase::Environment::get().getWorld()->getStore()); journal = formatText(a,journal,10,17); @@ -141,7 +141,7 @@ void MWGui::JournalWindow::open() //std::string a = MWBase::Environment::get().getJournal()->begin()->getText(MWBase::Environment::get().getWorld()->getStore()); //std::list journal = formatText(a,10,20,1); bool left = true; - for(std::list::iterator it = journal.pages.begin(); it != journal.pages.end();it++) + for(std::list::iterator it = journal.pages.begin(); it != journal.pages.end();++it) { if(left) { diff --git a/apps/openmw/mwgui/review.cpp b/apps/openmw/mwgui/review.cpp index 67b6cc24ac..97a3a6e154 100644 --- a/apps/openmw/mwgui/review.cpp +++ b/apps/openmw/mwgui/review.cpp @@ -257,7 +257,7 @@ void ReviewDialog::addGroup(const std::string &label, MyGUI::IntCoord &coord1, M coord2.top += lineHeight; } -MyGUI::TextBox* ReviewDialog::addValueItem(const std::string text, const std::string &value, const std::string& state, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) +MyGUI::TextBox* ReviewDialog::addValueItem(const std::string& text, const std::string &value, const std::string& state, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) { MyGUI::TextBox* skillNameWidget; MyGUI::TextBox* skillValueWidget; @@ -280,7 +280,7 @@ MyGUI::TextBox* ReviewDialog::addValueItem(const std::string text, const std::st return skillValueWidget; } -void ReviewDialog::addItem(const std::string text, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) +void ReviewDialog::addItem(const std::string& text, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) { MyGUI::TextBox* skillNameWidget; diff --git a/apps/openmw/mwgui/review.hpp b/apps/openmw/mwgui/review.hpp index bae4dc4592..6118168d57 100644 --- a/apps/openmw/mwgui/review.hpp +++ b/apps/openmw/mwgui/review.hpp @@ -74,8 +74,8 @@ namespace MWGui void addSkills(const SkillList &skills, const std::string &titleId, const std::string &titleDefault, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2); void addSeparator(MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2); void addGroup(const std::string &label, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2); - MyGUI::TextBox* addValueItem(const std::string text, const std::string &value, const std::string& state, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2); - void addItem(const std::string text, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2); + MyGUI::TextBox* addValueItem(const std::string& text, const std::string &value, const std::string& state, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2); + void addItem(const std::string& text, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2); void updateScroller(); void updateSkillArea(); diff --git a/apps/openmw/mwgui/stats_window.cpp b/apps/openmw/mwgui/stats_window.cpp index 75159f4dbd..3584af7c7d 100644 --- a/apps/openmw/mwgui/stats_window.cpp +++ b/apps/openmw/mwgui/stats_window.cpp @@ -340,7 +340,7 @@ MyGUI::TextBox* StatsWindow::addValueItem(const std::string& text, const std::st return skillValueWidget; } -MyGUI::Widget* StatsWindow::addItem(const std::string text, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) +MyGUI::Widget* StatsWindow::addItem(const std::string& text, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) { MyGUI::TextBox* skillNameWidget; diff --git a/apps/openmw/mwgui/stats_window.hpp b/apps/openmw/mwgui/stats_window.hpp index bbd9165859..10b794cc0e 100644 --- a/apps/openmw/mwgui/stats_window.hpp +++ b/apps/openmw/mwgui/stats_window.hpp @@ -47,7 +47,7 @@ namespace MWGui void addSeparator(MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2); void addGroup(const std::string &label, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2); MyGUI::TextBox* addValueItem(const std::string& text, const std::string &value, const std::string& state, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2); - MyGUI::Widget* addItem(const std::string text, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2); + MyGUI::Widget* addItem(const std::string& text, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2); void updateScroller(); void setFactions (const FactionList& factions); diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 1f614d56b3..7ec4441687 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -142,7 +142,6 @@ void ToolTips::onFrame(float frameDuration) std::string type = focus->getUserString("ToolTipType"); std::string text = focus->getUserString("ToolTipText"); - ToolTipInfo info; if (type == "") { return; diff --git a/apps/openmw/mwgui/widgets.cpp b/apps/openmw/mwgui/widgets.cpp index b850748057..65de7ce0a8 100644 --- a/apps/openmw/mwgui/widgets.cpp +++ b/apps/openmw/mwgui/widgets.cpp @@ -767,7 +767,7 @@ void MWDynamicStat::setValue(int cur, int max_) static_cast(barTextWidget)->setCaption(""); } } -void MWDynamicStat::setTitle(const std::string text) +void MWDynamicStat::setTitle(const std::string& text) { if (textWidget) static_cast(textWidget)->setCaption(text); diff --git a/apps/openmw/mwgui/widgets.hpp b/apps/openmw/mwgui/widgets.hpp index 04866b176d..5d00baf871 100644 --- a/apps/openmw/mwgui/widgets.hpp +++ b/apps/openmw/mwgui/widgets.hpp @@ -282,7 +282,7 @@ namespace MWGui MWDynamicStat(); void setValue(int value, int max); - void setTitle(const std::string text); + void setTitle(const std::string& text); int getValue() const { return value; } int getMax() const { return max; } diff --git a/apps/openmw/mwgui/window_manager.cpp b/apps/openmw/mwgui/window_manager.cpp index 800125f27c..5b963d3ae1 100644 --- a/apps/openmw/mwgui/window_manager.cpp +++ b/apps/openmw/mwgui/window_manager.cpp @@ -39,7 +39,7 @@ using namespace MWGui; WindowManager::WindowManager( - const Compiler::Extensions& extensions, int fpsLevel, bool newGame, OEngine::Render::OgreRenderer *mOgre, const std::string logpath) + const Compiler::Extensions& extensions, int fpsLevel, bool newGame, OEngine::Render::OgreRenderer *mOgre, const std::string& logpath) : mGuiManager(NULL) , hud(NULL) , map(NULL) @@ -657,7 +657,7 @@ void WindowManager::pushGuiMode(GuiMode mode) void WindowManager::popGuiMode() { - if (mGuiModes.size()) + if (!mGuiModes.empty()) mGuiModes.pop_back(); bool gameMode = !isGuiMode(); diff --git a/apps/openmw/mwgui/window_manager.hpp b/apps/openmw/mwgui/window_manager.hpp index 19ad7702a4..37f30c59a4 100644 --- a/apps/openmw/mwgui/window_manager.hpp +++ b/apps/openmw/mwgui/window_manager.hpp @@ -98,7 +98,7 @@ namespace MWGui typedef std::vector FactionList; typedef std::vector SkillList; - WindowManager(const Compiler::Extensions& extensions, int fpsLevel, bool newGame, OEngine::Render::OgreRenderer *mOgre, const std::string logpath); + WindowManager(const Compiler::Extensions& extensions, int fpsLevel, bool newGame, OEngine::Render::OgreRenderer *mOgre, const std::string& logpath); virtual ~WindowManager(); /** @@ -141,7 +141,7 @@ namespace MWGui updateVisible(); } - bool isAllowed(GuiWindow wnd) + bool isAllowed(GuiWindow wnd) const { return allowed & wnd; } diff --git a/apps/openmw/mwrender/debugging.cpp b/apps/openmw/mwrender/debugging.cpp index be8afbae65..9086a9bc49 100644 --- a/apps/openmw/mwrender/debugging.cpp +++ b/apps/openmw/mwrender/debugging.cpp @@ -68,7 +68,7 @@ ManualObject *Debugging::createPathgridLines(const ESM::Pathgrid *pathgrid) result->begin(PATHGRID_LINE_MATERIAL, RenderOperation::OT_LINE_LIST); for(ESM::Pathgrid::EdgeList::const_iterator it = pathgrid->edges.begin(); it != pathgrid->edges.end(); - it++) + ++it) { const ESM::Pathgrid::Edge &edge = *it; const ESM::Pathgrid::Point &p1 = pathgrid->points[edge.v0], &p2 = pathgrid->points[edge.v1]; @@ -197,7 +197,7 @@ void Debugging::togglePathgrid() // add path grid meshes to already loaded cells mPathGridRoot = mMwRoot->createChildSceneNode(); - for(CellList::iterator it = mActiveCells.begin(); it != mActiveCells.end(); it++) + for(CellList::iterator it = mActiveCells.begin(); it != mActiveCells.end(); ++it) { enableCellPathgrid(*it); } @@ -205,7 +205,7 @@ void Debugging::togglePathgrid() else { // remove path grid meshes from already loaded cells - for(CellList::iterator it = mActiveCells.begin(); it != mActiveCells.end(); it++) + for(CellList::iterator it = mActiveCells.begin(); it != mActiveCells.end(); ++it) { disableCellPathgrid(*it); } diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index c35fff1cee..5ceafca365 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -528,7 +528,7 @@ void NpcAnimation::insertFootPart(int type, const std::string &mesh){ } -std::pair*> NpcAnimation::insertFreePart(const std::string &mesh, const std::string suffix){ +std::pair*> NpcAnimation::insertFreePart(const std::string &mesh, const std::string& suffix){ std::string meshNumbered = mesh + getUniqueID(mesh + suffix) + suffix; NIFLoader::load(meshNumbered); diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index a37becc26d..8f4f8181d0 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -84,7 +84,7 @@ private: NpcAnimation(const MWWorld::Ptr& ptr, OEngine::Render::OgreRenderer& _rend, MWWorld::InventoryStore& _inv); virtual ~NpcAnimation(); Ogre::Entity* insertBoundedPart(const std::string &mesh, std::string bonename); - std::pair*> insertFreePart(const std::string &mesh, const std::string suffix); + std::pair*> insertFreePart(const std::string &mesh, const std::string& suffix); void insertFootPart(int type, const std::string &mesh); virtual void runAnimation(float timepassed); void updateParts(); diff --git a/apps/openmw/mwrender/objects.hpp b/apps/openmw/mwrender/objects.hpp index fb26808b96..6132879e69 100644 --- a/apps/openmw/mwrender/objects.hpp +++ b/apps/openmw/mwrender/objects.hpp @@ -39,7 +39,8 @@ struct LightInfo LightInfo() : flickerVariation(0), resetTime(0.5), - flickerSlowVariation(0), time(0), interior(true) + flickerSlowVariation(0), time(0), interior(true), + type(LT_Normal), radius(1.0) { } }; @@ -68,7 +69,7 @@ class Objects{ ///< Remove all movable objects from \a node. public: - Objects(OEngine::Render::OgreRenderer& renderer): mRenderer (renderer) {} + Objects(OEngine::Render::OgreRenderer& renderer): mRenderer (renderer), mIsStatic(false) {} ~Objects(){} void insertBegin (const MWWorld::Ptr& ptr, bool enabled, bool static_); void insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh); diff --git a/apps/openmw/mwrender/terrainmaterial.hpp b/apps/openmw/mwrender/terrainmaterial.hpp index db916bf253..e94e20b7e9 100644 --- a/apps/openmw/mwrender/terrainmaterial.hpp +++ b/apps/openmw/mwrender/terrainmaterial.hpp @@ -167,7 +167,7 @@ namespace Ogre class ShaderHelper : public TerrainAlloc { public: - ShaderHelper() {} + ShaderHelper() : mShadowSamplerStartHi(0), mShadowSamplerStartLo(0) {} virtual ~ShaderHelper() {} virtual HighLevelGpuProgramPtr generateVertexProgram(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt); virtual HighLevelGpuProgramPtr generateFragmentProgram(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt); diff --git a/apps/openmw/mwsound/sound_output.hpp b/apps/openmw/mwsound/sound_output.hpp index 7efed81293..100b2208c4 100644 --- a/apps/openmw/mwsound/sound_output.hpp +++ b/apps/openmw/mwsound/sound_output.hpp @@ -46,7 +46,7 @@ namespace MWSound public: virtual ~Sound_Output() { } - bool isInitialized() { return mInitialized; } + bool isInitialized() const { return mInitialized; } friend class OpenAL_Output; friend class SoundManager; diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 5598ff3c0b..7c1ff31b40 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -32,6 +32,7 @@ namespace MWWorld PhysicsSystem::~PhysicsSystem() { delete mEngine; + delete playerphysics; } OEngine::Physic::PhysicEngine* PhysicsSystem::getEngine() diff --git a/apps/openmw/mwworld/player.hpp b/apps/openmw/mwworld/player.hpp index 166d4cfee0..a5c5ff308b 100644 --- a/apps/openmw/mwworld/player.hpp +++ b/apps/openmw/mwworld/player.hpp @@ -107,7 +107,7 @@ namespace MWWorld return *mClass; } - bool getAutoMove() + bool getAutoMove() const { return mAutoMove; } diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 316463f539..3d6547d6ab 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -38,7 +38,8 @@ const float WeatherGlobals::mThunderSoundDelay = 0.25; WeatherManager::WeatherManager(MWRender::RenderingManager* rendering) : mHour(14), mCurrentWeather("clear"), mFirstUpdate(true), mWeatherUpdateTime(0), - mThunderFlash(0), mThunderChance(0), mThunderChanceNeeded(50), mThunderSoundDelay(0) + mThunderFlash(0), mThunderChance(0), mThunderChanceNeeded(50), mThunderSoundDelay(0), + mRemainingTransitionTime(0), mMonth(0), mDay(0) { mRendering = rendering; diff --git a/components/bsa/bsa_archive.cpp b/components/bsa/bsa_archive.cpp index fa197d9605..d3b75d4ae4 100644 --- a/components/bsa/bsa_archive.cpp +++ b/components/bsa/bsa_archive.cpp @@ -93,12 +93,12 @@ class DirArchive: public Ogre::FileSystemArchive return true; std::string folder; - int delimiter = 0; + //int delimiter = 0; size_t lastSlash = copy.rfind('/'); if (lastSlash != std::string::npos) { folder = copy.substr(0, lastSlash); - delimiter = lastSlash+1; + //delimiter = lastSlash+1; } std::vector current; diff --git a/components/compiler/generator.cpp b/components/compiler/generator.cpp index ee9876a147..26a80387b1 100644 --- a/components/compiler/generator.cpp +++ b/components/compiler/generator.cpp @@ -727,7 +727,7 @@ namespace Compiler opStopScript (code); } - void getDistance (CodeContainer& code, Literals& literals, const std::string id) + void getDistance (CodeContainer& code, Literals& literals, const std::string& id) { if (id.empty()) { @@ -746,7 +746,7 @@ namespace Compiler opGetSecondsPassed (code); } - void getDisabled (CodeContainer& code, Literals& literals, const std::string id) + void getDisabled (CodeContainer& code, Literals& literals, const std::string& id) { if (id.empty()) { @@ -760,7 +760,7 @@ namespace Compiler } } - void enable (CodeContainer& code, Literals& literals, const std::string id) + void enable (CodeContainer& code, Literals& literals, const std::string& id) { if (id.empty()) { @@ -774,7 +774,7 @@ namespace Compiler } } - void disable (CodeContainer& code, Literals& literals, const std::string id) + void disable (CodeContainer& code, Literals& literals, const std::string& id) { if (id.empty()) { diff --git a/components/compiler/generator.hpp b/components/compiler/generator.hpp index fd1f954cad..89e1984314 100644 --- a/components/compiler/generator.hpp +++ b/components/compiler/generator.hpp @@ -109,15 +109,15 @@ namespace Compiler void stopScript (CodeContainer& code); - void getDistance (CodeContainer& code, Literals& literals, const std::string id); + void getDistance (CodeContainer& code, Literals& literals, const std::string& id); void getSecondsPassed (CodeContainer& code); - void getDisabled (CodeContainer& code, Literals& literals, const std::string id); + void getDisabled (CodeContainer& code, Literals& literals, const std::string& id); - void enable (CodeContainer& code, Literals& literals, const std::string id); + void enable (CodeContainer& code, Literals& literals, const std::string& id); - void disable (CodeContainer& code, Literals& literals, const std::string id); + void disable (CodeContainer& code, Literals& literals, const std::string& id); } } diff --git a/components/esm/esm_reader.hpp b/components/esm/esm_reader.hpp index 0420f37cd6..340482891c 100644 --- a/components/esm/esm_reader.hpp +++ b/components/esm/esm_reader.hpp @@ -152,15 +152,15 @@ public: * *************************************************************************/ - int getVer() { return mCtx.header.version; } + int getVer() const { return mCtx.header.version; } float getFVer() { if(mCtx.header.version == VER_12) return 1.2; else return 1.3; } - int getSpecial() { return mSpf; } + int getSpecial() const { return mSpf; } const std::string getAuthor() { return mCtx.header.author.toString(); } const std::string getDesc() { return mCtx.header.desc.toString(); } - const SaveData &getSaveData() { return mSaveData; } + const SaveData &getSaveData() const { return mSaveData; } const MasterList &getMasters() { return mMasters; } const NAME &retSubName() { return mCtx.subName; } - uint32_t getSubSize() { return mCtx.leftSub; } + uint32_t getSubSize() const { return mCtx.leftSub; } /************************************************************************* * @@ -323,8 +323,8 @@ public: void getRecHeader() { uint32_t u; getRecHeader(u); } void getRecHeader(uint32_t &flags); - bool hasMoreRecs() { return mCtx.leftFile > 0; } - bool hasMoreSubs() { return mCtx.leftRec > 0; } + bool hasMoreRecs() const { return mCtx.leftFile > 0; } + bool hasMoreSubs() const { return mCtx.leftRec > 0; } /************************************************************************* diff --git a/components/files/filelibrary.cpp b/components/files/filelibrary.cpp index c114159291..ce67f0c667 100644 --- a/components/files/filelibrary.cpp +++ b/components/files/filelibrary.cpp @@ -11,7 +11,7 @@ namespace Files bool containsVectorString(const StringVector& list, const std::string& str) { for (StringVector::const_iterator iter = list.begin(); - iter != list.end(); iter++) + iter != list.end(); ++iter) { if (*iter == str) return true; @@ -112,7 +112,7 @@ namespace Files void FileLibrary::printSections() { for(StringPathContMap::const_iterator mapIter = mMap.begin(); - mapIter != mMap.end(); mapIter++) + mapIter != mMap.end(); ++mapIter) { std::cout << mapIter->first <recType == RC_NiTexturingProperty) - t = (NiTexturingProperty*)pr; + t = static_cast(pr); else if (pr->recType == RC_NiMaterialProperty) - m = (NiMaterialProperty*)pr; + m = static_cast(pr); else if (pr->recType == RC_NiAlphaProperty) - a = (NiAlphaProperty*)pr; + a = static_cast(pr); } // Texture diff --git a/libs/mangle/input/servers/ois_driver.cpp b/libs/mangle/input/servers/ois_driver.cpp index acca69df4a..b8e4f5eb9a 100644 --- a/libs/mangle/input/servers/ois_driver.cpp +++ b/libs/mangle/input/servers/ois_driver.cpp @@ -121,8 +121,7 @@ OISDriver::OISDriver(Ogre::RenderWindow *window, bool exclusive) OISDriver::~OISDriver() { // Delete the listener object - if(listener) - delete listener; + delete listener; if(inputMgr == NULL) return; diff --git a/libs/openengine/bullet/CMotionState.cpp b/libs/openengine/bullet/CMotionState.cpp index 5ddef51752..d7746cbc52 100644 --- a/libs/openengine/bullet/CMotionState.cpp +++ b/libs/openengine/bullet/CMotionState.cpp @@ -11,6 +11,8 @@ namespace Physic { CMotionState::CMotionState(PhysicEngine* eng,std::string name) + : isPC(false) + , isNPC(true) { pEng = eng; tr.setIdentity(); diff --git a/libs/openengine/gui/manager.cpp b/libs/openengine/gui/manager.cpp index 1bf8ec3257..022c5efb53 100644 --- a/libs/openengine/gui/manager.cpp +++ b/libs/openengine/gui/manager.cpp @@ -36,7 +36,7 @@ void MyGUIManager::setup(Ogre::RenderWindow *wnd, Ogre::SceneManager *mgr, bool void MyGUIManager::shutdown() { - if(mGui) delete mGui; + delete mGui; if(mPlatform) { mPlatform->shutdown(); diff --git a/libs/openengine/ogre/renderer.cpp b/libs/openengine/ogre/renderer.cpp index a5eca76ed8..fadfa8d8c7 100644 --- a/libs/openengine/ogre/renderer.cpp +++ b/libs/openengine/ogre/renderer.cpp @@ -17,11 +17,10 @@ using namespace OEngine::Render; void OgreRenderer::cleanup() { - if (mFader) - delete mFader; + delete mFader; + mFader = NULL; - if(mRoot) - delete mRoot; + OGRE_DELETE mRoot; mRoot = NULL; } @@ -30,7 +29,7 @@ void OgreRenderer::start() mRoot->startRendering(); } -bool OgreRenderer::loadPlugins() +bool OgreRenderer::loadPlugins() const { #ifdef ENABLE_PLUGIN_GL mGLPlugin = new Ogre::GLPlugin(); @@ -125,7 +124,7 @@ void OgreRenderer::createWindow(const std::string &title, const WindowSettings& Ogre::TU_DYNAMIC_WRITE_ONLY_DISCARDABLE); } -void OgreRenderer::createScene(const std::string camName, float fov, float nearClip) +void OgreRenderer::createScene(const std::string& camName, float fov, float nearClip) { assert(mRoot); assert(mWindow); diff --git a/libs/openengine/ogre/renderer.hpp b/libs/openengine/ogre/renderer.hpp index f4ea8fbc85..f188e2051d 100644 --- a/libs/openengine/ogre/renderer.hpp +++ b/libs/openengine/ogre/renderer.hpp @@ -119,7 +119,7 @@ namespace OEngine void createWindow(const std::string &title, const WindowSettings& settings); /// Set up the scene manager, camera and viewport - void createScene(const std::string camName="Camera",// Camera name + void createScene(const std::string& camName="Camera",// Camera name float fov=55, // Field of view angle float nearClip=5 // Near clip distance ); @@ -132,7 +132,7 @@ namespace OEngine /// Start the main rendering loop void start(); - bool loadPlugins(); + bool loadPlugins() const; void update(float dt); From 42e44ac1b5d095f6d0ecd7760b2f4597759bb983 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 6 Jun 2012 21:08:20 +0200 Subject: [PATCH 322/325] fixed some leaks --- apps/openmw/mwrender/renderingmanager.cpp | 4 +++- libs/openengine/bullet/physic.cpp | 15 ++++++++++++--- libs/openengine/bullet/physic.hpp | 10 ++++++++++ 3 files changed, 25 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index a6f10fcd28..a771eb12e8 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -97,7 +97,6 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const mTerrainManager = new TerrainManager(mRendering.getScene(), this); - //mSkyManager = 0; mSkyManager = new SkyManager(mMwRoot, mRendering.getCamera()); mOcclusionQuery = new OcclusionQuery(&mRendering, mSkyManager->getSunNode()); @@ -116,10 +115,13 @@ RenderingManager::~RenderingManager () delete mPlayer; delete mSkyManager; delete mDebugging; + delete mShaderHelper; + delete mShadows; delete mTerrainManager; delete mLocalMap; delete mOcclusionQuery; delete mCompositors; + delete mWater; } MWRender::SkyManager* RenderingManager::getSkyManager() diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index d30d5e9f13..a94434e5b5 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -300,7 +300,13 @@ namespace Physic body->collide = true; body->getWorldTransform().setOrigin(btVector3( (x+0.5)*triSize*(sqrtVerts-1), (y+0.5)*triSize*(sqrtVerts-1), (maxh+minh)/2.f)); - addRigidBody(body); + HeightField hf; + hf.mBody = body; + hf.mShape = hfShape; + + mHeightFieldMap [name] = hf; + + dynamicsWorld->addRigidBody(body,COL_WORLD,COL_WORLD|COL_ACTOR_INTERNAL|COL_ACTOR_EXTERNAL); } void PhysicEngine::removeHeightField(int x, int y) @@ -309,8 +315,11 @@ namespace Physic + boost::lexical_cast(x) + "_" + boost::lexical_cast(y); - removeRigidBody(name); - deleteRigidBody(name); + HeightField hf = mHeightFieldMap [name]; + + dynamicsWorld->removeRigidBody(hf.mBody); + delete hf.mShape; + delete hf.mBody; } RigidBody* PhysicEngine::createRigidBody(std::string mesh,std::string name,float scale) diff --git a/libs/openengine/bullet/physic.hpp b/libs/openengine/bullet/physic.hpp index ba241b2b77..8115723201 100644 --- a/libs/openengine/bullet/physic.hpp +++ b/libs/openengine/bullet/physic.hpp @@ -15,6 +15,7 @@ class btSequentialImpulseConstraintSolver; class btCollisionDispatcher; class btDiscreteDynamicsWorld; class btKinematicCharacterController; +class btHeightfieldTerrainShape; namespace BtOgre { @@ -115,6 +116,12 @@ namespace Physic bool collide; }; + struct HeightField + { + btHeightfieldTerrainShape* mShape; + RigidBody* mBody; + }; + /** * The PhysicEngine class contain everything which is needed for Physic. * It's needed that Ogre Resources are set up before the PhysicEngine is created. @@ -240,6 +247,9 @@ namespace Physic //the NIF file loader. BulletShapeLoader* mShapeLoader; + typedef std::map HeightFieldContainer; + HeightFieldContainer mHeightFieldMap; + typedef std::map RigidBodyContainer; RigidBodyContainer RigidBodyMap; From 6ec2a2091c6a5d63349542a182cef502fc9ba78a Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 7 Jun 2012 12:16:03 +0200 Subject: [PATCH 323/325] Issue #305: Allow the use of = as a synonym for == --- components/compiler/scanner.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/components/compiler/scanner.cpp b/components/compiler/scanner.cpp index 080ca7d987..d0397e8cf1 100644 --- a/components/compiler/scanner.cpp +++ b/components/compiler/scanner.cpp @@ -368,8 +368,10 @@ namespace Compiler special = S_cmpEQ; else { + special = S_cmpEQ; putback (c); - return false; +// return false; +// Allow = as synonym for ==. \todo optionally disable for post-1.0 scripting improvements. } } else From ff84fbbfa70725daadee5b22d9e73124dd67888a Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 7 Jun 2012 12:36:51 +0200 Subject: [PATCH 324/325] Added DontSaveObject script instruction We are ignoring it for now and unless users protest we will probably keep it that way. --- apps/openmw/mwscript/docs/vmformat.txt | 1 + apps/openmw/mwscript/miscextensions.cpp | 14 ++++++++++++++ 2 files changed, 15 insertions(+) diff --git a/apps/openmw/mwscript/docs/vmformat.txt b/apps/openmw/mwscript/docs/vmformat.txt index de7248c0c2..4423f17cfb 100644 --- a/apps/openmw/mwscript/docs/vmformat.txt +++ b/apps/openmw/mwscript/docs/vmformat.txt @@ -146,4 +146,5 @@ op 0x200014f: ForceGreeting op 0x2000150: ForceGreeting, explicit reference op 0x2000151: ToggleFullHelp op 0x2000152: Goodbye +op 0x2000153: DontSaveObject (left unimplemented) opcodes 0x2000154-0x3ffffff unused diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index 4ba523937c..c7569ccdda 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -194,6 +194,17 @@ namespace MWScript } }; + class OpDontSaveObject : public Interpreter::Opcode0 + { + public: + + 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. + } + }; + const int opcodeXBox = 0x200000c; const int opcodeOnActivate = 0x200000d; const int opcodeActivate = 0x2000075; @@ -208,6 +219,7 @@ namespace MWScript const int opcodeFadeTo = 0x200013e; const int opcodeToggleWater = 0x2000144; const int opcodeTogglePathgrid = 0x2000146; + const int opcodeDontSaveObject = 0x2000153; void registerExtensions (Compiler::Extensions& extensions) { @@ -229,6 +241,7 @@ namespace MWScript extensions.registerInstruction ("twa", "", opcodeToggleWater); extensions.registerInstruction ("togglepathgrid", "", opcodeTogglePathgrid); extensions.registerInstruction ("tpg", "", opcodeTogglePathgrid); + extensions.registerInstruction ("dontsaveobject", "", opcodeDontSaveObject); } void installOpcodes (Interpreter::Interpreter& interpreter) @@ -247,6 +260,7 @@ namespace MWScript interpreter.installSegment5 (opcodeFadeTo, new OpFadeTo); interpreter.installSegment5 (opcodeTogglePathgrid, new OpTogglePathgrid); interpreter.installSegment5 (opcodeToggleWater, new OpToggleWater); + interpreter.installSegment5 (opcodeDontSaveObject, new OpDontSaveObject); } } } From 447158e9d62540f9386fdc024460e493afbfc7f4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 9 Jun 2012 19:15:11 +0200 Subject: [PATCH 325/325] shutdown crash fix --- apps/openmw/mwrender/renderingmanager.cpp | 2 ++ apps/openmw/mwrender/water.cpp | 3 +++ libs/openengine/ogre/renderer.cpp | 5 +++++ libs/openengine/ogre/renderer.hpp | 1 + 4 files changed, 11 insertions(+) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index a771eb12e8..266362f9b4 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -112,6 +112,8 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const RenderingManager::~RenderingManager () { + mRendering.removeWindowEventListener(this); + delete mPlayer; delete mSkyManager; delete mDebugging; diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index b4486a0cac..dc9e1fbee1 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -114,6 +114,9 @@ Water::~Water() { MeshManager::getSingleton().remove("water"); + if (mReflectionTarget) + mReflectionTexture->getBuffer()->getRenderTarget()->removeListener(this); + mWaterNode->detachObject(mWater); mSceneManager->destroyEntity(mWater); mSceneManager->destroySceneNode(mWaterNode); diff --git a/libs/openengine/ogre/renderer.cpp b/libs/openengine/ogre/renderer.cpp index fadfa8d8c7..7c0f88bd70 100644 --- a/libs/openengine/ogre/renderer.cpp +++ b/libs/openengine/ogre/renderer.cpp @@ -156,6 +156,11 @@ void OgreRenderer::setWindowEventListener(Ogre::WindowEventListener* listener) Ogre::WindowEventUtilities::addWindowEventListener(mWindow, listener); } +void OgreRenderer::removeWindowEventListener(Ogre::WindowEventListener* listener) +{ + Ogre::WindowEventUtilities::removeWindowEventListener(mWindow, listener); +} + void OgreRenderer::setFov(float fov) { mCamera->setFOVy(Degree(fov)); diff --git a/libs/openengine/ogre/renderer.hpp b/libs/openengine/ogre/renderer.hpp index f188e2051d..f1520a3db4 100644 --- a/libs/openengine/ogre/renderer.hpp +++ b/libs/openengine/ogre/renderer.hpp @@ -106,6 +106,7 @@ namespace OEngine ~OgreRenderer() { cleanup(); } void setWindowEventListener(Ogre::WindowEventListener* listener); + void removeWindowEventListener(Ogre::WindowEventListener* listener); /** Configure the renderer. This will load configuration files and set up the Root and logging classes. */